from django.db import transaction from django.db.models import Q, F, Sum from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response from ERP_5.utils.base_views import MultipleDestroyMixin, MultipleAuditMixin from ERP_5.utils.paginations import GlobalPagination from basic_info.models import SupplierModel, SettlementAccountModel from erp_system.models import UserModel from financial_info.models import PaymentModel, PaymentItemModel from financial_info.serializer.payment_serializer import PaymentSerializer from warehouse_info.models import PurchaseStorageModel class PaymentViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditMixin): """ create: 付款单--新增,注意:其中images_list="1,2,3,4";里面是附件的ID 付款单新增, status: 201(成功), return: 新增付款单信息 destroy: 付款单--删除 付款单删除, status: 204(成功), return: None multiple_delete: 付款单--批量删除,必传参数:ids=[1,2,3,4...] 付款单批量删除, status: 204(成功), return: None update: 付款单--修改,注意:其中images_list="1,2,3,4";里面是附件的ID 付款单修改, status: 200(成功), return: 修改后的付款单信息 list: 付款单--该接口可以弃用 付款单列表信息, status: 200(成功), return: 付款单信息列表 retrieve: 查询某一个付款单 查询指定ID的付款单, status: 200(成功), return: 用户付款单 """ queryset = PaymentModel.objects.all() serializer_class = PaymentSerializer pagination_class = GlobalPagination def get_queryset(self): if self.action == 'find': # 过滤查询 # 获取请求参数(在json中): number_code = self.request.data.get('number_code', None) check_user = self.request.data.get('check_user', 0) start_date = self.request.data.get('start_date', None) end_date = self.request.data.get('start_date', None) supplier = self.request.data.get('supplier', 0) operator_user = self.request.data.get('operator_user', 0) status = self.request.data.get('status', None) account = self.request.data.get('account', 0) purchase_number_code = self.request.data.get('purchase_number_code', None) query = Q() if check_user: query.add(Q(check_user__id=check_user), 'AND') if account: query.add(Q(account__id=account), 'AND') if purchase_number_code: query.add(Q(purchase__number_code__contains=purchase_number_code), 'AND') if start_date: query.add(Q(pay_date__gt=start_date), 'AND') if end_date: query.add(Q(pay_date__lt=end_date), 'AND') if supplier: query.add(Q(supplier__id=supplier), 'AND') if number_code: query.add(Q(number_code__contains=number_code), 'AND') if operator_user: query.add(Q(operator_user__id=operator_user), 'AND') if status: query.add(Q(status=status), 'AND') return PaymentModel.objects.filter(query).distinct().all() else: return PaymentModel.objects.all() params = openapi.Schema(type=openapi.TYPE_OBJECT, properties={ 'start_date': openapi.Schema(type=openapi.TYPE_STRING, description="起始日期2020-10-01"), 'number_code': openapi.Schema(type=openapi.TYPE_STRING, description="付款单编号(序列号)"), 'end_date': openapi.Schema(type=openapi.TYPE_STRING, description="结束日期2020-10-01"), 'status': openapi.Schema(type=openapi.TYPE_STRING, description="状态0或者1"), 'supplier': openapi.Schema(type=openapi.TYPE_INTEGER, description="供应商的ID"), 'operator_user': openapi.Schema(type=openapi.TYPE_INTEGER, description="财务人员的ID"), 'check_user': openapi.Schema(type=openapi.TYPE_INTEGER, description="审核人员的ID"), 'account': openapi.Schema(type=openapi.TYPE_INTEGER, description="结算账户的ID"), 'purchase_number_code': openapi.Schema(type=openapi.TYPE_STRING, description="采购订单编号关键字"), }) # 分页参数必须是query_param(看源码) page_param = openapi.Parameter(name='page', in_=openapi.IN_QUERY, description="页号", type=openapi.TYPE_INTEGER) size_param = openapi.Parameter(name='size', in_=openapi.IN_QUERY, description="每页显示数量", type=openapi.TYPE_INTEGER) @swagger_auto_schema(method='POST', request_body=params, manual_parameters=[page_param, size_param], operation_description="付款单的搜索过滤") @action(methods=['POST'], detail=False) def find(self, request, *args, **kwargs): return super(PaymentViewSet, self).list(request=request, *args, **kwargs) """ 自定义的 批量审核的 视图函数 """ body_param = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids', 'user_id'], properties={ 'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER), description="选择哪些需要批量的ID(主键)列表"), 'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="审核人的用户ID"), }) @swagger_auto_schema(method='put', request_body=body_param, operation_description="批量审核") @action(methods=['put'], detail=False) @transaction.atomic # 自动 数据库事务 def multiple_audit(self, request, *args, **kwargs): audit_ids = request.data.get('ids') user_id = request.data.get('user_id') # 用户ID is_audit = request.data.get('is_audit', '1') # 审核:1 # 为了减少代码量,参数的验证就不写了 queryset = self.get_queryset().filter(id__in=audit_ids).all() check_user = UserModel.objects.get(id=int(user_id)) for pm in queryset: # 期中pm是付款单 # 判断1:关联的采购单状态是否为“未审核” if pm.purchase and pm.purchase.status == '0': return Response(data={'detail': '采购订单未审核,不能付款'}, status=status.HTTP_400_BAD_REQUEST) # 判断2 付款单的状态是否为:“已审核” if pm.status == '1': return Response(data={'detail': '付款单已经审核,不需要再次审核'}, status=status.HTTP_400_BAD_REQUEST) # 判断3 结算账户的余额是否够用 if pm.this_money > pm.account.balance: return Response(data={'detail': '选择的结算账户中的余额不够,不能付款'}, status=status.HTTP_400_BAD_REQUEST) # 处理关联业务逻辑 # 业务一: 采购定金付款 if pm.pay_category == '1' and pm.purchase and not pm.item_list.exists(): pm.purchase.status = '5' # 已付定金 pm.purchase.save() # 业务二: 供应商欠款 支付 if pm.pay_category == '3' and not pm.item_list.exists(): SupplierModel.objects.filter(id=pm.supplier.id).update(current_pay=F('current_pay') - pm.pay_money) # 业务三: 入库货款 支付 if pm.pay_category == '2' and pm.purchase: if pm.item_list.exists(): # 这种判断不回从数据库中返回数据 for item in pm.item_list.all(): # 期中item是付款项目 # 判断4: 入库单必须是已经审核状态 if item.purchase_storage and item.purchase_storage.status != '1': return Response(data={'detail': '入库单未审核或者已经付款,不能付款'}, status=status.HTTP_400_BAD_REQUEST) # 业务三——第1种情况 对应的入库单,是否应该:付款完成 ,首先需要查询该入库单的已经付款金额之和 sum_dict = PaymentItemModel.objects\ .filter(purchase_storage_id=item.purchase_storage.id, payment__status='1')\ .aggregate(sum=Sum('this_money')) pay_sum = sum_dict['sum'] if sum_dict['sum'] else 0 if item.should_money == (pay_sum + item.this_money): item.purchase_storage.status = '2' # 把入库单的状态修改为:付款完成 item.purchase_storage.save() # 业务三——第2种情况 对应的采购单状态是否要改为:采购完成 # 采购完成的条件: 1、该采购单必须是:全部入库状态;2、该采购单中 所有的入库单状态也都必须是:付款完成 purchase = item.payment.purchase if purchase.status == '3': # 查询 该采购单中 所有入库单状态不是:'付款完成' 的有多少个? number = PurchaseStorageModel.objects\ .filter(purchase_id=purchase.id)\ .exclude(status='2').count() if number == 0: # 则 所有的入库单状态都为:付款完成 purchase.status = '4' # 修改采购单状态为: 采购完成 purchase.save() else: return Response(data={'detail': '没有选择付款项目,支付货款的时候必须选择'}, status=status.HTTP_400_BAD_REQUEST) # 至此: 三种业务都完成 # 业务四: 修改 结算账户的余额 SettlementAccountModel.objects.filter(id=pm.account.id)\ .update(balance=F('balance') - pm.this_money) # 至此: 四种业务都完成,开始修改付款单的状态以及审核信息 # 审核 self.get_queryset().filter(id__in=audit_ids) \ .update( status='1', check_user_name=check_user.real_name, check_user_id=check_user.id) return Response(status=status.HTTP_200_OK)