|
|
@@ -1,7 +1,8 @@
|
|
|
"""
|
|
|
费控制度成员联动同步工具
|
|
|
|
|
|
-用于部门停用/员工解约时自动移除相关制度中的成员引用。
|
|
|
+部门停用/员工解约时自动移除相关制度中的成员引用。
|
|
|
+员工调部门/部门新增员工时自动创建本地额度记录。
|
|
|
"""
|
|
|
|
|
|
from app.api.v1.module_system.auth.schema import AuthSchema
|
|
|
@@ -10,6 +11,123 @@ from app.core.logger import log
|
|
|
from app.plugin.module_payment.expense.institution.crud import InstitutionCRUD
|
|
|
|
|
|
|
|
|
+async def _sync_employee_quota(
|
|
|
+ auth: AuthSchema, enterprise_id: str, employee_id: str, department_ids: list[str], is_add: bool
|
|
|
+) -> None:
|
|
|
+ """根据员工所属部门,同步本地额度记录
|
|
|
+
|
|
|
+ 扫描所有按部门模式的制度,如果该制度引用了员工所属部门,
|
|
|
+ 则为员工创建(或删除)本地 pay_expense_quota 记录。
|
|
|
+ """
|
|
|
+ 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:
|
|
|
+ crud = InstitutionCRUD(auth)
|
|
|
+ institutions = await crud.list(
|
|
|
+ search={
|
|
|
+ "enterprise_id": enterprise_id,
|
|
|
+ "status__ne": "INSTITUTION_DELETE",
|
|
|
+ "applicable_scope": "department",
|
|
|
+ },
|
|
|
+ order_by=[{"id": "desc"}],
|
|
|
+ )
|
|
|
+ if not institutions:
|
|
|
+ return
|
|
|
+
|
|
|
+ for inst in institutions:
|
|
|
+ inst_id = inst.institution_id
|
|
|
+ scope_owner_ids_str = getattr(inst, "scope_owner_id_list", None) or getattr(inst, "department_id", None)
|
|
|
+ if not inst_id:
|
|
|
+ continue
|
|
|
+
|
|
|
+ # 判断该制度的部门是否匹配员工部门
|
|
|
+ matched = False
|
|
|
+ if scope_owner_ids_str:
|
|
|
+ import json
|
|
|
+ try:
|
|
|
+ scope_ids = json.loads(scope_owner_ids_str) if isinstance(scope_owner_ids_str, str) else scope_owner_ids_str
|
|
|
+ except (json.JSONDecodeError, TypeError):
|
|
|
+ scope_ids = [str(scope_owner_ids_str)] if scope_owner_ids_str else []
|
|
|
+
|
|
|
+ for dept_id in department_ids:
|
|
|
+ if dept_id in scope_ids:
|
|
|
+ matched = True
|
|
|
+ break
|
|
|
+ else:
|
|
|
+ continue
|
|
|
+
|
|
|
+ if not matched:
|
|
|
+ continue
|
|
|
+
|
|
|
+ tenant_id = auth.user.tenant_id if auth.user else 1
|
|
|
+
|
|
|
+ if is_add:
|
|
|
+ # 员工加入部门 → 创建额度记录
|
|
|
+ check = select(QuotaModel).where(
|
|
|
+ QuotaModel.employee_id == employee_id,
|
|
|
+ QuotaModel.institution_id == inst_id,
|
|
|
+ )
|
|
|
+ existing = await auth.db.execute(check)
|
|
|
+ if existing.scalar_one_or_none():
|
|
|
+ continue
|
|
|
+
|
|
|
+ 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,
|
|
|
+ enterprise_id=enterprise_id,
|
|
|
+ tenant_id=tenant_id,
|
|
|
+ )
|
|
|
+ await auth.db.execute(stmt)
|
|
|
+ log.info(
|
|
|
+ f"部门联动 - 新增员工额度: employee_id={employee_id}, "
|
|
|
+ f"institution_id={inst_id}"
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ # 员工离开部门 → 删除额度记录
|
|
|
+ del_stmt = sa_delete(QuotaModel).where(
|
|
|
+ QuotaModel.employee_id == employee_id,
|
|
|
+ QuotaModel.institution_id == inst_id,
|
|
|
+ )
|
|
|
+ await auth.db.execute(del_stmt)
|
|
|
+ log.info(
|
|
|
+ f"部门联动 - 删除员工额度: employee_id={employee_id}, "
|
|
|
+ f"institution_id={inst_id}"
|
|
|
+ )
|
|
|
+
|
|
|
+ await auth.db.flush()
|
|
|
+ except Exception as e:
|
|
|
+ log.error(f"部门联动同步额度失败(不影响主体操作): {e}")
|
|
|
+
|
|
|
+
|
|
|
+async def sync_employee_add_to_department_institutions(
|
|
|
+ auth: AuthSchema,
|
|
|
+ enterprise_id: str,
|
|
|
+ employee_id: str,
|
|
|
+ department_ids: list[str],
|
|
|
+) -> None:
|
|
|
+ """员工加入部门时,为引用该部门的制度创建本地额度记录"""
|
|
|
+ await _sync_employee_quota(auth, enterprise_id, employee_id, department_ids, is_add=True)
|
|
|
+
|
|
|
+
|
|
|
+async def sync_employee_remove_from_department_institutions(
|
|
|
+ auth: AuthSchema,
|
|
|
+ enterprise_id: str,
|
|
|
+ employee_id: str,
|
|
|
+ department_ids: list[str],
|
|
|
+) -> None:
|
|
|
+ """员工离开部门时,从引用该部门的制度中删除本地额度记录"""
|
|
|
+ await _sync_employee_quota(auth, enterprise_id, employee_id, department_ids, is_add=False)
|
|
|
+
|
|
|
+
|
|
|
async def remove_department_from_institution_scopes(
|
|
|
auth: AuthSchema,
|
|
|
enterprise_id: str,
|
|
|
@@ -22,7 +140,6 @@ async def remove_department_from_institution_scopes(
|
|
|
"""
|
|
|
try:
|
|
|
crud = InstitutionCRUD(auth)
|
|
|
- # 查所有该企业下的有效制度
|
|
|
institutions = await crud.list(
|
|
|
search={"enterprise_id": enterprise_id, "status__ne": "INSTITUTION_DELETE"},
|
|
|
order_by=[{"id": "desc"}],
|