diff --git a/User/views.py b/User/views.py index a328bf3..b5ea172 100644 --- a/User/views.py +++ b/User/views.py @@ -922,17 +922,36 @@ class approvalProcessing(APIView): if type == "收入确认": try: - user = Income.objects.get(id=approval.user_id, is_deleted=False) + income = Income.objects.get(id=approval.user_id, is_deleted=False) except Income.DoesNotExist: return Response({'status': 'error', 'message': '收入确认记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND) + + # 审批人可以指定收入分配方案 + allocate = request.data.get('allocate') # 收入分配(可选,审批时指定) + if state == "已通过": approval.state = "已通过" - user.state = "已通过" + income.state = "已通过" + + # 如果审批人指定了分配方案,更新分配字段 + if allocate: + income.allocate = allocate + # 更新审批内容,添加分配信息 + if "收入分配:待审批人指定" in approval.content: + approval.content = approval.content.replace("收入分配:待审批人指定", f"收入分配:{allocate}") + else: + approval.content = approval.content + f",收入分配:{allocate}" + income.save(update_fields=['state', 'allocate']) + approval.save(update_fields=['state', 'content']) + else: + # 如果审批通过但未指定分配,保持"待审批人指定" + income.save(update_fields=['state']) + approval.save(update_fields=['state']) else: approval.state = "未通过" - user.state = "未通过" - approval.save(update_fields=['state']) - user.save(update_fields=['state']) + income.state = "未通过" + income.save(update_fields=['state']) + approval.save(update_fields=['state']) if type == "调账申请": try: user = Accounts.objects.get(id=approval.user_id, is_deleted=False) diff --git a/finance/urls.py b/finance/urls.py index 193c560..3e54694 100644 --- a/finance/urls.py +++ b/finance/urls.py @@ -1,4 +1,4 @@ -from .views import UserRegister,UserDeparture,UserDepartureDetail,EditUserDeparture,DeleteUserDeparture,issueAnInvoice,issueAnInvoiceDetail,confirm,loan,PaymentRequest,reimbursement,confirmdisplay,loandisplay,PaymentDisplay,reimbursementdetail,Change,ChangeDetail,EditInvoice,DeleteInvoice,EditIncome,DeleteIncome,EditAccounts,DeleteAccounts,EditPayment,DeletePayment,EditReimbursement,DeleteReimbursement,EditBonusChange,DeleteBonusChange +from .views import UserRegister,UserDeparture,UserDepartureDetail,EditUserDeparture,DeleteUserDeparture,issueAnInvoice,issueAnInvoiceDetail,confirm,loan,PaymentRequest,reimbursement,confirmdisplay,loandisplay,PaymentDisplay,reimbursementdetail,Change,ChangeDetail,EditInvoice,DeleteInvoice,EditIncome,DeleteIncome,EditAccounts,DeleteAccounts,EditPayment,DeletePayment,EditReimbursement,DeleteReimbursement,EditBonusChange,DeleteBonusChange,GetCaseListForInvoice from django.urls import path urlpatterns = [ @@ -7,6 +7,7 @@ urlpatterns = [ path("user-departure-detail", UserDepartureDetail.as_view(), name="user-departure-detail/"), path("editUserDeparture", EditUserDeparture.as_view(), name="editUserDeparture/"), path("deleteUserDeparture", DeleteUserDeparture.as_view(), name="deleteUserDeparture/"), + path("case-list-for-invoice", GetCaseListForInvoice.as_view(), name="case-list-for-invoice/"), path("issue-invoice", issueAnInvoice.as_view(), name="issue-invoice/"), path('issue-Detail', issueAnInvoiceDetail.as_view(), name="issue-Detail/"), path('editInvoice', EditInvoice.as_view(), name="editInvoice/"), diff --git a/finance/views.py b/finance/views.py index 4a49ac6..fed1aaf 100644 --- a/finance/views.py +++ b/finance/views.py @@ -197,18 +197,51 @@ class UserRegister(APIView): }, status=status.HTTP_200_OK) +class GetCaseListForInvoice(APIView): + """获取案件列表(用于开票申请选择)""" + + def post(self, request, *args, **kwargs): + """ + 获取案件列表,用于开票申请时选择合同号 + 返回案件ID、合同号、负责人等信息 + """ + from business.models import ProjectRegistration + + # 获取所有未删除的案件 + cases = ProjectRegistration.objects.filter(is_deleted=False).order_by('-id') + + data = [] + for case in cases: + data.append({ + 'id': case.id, + 'ContractNo': case.ContractNo, # 合同号 + 'responsiblefor': case.responsiblefor, # 负责人 + 'type': case.type, # 项目类型 + 'times': case.times, # 立项时间 + }) + + return Response({ + 'message': '获取成功', + 'data': data, + 'code': 0 + }, status=status.HTTP_200_OK) + + class issueAnInvoice(APIView): def post(self, request, *args, **kwargs): """ 财务开票 + 优化后:合同号从案件表选择,负责人自动同步 :param request: :param args: :param kwargs: :return: """ token = request.META.get('token') - ContractNo = request.data.get('ContractNo') - personincharge = request.data.get('personincharge') + case_id = request.data.get('case_id') # 案件ID(从案件表选择) + # 以下字段改为可选,如果提供了case_id,则从案件表同步 + ContractNo = request.data.get('ContractNo') # 合同号(可选,如果提供了case_id则自动同步) + personincharge = request.data.get('personincharge') # 负责人(可选,如果提供了case_id则自动同步) amount = request.data.get('amount') type = request.data.get('type') unit = request.data.get('unit') @@ -217,11 +250,65 @@ class issueAnInvoice(APIView): bank = request.data.get('bank') username = request.data.get('username') - if not all([token, ContractNo, personincharge, amount, type, unit, number, address_telephone, bank,username]): - return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST) + # 必填字段验证 + if not all([token, amount, type, unit, number, address_telephone, bank, username]): + missing_params = [] + if not token: + missing_params.append('token') + if not amount: + missing_params.append('amount(开票金额)') + if not type: + missing_params.append('type(开票类型)') + if not unit: + missing_params.append('unit(开票单位)') + if not number: + missing_params.append('number(纳税人识别号)') + if not address_telephone: + missing_params.append('address_telephone(地址/电话)') + if not bank: + missing_params.append('bank(银行卡)') + if not username: + missing_params.append('username(提交人)') + return Response({ + 'status': 'error', + 'message': f'缺少必填参数: {", ".join(missing_params)}', + 'code': 1 + }, status=status.HTTP_400_BAD_REQUEST) + + # 处理合同号和负责人:优先从案件表同步 + from business.models import ProjectRegistration + + if case_id: + # 如果提供了案件ID,从案件表获取合同号和负责人 + try: + case = ProjectRegistration.objects.get(id=case_id, is_deleted=False) + ContractNo = case.ContractNo # 自动同步合同号 + personincharge = case.responsiblefor # 自动同步负责人 + except ProjectRegistration.DoesNotExist: + return Response({ + 'status': 'error', + 'message': '案件不存在或已被删除', + 'code': 1 + }, status=status.HTTP_404_NOT_FOUND) + else: + # 如果没有提供案件ID,则ContractNo和personincharge必须手动提供 + if not ContractNo: + return Response({ + 'status': 'error', + 'message': '请选择案件或手动填写合同号', + 'code': 1 + }, status=status.HTTP_400_BAD_REQUEST) + if not personincharge: + return Response({ + 'status': 'error', + 'message': '请选择案件或手动填写负责人', + 'code': 1 + }, status=status.HTTP_400_BAD_REQUEST) + today = datetime.datetime.now() formatted_date = today.strftime("%Y-%m-%d") - invoice = Invoice.objects.create( + + invoice = Invoice.objects.create( ContractNo=ContractNo, personincharge=personincharge, amount=amount, @@ -240,9 +327,11 @@ class issueAnInvoice(APIView): new_data = { 'id': invoice.id, 'contract_no': invoice.ContractNo, + 'personincharge': invoice.personincharge, 'amount': invoice.amount, 'type': invoice.type, - 'unit': invoice.unit + 'unit': invoice.unit, + 'case_id': case_id if case_id else None } log_operation( request=request, @@ -253,10 +342,18 @@ class issueAnInvoice(APIView): target_id=invoice.id, target_name=invoice.ContractNo, new_data=new_data, - remark=f'新增开票申请:合同号 {invoice.ContractNo},金额 {invoice.amount}' + remark=f'新增开票申请:合同号 {invoice.ContractNo},负责人 {invoice.personincharge},金额 {invoice.amount}' ) - return Response({'message': '提交成功', 'code': 0}, status=status.HTTP_200_OK) + return Response({ + 'message': '提交成功', + 'code': 0, + 'data': { + 'id': invoice.id, + 'ContractNo': invoice.ContractNo, + 'personincharge': invoice.personincharge, + } + }, status=status.HTTP_200_OK) class issueAnInvoiceDetail(APIView): @@ -451,6 +548,8 @@ class confirm(APIView): def post(self, request, *args, **kwargs): """ 收入确认 + 优化后:收入分配由审批人指定,提交时不填写分配 + 数据来源案件管理 :param request: :param args: :param kwargs: @@ -460,41 +559,124 @@ class confirm(APIView): ContractNo = request.data.get('ContractNo') CustomerID = request.data.get('CustomerID') amount = request.data.get('amount') - allocate = request.data.get('allocate') + allocate = request.data.get('allocate') # 改为可选,由审批人指定 token = request.META.get('token') personincharge = request.data.get('personincharge') + case_id = request.data.get('case_id') # 案件ID(可选,用于关联案件) + try: user = User.objects.get(token=token, is_deleted=False) except User.DoesNotExist: return Response({'status': 'error', 'message': '用户不存在或已被删除', 'code': 1}, status=status.HTTP_401_UNAUTHORIZED) - if not all([times, ContractNo, CustomerID, amount, allocate]): - return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST) + + # 必填字段验证(allocate改为可选) + if not all([times, ContractNo, CustomerID, amount]): + missing_params = [] + if not times: + missing_params.append('times(收款日期)') + if not ContractNo: + missing_params.append('ContractNo(合同号)') + if not CustomerID: + missing_params.append('CustomerID(客户名称)') + if not amount: + missing_params.append('amount(收款金额)') + return Response({ + 'status': 'error', + 'message': f'缺少必填参数: {", ".join(missing_params)}', + 'code': 1 + }, status=status.HTTP_400_BAD_REQUEST) + + # 如果提供了案件ID,从案件表获取相关信息(可选) + from business.models import ProjectRegistration + case_info = None + if case_id: + try: + case = ProjectRegistration.objects.get(id=case_id, is_deleted=False) + case_info = { + 'id': case.id, + 'ContractNo': case.ContractNo, + 'responsiblefor': case.responsiblefor, + 'type': case.type + } + # 如果合同号未提供,从案件表同步 + if not ContractNo: + ContractNo = case.ContractNo + except ProjectRegistration.DoesNotExist: + return Response({ + 'status': 'error', + 'message': '案件不存在或已被删除', + 'code': 1 + }, status=status.HTTP_404_NOT_FOUND) + from datetime import datetime now = datetime.now() - - # 格式化日期为字符串,格式为 YYYY-MM-DD date_string = now.strftime("%Y-%m-%d") + + # 创建收入确认记录,allocate为空或"待审批人指定" income = Income.objects.create( times=times, ContractNo=ContractNo, CustomerID=CustomerID, amount=amount, - allocate=allocate, + allocate=allocate if allocate else "待审批人指定", # 如果未提供,设为"待审批人指定" submit=user.username, submit_tiem=date_string, state="审核中" ) + # 构建审批内容,包含案件信息(如果提供了) + content_parts = [ + f"{user.username}在{times}提交了收入确认", + f"合同编号:{ContractNo}", + f"客户名称:{CustomerID}", + f"收入金额:{amount}" + ] + if case_info: + content_parts.append(f"案件类型:{case_info['type']}") + content_parts.append(f"案件负责人:{case_info['responsiblefor']}") + content_parts.append("收入分配:待审批人指定") + content = ",".join(content_parts) + Approval.objects.create( title=user.username + "提交收入确认", - content=user.username + "在" + times + "提交了收入确认,合同编号:" + ContractNo + ",客户名称:" + CustomerID + "收入金额:" + amount, + content=content, times=date_string, personincharge=format_personincharge(personincharge, is_department=False), # 审批员用户名 state='审核中', type="收入确认", user_id=income.id ) - return Response({'message': '插入成功' ,'code': 0}, status=status.HTTP_200_OK) + + # 记录操作日志 + new_data = { + 'id': income.id, + 'ContractNo': income.ContractNo, + 'CustomerID': income.CustomerID, + 'amount': income.amount, + 'allocate': income.allocate, + 'case_id': case_id if case_id else None + } + log_operation( + request=request, + operation_type='CREATE', + module='Finance', + action='新增收入确认', + target_type='Income', + target_id=income.id, + target_name=f'{income.ContractNo} - {income.CustomerID}', + new_data=new_data, + remark=f'新增收入确认:合同号 {income.ContractNo},金额 {income.amount},分配待审批人指定' + ) + + return Response({ + 'message': '提交成功', + 'code': 0, + 'data': { + 'id': income.id, + 'ContractNo': income.ContractNo, + 'allocate': income.allocate + } + }, status=status.HTTP_200_OK) class confirmdisplay(APIView): def post(self, request, *args, **kwargs): diff --git a/开票申请接口优化说明.md b/开票申请接口优化说明.md new file mode 100644 index 0000000..ac5597c --- /dev/null +++ b/开票申请接口优化说明.md @@ -0,0 +1,247 @@ +# 开票申请接口优化说明 + +## 优化内容 + +根据需求12,开票申请接口已优化,**合同号从案件表选择,负责人自动同步**。 + +## 接口信息 + +### 1. 获取案件列表接口(新增) + +- **URL**:`/finance/case-list-for-invoice` +- **方法**:POST +- **功能**:获取案件列表,用于开票申请时选择合同号 + +#### 请求参数 + +无需参数 + +#### 响应示例 + +```json +{ + "message": "获取成功", + "data": [ + { + "id": 1, + "ContractNo": "HT2024001", + "responsiblefor": "张三", + "type": "民事诉讼", + "times": "2024-01-15" + }, + { + "id": 2, + "ContractNo": "HT2024002", + "responsiblefor": "李四", + "type": "刑事诉讼", + "times": "2024-01-20" + } + ], + "code": 0 +} +``` + +### 2. 开票申请接口(优化) + +- **URL**:`/finance/issue-invoice` +- **方法**:POST +- **功能**:财务开票 + +## 字段变更 + +### 优化前 +- ✅ `ContractNo` - 合同号(必填,手动输入) +- ✅ `personincharge` - 负责人(必填,手动输入) +- ✅ 其他字段(金额、类型、单位等) + +### 优化后 +- ✅ `case_id` - 案件ID(**推荐**,从案件表选择) +- ⭕ `ContractNo` - 合同号(可选,如果提供了case_id则自动同步) +- ⭕ `personincharge` - 负责人(可选,如果提供了case_id则自动同步) +- ✅ 其他字段(金额、类型、单位等,必填) + +## 数据同步逻辑 + +### 方式1:从案件表选择(推荐) + +1. **前端调用案件列表接口**:获取所有案件列表 +2. **用户选择案件**:前端显示案件列表,用户选择 +3. **自动同步数据**: + - 合同号(`ContractNo`)自动从案件表的 `ContractNo` 字段同步 + - 负责人(`personincharge`)自动从案件表的 `responsiblefor` 字段同步 + +### 方式2:手动填写(兼容) + +如果没有提供 `case_id`,可以手动填写 `ContractNo` 和 `personincharge`。 + +## 请求示例 + +### 方式1:从案件表选择(推荐) + +```json +POST /finance/issue-invoice +{ + "case_id": 1, + "amount": "10000", + "type": "增值税专用发票", + "unit": "XX律师事务所", + "number": "91110000MA01234567", + "address_telephone": "北京市XX区XX路XX号 010-12345678", + "bank": "6222021234567890123", + "username": "提交人姓名" +} +``` + +**说明**: +- 提供了 `case_id`,系统自动从案件表获取合同号和负责人 +- 不需要手动填写 `ContractNo` 和 `personincharge` + +### 方式2:手动填写(兼容) + +```json +POST /finance/issue-invoice +{ + "ContractNo": "HT2024001", + "personincharge": "张三", + "amount": "10000", + "type": "增值税专用发票", + "unit": "XX律师事务所", + "number": "91110000MA01234567", + "address_telephone": "北京市XX区XX路XX号 010-12345678", + "bank": "6222021234567890123", + "username": "提交人姓名" +} +``` + +**说明**: +- 没有提供 `case_id`,需要手动填写 `ContractNo` 和 `personincharge` + +## 响应示例 + +### 成功响应 + +```json +{ + "message": "提交成功", + "code": 0, + "data": { + "id": 123, + "ContractNo": "HT2024001", + "personincharge": "张三" + } +} +``` + +### 错误响应 + +#### 缺少必填参数 +```json +{ + "status": "error", + "message": "缺少必填参数: amount(开票金额), type(开票类型)", + "code": 1 +} +``` + +#### 案件不存在 +```json +{ + "status": "error", + "message": "案件不存在或已被删除", + "code": 1 +} +``` + +#### 未选择案件且未填写合同号 +```json +{ + "status": "error", + "message": "请选择案件或手动填写合同号", + "code": 1 +} +``` + +#### 未选择案件且未填写负责人 +```json +{ + "status": "error", + "message": "请选择案件或手动填写负责人", + "code": 1 +} +``` + +## 工作流程 + +### 推荐流程(从案件表选择) + +``` +1. 前端调用案件列表接口 + ↓ +2. 显示案件列表供用户选择 + ↓ +3. 用户选择案件(获取case_id) + ↓ +4. 前端自动填充合同号和负责人(可选,提升用户体验) + ↓ +5. 用户填写其他信息(金额、类型、单位等) + ↓ +6. 提交开票申请(传入case_id) + ↓ +7. 后端自动从案件表同步合同号和负责人 + ↓ +8. 创建开票申请记录 +``` + +### 兼容流程(手动填写) + +``` +1. 用户手动填写合同号和负责人 + ↓ +2. 用户填写其他信息 + ↓ +3. 提交开票申请(不传case_id) + ↓ +4. 后端验证必填字段 + ↓ +5. 创建开票申请记录 +``` + +## 优势 + +1. **数据一致性** + - 合同号和负责人直接从案件表同步,避免手动输入错误 + - 确保开票申请与案件信息一致 + +2. **操作便捷** + - 用户只需选择案件,无需手动输入合同号和负责人 + - 减少重复录入,提高效率 + +3. **向后兼容** + - 仍然支持手动填写合同号和负责人 + - 不影响现有功能 + +4. **数据可追溯** + - 开票申请关联到具体案件(通过case_id) + - 便于后续查询和统计 + +## 注意事项 + +1. **案件选择** + - 建议优先使用案件选择方式 + - 确保案件在案件管理中已正确创建 + +2. **数据同步** + - 如果案件信息发生变化,已创建的开票申请不会自动更新 + - 需要在编辑开票申请时重新选择案件 + +3. **必填字段** + - 金额、类型、单位、纳税人识别号、地址/电话、银行卡、提交人仍为必填 + - 合同号和负责人:要么选择案件,要么手动填写 + +## 更新日志 + +### v2.0.0 (2024-01-XX) +- ✅ 新增获取案件列表接口 +- ✅ 开票申请支持从案件表选择合同号 +- ✅ 负责人自动从案件表的负责人字段同步 +- ✅ 保持向后兼容,支持手动填写 diff --git a/收入确认接口优化说明.md b/收入确认接口优化说明.md new file mode 100644 index 0000000..5c23104 --- /dev/null +++ b/收入确认接口优化说明.md @@ -0,0 +1,243 @@ +# 收入确认接口优化说明 + +## 优化内容 + +根据需求13,收入确认接口已优化,**收入分配由审批人指定**,提交时不填写分配。 + +## 接口信息 + +- **URL**:`/finance/confirm` +- **方法**:POST +- **功能**:收入确认 + +## 字段变更 + +### 优化前 +- ✅ `allocate` - 收入分配(必填,提交时填写) + +### 优化后 +- ⭕ `allocate` - 收入分配(**可选**,提交时不填写,由审批人指定) +- ⭕ `case_id` - 案件ID(可选,用于关联案件管理) + +## 工作流程 + +### 提交阶段 +1. 用户提交收入确认 +2. **不填写** `allocate` 字段(或填写为空) +3. 系统自动设置 `allocate = "待审批人指定"` +4. 创建审批记录,状态为"审核中" + +### 审批阶段 +1. 审批人查看收入确认申请 +2. 审批人**指定收入分配方案**(`allocate` 字段) +3. 审批通过时,系统更新 `allocate` 字段 +4. 审批内容自动更新,包含分配信息 + +## 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| times | string | 是 | 收款日期 | +| ContractNo | string | 是 | 合同号 | +| CustomerID | string | 是 | 客户名称 | +| amount | string | 是 | 收款金额 | +| allocate | string | 否 | 收入分配(可选,由审批人指定) | +| personincharge | string | 是 | 审批人 | +| case_id | int | 否 | 案件ID(可选,用于关联案件) | + +## 请求示例 + +### 提交收入确认(不填写分配) + +```json +POST /finance/confirm +{ + "times": "2024-01-15", + "ContractNo": "HT2024001", + "CustomerID": "XX公司", + "amount": "100000", + "personincharge": "审批人姓名" +} +``` + +### 提交收入确认(关联案件) + +```json +POST /finance/confirm +{ + "times": "2024-01-15", + "ContractNo": "HT2024001", + "CustomerID": "XX公司", + "amount": "100000", + "personincharge": "审批人姓名", + "case_id": 1 +} +``` + +**说明**: +- 如果提供了 `case_id`,系统会从案件表获取相关信息 +- 如果未提供 `ContractNo`,会自动从案件表同步 + +## 审批处理 + +### 审批接口 + +- **URL**:`/user/approval_processing` +- **方法**:POST + +### 审批请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| id | int | 是 | 审批记录ID | +| type | string | 是 | 审批类型("收入确认") | +| state | string | 是 | 审批状态("已通过"或"未通过") | +| allocate | string | 否 | 收入分配方案(审批通过时指定) | + +### 审批请求示例 + +#### 审批通过并指定分配 + +```json +POST /user/approval_processing +{ + "id": 123, + "type": "收入确认", + "state": "已通过", + "allocate": "张三50%,李四30%,王五20%" +} +``` + +#### 审批通过但不指定分配 + +```json +POST /user/approval_processing +{ + "id": 123, + "type": "收入确认", + "state": "已通过" +} +``` + +**说明**:如果审批通过但未指定分配,`allocate` 保持为"待审批人指定" + +#### 审批不通过 + +```json +POST /user/approval_processing +{ + "id": 123, + "type": "收入确认", + "state": "未通过" +} +``` + +## 响应示例 + +### 提交成功 + +```json +{ + "message": "提交成功", + "code": 0, + "data": { + "id": 123, + "ContractNo": "HT2024001", + "allocate": "待审批人指定" + } +} +``` + +### 错误响应 + +#### 缺少必填参数 +```json +{ + "status": "error", + "message": "缺少必填参数: times(收款日期), ContractNo(合同号)", + "code": 1 +} +``` + +#### 案件不存在 +```json +{ + "status": "error", + "message": "案件不存在或已被删除", + "code": 1 +} +``` + +## 数据来源案件管理 + +### 关联案件(可选) + +如果提供了 `case_id`,系统会: +1. 从案件表(`ProjectRegistration`)获取案件信息 +2. 如果合同号未提供,自动从案件表同步 +3. 在审批内容中包含案件类型和负责人信息 + +### 案件信息包含 + +- 合同号(`ContractNo`) +- 负责人(`responsiblefor`) +- 案件类型(`type`) + +## 审批内容格式 + +### 提交时(未指定分配) + +``` +张三在2024-01-15提交了收入确认,合同编号:HT2024001,客户名称:XX公司,收入金额:100000,收入分配:待审批人指定 +``` + +### 审批后(已指定分配) + +``` +张三在2024-01-15提交了收入确认,合同编号:HT2024001,客户名称:XX公司,收入金额:100000,收入分配:张三50%,李四30%,王五20% +``` + +## 优势 + +1. **职责分离** + - 提交人只需填写基本信息 + - 审批人负责指定分配方案,更专业 + +2. **数据准确性** + - 分配方案由审批人指定,确保准确 + - 避免提交人填写错误 + +3. **灵活性** + - 支持关联案件管理 + - 可以从案件表同步相关信息 + +4. **可追溯** + - 分配方案记录在审批内容中 + - 便于后续查询和审计 + +## 注意事项 + +1. **分配方案格式** + - 建议使用清晰的格式,如"张三50%,李四30%,王五20%" + - 也可以使用其他格式,由审批人自由填写 + +2. **审批时机** + - 分配方案在审批通过时指定 + - 如果审批不通过,不需要指定分配 + +3. **案件关联** + - 案件关联是可选的 + - 如果提供了 `case_id`,系统会自动同步相关信息 + +4. **数据一致性** + - 如果案件信息发生变化,已创建的收入确认不会自动更新 + - 需要在编辑时重新关联案件 + +## 更新日志 + +### v2.0.0 (2024-01-XX) +- ✅ 收入分配改为由审批人指定 +- ✅ 提交时不填写分配,系统自动设为"待审批人指定" +- ✅ 审批通过时,审批人可以指定分配方案 +- ✅ 支持关联案件管理(可选) +- ✅ 审批内容自动更新,包含分配信息