Преглед изворни кода

fix(expense): 员工联动创建额度时判断制度有效期和发放模式

- 新增 _compute_quota_status 统一判定逻辑
  - 定额+有效期内 → ACTIVE + 全额
  - 手工/过期 → PENDING + 0
- 部门联动 _sync_employee_quota 和全员联动 sync_employee_to_all_institution
  都改用该判定逻辑
alphah пре 2 недеља
родитељ
комит
be38478444
1 измењених фајлова са 45 додато и 12 уклоњено
  1. 45 12
      backend/app/plugin/module_payment/expense/institution/scope_sync.py

+ 45 - 12
backend/app/plugin/module_payment/expense/institution/scope_sync.py

@@ -11,20 +11,49 @@ from app.core.logger import log
 from app.plugin.module_payment.expense.institution.crud import InstitutionCRUD
 
 
+def _compute_quota_status(inst) -> tuple:
+    """根据制度配置和当前时间,计算额度记录的状态和金额
+
+    返回: (total_amount, available_amount, status)
+    """
+    from datetime import datetime
+    from app.plugin.module_payment.expense.quota.enums import QuotaStatusEnum
+    from decimal import Decimal
+
+    grant_mode = getattr(inst, "grant_mode", None)
+    amount_val = float(getattr(inst, "amount", 0) or 0)
+
+    # 判断是否在有效期内
+    now = datetime.now()
+    in_period = True
+    start_date = getattr(inst, "effective_start_date", None)
+    end_date = getattr(inst, "effective_end_date", None)
+    if start_date and now < start_date:
+        in_period = False
+    if end_date and in_period and now > end_date:
+        in_period = False
+
+    # 定额+有效期内 → ACTIVE + 全额
+    if grant_mode == "period" and amount_val > 0 and in_period:
+        return (Decimal(str(amount_val)), Decimal(str(amount_val)), QuotaStatusEnum.QUOTA_ACTIVE.value)
+
+    # 否则 → PENDING + 0
+    return (Decimal("0"), Decimal("0"), QuotaStatusEnum.QUOTA_PENDING.value)
+
+
 async def _sync_employee_quota(
     auth: AuthSchema, enterprise_id: str, employee_id: str, department_ids: list[str], is_add: bool
 ) -> None:
     """根据员工所属部门,同步本地额度记录
 
     扫描所有按部门模式的制度:
-    - 匹配的部门 → 确保员工有额度记录(创建缺失的)
+    - 匹配的部门 → 确保员工有额度记录(检查有效期内状态
     - 不匹配的部门 → 删除该员工的额度记录(处理离部门场景)
     """
     if not employee_id:
         return
 
     from app.plugin.module_payment.expense.quota.model import QuotaModel
-    from app.plugin.module_payment.expense.quota.enums import QuotaStatusEnum
     from sqlalchemy import insert, delete as sa_delete, select
 
     try:
@@ -61,27 +90,27 @@ async def _sync_employee_quota(
             matched = bool(scope_ids and dept_id_set.intersection(scope_ids))
 
             if matched:
-                # 匹配 → 确保有额度记录
+                # 检查是否已有记录
                 check = select(QuotaModel).where(
                     QuotaModel.employee_id == employee_id,
                     QuotaModel.institution_id == inst_id,
                 )
                 existing = await auth.db.execute(check)
                 if not existing.scalar_one_or_none():
+                    total, available, status = _compute_quota_status(inst)
                     stmt = insert(QuotaModel).values(
                         employee_id=employee_id,
                         institution_id=inst_id,
                         out_biz_no=f"scope_{inst_id}_{employee_id}",
-                        total_amount=0,
-                        available_amount=0,
-                        status=QuotaStatusEnum.QUOTA_PENDING.value,
+                        total_amount=total,
+                        available_amount=available,
+                        status=status,
                         enterprise_id=enterprise_id,
                         tenant_id=tenant_id,
                     )
                     await auth.db.execute(stmt)
-                    log.info(f"部门联动 - 新增员工额度: employee_id={employee_id}, institution_id={inst_id}")
+                    log.info(f"部门联动 - 新增员工额度: employee_id={employee_id}, institution_id={inst_id}, status={status}, amount={total}")
             else:
-                # 不匹配 → 删除该员工的额度记录
                 if not is_add:
                     continue
                 del_stmt = sa_delete(QuotaModel).where(
@@ -159,7 +188,10 @@ async def remove_department_from_institution_scopes(
 async def sync_employee_to_all_institution(
     auth: AuthSchema, enterprise_id: str, employee_id: str
 ) -> None:
-    """员工激活时,为全体员工(applicable_scope=all)的制度创建本地额度记录"""
+    """员工激活时,为全体员工(applicable_scope=all)的制度创建本地额度记录
+
+    根据制度有效期和发放模式判断状态:有效期内定额→ACTIVE,否则→PENDING
+    """
     if not employee_id or not enterprise_id:
         return
     try:
@@ -171,7 +203,6 @@ async def sync_employee_to_all_institution(
         if not institutions:
             return
         from app.plugin.module_payment.expense.quota.model import QuotaModel
-        from app.plugin.module_payment.expense.quota.enums import QuotaStatusEnum
         from sqlalchemy import insert, select
         tenant_id = auth.user.tenant_id if auth.user else 1
         for inst in institutions:
@@ -182,14 +213,16 @@ async def sync_employee_to_all_institution(
             existing = await auth.db.execute(check)
             if existing.scalar_one_or_none():
                 continue
+            total, available, status = _compute_quota_status(inst)
             stmt = insert(QuotaModel).values(
                 employee_id=employee_id, institution_id=inst_id,
                 out_biz_no=f"all_{inst_id}_{employee_id}",
-                total_amount=0, available_amount=0,
-                status=QuotaStatusEnum.QUOTA_PENDING.value,
+                total_amount=total, available_amount=available,
+                status=status,
                 enterprise_id=enterprise_id, tenant_id=tenant_id,
             )
             await auth.db.execute(stmt)
+            log.info(f"全员联动 - 新增员工额度: employee_id={employee_id}, institution_id={inst_id}, status={status}, amount={total}")
         await auth.db.flush()
     except Exception as e:
         log.error(f"全员制度联动失败: {e}")