优化大版本

This commit is contained in:
27942
2026-01-08 18:24:40 +08:00
parent 332505b452
commit ee46203f92
5 changed files with 717 additions and 34 deletions

View 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),
),
]

View File

@@ -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) # 软删除标记

View File

@@ -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)