This commit is contained in:
ddrwode
2026-01-15 17:24:43 +08:00
parent 7a2adecca9
commit 1e85ae8353
2 changed files with 391 additions and 15 deletions

View File

@@ -340,43 +340,63 @@ def parse_approvers(approvers):
approvers: 审核人列表,可以是:
- 数组格式ID列表推荐[1, 2, 3] 或 ["1", "2", "3"]
- 数组格式(用户名列表,兼容):["张三", "李四", "王五"]
- JSON字符串格式ID列表"[1,2,3]"'"[1,2,3]"'
- JSON字符串格式ID列表"[1,2,3]" "[5]" '"[1,2,3]"'
- JSON字符串格式带空格"[ 5 ]""[1, 2, 3]"
- JSON字符串格式用户名列表兼容'["张三","李四","王五"]'
- 字符串格式逗号分隔的ID"1,2,3"
- 字符串格式逗号分隔的ID"1,2,3""5"
- 字符串格式(逗号分隔的用户名,兼容):"张三,李四,王五"
- None: 返回空列表
Returns:
list: 审核人用户名列表,如 ["张三", "李四", "王五"]
"""
import json
if not approvers:
return []
approvers_list = []
if isinstance(approvers, str):
# 尝试解析 JSON 字符串格式(如 "[1,2,3]" 或 '"[1,2,3]"'
# 去除首尾空格
approvers = approvers.strip()
# 如果字符串为空,返回空列表
if not approvers:
return []
# 尝试解析 JSON 字符串格式(如 "[1,2,3]" 或 "[5]" 或 '"[1,2,3]"'
try:
import json
# 先尝试直接解析 JSON
parsed = json.loads(approvers)
if isinstance(parsed, list):
approvers_list = [str(a).strip() for a in parsed if a]
else:
# 如果不是数组,可能是被双重编码的字符串,再解析一次
if isinstance(parsed, str):
try:
parsed2 = json.loads(parsed)
if isinstance(parsed2, list):
approvers_list = [str(a).strip() for a in parsed2 if a]
except:
pass
approvers_list = [str(a).strip() for a in parsed if a is not None and str(a).strip()]
elif isinstance(parsed, str):
# 如果是字符串,可能是被双重编码的JSON字符串,再解析一次
# 例如:'"[5]"' -> "[5]" -> [5]
try:
parsed2 = json.loads(parsed)
if isinstance(parsed2, list):
approvers_list = [str(a).strip() for a in parsed2 if a is not None and str(a).strip()]
elif isinstance(parsed2, (int, str)):
# 单个值,转换为列表
approvers_list = [str(parsed2).strip()]
except (json.JSONDecodeError, ValueError, TypeError):
# 双重解析失败,可能是普通字符串,按逗号分隔处理
approvers_list = [parsed.strip()] if parsed.strip() else []
elif isinstance(parsed, (int, str)):
# 单个值(数字或字符串),转换为列表
approvers_list = [str(parsed).strip()]
except (json.JSONDecodeError, ValueError, TypeError):
# JSON 解析失败,尝试按逗号分隔处理
# 例如:"1,2,3" 或 "5" 或 "张三,李四"
approvers_list = [a.strip() for a in approvers.split(',') if a.strip()]
elif isinstance(approvers, list):
# 数组格式(推荐)
approvers_list = [str(a).strip() for a in approvers if a]
approvers_list = [str(a).strip() for a in approvers if a is not None and str(a).strip()]
elif isinstance(approvers, (int, float)):
# 单个数字,转换为列表
approvers_list = [str(int(approvers))]
else:
return []

356
立项审核逻辑解析.md Normal file
View File

@@ -0,0 +1,356 @@
# 立项审核逻辑完整解析
## 一、审核流程概述
立项审核采用**基于团队类型的多级审核机制**,根据负责人所属团队的类型,决定是否需要审核人以及审核流程。
## 二、核心审核逻辑
### 1. 团队类型判断
系统根据**负责人responsible_person**所属的团队类型来决定审核流程:
- **个人团队personal**:直接抄送财务,无需审核人
- **团队team**:需要指定审核人,按顺序审核,最后抄送财务
- **无团队**:直接抄送财务
### 2. 审核流程函数
核心函数:`create_approval_with_team_logic`(位于 `User/utils.py`
#### 2.1 个人团队流程
```python
# 个人团队:直接抄送财务
approval = Approval.objects.create(
personincharge="财务",
state="已抄送财务",
type="立项登记",
user_id=项目ID
)
# 项目状态:待财务处理
```
#### 2.2 团队类型流程
```python
# 团队类型:需要审核人审核(按顺序)
# 1. 解析审核人列表(从参数或团队配置获取)
# 2. 验证审核人有效性
# 3. 将审核人顺序存储到 approvers_order 字段JSON格式
# 4. 创建审批记录,第一个审核人开始审核
approval = Approval.objects.create(
personincharge=第一个审核人,
state="审核中",
content="审批流程:张三 → 李四 → 王五 → 财务(按顺序审批),当前审批人:张三"
)
# 项目状态:审核中
```
## 三、立项创建流程Project类
### 1. 创建步骤
**接口路径**`POST /business/project`
**关键步骤**
1. **参数验证**
- 必填字段type项目类型、ContractNo合同编号、times立项日期、client_info委托人信息、party_info相对方信息、description项目简述、charge收费情况
- 负责人信息responsiblefor必须是字典格式`responsible_person` 字段必填
- 检查合同编号是否已存在
2. **获取团队信息**
```python
# 从负责人信息中获取负责人姓名
responsible_person = responsiblefor_dict.get('responsible_person')
# 查询负责人的团队
responsible_user = User.objects.get(username=responsible_person)
team_name = responsible_user.team
```
3. **创建项目记录**
```python
pro = ProjectRegistration.objects.create(
state="审核中", # 初始状态
# ... 其他字段
)
```
4. **创建审核流程**
```python
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
team_name=team_name,
approvers=approvers, # 可选,推荐格式:[1,2,3]用户ID数组
title="负责人姓名立项登记",
content="负责人信息 + 项目信息",
approval_type="立项登记",
user_id=pro.id,
business_record=pro,
today=当前日期
)
```
5. **错误处理**
- 如果 `approval is None and needs_approval`,说明缺少审核人,返回详细错误信息
### 2. 审核人参数格式
支持多种格式推荐使用用户ID数组
- **推荐**`[1, 2, 3]` 或 `["1", "2", "3"]`用户ID数组
- **兼容**`["张三", "李四", "王五"]`(用户名数组)
- **字符串**`"1,2,3"` 或 `"张三,李四,王五"`(逗号分隔)
- **JSON字符串**`"[1,2,3]"` 或 `'["张三","李四","王五"]'`
### 3. 审核人获取优先级
1. 如果传入了 `approvers` 参数,使用传入的审核人
2. 如果未传入,从团队配置中获取审核人(`team.approvers`
3. 如果团队没有配置审核人,返回错误
## 四、立项编辑流程EditProject类
### 1. 编辑步骤
**接口路径**`POST /business/editproject`
**关键步骤**
1. **参数验证**
- 不允许修改的字段type项目类型、ContractNo合同编号
- 其他字段可以修改
2. **更新项目记录**
```python
pro.state = "审核中" # 重新进入审核流程
pro.save()
```
3. **重新创建审核流程**
```python
# 重新获取团队信息
team_name = get_team_name_from_responsiblefor(responsiblefor_dict)
# 重新创建审核流程(与创建流程相同)
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(...)
```
## 五、审核处理流程approvalProcessing类
### 1. 审核处理接口
**接口路径**`POST /User/approvalProcessing`
**参数**
- `state`: "已通过" 或 "未通过"
- `type`: "立项登记"
- `id`: 审批记录ID
### 2. 审核处理逻辑
核心函数:`process_approval_flow`(位于 `User/utils.py`
#### 2.1 审核不通过
```python
if state == "未通过":
approval.state = "未通过"
project.state = "未通过"
# 审核流程结束
return True # 已完成
```
#### 2.2 财务审核
```python
if approval.personincharge == "财务" and approval.state == "已抄送财务":
if state == "已通过":
approval.state = "已通过"
project.state = "已通过"
# 审核流程结束
return True # 已完成
```
#### 2.3 团队审核流程(按顺序流转)
1. **获取审核人列表**
```python
# 从项目的 approvers_order 字段读取JSON格式
approvers_list = json.loads(project.approvers_order)
# 例如:["张三", "李四", "王五"]
```
2. **找到当前审核人位置**
```python
current_index = approvers_list.index(current_approver)
```
3. **判断是否还有下一个审核人**
```python
if current_index < len(approvers_list) - 1:
# 不是最后一个,流转到下一个审核人
next_approver = approvers_list[current_index + 1]
approval.personincharge = next_approver
approval.state = "审核中"
# 更新审批内容中的当前审批人
else:
# 最后一个审核人,抄送财务
approval.personincharge = "财务"
approval.state = "已抄送财务"
project.state = "待财务处理"
```
### 3. 审核流程状态流转
```
创建立项
审核中(第一个审核人)
审核中(第二个审核人)
...
审核中(最后一个审核人)
已抄送财务(财务审核)
已通过 / 未通过
```
## 六、审核人顺序存储
### 1. 存储位置
- **字段**`ProjectRegistration.approvers_order`
- **格式**JSON字符串如 `'["张三", "李四", "王五"]'`
### 2. 存储时机
在 `create_approval_with_team_logic` 函数中,当团队类型为 `team` 时:
```python
approvers_order_json = json.dumps(approvers_list, ensure_ascii=False)
project.approvers_order = approvers_order_json
project.save()
```
### 3. 读取方式
在 `process_approval_flow` 函数中:
```python
approvers_list = json.loads(project.approvers_order)
```
## 七、审核记录Approval模型
### 1. 关键字段
- `title`: 审批标题,如 "张三立项登记"
- `content`: 审批内容,包含审批流程和当前审批人
- `personincharge`: 当前负责人/审批人
- 审核人:用户名,如 "张三"
- 财务审核:固定为 "财务"
- `state`: 审批状态
- "审核中":正在审核
- "已抄送财务":已到财务审核阶段
- "已通过":审核通过
- "未通过":审核不通过
- `type`: 审批类型,固定为 "立项登记"
- `user_id`: 关联的项目ID字符串格式
### 2. 审批内容格式
**团队类型**
```
负责人姓名在日期办理立项登记项目类型xxx合同编号xxx负责人信息收费情况xxx审批流程张三 → 李四 → 王五 → 财务(按顺序审批),当前审批人:张三
```
**个人团队**
```
负责人姓名在日期办理立项登记项目类型xxx合同编号xxx负责人信息收费情况xxx
```
## 八、项目状态流转
```
审核中 → 待财务处理 → 已通过 / 未通过
```
- **审核中**:正在团队审核阶段
- **待财务处理**:已到财务审核阶段
- **已通过**:审核通过
- **未通过**:审核不通过
## 九、关键函数说明
### 1. `create_approval_with_team_logic`
- **位置**`User/utils.py`
- **功能**:根据团队类型创建审批记录
- **返回**`(approval对象, approvers_order_json, 是否需要审核)`
### 2. `process_approval_flow`
- **位置**`User/utils.py`
- **功能**:处理审核流程流转
- **返回**`(是否完成, 错误信息)`
### 3. `parse_approvers`
- **位置**`User/utils.py`
- **功能**:解析审核人列表(支持多种格式)
- **返回**:用户名列表
### 4. `get_approvers_from_record`
- **位置**`User/utils.py`
- **功能**:从业务记录中获取审核人列表
- **优先级**`approvers_order` 字段 > `Approval.content` 字段解析
## 十、注意事项
1. **审核人验证**:系统会自动验证审核人是否存在,过滤掉无效的审核人
2. **审核顺序**:严格按照 `approvers_order` 中的顺序进行审核
3. **财务审核**:财务部只需要一个人审核即可完成
4. **编辑重新审核**:编辑立项会重新进入审核流程,状态重置为"审核中"
5. **审核不通过**:任何阶段审核不通过,流程立即结束,项目状态变为"未通过"
6. **团队配置**:如果团队类型为 `team` 但没有配置审核人,创建时会返回错误
## 十一、数据模型关系
```
User (负责人)
↓ (team字段)
Team (团队)
↓ (team_type: personal/team)
↓ (approvers: 多对多关系)
User (审核人列表)
ProjectRegistration (项目)
↓ (approvers_order: JSON字符串)
↓ (state: 审核状态)
↓ (id → Approval.user_id)
Approval (审批记录)
↓ (personincharge: 当前审核人)
↓ (state: 审批状态)
```
## 十二、示例流程
### 示例1个人团队
1. 创建立项:负责人属于个人团队
2. 直接创建审批记录:`personincharge="财务"`, `state="已抄送财务"`
3. 项目状态:`state="待财务处理"`
4. 财务审核通过:项目状态变为 `"已通过"`
### 示例2团队类型3个审核人
1. 创建立项:负责人属于团队类型,传入审核人 `[1, 2, 3]`(对应张三、李四、王五)
2. 创建审批记录:
- `personincharge="张三"`(第一个审核人)
- `state="审核中"`
- `approvers_order='["张三", "李四", "王五"]'`
3. 张三审核通过:
- `personincharge="李四"`(流转到下一个)
- `state="审核中"`
4. 李四审核通过:
- `personincharge="王五"`(流转到下一个)
- `state="审核中"`
5. 王五审核通过:
- `personincharge="财务"`(最后一个,抄送财务)
- `state="已抄送财务"`
- 项目状态:`state="待财务处理"`
6. 财务审核通过:项目状态变为 `"已通过"`