Sfoglia il codice sorgente

fix(expense): 代码审查修复 - 部门模式下IDs展开+typo修正+quota_id注释补充

Fixed:
- C1: _sync_modify_quotas_by_scope 在部门模式下将部门ID展开为员工ID列表后再操作额度
- C2: quota_id 字段注释补充说明可存发放规则ID
- C3: onwer→owner typo + CP→CAP typo
alphah 2 settimane fa
parent
commit
dbd1a53fa2

+ 35 - 6
backend/app/plugin/module_payment/expense/institution/service.py

@@ -403,6 +403,9 @@ class InstitutionService:
 
         新增员工:按发放模式+有效期创建额度记录
         删除员工:删除对应额度记录
+
+        部门模式(EMPLOYEE_DEPARTMENT):add/delete_ids 是部门ID,
+        需要先展开为员工ID列表再操作额度。
         """
         from app.plugin.module_payment.expense.quota.model import QuotaModel
         from app.plugin.module_payment.expense.quota.enums import QuotaStatusEnum
@@ -411,6 +414,7 @@ class InstitutionService:
         grant_mode = (raw_data or {}).get("grant_mode", "manual")
         amount_val = float((raw_data or {}).get("amount", 0) or 0)
         tenant_id = auth.user.tenant_id if auth.user else 1
+        adapter_type = scope_info.get("adapter_type", "")
 
         # 判断制度是否在有效期内
         now = datetime.now()
@@ -431,8 +435,34 @@ class InstitutionService:
 
         is_active = (grant_mode == "period") and amount_val > 0 and is_in_period
 
+        # 如为部门模式,将部门ID展开为员工ID列表
+        if adapter_type in ("EMPLOYEE_DEPARTMENT", "DEPARTMENT_SELECT"):
+            from app.plugin.module_payment.employee.model import EmployeeModel
+            emp_all = await auth.db.execute(
+                select(EmployeeModel).where(
+                    EmployeeModel.enterprise_id == enterprise_id,
+                    EmployeeModel.status == "EMPLOYEE_ACTIVATED",
+                )
+            )
+            emp_by_dept: dict[str, list[str]] = {}
+            for emp in emp_all.scalars().all():
+                if emp.employee_id and emp.department_ids:
+                    for did in emp.department_ids:
+                        emp_by_dept.setdefault(str(did), []).append(emp.employee_id)
+
+            raw_delete = scope_info.get("delete_owner_id_list") or []
+            raw_add = scope_info.get("add_owner_id_list") or []
+            delete_ids = []
+            for did in raw_delete:
+                delete_ids.extend(emp_by_dept.get(str(did), []))
+            add_ids = []
+            for did in raw_add:
+                add_ids.extend(emp_by_dept.get(str(did), []))
+        else:
+            delete_ids = scope_info.get("delete_owner_id_list") or []
+            add_ids = scope_info.get("add_owner_id_list") or []
+
         # 删除被移除的员工额度
-        delete_ids = scope_info.get("delete_owner_id_list") or []
         if delete_ids:
             del_stmt = sa_delete(QuotaModel).where(
                 QuotaModel.institution_id == institution_id,
@@ -442,14 +472,13 @@ class InstitutionService:
             log.info(f"删除已移除员工额度: count={len(delete_ids)}")
 
         # 新增员工的额度
-        add_ids = scope_info.get("add_owner_id_list") or []
         if add_ids:
             total = Decimal(str(amount_val)) if is_active else Decimal("0")
             available = total
             status = QuotaStatusEnum.QUOTA_ACTIVE.value if is_active else QuotaStatusEnum.QUOTA_PENDING.value
 
             created = 0
-            for emp_id in add_ids:
+            for emp_id in set(add_ids):
                 emp_id_str = str(emp_id)
                 check = select(QuotaModel).where(
                     QuotaModel.employee_id == emp_id_str,
@@ -1064,12 +1093,12 @@ class InstitutionScopeService:
             "total_page_count": getattr(result, 'total_page_count', 0) or 0,
             "adapter_type": getattr(result, 'adapter_type', None),
             "owner_id_list": getattr(result, 'owner_id_list', []) or [],
-            "owner_open_id_list": getattr(result, 'onwer_open_id_list', []) or [],
+            "owner_open_id_list": getattr(result, 'owner_open_id_list', []) or [],
             "scope_info_list": [
                 {
                     "adapter_type": getattr(result, 'adapter_type', None),
                     "owner_id_list": getattr(result, 'owner_id_list', []) or [],
-                    "owner_open_id_list": getattr(result, 'onwer_open_id_list', []) or [],
+                    "owner_open_id_list": getattr(result, 'owner_open_id_list', []) or [],
                 }
             ] if getattr(result, 'adapter_type', None) else [],
         }
@@ -1125,7 +1154,7 @@ class IssueruleService:
 
         # 参数约束校验
         if quota_type == "CAP" and invalid_mode is not None and invalid_mode != 1:
-            raise CustomException(msg="余额类型(CP)的发放规则必须为可累计(invalid_mode=1)")
+            raise CustomException(msg="余额类型(CAP)的发放规则必须为可累计(invalid_mode=1)")
         if quota_type == "COUNT" and share_mode is not None and share_mode != 0:
             raise CustomException(msg="次卡类型(COUNT)的发放规则不可转赠(share_mode=0)")
 

+ 1 - 1
backend/app/plugin/module_payment/expense/quota/model.py

@@ -27,7 +27,7 @@ class QuotaModel(PaymentModelMixin, TenantMixin, EnterpriseMixin):
         String(64), unique=True, index=True, comment="外部业务编号"
     )
     quota_id: Mapped[str | None] = mapped_column(
-        String(64), comment="额度ID(支付宝返回)"
+        String(64), comment="额度ID(支付宝返回)或关联的发放规则ID(issue_rule_id)"
     )
     total_amount: Mapped[Decimal | None] = mapped_column(
         Numeric(12, 2), default=0, comment="总金额"