优化大版本
This commit is contained in:
@@ -982,17 +982,63 @@ class approvalProcessing(APIView):
|
||||
|
||||
if type == "报销申请":
|
||||
try:
|
||||
user = Reimbursement.objects.get(id=approval.user_id, is_deleted=False)
|
||||
reimbursement = Reimbursement.objects.get(id=approval.user_id, is_deleted=False)
|
||||
except Reimbursement.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '报销申请记录不存在或已被删除', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
if state == "已通过":
|
||||
approval.state = "已通过"
|
||||
user.state = "已通过"
|
||||
# 多级审批逻辑:检查是否还有下一个审批人
|
||||
# personincharge字段存储所有审批人(用逗号分隔),当前审批人是第一个
|
||||
# 从审批内容中提取所有审批人列表
|
||||
approvers_list = []
|
||||
if "审批流程:" in approval.content:
|
||||
# 从内容中提取审批人列表
|
||||
try:
|
||||
flow_part = approval.content.split("审批流程:")[1].split("(按顺序审批)")[0]
|
||||
approvers_list = [a.strip() for a in flow_part.split(',') if a.strip()]
|
||||
except:
|
||||
# 如果解析失败,使用personincharge作为单个审批人
|
||||
approvers_list = [approval.personincharge]
|
||||
else:
|
||||
# 如果没有审批流程信息,使用personincharge作为单个审批人
|
||||
approvers_list = [approval.personincharge]
|
||||
|
||||
current_approver = approval.personincharge
|
||||
|
||||
# 找到当前审批人在列表中的位置
|
||||
try:
|
||||
current_index = approvers_list.index(current_approver)
|
||||
except ValueError:
|
||||
# 如果找不到,说明是单个审批人或格式不对,直接完成
|
||||
current_index = 0
|
||||
|
||||
# 检查是否还有下一个审批人
|
||||
if current_index < len(approvers_list) - 1:
|
||||
# 还有下一个审批人,流转到下一个
|
||||
next_approver = approvers_list[current_index + 1]
|
||||
approval.personincharge = next_approver
|
||||
approval.state = '审核中' # 继续审核中
|
||||
approval.content = approval.content.replace(
|
||||
f"当前审批人:{current_approver}",
|
||||
f"当前审批人:{next_approver}"
|
||||
) if f"当前审批人:{current_approver}" in approval.content else approval.content + f",当前审批人:{next_approver}"
|
||||
approval.save(update_fields=['state', 'personincharge', 'content'])
|
||||
reimbursement.state = "审核中"
|
||||
reimbursement.save(update_fields=['state'])
|
||||
else:
|
||||
# 最后一个审批人,审批通过后抄送财务
|
||||
approval.personincharge = "财务"
|
||||
approval.state = "已通过"
|
||||
approval.content = approval.content + ",所有审批人已通过,已抄送财务"
|
||||
approval.save(update_fields=['state', 'personincharge', 'content'])
|
||||
reimbursement.state = "待财务处理"
|
||||
reimbursement.save(update_fields=['state'])
|
||||
else:
|
||||
# 审批不通过
|
||||
approval.state = "未通过"
|
||||
user.state = "未通过"
|
||||
approval.save(update_fields=['state'])
|
||||
user.save(update_fields=['state'])
|
||||
reimbursement.state = "未通过"
|
||||
approval.save(update_fields=['state'])
|
||||
reimbursement.save(update_fields=['state'])
|
||||
|
||||
if type == "工资/奖金变更":
|
||||
try:
|
||||
|
||||
18
finance/migrations/0011_bonuschange_submitter.py
Normal file
18
finance/migrations/0011_bonuschange_submitter.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.25 on 2026-01-08 10:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0010_add_is_deleted_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bonuschange',
|
||||
name='submitter',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
]
|
||||
@@ -68,4 +68,5 @@ class BonusChange(models.Model):
|
||||
Instructions = models.TextField() # 调整说明
|
||||
times = models.CharField(max_length=100) # 时间
|
||||
state = models.CharField(max_length=100) # 状态
|
||||
submitter = models.CharField(max_length=100, null=True, blank=True) # 提交人
|
||||
is_deleted = models.BooleanField(default=False) # 软删除标记
|
||||
302
finance/views.py
302
finance/views.py
@@ -831,6 +831,7 @@ class loan(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
调账申请
|
||||
优化后:不需要指定审批人,直接抄送财务(数据来源案件管理)
|
||||
:param request:
|
||||
:param args:
|
||||
:param kwargs:
|
||||
@@ -841,20 +842,59 @@ class loan(APIView):
|
||||
CustomerID = request.data.get('CustomerID')
|
||||
amount = request.data.get('amount')
|
||||
situation = request.data.get('situation')
|
||||
personincharge = request.data.get('personincharge')
|
||||
case_id = request.data.get('case_id') # 案件ID(可选,用于关联案件)
|
||||
token = request.META.get('token')
|
||||
if not all([times, ContractNo, amount, situation,CustomerID,personincharge]):
|
||||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 移除personincharge必填验证
|
||||
if not all([times, ContractNo, amount, situation, CustomerID]):
|
||||
missing_params = []
|
||||
if not times:
|
||||
missing_params.append('times(收款日期)')
|
||||
if not ContractNo:
|
||||
missing_params.append('ContractNo(合同号)')
|
||||
if not CustomerID:
|
||||
missing_params.append('CustomerID(客户名称)')
|
||||
if not amount:
|
||||
missing_params.append('amount(收款金额)')
|
||||
if not situation:
|
||||
missing_params.append('situation(情况说明)')
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': f'缺少必填参数: {", ".join(missing_params)}',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
|
||||
# 格式化日期为字符串,格式为 YYYY-MM-DD
|
||||
date_string = now.strftime("%Y-%m-%d")
|
||||
|
||||
try:
|
||||
user = User.objects.get(token=token, is_deleted=False)
|
||||
except User.DoesNotExist:
|
||||
return Response({'status': 'error', 'message': '用户不存在或已被删除', 'code': 1}, status=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
# 如果提供了案件ID,从案件表获取相关信息(可选)
|
||||
from business.models import ProjectRegistration
|
||||
case_info = None
|
||||
if case_id:
|
||||
try:
|
||||
case = ProjectRegistration.objects.get(id=case_id, is_deleted=False)
|
||||
case_info = {
|
||||
'id': case.id,
|
||||
'ContractNo': case.ContractNo,
|
||||
'responsiblefor': case.responsiblefor,
|
||||
'type': case.type
|
||||
}
|
||||
# 如果合同号未提供,从案件表同步
|
||||
if not ContractNo:
|
||||
ContractNo = case.ContractNo
|
||||
except ProjectRegistration.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '案件不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
acc = Accounts.objects.create(
|
||||
times=times,
|
||||
ContractNo=ContractNo,
|
||||
@@ -863,18 +903,62 @@ class loan(APIView):
|
||||
situation=situation,
|
||||
submit=user.username,
|
||||
submit_tiem=date_string,
|
||||
state="审核中"
|
||||
state="待财务处理" # 直接设为待财务处理
|
||||
)
|
||||
|
||||
# 构建审批内容,包含案件信息(如果提供了)
|
||||
content_parts = [
|
||||
f"{user.username}在{times}提交了调账申请",
|
||||
f"合同编号:{ContractNo}",
|
||||
f"客户名称:{CustomerID}",
|
||||
f"收入金额:{amount}",
|
||||
f"情况说明:{situation}"
|
||||
]
|
||||
if case_info:
|
||||
content_parts.append(f"案件类型:{case_info['type']}")
|
||||
content_parts.append(f"案件负责人:{case_info['responsiblefor']}")
|
||||
content = ",".join(content_parts)
|
||||
|
||||
# 直接抄送财务,不需要审批人
|
||||
Approval.objects.create(
|
||||
title=user.username + "提交调账申请",
|
||||
content=user.username + "在" + times + "提交了调账申请,合同编号:" + ContractNo + ",客户名称:" + CustomerID + "收入金额:" + amount,
|
||||
content=content,
|
||||
times=date_string,
|
||||
personincharge=format_personincharge(personincharge, is_department=False), # 审批员用户名
|
||||
state='审核中',
|
||||
personincharge="财务", # 直接抄送财务
|
||||
state='已抄送财务', # 直接标记为已抄送财务
|
||||
type="调账申请",
|
||||
user_id=acc.id
|
||||
)
|
||||
return Response({'message': '插入成功' ,'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': acc.id,
|
||||
'ContractNo': acc.ContractNo,
|
||||
'CustomerID': acc.CustomerID,
|
||||
'amount': acc.amount,
|
||||
'case_id': case_id if case_id else None
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Finance',
|
||||
action='新增调账申请',
|
||||
target_type='Accounts',
|
||||
target_id=acc.id,
|
||||
target_name=f'{acc.ContractNo} - {acc.CustomerID}',
|
||||
new_data=new_data,
|
||||
remark=f'新增调账申请:合同号 {acc.ContractNo},金额 {acc.amount},已直接抄送财务'
|
||||
)
|
||||
|
||||
return Response({
|
||||
'message': '提交成功',
|
||||
'code': 0,
|
||||
'data': {
|
||||
'id': acc.id,
|
||||
'ContractNo': acc.ContractNo,
|
||||
'state': acc.state
|
||||
}
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
class loandisplay(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -1160,7 +1244,10 @@ class DeletePayment(APIView):
|
||||
class reimbursement(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
报销
|
||||
报销申请
|
||||
优化后:根据团队类型判断是否需要审批
|
||||
- 个人团队(personal/独立律师):不触发审批,直接抄送财务
|
||||
- 团队(team/团队律师):需要多级审批,按顺序依次审批,最后抄送财务
|
||||
:param request:
|
||||
:param args:
|
||||
:param kwargs:
|
||||
@@ -1171,30 +1258,148 @@ class reimbursement(APIView):
|
||||
reason = request.data.get('reason')
|
||||
amount = request.data.get('amount')
|
||||
FeeDescription = request.data.get('FeeDescription')
|
||||
personincharge = request.data.get('personincharge')
|
||||
if not all([person,times, reason, amount, FeeDescription, personincharge]):
|
||||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||||
approvers = request.data.get('approvers') # 审批人列表(数组,仅团队类型需要)
|
||||
token = request.META.get('token')
|
||||
|
||||
if not all([person, times, reason, amount, FeeDescription]):
|
||||
missing_params = []
|
||||
if not person:
|
||||
missing_params.append('person(报销人)')
|
||||
if not times:
|
||||
missing_params.append('times(报销日期)')
|
||||
if not reason:
|
||||
missing_params.append('reason(报销理由)')
|
||||
if not amount:
|
||||
missing_params.append('amount(报销金额)')
|
||||
if not FeeDescription:
|
||||
missing_params.append('FeeDescription(费用说明)')
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': f'缺少必填参数: {", ".join(missing_params)}',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 获取报销人的团队信息
|
||||
try:
|
||||
submitter_user = User.objects.get(username=person, is_deleted=False)
|
||||
except User.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': f'报销人"{person}"不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
from User.models import Team
|
||||
team_name = submitter_user.team
|
||||
team = None
|
||||
if team_name:
|
||||
try:
|
||||
team = Team.objects.get(name=team_name, is_deleted=False)
|
||||
except Team.DoesNotExist:
|
||||
pass
|
||||
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
date_string = now.strftime("%Y-%m-%d")
|
||||
|
||||
reim = Reimbursement.objects.create(
|
||||
person=person,
|
||||
times=times,
|
||||
reason=reason,
|
||||
amount=amount,
|
||||
FeeDescription=FeeDescription,
|
||||
submit_tiem=now.strftime("%Y-%m-%d"),
|
||||
state="审核中"
|
||||
submit_tiem=date_string,
|
||||
state="审核中" if (team and team.team_type == 'team') else "待财务处理"
|
||||
)
|
||||
Approval.objects.create(
|
||||
title=person + "报销申请",
|
||||
content=person + "在" + times + "提交了报销申请,报销理由:" + reason + ",付款金额:" + amount + ",付款日期:" + times + ",费用说明:" + FeeDescription,
|
||||
times=times,
|
||||
personincharge=format_personincharge(personincharge, is_department=False), # 审批员用户名
|
||||
state='审核中',
|
||||
type="报销申请",
|
||||
user_id=reim.id
|
||||
|
||||
# 根据团队类型判断是否需要审批
|
||||
if team and team.team_type == 'personal':
|
||||
# 个人团队(独立律师):不触发审批,直接抄送财务
|
||||
Approval.objects.create(
|
||||
title=person + "报销申请",
|
||||
content=f"{person}在{times}提交了报销申请,报销理由:{reason},付款金额:{amount},付款日期:{times},费用说明:{FeeDescription}",
|
||||
times=date_string,
|
||||
personincharge="财务", # 直接抄送财务
|
||||
state='已抄送财务', # 直接标记为已抄送财务
|
||||
type="报销申请",
|
||||
user_id=reim.id
|
||||
)
|
||||
reim.state = "待财务处理"
|
||||
reim.save(update_fields=['state'])
|
||||
else:
|
||||
# 团队类型(团队律师):需要多级审批
|
||||
if not approvers:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '团队类型需要指定审批人,请提供审批人列表',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证审批人列表
|
||||
if not isinstance(approvers, list) or len(approvers) == 0:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '审批人列表不能为空,请提供至少一个审批人',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证所有审批人是否存在
|
||||
valid_approvers = []
|
||||
for approver_name in approvers:
|
||||
try:
|
||||
approver = User.objects.get(username=approver_name, is_deleted=False)
|
||||
valid_approvers.append(approver_name)
|
||||
except User.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': f'审批人"{approver_name}"不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 创建审批记录,personincharge存储当前审批人(第一个)
|
||||
# 所有审批人信息存储在content中,用于后续流转
|
||||
all_approvers_str = ','.join(valid_approvers)
|
||||
current_approver = valid_approvers[0] # 第一个审批人
|
||||
|
||||
Approval.objects.create(
|
||||
title=person + "报销申请",
|
||||
content=f"{person}在{times}提交了报销申请,报销理由:{reason},付款金额:{amount},付款日期:{times},费用说明:{FeeDescription}。审批流程:{all_approvers_str}(按顺序审批),当前审批人:{current_approver}",
|
||||
times=date_string,
|
||||
personincharge=current_approver, # 当前审批人(第一个)
|
||||
state='审核中',
|
||||
type="报销申请",
|
||||
user_id=reim.id
|
||||
)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': reim.id,
|
||||
'person': reim.person,
|
||||
'amount': reim.amount,
|
||||
'team_type': team.team_type if team else 'unknown',
|
||||
'approvers': approvers if (team and team.team_type == 'team') else None
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Finance',
|
||||
action='新增报销申请',
|
||||
target_type='Reimbursement',
|
||||
target_id=reim.id,
|
||||
target_name=f'{reim.person} - {reim.amount}',
|
||||
new_data=new_data,
|
||||
remark=f'新增报销申请:{reim.person},金额 {reim.amount},团队类型 {team.team_type if team else "未知"}'
|
||||
)
|
||||
return Response({'message': '插入成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
return Response({
|
||||
'message': '提交成功',
|
||||
'code': 0,
|
||||
'data': {
|
||||
'id': reim.id,
|
||||
'state': reim.state,
|
||||
'needs_approval': team is None or team.team_type != 'personal'
|
||||
}
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
class reimbursementdetail(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -1312,6 +1517,7 @@ class Change(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
工资/奖金变更
|
||||
优化后:增加提交人字段,明确是谁提交的
|
||||
:param request:
|
||||
:param args:
|
||||
:param kwargs:
|
||||
@@ -1321,9 +1527,20 @@ class Change(APIView):
|
||||
type = request.data.get('type')
|
||||
Instructions = request.data.get('Instructions')
|
||||
personincharge = request.data.get('personincharge')
|
||||
token = request.META.get('token')
|
||||
|
||||
if not all([username, type, Instructions]):
|
||||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 获取提交人信息
|
||||
submitter = '未知用户'
|
||||
try:
|
||||
user = User.objects.get(token=token, is_deleted=False)
|
||||
submitter = user.username
|
||||
except User.DoesNotExist:
|
||||
# 如果token无效,使用username作为提交人(兼容旧逻辑)
|
||||
submitter = username
|
||||
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
bonus = BonusChange.objects.create(
|
||||
@@ -1331,18 +1548,46 @@ class Change(APIView):
|
||||
type=type,
|
||||
Instructions=Instructions,
|
||||
times=now.strftime("%Y-%m-%d"),
|
||||
state="审核中"
|
||||
state="审核中",
|
||||
submitter=submitter # 记录提交人
|
||||
)
|
||||
Approval.objects.create(
|
||||
title=username + "工资/奖金变更",
|
||||
content=username + "在" + now.strftime('%Y-%m-%d"') + "提交了工资/奖金变更,类型:" + type + ",调整说明:" + Instructions,
|
||||
content=f"{submitter}在{now.strftime('%Y-%m-%d')}提交了工资/奖金变更,类型:{type},调整说明:{Instructions}",
|
||||
times=now.strftime("%Y-%m-%d"),
|
||||
personincharge=format_personincharge(personincharge, is_department=False), # 审批员用户名
|
||||
state='审核中',
|
||||
type="工资/奖金变更",
|
||||
user_id=bonus.id
|
||||
)
|
||||
return Response({'message': '插入成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': bonus.id,
|
||||
'username': bonus.username,
|
||||
'type': bonus.type,
|
||||
'submitter': bonus.submitter
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
operation_type='CREATE',
|
||||
module='Finance',
|
||||
action='新增工资/奖金变更',
|
||||
target_type='BonusChange',
|
||||
target_id=bonus.id,
|
||||
target_name=f'{bonus.username} - {bonus.type}',
|
||||
new_data=new_data,
|
||||
remark=f'新增工资/奖金变更:{bonus.username},类型 {bonus.type},提交人 {bonus.submitter}'
|
||||
)
|
||||
|
||||
return Response({
|
||||
'message': '插入成功',
|
||||
'code': 0,
|
||||
'data': {
|
||||
'id': bonus.id,
|
||||
'submitter': bonus.submitter
|
||||
}
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
class ChangeDetail(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -1377,6 +1622,7 @@ class ChangeDetail(APIView):
|
||||
"type": info.type,
|
||||
"Instructions": info.Instructions,
|
||||
"username": info.username,
|
||||
"submitter": info.submitter if info.submitter else info.username, # 提交人,如果没有则使用username
|
||||
}
|
||||
data.append(itme)
|
||||
return Response({'message': '展示成功', "total": total, 'data': data, 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
372
系统变更需求14-16接口文档.md
Normal file
372
系统变更需求14-16接口文档.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# 系统变更需求14-16接口文档
|
||||
|
||||
## 需求概述
|
||||
|
||||
本文档包含以下三个需求的接口优化说明:
|
||||
- **需求14**:调账申请不需要指定审批人直接抄送财务(数据来源案件管理)
|
||||
- **需求15**:报销审批功能修改,支持多级审批和团队类型判断
|
||||
- **需求16**:工资奖金变更增加提交人字段
|
||||
|
||||
---
|
||||
|
||||
## 需求14:调账申请优化
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **URL**:`/finance/loan`
|
||||
- **方法**:POST
|
||||
- **功能**:调账申请
|
||||
|
||||
### 优化内容
|
||||
|
||||
1. **移除审批人参数**:不再需要指定 `personincharge`
|
||||
2. **直接抄送财务**:创建审批记录时,`personincharge` 设为"财务",状态设为"已抄送财务"
|
||||
3. **支持案件管理**:可选参数 `case_id`,从案件表获取相关信息
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| times | string | 是 | 收款日期 |
|
||||
| ContractNo | string | 是 | 合同号 |
|
||||
| CustomerID | string | 是 | 客户名称 |
|
||||
| amount | string | 是 | 收款金额 |
|
||||
| situation | string | 是 | 情况说明 |
|
||||
| case_id | int | 否 | 案件ID(可选,用于关联案件) |
|
||||
| token | string | 是 | 用户Token |
|
||||
|
||||
### 请求示例
|
||||
|
||||
```json
|
||||
POST /finance/loan
|
||||
{
|
||||
"times": "2024-01-15",
|
||||
"ContractNo": "HT2024001",
|
||||
"CustomerID": "XX公司",
|
||||
"amount": "100000",
|
||||
"situation": "调账说明",
|
||||
"case_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "提交成功",
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 123,
|
||||
"ContractNo": "HT2024001",
|
||||
"state": "待财务处理"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 审批记录
|
||||
|
||||
- **personincharge**:`"财务"`
|
||||
- **state**:`"已抄送财务"`
|
||||
- **说明**:不需要审批流程,直接抄送财务处理
|
||||
|
||||
---
|
||||
|
||||
## 需求15:报销审批优化
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **URL**:`/finance/reimbursement`
|
||||
- **方法**:POST
|
||||
- **功能**:报销申请
|
||||
|
||||
### 优化内容
|
||||
|
||||
1. **根据团队类型判断是否需要审批**:
|
||||
- 个人团队(personal/独立律师):不触发审批,直接抄送财务
|
||||
- 团队(team/团队律师):需要多级审批,按顺序依次审批
|
||||
|
||||
2. **多级审批流程**:
|
||||
- 支持多个审批人按顺序审批
|
||||
- 第一个审批人审批通过后,自动流转到下一个
|
||||
- 最后一个审批人审批通过后,抄送财务
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| person | string | 是 | 报销人 |
|
||||
| times | string | 是 | 报销日期 |
|
||||
| reason | string | 是 | 报销理由 |
|
||||
| amount | string | 是 | 报销金额 |
|
||||
| FeeDescription | string | 是 | 费用说明 |
|
||||
| approvers | array | 条件必填 | 审批人列表(仅团队类型必填) |
|
||||
|
||||
### 请求示例
|
||||
|
||||
#### 个人团队(不需要审批人)
|
||||
|
||||
```json
|
||||
POST /finance/reimbursement
|
||||
{
|
||||
"person": "张三",
|
||||
"times": "2024-01-15",
|
||||
"reason": "差旅费",
|
||||
"amount": "5000",
|
||||
"FeeDescription": "出差住宿和交通费用"
|
||||
}
|
||||
```
|
||||
|
||||
#### 团队(需要审批人列表)
|
||||
|
||||
```json
|
||||
POST /finance/reimbursement
|
||||
{
|
||||
"person": "李四",
|
||||
"times": "2024-01-15",
|
||||
"reason": "差旅费",
|
||||
"amount": "5000",
|
||||
"FeeDescription": "出差住宿和交通费用",
|
||||
"approvers": ["王五", "赵六", "孙七"]
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `approvers` 是数组,按顺序排列
|
||||
- 第一个审批人先审批,通过后流转到第二个,以此类推
|
||||
- 最后一个审批人审批通过后,抄送财务
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "提交成功",
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 123,
|
||||
"state": "审核中",
|
||||
"needs_approval": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 审批流程
|
||||
|
||||
#### 个人团队流程
|
||||
```
|
||||
提交报销申请
|
||||
↓
|
||||
直接抄送财务
|
||||
↓
|
||||
状态:待财务处理
|
||||
```
|
||||
|
||||
#### 团队流程(多级审批)
|
||||
```
|
||||
提交报销申请
|
||||
↓
|
||||
创建审批记录(当前审批人:第一个)
|
||||
↓
|
||||
第一个审批人审批通过
|
||||
↓
|
||||
流转到第二个审批人
|
||||
↓
|
||||
第二个审批人审批通过
|
||||
↓
|
||||
流转到第三个审批人
|
||||
↓
|
||||
...(依次流转)
|
||||
↓
|
||||
最后一个审批人审批通过
|
||||
↓
|
||||
抄送财务
|
||||
↓
|
||||
状态:待财务处理
|
||||
```
|
||||
|
||||
### 审批处理接口
|
||||
|
||||
- **URL**:`/user/approval_processing`
|
||||
- **方法**:POST
|
||||
|
||||
#### 审批请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | int | 是 | 审批记录ID |
|
||||
| type | string | 是 | 审批类型("报销申请") |
|
||||
| state | string | 是 | 审批状态("已通过"或"未通过") |
|
||||
|
||||
#### 审批请求示例
|
||||
|
||||
```json
|
||||
POST /user/approval_processing
|
||||
{
|
||||
"id": 123,
|
||||
"type": "报销申请",
|
||||
"state": "已通过"
|
||||
}
|
||||
```
|
||||
|
||||
#### 审批流转逻辑
|
||||
|
||||
1. **审批通过**:
|
||||
- 检查是否还有下一个审批人
|
||||
- 如果有:更新 `personincharge` 为下一个审批人,状态保持"审核中"
|
||||
- 如果没有:更新 `personincharge` 为"财务",状态改为"已通过",报销申请状态改为"待财务处理"
|
||||
|
||||
2. **审批不通过**:
|
||||
- 审批状态改为"未通过"
|
||||
- 报销申请状态改为"未通过"
|
||||
- 终止审批流程
|
||||
|
||||
### 错误响应
|
||||
|
||||
#### 团队类型未提供审批人
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "团队类型需要指定审批人,请提供审批人列表",
|
||||
"code": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 审批人列表为空
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "审批人列表不能为空,请提供至少一个审批人",
|
||||
"code": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 审批人不存在
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "审批人\"王五\"不存在或已被删除",
|
||||
"code": 1
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 需求16:工资奖金变更优化
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **URL**:`/finance/change`
|
||||
- **方法**:POST
|
||||
- **功能**:工资/奖金变更
|
||||
|
||||
### 优化内容
|
||||
|
||||
1. **新增提交人字段**:在 `BonusChange` 模型中添加 `submitter` 字段
|
||||
2. **自动记录提交人**:从Token获取当前登录用户,自动记录为提交人
|
||||
3. **返回提交人信息**:在查询接口中返回提交人字段
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| username | string | 是 | 用户名(变更对象) |
|
||||
| type | string | 是 | 变更类型 |
|
||||
| Instructions | string | 是 | 调整说明 |
|
||||
| personincharge | string | 是 | 审批人 |
|
||||
| token | string | 是 | 用户Token(用于获取提交人) |
|
||||
|
||||
### 请求示例
|
||||
|
||||
```json
|
||||
POST /finance/change
|
||||
{
|
||||
"username": "张三",
|
||||
"type": "工资调整",
|
||||
"Instructions": "根据绩效考核调整工资",
|
||||
"personincharge": "李四"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "插入成功",
|
||||
"code": 0,
|
||||
"data": {
|
||||
"id": 123,
|
||||
"submitter": "王五"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 查询接口
|
||||
|
||||
- **URL**:`/finance/ChangeDetail`
|
||||
- **方法**:POST
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "展示成功",
|
||||
"total": 10,
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"times": "2024-01-15",
|
||||
"type": "工资调整",
|
||||
"Instructions": "根据绩效考核调整工资",
|
||||
"username": "张三",
|
||||
"submitter": "王五"
|
||||
}
|
||||
],
|
||||
"code": 0
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `submitter` 字段显示是谁提交的变更申请
|
||||
- 如果 `submitter` 为空,则使用 `username` 作为提交人(兼容旧数据)
|
||||
|
||||
### 模型变更
|
||||
|
||||
在 `BonusChange` 模型中新增字段:
|
||||
|
||||
```python
|
||||
submitter = models.CharField(max_length=100, null=True, blank=True) # 提交人
|
||||
```
|
||||
|
||||
**注意**:需要执行数据库迁移:
|
||||
```bash
|
||||
python manage.py makemigrations
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
### 需求14:调账申请
|
||||
- ✅ 移除审批人参数
|
||||
- ✅ 直接抄送财务
|
||||
- ✅ 支持案件管理数据来源
|
||||
|
||||
### 需求15:报销审批
|
||||
- ✅ 根据团队类型判断是否需要审批
|
||||
- ✅ 个人团队:直接抄送财务
|
||||
- ✅ 团队:支持多级审批,按顺序流转
|
||||
- ✅ 最后一个审批人审批通过后抄送财务
|
||||
|
||||
### 需求16:工资奖金变更
|
||||
- ✅ 新增提交人字段
|
||||
- ✅ 自动记录提交人
|
||||
- ✅ 查询接口返回提交人信息
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2024-01-XX)
|
||||
- ✅ 需求14:调账申请优化完成
|
||||
- ✅ 需求15:报销审批多级审批功能完成
|
||||
- ✅ 需求16:工资奖金变更提交人字段完成
|
||||
Reference in New Issue
Block a user