2486 lines
95 KiB
Python
2486 lines
95 KiB
Python
from rest_framework.views import APIView
|
||
from rest_framework.response import Response
|
||
from rest_framework import status
|
||
import json
|
||
import ast
|
||
from User.models import User, Approval, Department
|
||
from User.utils import format_personincharge, log_operation
|
||
import datetime
|
||
from .models import Invoice, Income, Accounts, Payment, Reimbursement, BonusChange
|
||
from utility.utility import flies
|
||
from django.contrib.sessions.backends.db import SessionStore
|
||
from django.db.models import Count, Q
|
||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||
from business.models import PreFiling
|
||
|
||
|
||
class UserRegister(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
入职财务登记
|
||
优化后:只需填写姓名、入职时间、工资三个字段
|
||
其他数据(身份证、岗位等)从人事管理同步
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
username = request.data.get('username')
|
||
Dateofjoining = request.data.get('Dateofjoining')
|
||
salary = request.data.get('salary')
|
||
# 以下字段改为可选,如果未提供则从人事管理同步
|
||
card = request.data.get('card') # 身份证(可选)
|
||
position = request.data.get('position') # 岗位(可选)
|
||
approvers = request.data.get('approvers') # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组)
|
||
# 兼容旧接口:如果传了 personincharge,转换为 approvers
|
||
personincharge = request.data.get('personincharge')
|
||
if personincharge and not approvers:
|
||
# 兼容旧接口:将单个 personincharge 转换为 approvers 数组
|
||
approvers = [personincharge] if personincharge else None
|
||
|
||
# 调试日志:记录传入的 approvers 格式
|
||
if approvers:
|
||
import logging
|
||
logger = logging.getLogger(__name__)
|
||
logger.debug(f"UserRegister - approvers 原始值: {approvers}, 类型: {type(approvers)}")
|
||
|
||
print(approvers)
|
||
print(type(approvers))
|
||
|
||
# 只验证必填字段:姓名、入职时间、工资
|
||
if not all([username, Dateofjoining, salary]):
|
||
missing_params = []
|
||
if not username:
|
||
missing_params.append('username(姓名)')
|
||
if not Dateofjoining:
|
||
missing_params.append('Dateofjoining(入职时间)')
|
||
if not salary:
|
||
missing_params.append('salary(工资)')
|
||
return Response({
|
||
'status': 'error',
|
||
'message': f'缺少必填参数: {", ".join(missing_params)}',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 验证日期格式
|
||
try:
|
||
Dateofjoinings = datetime.datetime.strptime(Dateofjoining, "%Y-%m-%d")
|
||
except ValueError:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '入职时间格式错误,请使用YYYY-MM-DD格式',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 查找用户(必须已存在于人事管理中)
|
||
try:
|
||
user = User.objects.get(username=username, is_deleted=False)
|
||
except User.DoesNotExist:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '用户不存在,请先在人事管理中创建该用户',
|
||
'code': 1
|
||
}, status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 从人事管理同步其他数据(如果入职登记未提供)
|
||
# 如果提供了card或position,则使用提供的值;否则使用人事管理中的值
|
||
# 团队信息始终从人事管理中获取,不在财务登记中修改
|
||
update_fields = []
|
||
|
||
# 更新必填字段
|
||
user.Dateofjoining = Dateofjoinings
|
||
user.salary = salary
|
||
update_fields.extend(['Dateofjoining', 'salary'])
|
||
|
||
# 处理可选字段:如果提供了则更新,否则保持人事管理中的值
|
||
if card:
|
||
user.card = card
|
||
update_fields.append('card')
|
||
# 如果未提供card,使用人事管理中的card(已存在,无需更新)
|
||
|
||
if position:
|
||
user.position = position
|
||
update_fields.append('position')
|
||
# 如果未提供position,使用人事管理中的position(已存在,无需更新)
|
||
|
||
# 更新状态
|
||
user.state = "待确认"
|
||
update_fields.append('state')
|
||
|
||
# 保存用户信息
|
||
user.save(update_fields=update_fields)
|
||
|
||
# 从人事管理中获取团队信息(团队信息不在财务登记中修改)
|
||
team_name = user.team # 用户的团队名称(从人事管理中获取)
|
||
team = None
|
||
team_type_display = None
|
||
if team_name:
|
||
try:
|
||
from User.models import Team
|
||
team = Team.objects.get(name=team_name, is_deleted=False)
|
||
team_type_display = team.get_team_type_display()
|
||
except Team.DoesNotExist:
|
||
# 如果团队不存在,默认按团队类型处理(需要审批)
|
||
pass
|
||
|
||
# 构建审批内容(使用实际的值,包括从人事管理同步的)
|
||
actual_card = card if card else (user.card if user.card else '未填写')
|
||
actual_position = position if position else (user.position if user.position else '未填写')
|
||
actual_team = team_name if team_name else '未分配团队'
|
||
|
||
today = datetime.datetime.now()
|
||
formatted_date = today.strftime("%Y-%m-%d")
|
||
|
||
# 根据团队类型判断是否需要审批,使用统一的审核流程函数
|
||
from User.utils import create_approval_with_team_logic, parse_approvers
|
||
|
||
# 构建审批内容
|
||
content_parts = [
|
||
f"{username}在{Dateofjoining}办理入职",
|
||
f"身份证:{actual_card}",
|
||
f"岗位:{actual_position}",
|
||
f"团队:{actual_team}"
|
||
]
|
||
if team_type_display:
|
||
content_parts.append(f"团队类型:{team_type_display}")
|
||
content_parts.append(f"薪资:{salary}")
|
||
content = ",".join(content_parts)
|
||
|
||
# 使用统一的审核流程函数
|
||
try:
|
||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||
team_name=team_name,
|
||
approvers=approvers,
|
||
title=username + "入职财务登记",
|
||
content=content,
|
||
approval_type="入职财务登记",
|
||
user_id=str(user.id),
|
||
business_record=user, # User对象没有approvers_order字段,但可以更新state
|
||
today=formatted_date
|
||
)
|
||
except Exception as e:
|
||
# 记录异常并返回错误信息
|
||
import logging
|
||
logger = logging.getLogger(__name__)
|
||
logger.error(f"创建入职财务登记审批失败: {str(e)}", exc_info=True)
|
||
return Response({
|
||
'status': 'error',
|
||
'message': f'创建审批流程失败: {str(e)},请检查团队配置和审核人信息',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 如果返回None且需要审核,说明缺少审核人
|
||
if approval is None and needs_approval:
|
||
# 检查团队是否配置了审核人
|
||
team_has_approvers = False
|
||
team_approvers_list = []
|
||
team_approvers_valid = []
|
||
if team and team.team_type == 'team':
|
||
team_approvers = team.approvers.filter(is_deleted=False)
|
||
team_has_approvers = team_approvers.exists()
|
||
if team_has_approvers:
|
||
team_approvers_list = [approver.username for approver in team_approvers]
|
||
# 验证团队配置的审核人是否有效
|
||
for approver_name in team_approvers_list:
|
||
if User.objects.filter(username=approver_name, is_deleted=False).exists():
|
||
team_approvers_valid.append(approver_name)
|
||
|
||
# 检查传入的审核人是否存在
|
||
approvers_list = []
|
||
if approvers:
|
||
from User.utils import parse_approvers
|
||
approvers_list = parse_approvers(approvers)
|
||
# 验证审核人是否存在
|
||
invalid_approvers = []
|
||
for approver_name in approvers_list:
|
||
if not User.objects.filter(username=approver_name, is_deleted=False).exists():
|
||
invalid_approvers.append(approver_name)
|
||
|
||
if invalid_approvers:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': f'审核人不存在或已被删除: {", ".join(invalid_approvers)},请检查审核人是否有效',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 构建错误信息
|
||
if team_has_approvers:
|
||
if approvers_list:
|
||
# 传入了审核人但可能有问题(这种情况不应该发生,因为已经验证过了)
|
||
error_message = '团队类型需要指定有效的审核人,请检查传入的approvers参数中的审核人是否有效'
|
||
else:
|
||
# 团队已配置审核人,但可能审核人不存在或已被删除
|
||
if team_approvers_valid:
|
||
# 团队有有效的审核人,但 create_approval_with_team_logic 返回了 None
|
||
# 这可能是其他原因导致的,提供通用错误信息
|
||
error_message = f'创建审批流程失败,请检查团队"{team_name}"配置。团队当前配置的审核人:{", ".join(team_approvers_valid)}'
|
||
else:
|
||
# 团队配置的审核人都无效
|
||
error_message = f'团队"{team_name}"配置的审核人无效或已被删除。团队当前配置的审核人:{", ".join(team_approvers_list) if team_approvers_list else "无"}。请在前端传递approvers参数(推荐格式:[用户ID数组],如[1,2,3])或为团队重新配置有效的审核人'
|
||
else:
|
||
# 团队未配置审核人
|
||
error_message = f'团队类型需要指定审核人。团队"{team_name}"未配置审核人,请在前端传递approvers参数(推荐格式:[用户ID数组],如[1,2,3])或为团队配置审核人'
|
||
|
||
return Response({
|
||
'status': 'error',
|
||
'message': error_message,
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 记录操作日志(包含从人事管理获取的团队信息)
|
||
new_data = {
|
||
'user_id': user.id,
|
||
'username': user.username,
|
||
'card': user.card,
|
||
'position': user.position,
|
||
'team': team_name, # 从人事管理中获取的团队名称
|
||
'team_type': team_type_display if team else None, # 团队类型显示名称
|
||
'salary': user.salary,
|
||
'Dateofjoining': Dateofjoining,
|
||
'state': user.state
|
||
}
|
||
log_operation(
|
||
request=request,
|
||
operation_type='CREATE',
|
||
module='Finance',
|
||
action='新增入职财务登记',
|
||
target_type='User',
|
||
target_id=user.id,
|
||
target_name=user.username,
|
||
new_data=new_data,
|
||
remark=f'新增入职财务登记:{user.username},入职时间 {Dateofjoining},薪资 {salary},团队 {team_name if team_name else "未分配"}'
|
||
)
|
||
|
||
return Response({
|
||
'message': '登记成功',
|
||
'code': 0,
|
||
'data': {
|
||
'username': user.username,
|
||
'Dateofjoining': Dateofjoining,
|
||
'salary': salary,
|
||
'card': user.card, # 返回实际使用的身份证(从人事管理同步)
|
||
'position': user.position, # 返回实际使用的岗位(从人事管理同步)
|
||
'team': team_name, # 返回团队名称(从人事管理中获取)
|
||
'team_type': team_type_display if team else None, # 返回团队类型(从人事管理中获取)
|
||
}
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class RegisteredUserList(APIView):
|
||
"""查询已入职登记的用户列表"""
|
||
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
查询已完成入职财务登记的用户
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
page = request.data.get('page', 1)
|
||
per_page = request.data.get('per_page', 10)
|
||
username = request.data.get('username', '') # 用户名搜索
|
||
department = request.data.get('department', '') # 部门搜索
|
||
|
||
if not all([page, per_page]):
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '缺少参数:页码和每页数量不能为空',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 获取所有已完成入职登记的用户ID(状态为"已通过"的入职财务登记)
|
||
completed_registration_user_ids = Approval.objects.filter(
|
||
type="入职财务登记",
|
||
state="已通过",
|
||
is_deleted=False
|
||
).values_list('user_id', flat=True)
|
||
|
||
# 将user_id转换为整数列表(因为user_id是CharField存储的字符串)
|
||
# 同时验证用户是否被软删除,只保留未删除的用户ID
|
||
completed_user_ids = []
|
||
for user_id_str in completed_registration_user_ids:
|
||
try:
|
||
user_id = int(user_id_str)
|
||
# 验证用户是否存在且未被软删除
|
||
if User.objects.filter(id=user_id, is_deleted=False).exists():
|
||
completed_user_ids.append(user_id)
|
||
except (ValueError, TypeError):
|
||
continue
|
||
|
||
# 查询条件:已完成入职登记的用户
|
||
# 只查询未软删除的用户
|
||
Q_obj = Q(is_deleted=False)
|
||
|
||
# 只查询已完成入职登记的用户
|
||
if completed_user_ids:
|
||
Q_obj &= Q(id__in=completed_user_ids)
|
||
else:
|
||
# 如果没有已完成入职登记的用户,返回空列表
|
||
return Response({
|
||
'message': '查询成功',
|
||
'total': 0,
|
||
'data': [],
|
||
'code': 0
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
# 排除admin用户(超级管理员)
|
||
Q_obj &= ~Q(username='admin')
|
||
Q_obj &= ~Q(account='admin')
|
||
|
||
# 用户名搜索
|
||
if username:
|
||
Q_obj &= Q(username__icontains=username)
|
||
|
||
# 部门搜索
|
||
if department:
|
||
Q_obj &= Q(department__username__icontains=department)
|
||
|
||
# 查询用户
|
||
users = User.objects.prefetch_related('department', 'role').filter(Q_obj).order_by('-id')
|
||
total = users.count()
|
||
|
||
# 分页
|
||
paginator = Paginator(users, per_page)
|
||
try:
|
||
users_page = paginator.page(page)
|
||
except PageNotAnInteger:
|
||
users_page = paginator.page(1)
|
||
except EmptyPage:
|
||
users_page = paginator.page(paginator.num_pages)
|
||
|
||
data = []
|
||
for user in users_page.object_list:
|
||
# 获取入职登记的审批记录信息
|
||
approval = Approval.objects.filter(
|
||
type="入职财务登记",
|
||
user_id=str(user.id),
|
||
state="已通过",
|
||
is_deleted=False
|
||
).order_by('-id').first()
|
||
|
||
data.append({
|
||
'id': user.id,
|
||
'username': user.username,
|
||
'account': user.account,
|
||
'card': user.card,
|
||
'position': user.position,
|
||
'mobilePhone': user.mobilePhone,
|
||
'department': list(user.department.values('id', 'username')),
|
||
'role': list(user.role.values('id', 'RoleName', 'permissionId')),
|
||
'team': user.team,
|
||
'Dateofjoining': user.Dateofjoining.strftime("%Y-%m-%d") if user.Dateofjoining else None,
|
||
'salary': user.salary,
|
||
'state': user.state,
|
||
'registration_date': approval.times.strftime("%Y-%m-%d") if approval and approval.times else None,
|
||
# 入职登记日期
|
||
'approval_id': approval.id if approval else None
|
||
})
|
||
|
||
return Response({
|
||
'message': '查询成功',
|
||
'total': total,
|
||
'data': data,
|
||
'code': 0
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class UnregisteredUserList(APIView):
|
||
"""查询未入职登记的用户列表"""
|
||
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
查询在人事管理中已创建,但还没有完成入职财务登记的用户
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
page = request.data.get('page', 1)
|
||
per_page = request.data.get('per_page', 10)
|
||
username = request.data.get('username', '') # 用户名搜索
|
||
department = request.data.get('department', '') # 部门搜索
|
||
|
||
if not all([page, per_page]):
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '缺少参数:页码和每页数量不能为空',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 获取所有已完成入职登记的用户ID(状态为"已通过"的入职财务登记)
|
||
completed_registration_user_ids = Approval.objects.filter(
|
||
type="入职财务登记",
|
||
state="已通过",
|
||
is_deleted=False
|
||
).values_list('user_id', flat=True)
|
||
|
||
# 将user_id转换为整数列表(因为user_id是CharField存储的字符串)
|
||
# 同时验证用户是否被软删除,只保留未删除的用户ID
|
||
completed_user_ids = []
|
||
for user_id_str in completed_registration_user_ids:
|
||
try:
|
||
user_id = int(user_id_str)
|
||
# 验证用户是否存在且未被软删除
|
||
if User.objects.filter(id=user_id, is_deleted=False).exists():
|
||
completed_user_ids.append(user_id)
|
||
except (ValueError, TypeError):
|
||
continue
|
||
|
||
# 查询条件:在人事管理中,但不在已完成入职登记的用户列表中
|
||
# 只查询未软删除的用户
|
||
Q_obj = Q(is_deleted=False)
|
||
|
||
# 排除已完成入职登记的用户
|
||
if completed_user_ids:
|
||
Q_obj &= ~Q(id__in=completed_user_ids)
|
||
|
||
# 排除admin用户(超级管理员)
|
||
Q_obj &= ~Q(username='admin')
|
||
Q_obj &= ~Q(account='admin')
|
||
|
||
# 用户名搜索
|
||
if username:
|
||
Q_obj &= Q(username__icontains=username)
|
||
|
||
# 部门搜索
|
||
if department:
|
||
Q_obj &= Q(department__username__icontains=department)
|
||
|
||
# 查询用户
|
||
users = User.objects.prefetch_related('department', 'role').filter(Q_obj).order_by('-id')
|
||
total = users.count()
|
||
|
||
# 分页
|
||
paginator = Paginator(users, per_page)
|
||
try:
|
||
users_page = paginator.page(page)
|
||
except PageNotAnInteger:
|
||
users_page = paginator.page(1)
|
||
except EmptyPage:
|
||
users_page = paginator.page(paginator.num_pages)
|
||
|
||
# 批量获取所有用户的团队信息,优化查询性能
|
||
from User.models import Team
|
||
team_names = [user.team for user in users_page.object_list if user.team]
|
||
teams_dict = {}
|
||
if team_names:
|
||
teams = Team.objects.prefetch_related('approvers').filter(
|
||
name__in=team_names,
|
||
is_deleted=False
|
||
)
|
||
for team in teams:
|
||
teams_dict[team.name] = team
|
||
|
||
# 批量获取所有用户的待审核入职登记,优化查询性能
|
||
user_ids = [user.id for user in users_page.object_list]
|
||
pending_approvals_dict = {}
|
||
if user_ids:
|
||
pending_approvals = Approval.objects.filter(
|
||
type="入职财务登记",
|
||
user_id__in=[str(uid) for uid in user_ids],
|
||
state="审核中",
|
||
is_deleted=False
|
||
)
|
||
for approval in pending_approvals:
|
||
try:
|
||
user_id = int(approval.user_id)
|
||
if user_id not in pending_approvals_dict:
|
||
pending_approvals_dict[user_id] = approval
|
||
except (ValueError, TypeError):
|
||
continue
|
||
|
||
data = []
|
||
for user in users_page.object_list:
|
||
# 检查是否有待审核的入职登记(状态为"审核中")
|
||
pending_approval = pending_approvals_dict.get(user.id)
|
||
|
||
# 获取完整的团队信息
|
||
team_info = None
|
||
if user.team:
|
||
team = teams_dict.get(user.team)
|
||
if team:
|
||
team_info = {
|
||
'id': team.id,
|
||
'name': team.name,
|
||
'team_type': team.team_type,
|
||
'team_type_display': team.get_team_type_display(), # 个人团队/团队
|
||
'description': team.description,
|
||
'approvers': list(team.approvers.filter(is_deleted=False).values('id', 'username'))
|
||
}
|
||
else:
|
||
# 如果团队不存在,只返回团队名称
|
||
team_info = {
|
||
'name': user.team,
|
||
'team_type': None,
|
||
'team_type_display': None,
|
||
'description': None,
|
||
'approvers': []
|
||
}
|
||
|
||
data.append({
|
||
'id': user.id,
|
||
'username': user.username,
|
||
'account': user.account,
|
||
'card': user.card,
|
||
'position': user.position,
|
||
'mobilePhone': user.mobilePhone,
|
||
'department': list(user.department.values('id', 'username')),
|
||
'role': list(user.role.values('id', 'RoleName', 'permissionId')),
|
||
'team': team_info, # 返回完整的团队信息对象
|
||
'Dateofjoining': user.Dateofjoining.strftime("%Y-%m-%d") if user.Dateofjoining else None,
|
||
'state': user.state,
|
||
'has_pending_approval': pending_approval is not None, # 是否有待审核的入职登记
|
||
'pending_approval_id': pending_approval.id if pending_approval else None
|
||
})
|
||
|
||
return Response({
|
||
'message': '查询成功',
|
||
'total': total,
|
||
'data': data,
|
||
'code': 0
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class GetCaseListForInvoice(APIView):
|
||
"""获取案件列表(用于开票申请选择)"""
|
||
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
获取案件列表,用于开票申请时选择合同号
|
||
返回案件ID、合同号、负责人等信息
|
||
"""
|
||
from business.models import ProjectRegistration
|
||
|
||
# 获取所有未删除的案件
|
||
cases = ProjectRegistration.objects.filter(is_deleted=False).order_by('-id')
|
||
|
||
data = []
|
||
for case in cases:
|
||
data.append({
|
||
'id': case.id,
|
||
'ContractNo': case.ContractNo, # 合同号
|
||
'responsiblefor': case.responsiblefor, # 负责人
|
||
'type': case.type, # 项目类型
|
||
'times': case.times, # 立项时间
|
||
})
|
||
|
||
return Response({
|
||
'message': '获取成功',
|
||
'data': data,
|
||
'code': 0
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class issueAnInvoice(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
财务开票
|
||
优化后:合同号从案件表选择,负责人自动同步
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
token = request.META.get('token')
|
||
case_id = request.data.get('case_id') # 案件ID(从案件表选择)
|
||
# 以下字段改为可选,如果提供了case_id,则从案件表同步
|
||
ContractNo = request.data.get('ContractNo') # 合同号(可选,如果提供了case_id则自动同步)
|
||
personincharge = request.data.get('personincharge') # 负责人(可选,如果提供了case_id则自动同步)
|
||
amount = request.data.get('amount')
|
||
type = request.data.get('type')
|
||
unit = request.data.get('unit')
|
||
number = request.data.get('number')
|
||
address_telephone = request.data.get('address_telephone')
|
||
bank = request.data.get('bank')
|
||
username = request.data.get('username')
|
||
|
||
# 必填字段验证
|
||
if not all([token, amount, type, unit, number, address_telephone, bank, username]):
|
||
missing_params = []
|
||
if not token:
|
||
missing_params.append('token')
|
||
if not amount:
|
||
missing_params.append('amount(开票金额)')
|
||
if not type:
|
||
missing_params.append('type(开票类型)')
|
||
if not unit:
|
||
missing_params.append('unit(开票单位)')
|
||
if not number:
|
||
missing_params.append('number(纳税人识别号)')
|
||
if not address_telephone:
|
||
missing_params.append('address_telephone(地址/电话)')
|
||
if not bank:
|
||
missing_params.append('bank(银行卡)')
|
||
if not username:
|
||
missing_params.append('username(提交人)')
|
||
return Response({
|
||
'status': 'error',
|
||
'message': f'缺少必填参数: {", ".join(missing_params)}',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 处理合同号和负责人:优先从案件表同步
|
||
from business.models import ProjectRegistration
|
||
|
||
if case_id:
|
||
# 如果提供了案件ID,从案件表获取合同号和负责人
|
||
try:
|
||
case = ProjectRegistration.objects.get(id=case_id, is_deleted=False)
|
||
ContractNo = case.ContractNo # 自动同步合同号
|
||
personincharge = case.responsiblefor # 自动同步负责人
|
||
except ProjectRegistration.DoesNotExist:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '案件不存在或已被删除',
|
||
'code': 1
|
||
}, status=status.HTTP_404_NOT_FOUND)
|
||
else:
|
||
# 如果没有提供案件ID,则ContractNo和personincharge必须手动提供
|
||
if not ContractNo:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '请选择案件或手动填写合同号',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
if not personincharge:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '请选择案件或手动填写负责人',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
today = datetime.datetime.now()
|
||
formatted_date = today.strftime("%Y-%m-%d")
|
||
|
||
invoice = Invoice.objects.create(
|
||
ContractNo=ContractNo,
|
||
personincharge=personincharge,
|
||
amount=amount,
|
||
type=type,
|
||
unit=unit,
|
||
number=number,
|
||
address_telephone=address_telephone,
|
||
bank=bank,
|
||
state="审核中",
|
||
username=username,
|
||
times=formatted_date,
|
||
)
|
||
# 已删除:不再创建开票待办事项
|
||
|
||
# 记录操作日志
|
||
new_data = {
|
||
'id': invoice.id,
|
||
'contract_no': invoice.ContractNo,
|
||
'personincharge': invoice.personincharge,
|
||
'amount': invoice.amount,
|
||
'type': invoice.type,
|
||
'unit': invoice.unit,
|
||
'case_id': case_id if case_id else None
|
||
}
|
||
log_operation(
|
||
request=request,
|
||
operation_type='CREATE',
|
||
module='Finance',
|
||
action='新增开票申请',
|
||
target_type='Invoice',
|
||
target_id=invoice.id,
|
||
target_name=invoice.ContractNo,
|
||
new_data=new_data,
|
||
remark=f'新增开票申请:合同号 {invoice.ContractNo},负责人 {invoice.personincharge},金额 {invoice.amount}'
|
||
)
|
||
|
||
return Response({
|
||
'message': '提交成功',
|
||
'code': 0,
|
||
'data': {
|
||
'id': invoice.id,
|
||
'ContractNo': invoice.ContractNo,
|
||
'personincharge': invoice.personincharge,
|
||
}
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class issueAnInvoiceDetail(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
开票记录详情
|
||
"""
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
times = request.data.get('times')
|
||
end_time = request.data.get('end_time')
|
||
unit = request.data.get('unit')
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
Q_obj = Q()
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if unit:
|
||
Q_obj &= Q(unit__icontains=unit)
|
||
|
||
invos = Invoice.objects.filter(Q_obj, is_deleted=False).order_by('-id')
|
||
total = len(invos)
|
||
|
||
paginator = Paginator(invos, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
data = []
|
||
for info in user_agents_page.object_list:
|
||
itme = {
|
||
'id': info.id,
|
||
"ContractNo": info.ContractNo,
|
||
"personincharge": info.personincharge,
|
||
"amount": info.amount,
|
||
"type": info.type,
|
||
"unit": info.unit,
|
||
"number": info.number,
|
||
"address_telephone": info.address_telephone,
|
||
"bank": info.bank,
|
||
"state": info.state,
|
||
"username": info.username,
|
||
"times": info.times,
|
||
}
|
||
data.append(itme)
|
||
return Response({'message': '展示成功', "total": total, 'data': data, 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class EditInvoice(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑开票申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
ContractNo = request.data.get('ContractNo')
|
||
personincharge = request.data.get('personincharge')
|
||
amount = request.data.get('amount')
|
||
type = request.data.get('type')
|
||
unit = request.data.get('unit')
|
||
number = request.data.get('number')
|
||
address_telephone = request.data.get('address_telephone')
|
||
bank = request.data.get('bank')
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
invoice = Invoice.objects.get(id=id, is_deleted=False)
|
||
except Invoice.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '开票申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
|
||
if ContractNo:
|
||
invoice.ContractNo = ContractNo
|
||
update_fields_list.append('ContractNo')
|
||
if personincharge:
|
||
invoice.personincharge = personincharge
|
||
update_fields_list.append('personincharge')
|
||
if amount:
|
||
invoice.amount = amount
|
||
update_fields_list.append('amount')
|
||
if type:
|
||
invoice.type = type
|
||
update_fields_list.append('type')
|
||
if unit:
|
||
invoice.unit = unit
|
||
update_fields_list.append('unit')
|
||
if number:
|
||
invoice.number = number
|
||
update_fields_list.append('number')
|
||
if address_telephone:
|
||
invoice.address_telephone = address_telephone
|
||
update_fields_list.append('address_telephone')
|
||
if bank:
|
||
invoice.bank = bank
|
||
update_fields_list.append('bank')
|
||
|
||
# 记录操作前的数据
|
||
old_data = {
|
||
'id': invoice.id,
|
||
'contract_no': invoice.ContractNo,
|
||
'amount': invoice.amount,
|
||
'type': invoice.type,
|
||
'unit': invoice.unit
|
||
}
|
||
|
||
if update_fields_list:
|
||
invoice.save(update_fields=update_fields_list)
|
||
|
||
# 记录操作后的数据
|
||
invoice.refresh_from_db()
|
||
new_data = {
|
||
'id': invoice.id,
|
||
'contract_no': invoice.ContractNo,
|
||
'amount': invoice.amount,
|
||
'type': invoice.type,
|
||
'unit': invoice.unit
|
||
}
|
||
|
||
# 记录操作日志
|
||
log_operation(
|
||
request=request,
|
||
operation_type='UPDATE',
|
||
module='Finance',
|
||
action='编辑开票申请',
|
||
target_type='Invoice',
|
||
target_id=invoice.id,
|
||
target_name=invoice.ContractNo,
|
||
old_data=old_data,
|
||
new_data=new_data,
|
||
remark=f'编辑开票申请:合同号 {invoice.ContractNo}'
|
||
)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeleteInvoice(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除开票申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
invoice = Invoice.objects.get(id=id, is_deleted=False)
|
||
except Invoice.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '开票申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 记录操作前的数据
|
||
old_data = {
|
||
'id': invoice.id,
|
||
'contract_no': invoice.ContractNo,
|
||
'amount': invoice.amount,
|
||
'unit': invoice.unit
|
||
}
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
invoice.is_deleted = True
|
||
invoice.save()
|
||
|
||
# 记录操作日志
|
||
log_operation(
|
||
request=request,
|
||
operation_type='DELETE',
|
||
module='Finance',
|
||
action='删除开票申请',
|
||
target_type='Invoice',
|
||
target_id=invoice.id,
|
||
target_name=invoice.ContractNo,
|
||
old_data=old_data,
|
||
remark=f'删除开票申请:合同号 {invoice.ContractNo},金额 {invoice.amount}'
|
||
)
|
||
|
||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class confirm(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
收入确认
|
||
优化后:收入分配由审批人指定,提交时不填写分配
|
||
数据来源案件管理
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
times = request.data.get('times')
|
||
ContractNo = request.data.get('ContractNo')
|
||
CustomerID = request.data.get('CustomerID')
|
||
amount = request.data.get('amount')
|
||
allocate = request.data.get('allocate') # 改为可选,由审批人指定
|
||
token = request.META.get('token')
|
||
approvers = request.data.get('approvers') # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组)
|
||
# 兼容旧接口:如果传了 personincharge,转换为 approvers
|
||
personincharge = request.data.get('personincharge')
|
||
if personincharge and not approvers:
|
||
approvers = [personincharge] if personincharge else None
|
||
case_id = request.data.get('case_id') # 案件ID(可选,用于关联案件)
|
||
|
||
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)
|
||
|
||
# 必填字段验证(allocate改为可选)
|
||
if not all([times, ContractNo, CustomerID, amount]):
|
||
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(收款金额)')
|
||
return Response({
|
||
'status': 'error',
|
||
'message': f'缺少必填参数: {", ".join(missing_params)}',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 如果提供了案件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)
|
||
|
||
from datetime import datetime
|
||
now = datetime.now()
|
||
date_string = now.strftime("%Y-%m-%d")
|
||
|
||
# 创建收入确认记录,allocate为空或"待审批人指定"
|
||
income = Income.objects.create(
|
||
times=times,
|
||
ContractNo=ContractNo,
|
||
CustomerID=CustomerID,
|
||
amount=amount,
|
||
allocate=allocate if allocate else "待审批人指定", # 如果未提供,设为"待审批人指定"
|
||
submit=user.username,
|
||
submit_tiem=date_string,
|
||
state="审核中"
|
||
)
|
||
|
||
# 获取用户的团队信息
|
||
team_name = user.team
|
||
from User.utils import create_approval_with_team_logic
|
||
|
||
# 构建审批内容,包含案件信息(如果提供了)
|
||
content_parts = [
|
||
f"{user.username}在{times}提交了收入确认",
|
||
f"合同编号:{ContractNo}",
|
||
f"客户名称:{CustomerID}",
|
||
f"收入金额:{amount}"
|
||
]
|
||
if case_info:
|
||
content_parts.append(f"案件类型:{case_info['type']}")
|
||
content_parts.append(f"案件负责人:{case_info['responsiblefor']}")
|
||
content_parts.append("收入分配:待审批人指定")
|
||
content = ",".join(content_parts)
|
||
|
||
# 使用统一的审核流程函数
|
||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||
team_name=team_name,
|
||
approvers=approvers,
|
||
title=user.username + "提交收入确认",
|
||
content=content,
|
||
approval_type="收入确认",
|
||
user_id=income.id,
|
||
business_record=income,
|
||
today=date_string
|
||
)
|
||
|
||
# 如果返回None且需要审核,说明缺少审核人
|
||
if approval is None and needs_approval:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '团队类型需要指定审核人,请提供approvers参数',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 记录操作日志
|
||
new_data = {
|
||
'id': income.id,
|
||
'ContractNo': income.ContractNo,
|
||
'CustomerID': income.CustomerID,
|
||
'amount': income.amount,
|
||
'allocate': income.allocate,
|
||
'case_id': case_id if case_id else None
|
||
}
|
||
log_operation(
|
||
request=request,
|
||
operation_type='CREATE',
|
||
module='Finance',
|
||
action='新增收入确认',
|
||
target_type='Income',
|
||
target_id=income.id,
|
||
target_name=f'{income.ContractNo} - {income.CustomerID}',
|
||
new_data=new_data,
|
||
remark=f'新增收入确认:合同号 {income.ContractNo},金额 {income.amount},分配待审批人指定'
|
||
)
|
||
|
||
return Response({
|
||
'message': '提交成功',
|
||
'code': 0,
|
||
'data': {
|
||
'id': income.id,
|
||
'ContractNo': income.ContractNo,
|
||
'allocate': income.allocate
|
||
}
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class confirmdisplay(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
收入确认展示
|
||
权限控制:律师只能看自己的数据,管委会和财务部能查看所有
|
||
"""
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
times = request.data.get('times')
|
||
end_time = request.data.get('end_time')
|
||
CustomerID = request.data.get('CustomerID')
|
||
token = request.META.get('token')
|
||
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 获取当前用户信息
|
||
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)
|
||
|
||
# 检查用户是否有权限查看所有数据
|
||
# 获取用户的角色名称列表
|
||
user_roles = user.role.values_list('RoleName', flat=True)
|
||
user_role_names = list(user_roles)
|
||
|
||
# 获取用户的部门名称列表
|
||
user_departments = user.department.values_list('username', flat=True)
|
||
user_department_names = list(user_departments)
|
||
|
||
# 判断是否有权限查看所有数据:管委会角色或财务部角色或财务部部门
|
||
has_all_permission = (
|
||
'管委会' in user_role_names or
|
||
'财务部' in user_role_names or
|
||
'财务部' in user_department_names
|
||
)
|
||
|
||
# 构建查询条件
|
||
Q_obj = Q()
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if CustomerID:
|
||
Q_obj &= Q(CustomerID__icontains=CustomerID)
|
||
|
||
# 如果没有查看所有数据的权限,只显示自己提交的数据
|
||
if not has_all_permission:
|
||
Q_obj &= Q(submit=user.username)
|
||
|
||
income = Income.objects.filter(Q_obj, is_deleted=False).order_by('-id')
|
||
total = len(income)
|
||
|
||
paginator = Paginator(income, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
data = []
|
||
for info in user_agents_page.object_list:
|
||
itme = {
|
||
'id': info.id,
|
||
"times": info.times,
|
||
"ContractNo": info.ContractNo,
|
||
"CustomerID": info.CustomerID,
|
||
"amount": info.amount,
|
||
"allocate": info.allocate,
|
||
"state": info.state,
|
||
"submit": info.submit, # 添加提交人信息
|
||
"submit_tiem": info.submit_tiem, # 添加提交时间
|
||
}
|
||
data.append(itme)
|
||
return Response({'message': '展示成功', "total": total, 'data': data, 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class EditIncome(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑收入确认
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
times = request.data.get('times')
|
||
ContractNo = request.data.get('ContractNo')
|
||
CustomerID = request.data.get('CustomerID')
|
||
amount = request.data.get('amount')
|
||
allocate = request.data.get('allocate')
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
income = Income.objects.get(id=id, is_deleted=False)
|
||
except Income.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '收入确认不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
|
||
if times:
|
||
income.times = times
|
||
update_fields_list.append('times')
|
||
if ContractNo:
|
||
income.ContractNo = ContractNo
|
||
update_fields_list.append('ContractNo')
|
||
if CustomerID:
|
||
income.CustomerID = CustomerID
|
||
update_fields_list.append('CustomerID')
|
||
if amount:
|
||
income.amount = amount
|
||
update_fields_list.append('amount')
|
||
if allocate:
|
||
income.allocate = allocate
|
||
update_fields_list.append('allocate')
|
||
|
||
if update_fields_list:
|
||
income.save(update_fields=update_fields_list)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeleteIncome(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除收入确认
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
income = Income.objects.get(id=id, is_deleted=False)
|
||
except Income.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '收入确认不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
income.is_deleted = True
|
||
income.save()
|
||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class loan(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
调账申请
|
||
优化后:不需要指定审批人,直接抄送财务(数据来源案件管理)
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
times = request.data.get('times')
|
||
ContractNo = request.data.get('ContractNo')
|
||
CustomerID = request.data.get('CustomerID')
|
||
amount = request.data.get('amount')
|
||
situation = request.data.get('situation')
|
||
case_id = request.data.get('case_id') # 案件ID(可选,用于关联案件)
|
||
token = request.META.get('token')
|
||
|
||
# 移除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()
|
||
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,
|
||
CustomerID=CustomerID,
|
||
amount=amount,
|
||
situation=situation,
|
||
submit=user.username,
|
||
submit_tiem=date_string,
|
||
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=content,
|
||
times=date_string,
|
||
personincharge="财务", # 直接抄送财务
|
||
state='已抄送财务', # 直接标记为已抄送财务
|
||
type="调账申请",
|
||
user_id=acc.id
|
||
)
|
||
|
||
# 记录操作日志
|
||
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):
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
times = request.data.get('times')
|
||
end_time = request.data.get('end_time')
|
||
CustomerID = request.data.get('CustomerID')
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
Q_obj = Q()
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if CustomerID:
|
||
Q_obj &= Q(CustomerID__icontains=CustomerID)
|
||
acc = Accounts.objects.filter(Q_obj, is_deleted=False).order_by('-id')
|
||
total = len(acc)
|
||
|
||
paginator = Paginator(acc, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
data = []
|
||
for info in user_agents_page.object_list:
|
||
itme = {
|
||
'id': info.id,
|
||
"times": info.times,
|
||
"ContractNo": info.ContractNo,
|
||
"CustomerID": info.CustomerID,
|
||
"amount": info.amount,
|
||
"situation": info.situation,
|
||
"state": info.state,
|
||
}
|
||
data.append(itme)
|
||
return Response({'message': '展示成功', "total": total, 'data': data, 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class EditAccounts(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑调账申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
times = request.data.get('times')
|
||
ContractNo = request.data.get('ContractNo')
|
||
CustomerID = request.data.get('CustomerID')
|
||
amount = request.data.get('amount')
|
||
situation = request.data.get('situation')
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
account = Accounts.objects.get(id=id, is_deleted=False)
|
||
except Accounts.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '调账申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
|
||
if times:
|
||
account.times = times
|
||
update_fields_list.append('times')
|
||
if ContractNo:
|
||
account.ContractNo = ContractNo
|
||
update_fields_list.append('ContractNo')
|
||
if CustomerID:
|
||
account.CustomerID = CustomerID
|
||
update_fields_list.append('CustomerID')
|
||
if amount:
|
||
account.amount = amount
|
||
update_fields_list.append('amount')
|
||
if situation:
|
||
account.situation = situation
|
||
update_fields_list.append('situation')
|
||
|
||
if update_fields_list:
|
||
account.save(update_fields=update_fields_list)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeleteAccounts(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除调账申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
account = Accounts.objects.get(id=id, is_deleted=False)
|
||
except Accounts.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '调账申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
account.is_deleted = True
|
||
account.save()
|
||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class PaymentRequest(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
付款申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
reason = request.data.get('reason')
|
||
amount = request.data.get('amount')
|
||
times = request.data.get('times')
|
||
payee = request.data.get('payee')
|
||
bankcard = request.data.get('bankcard')
|
||
BankName = request.data.get('BankName')
|
||
applicant = request.data.get('applicant')
|
||
approvers = request.data.get('approvers') # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组)
|
||
# 兼容旧接口:如果传了 personincharge,转换为 approvers
|
||
personincharge = request.data.get('personincharge')
|
||
if personincharge and not approvers:
|
||
approvers = [personincharge] if personincharge else None
|
||
|
||
if not all([times, payee, bankcard, BankName, reason, amount]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 获取申请人的团队信息
|
||
team_name = None
|
||
try:
|
||
applicant_user = User.objects.get(username=applicant, is_deleted=False)
|
||
team_name = applicant_user.team
|
||
except User.DoesNotExist:
|
||
pass
|
||
from datetime import datetime
|
||
now = datetime.now()
|
||
|
||
# 格式化日期为字符串,格式为 YYYY-MM-DD
|
||
date_string = now.strftime("%Y-%m-%d")
|
||
pay = Payment.objects.create(
|
||
reason=reason,
|
||
amount=amount,
|
||
times=times,
|
||
payee=payee,
|
||
bankcard=bankcard,
|
||
BankName=BankName,
|
||
applicant=applicant,
|
||
submit_tiem=date_string,
|
||
state="审核中"
|
||
)
|
||
|
||
# 使用统一的审核流程函数
|
||
from User.utils import create_approval_with_team_logic
|
||
|
||
content = f"{applicant}在{times}提交了付款申请,付款理由:{reason},付款金额:{amount},付款日期:{times},收款人:{payee},银行卡:{bankcard},开户行:{BankName}"
|
||
|
||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||
team_name=team_name,
|
||
approvers=approvers,
|
||
title=applicant + "提交付款申请",
|
||
content=content,
|
||
approval_type="付款申请",
|
||
user_id=pay.id,
|
||
business_record=pay,
|
||
today=date_string
|
||
)
|
||
|
||
# 如果返回None且需要审核,说明缺少审核人
|
||
if approval is None and needs_approval:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '团队类型需要指定审核人,请提供approvers参数',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
return Response({'message': '插入成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class PaymentDisplay(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
times = request.data.get('times')
|
||
end_time = request.data.get('end_time')
|
||
payee = request.data.get('payee')
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
Q_obj = Q()
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if payee:
|
||
Q_obj &= Q(payee__icontains=payee)
|
||
pay = Payment.objects.filter(Q_obj, is_deleted=False).order_by('-id')
|
||
total = len(pay)
|
||
|
||
paginator = Paginator(pay, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
data = []
|
||
for info in user_agents_page.object_list:
|
||
itme = {
|
||
'id': info.id,
|
||
"times": info.times,
|
||
"payee": info.payee,
|
||
"reason": info.reason,
|
||
"amount": info.amount,
|
||
"bankcard": info.bankcard,
|
||
"BankName": info.BankName,
|
||
"applicant": info.applicant,
|
||
"state": info.state,
|
||
}
|
||
data.append(itme)
|
||
return Response({'message': '展示成功', "total": total, 'data': data, 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class EditPayment(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑付款申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
reason = request.data.get('reason')
|
||
amount = request.data.get('amount')
|
||
times = request.data.get('times')
|
||
payee = request.data.get('payee')
|
||
bankcard = request.data.get('bankcard')
|
||
BankName = request.data.get('BankName')
|
||
applicant = request.data.get('applicant')
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
payment = Payment.objects.get(id=id, is_deleted=False)
|
||
except Payment.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '付款申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
|
||
if reason:
|
||
payment.reason = reason
|
||
update_fields_list.append('reason')
|
||
if amount:
|
||
payment.amount = amount
|
||
update_fields_list.append('amount')
|
||
if times:
|
||
payment.times = times
|
||
update_fields_list.append('times')
|
||
if payee:
|
||
payment.payee = payee
|
||
update_fields_list.append('payee')
|
||
if bankcard:
|
||
payment.bankcard = bankcard
|
||
update_fields_list.append('bankcard')
|
||
if BankName:
|
||
payment.BankName = BankName
|
||
update_fields_list.append('BankName')
|
||
if applicant:
|
||
payment.applicant = applicant
|
||
update_fields_list.append('applicant')
|
||
|
||
if update_fields_list:
|
||
payment.save(update_fields=update_fields_list)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeletePayment(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除付款申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
payment = Payment.objects.get(id=id, is_deleted=False)
|
||
except Payment.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '付款申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
payment.is_deleted = True
|
||
payment.save()
|
||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class reimbursement(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
报销申请
|
||
优化后:根据团队类型判断是否需要审批
|
||
- 个人团队(personal/独立律师):不触发审批,直接抄送财务
|
||
- 团队(team/团队律师):需要多级审批,按顺序依次审批,最后抄送财务
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
person = request.data.get('person')
|
||
times = request.data.get('times')
|
||
reason = request.data.get('reason')
|
||
amount = request.data.get('amount')
|
||
FeeDescription = request.data.get('FeeDescription')
|
||
approvers = request.data.get('approvers') # 审批人列表(数组,仅团队类型需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组)
|
||
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=date_string,
|
||
state="审核中" if (team and team.team_type == 'team') else "待财务处理"
|
||
)
|
||
|
||
# 使用统一的审核流程函数
|
||
from User.utils import create_approval_with_team_logic
|
||
|
||
content = f"{person}在{times}提交了报销申请,报销理由:{reason},付款金额:{amount},付款日期:{times},费用说明:{FeeDescription}"
|
||
|
||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||
team_name=team_name,
|
||
approvers=approvers,
|
||
title=person + "报销申请",
|
||
content=content,
|
||
approval_type="报销申请",
|
||
user_id=reim.id,
|
||
business_record=reim,
|
||
today=date_string
|
||
)
|
||
|
||
# 如果返回None且需要审核,说明缺少审核人
|
||
if approval is None and needs_approval:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '团队类型需要指定审核人,请提供approvers参数',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 记录操作日志
|
||
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,
|
||
'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):
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
times = request.data.get('times')
|
||
end_time = request.data.get('end_time')
|
||
person = request.data.get('person')
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
Q_obj = Q()
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if person:
|
||
Q_obj &= Q(person__icontains=person)
|
||
rei = Reimbursement.objects.filter(Q_obj, is_deleted=False).order_by('-id')
|
||
total = len(rei)
|
||
|
||
paginator = Paginator(rei, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
data = []
|
||
for info in user_agents_page.object_list:
|
||
itme = {
|
||
"id": info.id,
|
||
"times": info.times,
|
||
"person": info.person,
|
||
"reason": info.reason,
|
||
"amount": info.amount,
|
||
"FeeDescription": info.FeeDescription,
|
||
"state": info.state,
|
||
}
|
||
data.append(itme)
|
||
return Response({'message': '展示成功', "total": total, 'data': data, 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class EditReimbursement(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑报销申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
person = request.data.get('person')
|
||
times = request.data.get('times')
|
||
reason = request.data.get('reason')
|
||
amount = request.data.get('amount')
|
||
FeeDescription = request.data.get('FeeDescription')
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
reimbursement = Reimbursement.objects.get(id=id, is_deleted=False)
|
||
except Reimbursement.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '报销申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
|
||
if person:
|
||
reimbursement.person = person
|
||
update_fields_list.append('person')
|
||
if times:
|
||
reimbursement.times = times
|
||
update_fields_list.append('times')
|
||
if reason:
|
||
reimbursement.reason = reason
|
||
update_fields_list.append('reason')
|
||
if amount:
|
||
reimbursement.amount = amount
|
||
update_fields_list.append('amount')
|
||
if FeeDescription:
|
||
reimbursement.FeeDescription = FeeDescription
|
||
update_fields_list.append('FeeDescription')
|
||
|
||
if update_fields_list:
|
||
reimbursement.save(update_fields=update_fields_list)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeleteReimbursement(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除报销申请
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
reimbursement = Reimbursement.objects.get(id=id, is_deleted=False)
|
||
except Reimbursement.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '报销申请不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
reimbursement.is_deleted = True
|
||
reimbursement.save()
|
||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class Change(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
工资/奖金变更
|
||
优化后:增加提交人字段,明确是谁提交的
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
username = request.data.get('username')
|
||
type = request.data.get('type')
|
||
Instructions = request.data.get('Instructions')
|
||
approvers = request.data.get('approvers') # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组)
|
||
# 兼容旧接口:如果传了 personincharge,转换为 approvers
|
||
personincharge = request.data.get('personincharge')
|
||
if personincharge and not approvers:
|
||
approvers = [personincharge] if personincharge else None
|
||
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(
|
||
username=username,
|
||
type=type,
|
||
Instructions=Instructions,
|
||
times=now.strftime("%Y-%m-%d"),
|
||
state="审核中",
|
||
submitter=submitter # 记录提交人
|
||
)
|
||
|
||
# 获取用户的团队信息
|
||
team_name = user.team if user else None
|
||
from User.utils import create_approval_with_team_logic
|
||
|
||
content = f"{submitter}在{now.strftime('%Y-%m-%d')}提交了工资/奖金变更,类型:{type},调整说明:{Instructions}"
|
||
|
||
# 使用统一的审核流程函数
|
||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||
team_name=team_name,
|
||
approvers=approvers,
|
||
title=username + "工资/奖金变更",
|
||
content=content,
|
||
approval_type="工资/奖金变更",
|
||
user_id=bonus.id,
|
||
business_record=bonus,
|
||
today=now.strftime("%Y-%m-%d")
|
||
)
|
||
|
||
# 如果返回None且需要审核,说明缺少审核人
|
||
if approval is None and needs_approval:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '团队类型需要指定审核人,请提供approvers参数',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 记录操作日志
|
||
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):
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
times = request.data.get('times')
|
||
end_time = request.data.get('end_time')
|
||
username = request.data.get('username')
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
Q_obj = Q()
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if username:
|
||
Q_obj &= Q(username__icontains=username)
|
||
bon = BonusChange.objects.filter(Q_obj, is_deleted=False).order_by('-id')
|
||
total = len(bon)
|
||
|
||
paginator = Paginator(bon, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
data = []
|
||
for info in user_agents_page.object_list:
|
||
itme = {
|
||
"id": info.id,
|
||
"times": info.times,
|
||
"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)
|
||
|
||
|
||
class EditBonusChange(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑工资/奖金变更
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
username = request.data.get('username')
|
||
type = request.data.get('type')
|
||
Instructions = request.data.get('Instructions')
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
bonus = BonusChange.objects.get(id=id, is_deleted=False)
|
||
except BonusChange.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '工资/奖金变更不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
|
||
if username:
|
||
bonus.username = username
|
||
update_fields_list.append('username')
|
||
if type:
|
||
bonus.type = type
|
||
update_fields_list.append('type')
|
||
if Instructions:
|
||
bonus.Instructions = Instructions
|
||
update_fields_list.append('Instructions')
|
||
|
||
if update_fields_list:
|
||
bonus.save(update_fields=update_fields_list)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeleteBonusChange(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除工资/奖金变更
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id')
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
bonus = BonusChange.objects.get(id=id, is_deleted=False)
|
||
except BonusChange.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '工资/奖金变更不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
bonus.is_deleted = True
|
||
bonus.save()
|
||
return Response({'message': '删除成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class UserDeparture(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
离职财务登记
|
||
优化后:只需填写姓名和离职时间,其余字段从人事管理中同步
|
||
离职工资由审批人填写
|
||
如果用户有案件(作为承办人员),需要先转移案件才能完成离职登记
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
username = request.data.get('username')
|
||
Dateofdeparture = request.data.get('Dateofdeparture') # 离职时间
|
||
approvers = request.data.get('approvers') # 审核人列表(可选,多人团队时需要,推荐:用户ID数组如[1,2,3],兼容:用户名数组)
|
||
# 兼容旧接口:如果传了 personincharge,转换为 approvers
|
||
personincharge = request.data.get('personincharge')
|
||
if personincharge and not approvers:
|
||
approvers = [personincharge] if personincharge else None
|
||
|
||
# 只验证必填字段:姓名和离职时间
|
||
if not all([username, Dateofdeparture]):
|
||
return Response({'status': 'error', 'message': '缺少参数:姓名和离职时间不能为空', 'code': 1},
|
||
status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
user = User.objects.get(username=username, is_deleted=False)
|
||
except User.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '用户不存在或已被删除', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 检查用户是否有案件(作为承办人员)
|
||
cases = PreFiling.objects.filter(Undertaker=username)
|
||
case_count = cases.count()
|
||
|
||
if case_count > 0:
|
||
# 用户有案件,需要先转移案件才能离职
|
||
case_list = []
|
||
for case in cases:
|
||
case_list.append({
|
||
'id': case.id,
|
||
'times': case.times,
|
||
'client_username': case.client_username,
|
||
'party_username': case.party_username,
|
||
'description': case.description
|
||
})
|
||
|
||
return Response({
|
||
'status': 'error',
|
||
'message': f'该用户还有{case_count}个案件未转移,请先转移案件后再进行离职登记',
|
||
'code': 1,
|
||
'data': {
|
||
'has_cases': True,
|
||
'case_count': case_count,
|
||
'cases': case_list
|
||
}
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 用户没有案件,可以正常离职登记
|
||
try:
|
||
Dateofdepartures = datetime.datetime.strptime(Dateofdeparture, "%Y-%m-%d")
|
||
except ValueError:
|
||
return Response({'status': 'error', 'message': '离职时间格式错误,请使用YYYY-MM-DD格式', 'code': 1},
|
||
status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 更新用户离职时间和状态
|
||
user.Dateofdeparture = Dateofdepartures
|
||
user.state = "已离职"
|
||
user.save(update_fields=['Dateofdeparture', 'state'])
|
||
|
||
# 根据团队类型判断是否需要审批
|
||
# 规则:
|
||
# - 个人团队(personal/独立律师):不触发审批
|
||
# - 团队(team/团队律师):需要审批,审批人需要指定结算工资
|
||
from User.models import Team
|
||
|
||
# 获取用户的团队信息
|
||
team_name = user.team # 用户的团队名称(CharField)
|
||
team = None
|
||
if team_name:
|
||
try:
|
||
team = Team.objects.get(name=team_name, is_deleted=False)
|
||
except Team.DoesNotExist:
|
||
# 如果团队不存在,默认按团队类型处理(需要审批)
|
||
pass
|
||
|
||
# 使用统一的审核流程函数
|
||
from User.utils import create_approval_with_team_logic
|
||
|
||
today = datetime.datetime.now()
|
||
formatted_date = today.strftime("%Y-%m-%d")
|
||
|
||
# 从人事管理同步用户信息,构建审批内容
|
||
# 包含用户的基本信息:姓名、岗位、部门、团队等
|
||
content_parts = [f"{user.username}在{Dateofdeparture}办理离职登记"]
|
||
|
||
# 同步岗位信息
|
||
if user.position:
|
||
content_parts.append(f"岗位:{user.position}")
|
||
|
||
# 同步部门信息
|
||
departments = user.department.filter(is_deleted=False)
|
||
if departments.exists():
|
||
dept_names = [dept.username for dept in departments]
|
||
content_parts.append(f"部门:{', '.join(dept_names)}")
|
||
|
||
# 同步团队信息
|
||
if user.team:
|
||
content_parts.append(f"团队:{user.team}")
|
||
|
||
# 离职工资由审批人填写,初始状态为"待审批人指定"
|
||
content_parts.append("结算工资:待审批人指定")
|
||
|
||
content = ",".join(content_parts)
|
||
|
||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||
team_name=team_name,
|
||
approvers=approvers,
|
||
title=user.username + "离职财务登记",
|
||
content=content,
|
||
approval_type="离职财务登记",
|
||
user_id=str(user.id),
|
||
business_record=user, # User对象没有approvers_order字段,但可以更新state
|
||
today=formatted_date
|
||
)
|
||
|
||
# 如果返回None且需要审核,说明缺少审核人
|
||
if approval is None and needs_approval:
|
||
return Response({
|
||
'status': 'error',
|
||
'message': '团队类型需要指定审核人,请提供approvers参数',
|
||
'code': 1
|
||
}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 如果是个人团队,不创建审批记录,但记录日志
|
||
if team and team.team_type == 'personal' and approval is None:
|
||
new_data = {
|
||
'user_id': user.id,
|
||
'username': user.username,
|
||
'Dateofdeparture': Dateofdeparture,
|
||
'state': user.state,
|
||
'team_type': 'personal',
|
||
'note': '个人团队,无需审批'
|
||
}
|
||
log_operation(
|
||
request=request,
|
||
operation_type='CREATE',
|
||
module='Finance',
|
||
action='新增离职财务登记(个人团队)',
|
||
target_type='User',
|
||
target_id=user.id,
|
||
target_name=user.username,
|
||
new_data=new_data,
|
||
remark=f'新增离职财务登记:{user.username},离职时间 {Dateofdeparture}(个人团队,无需审批)'
|
||
)
|
||
else:
|
||
# 如果创建了审批记录,记录操作日志
|
||
if approval:
|
||
new_data = {
|
||
'user_id': user.id,
|
||
'username': user.username,
|
||
'Dateofdeparture': Dateofdeparture,
|
||
'state': user.state,
|
||
'position': user.position,
|
||
'team': user.team,
|
||
'settlement_salary': '待审批人指定'
|
||
}
|
||
log_operation(
|
||
request=request,
|
||
operation_type='CREATE',
|
||
module='Finance',
|
||
action='新增离职财务登记',
|
||
target_type='User',
|
||
target_id=user.id,
|
||
target_name=user.username,
|
||
new_data=new_data,
|
||
remark=f'新增离职财务登记:{user.username},离职时间 {Dateofdeparture}'
|
||
)
|
||
|
||
return Response({
|
||
'message': '离职登记成功',
|
||
'code': 0,
|
||
'data': {
|
||
'has_cases': False,
|
||
'case_count': 0,
|
||
'needs_approval': team is None or team.team_type != 'personal' # 是否需要审批
|
||
}
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class UserDepartureDetail(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
离职登记列表查询
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
page = request.data.get('page')
|
||
per_page = request.data.get('per_page')
|
||
username = request.data.get('username') # 用户名搜索
|
||
times = request.data.get('times') # 开始时间
|
||
end_time = request.data.get('end_time') # 结束时间
|
||
state = request.data.get('state') # 审批状态
|
||
|
||
if not all([page, per_page]):
|
||
return Response({'status': 'error', 'message': '缺少参数:页码和每页数量不能为空', 'code': 1},
|
||
status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 查询离职财务登记的审批记录
|
||
Q_obj = Q(type="离职财务登记", is_deleted=False)
|
||
|
||
if username:
|
||
Q_obj &= Q(title__icontains=username) | Q(content__icontains=username)
|
||
if times and end_time:
|
||
Q_obj &= Q(times__gte=times) & Q(times__lte=end_time)
|
||
if state:
|
||
Q_obj &= Q(state=state)
|
||
|
||
approvals = Approval.objects.filter(Q_obj).order_by('-id')
|
||
total = len(approvals)
|
||
|
||
paginator = Paginator(approvals, per_page)
|
||
try:
|
||
user_agents_page = paginator.page(page)
|
||
except PageNotAnInteger:
|
||
user_agents_page = paginator.page(1)
|
||
except EmptyPage:
|
||
user_agents_page = paginator.page(paginator.num_pages)
|
||
|
||
data = []
|
||
for approval in user_agents_page.object_list:
|
||
# 获取用户信息
|
||
try:
|
||
user = User.objects.get(id=int(approval.user_id), is_deleted=False)
|
||
user_info = {
|
||
'id': user.id,
|
||
'username': user.username,
|
||
'account': user.account,
|
||
'position': user.position,
|
||
'Dateofdeparture': user.Dateofdeparture.strftime("%Y-%m-%d") if user.Dateofdeparture else None,
|
||
'state': user.state
|
||
}
|
||
except (User.DoesNotExist, ValueError):
|
||
user_info = {
|
||
'id': None,
|
||
'username': '用户不存在',
|
||
'account': '',
|
||
'position': '',
|
||
'Dateofdeparture': None,
|
||
'state': ''
|
||
}
|
||
|
||
item = {
|
||
'id': approval.id,
|
||
'title': approval.title,
|
||
'content': approval.content,
|
||
'times': approval.times.strftime("%Y-%m-%d") if approval.times else None,
|
||
'completeTiem': approval.completeTiem.strftime("%Y-%m-%d") if approval.completeTiem else None,
|
||
'personincharge': approval.personincharge,
|
||
'state': approval.state,
|
||
'type': approval.type,
|
||
'user_id': approval.user_id,
|
||
'user_info': user_info
|
||
}
|
||
data.append(item)
|
||
|
||
return Response({
|
||
'message': '查询成功',
|
||
'total': total,
|
||
'data': data,
|
||
'code': 0
|
||
}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class EditUserDeparture(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
编辑离职登记
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id') # 审批记录ID
|
||
Dateofdeparture = request.data.get('Dateofdeparture') # 离职时间
|
||
personincharge = request.data.get('personincharge') # 负责人
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
approval = Approval.objects.get(id=id, type="离职财务登记", is_deleted=False)
|
||
except Approval.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '离职登记记录不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 获取用户信息
|
||
try:
|
||
user = User.objects.get(id=int(approval.user_id), is_deleted=False)
|
||
except (User.DoesNotExist, ValueError):
|
||
return Response({'status': 'error', 'message': '用户不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||
|
||
update_fields_list = []
|
||
approval_update_fields = []
|
||
|
||
# 更新离职时间
|
||
if Dateofdeparture:
|
||
try:
|
||
Dateofdepartures = datetime.datetime.strptime(Dateofdeparture, "%Y-%m-%d")
|
||
user.Dateofdeparture = Dateofdepartures
|
||
update_fields_list.append('Dateofdeparture')
|
||
# 更新审批记录内容
|
||
approval.content = user.username + "在" + Dateofdeparture + "办理离职登记"
|
||
approval_update_fields.append('content')
|
||
except ValueError:
|
||
return Response({'status': 'error', 'message': '离职时间格式错误,请使用YYYY-MM-DD格式', 'code': 1},
|
||
status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
# 更新负责人
|
||
if personincharge:
|
||
approval.personincharge = personincharge
|
||
approval_update_fields.append('personincharge')
|
||
|
||
# 保存更新
|
||
if update_fields_list:
|
||
user.save(update_fields=update_fields_list)
|
||
if approval_update_fields:
|
||
approval.save(update_fields=approval_update_fields)
|
||
|
||
return Response({'message': '编辑成功', 'code': 0}, status=status.HTTP_200_OK)
|
||
|
||
|
||
class DeleteUserDeparture(APIView):
|
||
def post(self, request, *args, **kwargs):
|
||
"""
|
||
删除离职登记
|
||
删除离职登记记录,并恢复用户状态为"在职",清空离职时间
|
||
:param request:
|
||
:param args:
|
||
:param kwargs:
|
||
:return:
|
||
"""
|
||
id = request.data.get('id') # 审批记录ID
|
||
|
||
if not id:
|
||
return Response({'status': 'error', 'message': '缺少参数id', 'code': 1}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
||
try:
|
||
approval = Approval.objects.get(id=id, type="离职财务登记", is_deleted=False)
|
||
except Approval.DoesNotExist:
|
||
return Response({'status': 'error', 'message': '离职登记记录不存在', 'code': 1},
|
||
status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 获取用户信息
|
||
try:
|
||
user = User.objects.get(id=int(approval.user_id), is_deleted=False)
|
||
except (User.DoesNotExist, ValueError):
|
||
return Response({'status': 'error', 'message': '用户不存在', 'code': 1}, status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# 记录操作前的数据
|
||
old_data = {
|
||
'user_id': user.id,
|
||
'username': user.username,
|
||
'state': user.state,
|
||
'dateofdeparture': str(user.Dateofdeparture) if user.Dateofdeparture else None,
|
||
'approval_id': approval.id
|
||
}
|
||
|
||
# 恢复用户状态
|
||
user.state = "在职"
|
||
user.Dateofdeparture = None
|
||
user.save(update_fields=['state', 'Dateofdeparture'])
|
||
|
||
# 软删除:更新 is_deleted 字段
|
||
approval.is_deleted = True
|
||
approval.save()
|
||
|
||
# 记录操作日志
|
||
log_operation(
|
||
request=request,
|
||
operation_type='DELETE',
|
||
module='Finance',
|
||
action='删除离职登记',
|
||
target_type='Approval',
|
||
target_id=approval.id,
|
||
target_name=f'离职登记-{user.username}',
|
||
old_data=old_data,
|
||
new_data={'user_id': user.id, 'username': user.username, 'state': '在职'},
|
||
remark=f'删除离职登记,恢复用户 {user.username} 状态为"在职"'
|
||
)
|
||
|
||
return Response({'message': '删除成功,用户状态已恢复为"在职"', 'code': 0}, status=status.HTTP_200_OK)
|