service.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. from app.api.v1.module_system.auth.schema import AuthSchema
  2. from app.core.exceptions import CustomException
  3. from app.core.logger import log
  4. from .crud import PointsCRUD, PointsRecordCRUD
  5. from .enums import PointsChangeTypeEnum, BusinessTypeEnum
  6. from .schema import PointsCreateSchema, PointsRecordOutSchema, PointsUpdateSchema, PointsOutSchema, PointsChangeSchema
  7. class PointsService:
  8. """积分服务层"""
  9. @classmethod
  10. async def create_points_service(
  11. cls, auth: AuthSchema, data: PointsCreateSchema
  12. ) -> PointsOutSchema:
  13. """
  14. 创建积分账户
  15. """
  16. crud = PointsCRUD(auth)
  17. # 检查租户是否已存在积分账户
  18. existing_points = await crud.get_by_tenant_id(data.tenant_id)
  19. if existing_points:
  20. raise CustomException(msg="租户已存在积分账户")
  21. points = await crud.create(data.model_dump(exclude_unset=True), skip_tenant_id=True)
  22. return PointsOutSchema.model_validate(points)
  23. @classmethod
  24. async def get_points_service(cls, auth: AuthSchema) -> PointsOutSchema:
  25. """
  26. 查询租户积分
  27. """
  28. crud = PointsCRUD(auth)
  29. points = await crud.get_by_tenant_id(auth.tenant_id)
  30. if not points:
  31. raise CustomException(msg="积分账户不存在")
  32. return PointsOutSchema.model_validate(points)
  33. @classmethod
  34. async def update_points_service(
  35. cls, auth: AuthSchema, data: PointsUpdateSchema
  36. ) -> PointsOutSchema:
  37. """
  38. 更新积分
  39. """
  40. change_data = PointsChangeSchema(
  41. points=data.points,
  42. change_type=PointsChangeTypeEnum.ADD.value,
  43. business_type=BusinessTypeEnum.RECHARGE.value,
  44. remark="后台充值"
  45. )
  46. return await cls.change_points_service(auth, change_data)
  47. @classmethod
  48. async def add_points_service(
  49. cls, auth: AuthSchema, data: PointsChangeSchema
  50. ) -> PointsOutSchema:
  51. """
  52. 增加积分
  53. """
  54. crud = PointsCRUD(auth)
  55. points = await crud.get_by_tenant_id(auth.tenant_id)
  56. if not points:
  57. raise CustomException(msg="积分账户不存在")
  58. # 计算新的积分余额
  59. new_points = points.points + data.points
  60. # 更新积分
  61. points.points = new_points
  62. await auth.db.flush()
  63. await auth.db.refresh(points)
  64. # 记录积分变动
  65. record_crud = PointsRecordCRUD(auth)
  66. await record_crud.create({
  67. "tenant_id": auth.tenant_id,
  68. "enterprise_id": data.enterprise_id,
  69. "employee_id": data.employee_id,
  70. "points": data.points,
  71. "balance": new_points,
  72. "type": PointsChangeTypeEnum.ADD.value,
  73. "business_type": data.business_type,
  74. "business_id": data.business_id,
  75. "remark": data.remark
  76. })
  77. log.info(f"增加积分成功: 租户={auth.tenant_id}, 增加={data.points}, 余额={new_points}")
  78. return PointsOutSchema.model_validate(points)
  79. @classmethod
  80. async def deduct_points_service(
  81. cls, auth: AuthSchema, data: PointsChangeSchema
  82. ) -> PointsOutSchema:
  83. """
  84. 扣除积分
  85. """
  86. crud = PointsCRUD(auth)
  87. points = await crud.get_by_tenant_id(auth.tenant_id)
  88. if not points:
  89. raise CustomException(msg="积分账户不存在")
  90. if points.points < data.points:
  91. raise CustomException(msg="积分不足")
  92. # 计算新的积分余额
  93. new_points = points.points - data.points
  94. # 更新积分
  95. points.points = new_points
  96. await auth.db.flush()
  97. await auth.db.refresh(points)
  98. # 记录积分变动
  99. record_crud = PointsRecordCRUD(auth)
  100. await record_crud.create({
  101. "tenant_id": auth.tenant_id,
  102. "enterprise_id": data.enterprise_id,
  103. "employee_id": data.employee_id,
  104. "points": data.points,
  105. "balance": new_points,
  106. "type": PointsChangeTypeEnum.DEDUCT.value,
  107. "business_type": data.business_type,
  108. "business_id": data.business_id,
  109. "remark": data.remark
  110. })
  111. log.info(f"扣除积分成功: 租户={auth.tenant_id}, 扣除={data.points}, 余额={new_points}")
  112. return PointsOutSchema.model_validate(points)
  113. @classmethod
  114. async def check_points_service(cls, auth: AuthSchema, change_data: PointsChangeSchema) -> bool:
  115. """
  116. 检查积分余额
  117. """
  118. crud = PointsCRUD(auth)
  119. points = await crud.get_by_tenant_id(auth.tenant_id)
  120. return points.points >= change_data.points
  121. @classmethod
  122. async def change_points_service(
  123. cls, auth: AuthSchema, data: PointsChangeSchema
  124. ) -> PointsOutSchema:
  125. """
  126. 通用积分变动
  127. """
  128. if data.change_type == PointsChangeTypeEnum.ADD.value:
  129. return await cls.add_points_service(auth, data)
  130. elif data.change_type == PointsChangeTypeEnum.DEDUCT.value:
  131. return await cls.deduct_points_service(auth, data)
  132. else:
  133. raise CustomException(msg="无效的积分变动类型")
  134. @classmethod
  135. async def list_record_service(
  136. cls,
  137. auth: AuthSchema,
  138. page_no: int = 1,
  139. page_size: int = 20,
  140. search: dict | None = None,
  141. ) -> dict:
  142. """
  143. 查询积分记录
  144. """
  145. crud = PointsRecordCRUD(auth)
  146. offset = (page_no - 1) * page_size
  147. return await crud.page(
  148. offset=offset,
  149. limit=page_size,
  150. order_by=[{"id": "desc"}],
  151. search=search or {},
  152. out_schema=PointsRecordOutSchema
  153. )