base.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. """报销模块 Service 基类 — 租户隔离 + UUID + 软删除。"""
  2. from __future__ import annotations
  3. from typing import TYPE_CHECKING, Any, List, Optional, Sequence, Tuple, Type, TypeVar
  4. from sqlalchemy.orm import Session
  5. from app.core.utils import generate_uuid
  6. from app.core.delete_guard import assert_row_deletable_by_creator, user_info_from_context
  7. from app.services.bx_data_scope import apply_bx_scope, assert_bx_row_in_scope
  8. if TYPE_CHECKING:
  9. from app.core.bx_auth import BxUserContext
  10. M = TypeVar("M")
  11. class BxCrudService:
  12. @staticmethod
  13. def get_by_id(
  14. model: Type[M],
  15. db: Session,
  16. id: str,
  17. tenant_no: str,
  18. *,
  19. user: Optional["BxUserContext"] = None,
  20. skip_scope: bool = False,
  21. ) -> Optional[M]:
  22. query = db.query(model).filter(model.id == id, model.tenant_no == tenant_no)
  23. if hasattr(model, "del_flag"):
  24. query = query.filter(model.del_flag == 0)
  25. row = query.first()
  26. if row and user and not skip_scope:
  27. assert_bx_row_in_scope(db, row, model, user, tenant_no)
  28. return row
  29. @staticmethod
  30. def get_paged(
  31. model: Type[M],
  32. db: Session,
  33. tenant_no: str,
  34. page: int,
  35. page_size: int,
  36. filters: Optional[List[Any]] = None,
  37. *,
  38. user: Optional["BxUserContext"] = None,
  39. skip_scope: bool = False,
  40. order_by: Optional[Any] = None,
  41. ) -> Tuple[Sequence[M], int]:
  42. query = db.query(model).filter(model.tenant_no == tenant_no)
  43. if hasattr(model, "del_flag"):
  44. query = query.filter(model.del_flag == 0)
  45. if filters:
  46. query = query.filter(*filters)
  47. if user and not skip_scope:
  48. query = apply_bx_scope(query, model, user, db, tenant_no)
  49. total = query.count()
  50. if order_by is not None:
  51. query = query.order_by(order_by)
  52. elif hasattr(model, "sort_order"):
  53. query = query.order_by(model.sort_order.asc(), model.create_time.desc())
  54. else:
  55. query = query.order_by(model.create_time.desc())
  56. rows = query.offset((page - 1) * page_size).limit(page_size).all()
  57. return rows, total
  58. @staticmethod
  59. def create(
  60. model: Type[M],
  61. db: Session,
  62. obj_in: dict,
  63. *,
  64. tenant_no: str,
  65. user_id: str,
  66. dept_id: str,
  67. ) -> M:
  68. data = dict(obj_in)
  69. data.setdefault("id", generate_uuid())
  70. data["tenant_no"] = tenant_no
  71. data["create_by"] = user_id
  72. data["create_dept_id"] = dept_id or ""
  73. obj = model(**data)
  74. db.add(obj)
  75. db.flush()
  76. return obj
  77. @staticmethod
  78. def update(
  79. model: Type[M],
  80. db: Session,
  81. id: str,
  82. tenant_no: str,
  83. obj_in: dict,
  84. *,
  85. user_id: str,
  86. user: Optional["BxUserContext"] = None,
  87. skip_scope: bool = False,
  88. ) -> Optional[M]:
  89. obj = BxCrudService.get_by_id(
  90. model, db, id, tenant_no, user=user, skip_scope=skip_scope
  91. )
  92. if not obj:
  93. return None
  94. for key, value in obj_in.items():
  95. setattr(obj, key, value)
  96. if hasattr(obj, "update_by"):
  97. obj.update_by = user_id
  98. db.flush()
  99. return obj
  100. @staticmethod
  101. def soft_delete(
  102. model: Type[M],
  103. db: Session,
  104. id: str,
  105. tenant_no: str,
  106. *,
  107. user_id: str = "",
  108. user: Optional["BxUserContext"] = None,
  109. skip_scope: bool = False,
  110. ) -> bool:
  111. obj = BxCrudService.get_by_id(
  112. model, db, id, tenant_no, user=user, skip_scope=skip_scope
  113. )
  114. if not obj:
  115. return False
  116. if user:
  117. assert_row_deletable_by_creator(obj, user_info_from_context(user))
  118. elif user_id:
  119. assert_row_deletable_by_creator(obj, {"user_id": user_id})
  120. obj.del_flag = 1
  121. if hasattr(obj, "update_by") and user_id:
  122. obj.update_by = user_id
  123. db.flush()
  124. return True