优化案件模块

This commit is contained in:
27942
2026-01-15 14:34:22 +08:00
parent 1baac150b4
commit c820516e77
5 changed files with 302 additions and 32 deletions

View File

@@ -15,7 +15,7 @@ from django.contrib.sessions.backends.db import SessionStore
from django.db.models import Count, Q
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from collections import defaultdict
from .utils import is_department_id, log_operation
from .utils import is_department_id, log_operation, get_approvers_from_record
class CreateUserView(APIView):
@@ -850,9 +850,10 @@ class roxyExhibition(APIView):
# 排除关联的业务记录已被删除的审批记录
exclude_conditions = Q()
# 排除 type="案件管理" 且关联的案件已被删除的审批记录
# 排除 type="案件管理" 或 "案件变更" 且关联的案件已被删除的审批记录
if deleted_case_ids_str:
exclude_conditions |= Q(type="案件管理") & Q(user_id__in=deleted_case_ids_str)
exclude_conditions |= Q(type="案件变更") & Q(user_id__in=deleted_case_ids_str)
# 排除 type="投标登记" 且关联的投标登记已被删除的审批记录
if deleted_bid_ids_str:
@@ -1321,6 +1322,61 @@ class approvalProcessing(APIView):
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
if type == "案件变更":
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)
try:
case = Case.objects.get(id=approval.user_id, is_deleted=False)
except Case.DoesNotExist:
return Response({'status': 'error', 'message': '案件记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
current_approver = approval.personincharge
if state == "未通过":
approval.state = "未通过"
case.state = "变更未通过"
approval.save(update_fields=['state'])
case.save(update_fields=['state'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
approvers_list = get_approvers_from_record(case, approval=approval)
if not approvers_list:
approval.state = "已通过"
case.state = "变更完成"
approval.save(update_fields=['state'])
case.save(update_fields=['state'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
try:
current_index = approvers_list.index(current_approver)
except ValueError:
approval.state = "已通过"
case.state = "变更完成"
approval.save(update_fields=['state'])
case.save(update_fields=['state'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
if current_index < len(approvers_list) - 1:
next_approver = approvers_list[current_index + 1]
approval.personincharge = next_approver
approval.state = "审核中"
if "当前审批人:" in approval.content:
approval.content = approval.content.replace(
f"当前审批人:{current_approver}",
f"当前审批人:{next_approver}"
)
approval.save(update_fields=['state', 'personincharge', 'content'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
approval.state = "已通过"
case.state = "变更完成"
approval.save(update_fields=['state'])
case.save(update_fields=['state'])
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
if type == "申请用印":
try:
seal_app = SealApplication.objects.get(id=approval.user_id, is_deleted=False)

View File

@@ -0,0 +1,26 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("business", "0005_add_case_project_snapshot_fields"),
]
operations = [
migrations.AddField(
model_name="case",
name="ChangeItem",
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name="case",
name="ChangeReason",
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name="case",
name="ChangeAgreement",
field=models.TextField(blank=True, null=True),
),
]

View File

@@ -54,6 +54,9 @@ class Case(models.Model):
Contractreturn = models.TextField() # 合同返还
Closingapplication = models.TextField() # 结案申请
ChangeRequest = models.CharField(max_length=100) # 变更申请
ChangeItem = models.TextField(null=True, blank=True) # 变更事项
ChangeReason = models.TextField(null=True, blank=True) # 变更原因
ChangeAgreement = models.TextField(null=True, blank=True) # 变更协议URL列表
invoice_status = models.CharField(max_length=100, default='未开票') # 已开票
paymentcollection = models.CharField(max_length=100) # 已收款
state = models.CharField(max_length=100) # 状态

View File

@@ -3,7 +3,7 @@ from rest_framework.response import Response
from rest_framework import status
import json
import ast
from User.models import User
from User.models import User, Approval
from User.utils import log_operation, normalize_approvers_param, build_missing_approvers_message
from .models import PreFiling, ProjectRegistration, Bid, Case, Invoice, Caselog, SealApplication, Warehousing, \
RegisterPlatform, Announcement, LawyerFlie, Schedule, permission, role
@@ -37,6 +37,34 @@ def get_team_name_from_responsiblefor(responsiblefor):
return None
def get_change_approvers():
"""获取变更审批人(管委会或行政部)"""
try:
approvers = (
User.objects.filter(is_deleted=False)
.filter(
Q(role__RoleName__in=["管委会", "行政部"])
| Q(department__username="行政部")
)
.distinct()
.order_by("id")
)
return [user.username for user in approvers if user.username]
except Exception:
return []
def build_change_approval_content(applicant_name, case, change_item, change_reason, agreement_urls):
agreement_display = "".join(agreement_urls) if agreement_urls else ""
return (
f"{applicant_name}提交案件变更申请,"
f"案件ID{case.id}"
f"变更事项:{change_item}"
f"变更原因:{change_reason}"
f"变更协议:{agreement_display}"
)
def build_case_approval_content(project_registration, times, change_request=False):
times_str = times or "未填写日期"
content_parts = [f"{times_str}提交了一份案件信息"]
@@ -987,6 +1015,12 @@ class caseManagement(APIView):
Contractreturn = request.FILES.getlist('Contractreturn')
Closingapplication = request.FILES.getlist('Closingapplication')
ChangeRequest = request.data.get('ChangeRequest')
ChangeItem = request.data.get('change_item') or request.data.get('ChangeItem') or ChangeRequest
ChangeReason = request.data.get('change_reason') or request.data.get('ChangeReason')
ChangeAgreement = request.FILES.getlist('ChangeAgreement') or request.FILES.getlist('change_agreement')
ChangeItem = request.data.get('change_item') or request.data.get('ChangeItem') or ChangeRequest
ChangeReason = request.data.get('change_reason') or request.data.get('ChangeReason')
ChangeAgreement = request.FILES.getlist('ChangeAgreement') or request.FILES.getlist('change_agreement')
invoice_status = request.data.get('invoice_status') # 已开票
paymentcollection = request.data.get('paymentcollection')
@@ -1020,6 +1054,7 @@ class caseManagement(APIView):
project_responsiblefor = project_registration.responsiblefor if project_registration else None
project_charge = project_registration.charge if project_registration else None
# 创建新案件(在事务内创建,防止并发重复创建)
agreement_urls = flies(ChangeAgreement) if ChangeAgreement else []
case_id = Case.objects.create(
project_id=project_id,
contract_no=project_contract_no,
@@ -1033,30 +1068,73 @@ class caseManagement(APIView):
AgencyContract=json.dumps(agency_contract_list, ensure_ascii=False),
Contractreturn=json.dumps(contract_return_list, ensure_ascii=False),
Closingapplication=json.dumps(closing_application_list, ensure_ascii=False),
ChangeRequest=ChangeRequest,
ChangeRequest=ChangeItem or ChangeRequest or "",
ChangeItem=ChangeItem,
ChangeReason=ChangeReason,
ChangeAgreement=json.dumps(agreement_urls, ensure_ascii=False) if agreement_urls else "",
invoice_status=invoice_status or '未开票',
paymentcollection=paymentcollection,
state="审核中"
)
from User.utils import create_approval_with_team_logic
team_name = get_team_name_from_responsiblefor(project_registration.responsiblefor)
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
team_name=team_name,
approvers=approvers,
title="案件管理信息提交",
content=build_case_approval_content(project_registration, times),
approval_type="案件管理",
user_id=case_id.id,
business_record=case_id,
today=times
)
if approval is None and needs_approval:
return Response({
'status': 'error',
'message': build_missing_approvers_message(team_name, approvers),
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
if ChangeItem or ChangeReason or ChangeAgreement:
if not all([ChangeItem, ChangeReason, ChangeAgreement]):
return Response({
'status': 'error',
'message': '变更申请需要填写变更事项、变更原因并上传变更协议',
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
approvers_list = get_change_approvers()
if not approvers_list:
return Response({
'status': 'error',
'message': '未找到管委会或行政部审批人,请先配置审批人',
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
applicant_name = "未知用户"
token = request.META.get('token')
if token:
try:
applicant = User.objects.get(token=token, is_deleted=False)
applicant_name = applicant.username
except User.DoesNotExist:
pass
approvers_str = "".join(approvers_list)
content = build_change_approval_content(
applicant_name, case_id, ChangeItem, ChangeReason, agreement_urls
)
content = f"{content},审批流程:{approvers_str}(按顺序审批),当前审批人:{approvers_list[0]}"
Approval.objects.create(
title="案件变更申请",
content=content,
times=times,
personincharge=approvers_list[0],
state="审核中",
type="案件变更",
user_id=str(case_id.id)
)
case_id.approvers_order = json.dumps(approvers_list, ensure_ascii=False)
case_id.state = "变更审核中"
case_id.save(update_fields=['approvers_order', 'state'])
else:
from User.utils import create_approval_with_team_logic
team_name = get_team_name_from_responsiblefor(project_registration.responsiblefor)
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
team_name=team_name,
approvers=approvers,
title="案件管理信息提交",
content=build_case_approval_content(project_registration, times),
approval_type="案件管理",
user_id=case_id.id,
business_record=case_id,
today=times
)
if approval is None and needs_approval:
return Response({
'status': 'error',
'message': build_missing_approvers_message(team_name, approvers),
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
# 创建成功,直接返回
return Response({'message': '创建成功', 'code': 0}, status=status.HTTP_200_OK)
# 如果已存在,事务结束,在事务外处理更新逻辑
@@ -1091,7 +1169,52 @@ class caseManagement(APIView):
case.Closingapplication = json.dumps(flies(Closingapplication), ensure_ascii=False)
update_fields_list.append('Closingapplication')
if ChangeRequest:
if ChangeItem or ChangeReason or ChangeAgreement:
if not all([ChangeItem, ChangeReason, ChangeAgreement]):
return Response({
'status': 'error',
'message': '变更申请需要填写变更事项、变更原因并上传变更协议',
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
case.ChangeRequest = ChangeItem or ChangeRequest or ""
case.ChangeItem = ChangeItem
case.ChangeReason = ChangeReason
agreement_urls = flies(ChangeAgreement)
case.ChangeAgreement = json.dumps(agreement_urls, ensure_ascii=False)
case.state = "变更审核中"
update_fields_list.extend(['ChangeRequest', 'ChangeItem', 'ChangeReason', 'ChangeAgreement', 'state'])
approvers_list = get_change_approvers()
if not approvers_list:
return Response({
'status': 'error',
'message': '未找到管委会或行政部审批人,请先配置审批人',
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
applicant_name = "未知用户"
token = request.META.get('token')
if token:
try:
applicant = User.objects.get(token=token, is_deleted=False)
applicant_name = applicant.username
except User.DoesNotExist:
pass
approvers_str = "".join(approvers_list)
content = build_change_approval_content(
applicant_name, case, ChangeItem, ChangeReason, agreement_urls
)
content = f"{content},审批流程:{approvers_str}(按顺序审批),当前审批人:{approvers_list[0]}"
Approval.objects.create(
title="案件变更申请",
content=content,
times=times or case.times,
personincharge=approvers_list[0],
state="审核中",
type="案件变更",
user_id=str(case.id)
)
case.approvers_order = json.dumps(approvers_list, ensure_ascii=False)
update_fields_list.append('approvers_order')
elif ChangeRequest:
case.ChangeRequest = ChangeRequest
case.state = "审核中"
update_fields_list.extend(['ChangeRequest', 'state'])
@@ -1289,7 +1412,10 @@ class caseManagementDetail(APIView):
"AgencyContract": info.AgencyContract, # 代理合同
"Contractreturn": info.Contractreturn, # 合同返还
"Closingapplication": info.Closingapplication, # 结案申请
"ChangeRequest": info.ChangeRequest, # 变更申请
"ChangeRequest": info.ChangeRequest, # 变更申请(兼容旧字段)
"ChangeItem": info.ChangeItem,
"ChangeReason": info.ChangeReason,
"ChangeAgreement": info.ChangeAgreement,
"invoice_status": info.invoice_status, # 已开票
"paymentcollection": info.paymentcollection, # 已收款
"state": info.state,
@@ -1359,7 +1485,53 @@ class EditCase(APIView):
case.Closingapplication = json.dumps(flies(Closingapplication), ensure_ascii=False)
update_fields_list.append('Closingapplication')
if ChangeRequest:
if ChangeItem or ChangeReason or ChangeAgreement:
if not all([ChangeItem, ChangeReason, ChangeAgreement]):
return Response({
'status': 'error',
'message': '变更申请需要填写变更事项、变更原因并上传变更协议',
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
agreement_urls = flies(ChangeAgreement)
case.ChangeRequest = ChangeItem if ChangeItem else ChangeRequest
case.ChangeItem = ChangeItem
case.ChangeReason = ChangeReason
case.ChangeAgreement = json.dumps(agreement_urls, ensure_ascii=False)
case.state = "变更审核中"
update_fields_list.extend(['ChangeRequest', 'ChangeItem', 'ChangeReason', 'ChangeAgreement', 'state'])
approvers_list = get_change_approvers()
if not approvers_list:
return Response({
'status': 'error',
'message': '未找到管委会或行政部审批人,请先配置审批人',
'code': 1
}, status=status.HTTP_400_BAD_REQUEST)
applicant_name = "未知用户"
token = request.META.get('token')
if token:
try:
applicant = User.objects.get(token=token, is_deleted=False)
applicant_name = applicant.username
except User.DoesNotExist:
pass
approvers_str = "".join(approvers_list)
content = build_change_approval_content(
applicant_name, case, ChangeItem, ChangeReason, agreement_urls
)
content = f"{content},审批流程:{approvers_str}(按顺序审批),当前审批人:{approvers_list[0]}"
Approval.objects.create(
title="案件变更申请",
content=content,
times=times or case.times,
personincharge=approvers_list[0],
state="审核中",
type="案件变更",
user_id=str(case.id)
)
case.approvers_order = json.dumps(approvers_list, ensure_ascii=False)
update_fields_list.append('approvers_order')
elif ChangeRequest:
case.ChangeRequest = ChangeRequest
case.state = "审核中"
update_fields_list.extend(['ChangeRequest', 'state'])

View File

@@ -231,7 +231,7 @@ token: {用户token}
**请求头:**
```
Content-Type: application/json
Content-Type: multipart/form-data
token: {用户token}
```
@@ -789,18 +789,23 @@ token: {用户token}
| AgencyContract | File[] | 否 | 代理合同文件 |
| Contractreturn | File[] | 否 | 合同返还文件 |
| Closingapplication | File[] | 否 | 结案申请文件 |
| ChangeRequest | String | 否 | 变更申请(如果传入会触发审核流程 |
| change_item / ChangeItem | String | 否 | 变更事项(律师申请时必填 |
| change_reason / ChangeReason | String | 否 | 变更原因(律师申请时必填) |
| ChangeAgreement | File[] | 否 | 变更协议文件(律师申请时必填) |
| invoice_status | String | 否 | 已开票状态(默认:未开票) |
| paymentcollection | String | 否 | 已收款金额 |
| approvers | Array/String | 否 | 审核人列表团队类型时需要推荐ID数组兼容用户名数组/逗号字符串) |
| personincharge | String | 否 | 审核人兼容旧接口会转为approvers |
**说明:** 若提交变更申请,需同时填写变更事项、变更原因并上传变更协议。
**请求示例:**
```json
{
"project_id": 1,
"times": "2024-01-15",
"ChangeRequest": "需要变更代理方案",
"change_item": "代理方案变更",
"change_reason": "客户要求调整代理范围",
"invoice_status": "已开票",
"paymentcollection": "50000"
}
@@ -979,7 +984,10 @@ token: {用户token}
"AgencyContract": "[\"http://example.com/agency.pdf\"]",
"Contractreturn": "[\"http://example.com/return.pdf\"]",
"Closingapplication": "[\"http://example.com/closing.pdf\"]",
"ChangeRequest": "需要变更代理方案",
"ChangeRequest": "代理方案变更",
"ChangeItem": "代理方案变更",
"ChangeReason": "客户要求调整代理范围",
"ChangeAgreement": "[\"http://example.com/change-agreement.pdf\"]",
"invoice_status": "已开票",
"paymentcollection": "50000",
"state": "审核中",
@@ -1013,17 +1021,22 @@ token: {用户token}
| AgencyContractUrls / agency_contract_urls | String/Array | 否 | 代理合同URL列表JSON数组字符串/逗号分隔/数组) |
| ContractreturnUrls / contractreturn_urls | String/Array | 否 | 合同返还URL列表JSON数组字符串/逗号分隔/数组) |
| ClosingapplicationUrls / closingapplication_urls | String/Array | 否 | 结案申请URL列表JSON数组字符串/逗号分隔/数组) |
| ChangeRequest | String | 否 | 变更申请(如果传入会触发审核流程 |
| change_item / ChangeItem | String | 否 | 变更事项(律师申请时必填 |
| change_reason / ChangeReason | String | 否 | 变更原因(律师申请时必填) |
| ChangeAgreement | File[] | 否 | 变更协议文件(律师申请时必填) |
| invoice_status | String | 否 | 已开票状态 |
| paymentcollection | String | 否 | 已收款金额 |
| approvers | Array/String | 否 | 审核人列表团队类型时需要推荐ID数组兼容用户名数组/逗号字符串) |
| personincharge | String | 否 | 审核人兼容旧接口会转为approvers |
**说明:** 若提交变更申请,需同时填写变更事项、变更原因并上传变更协议。
**请求示例:**
```json
{
"id": 1,
"ClosingapplicationUrls": "[\"http://example.com/closing.pdf\"]",
"change_item": "代理方案变更",
"change_reason": "客户要求调整代理范围",
"invoice_status": "已开票",
"paymentcollection": "60000"
}
@@ -1395,7 +1408,7 @@ token: {用户token}
3. **合同编号必须唯一**,不能重复
4. **案件创建后会自动关联立项登记**,无法修改关联关系
5. **删除立项登记前**,需要先删除关联的案件
6. **变更申请会触发审核流程**,需要提供审核人
6. **变更申请会触发审核流程**:由管委会或行政部审批,同意后完成变更;需填写变更事项、变更原因并上传变更协议
7. **文件上传支持多文件**返回的是JSON字符串格式的URL数组
8. **投标登记创建时会触发审核流程**,团队类型需要提供审核人
9. **负责人信息格式**