haha
This commit is contained in:
@@ -1148,20 +1148,62 @@ class approvalProcessing(APIView):
|
||||
approval.save(update_fields=['state'])
|
||||
return Response({'message': '处理成功', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
# 审批人可以指定收入分配方案
|
||||
allocate = request.data.get('allocate') # 收入分配(可选,审批时指定)
|
||||
# 负责人填写收入分配
|
||||
allocate = request.data.get('allocate') # 收入分配(负责人必须填写)
|
||||
|
||||
# 如果审批人指定了分配方案,更新分配字段
|
||||
# 如果当前状态是"待负责人填写分配",负责人必须填写收入分配
|
||||
if income.state == "待负责人填写分配":
|
||||
if not allocate:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '请填写收入分配',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 更新收入分配
|
||||
income.allocate = allocate
|
||||
income.state = "待财务处理" # 更新状态为待财务处理
|
||||
|
||||
# 更新审批内容,添加分配信息
|
||||
if "收入分配:待负责人指定" in approval.content:
|
||||
approval.content = approval.content.replace("收入分配:待负责人指定", f"收入分配:{allocate}")
|
||||
else:
|
||||
approval.content = approval.content + f",收入分配:{allocate}"
|
||||
|
||||
income.save(update_fields=['allocate', 'state'])
|
||||
|
||||
# 负责人填写收入分配后,抄送给财务负责人
|
||||
from User.utils import get_finance_personincharge_value
|
||||
finance_personincharge = get_finance_personincharge_value()
|
||||
|
||||
# 更新审批记录,抄送给财务
|
||||
approval.personincharge = finance_personincharge
|
||||
approval.state = "已抄送财务"
|
||||
approval.content = approval.content + ",已抄送财务部"
|
||||
approval.save(update_fields=['personincharge', 'state', 'content'])
|
||||
|
||||
return Response({
|
||||
'message': '收入分配已提交,已抄送给财务',
|
||||
'code': 0,
|
||||
'data': {
|
||||
'allocate': allocate,
|
||||
'state': income.state
|
||||
}
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
# 兼容旧流程:如果负责人未填写分配,但审批人指定了分配方案
|
||||
if allocate:
|
||||
income.allocate = allocate
|
||||
# 更新审批内容,添加分配信息
|
||||
if "收入分配:待审批人指定" in approval.content:
|
||||
approval.content = approval.content.replace("收入分配:待审批人指定", f"收入分配:{allocate}")
|
||||
elif "收入分配:待负责人指定" in approval.content:
|
||||
approval.content = approval.content.replace("收入分配:待负责人指定", f"收入分配:{allocate}")
|
||||
else:
|
||||
approval.content = approval.content + f",收入分配:{allocate}"
|
||||
income.save(update_fields=['allocate'])
|
||||
|
||||
# 使用统一的审核流程处理函数
|
||||
# 使用统一的审核流程处理函数(兼容旧流程)
|
||||
from User.utils import process_approval_flow
|
||||
current_approver = approval.personincharge
|
||||
is_completed, error = process_approval_flow(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .views import UserRegister,UnregisteredUserList,RegisteredUserList,UserDeparture,UserDepartureDetail,EditUserDeparture,DeleteUserDeparture,issueAnInvoice,issueAnInvoiceDetail,confirm,loan,PaymentRequest,reimbursement,confirmdisplay,loandisplay,PaymentDisplay,reimbursementdetail,Change,ChangeDetail,EditInvoice,DeleteInvoice,EditIncome,DeleteIncome,EditAccounts,DeleteAccounts,EditPayment,DeletePayment,EditReimbursement,DeleteReimbursement,EditBonusChange,DeleteBonusChange,GetCaseListForInvoice
|
||||
from .views import UserRegister,UnregisteredUserList,RegisteredUserList,UserDeparture,UserDepartureDetail,EditUserDeparture,DeleteUserDeparture,issueAnInvoice,issueAnInvoiceDetail,confirm,loan,PaymentRequest,reimbursement,confirmdisplay,loandisplay,PaymentDisplay,reimbursementdetail,Change,ChangeDetail,EditInvoice,DeleteInvoice,EditIncome,DeleteIncome,EditAccounts,DeleteAccounts,EditPayment,DeletePayment,EditReimbursement,DeleteReimbursement,EditBonusChange,DeleteBonusChange,GetCaseListForInvoice,SearchCaseByContractNo,AddInvoice
|
||||
from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
@@ -11,6 +11,8 @@ urlpatterns = [
|
||||
path("editUserDeparture", EditUserDeparture.as_view(), name="editUserDeparture/"),
|
||||
path("deleteUserDeparture", DeleteUserDeparture.as_view(), name="deleteUserDeparture/"),
|
||||
path("case-list-for-invoice", GetCaseListForInvoice.as_view(), name="case-list-for-invoice/"),
|
||||
path("search-case-by-contract-no", SearchCaseByContractNo.as_view(), name="search-case-by-contract-no/"),
|
||||
path("add-invoice", AddInvoice.as_view(), name="add-invoice/"),
|
||||
path("issue-invoice", issueAnInvoice.as_view(), name="issue-invoice/"),
|
||||
path('issue-Detail', issueAnInvoiceDetail.as_view(), name="issue-Detail/"),
|
||||
path('editInvoice', EditInvoice.as_view(), name="editInvoice/"),
|
||||
|
||||
616
finance/views.py
616
finance/views.py
@@ -870,42 +870,47 @@ class confirm(APIView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
收入确认
|
||||
优化后:收入分配由审批人指定,提交时不填写分配
|
||||
数据来源案件管理
|
||||
优化后:
|
||||
1. 通过合同号搜索选择案件(case_id或project_id)
|
||||
2. 从案件管理中同步:客户名称、负责人
|
||||
3. 手动填写:收款日期、收款金额
|
||||
4. 财务填写好后直接抄送给案件负责人
|
||||
5. 负责人在待办中填写收入分配后,再抄送给财务负责人
|
||||
: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') # 改为可选,由审批人指定
|
||||
# 案件选择(二选一)
|
||||
case_id = request.data.get('case_id') # 案件管理ID
|
||||
project_id = request.data.get('project_id') # 立项登记ID
|
||||
|
||||
# 手动填写信息
|
||||
times = request.data.get('times') # 收款日期
|
||||
amount = request.data.get('amount') # 收款金额
|
||||
|
||||
# 可选字段(如果提供了case_id或project_id,将从案件管理中同步)
|
||||
ContractNo = request.data.get('ContractNo') # 合同号(可选,如果提供了case_id或project_id则自动同步)
|
||||
CustomerID = request.data.get('CustomerID') # 客户名称(可选,如果提供了case_id或project_id则自动同步)
|
||||
|
||||
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')
|
||||
approvers = normalize_approvers_param(approvers, personincharge)
|
||||
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改为可选)
|
||||
# ContractNo 允许通过 case_id 同步
|
||||
# 必填字段验证
|
||||
missing_params = []
|
||||
if not times:
|
||||
missing_params.append('times(收款日期)')
|
||||
if not CustomerID:
|
||||
missing_params.append('CustomerID(客户名称)')
|
||||
if not amount:
|
||||
missing_params.append('amount(收款金额)')
|
||||
if not ContractNo and not case_id:
|
||||
missing_params.append('ContractNo(合同号)')
|
||||
if not case_id and not project_id:
|
||||
missing_params.append('case_id或project_id(请选择案件)')
|
||||
|
||||
if missing_params:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
@@ -913,81 +918,173 @@ class confirm(APIView):
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 如果提供了案件ID,从案件表获取相关信息(可选)
|
||||
from business.models import ProjectRegistration
|
||||
# 从案件管理中提取信息
|
||||
from business.models import Case, ProjectRegistration
|
||||
import json
|
||||
|
||||
responsible_person = None # 负责人姓名(用于抄送)
|
||||
responsible_person_username = None # 负责人用户名(用于抄送)
|
||||
case_info = None
|
||||
|
||||
if case_id:
|
||||
# 从Case(案件管理)中获取信息
|
||||
try:
|
||||
case = ProjectRegistration.objects.get(id=case_id, is_deleted=False)
|
||||
case = Case.objects.select_related('project').get(id=case_id, is_deleted=False)
|
||||
|
||||
# 获取合同号
|
||||
ContractNo = ContractNo or case.contract_no
|
||||
|
||||
# 获取客户名称
|
||||
CustomerID = CustomerID or case.client_name
|
||||
|
||||
# 获取负责人信息
|
||||
responsiblefor = case.responsiblefor
|
||||
|
||||
# 如果案件信息不完整,从关联的ProjectRegistration获取
|
||||
if case.project:
|
||||
project = case.project
|
||||
ContractNo = ContractNo or project.ContractNo
|
||||
CustomerID = CustomerID or project.client_info
|
||||
responsiblefor = responsiblefor or project.responsiblefor
|
||||
|
||||
# 解析负责人信息
|
||||
try:
|
||||
if responsiblefor:
|
||||
if isinstance(responsiblefor, str):
|
||||
responsiblefor_dict = json.loads(responsiblefor)
|
||||
else:
|
||||
responsiblefor_dict = responsiblefor
|
||||
responsible_person = responsiblefor_dict.get('responsible_person', '')
|
||||
# 查找负责人用户名
|
||||
if responsible_person:
|
||||
try:
|
||||
responsible_user = User.objects.get(username=responsible_person, is_deleted=False)
|
||||
responsible_person_username = responsible_user.username
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
except (json.JSONDecodeError, TypeError, AttributeError):
|
||||
responsible_person = str(responsiblefor) if responsiblefor else ''
|
||||
|
||||
case_info = {
|
||||
'id': case.id,
|
||||
'ContractNo': case.ContractNo,
|
||||
'responsiblefor': case.responsiblefor,
|
||||
'type': case.type
|
||||
'type': 'case',
|
||||
'contract_no': ContractNo,
|
||||
'customer_name': CustomerID,
|
||||
'responsible_person': responsible_person
|
||||
}
|
||||
# 如果合同号未提供,从案件表同步
|
||||
if not ContractNo:
|
||||
ContractNo = case.ContractNo
|
||||
except ProjectRegistration.DoesNotExist:
|
||||
|
||||
except Case.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '案件不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
elif project_id:
|
||||
# 从ProjectRegistration(立项登记)中获取信息
|
||||
try:
|
||||
project = ProjectRegistration.objects.get(id=project_id, is_deleted=False)
|
||||
|
||||
ContractNo = ContractNo or project.ContractNo
|
||||
CustomerID = CustomerID or project.client_info
|
||||
responsiblefor = project.responsiblefor
|
||||
|
||||
# 解析负责人信息
|
||||
try:
|
||||
if responsiblefor:
|
||||
if isinstance(responsiblefor, str):
|
||||
responsiblefor_dict = json.loads(responsiblefor)
|
||||
else:
|
||||
responsiblefor_dict = responsiblefor
|
||||
responsible_person = responsiblefor_dict.get('responsible_person', '')
|
||||
# 查找负责人用户名
|
||||
if responsible_person:
|
||||
try:
|
||||
responsible_user = User.objects.get(username=responsible_person, is_deleted=False)
|
||||
responsible_person_username = responsible_user.username
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
except (json.JSONDecodeError, TypeError, AttributeError):
|
||||
responsible_person = str(responsiblefor) if responsiblefor else ''
|
||||
|
||||
case_info = {
|
||||
'id': project.id,
|
||||
'type': 'project',
|
||||
'contract_no': ContractNo,
|
||||
'customer_name': CustomerID,
|
||||
'responsible_person': responsible_person
|
||||
}
|
||||
|
||||
except ProjectRegistration.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '立项登记不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 验证合同号、客户名称和负责人是否获取成功
|
||||
if not ContractNo:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '无法从案件管理中获取合同号,请检查案件信息',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not CustomerID:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '无法从案件管理中获取客户名称,请检查案件信息',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if not responsible_person_username:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': f'无法找到负责人"{responsible_person}"的用户信息,请检查负责人是否正确',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
date_string = now.strftime("%Y-%m-%d")
|
||||
|
||||
# 创建收入确认记录,allocate为空或"待审批人指定"
|
||||
# 创建收入确认记录,allocate为"待负责人指定"
|
||||
income = Income.objects.create(
|
||||
times=times,
|
||||
ContractNo=ContractNo,
|
||||
CustomerID=CustomerID,
|
||||
amount=amount,
|
||||
allocate=allocate if allocate else "待审批人指定", # 如果未提供,设为"待审批人指定"
|
||||
allocate=allocate if allocate else "待负责人指定", # 如果未提供,设为"待负责人指定"
|
||||
submit=user.username,
|
||||
submit_tiem=date_string,
|
||||
state="审核中"
|
||||
state="待负责人填写分配" # 新状态:等待负责人填写收入分配
|
||||
)
|
||||
|
||||
# 获取用户的团队信息
|
||||
team_name = user.team
|
||||
from User.utils import create_approval_with_team_logic
|
||||
|
||||
# 构建审批内容,包含案件信息(如果提供了)
|
||||
# 直接抄送给案件负责人(不经过团队审批流程)
|
||||
from User.models import Approval
|
||||
from User.utils import get_finance_personincharge_value
|
||||
|
||||
# 构建审批内容
|
||||
content_parts = [
|
||||
f"{user.username}在{times}提交了收入确认",
|
||||
f"合同编号:{ContractNo}",
|
||||
f"客户名称:{CustomerID}",
|
||||
f"收入金额:{amount}"
|
||||
f"收款金额:{amount}",
|
||||
f"收入分配:待负责人指定"
|
||||
]
|
||||
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,
|
||||
# 创建审批记录,直接抄送给负责人
|
||||
approval = Approval.objects.create(
|
||||
title=user.username + "提交收入确认",
|
||||
content=content,
|
||||
approval_type="收入确认",
|
||||
user_id=income.id,
|
||||
business_record=income,
|
||||
today=date_string
|
||||
times=date_string,
|
||||
personincharge=responsible_person_username, # 直接抄送给案件负责人
|
||||
state="审核中", # 负责人需要填写收入分配
|
||||
type="收入确认",
|
||||
user_id=str(income.id)
|
||||
)
|
||||
|
||||
# 如果返回None且需要审核,说明缺少审核人
|
||||
if approval is None and needs_approval:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': build_missing_approvers_message(team_name, approvers),
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 记录操作日志
|
||||
new_data = {
|
||||
'id': income.id,
|
||||
@@ -995,7 +1092,9 @@ class confirm(APIView):
|
||||
'CustomerID': income.CustomerID,
|
||||
'amount': income.amount,
|
||||
'allocate': income.allocate,
|
||||
'case_id': case_id if case_id else None
|
||||
'case_id': case_id if case_id else None,
|
||||
'project_id': project_id if project_id else None,
|
||||
'responsible_person': responsible_person_username
|
||||
}
|
||||
log_operation(
|
||||
request=request,
|
||||
@@ -1006,16 +1105,19 @@ class confirm(APIView):
|
||||
target_id=income.id,
|
||||
target_name=f'{income.ContractNo} - {income.CustomerID}',
|
||||
new_data=new_data,
|
||||
remark=f'新增收入确认:合同号 {income.ContractNo},金额 {income.amount},分配待审批人指定'
|
||||
remark=f'新增收入确认:合同号 {income.ContractNo},金额 {income.amount},已抄送给负责人 {responsible_person_username}'
|
||||
)
|
||||
|
||||
return Response({
|
||||
'message': '提交成功',
|
||||
'message': '提交成功,已抄送给负责人',
|
||||
'code': 0,
|
||||
'data': {
|
||||
'id': income.id,
|
||||
'ContractNo': income.ContractNo,
|
||||
'allocate': income.allocate
|
||||
'CustomerID': income.CustomerID,
|
||||
'responsible_person': responsible_person_username,
|
||||
'state': income.state,
|
||||
'approval_id': approval.id
|
||||
}
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
@@ -2525,3 +2627,393 @@ class DeleteUserDeparture(APIView):
|
||||
)
|
||||
|
||||
return Response({'message': '删除成功,用户状态已恢复为"在职"', 'code': 0}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class SearchCaseByContractNo(APIView):
|
||||
"""通过合同号搜索案件(用于增开票功能)"""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
通过合同号搜索案件,支持从Case和ProjectRegistration中搜索
|
||||
返回案件信息,包括合同号、负责人、项目类型等
|
||||
"""
|
||||
contract_no = request.data.get('contract_no', '').strip()
|
||||
|
||||
if not contract_no:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '缺少参数:contract_no(合同号)',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
from business.models import Case, ProjectRegistration
|
||||
import json
|
||||
|
||||
results = []
|
||||
|
||||
# 1. 从Case(案件管理)中搜索
|
||||
cases = Case.objects.filter(
|
||||
contract_no__icontains=contract_no,
|
||||
is_deleted=False
|
||||
).select_related('project').order_by('-id')[:20] # 限制返回数量
|
||||
|
||||
for case in cases:
|
||||
# 获取案件信息
|
||||
case_contract_no = case.contract_no
|
||||
case_responsiblefor = case.responsiblefor
|
||||
case_project_type = case.project_type
|
||||
case_client_name = case.client_name
|
||||
case_party_name = case.party_name
|
||||
case_project_description = case.project_description
|
||||
case_charge = case.charge
|
||||
|
||||
# 如果案件信息不完整,尝试从关联的ProjectRegistration获取
|
||||
if case.project:
|
||||
project = case.project
|
||||
case_contract_no = case_contract_no or project.ContractNo
|
||||
case_responsiblefor = case_responsiblefor or project.responsiblefor
|
||||
case_project_type = case_project_type or project.type
|
||||
case_client_name = case_client_name or project.client_info
|
||||
case_party_name = case_party_name or project.party_info
|
||||
case_project_description = case_project_description or project.description
|
||||
case_charge = case_charge or project.charge
|
||||
|
||||
# 解析负责人信息
|
||||
responsiblefor_dict = {}
|
||||
responsible_person = ''
|
||||
try:
|
||||
if case_responsiblefor:
|
||||
if isinstance(case_responsiblefor, str):
|
||||
responsiblefor_dict = json.loads(case_responsiblefor)
|
||||
else:
|
||||
responsiblefor_dict = case_responsiblefor
|
||||
responsible_person = responsiblefor_dict.get('responsible_person', '')
|
||||
except (json.JSONDecodeError, TypeError, AttributeError):
|
||||
responsible_person = str(case_responsiblefor) if case_responsiblefor else ''
|
||||
|
||||
results.append({
|
||||
'id': case.id,
|
||||
'type': 'case', # 标识这是案件管理中的案件
|
||||
'contract_no': case_contract_no or '',
|
||||
'responsiblefor': responsiblefor_dict if responsiblefor_dict else case_responsiblefor,
|
||||
'responsible_person': responsible_person, # 负责人姓名(用于显示)
|
||||
'project_type': case_project_type or '',
|
||||
'client_name': case_client_name or '',
|
||||
'party_name': case_party_name or '',
|
||||
'project_description': case_project_description or '',
|
||||
'charge': case_charge or '',
|
||||
'times': case.times,
|
||||
'project_id': case.project_id
|
||||
})
|
||||
|
||||
# 2. 从ProjectRegistration(立项登记)中搜索(如果还没有生成案件)
|
||||
projects = ProjectRegistration.objects.filter(
|
||||
ContractNo__icontains=contract_no,
|
||||
is_deleted=False
|
||||
).order_by('-id')[:20]
|
||||
|
||||
# 过滤掉已经生成案件的立项登记
|
||||
existing_project_ids = [case.project_id for case in cases if case.project_id]
|
||||
projects = projects.exclude(id__in=existing_project_ids)
|
||||
|
||||
for project in projects:
|
||||
# 解析负责人信息
|
||||
responsiblefor_dict = {}
|
||||
responsible_person = ''
|
||||
try:
|
||||
if project.responsiblefor:
|
||||
if isinstance(project.responsiblefor, str):
|
||||
responsiblefor_dict = json.loads(project.responsiblefor)
|
||||
else:
|
||||
responsiblefor_dict = project.responsiblefor
|
||||
responsible_person = responsiblefor_dict.get('responsible_person', '')
|
||||
except (json.JSONDecodeError, TypeError, AttributeError):
|
||||
responsible_person = str(project.responsiblefor) if project.responsiblefor else ''
|
||||
|
||||
results.append({
|
||||
'id': project.id,
|
||||
'type': 'project', # 标识这是立项登记
|
||||
'contract_no': project.ContractNo,
|
||||
'responsiblefor': responsiblefor_dict if responsiblefor_dict else project.responsiblefor,
|
||||
'responsible_person': responsible_person, # 负责人姓名(用于显示)
|
||||
'project_type': project.type or '',
|
||||
'client_name': project.client_info or '',
|
||||
'party_name': project.party_info or '',
|
||||
'project_description': project.description or '',
|
||||
'charge': project.charge or '',
|
||||
'times': project.times,
|
||||
'project_id': None
|
||||
})
|
||||
|
||||
return Response({
|
||||
'message': '搜索成功',
|
||||
'code': 0,
|
||||
'data': results,
|
||||
'total': len(results)
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class AddInvoice(APIView):
|
||||
"""增开票功能:通过合同号搜索,提取案件管理板块内容,负责人直接同步,其余信息手填,填好后直接抄送财务"""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
增开票申请
|
||||
- 通过合同号搜索选择案件(case_id或project_id)
|
||||
- 从案件管理中提取信息(合同号、负责人等)
|
||||
- 负责人自动同步
|
||||
- 其余信息手填
|
||||
- 提交后直接抄送财务(不需要审批流程)
|
||||
"""
|
||||
# 案件选择(二选一)
|
||||
case_id = request.data.get('case_id') # 案件管理ID
|
||||
project_id = request.data.get('project_id') # 立项登记ID
|
||||
contract_no = request.data.get('contract_no') # 合同号(用于搜索,可选)
|
||||
|
||||
# 手填信息
|
||||
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') # 提交人
|
||||
|
||||
# 必填字段验证
|
||||
missing_params = []
|
||||
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(提交人)')
|
||||
|
||||
if missing_params:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': f'缺少必填参数: {", ".join(missing_params)}',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 必须提供case_id或project_id之一
|
||||
if not case_id and not project_id:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '请选择案件:提供case_id(案件管理ID)或project_id(立项登记ID)',
|
||||
'code': 1
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
from business.models import Case, ProjectRegistration
|
||||
import json
|
||||
|
||||
# 从案件管理中提取信息
|
||||
ContractNo = None
|
||||
personincharge = None
|
||||
case_info = None
|
||||
|
||||
if case_id:
|
||||
# 从Case(案件管理)中获取信息
|
||||
try:
|
||||
case = Case.objects.select_related('project').get(id=case_id, is_deleted=False)
|
||||
|
||||
# 获取合同号
|
||||
ContractNo = case.contract_no
|
||||
|
||||
# 获取负责人信息
|
||||
personincharge = case.responsiblefor
|
||||
|
||||
# 如果案件信息不完整,从关联的ProjectRegistration获取
|
||||
if case.project:
|
||||
project = case.project
|
||||
ContractNo = ContractNo or project.ContractNo
|
||||
personincharge = personincharge or project.responsiblefor
|
||||
|
||||
# 解析负责人信息,提取负责人姓名用于显示
|
||||
responsible_person = ''
|
||||
try:
|
||||
if personincharge:
|
||||
if isinstance(personincharge, str):
|
||||
responsiblefor_dict = json.loads(personincharge)
|
||||
else:
|
||||
responsiblefor_dict = personincharge
|
||||
responsible_person = responsiblefor_dict.get('responsible_person', '')
|
||||
except (json.JSONDecodeError, TypeError, AttributeError):
|
||||
responsible_person = str(personincharge) if personincharge else ''
|
||||
|
||||
case_info = {
|
||||
'id': case.id,
|
||||
'type': 'case',
|
||||
'contract_no': ContractNo,
|
||||
'responsible_person': responsible_person
|
||||
}
|
||||
|
||||
except Case.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '案件不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
elif project_id:
|
||||
# 从ProjectRegistration(立项登记)中获取信息
|
||||
try:
|
||||
project = ProjectRegistration.objects.get(id=project_id, is_deleted=False)
|
||||
|
||||
ContractNo = project.ContractNo
|
||||
personincharge = project.responsiblefor
|
||||
|
||||
# 解析负责人信息,提取负责人姓名用于显示
|
||||
responsible_person = ''
|
||||
try:
|
||||
if personincharge:
|
||||
if isinstance(personincharge, str):
|
||||
responsiblefor_dict = json.loads(personincharge)
|
||||
else:
|
||||
responsiblefor_dict = personincharge
|
||||
responsible_person = responsiblefor_dict.get('responsible_person', '')
|
||||
except (json.JSONDecodeError, TypeError, AttributeError):
|
||||
responsible_person = str(personincharge) if personincharge else ''
|
||||
|
||||
case_info = {
|
||||
'id': project.id,
|
||||
'type': 'project',
|
||||
'contract_no': ContractNo,
|
||||
'responsible_person': responsible_person
|
||||
}
|
||||
|
||||
except ProjectRegistration.DoesNotExist:
|
||||
return Response({
|
||||
'status': 'error',
|
||||
'message': '立项登记不存在或已被删除',
|
||||
'code': 1
|
||||
}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# 验证合同号和负责人是否获取成功
|
||||
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)
|
||||
|
||||
# 处理负责人信息:提取负责人姓名,确保不超过100字符限制
|
||||
personincharge_display = ''
|
||||
try:
|
||||
if isinstance(personincharge, str):
|
||||
# 尝试解析JSON
|
||||
try:
|
||||
responsiblefor_dict = json.loads(personincharge)
|
||||
personincharge_display = responsiblefor_dict.get('responsible_person', '')
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
# 如果不是JSON,直接使用字符串
|
||||
personincharge_display = personincharge
|
||||
else:
|
||||
# 如果是字典,直接提取
|
||||
personincharge_display = personincharge.get('responsible_person', '') if isinstance(personincharge, dict) else str(personincharge)
|
||||
except (AttributeError, TypeError):
|
||||
personincharge_display = str(personincharge) if personincharge else ''
|
||||
|
||||
# 确保不超过100字符(Invoice.personincharge字段限制)
|
||||
if len(personincharge_display) > 100:
|
||||
personincharge_display = personincharge_display[:100]
|
||||
|
||||
# 如果提取失败,使用原始值(但需要确保是字符串且不超过100字符)
|
||||
if not personincharge_display:
|
||||
personincharge_str = str(personincharge) if personincharge else ''
|
||||
personincharge_display = personincharge_str[:100] if len(personincharge_str) > 100 else personincharge_str
|
||||
|
||||
# 创建开票记录
|
||||
today = datetime.datetime.now()
|
||||
formatted_date = today.strftime("%Y-%m-%d")
|
||||
|
||||
invoice = Invoice.objects.create(
|
||||
ContractNo=ContractNo,
|
||||
personincharge=personincharge_display, # 负责人姓名(字符串,不超过100字符)
|
||||
amount=amount,
|
||||
type=type,
|
||||
unit=unit,
|
||||
number=number,
|
||||
address_telephone=address_telephone,
|
||||
bank=bank,
|
||||
state="待财务处理", # 直接设为待财务处理,不需要审批
|
||||
username=username,
|
||||
times=formatted_date,
|
||||
)
|
||||
|
||||
# 直接抄送财务,不需要审批流程
|
||||
from User.utils import create_approval_with_team_logic
|
||||
|
||||
# 构建审批内容
|
||||
responsible_person_display = personincharge_display # 使用处理后的负责人姓名
|
||||
content_parts = [
|
||||
f"{username}在{formatted_date}提交了增开票申请",
|
||||
f"合同编号:{ContractNo}",
|
||||
f"负责人:{responsible_person_display}",
|
||||
f"开票金额:{amount}",
|
||||
f"开票类型:{type}",
|
||||
f"开票单位:{unit}"
|
||||
]
|
||||
content = ",".join(content_parts)
|
||||
|
||||
# 直接抄送财务(team_name=None, approvers=None)
|
||||
approval, approvers_order_json, needs_approval = create_approval_with_team_logic(
|
||||
team_name=None,
|
||||
approvers=None,
|
||||
title=username + "提交增开票申请",
|
||||
content=content,
|
||||
approval_type="增开票申请",
|
||||
user_id=invoice.id,
|
||||
business_record=invoice,
|
||||
today=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,
|
||||
'project_id': project_id if project_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},负责人 {responsible_person_display},金额 {invoice.amount},已直接抄送财务'
|
||||
)
|
||||
|
||||
return Response({
|
||||
'message': '提交成功,已直接抄送财务',
|
||||
'code': 0,
|
||||
'data': {
|
||||
'id': invoice.id,
|
||||
'ContractNo': invoice.ContractNo,
|
||||
'personincharge': invoice.personincharge,
|
||||
'responsible_person': responsible_person_display,
|
||||
'state': invoice.state,
|
||||
'approval_id': approval.id if approval else None
|
||||
}
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
Reference in New Issue
Block a user