diff --git a/finance/views.py b/finance/views.py index 22eb24c..980ad8c 100644 --- a/finance/views.py +++ b/finance/views.py @@ -1992,6 +1992,8 @@ class PaymentRequest(APIView): payee_account = request.data.get('payee_account') # 收款方银行账号 payee_bank = request.data.get('payee_bank') # 收款方开户行 payment_description = request.data.get('payment_description') # 支付说明 + payment_type = request.data.get('payment_type', '律所支付') # 支付方式(可选,保留字段,但不影响审批流程) + applicant = request.data.get('applicant') # 申请人(可选,如果前端传递则使用,否则从token获取) approvers = request.data.get('approvers') # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组) # 兼容旧接口:如果传了 personincharge,转换为 approvers personincharge = request.data.get('personincharge') @@ -2003,7 +2005,7 @@ class PaymentRequest(APIView): bankcard = request.data.get('bankcard') or payee_account BankName = request.data.get('BankName') or payee_bank - # 必填字段验证(申请人通过token获取,不需要验证) + # 必填字段验证 if not all([payment_reason or reason, amount, payee_name or payee, payee_account or bankcard, payee_bank or BankName, payment_description]): missing_params = [] if not (payment_reason or reason): @@ -2024,14 +2026,28 @@ class PaymentRequest(APIView): 'code': 1 }, status=status.HTTP_400_BAD_REQUEST) - # 从token获取申请人 + # 获取申请人:优先使用前端传递的applicant,如果没有则从token获取 + applicant_user = None token = request.META.get('token') - try: - applicant_user = User.objects.get(token=token, is_deleted=False) - applicant = applicant_user.username - except User.DoesNotExist: - return Response({'status': 'error', 'message': '用户不存在或已被删除', 'code': 1}, - status=status.HTTP_401_UNAUTHORIZED) + + if applicant: + # 如果前端传递了申请人,验证申请人是否存在 + try: + applicant_user = User.objects.get(username=applicant, is_deleted=False) + except User.DoesNotExist: + return Response({'status': 'error', 'message': '申请人不存在或已被删除', 'code': 1}, + status=status.HTTP_400_BAD_REQUEST) + else: + # 如果前端没有传递申请人,从token获取 + if not token: + return Response({'status': 'error', 'message': '缺少参数:请提供applicant或token', 'code': 1}, + status=status.HTTP_400_BAD_REQUEST) + try: + applicant_user = User.objects.get(token=token, is_deleted=False) + applicant = applicant_user.username + except User.DoesNotExist: + return Response({'status': 'error', 'message': '用户不存在或已被删除', 'code': 1}, + status=status.HTTP_401_UNAUTHORIZED) from datetime import datetime now = datetime.now() diff --git a/付款申请接口文档.md b/付款申请接口文档.md new file mode 100644 index 0000000..58758a6 --- /dev/null +++ b/付款申请接口文档.md @@ -0,0 +1,344 @@ +# 付款申请接口文档 + +## 概述 + +付款申请接口用于创建新的付款申请单。申请人可以通过前端传递,也可以从token自动获取(优先使用前端传递的申请人),审批逻辑与离职逻辑一致,根据团队类型决定是否需要审批流程。 + +## 接口地址 + +**POST** `/finance/payment-request` + +## 请求头 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| token | String | 是 | 用户认证token(用于自动获取申请人) | + +## 请求参数 + +### 必填参数 + +| 参数名 | 类型 | 说明 | +|--------|------|------| +| payment_reason | String | 付款事由 | +| amount | String | 付款金额 | +| payee_name | String | 收款方名称 | +| payee_account | String | 收款方银行账号 | +| payee_bank | String | 收款方开户行 | +| payment_description | String | 支付说明 | + +### 可选参数 + +| 参数名 | 类型 | 说明 | +|--------|------|------| +| applicant | String | 申请人(可选)
- 如果前端传递,则使用传递的申请人
- 如果前端不传递,则从token自动获取
- **推荐**:前端传递申请人,便于灵活控制 | +| times | String | 付款日期(格式:YYYY-MM-DD) | +| approvers | Array/String | 审批人列表(团队类型时需要)
- 推荐格式:用户ID数组,如 `[1, 2, 3]` 或 `["1", "2", "3"]`
- 兼容格式:用户名数组,如 `["张三", "李四", "王五"]`
- 字符串格式:逗号分隔,如 `"1,2,3"` 或 `"张三,李四,王五"` | +| payment_type | String | 支付方式(可选,默认:"律所支付")
- "律所支付"
- "自己账户支付" | + +### 兼容旧字段(可选) + +以下字段为兼容旧接口保留,建议使用新字段: + +| 参数名 | 类型 | 说明 | +|--------|------|------| +| reason | String | 付款理由(兼容字段,等同于payment_reason) | +| payee | String | 收款人(兼容字段,等同于payee_name) | +| bankcard | String | 银行卡(兼容字段,等同于payee_account) | +| BankName | String | 开户行(兼容字段,等同于payee_bank) | +| personincharge | String | 审批人(兼容字段,会自动转换为approvers) | + +## 审批逻辑 + +### 团队类型判断 + +系统会根据申请人的团队类型自动判断审批流程: + +1. **个人团队(personal/独立律师)**: + - 不触发审批流程 + - 直接抄送财务 + - 状态直接设为"已通过" + +2. **团队(team/团队律师)**: + - 需要审批流程 + - 必须提供 `approvers` 参数(审批人列表) + - 按审批人顺序依次审批 + - 最后一个审批人通过后,抄送财务 + - 状态初始为"审核中" + +3. **无团队**: + - 默认按团队类型处理(需要审批) + - 必须提供 `approvers` 参数 + +### 审批流程 + +``` +提交申请 → 审批人1 → 审批人2 → ... → 审批人N → 财务 → 完成 +``` + +- 每个审批人按顺序审核 +- 如果任一审批人拒绝,流程终止,状态设为"未通过" +- 所有审批人通过后,自动抄送财务 +- 财务查看后,状态更新为"已通过" + +## 请求示例 + +### 示例1:个人团队(不需要审批) + +```json +{ + "applicant": "张三", + "payment_reason": "案件代理费", + "amount": "10000", + "times": "2024-01-15", + "payee_name": "XX律师事务所", + "payee_account": "1234567890123456", + "payee_bank": "XX银行XX支行", + "payment_description": "支付案件代理费用" +} +``` + +**说明**: +- 前端传递了 `applicant` 参数,使用传递的申请人 +- 个人团队不需要提供 `approvers` +- 系统自动判断为个人团队,直接抄送财务 +- 状态直接设为"已通过" + +**注意**:如果不传递 `applicant`,系统会从token自动获取申请人 + +### 示例2:团队类型(需要审批) + +```json +{ + "applicant": "李四", + "payment_reason": "差旅费", + "amount": "5000", + "payee_name": "XX酒店", + "payee_account": "9876543210987654", + "payee_bank": "XX银行XX支行", + "payment_description": "支付差旅住宿费", + "approvers": [1, 2, 3] +} +``` + +**说明**: +- 前端传递了 `applicant` 参数,使用传递的申请人 +- 团队类型必须提供 `approvers` 参数 +- `approvers` 可以是用户ID数组或用户名数组 +- 系统会按顺序创建审批流程 + +### 示例3:使用用户名数组(兼容格式) + +```json +{ + "payment_reason": "办公用品采购", + "amount": "3000", + "payee_name": "XX办公用品公司", + "payee_account": "1111222233334444", + "payee_bank": "XX银行XX支行", + "payment_description": "采购办公用品", + "approvers": ["张三", "李四", "王五"] +} +``` + +### 示例4:使用字符串格式(兼容格式) + +```json +{ + "payment_reason": "案件费用", + "amount": "8000", + "payee_name": "XX公司", + "payee_account": "5555666677778888", + "payee_bank": "XX银行XX支行", + "payment_description": "支付案件相关费用", + "approvers": "1,2,3" +} +``` + +## 响应数据 + +### 成功响应 + +**HTTP状态码**:200 + +```json +{ + "message": "提交成功", + "code": 0, + "data": { + "id": 1, + "state": "审核中", + "approval_id": 10, + "needs_approval": true, + "team_type": "team", + "team_name": "XX团队" + } +} +``` + +### 响应字段说明 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| id | Integer | 付款申请记录ID | +| state | String | 付款申请状态
- "审核中":正在审批流程中
- "已通过":审批完成
- "未通过":审批被拒绝 | +| approval_id | Integer | 审批记录ID(如果创建了审批记录)
个人团队可能为null | +| needs_approval | Boolean | 是否需要审批
- `true`:需要审批(团队类型)
- `false`:不需要审批(个人团队)
**前端用这个字段判断是团队还是个人** | +| team_type | String | 团队类型
- "team":团队类型
- "personal":个人团队
- `null`:无团队
**前端用这个字段判断团队类型** | +| team_name | String | 团队名称
- 如果有团队,返回团队名称
- 如果没有团队,返回 `null` | + +### 错误响应 + +**HTTP状态码**:400/401 + +```json +{ + "status": "error", + "message": "缺少必填参数: payment_reason(付款事由), amount(付款金额)", + "code": 1 +} +``` + +## 错误码说明 + +| 错误码 | 说明 | +|--------|------| +| 1 | 参数错误或业务逻辑错误 | +| 401 | 用户认证失败(token无效或用户不存在) | + +## 常见错误 + +### 1. 缺少必填参数 + +**错误信息**:`缺少必填参数: payment_reason(付款事由), amount(付款金额)` + +**解决方案**:检查请求参数,确保所有必填字段都已提供 + +### 2. 用户不存在 + +**错误信息**:`用户不存在或已被删除` 或 `申请人不存在或已被删除` + +**解决方案**: +- 如果传递了 `applicant` 参数,检查申请人用户名是否正确 +- 如果没有传递 `applicant`,检查token是否有效,确保用户账号未被删除 + +### 2.1. 缺少申请人或token + +**错误信息**:`缺少参数:请提供applicant或token` + +**解决方案**:确保传递了 `applicant` 参数,或者请求头中包含有效的 `token` + +### 3. 缺少审批人(团队类型) + +**错误信息**:`XX团队需要指定审批人,请提供approvers参数(推荐:用户ID数组如[1,2,3],兼容:用户名数组)` + +**解决方案**: +- 如果是团队类型,必须提供 `approvers` 参数 +- 确保审批人列表不为空 +- 确保审批人用户ID或用户名正确 + +### 4. 审批人不存在 + +**错误信息**:`部分审批人不存在或已被删除` + +**解决方案**:检查审批人列表中的用户ID或用户名是否正确 + +## 前端判断逻辑 + +前端可以通过返回数据中的字段判断团队类型和是否需要审批: + +```javascript +// 判断是否需要审批 +if (response.data.needs_approval) { + // 需要审批(团队类型) + // 显示审批人选择组件 + // 要求用户填写审批人列表 +} else { + // 不需要审批(个人团队) + // 隐藏审批人选择组件 + // 直接提交即可 +} + +// 判断团队类型 +if (response.data.team_type === 'team') { + // 团队类型 + console.log('团队类型,需要审批'); +} else if (response.data.team_type === 'personal') { + // 个人团队 + console.log('个人团队,不需要审批'); +} else { + // 无团队 + console.log('无团队,默认需要审批'); +} +``` + +## 审批流程说明 + +### 1. 提交申请 + +调用 `/finance/payment-request` 接口提交付款申请。 + +### 2. 审批处理 + +审批人通过 `/user/approval_processing` 接口处理审批: + +```json +{ + "id": 10, + "type": "付款申请", + "state": "已通过" +} +``` + +### 3. 查看待办 + +审批人可以通过 `/user/roxyexhibition` 接口查看待办列表。 + +### 4. 查看申请列表 + +通过 `/finance/PaymentDisplay` 接口查看付款申请列表。 + +## 数据模型 + +### Payment 模型字段 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| payment_reason | TextField | 付款事由 | +| amount | CharField | 付款金额 | +| times | CharField | 付款日期(可选) | +| payee_name | CharField | 收款方名称 | +| payee_account | CharField | 收款方银行账号 | +| payee_bank | CharField | 收款方开户行 | +| applicant | CharField | 申请人(自动从token获取) | +| payment_description | TextField | 支付说明 | +| payment_type | CharField | 支付方式(可选) | +| submit_tiem | CharField | 提交时间 | +| state | CharField | 状态(审核中/已通过/未通过) | +| approvers_order | TextField | 审核人顺序(JSON格式) | +| is_deleted | BooleanField | 软删除标记 | + +## 注意事项 + +1. **申请人获取**: + - **推荐**:前端传递 `applicant` 参数,便于灵活控制 + - **备选**:如果不传递 `applicant`,系统会从token自动获取申请人 + - 如果传递了 `applicant`,系统会验证申请人是否存在 +2. **审批人必填**:团队类型必须提供 `approvers` 参数,否则会返回错误 +3. **审批顺序**:审批人列表的顺序就是审批顺序,请确保顺序正确 +4. **状态管理**:个人团队直接设为"已通过",团队类型初始为"审核中" +5. **兼容性**:接口支持旧字段格式,但建议使用新字段名称 + +## 相关接口 + +- **审批处理**:`POST /user/approval_processing` +- **查看待办**:`POST /user/roxyexhibition` +- **查看申请列表**:`POST /finance/PaymentDisplay` +- **编辑付款申请**:`POST /finance/editPayment` +- **删除付款申请**:`POST /finance/deletePayment` + +## 更新日志 + +- 2024-01-XX:优化接口,申请人通过token自动获取,审批逻辑与离职逻辑一致 +- 2024-01-XX:添加审批人字段,支持团队类型审批流程 +- 2024-01-XX:返回数据中添加团队类型信息,方便前端判断