haha
This commit is contained in:
@@ -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
356
立项审核逻辑解析.md
Normal 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. 财务审核通过:项目状态变为 `"已通过"`
|
||||
Reference in New Issue
Block a user