attachment.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. from __future__ import annotations
  2. from typing import List, Optional, Optional
  3. from sqlalchemy import case as sql_case, func, or_
  4. from sqlalchemy.orm import Session
  5. from app.core.bx_auth import BxUserContext
  6. from app.core.tenant_context import get_tenant_no
  7. from app.models.bx_models import BxAttachment
  8. from app.services.bx.base import BxCrudService
  9. from app.services.bx_data_scope import assert_bx_attachment_biz_in_scope, assert_bx_biz_in_scope
  10. class AttachmentService:
  11. @staticmethod
  12. def _tenant_no(db: Session, user: BxUserContext) -> str:
  13. return get_tenant_no(db, user.to_tenant_user_dict())
  14. @staticmethod
  15. def get_by_id(
  16. db: Session,
  17. attachment_id: str,
  18. tenant_no: str,
  19. *,
  20. user: Optional[BxUserContext] = None,
  21. ) -> Optional[BxAttachment]:
  22. row = BxCrudService.get_by_id(BxAttachment, db, attachment_id, tenant_no)
  23. if row and user:
  24. assert_bx_attachment_biz_in_scope(db, row, user, tenant_no)
  25. return row
  26. @staticmethod
  27. def create(
  28. db: Session,
  29. obj_in: dict,
  30. *,
  31. user: BxUserContext,
  32. ) -> BxAttachment:
  33. tenant_no = AttachmentService._tenant_no(db, user)
  34. return BxCrudService.create(
  35. BxAttachment,
  36. db,
  37. obj_in,
  38. tenant_no=tenant_no,
  39. user_id=user.id,
  40. dept_id=user.dept_id,
  41. )
  42. @staticmethod
  43. def soft_delete(db: Session, attachment_id: str, *, user: BxUserContext) -> bool:
  44. tenant_no = AttachmentService._tenant_no(db, user)
  45. row = AttachmentService.get_by_id(db, attachment_id, tenant_no, user=user)
  46. if not row:
  47. return False
  48. return BxCrudService.soft_delete(
  49. BxAttachment, db, attachment_id, tenant_no, user_id=user.id
  50. )
  51. @staticmethod
  52. def get_by_biz(
  53. db: Session, biz_type: str, biz_id: str, tenant_no: str, *, user: BxUserContext
  54. ) -> List[BxAttachment]:
  55. assert_bx_biz_in_scope(db, biz_type, biz_id, user, tenant_no)
  56. query = db.query(BxAttachment).filter(
  57. BxAttachment.biz_type == biz_type,
  58. BxAttachment.biz_id == biz_id,
  59. BxAttachment.tenant_no == tenant_no,
  60. BxAttachment.del_flag == 0,
  61. )
  62. return query.order_by(BxAttachment.sort_order, BxAttachment.create_time).all()
  63. @staticmethod
  64. def bind_biz(
  65. db: Session,
  66. ids: List[str],
  67. biz_type: str,
  68. biz_id: str,
  69. *,
  70. user: BxUserContext,
  71. ) -> int:
  72. tenant_no = AttachmentService._tenant_no(db, user)
  73. assert_bx_biz_in_scope(db, biz_type, biz_id, user, tenant_no)
  74. if not ids:
  75. return 0
  76. count = (
  77. db.query(BxAttachment)
  78. .filter(
  79. BxAttachment.id.in_(ids),
  80. BxAttachment.tenant_no == tenant_no,
  81. BxAttachment.del_flag == 0,
  82. )
  83. .update(
  84. {
  85. BxAttachment.biz_type: biz_type,
  86. BxAttachment.biz_id: biz_id,
  87. BxAttachment.update_by: user.id,
  88. },
  89. synchronize_session="fetch",
  90. )
  91. )
  92. db.flush()
  93. return int(count or 0)
  94. @staticmethod
  95. def count_invoice_attach_by_biz_ids(
  96. db: Session, biz_type: str, biz_ids: List[str], tenant_no: str
  97. ) -> dict[str, tuple[int, int]]:
  98. if not biz_ids:
  99. return {}
  100. if biz_type == "reimburse_apply":
  101. inv_cond = or_(
  102. BxAttachment.attach_type == "invoice",
  103. BxAttachment.file_type.isnot(None) & BxAttachment.file_type.like("image/%"),
  104. BxAttachment.file_type == "application/pdf",
  105. )
  106. else:
  107. inv_cond = BxAttachment.attach_type == "invoice"
  108. inv_case = sql_case((inv_cond, 1), else_=0)
  109. att_case = sql_case((inv_cond, 0), else_=1)
  110. rows = (
  111. db.query(
  112. BxAttachment.biz_id,
  113. func.coalesce(func.sum(inv_case), 0).label("inv"),
  114. func.coalesce(func.sum(att_case), 0).label("att"),
  115. )
  116. .filter(
  117. BxAttachment.biz_type == biz_type,
  118. BxAttachment.biz_id.in_(biz_ids),
  119. BxAttachment.tenant_no == tenant_no,
  120. BxAttachment.del_flag == 0,
  121. )
  122. .group_by(BxAttachment.biz_id)
  123. .all()
  124. )
  125. return {str(r.biz_id): (int(r.inv), int(r.att)) for r in rows}