diff --git a/User/views.py b/User/views.py index 7c84f8f..bf2a7a6 100644 --- a/User/views.py +++ b/User/views.py @@ -829,9 +829,10 @@ class roxyExhibition(APIView): deleted_income_ids = Income.objects.filter(is_deleted=True).values_list('id', flat=True) deleted_income_ids_str = [str(iid) for iid in deleted_income_ids] - # 已删除:开票不再生成待办,因此不需要过滤已删除的开票记录 - # deleted_invoice_ids = Invoice.objects.filter(is_deleted=True).values_list('id', flat=True) - # deleted_invoice_ids_str = [str(iid) for iid in deleted_invoice_ids] + # 过滤已删除的开票记录 + from finance.models import Invoice + deleted_invoice_ids = Invoice.objects.filter(is_deleted=True).values_list('id', flat=True) + deleted_invoice_ids_str = [str(iid) for iid in deleted_invoice_ids] # 获取所有已删除的调账申请ID deleted_accounts_ids = Accounts.objects.filter(is_deleted=True).values_list('id', flat=True) @@ -885,9 +886,9 @@ class roxyExhibition(APIView): if deleted_income_ids_str: exclude_conditions |= Q(type="收入确认") & Q(user_id__in=deleted_income_ids_str) - # 已删除:开票不再生成待办,因此不需要过滤 - # if deleted_invoice_ids_str: - # exclude_conditions |= Q(type="开票") & Q(user_id__in=deleted_invoice_ids_str) + # 过滤已删除的开票记录 + if deleted_invoice_ids_str: + exclude_conditions |= Q(type="开票") & Q(user_id__in=deleted_invoice_ids_str) # 排除 type="调账申请" 且关联的调账申请已被删除的审批记录 if deleted_accounts_ids_str: @@ -1114,20 +1115,42 @@ class approvalProcessing(APIView): return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK) - # 已删除:开票不再生成待办,因此不再处理开票类型的审批 - # if type == "开票": - # try: - # user = Invoice.objects.get(id=approval.user_id, is_deleted=False) - # except Invoice.DoesNotExist: - # return Response({'status': 'error', 'message': '开票记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) - # if state == "已通过": - # approval.state = "已通过" - # user.state = "已通过" - # else: - # approval.state = "未通过" - # user.state = "异常" - # approval.save(update_fields=['state']) - # user.save(update_fields=['state']) + if type == "开票": + from finance.models import Invoice + try: + invoice = Invoice.objects.get(id=approval.user_id, is_deleted=False) + except Invoice.DoesNotExist: + return Response({'status': 'error', 'message': '开票记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) + + # 检查当前是否已经是财务审核 + if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务": + # 财务部审核逻辑:财务部只需要一个人审核完即可完成 + if state == "已通过": + approval.state = "已通过" + invoice.state = "已通过" + else: + approval.state = "未通过" + invoice.state = "未通过" + invoice.save(update_fields=['state']) + approval.save(update_fields=['state']) + return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK) + + # 使用统一的审核流程处理函数 + from User.utils import process_approval_flow + current_approver = approval.personincharge + is_completed, error = process_approval_flow( + approval=approval, + business_record=invoice, + current_approver=current_approver, + state=state, + approval_type="开票", + final_state_map={"已通过": "已通过", "未通过": "未通过"} + ) + + if error: + return Response({'status': 'error', 'message': error, 'code': 1}, status=status.HTTP_400_BAD_REQUEST) + + return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK) if type == "收入确认": try: diff --git a/business/views.py b/business/views.py index 79bb144..41b0fa6 100644 --- a/business/views.py +++ b/business/views.py @@ -1608,13 +1608,15 @@ class caseManagementDetail(APIView): else: invoice_amounts[contract_no] = str(amount) - # 批量查询收入确认金额(按合同号统计) + # 批量查询收入确认金额(按合同号统计,只统计审核通过的) income_amounts = {} # 合同号 -> 总收入确认金额 if contract_nos: - # 查询所有未删除的收入确认记录(一次性查询,避免N+1问题) + # 查询所有未删除且审核通过的收入确认记录(一次性查询,避免N+1问题) + # 只统计 state="已通过" 的记录 incomes = Income.objects.filter( ContractNo__in=contract_nos, - is_deleted=False + is_deleted=False, + state="已通过" # 只统计审核通过的收入确认 ).values('ContractNo', 'amount') # 计算每个合同号的总收入确认金额 diff --git a/finance/migrations/0003_invoice_approvers_order.py b/finance/migrations/0003_invoice_approvers_order.py new file mode 100644 index 0000000..0a850ae --- /dev/null +++ b/finance/migrations/0003_invoice_approvers_order.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.25 on 2026-01-20 06:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finance', '0002_add_missing_approvers_order'), + ] + + operations = [ + migrations.AddField( + model_name='invoice', + name='approvers_order', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/finance/models.py b/finance/models.py index 54cbb8f..adb611b 100644 --- a/finance/models.py +++ b/finance/models.py @@ -13,6 +13,7 @@ class Invoice(models.Model): state = models.CharField(max_length=100) # 状态 username = models.CharField(max_length=100) # 谁提交的 times = models.TextField() # 提交时间 + approvers_order = models.TextField(null=True, blank=True) # 审核人顺序(JSON格式存储,如:["张三","李四","王五"]) is_deleted = models.BooleanField(default=False) # 软删除标记 diff --git a/finance/views.py b/finance/views.py index 399093e..53c4f87 100644 --- a/finance/views.py +++ b/finance/views.py @@ -691,6 +691,26 @@ class issueAnInvoice(APIView): today = datetime.datetime.now() formatted_date = today.strftime("%Y-%m-%d") + + # 获取提交人的团队信息(用于审核流程) + from User.models import Team + team_name = user.team + team = None + if team_name: + try: + team = Team.objects.get(name=team_name, is_deleted=False) + except Team.DoesNotExist: + pass + + # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组) + approvers = request.data.get('approvers') + # 兼容旧接口:如果传了 personincharge,转换为 approvers + personincharge_param = request.data.get('personincharge') + approvers = normalize_approvers_param(approvers, personincharge_param) + + # 根据团队类型决定初始状态 + # 如果是团队类型且需要审核,状态为"审核中";否则为"待财务处理" + initial_state = "审核中" if (team and team.team_type == 'team') else "待财务处理" invoice = Invoice.objects.create( ContractNo=ContractNo, @@ -701,11 +721,55 @@ class issueAnInvoice(APIView): number=number, address_telephone=address_telephone, bank=bank, - state="审核中", + state=initial_state, username=username, times=formatted_date, ) - # 已删除:不再创建开票待办事项 + + # 创建开票待办事项 + from User.utils import create_approval_with_team_logic, build_missing_approvers_message + + # 构建审批内容 + content_parts = [ + f"{username}在{formatted_date}提交了开票申请", + f"合同编号:{ContractNo}", + f"负责人:{personincharge}", + f"开票金额:{amount}", + f"开票类型:{type}", + f"开票单位:{unit}" + ] + content = ",".join(content_parts) + + # 使用统一的审核流程函数 + try: + approval, approvers_order_json, needs_approval = create_approval_with_team_logic( + team_name=team_name, + approvers=approvers, + title=username + "提交开票申请", + content=content, + approval_type="开票", + user_id=str(invoice.id), + business_record=invoice, + today=formatted_date + ) + except Exception as e: + # 记录异常并返回错误信息 + import logging + logger = logging.getLogger(__name__) + logger.error(f"创建开票审批失败: {str(e)}", exc_info=True) + return Response({ + 'status': 'error', + 'message': f'创建审批流程失败: {str(e)},请检查团队配置和审核人信息', + 'code': 1 + }, status=status.HTTP_400_BAD_REQUEST) + + # 如果返回None且需要审核,说明缺少审核人 + if approval is None and needs_approval: + return Response({ + 'status': 'error', + 'message': build_missing_approvers_message(team_name, approvers), + 'code': 1 + }, status=status.HTTP_400_BAD_REQUEST) # 记录操作日志 new_data = { @@ -736,6 +800,9 @@ class issueAnInvoice(APIView): 'id': invoice.id, 'ContractNo': invoice.ContractNo, 'personincharge': invoice.personincharge, + 'state': invoice.state, + 'approval_id': approval.id if approval else None, + 'needs_approval': team is None or team.team_type != 'personal' } }, status=status.HTTP_200_OK)