From b097ecffbe9c1dc976136b4ff5339f7d1ba597b6 Mon Sep 17 00:00:00 2001 From: laoxiao Date: Thu, 6 Apr 2023 22:02:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=98=E6=AC=BE=E5=8D=95=E7=9A=84=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=AE=8C=E6=88=90=E9=83=A8=E5=88=86=E5=B9=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=88=90=E5=8A=9F=EF=BC=8C=E8=BF=98=E6=9C=89?= =?UTF-8?q?=E4=BB=98=E6=AC=BE=E5=8D=95=E7=9A=84=E5=AE=A1=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../financial_info/serializer/__init__.py | 0 .../serializer/payment_serializer.py | 74 ++++++++++ ERP_5/apps/financial_info/urls.py | 32 +++++ ERP_5/apps/financial_info/views/__init__.py | 0 .../financial_info/views/payment_views.py | 135 ++++++++++++++++++ ERP_5/apps/purchase_info/models.py | 2 +- .../serializers/purchase_serializer.py | 2 +- ERP_5/apps/warehouse_info/models.py | 4 +- ERP_5/apps/warehouse_info/urls.py | 32 +++++ .../warehouse_info/views/in_storage_views.py | 2 +- ERP_5/settings/dev.py | 1 + ERP_5/urls.py | 2 + 12 files changed, 281 insertions(+), 5 deletions(-) create mode 100644 ERP_5/apps/financial_info/serializer/__init__.py create mode 100644 ERP_5/apps/financial_info/serializer/payment_serializer.py create mode 100644 ERP_5/apps/financial_info/urls.py create mode 100644 ERP_5/apps/financial_info/views/__init__.py create mode 100644 ERP_5/apps/financial_info/views/payment_views.py create mode 100644 ERP_5/apps/warehouse_info/urls.py diff --git a/ERP_5/apps/financial_info/serializer/__init__.py b/ERP_5/apps/financial_info/serializer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ERP_5/apps/financial_info/serializer/payment_serializer.py b/ERP_5/apps/financial_info/serializer/payment_serializer.py new file mode 100644 index 0000000..035178a --- /dev/null +++ b/ERP_5/apps/financial_info/serializer/payment_serializer.py @@ -0,0 +1,74 @@ +from django.db import transaction +from django.db.models import Sum +from rest_framework import serializers +from rest_framework.exceptions import ValidationError + +from financial_info.models import PaymentItemModel, PaymentModel + + +class PaymentItemSerializer(serializers.ModelSerializer): + """ + 付款单中 付款项目 的序列化器 + """ + # 查询当前采购入库单中已经支付金额 + already_payment = serializers.SerializerMethodField(read_only=True, help_text='已经付款的金额') + + class Meta: + model = PaymentItemModel + fields = '__all__' + + def get_already_payment(self, obj): + """ + 查询当前采购入库单中已经支付金额 + :param obj: PaymentItemModel + :return: 0获取其他的数值 + """ + if obj.purchase_storage: + pay_dict = PaymentItemModel.objects.filter(purchase_storage_id=obj.purchase_storage.id)\ + .exclude(payment__status='0')\ + .aggregate(sum=Sum('this_money')) + if pay_dict: + return pay_dict['sum'] if pay_dict['sum'] else 0 + return 0 + return 0 + + +class PaymentSerializer(serializers.ModelSerializer): + """ + 付款单——序列化器 + """ + item_list = PaymentItemSerializer(many=True, required=False) + + class Meta: + model = PaymentModel + fields = '__all__' + + def create(self, validated_data): + if 'item_list' not in validated_data: + return super(PaymentSerializer, self).create(validated_data) + item_list = validated_data.pop('item_list') + with transaction.atomic(): + payment = PaymentModel.objects.create(**validated_data) + for item in item_list: + # 插入付款项目 + PaymentItemModel.objects.create(payment=payment, **item) + return payment + + # 必须重写update + def update(self, instance, validated_data): + if instance.status != '0': + raise ValidationError("付款单已经生效,不能修改!") + with transaction.atomic(): + + if 'item_list' in validated_data: + item_list = validated_data.pop('item_list') + old_list = instance.item_list.all() + + if old_list.exists(): + # 然后把旧数据删除,因为在validated_data拿不到货品库存数据的ID + instance.item_list.all().delete() + + for item in item_list: # 重新插入采购项 数据 + PaymentItemModel.objects.create(payment=instance, **item) + result = super(PaymentSerializer, self).update(instance=instance, validated_data=validated_data) + return result diff --git a/ERP_5/apps/financial_info/urls.py b/ERP_5/apps/financial_info/urls.py new file mode 100644 index 0000000..67e36b3 --- /dev/null +++ b/ERP_5/apps/financial_info/urls.py @@ -0,0 +1,32 @@ +"""ERP_5 URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, re_path +from rest_framework.routers import DefaultRouter +from .views import payment_views + +from rest_framework_jwt.views import obtain_jwt_token + +urlpatterns = [ + # path('admin/', admin.site.urls), + + +] + +router = DefaultRouter() +router.register('payment', payment_views.PaymentViewSet) + +urlpatterns += router.urls diff --git a/ERP_5/apps/financial_info/views/__init__.py b/ERP_5/apps/financial_info/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ERP_5/apps/financial_info/views/payment_views.py b/ERP_5/apps/financial_info/views/payment_views.py new file mode 100644 index 0000000..c40dbd4 --- /dev/null +++ b/ERP_5/apps/financial_info/views/payment_views.py @@ -0,0 +1,135 @@ +from django.db import transaction +from django.db.models import Q +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema +from rest_framework import viewsets +from rest_framework.decorators import action + +from ERP_5.utils.base_views import MultipleDestroyMixin, MultipleAuditMixin +from ERP_5.utils.paginations import GlobalPagination +from erp_system.models import UserModel +from financial_info.models import PaymentModel +from financial_info.serializer.payment_serializer import PaymentSerializer + + +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"), + 'is_audit': openapi.Schema(type=openapi.TYPE_STRING, description="是否审核,审核:1") + }) + + @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 item in queryset: + pass \ No newline at end of file diff --git a/ERP_5/apps/purchase_info/models.py b/ERP_5/apps/purchase_info/models.py index 77519f8..b1cc4e9 100644 --- a/ERP_5/apps/purchase_info/models.py +++ b/ERP_5/apps/purchase_info/models.py @@ -22,7 +22,7 @@ class PurchaseModel(BaseModel): verbose_name='采购操作人员,不能修改') # 增加一个冗余字段 operator_user_name = models.CharField('操作人员的真实姓名', max_length=20, null=True, blank=True) - check_user = models.ForeignKey('erp_system.UserModel', null=True, blank=True, on_delete=models.SET_NULL, + check_user = models.ForeignKey('erp_system.UserModel', related_name='checker2_purchase_list', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='审核人员,不能修改') # 增加一个冗余字段 check_user_name = models.CharField('操作人员的真实姓名', max_length=20, null=True, blank=True) diff --git a/ERP_5/apps/purchase_info/serializers/purchase_serializer.py b/ERP_5/apps/purchase_info/serializers/purchase_serializer.py index 8f4e7af..2368a33 100644 --- a/ERP_5/apps/purchase_info/serializers/purchase_serializer.py +++ b/ERP_5/apps/purchase_info/serializers/purchase_serializer.py @@ -35,7 +35,7 @@ class PurchaseItemsSerializer(serializers.ModelSerializer): goods_id=obj.goods.id).exclude(purchase_storage__status='0')\ .aggregate(sum=Sum('purchase_count')) if in_count: - return in_count['sum'] + return in_count['sum'] if in_count['sum'] else 0 return 0 class PurchaseSerializer(serializers.ModelSerializer): diff --git a/ERP_5/apps/warehouse_info/models.py b/ERP_5/apps/warehouse_info/models.py index 9283bf0..f35bad4 100644 --- a/ERP_5/apps/warehouse_info/models.py +++ b/ERP_5/apps/warehouse_info/models.py @@ -25,12 +25,12 @@ class PurchaseStorageModel(BaseModel): number_count = models.DecimalField('入库总数量,最多精确到小数点后两位', max_digits=10, decimal_places=2, blank=True, default=0) status = models.CharField('状态,0:未审核,1:已审核,2:付款完成', max_length=1, default='0') - operator_user = models.ForeignKey('erp_system.UserModel', related_name='operator_in_list', null=True, + operator_user = models.ForeignKey('erp_system.UserModel', related_name='operator4_in_list', null=True, on_delete=models.SET_NULL, verbose_name='入库操作人员,不能修改') # 增加一个冗余字段 operator_user_name = models.CharField('操作人员的真实姓名', max_length=20, null=True, blank=True) - check_user = models.ForeignKey('erp_system.UserModel', null=True, blank=True, on_delete=models.SET_NULL, + check_user = models.ForeignKey('erp_system.UserModel', related_name='checker3_in_list', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='审核人员,不能修改') # 增加一个冗余字段 check_user_name = models.CharField('操作人员的真实姓名', max_length=20, null=True, blank=True) diff --git a/ERP_5/apps/warehouse_info/urls.py b/ERP_5/apps/warehouse_info/urls.py new file mode 100644 index 0000000..af64f97 --- /dev/null +++ b/ERP_5/apps/warehouse_info/urls.py @@ -0,0 +1,32 @@ +"""ERP_5 URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, re_path +from rest_framework.routers import DefaultRouter +from .views import in_storage_views + +from rest_framework_jwt.views import obtain_jwt_token + +urlpatterns = [ + # path('admin/', admin.site.urls), + + +] + +router = DefaultRouter() +router.register('storage', in_storage_views.InStorageViewSet) + +urlpatterns += router.urls diff --git a/ERP_5/apps/warehouse_info/views/in_storage_views.py b/ERP_5/apps/warehouse_info/views/in_storage_views.py index 894142a..bc6bff8 100644 --- a/ERP_5/apps/warehouse_info/views/in_storage_views.py +++ b/ERP_5/apps/warehouse_info/views/in_storage_views.py @@ -160,7 +160,7 @@ class InStorageViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAudi .aggregate(my_sum=Sum('number_count')) in_count = 0 if in_count_dict: - in_count = in_count_dict['my_sum'] + in_count = in_count_dict['my_sum'] if in_count_dict['my_sum'] else 0 # 第一种情况: 已经入库数量 + 当前正在入库的数量 == 采购总数量。 if (in_count + item.number_count) == item.purchase.number_count: item.purchase.status = '3' # 全部入库 diff --git a/ERP_5/settings/dev.py b/ERP_5/settings/dev.py index a479f68..7242f6f 100644 --- a/ERP_5/settings/dev.py +++ b/ERP_5/settings/dev.py @@ -46,6 +46,7 @@ INSTALLED_APPS = [ 'goods_info', 'purchase_info', 'warehouse_info', + 'financial_info', # 'django.contrib.staticfiles', # required for serving swagger ui's css/js files 'drf_yasg', diff --git a/ERP_5/urls.py b/ERP_5/urls.py index ace57ca..d025cd5 100644 --- a/ERP_5/urls.py +++ b/ERP_5/urls.py @@ -39,6 +39,8 @@ urlpatterns = [ path('api/', include('basic_info.urls')), path('api/', include('goods_info.urls')), path('api/', include('purchase_info.urls')), + path('api/', include('warehouse_info.urls')), + path('api/', include('financial_info.urls')), re_path(r'^api/generate_code/$', GenerateCode.as_view()), # 媒体资源文件的访问路由