diff --git a/User/utils.py b/User/utils.py index d784558..920a229 100644 --- a/User/utils.py +++ b/User/utils.py @@ -3,7 +3,7 @@ """ import json from datetime import datetime -from .models import OperationLog, User, Team, Approval +from .models import OperationLog, User, Team, Approval, Department def is_department_id(value): """ @@ -64,6 +64,50 @@ def format_personincharge(value, is_department=False): return str(value).strip() +def get_finance_personincharge_candidates(): + """ + 获取财务部抄送的负责人标识列表,优先使用部门ID,其次回退字符串“财务”。 + 返回按优先级去重的字符串列表,便于 personincharge 匹配和查询。 + """ + candidates = [] + try: + finance_dept_ids = Department.objects.filter( + is_deleted=False, + username__icontains="财务" + ).values_list("id", flat=True) + candidates.extend([str(dept_id) for dept_id in finance_dept_ids]) + except Exception: + pass + + # 回退保留原有字符串标识,兼容历史数据 + candidates.append("财务") + + # 去重保持顺序 + uniq = [] + seen = set() + for item in candidates: + if item is None: + continue + item_str = str(item) + if item_str not in seen: + uniq.append(item_str) + seen.add(item_str) + return uniq + + +def get_finance_personincharge_value(): + """获取优先的财务抄送标识(用于写入 personincharge)。""" + candidates = get_finance_personincharge_candidates() + return candidates[0] if candidates else "财务" + + +def is_finance_personincharge(value): + """判断 personincharge 是否表示财务部门抄送(部门ID或“财务”字符串)。""" + if value is None: + return False + return str(value) in get_finance_personincharge_candidates() + + def log_operation(request, operation_type, module, action, target_type, target_id=None, target_name=None, old_data=None, new_data=None, remark=None): """ @@ -517,8 +561,8 @@ def process_approval_flow(approval, business_record, current_approver, state, return True, None - # 检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + # 检查当前是否已经是财务审核(部门ID或“财务”字符串均视为财务阶段) + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" @@ -540,11 +584,12 @@ def process_approval_flow(approval, business_record, current_approver, state, if not approvers_list: # 没有审核人列表(个人团队或直接到财务) # 如果当前不是财务,则抄送财务 - if approval.personincharge != "财务": - approval.personincharge = "财务" + if not is_finance_personincharge(approval.personincharge): + finance_personincharge = get_finance_personincharge_value() + approval.personincharge = finance_personincharge approval.state = "已抄送财务" - if "已抄送财务" not in approval.content: - approval.content = approval.content + ",已抄送财务" + if "已抄送财务" not in approval.content and "已抄送财务部" not in approval.content: + approval.content = approval.content + ",已抄送财务部" approval.save(update_fields=['state', 'personincharge', 'content']) if business_record and hasattr(business_record, 'state'): @@ -583,17 +628,18 @@ def process_approval_flow(approval, business_record, current_approver, state, else: # 最后一个审核人,抄送财务 logger.info(f"process_approval_flow: 最后一个审核人已审核,流转到财务部") - approval.personincharge = "财务" + finance_personincharge = get_finance_personincharge_value() + approval.personincharge = finance_personincharge approval.state = "已抄送财务" - if "已抄送财务" not in approval.content: - approval.content = approval.content + ",已抄送财务" + if "已抄送财务" not in approval.content and "已抄送财务部" not in approval.content: + approval.content = approval.content + ",已抄送财务部" approval.save(update_fields=['state', 'personincharge', 'content']) if business_record and hasattr(business_record, 'state'): business_record.state = "待财务处理" business_record.save(update_fields=['state']) - logger.info(f"process_approval_flow: 已抄送财务部,personincharge=财务, state=已抄送财务") + logger.info(f"process_approval_flow: 已抄送财务部,personincharge=%s, state=已抄送财务", approval.personincharge) return False, None @@ -641,11 +687,16 @@ def create_approval_with_team_logic(team_name, approvers, title, content, approv # 判断团队类型 if not team_name or not team or (team and team.team_type == 'personal'): # 个人团队或无团队:直接到财务团队审核 + finance_personincharge = get_finance_personincharge_value() + content_to_save = content + if "已抄送财务" not in content and "已抄送财务部" not in content: + content_to_save = content + ",已抄送财务部" + approval = Approval.objects.create( title=title, - content=content, + content=content_to_save, times=today, - personincharge="财务", + personincharge=finance_personincharge, state="已抄送财务", type=approval_type, user_id=str(user_id) @@ -698,7 +749,7 @@ def create_approval_with_team_logic(team_name, approvers, title, content, approv # 创建审批记录,第一个审核人 first_approver = approvers_list[0] approvers_str = ' → '.join(approvers_list) # 使用箭头表示顺序 - content_with_flow = f"{content},审批流程:{approvers_str} → 财务(按顺序审批),当前审批人:{first_approver}" + content_with_flow = f"{content},审批流程:{approvers_str} → 财务部(按顺序审批),当前审批人:{first_approver}" import logging logger = logging.getLogger(__name__) @@ -720,11 +771,16 @@ def create_approval_with_team_logic(team_name, approvers, title, content, approv else: # 找不到团队或团队类型未知,直接抄送财务 + finance_personincharge = get_finance_personincharge_value() + content_to_save = content + if "已抄送财务" not in content and "已抄送财务部" not in content: + content_to_save = content + ",已抄送财务部" + approval = Approval.objects.create( title=title, - content=content, + content=content_to_save, times=today, - personincharge="财务", + personincharge=finance_personincharge, state="已抄送财务", type=approval_type, user_id=str(user_id) diff --git a/User/views.py b/User/views.py index d0879a6..adf03fe 100644 --- a/User/views.py +++ b/User/views.py @@ -15,7 +15,13 @@ from django.contrib.sessions.backends.db import SessionStore from django.db.models import Count, Q from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from collections import defaultdict -from .utils import is_department_id, log_operation, get_approvers_from_record +from .utils import ( + is_department_id, + log_operation, + get_approvers_from_record, + is_finance_personincharge, + get_finance_personincharge_candidates, +) class CreateUserView(APIView): @@ -748,6 +754,7 @@ class roxyExhibition(APIView): # 判断用户是否是财务部人员:只通过部门名称判断 is_finance_user = '财务部' in user_department_names + finance_personincharge_candidates = get_finance_personincharge_candidates() # 构建查询条件: # personincharge字段统一规则: @@ -772,7 +779,7 @@ class roxyExhibition(APIView): # 重要:只有财务部人员才能看到财务审核的审批记录 finance_query = Q() if is_finance_user: - finance_query = Q(personincharge="财务", state="已抄送财务") + finance_query = Q(personincharge__in=finance_personincharge_candidates, state="已抄送财务") # 组合查询:部门匹配 OR 审批员匹配 OR 财务匹配(仅财务部人员) # 如果用户有部门,使用部门匹配;否则只使用审批员匹配 @@ -788,7 +795,11 @@ class roxyExhibition(APIView): logger = logging.getLogger(__name__) logger.info(f"roxyExhibition: 用户={user.username}, 部门IDs={user_department_ids_str}, 部门名称={user_department_names}") logger.info(f"roxyExhibition: 是否是财务部人员={is_finance_user} (仅通过部门名称判断)") - logger.info(f"roxyExhibition: 查询条件 - personincharge={user.username} OR personincharge=财务(已抄送财务,仅财务部) OR personincharge IN {user_department_ids_str}") + logger.info( + f"roxyExhibition: 查询条件 - personincharge={user.username} " + f"OR personincharge in 财务标识{finance_personincharge_candidates}(已抄送财务,仅财务部) " + f"OR personincharge IN {user_department_ids_str}" + ) approvals = Approval.objects.filter(query, is_deleted=False).order_by('-id') @@ -1030,7 +1041,7 @@ class approvalProcessing(APIView): return Response({'status': 'error', 'message': '用户记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) # 检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" @@ -1095,7 +1106,7 @@ class approvalProcessing(APIView): return Response({'status': 'error', 'message': '收入确认记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) # 检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" @@ -1143,7 +1154,7 @@ class approvalProcessing(APIView): return Response({'status': 'error', 'message': '调账申请记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) # 调账申请直接抄送财务,检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" @@ -1292,7 +1303,7 @@ class approvalProcessing(APIView): return Response({'status': 'error', 'message': '案件记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) # 检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" @@ -1383,7 +1394,7 @@ class approvalProcessing(APIView): return Response({'status': 'error', 'message': '用印申请记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) # 检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" @@ -1437,7 +1448,7 @@ class approvalProcessing(APIView): approval.save(update_fields=['content']) # 检查当前是否已经是财务审核 - if approval.personincharge == "财务" and approval.state == "已抄送财务": + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": # 财务部审核逻辑:财务部只需要一个人审核完即可完成 if state == "已通过": approval.state = "已通过" diff --git a/立项审核逻辑解析.md b/立项审核逻辑解析.md index 654f4b5..f0ecb7f 100644 --- a/立项审核逻辑解析.md +++ b/立项审核逻辑解析.md @@ -20,9 +20,9 @@ #### 2.1 个人团队流程 ```python -# 个人团队:直接抄送财务 +# 个人团队:直接抄送财务部(优先使用部门ID,回退“财务”) approval = Approval.objects.create( - personincharge="财务", + personincharge="<财务部部门ID或'财务'>", state="已抄送财务", type="立项登记", user_id=项目ID @@ -40,7 +40,7 @@ approval = Approval.objects.create( approval = Approval.objects.create( personincharge=第一个审核人, state="审核中", - content="审批流程:张三 → 李四 → 王五 → 财务(按顺序审批),当前审批人:张三" + content="审批流程:张三 → 李四 → 王五 → 财务部(按顺序审批),当前审批人:张三" ) # 项目状态:审核中 ``` @@ -106,6 +106,12 @@ approval = Approval.objects.create( 2. 如果未传入,从团队配置中获取审核人(`team.approvers`) 3. 如果团队没有配置审核人,返回错误 +### 4. 财务抄送(全员) + +- 财务阶段 `state="已抄送财务"`,`personincharge` 优先写入部门表中 `username` 包含“财务”的部门ID(字符串),未找到时回退 `"财务"`。 +- 代办查询支持 `personincharge` 为财务部门ID或 `"财务"`,保证财务部全员可见。 +- 审批内容会附加“已抄送财务部”提示,流程文案展示“财务部”节点。 + ## 四、立项编辑流程(EditProject类) ### 1. 编辑步骤 @@ -159,7 +165,8 @@ if state == "未通过": #### 2.2 财务审核 ```python -if approval.personincharge == "财务" and approval.state == "已抄送财务": +# personincharge 为财务部部门ID或 "财务",state 为 "已抄送财务" +if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": if state == "已通过": approval.state = "已通过" project.state = "已通过" @@ -190,8 +197,8 @@ if approval.personincharge == "财务" and approval.state == "已抄送财务": approval.state = "审核中" # 更新审批内容中的当前审批人 else: - # 最后一个审核人,抄送财务 - approval.personincharge = "财务" + # 最后一个审核人,抄送财务部(部门ID或"财务") + approval.personincharge = <财务部部门ID或"财务"> approval.state = "已抄送财务" project.state = "待财务处理" ``` @@ -332,7 +339,7 @@ Approval (审批记录) ### 示例1:个人团队 1. 创建立项:负责人属于个人团队 -2. 直接创建审批记录:`personincharge="财务"`, `state="已抄送财务"` +2. 直接创建审批记录:`personincharge="<财务部部门ID或'财务'>"`, `state="已抄送财务"` 3. 项目状态:`state="待财务处理"` 4. 财务审核通过:项目状态变为 `"已通过"` @@ -350,7 +357,7 @@ Approval (审批记录) - `personincharge="王五"`(流转到下一个) - `state="审核中"` 5. 王五审核通过: - - `personincharge="财务"`(最后一个,抄送财务) + - `personincharge="<财务部部门ID或'财务'>"`(最后一个,抄送财务部全员) - `state="已抄送财务"` - 项目状态:`state="待财务处理"` 6. 财务审核通过:项目状态变为 `"已通过"`