expense_item.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. from __future__ import annotations
  2. from typing import List, Optional
  3. from sqlalchemy.orm import Session
  4. from app.core.bx_auth import BxUserContext
  5. from app.core.tenant_context import get_tenant_no
  6. from app.models.bx_models import BxExpenseItem
  7. from app.services.bx.base import BxCrudService
  8. class ExpenseItemService:
  9. @staticmethod
  10. def _tenant_no(db: Session, user: BxUserContext) -> str:
  11. return get_tenant_no(db, user.to_tenant_user_dict())
  12. @staticmethod
  13. def get_by_id(
  14. db: Session,
  15. item_id: str,
  16. tenant_no: str,
  17. *,
  18. user: Optional[BxUserContext] = None,
  19. skip_scope: bool = True,
  20. ) -> Optional[BxExpenseItem]:
  21. # 费用项目为主数据:默认跳过 create_by 数据范围
  22. return BxCrudService.get_by_id(
  23. BxExpenseItem, db, item_id, tenant_no, user=user, skip_scope=skip_scope
  24. )
  25. @staticmethod
  26. def create(
  27. db: Session,
  28. obj_in: dict,
  29. *,
  30. user: BxUserContext,
  31. ) -> BxExpenseItem:
  32. tenant_no = ExpenseItemService._tenant_no(db, user)
  33. data = dict(obj_in)
  34. parent_id = data.get("parent_id") or "0"
  35. data["parent_id"] = parent_id
  36. if parent_id and parent_id != "0":
  37. parent = ExpenseItemService.get_by_id(db, parent_id, tenant_no, user=user)
  38. if not parent:
  39. raise ValueError("父级费用项目不存在")
  40. data.setdefault("level", (parent.level or 1) + 1)
  41. else:
  42. data["parent_id"] = "0"
  43. data.setdefault("level", 1)
  44. return BxCrudService.create(
  45. BxExpenseItem,
  46. db,
  47. data,
  48. tenant_no=tenant_no,
  49. user_id=user.id,
  50. dept_id=user.dept_id,
  51. )
  52. @staticmethod
  53. def update(
  54. db: Session,
  55. item_id: str,
  56. obj_in: dict,
  57. *,
  58. user: BxUserContext,
  59. ) -> Optional[BxExpenseItem]:
  60. tenant_no = ExpenseItemService._tenant_no(db, user)
  61. data = dict(obj_in)
  62. if "parent_id" in data and data["parent_id"] is not None:
  63. parent_id = data["parent_id"] or "0"
  64. data["parent_id"] = parent_id
  65. if parent_id != "0":
  66. if parent_id == item_id:
  67. raise ValueError("不能将项目设置为自己的父级")
  68. parent = ExpenseItemService.get_by_id(db, parent_id, tenant_no, user=user)
  69. if not parent:
  70. raise ValueError("父级费用项目不存在")
  71. return BxCrudService.update(
  72. BxExpenseItem,
  73. db,
  74. item_id,
  75. tenant_no,
  76. data,
  77. user_id=user.id,
  78. user=user,
  79. skip_scope=True,
  80. )
  81. @staticmethod
  82. def soft_delete(db: Session, item_id: str, *, user: BxUserContext) -> bool:
  83. tenant_no = ExpenseItemService._tenant_no(db, user)
  84. return BxCrudService.soft_delete(
  85. BxExpenseItem,
  86. db,
  87. item_id,
  88. tenant_no,
  89. user_id=user.id,
  90. user=user,
  91. skip_scope=True,
  92. )
  93. @staticmethod
  94. def get_item_tree(db: Session, tenant_no: str, *, user: BxUserContext) -> List[BxExpenseItem]:
  95. # 费用项目是租户级主数据,供报销/备用金选择;不做 create_by 数据范围过滤,
  96. # 否则「仅本人」角色看不到管理员维护的费用项目。
  97. _ = user
  98. query = db.query(BxExpenseItem).filter(
  99. BxExpenseItem.del_flag == 0, BxExpenseItem.tenant_no == tenant_no
  100. )
  101. items = query.order_by(
  102. BxExpenseItem.sort_order.asc(), BxExpenseItem.create_time.desc()
  103. ).all()
  104. return ExpenseItemService._build_tree(items)
  105. @staticmethod
  106. def _build_tree(items: List[BxExpenseItem]) -> List[BxExpenseItem]:
  107. item_map = {item.id: item for item in items}
  108. roots: List[BxExpenseItem] = []
  109. for item in items:
  110. parent_id = item.parent_id or "0"
  111. if not parent_id or parent_id == "0":
  112. roots.append(item)
  113. else:
  114. parent = item_map.get(parent_id)
  115. if parent:
  116. if not hasattr(parent, "children") or parent.children is None:
  117. parent.children = []
  118. parent.children.append(item)
  119. for item in items:
  120. if hasattr(item, "children") and item.children:
  121. item.child_count = len(item.children)
  122. else:
  123. item.child_count = 0
  124. return roots