diff --git a/ERP_5/apps/financial_info/__init__.py b/ERP_5/apps/financial_info/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ERP_5/apps/financial_info/admin.py b/ERP_5/apps/financial_info/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/ERP_5/apps/financial_info/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/ERP_5/apps/financial_info/apps.py b/ERP_5/apps/financial_info/apps.py new file mode 100644 index 0000000..75bd5f6 --- /dev/null +++ b/ERP_5/apps/financial_info/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class FinancialInfoConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'financial_info' diff --git a/ERP_5/apps/financial_info/migrations/__init__.py b/ERP_5/apps/financial_info/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ERP_5/apps/financial_info/models.py b/ERP_5/apps/financial_info/models.py new file mode 100644 index 0000000..e0fdd10 --- /dev/null +++ b/ERP_5/apps/financial_info/models.py @@ -0,0 +1,79 @@ +from django.db import models +from ERP_5.utils.base_model import BaseModel +# 货币种类 +currency_choices = ( + ('CNY', '人民币'), + ('USD', '美元'), + ('EUR', '欧元'), + ('JPY', '日元'), + ('HKD', '港币') +) + +# 付款类型 +pay_choices = ( + ('1', '采购定金'), + ('2', '采购货款'), + ('3', '欠款还款'), + ('4', '其他付款') +) + + +# 付款单的模型类 +class PaymentModel(BaseModel): + pay_date = models.DateTimeField('付款日期') + number_code = models.CharField('单据编号,不让用户填写', max_length=28) + discount_money = models.DecimalField('优惠金额(付款优惠),最多精确到小数点后两位', max_digits=10, default=0, decimal_places=2, + blank=True, null=True) + pay_money = models.DecimalField('合计 付款金额最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + this_money = models.DecimalField('实际 付款金额最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + remark = models.CharField('备注', max_length=512, blank=True, null=True) + currency = models.CharField('货币种类', max_length=20, null=True, choices=currency_choices, default='CNY') + pay_category = models.CharField('付款类型', max_length=2, null=True, choices=pay_choices, default='1') + status = models.CharField('状态,0:未审核,1:已审核', max_length=1, default='0') + + account = models.ForeignKey('basic_info.SettlementAccountModel', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='结算账户,审核之后不能改') + operator_user = models.ForeignKey('erp_system.UserModel', related_name='operator_pay_list', null=True, + blank=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', related_name='operator3_pay_list', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='审核人员,不能修改') + # 增加一个冗余字段 + check_user_name = models.CharField('审核人员的真实姓名', max_length=20, null=True, blank=True) + + supplier = models.ForeignKey('basic_info.SupplierModel', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='供应商,审核之后不能改') + # 增加一个冗余字段 + supplier_name = models.CharField('供应商名称', max_length=30, null=True, blank=True) + purchase = models.ForeignKey('purchase_info.PurchaseModel', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='采购订单,审核之后不能改') + attachment_list = models.CharField('附件的id列表,字段的值为: 1,2,3,4', max_length=20, null=True, blank=True) + + class Meta: + db_table = 't_payment' + verbose_name = '付款单表' + verbose_name_plural = verbose_name + ordering = ['id'] + + +# 付款单中 付款项目的模型类 +class PaymentItemModel(BaseModel): + # 冗余字段 + storage_code = models.CharField('采购入库单编号,不让用户填写', max_length=28) + purchase_storage = models.ForeignKey('warehouse_info.PurchaseStorageModel', related_name='pay_item_list', null=True, blank=True, + on_delete=models.SET_NULL, verbose_name='采购入库单') + + payment = models.ForeignKey('PaymentModel', null=True, blank=True, related_name='item_list', on_delete=models.SET_NULL, + verbose_name='付款单,不能改') + should_money = models.DecimalField('应该 付款金额(就是采购入库单中需要支付的金额),最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + this_money = models.DecimalField('本次 付款金额,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + + remark = models.CharField('备注', max_length=512, blank=True, null=True) + + class Meta: + db_table = 't_payment_item' + verbose_name = '付款单中的 付款项目表' + verbose_name_plural = verbose_name + ordering = ['id'] diff --git a/ERP_5/apps/financial_info/tests.py b/ERP_5/apps/financial_info/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ERP_5/apps/financial_info/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ERP_5/apps/financial_info/views.py b/ERP_5/apps/financial_info/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/ERP_5/apps/financial_info/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/ERP_5/apps/financial_info/views/payment_views.py b/ERP_5/apps/financial_info/views/payment_views.py index c40dbd4..4bb63ed 100644 --- a/ERP_5/apps/financial_info/views/payment_views.py +++ b/ERP_5/apps/financial_info/views/payment_views.py @@ -1,15 +1,18 @@ from django.db import transaction -from django.db.models import Q +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 +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 +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): @@ -118,7 +121,6 @@ class PaymentViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditM '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="批量审核") @@ -131,5 +133,64 @@ class PaymentViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditM # 为了减少代码量,参数的验证就不写了 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 + 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: + pm.purchase.status = '5' # 已付定金 + pm.purchase.save() + # 业务二: 供应商欠款 支付 + if pm.pay_category == '3': + 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) \ No newline at end of file diff --git a/ERP_5/apps/sale_info/__init__.py b/ERP_5/apps/sale_info/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ERP_5/apps/sale_info/admin.py b/ERP_5/apps/sale_info/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/ERP_5/apps/sale_info/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/ERP_5/apps/sale_info/apps.py b/ERP_5/apps/sale_info/apps.py new file mode 100644 index 0000000..9633351 --- /dev/null +++ b/ERP_5/apps/sale_info/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SaleInfoConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'sale_info' diff --git a/ERP_5/apps/sale_info/migrations/__init__.py b/ERP_5/apps/sale_info/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ERP_5/apps/sale_info/models.py b/ERP_5/apps/sale_info/models.py new file mode 100644 index 0000000..8cb3d27 --- /dev/null +++ b/ERP_5/apps/sale_info/models.py @@ -0,0 +1,71 @@ +from django.db import models +from ERP_5.utils.base_model import BaseModel + + +# 销售订单 模型类 +class SaleModel(BaseModel): + invoices_date = models.DateTimeField('单据日期') + number_code = models.CharField('单据编号,不让用户填写', max_length=28) + discount = models.DecimalField('优惠率,最多精确到小数点后两位', max_digits=5, decimal_places=2, blank=True, default=0) + discount_money = models.DecimalField('优惠金额(付款优惠),最多精确到小数点后两位', max_digits=10, decimal_places=2, blank=True, + default=0) + remark = models.CharField('备注', max_length=512, blank=True, null=True) + last_amount = models.DecimalField('优惠后总金额,最多精确到小数点后两位', max_digits=13, decimal_places=2, blank=True, default=0) + deposit = models.DecimalField('收取定金,最多精确到小数点后两位', max_digits=10, decimal_places=2, blank=True, default=0) + + number_count = models.DecimalField('销售数量,最多精确到小数点后两位', max_digits=10, decimal_places=2, blank=True, default=0) + status = models.CharField('状态,0:未审核,1:已审核,2:部分发货,3:全部发货,4:完成销售,5:已收定金', max_length=1, default='0') + + operator_user = models.ForeignKey('erp_system.UserModel', related_name='operator_sale_list', null=True, + blank=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, + verbose_name='审核人员,不能修改') + # 增加一个冗余字段 + check_user_name = models.CharField('审核人员的真实姓名', max_length=20, null=True, blank=True) + + account = models.ForeignKey('basic_info.SettlementAccountModel', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='结算账户,审核之后不能改') + + customer = models.ForeignKey('basic_info.CustomerModel', null=True, blank=True, on_delete=models.SET_NULL, + verbose_name='客户,审核之后不能改') + # 增加一个冗余字段 + customer_name = models.CharField('客户名称', max_length=30, null=True, blank=True) + + attachment_list = models.CharField('附件的id列表,字段的值为: 1,2,3,4', max_length=20, null=True, blank=True) + + class Meta: + db_table = 't_sales' + verbose_name = '销售表' + verbose_name_plural = verbose_name + ordering = ['id'] + + +# 销售订单(货品项目) 模型类 +class SaleItemModel(BaseModel): + # 这些个也都是冗余字段, 减少查询的时候,表连接查询的次数 + name = models.CharField(max_length=20, verbose_name='货品名称') + number_code = models.CharField('货品的编号或者批号', max_length=28, null=True, blank=True) + specification = models.CharField('货品规格', max_length=50, null=True, blank=True) + model_number = models.CharField('型号', max_length=50, null=True, blank=True) + color = models.CharField('颜色', max_length=50, null=True, blank=True) + units_name = models.CharField('单位名字', max_length=50, null=True, blank=True) + units = models.ForeignKey('goods_info.UnitsModel', on_delete=models.SET_NULL, null=True, blank=True) + remark = models.CharField('备注', max_length=512, blank=True, null=True) + sales_count = models.DecimalField('销售数量,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + sales_price = models.DecimalField('销售单价,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + sales_money = models.DecimalField('销售金额,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0) + + sale = models.ForeignKey('SaleModel', related_name='item_list', null=True, blank=True, + on_delete=models.CASCADE, + verbose_name='销售单') + goods = models.ForeignKey('goods_info.GoodsModel', null=True, on_delete=models.SET_NULL, + verbose_name='货品,必须要传') + + class Meta: + db_table = 't_sales_items' + verbose_name = '销售订单的项目表' + verbose_name_plural = verbose_name + ordering = ['id'] \ No newline at end of file diff --git a/ERP_5/apps/sale_info/tests.py b/ERP_5/apps/sale_info/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ERP_5/apps/sale_info/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ERP_5/apps/sale_info/views.py b/ERP_5/apps/sale_info/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/ERP_5/apps/sale_info/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.