优化案件模块

This commit is contained in:
27942
2026-01-20 14:39:10 +08:00
parent fad9d7b595
commit b8ec7897e6
3 changed files with 636 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
from django.urls import path
from .views import CreateUserView,LoginView,EditorialStaffView,PersonnelDetailsView,DepartmentView,PersonnelListView,AddDepartment,DeleteDepartment,Personlist,roxyExhibition,approvalProcessing,personneldisplay,DeleteUser,OperationLogView,TeamView,TeamListView,AddTeam,EditTeam,DeleteTeam,ChangePasswordView
from .views import CreateUserView,LoginView,EditorialStaffView,PersonnelDetailsView,DepartmentView,PersonnelListView,AddDepartment,DeleteDepartment,Personlist,roxyExhibition,approvalProcessing,personneldisplay,DeleteUser,OperationLogView,TeamView,TeamListView,AddTeam,EditTeam,DeleteTeam,ChangePasswordView,ApprovalStatusCheck
urlpatterns = [
path('create-user',CreateUserView.as_view(),name='create-user'),
path('login',LoginView.as_view(),name='login'),
@@ -12,6 +12,7 @@ urlpatterns = [
path('personlist',Personlist.as_view(),name='Personlist'),
path('roxyexhibition',roxyExhibition.as_view(),name='roxyExhibition'),
path('approval_processing',approvalProcessing.as_view(),name='approval_processing'),
path('approval-status-check',ApprovalStatusCheck.as_view(),name='approval-status-check'),
path('personneldisplay',personneldisplay.as_view(),name='personneldisplay'),
path('deleteUser',DeleteUser.as_view(),name='deleteUser'),
path('operation-log',OperationLogView.as_view(),name='operation-log'),

View File

@@ -1048,6 +1048,7 @@ class approvalProcessing(APIView):
def post(self, request, *args, **kwargs):
"""
消除代办
财务查看时只需要传type和id不需要传state默认为查看通过
:param request:
:param args:
:param kwargs:
@@ -1057,14 +1058,21 @@ class approvalProcessing(APIView):
type = request.data.get('type')
id = request.data.get('id')
if not all([state, type, id]):
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
if not all([type, id]):
return Response({'status': 'error', 'message': '缺少参数type或id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
try:
approval = Approval.objects.get(id=id, is_deleted=False)
except Approval.DoesNotExist:
return Response({'status': 'error', 'message': '审批记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
# 财务查看逻辑如果只传了type和id没有传state且当前是财务审核则默认为查看通过
from User.utils import is_finance_personincharge
is_finance_view = False
if not state and is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务":
state = "已通过" # 财务查看默认通过
is_finance_view = True
if type == "入职财务登记":
try:
user = User.objects.get(id=approval.user_id, is_deleted=False)
@@ -1073,7 +1081,10 @@ class approvalProcessing(APIView):
# 检查当前是否已经是财务审核
if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务":
# 财务部审核逻辑:财务部只需要一个人审核完即可完成
# 财务部审核逻辑:如果只传了type和id不传state则默认为"已通过"
if not state:
state = "已通过"
if state == "已通过":
approval.state = "已通过"
user.state = "在职"
@@ -1085,6 +1096,10 @@ class approvalProcessing(APIView):
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
# 使用统一的审核流程处理函数
# 非财务查看时state参数是必填的
if not state:
return Response({'status': 'error', 'message': '缺少参数state审核状态已通过/未通过)', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
from User.utils import process_approval_flow
import logging
logger = logging.getLogger(__name__)
@@ -1124,7 +1139,10 @@ class approvalProcessing(APIView):
# 检查当前是否已经是财务审核
if is_finance_personincharge(approval.personincharge) and approval.state == "已抄送财务":
# 财务部审核逻辑:财务部只需要一个人审核完即可完成
# 财务部审核逻辑:如果只传了type和id不传state则默认为"已通过"
if not state:
state = "已通过"
if state == "已通过":
approval.state = "已通过"
invoice.state = "已通过"
@@ -1136,6 +1154,10 @@ class approvalProcessing(APIView):
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
# 使用统一的审核流程处理函数
# 非财务查看时state参数是必填的
if not state:
return Response({'status': 'error', 'message': '缺少参数state审核状态已通过/未通过)', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
from User.utils import process_approval_flow
current_approver = approval.personincharge
is_completed, error = process_approval_flow(
@@ -1169,7 +1191,11 @@ class approvalProcessing(APIView):
approval.save(update_fields=['state'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
else:
# 财务查看通过,状态保持"已通过"(已经是"已通过"
# 财务查看通过默认或不传state,状态保持"已通过"(已经是"已通过"
# 如果审批记录状态不是"已通过",更新为"已通过"(表示财务已查看)
if approval.state != "已通过":
approval.state = "已通过"
approval.save(update_fields=['state'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
# 负责人填写收入分配
@@ -1229,6 +1255,10 @@ class approvalProcessing(APIView):
income.save(update_fields=['allocate'])
# 使用统一的审核流程处理函数(兼容旧流程)
# 非财务查看时state参数是必填的
if not state:
return Response({'status': 'error', 'message': '缺少参数state审核状态已通过/未通过)', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
from User.utils import process_approval_flow
current_approver = approval.personincharge
is_completed, error = process_approval_flow(
@@ -2017,6 +2047,92 @@ class DeleteTeam(APIView):
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
class ApprovalStatusCheck(APIView):
"""查询待办是否已经审核完全通过"""
def post(self, request, *args, **kwargs):
"""
查询待办的审核状态,判断是否已经审核完全通过
:param request:
:param args:
:param kwargs:
:return:
"""
type = request.data.get('type')
id = request.data.get('id')
if not all([type, id]):
return Response({'status': 'error', 'message': '缺少参数type或id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
try:
approval = Approval.objects.get(id=id, is_deleted=False)
except Approval.DoesNotExist:
return Response({'status': 'error', 'message': '审批记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
# 获取业务记录状态
business_state = None
is_approved = False
try:
if type == "收入确认":
from finance.models import Income
try:
income = Income.objects.get(id=approval.user_id, is_deleted=False)
business_state = income.state
is_approved = (income.state == "已通过")
except Income.DoesNotExist:
pass
elif type == "开票":
from finance.models import Invoice
try:
invoice = Invoice.objects.get(id=approval.user_id, is_deleted=False)
business_state = invoice.state
is_approved = (invoice.state == "已通过")
except Invoice.DoesNotExist:
pass
elif type == "付款申请":
from finance.models import Payment
try:
payment = Payment.objects.get(id=approval.user_id, is_deleted=False)
business_state = payment.state
is_approved = (payment.state == "已通过")
except Payment.DoesNotExist:
pass
elif type == "报销申请":
from finance.models import Reimbursement
try:
reimbursement = Reimbursement.objects.get(id=approval.user_id, is_deleted=False)
business_state = reimbursement.state
is_approved = (reimbursement.state == "已完成")
except Reimbursement.DoesNotExist:
pass
elif type == "案件管理":
from business.models import Case
try:
case = Case.objects.get(id=approval.user_id, is_deleted=False)
business_state = case.state
is_approved = (case.state == "已通过")
except Case.DoesNotExist:
pass
# 可以根据需要添加其他类型
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(f"查询业务记录状态失败: {str(e)}")
return Response({
'message': '查询成功',
'code': 0,
'data': {
'approval_id': approval.id,
'approval_state': approval.state,
'business_state': business_state,
'is_approved': is_approved, # 是否已经审核完全通过
'type': type
}
}, status=status.HTTP_200_OK)
class ChangePasswordView(APIView):
"""修改密码接口"""

View File

@@ -0,0 +1,513 @@
# 财务查看功能使用说明
## 概述
收入确认在抄送财务时,状态已经是"已通过",财务只是查看,不需要再次审核。如果财务发现问题,可以标记为"未通过"。
## 审批接口
**接口地址:** `POST /user/approval_processing`
**接口描述:** 处理审批待办,支持审核通过、审核未通过等操作。
### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| token | String | 是 | 用户认证token请求头 |
| id | Integer | 是 | 审批记录ID从待办列表获取 |
| type | String | 是 | 审批类型,收入确认为 `"收入确认"` |
| state | String | 否 | 审核状态:`"已通过"``"未通过"`<br/>**财务查看时可不传**(默认为"已通过"<br/>**非财务审核时必填** |
| allocate | String | 否 | 收入分配(仅当状态为"待负责人填写分配"时必填) |
### 请求示例
#### 1. 财务查看收入确认(默认通过,推荐方式)
```json
{
"id": 10,
"type": "收入确认"
}
```
**说明:**
- 财务查看时,只需要传 `id``type`,不需要传 `state`
- 系统会自动判断:如果是财务查看(`personincharge` 为财务且 `state` 为"已抄送财务"),默认 `state``"已通过"`
- 接口会直接返回成功,状态保持"已通过"(因为已经是"已通过"
#### 2. 财务标记为未通过(发现问题)
```json
{
"id": 10,
"type": "收入确认",
"state": "未通过"
}
```
**说明:**
- 如果财务发现问题,需要传 `state: "未通过"`
- 接口会将收入确认状态更新为"未通过"
- 审批记录状态也会更新为"未通过"
#### 3. 负责人填写收入分配
```json
{
"id": 10,
"type": "收入确认",
"state": "已通过",
"allocate": "50%分配给A50%分配给B"
}
```
**说明:**
- 当收入确认状态为"待负责人填写分配"时,负责人必须填写 `allocate` 字段
- 填写后,状态自动变为"已通过",并抄送财务
- 财务收到时状态已经是"已通过",财务只是查看
### 返回数据
**成功响应:**
```json
{
"message": "处理成功",
"code": 0
}
```
**失败响应:**
```json
{
"status": "error",
"message": "收入确认记录不存在或已被删除",
"code": 1
}
```
---
## 查询待办审核状态
**接口地址:** `POST /user/approval-status-check`
**接口描述:** 查询待办是否已经审核完全通过,用于前端判断待办状态。
### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| token | String | 是 | 用户认证token请求头 |
| id | Integer | 是 | 审批记录ID |
| type | String | 是 | 审批类型,如 `"收入确认"``"开票"` 等 |
### 请求示例
```json
{
"id": 10,
"type": "收入确认"
}
```
### 返回数据
**成功响应:**
```json
{
"message": "查询成功",
"code": 0,
"data": {
"approval_id": 10,
"approval_state": "已抄送财务",
"business_state": "已通过",
"is_approved": true,
"type": "收入确认"
}
}
```
### 字段说明
- **approval_id**审批记录ID
- **approval_state**:审批记录状态(审核中/已抄送财务/已通过/未通过)
- **business_state**:业务记录状态(如收入确认的状态)
- **is_approved**:是否已经审核完全通过
- `true`:业务记录状态为"已通过"(或"已完成"
- `false`:业务记录状态不是"已通过"
- **type**:审批类型
---
## 获取待办列表
**接口地址:** `POST /user/roxyexhibition`
**接口描述:** 获取当前用户的待办列表,包括收入确认的待办事项。
### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| token | String | 是 | 用户认证token请求头 |
| page | Integer | 是 | 页码从1开始 |
| per_page | Integer | 是 | 每页数量 |
| type | String | 否 | 筛选类型,如 `"收入确认"` |
### 请求示例
```json
{
"page": 1,
"per_page": 10,
"type": "收入确认"
}
```
### 返回数据
**成功响应:**
```json
{
"message": "展示成功",
"total": 5,
"code": 0,
"data": [
{
"id": 10,
"title": "张三提交收入确认",
"content": "张三在2024-01-15提交了收入确认合同编号HT2024001客户名称某某公司收款金额10000收入分配待负责人指定已抄送财务部",
"times": "2024-01-15",
"personincharge": "财务",
"state": "已抄送财务",
"type": "收入确认",
"user_id": "1"
}
]
}
```
### 字段说明
- **id**审批记录ID用于调用审批处理接口
- **type**:审批类型,收入确认为 `"收入确认"`
- **state**:审批状态
- `"审核中"`:正在审核中
- `"已抄送财务"`:已抄送财务,财务可以查看
- `"已通过"`:审核通过
- `"未通过"`:审核未通过
- **personincharge**:当前负责人
- 如果是财务部门ID或"财务",表示已抄送财务
- **user_id**关联的业务记录ID收入确认记录ID
---
## 财务查看流程
### 场景1个人团队提交的收入确认
1. **提交阶段**
- 用户提交收入确认
- 状态直接设为 `"已通过"`
- 直接抄送财务,审批状态为 `"已抄送财务"`
2. **财务查看**
- 财务在待办列表中看到该收入确认
- 调用审批接口,`state``"已通过"`(表示查看通过)
- 接口直接返回成功,状态保持 `"已通过"`
3. **财务发现问题**
- 如果财务发现问题,调用审批接口,`state``"未通过"`
- 收入确认状态更新为 `"未通过"`
- 审批记录状态也更新为 `"未通过"`
### 场景2团队类型提交的收入确认
1. **提交阶段**
- 用户提交收入确认
- 状态为 `"审核中"`
- 创建待办事项,第一个审核人审核
2. **审核阶段**
- 审核人依次审核(按顺序)
- 所有审核人通过后,状态变为 `"待负责人填写分配"`
3. **负责人填写分配**
- 负责人调用审批接口,填写 `allocate` 字段
- 状态自动变为 `"已通过"`
- 抄送财务,审批状态为 `"已抄送财务"`
4. **财务查看**
- 财务在待办列表中看到该收入确认
- 调用审批接口,`state``"已通过"`(表示查看通过)
- 接口直接返回成功,状态保持 `"已通过"`
---
## 代码示例
### 前端调用示例JavaScript
```javascript
// 1. 获取待办列表
async function getTodoList(page = 1, perPage = 10) {
const response = await fetch('/user/roxyexhibition', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': localStorage.getItem('token')
},
body: JSON.stringify({
page: page,
per_page: perPage,
type: '收入确认' // 可选,筛选收入确认类型
})
});
const data = await response.json();
return data;
}
// 2. 查询待办审核状态(判断是否已审核通过)
async function checkApprovalStatus(approvalId, type = '收入确认') {
const response = await fetch('/user/approval-status-check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': localStorage.getItem('token')
},
body: JSON.stringify({
id: approvalId,
type: type
})
});
const data = await response.json();
return data;
}
// 3. 财务查看通过(默认操作,推荐方式)
async function financeViewPass(approvalId, type = '收入确认') {
const response = await fetch('/user/approval_processing', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': localStorage.getItem('token')
},
body: JSON.stringify({
id: approvalId,
type: type
// 不传state财务查看时默认为"已通过"
})
});
const data = await response.json();
return data;
}
// 4. 财务标记为未通过(发现问题)
async function financeMarkReject(approvalId, type = '收入确认') {
const response = await fetch('/user/approval_processing', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': localStorage.getItem('token')
},
body: JSON.stringify({
id: approvalId,
type: type,
state: '未通过' // 财务发现问题,标记为未通过
})
});
const data = await response.json();
return data;
}
// 5. 负责人填写收入分配
async function fillAllocate(approvalId, allocate) {
const response = await fetch('/user/approval_processing', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': localStorage.getItem('token')
},
body: JSON.stringify({
id: approvalId,
type: '收入确认',
state: '已通过',
allocate: allocate // 收入分配,如:"50%分配给A50%分配给B"
})
});
const data = await response.json();
return data;
}
```
---
## 状态说明
### 收入确认状态Income.state
| 状态 | 说明 | 何时出现 |
|------|------|----------|
| `"审核中"` | 正在审核中 | 团队类型,审核人正在审核 |
| `"待负责人填写分配"` | 待负责人填写收入分配 | 所有审核人通过后 |
| `"已通过"` | 审核通过 | 抄送财务时就已经是"已通过",财务只是查看 |
| `"未通过"` | 审核未通过 | 审核人未通过或财务发现问题 |
### 审批记录状态Approval.state
| 状态 | 说明 | 何时出现 |
|------|------|----------|
| `"审核中"` | 正在审核中 | 审核人正在审核 |
| `"已抄送财务"` | 已抄送财务 | 抄送财务时(收入确认状态已经是"已通过" |
| `"已通过"` | 审批通过 | 财务查看通过或审批完成 |
| `"未通过"` | 审批未通过 | 审核人未通过或财务标记为未通过 |
---
## 注意事项
1. **财务查看逻辑**
- 抄送财务时,收入确认状态已经是 `"已通过"`
- 财务调用审批接口时,`state``"已通过"` 表示查看通过,不会改变状态
- 只有财务标记为 `"未通过"` 时,才会改变状态
2. **权限判断**
- 接口会自动判断当前用户是否是财务部门
- 只有财务部门的人员才能看到 `personincharge` 为财务的待办
3. **状态流转**
- 个人团队:提交 → `"已通过"` → 抄送财务
- 团队类型:提交 → `"审核中"``"待负责人填写分配"``"已通过"` → 抄送财务
4. **金额统计**
- 只有状态为 `"已通过"` 的收入确认才会计入金额统计
- 抄送财务时已经是 `"已通过"`,所以会立即计入统计
---
## 完整流程示例
### 示例1个人团队提交收入确认
```javascript
// 1. 用户提交收入确认
const submitResponse = await fetch('/finance/confirm', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': userToken
},
body: JSON.stringify({
case_id: 123,
times: '2024-01-15',
amount: '10000'
})
});
// 返回:{ state: "已通过", approval_id: 10 }
// 2. 财务获取待办列表
const todoList = await getTodoList(1, 10);
// 财务看到:{ id: 10, type: "收入确认", state: "已抄送财务", personincharge: "财务" }
// 3. 财务查看通过
const viewResponse = await financeViewPass(10);
// 返回:{ message: "处理成功", code: 0 }
// 收入确认状态保持 "已通过"
```
### 示例2团队类型提交收入确认
```javascript
// 1. 用户提交收入确认
const submitResponse = await fetch('/finance/confirm', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': userToken
},
body: JSON.stringify({
case_id: 123,
times: '2024-01-15',
amount: '10000',
approvers: [1, 2, 3] // 审核人列表
})
});
// 返回:{ state: "审核中", approval_id: 10 }
// 2. 审核人1审核通过
await fetch('/user/approval_processing', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': approver1Token
},
body: JSON.stringify({
id: 10,
type: '收入确认',
state: '已通过'
})
});
// 3. 审核人2审核通过
// ...(同上)
// 4. 审核人3审核通过后状态变为 "待负责人填写分配"
// 5. 负责人填写收入分配
await fillAllocate(10, '50%分配给A50%分配给B');
// 返回:{ state: "已通过" },已抄送财务
// 6. 查询待办审核状态
const statusResponse = await checkApprovalStatus(10, '收入确认');
// 返回:{ is_approved: true, business_state: "已通过" }
// 7. 财务查看通过只需要传id和type
await financeViewPass(10, '收入确认');
// 返回:{ message: "处理成功", code: 0 }
```
---
## 接口地址汇总
| 接口 | 地址 | 说明 |
|------|------|------|
| 获取待办列表 | `POST /user/roxyexhibition` | 获取当前用户的待办事项 |
| 查询待办审核状态 | `POST /user/approval-status-check` | 查询待办是否已经审核完全通过 |
| 审批处理 | `POST /user/approval_processing` | 处理审批待办(审核通过/未通过)<br/>**财务查看时只需传id和type** |
| 新增收入确认 | `POST /finance/confirm` | 创建收入确认记录 |
| 收入确认列表 | `POST /finance/confirmdisplay` | 查询收入确认列表 |
---
## 常见问题
### Q1: 财务如何知道哪些收入确认需要查看?
**A:** 财务在待办列表接口中,筛选 `type="收入确认"``state="已抄送财务"` 的记录。
### Q2: 财务查看时,`state` 参数应该传什么?
**A:**
- **推荐方式**:不传 `state` 参数,只传 `id``type`,系统会自动判断为财务查看通过
- 如果发现问题,传 `state: "未通过"`,状态会更新为 `"未通过"`
### Q3: 收入确认什么时候状态变为"已通过"
**A:**
- 个人团队:提交时就是 `"已通过"`
- 团队类型:负责人填写收入分配后,状态变为 `"已通过"`,然后抄送财务
### Q4: 财务可以修改收入确认的金额吗?
**A:** 不可以。财务只能查看,如果发现问题,可以标记为 `"未通过"`。如果需要修改,应该联系提交人重新提交。
### Q5: 如何判断当前用户是否是财务?
**A:** 系统会自动判断:
- 用户的部门包含"财务部"
- 用户的角色包含"财务部"
- 审批记录的 `personincharge` 是财务部门ID或"财务"字符串