Compare commits

..

4 Commits

Author SHA1 Message Date
laoxiao 7d1e03cbe0 Merge branch 'master' of https://git.mashibing.com/msb_20618/ERP6
2 years ago
laoxiao 6a83bf6e14 写完了领料功能
2 years ago
laoxiao f02faf8772 写完了领料功能
2 years ago
laoxiao 5062f48c88 写完了领料功能
2 years ago

@ -0,0 +1,74 @@
# Generated by Django 3.2.16 on 2023-04-06 21:31
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('basic_info', '0002_initial'),
('warehouse_info', '0001_initial'),
('purchase_info', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='PaymentModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('pay_date', models.DateTimeField(verbose_name='付款日期')),
('number_code', models.CharField(max_length=28, verbose_name='单据编号,不让用户填写')),
('discount_money', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='优惠金额(付款优惠),最多精确到小数点后两位')),
('pay_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='合计 付款金额最多精确到小数点后两位')),
('this_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='实际 付款金额最多精确到小数点后两位')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('currency', models.CharField(choices=[('CNY', '人民币'), ('USD', '美元'), ('EUR', '欧元'), ('JPY', '日元'), ('HKD', '港币')], default='CNY', max_length=20, null=True, verbose_name='货币种类')),
('pay_category', models.CharField(choices=[('1', '采购定金'), ('2', '采购货款'), ('3', '欠款还款'), ('4', '其他付款')], default='1', max_length=2, null=True, verbose_name='付款类型')),
('status', models.CharField(default='0', max_length=1, verbose_name='状态,0:未审核,1:已审核')),
('operator_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='财务人员的真实姓名')),
('check_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='审核人员的真实姓名')),
('supplier_name', models.CharField(blank=True, max_length=30, null=True, verbose_name='供应商名称')),
('attachment_list', models.CharField(blank=True, max_length=20, null=True, verbose_name='附件的id列表字段的值为: 1,2,3,4')),
('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.settlementaccountmodel', verbose_name='结算账户,审核之后不能改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator3_pay_list', to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('operator_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator_pay_list', to=settings.AUTH_USER_MODEL, verbose_name='财务操作人员,不能修改')),
('purchase', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='purchase_info.purchasemodel', verbose_name='采购订单,审核之后不能改')),
('supplier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.suppliermodel', verbose_name='供应商,审核之后不能改')),
],
options={
'verbose_name': '付款单表',
'verbose_name_plural': '付款单表',
'db_table': 't_payment',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='PaymentItemModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('storage_code', models.CharField(max_length=28, verbose_name='采购入库单编号,不让用户填写')),
('should_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='应该 付款金额(就是采购入库单中需要支付的金额),最多精确到小数点后两位')),
('this_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='本次 付款金额,最多精确到小数点后两位')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('payment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='item_list', to='financial_info.paymentmodel', verbose_name='付款单,不能改')),
('purchase_storage', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pay_item_list', to='warehouse_info.purchasestoragemodel', verbose_name='采购入库单')),
],
options={
'verbose_name': '付款单中的 付款项目表',
'verbose_name_plural': '付款单中的 付款项目表',
'db_table': 't_payment_item',
'ordering': ['id'],
},
),
]

@ -0,0 +1,73 @@
# Generated by Django 3.2.16 on 2023-04-13 20:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('warehouse_info', '0002_saledeliveritemmodel_saledelivermodel'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('basic_info', '0002_initial'),
('sale_info', '0001_initial'),
('financial_info', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='ReceiptModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('pay_date', models.DateTimeField(verbose_name='收款日期')),
('number_code', models.CharField(max_length=28, verbose_name='单据编号,不让用户填写')),
('discount_money', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='优惠金额(收款优惠),最多精确到小数点后两位')),
('receipt_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='合计 收款金额最多精确到小数点后两位')),
('this_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='实际 收款金额最多精确到小数点后两位')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('currency', models.CharField(choices=[('CNY', '人民币'), ('USD', '美元'), ('EUR', '欧元'), ('JPY', '日元'), ('HKD', '港币')], default='CNY', max_length=20, null=True, verbose_name='货币种类')),
('receipt_category', models.CharField(choices=[('1', '销售定金'), ('2', '销售出库货款'), ('3', '客户还款的收款'), ('4', '其他收款')], default='1', max_length=2, null=True, verbose_name='收款类型')),
('status', models.CharField(default='0', max_length=1, verbose_name='状态,0:未审核,1:已审核')),
('operator_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='财务人员的真实姓名')),
('check_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='审核人员的真实姓名')),
('customer_name', models.CharField(blank=True, max_length=30, null=True, verbose_name='客户名称')),
('attachment_list', models.CharField(blank=True, max_length=20, null=True, verbose_name='附件的id列表字段的值为: 1,2,3,4')),
('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.settlementaccountmodel', verbose_name='结算账户,审核之后不能改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator4_pay_list', to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.customermodel', verbose_name='客户,审核之后不能改')),
('operator_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator2_pay_list', to=settings.AUTH_USER_MODEL, verbose_name='财务操作人员,不能修改')),
('sale', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sale_info.salemodel', verbose_name='销售订单,审核之后不能改')),
],
options={
'verbose_name': '收款单表',
'verbose_name_plural': '收款单表',
'db_table': 't_receipt',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='ReceiptItemModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('storage_code', models.CharField(max_length=28, verbose_name='销售出库单编号,不让用户填写')),
('should_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='应该 收款金额(就是采购入库单中需要支收的金额),最多精确到小数点后两位')),
('this_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='本次 收款金额,最多精确到小数点后两位')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('deliver_storage', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pay_item_list', to='warehouse_info.saledelivermodel', verbose_name='采购入库单')),
('receipt', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='item_list', to='financial_info.receiptmodel', verbose_name='收款单,不能改')),
],
options={
'verbose_name': '收款单中的 收款项目表',
'verbose_name_plural': '收款单中的 收款项目表',
'db_table': 't_receipt_item',
'ordering': ['id'],
},
),
]

@ -79,6 +79,75 @@ class PaymentItemModel(BaseModel):
ordering = ['id']
# 收款类型
receipt_choices = (
('1', '销售定金'),
('2', '销售出库货款'),
('3', '客户还款的收款'),
('4', '其他收款')
)
# 收款单的模型类
class ReceiptModel(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)
receipt_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')
receipt_category = models.CharField('收款类型', max_length=2, null=True, choices=receipt_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='operator2_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='operator4_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)
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)
sale = models.ForeignKey('sale_info.SaleModel', 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_receipt'
verbose_name = '收款单表'
verbose_name_plural = verbose_name
ordering = ['id']
# 收款单中 收款项目的模型类
class ReceiptItemModel(BaseModel):
# 冗余字段
storage_code = models.CharField('销售出库单编号,不让用户填写', max_length=28)
deliver_storage = models.ForeignKey('warehouse_info.SaleDeliverModel', related_name='pay_item_list', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='采购入库单')
receipt = models.ForeignKey('ReceiptModel', 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_receipt_item'
verbose_name = '收款单中的 收款项目表'
verbose_name_plural = verbose_name
ordering = ['id']
# 收款单的模型类
class ReceiptModel(BaseModel):
pay_date = models.DateTimeField('收款日期')

@ -52,7 +52,7 @@ class ReceiptSerializer(serializers.ModelSerializer):
for item in item_list:
# 插入收款项目
ReceiptItemModel.objects.create(receipt=receipt, **item)
return payment
return receipt
# 必须重写update
def update(self, instance, validated_data):

@ -16,7 +16,7 @@ Including another URLconf
from django.contrib import admin
from django.urls import path, re_path
from rest_framework.routers import DefaultRouter
from .views import payment_views
from .views import payment_views, receipt_views
from rest_framework_jwt.views import obtain_jwt_token
@ -28,5 +28,6 @@ urlpatterns = [
router = DefaultRouter()
router.register('payment', payment_views.PaymentViewSet)
router.register('receipt', receipt_views.ReceiptViewSet)
urlpatterns += router.urls

@ -8,10 +8,10 @@ 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 basic_info.models import SettlementAccountModel, CustomerModel
from erp_system.models import UserModel
from financial_info.models import ReceiptModel, ReceiptItemModel
from financial_info.serializer.payment_serializer import PaymentSerializer
from financial_info.serializer.receipt_serializer import ReceiptSerializer
from warehouse_info.models import SaleDeliverModel
@ -59,28 +59,28 @@ class ReceiptViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditM
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)
customer = self.request.data.get('customer', 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)
sale_number_code = self.request.data.get('sale_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 sale_number_code:
query.add(Q(sale__number_code__contains=sale_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 customer:
query.add(Q(customer__id=customer), 'AND')
if number_code:
query.add(Q(number_code__contains=number_code), 'AND')
if operator_user:
@ -88,31 +88,32 @@ class ReceiptViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditM
if status:
query.add(Q(status=status), 'AND')
return PaymentModel.objects.filter(query).distinct().all()
return ReceiptModel.objects.filter(query).distinct().all()
else:
return PaymentModel.objects.all()
return ReceiptModel.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"),
'customer': 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="采购订单编号关键字"),
'sale_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)
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)
return super(ReceiptViewSet, self).list(request=request, *args, **kwargs)
"""
自定义的 批量审核的 视图函数
@ -133,64 +134,64 @@ class ReceiptViewSet(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditM
# 为了减少代码量,参数的验证就不写了
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)
for receipt in queryset: # 期中receipt是收款单
# 判断1关联的销售 单状态是否为“未审核”
if receipt.sale and receipt.sale.status == '0':
return Response(data={'detail': '销售订单未审核,不能收款'}, status=status.HTTP_400_BAD_REQUEST)
# 判断2 收款单的状态是否为:“已审核”
if pm.status == '1':
if receipt.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')\
# 业务一: 销售定金收款
if receipt.receipt_category == '1' and receipt.sale and not receipt.item_list.exists():
receipt.sale.status = '5' # 已收 销售定金
receipt.sale.save()
# 业务二: 客户还款 的收款
if receipt.receipt_category == '3' and not receipt.item_list.exists():
CustomerModel.objects.filter(id=receipt.customer.id).update(
current_receivable=F('current_receivable') - receipt.this_money)
# 业务三: 出库货款 的收入
if receipt.receipt_category == '2' and receipt.sale:
if receipt.item_list.exists(): # 这种判断不回从数据库中返回数据
for item in receipt.item_list.all(): # 期中item是收款项目
# 判断4 出库单必须是已经审核状态
if item.deliver_storage and item.deliver_storage.status != '1':
return Response(data={'detail': '出库单未审核或者已经收款,不能收款'},
status=status.HTTP_400_BAD_REQUEST)
# 业务三——第1种情况 对应的出库单,是否应该:收款完成 ,首先需要查询该出库单的已经收款金额之和
sum_dict = ReceiptItemModel.objects \
.filter(deliver_storage_id=item.deliver_storage.id, receipt__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)\
in_sum = sum_dict['sum'] if sum_dict['sum'] else 0
if item.should_money == (in_sum + item.this_money):
item.deliver_storage.status = '2' # 把出库单的状态修改为:收款完成
item.deliver_storage.save()
# 业务三——第2种情况 对应的销售单状态是否要改为:销售完成
# 销售完成的条件: 1、该销售单必须是全部出库状态2、该销售单中 所有的出库单状态也都必须是:收款完成
sale = item.receipt.sale
if sale.status == '3':
# 查询 该销售单中 所有出库单状态不是:'收款完成' 的有多少个?
number = SaleDeliverModel.objects \
.filter(sale_id=sale.id) \
.exclude(status='2').count()
if number == 0: # 则 所有的库单状态都为:收款完成
purchase.status = '4' # 修改采购单状态为: 采购完成
purchase.save()
if number == 0: # 则 所有的库单状态都为:收款完成
sale.status = '4' # 修改销售单状态为: 销售完成
sale.save()
else:
return Response(data={'detail': '没有选择收款项目,支收货款的时候必须选择'}, status=status.HTTP_400_BAD_REQUEST)
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)
SettlementAccountModel.objects.filter(id=receipt.account.id) \
.update(balance=F('balance') + receipt.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)

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ProductionInfoConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'production_info'

@ -0,0 +1,67 @@
# Generated by Django 3.2.16 on 2023-04-13 21:27
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('goods_info', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='BomProcessModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('process_order', models.IntegerField(verbose_name='执行顺序')),
('name', models.CharField(max_length=50, verbose_name='工序名称')),
('leader_name', models.CharField(max_length=20, verbose_name='负责人的名字')),
('money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='工价,最多精确到小数点后两位')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('leader_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='leader1_in_list', to=settings.AUTH_USER_MODEL, verbose_name='负责人员')),
('parent_goods', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='process_list', to='goods_info.goodsmodel', verbose_name='当前的生产工序属于哪个货品')),
],
options={
'verbose_name': '生产工序表',
'verbose_name_plural': '生产工序表',
'db_table': 't_bom_process',
'ordering': ['process_order'],
},
),
migrations.CreateModel(
name='BomMaterialModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('goods_code', models.CharField(max_length=28, verbose_name='货品编号,不让用户填写')),
('name', models.CharField(max_length=20, verbose_name='货品名称')),
('specification', models.CharField(blank=True, max_length=50, null=True, verbose_name='货品规格')),
('model_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='型号')),
('units_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='单位名字')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('purchase_price', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, verbose_name='采购价')),
('count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='数量,最多精确到小数点后两位')),
('money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='费用,最多精确到小数点后两位')),
('goods', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.goodsmodel', verbose_name='货品')),
('parent_goods', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='material_list', to='goods_info.goodsmodel', verbose_name='当前的物料清单属于哪个货品')),
('units', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.unitsmodel')),
],
options={
'verbose_name': '生产物料表',
'verbose_name_plural': '生产物料表',
'db_table': 't_bom_material',
'ordering': ['id'],
},
),
]

@ -0,0 +1,105 @@
# Generated by Django 3.2.16 on 2023-04-22 20:49
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('goods_info', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('sale_info', '0001_initial'),
('production_info', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='ProductTaskModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('invoices_date', models.DateTimeField(blank=True, default=django.utils.timezone.now, null=True, verbose_name='单据日期')),
('number_code', models.CharField(max_length=28, unique=True, verbose_name='编号或者条码')),
('name', models.CharField(max_length=20, verbose_name='货品名称')),
('specification', models.CharField(blank=True, max_length=50, null=True, verbose_name='货品规格')),
('model_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='型号')),
('goods_number_code', models.CharField(max_length=28, verbose_name='生产的货品编号或者批号')),
('units_name', models.CharField(blank=True, max_length=28, null=True, verbose_name='货品的单位')),
('sale_number', models.DecimalField(decimal_places=2, default=1, max_digits=10, verbose_name='订单数量')),
('p_number', models.DecimalField(decimal_places=2, default=1, max_digits=10, verbose_name='生产数量')),
('finish_date', models.DateField(blank=True, null=True, verbose_name='实际完工日期')),
('plan_finish_date', models.DateField(verbose_name='计划完工日期')),
('sale_number_code', models.CharField(blank=True, max_length=28, null=True, verbose_name='销售单的编号或者批号')),
('status', models.CharField(default='0', max_length=1, verbose_name='状态,0:未审核,1:加工中,2:完工')),
('check_number', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='验收合格数量')),
('storage_number', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='已入库数量')),
('cost_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='合计成本')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('goods', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.goodsmodel', verbose_name='货品')),
('sale', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sale_info.salemodel', verbose_name='销售单')),
],
options={
'verbose_name': '生产任务表',
'verbose_name_plural': '生产任务表',
'db_table': 't_product_task',
},
),
migrations.CreateModel(
name='ProductProcessModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('process_order', models.IntegerField(verbose_name='执行顺序')),
('name', models.CharField(max_length=128, verbose_name='工序名称')),
('leader_name', models.CharField(max_length=20, verbose_name='负责人的名字')),
('price', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='工价,最多精确到小数点后两位')),
('money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='费用,最多精确到小数点后两位')),
('plan_finish_date', models.DateField(blank=True, null=True, verbose_name='计划完工日期')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('leader_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='leader2_in_list', to=settings.AUTH_USER_MODEL, verbose_name='负责人员')),
('product_task', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='process_list', to='production_info.producttaskmodel', verbose_name='生产任务')),
],
options={
'verbose_name': '生产工序表',
'verbose_name_plural': '生产工序表',
'db_table': 't_product_process',
},
),
migrations.CreateModel(
name='ProductMaterialModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('goods_code', models.CharField(max_length=28, verbose_name='货品编号,不让用户填写')),
('name', models.CharField(max_length=20, verbose_name='货品名称')),
('specification', models.CharField(blank=True, max_length=50, null=True, verbose_name='货品规格')),
('model_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='型号')),
('units_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='单位名字')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('purchase_price', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, verbose_name='采购价')),
('count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='总共需要的数量')),
('money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='费用,最多精确到小数点后两位')),
('get_count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='已经领取的数量')),
('back_count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='退回的数量')),
('use_count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='已使用的数量')),
('scrap_count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='报废的数量')),
('goods', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.goodsmodel', verbose_name='货品')),
('product_task', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='material_list', to='production_info.producttaskmodel', verbose_name='生产任务')),
('units', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.unitsmodel')),
],
options={
'verbose_name': '生产物料表',
'verbose_name_plural': '生产物料表',
'db_table': 't_product_material',
},
),
]

@ -0,0 +1,26 @@
# Generated by Django 3.2.16 on 2023-04-22 21:38
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('production_info', '0002_productmaterialmodel_productprocessmodel_producttaskmodel'),
]
operations = [
migrations.AddField(
model_name='producttaskmodel',
name='check_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='checker6_list', to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改'),
),
migrations.AddField(
model_name='producttaskmodel',
name='check_user_name',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='操作人员的真实姓名'),
),
]

@ -0,0 +1,144 @@
from django.db import models
from django.utils import timezone
from ERP_5.utils.base_model import BaseModel
# BOM表中的物料模型类
class BomMaterialModel(BaseModel):
# 冗余字段
goods_code = models.CharField('货品编号,不让用户填写', max_length=28)
name = models.CharField(max_length=20, verbose_name='货品名称')
specification = models.CharField('货品规格', max_length=50, null=True, blank=True)
model_number = 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)
purchase_price = models.DecimalField('采购价', max_digits=10, decimal_places=2, blank=True, default=0)
count = models.DecimalField('数量,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
money = models.DecimalField('费用,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
goods = models.ForeignKey('goods_info.GoodsModel', null=True, on_delete=models.SET_NULL,
verbose_name='货品')
parent_goods = models.ForeignKey('goods_info.GoodsModel', blank=True, related_name='material_list', null=True,
on_delete=models.SET_NULL, verbose_name='当前的物料清单属于哪个货品')
class Meta:
db_table = 't_bom_material'
verbose_name = '生产物料表'
verbose_name_plural = verbose_name
ordering = ['id']
# BOM表中 的生产工序模型类
class BomProcessModel(BaseModel):
process_order = models.IntegerField('执行顺序')
name = models.CharField('工序名称', max_length=50)
leader_name = models.CharField('负责人的名字', max_length=20)
leader_user = models.ForeignKey('erp_system.UserModel', related_name='leader1_in_list', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='负责人员')
money = models.DecimalField('工价,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
remark = models.CharField('备注', max_length=512, blank=True, null=True)
parent_goods = models.ForeignKey('goods_info.GoodsModel', blank=True, related_name='process_list', null=True,
on_delete=models.SET_NULL, verbose_name='当前的生产工序属于哪个货品')
class Meta:
db_table = 't_bom_process'
verbose_name = '生产工序表'
verbose_name_plural = verbose_name
ordering = ['process_order']
# 生产任务模型类
class ProductTaskModel(BaseModel):
invoices_date = models.DateTimeField('单据日期', blank=True, null=True, default=timezone.now)
number_code = models.CharField('编号或者条码', max_length=28, unique=True)
# 冗余字段
name = models.CharField(max_length=20, verbose_name='货品名称')
specification = models.CharField('货品规格', max_length=50, null=True, blank=True)
model_number = models.CharField('型号', max_length=50, null=True, blank=True)
goods_number_code = models.CharField('生产的货品编号或者批号', max_length=28)
units_name = models.CharField('货品的单位', max_length=28, null=True, blank=True)
sale_number = models.DecimalField('订单数量', default=1, max_digits=10, decimal_places=2)
p_number = models.DecimalField('生产数量', default=1, max_digits=10, decimal_places=2)
finish_date = models.DateField('实际完工日期', null=True, blank=True)
plan_finish_date = models.DateField('计划完工日期')
goods = models.ForeignKey('goods_info.GoodsModel', null=True, blank=True, on_delete=models.SET_NULL,
verbose_name='货品')
sale_number_code = models.CharField('销售单的编号或者批号', max_length=28, null=True, blank=True)
sale = models.ForeignKey('sale_info.SaleModel', null=True, blank=True, on_delete=models.SET_NULL,
verbose_name='销售单')
status = models.CharField('状态,0:未审核,1:加工中,2:完工', max_length=1,
default='0')
check_number = models.DecimalField('验收合格数量', default=0, max_digits=10, decimal_places=2)
storage_number = models.DecimalField('已入库数量', default=0, max_digits=10, decimal_places=2)
cost_money = models.DecimalField('合计成本', max_digits=10, decimal_places=2, default=0)
remark = models.CharField('备注', max_length=512, blank=True, null=True)
check_user = models.ForeignKey('erp_system.UserModel', related_name='checker6_list', null=True, blank=True,
on_delete=models.SET_NULL,
verbose_name='审核人员,不能修改')
# 增加一个冗余字段
check_user_name = models.CharField('操作人员的真实姓名', max_length=20, null=True, blank=True)
class Meta:
db_table = 't_product_task'
verbose_name = '生产任务表'
verbose_name_plural = verbose_name
# 生产物料模型
class ProductMaterialModel(BaseModel):
# 冗余字段
goods_code = models.CharField('货品编号,不让用户填写', max_length=28)
name = models.CharField(max_length=20, verbose_name='货品名称')
specification = models.CharField('货品规格', max_length=50, null=True, blank=True)
model_number = 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)
purchase_price = models.DecimalField('采购价', max_digits=10, decimal_places=2, blank=True, default=0)
count = models.DecimalField('总共需要的数量', max_digits=10, decimal_places=2, default=0)
money = models.DecimalField('费用,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
goods = models.ForeignKey('goods_info.GoodsModel', null=True, on_delete=models.SET_NULL,
verbose_name='货品')
get_count = models.DecimalField('已经领取的数量', max_digits=10, decimal_places=2, default=0)
back_count = models.DecimalField('退回的数量', max_digits=10, decimal_places=2, default=0)
use_count = models.DecimalField('已使用的数量', max_digits=10, decimal_places=2, default=0)
scrap_count = models.DecimalField('报废的数量', max_digits=10, decimal_places=2, default=0)
product_task = models.ForeignKey('ProductTaskModel', null=True, on_delete=models.SET_NULL,
verbose_name='生产任务', related_name='material_list')
class Meta:
db_table = 't_product_material'
verbose_name = '生产物料表'
verbose_name_plural = verbose_name
# 生产任务中 的生产工序模型类
class ProductProcessModel(BaseModel):
process_order = models.IntegerField('执行顺序')
name = models.CharField('工序名称', max_length=128)
leader_name = models.CharField('负责人的名字', max_length=20)
leader_user = models.ForeignKey('erp_system.UserModel', related_name='leader2_in_list', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='负责人员')
price = models.DecimalField('工价,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
money = models.DecimalField('费用,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
plan_finish_date = models.DateField('计划完工日期', null=True, blank=True)
remark = models.CharField('备注', max_length=512, blank=True, null=True)
product_task = models.ForeignKey('ProductTaskModel', null=True, on_delete=models.SET_NULL,
verbose_name='生产任务', related_name='process_list')
class Meta:
db_table = 't_product_process'
verbose_name = '生产工序表'
verbose_name_plural = verbose_name

@ -0,0 +1,44 @@
from rest_framework import serializers
from ERP_5.utils.get_inventory import get_inventory_by_goods
from goods_info.models import GoodsModel
from production_info.models import BomProcessModel, BomMaterialModel
class ProcessSerializer(serializers.ModelSerializer):
"""
生产工序的 序列化器
"""
class Meta:
model = BomProcessModel
fields = '__all__'
class MaterialSerializer(serializers.ModelSerializer):
"""
生产物料的 序列化器
"""
cur_inventory = serializers.SerializerMethodField(read_only=True, help_text='在仓库中库存')
class Meta:
model = BomMaterialModel
fields = '__all__'
def get_cur_inventory(self, obj: BomMaterialModel): # 当前的obj为BomMaterialModel
result = get_inventory_by_goods(obj.goods.id)
return result if result else 0
class GoodsBomSerializer(serializers.ModelSerializer):
"""
某一个货品的BOM表数据 序列化器
"""
# 当前商品BOM表中所有的 生产工序列表
process_list = ProcessSerializer(many=True, read_only=True)
# 当前商品BOM表中所有的 生产物料列表
material_list = MaterialSerializer(many=True, read_only=True)
class Meta:
model = GoodsModel
fields = ['number_code', 'name', 'material_list', 'process_list']

@ -0,0 +1,153 @@
from django.db import transaction
from django.db.models import F
from django.utils import timezone
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from ERP_5.utils.cont import NumberPrefix
from ERP_5.utils.generate_code import generate_code
from ERP_5.utils.get_inventory import get_inventory_by_goods
from basic_info.models import WarehouseModel
from goods_info.models import GoodsModel, GoodsInventoryModel
from production_info.models import ProductProcessModel, ProductMaterialModel, ProductTaskModel
from warehouse_info.models import SaleDeliverModel, SaleDeliverItemModel
class ProductProcessSerializer(serializers.ModelSerializer):
"""
生产计划中的生产工序 序列化器
"""
class Meta:
model = ProductProcessModel
fields = '__all__'
class ProductMaterialSerializer(serializers.ModelSerializer):
"""
生产计划中的生产物料 序列化器
"""
cur_inventory = serializers.SerializerMethodField(read_only=True, help_text='在仓库中库存')
class Meta:
model = ProductMaterialModel
fields = '__all__'
def get_cur_inventory(self, obj: ProductMaterialModel): # 当前的obj为ProductMaterialModel
result = get_inventory_by_goods(obj.goods.id)
return result if result else 0
class ProductTaskSerializer(serializers.ModelSerializer):
"""
生产任务的 序列化器
"""
# 当前生产任务中所有的: 生产工序列表
process_list = ProductProcessSerializer(many=True)
# 当前生产任务中所有的: 生产物料列表
material_list = ProductMaterialSerializer(many=True)
class Meta:
model = ProductTaskModel
fields = '__all__'
def create(self, validated_data):
process_list = validated_data.pop('process_list')
material_list = validated_data.pop('material_list')
with transaction.atomic():
pt = ProductTaskModel.objects.create(**validated_data)
for item in process_list:
ProductProcessModel.objects.create(product_task=pt, **item)
for item in material_list:
ProductMaterialModel.objects.create(product_task=pt, **item)
return pt
def update(self, instance, validated_data):
if instance.status != '0':
raise ValidationError("生产任务已经生效,不能修改!")
process_list = validated_data.pop('process_list')
material_list = validated_data.pop('material_list')
old_list1 = instance.process_list
old_list2 = instance.material_list
with transaction.atomic():
if old_list1.exists():
# 然后把旧数据删除因为在validated_data拿不到货品库存数据的ID
instance.process_list.all().delete()
if old_list2.exists():
# 然后把旧数据删除因为在validated_data拿不到货品库存数据的ID
instance.material_list.all().delete()
for item in process_list:
ProductProcessModel.objects.create(product_task=instance, **item)
for item in material_list:
ProductMaterialModel.objects.create(product_task=instance, **item)
result = super(ProductTaskSerializer, self).update(instance=instance, validated_data=validated_data)
return result
class GetMaterialSerializer(serializers.Serializer):
"""
领料的序列化器
"""
def update(self, instance, validated_data):
pass
def create(self, validated_data):
# 需要完成4件事情
with transaction.atomic():
# 1、插入出库单
deliver = SaleDeliverModel.objects.create(invoices_date=timezone.now(),
number_code=generate_code(NumberPrefix['deliver'].value),
last_amount=validated_data['money'],
number_count=validated_data['count'],
product_task_id=validated_data['pt_id'],
status='1',
is_other='1')
# 2、插入出库项目
goods = GoodsModel.objects.get(pk=validated_data['good_id'])
wh = WarehouseModel.objects.get(pk=validated_data['warehouse_id'])
psi = SaleDeliverItemModel()
psi.goods_id = goods.id
psi.specification = goods.specification
psi.model_number = goods.model_number
psi.number_code = goods.number_code
psi.color = goods.color
psi.category = goods.category
psi.category_name = goods.category.name
psi.units = goods.units
psi.units_name = goods.units.basic_name
psi.name = goods.name
psi.sale_count = validated_data['count']
psi.sale_price = validated_data['price']
psi.sale_money = validated_data['money']
psi.warehouse_name = wh.name
psi.warehouse_id = wh.id
psi.sale_deliver_id = deliver.id
psi.save()
# 3、 修改库存数量
GoodsInventoryModel.objects \
.filter(goods_id=goods.id, warehouse_id=wh.id) \
.update(cur_inventory=F('cur_inventory') - psi.sale_count)
# 4、 修改生产物料中领料数量
ProductMaterialModel.objects.filter(id=validated_data['material_id']) \
.update(get_count=F('get_count') + psi.sale_count)
return deliver
goods_number_code = serializers.CharField(help_text='物料的条码或者编号', required=False)
warehouse_name = serializers.CharField(help_text='领取仓库的名字')
warehouse_id = serializers.IntegerField(help_text='领取仓库的主键')
good_id = serializers.IntegerField(help_text='领取的货品主键')
count = serializers.DecimalField(help_text='领取数量,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
price = serializers.DecimalField(help_text='领取的成本单价,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
money = serializers.DecimalField(help_text='领取的成本总价,最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
material_id = serializers.IntegerField(help_text='所属生产物料的主键')
pt_id = serializers.IntegerField(help_text='所属生产任务的主键')

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,35 @@
"""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 bom_views, product_task_views
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
# path('admin/', admin.site.urls),
]
router = DefaultRouter()
router.register('bom_material', bom_views.MaterialViewSets)
router.register('bom_process', bom_views.ProcessViewSets)
router.register('bom', bom_views.GoodsBomViewSet)
router.register('products', product_task_views.ProductTaskViewSets)
urlpatterns += router.urls

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

@ -0,0 +1,84 @@
from rest_framework import mixins, viewsets
from ERP_5.utils.base_views import MultipleDestroyMixin
from goods_info.models import GoodsModel
from production_info.models import BomMaterialModel, BomProcessModel
from production_info.serializer.bom_serializer import MaterialSerializer, ProcessSerializer, GoodsBomSerializer
class MaterialViewSets(mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
mixins.RetrieveModelMixin, viewsets.GenericViewSet, MultipleDestroyMixin):
"""
create:
生产物料--新增,
生产物料新增, status: 201(成功), return: 新增生产物料信息
destroy:
生产物料--删除
生产物料删除, status: 204(成功), return: None
multiple_delete:
生产物料--批量删除,必传参数ids=[1,2,3,4...]
生产物料批量删除, status: 204(成功), return: None
update:
生产物料--修改,
生产物料修改, status: 200(成功), return: 修改后的生产物料信息
retrieve:
查询某一个生产物料
查询指定ID的生产物料, status: 200(成功), return: 生产物料
"""
queryset = BomMaterialModel.objects.all()
serializer_class = MaterialSerializer
class ProcessViewSets(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
mixins.DestroyModelMixin, viewsets.GenericViewSet, MultipleDestroyMixin):
"""
create:
生产工序--新增,
生产工序新增, status: 201(成功), return: 新增生产工序信息
destroy:
生产工序--删除
生产工序删除, status: 204(成功), return: None
multiple_delete:
生产工序--批量删除,必传参数ids=[1,2,3,4...]
生产工序批量删除, status: 204(成功), return: None
update:
生产工序--修改,
生产工序修改, status: 200(成功), return: 修改后的生产物料信息
retrieve:
查询某一个生产工序
查询指定ID的生产工序, status: 200(成功), return: 生产工序
"""
queryset = BomProcessModel.objects.all()
serializer_class = ProcessSerializer
class GoodsBomViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
"""
retrieve:
查询某一个货品的BOM表数据包括BOM表中物料清单和工序清单
包括BOM中的物料清单和生产工序列表, status: 200(成功), return: BOM表
"""
serializer_class = GoodsBomSerializer
queryset = GoodsModel.objects.all()

@ -0,0 +1,110 @@
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 rest_framework.response import Response
from ERP_5.utils.base_views import MultipleDestroyMixin, MultipleAuditMixin
from ERP_5.utils.paginations import GlobalPagination
from production_info.models import ProductTaskModel
from production_info.serializer.product_task_serializer import ProductTaskSerializer, GetMaterialSerializer
class ProductTaskViewSets(viewsets.ModelViewSet, MultipleDestroyMixin, MultipleAuditMixin):
"""
create:
生产任务--新增,注意如果有BOM表则直接读取BOM如果没有需要自己添加生产物料和工序
生产任务新增, 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: 修改后的生产任务信息
partial_update:
生产任务--局部修改,可以传参任意属性的值服务器会修改指定的属性值
生产任务局部修改, status: 200(成功), return: 修改后的生产任务信息
list:
生产任务--该接口可以弃用
生产任务列表信息, status: 200(成功), return: 生产任务信息列表
retrieve:
查询某一个生产任务
查询指定ID的生产任务, status: 200(成功), return: 用户生产任务
"""
queryset = ProductTaskModel.objects.all()
serializer_class = ProductTaskSerializer
pagination_class = GlobalPagination
def get_queryset(self):
if self.action == 'find': # 过滤查询
# 获取请求参数(在json中)
number_code = self.request.data.get('number_code', None)
keyword = self.request.data.get('keyword', None)
start_date = self.request.data.get('start_date', None)
end_date = self.request.data.get('start_date', None)
query = Q()
if keyword:
child_query = Q()
child_query.add(Q(name__contains=keyword), 'OR')
child_query.add(Q(specification=keyword), 'OR')
query.add(child_query, 'AND')
if start_date:
query.add(Q(invoices_date__gt=start_date), 'AND')
if end_date:
query.add(Q(invoices_date__lt=end_date), 'AND')
if number_code:
query.add(Q(number_code__contains=number_code), 'AND')
return ProductTaskModel.objects.filter(query).distinct().all()
else:
return ProductTaskModel.objects.all()
params = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
'keyword': openapi.Schema(type=openapi.TYPE_STRING, description="名称的关键字或者型号"),
'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")
})
# 分页参数必须是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(ProductTaskViewSets, self).list(request=request, *args, **kwargs)
@swagger_auto_schema(method='POST', request_body=GetMaterialSerializer,
operation_description="生产任务中领取物料")
@action(methods=['POST'], detail=False)
def get_material(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
result = serializer.save()
return Response({'msg': 'ok'})
def get_serializer_class(self):
if self.action == 'get_material':
return GetMaterialSerializer
else:
return ProductTaskSerializer

@ -1,4 +1,4 @@
# Generated by Django 3.2.16 on 2023-04-01 21:07
# Generated by Django 3.2.16 on 2023-04-04 22:26
from django.conf import settings
from django.db import migrations, models
@ -10,9 +10,9 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('goods_info', '0001_initial'),
('basic_info', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('goods_info', '0001_initial'),
('basic_info', '0002_initial'),
]
operations = [
@ -37,7 +37,7 @@ class Migration(migrations.Migration):
('supplier_name', models.CharField(blank=True, max_length=30, null=True, verbose_name='供应商名称')),
('attachment_list', models.CharField(blank=True, max_length=20, null=True, verbose_name='附件的id列表字段的值为: 1,2,3,4')),
('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.settlementaccountmodel', verbose_name='结算账户,审核之后不能改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='checker2_purchase_list', to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('operator_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator_purchase_list', to=settings.AUTH_USER_MODEL, verbose_name='采购操作人员,不能修改')),
('supplier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.suppliermodel', verbose_name='供应商,审核之后不能改')),
],

@ -0,0 +1,79 @@
# Generated by Django 3.2.16 on 2023-04-11 20:03
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('goods_info', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('basic_info', '0002_initial'),
]
operations = [
migrations.CreateModel(
name='SaleModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('invoices_date', models.DateTimeField(verbose_name='单据日期')),
('number_code', models.CharField(max_length=28, verbose_name='单据编号,不让用户填写')),
('discount', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=5, verbose_name='优惠率,最多精确到小数点后两位')),
('discount_money', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, verbose_name='优惠金额(付款优惠),最多精确到小数点后两位')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('last_amount', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=13, verbose_name='优惠后总金额,最多精确到小数点后两位')),
('deposit', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, verbose_name='收取定金,最多精确到小数点后两位')),
('number_count', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, verbose_name='销售数量,最多精确到小数点后两位')),
('status', models.CharField(default='0', max_length=1, verbose_name='状态,0:未审核,1:已审核,2:部分发货,3:全部发货,4:完成销售,5:已收定金')),
('operator_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='销售人员的真实姓名')),
('check_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='审核人员的真实姓名')),
('customer_name', models.CharField(blank=True, max_length=30, null=True, verbose_name='客户名称')),
('attachment_list', models.CharField(blank=True, max_length=20, null=True, verbose_name='附件的id列表字段的值为: 1,2,3,4')),
('account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.settlementaccountmodel', verbose_name='结算账户,审核之后不能改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.customermodel', verbose_name='客户,审核之后不能改')),
('operator_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator_sale_list', to=settings.AUTH_USER_MODEL, verbose_name='销售操作人员,不能修改')),
],
options={
'verbose_name': '销售表',
'verbose_name_plural': '销售表',
'db_table': 't_sales',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='SaleItemModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('name', models.CharField(max_length=20, verbose_name='货品名称')),
('number_code', models.CharField(blank=True, max_length=28, null=True, verbose_name='货品的编号或者批号')),
('specification', models.CharField(blank=True, max_length=50, null=True, verbose_name='货品规格')),
('model_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='型号')),
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='颜色')),
('units_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='单位名字')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('sales_count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='销售数量,最多精确到小数点后两位')),
('sales_price', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='销售单价,最多精确到小数点后两位')),
('sales_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='销售金额,最多精确到小数点后两位')),
('goods', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.goodsmodel', verbose_name='货品,必须要传')),
('sale', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_list', to='sale_info.salemodel', verbose_name='销售单')),
('units', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.unitsmodel')),
],
options={
'verbose_name': '销售订单的项目表',
'verbose_name_plural': '销售订单的项目表',
'db_table': 't_sales_items',
'ordering': ['id'],
},
),
]

@ -1,4 +1,4 @@
# Generated by Django 3.2.16 on 2023-04-04 20:18
# Generated by Django 3.2.16 on 2023-04-04 22:26
from django.conf import settings
from django.db import migrations, models
@ -10,9 +10,9 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('basic_info', '0002_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('goods_info', '0001_initial'),
('basic_info', '0002_initial'),
('purchase_info', '0001_initial'),
]
@ -41,8 +41,8 @@ class Migration(migrations.Migration):
('attachment_list', models.CharField(blank=True, max_length=20, null=True, verbose_name='附件的id列表字段的值为: 1,2,3,4')),
('is_other', models.CharField(default='0', max_length=1, verbose_name='是否是其他入库,0:采购入库,1:其他入库')),
('account', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.settlementaccountmodel', verbose_name='结算账户,审核之后不能改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('operator_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator_in_list', to=settings.AUTH_USER_MODEL, verbose_name='入库操作人员,不能修改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='checker3_in_list', to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('operator_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator4_in_list', to=settings.AUTH_USER_MODEL, verbose_name='入库操作人员,不能修改')),
('purchase', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='purchase_info.purchasemodel', verbose_name='采购订单,审核之后不能改')),
('supplier', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.suppliermodel', verbose_name='供应商,审核之后不能改')),
],

@ -0,0 +1,88 @@
# Generated by Django 3.2.16 on 2023-04-11 21:06
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('goods_info', '0001_initial'),
('basic_info', '0002_initial'),
('sale_info', '0001_initial'),
('warehouse_info', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SaleDeliverModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('invoices_date', models.DateTimeField(verbose_name='单据日期')),
('number_code', models.CharField(max_length=28, verbose_name='单据编号,不让用户填写')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('discount', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=5, null=True, verbose_name='优惠率,最多精确到小数点后两位')),
('discount_money', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='优惠金额(付款优惠),最多精确到小数点后两位')),
('last_amount', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=13, null=True, verbose_name='优惠后总金额,最多精确到小数点后两位')),
('other_money', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='其他费用,最多精确到小数点后两位')),
('deduction_deposit', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='订金抵扣,最多精确到小数点后两位')),
('this_proceeds', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='本次收款,最多精确到小数点后两位')),
('this_debt', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True, verbose_name='本次欠款,最多精确到小数点后两位')),
('number_count', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, verbose_name='出库总数量,最多精确到小数点后两位')),
('status', models.CharField(default='0', max_length=1, verbose_name='状态,0:未审核,1:已审核,2:已收款完成')),
('operator_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='操作人员的真实姓名')),
('check_user_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='操作人员的真实姓名')),
('customer_name', models.CharField(blank=True, max_length=30, null=True, verbose_name='客户商的名称')),
('attachment_list', models.CharField(blank=True, max_length=20, null=True, verbose_name='附件的id列表字段的值为: 1,2,3,4')),
('is_other', models.CharField(default='0', max_length=1, verbose_name='是否是其他出库,0:销售出库,1:其他出库')),
('account', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.settlementaccountmodel', verbose_name='结算账户,审核之后不能改')),
('check_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='check7_in_list', to=settings.AUTH_USER_MODEL, verbose_name='审核人员,不能修改')),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.customermodel', verbose_name='客户,审核之后不能改')),
('operator_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operator6_in_list', to=settings.AUTH_USER_MODEL, verbose_name='入库操作人员,不能修改')),
('sale', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sale_info.salemodel', verbose_name='销售订单,审核之后不能改')),
],
options={
'verbose_name': '出库单表',
'verbose_name_plural': '出库单表',
'db_table': 't_sale_deliver',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='SaleDeliverItemModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('delete_flag', models.CharField(default='0', help_text='是否启用', max_length=1, verbose_name='是否启用')),
('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='更新时间', verbose_name='更新时间')),
('name', models.CharField(max_length=20, verbose_name='货品名称')),
('number_code', models.CharField(blank=True, max_length=28, null=True, verbose_name='货品的编号或者批号')),
('specification', models.CharField(blank=True, max_length=50, null=True, verbose_name='货品规格')),
('model_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='型号')),
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='颜色')),
('units_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='单位名字')),
('category_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='货品类别名称')),
('remark', models.CharField(blank=True, max_length=512, null=True, verbose_name='备注')),
('sale_count', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='出库数量,最多精确到小数点后两位')),
('sale_price', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='单价,最多精确到小数点后两位')),
('sale_money', models.DecimalField(decimal_places=2, default=0, max_digits=10, verbose_name='金额,最多精确到小数点后两位')),
('warehouse_name', models.CharField(max_length=50, null=True, verbose_name='仓库名字')),
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.goodscategorymodel')),
('goods', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.goodsmodel', verbose_name='货品')),
('sale_deliver', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='item_list', to='warehouse_info.saledelivermodel', verbose_name='销售出库单')),
('units', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='goods_info.unitsmodel')),
('warehouse', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='basic_info.warehousemodel', verbose_name='出库的仓库')),
],
options={
'verbose_name': '出库单的项目表',
'verbose_name_plural': '出库单的项目表',
'db_table': 't_sale_deliver_items',
'ordering': ['id'],
},
),
]

@ -0,0 +1,20 @@
# Generated by Django 3.2.16 on 2023-04-22 22:11
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('production_info', '0003_auto_20230422_2138'),
('warehouse_info', '0002_saledeliveritemmodel_saledelivermodel'),
]
operations = [
migrations.AddField(
model_name='saledelivermodel',
name='product_task',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='production_info.producttaskmodel', verbose_name='所属的生产任务'),
),
]

@ -144,6 +144,10 @@ class SaleDeliverModel(BaseModel):
is_other = models.CharField('是否是其他出库,0:销售出库,1:其他出库', max_length=1, default='0')
product_task = models.ForeignKey('production_info.ProductTaskModel', null=True, blank=True,
on_delete=models.SET_NULL,
verbose_name='所属的生产任务')
class Meta:
db_table = 't_sale_deliver'
verbose_name = '出库单表'

@ -1,8 +1,10 @@
from django.db import transaction
from django.db.models import Sum
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from ERP_5.utils.get_inventory import get_inventory_by_goods
from financial_info.models import ReceiptItemModel
from warehouse_info.models import SaleDeliverItemModel, SaleDeliverModel
@ -30,10 +32,28 @@ class DeliverySerializer(serializers.ModelSerializer):
# 出库单列表中需要展示:商品信息。
goods_info = serializers.SerializerMethodField(read_only=True, label='列表中展示的商品信息')
# 查询当前销售 出库单中已经 收金额
already_receipt = serializers.SerializerMethodField(read_only=True, help_text='已经收款的金额')
class Meta:
model = SaleDeliverModel
fields = '__all__'
def get_already_receipt(self, obj: SaleDeliverModel):
"""
查询当前 销售出库单中已经 收的货款金额
:param obj: SaleDeliverModel
:return: 0获取其他的数值
"""
sum_dict = ReceiptItemModel.objects.filter(deliver_storage_id=obj.id)\
.exclude(receipt__status='0')\
.aggregate(sum=Sum('this_money'))
if sum_dict:
return sum_dict['sum'] if sum_dict['sum'] else 0
return 0
def get_goods_info(self, obj):
"""
商品信息是由 商品1名称 商品1规格 , 商品2名称 商品2规格 ....

@ -48,6 +48,7 @@ INSTALLED_APPS = [
'warehouse_info',
'financial_info',
'sale_info',
'production_info',
# 'django.contrib.staticfiles', # required for serving swagger ui's css/js files
'drf_yasg',

@ -42,6 +42,7 @@ urlpatterns = [
path('api/', include('warehouse_info.urls')),
path('api/', include('financial_info.urls')),
path('api/', include('sale_info.urls')),
path('api/', include('production_info.urls')),
re_path(r'^api/generate_code/$', GenerateCode.as_view()),
# 媒体资源文件的访问路由

@ -15,3 +15,7 @@ class NumberPrefix(Enum): # 定义编号的前缀
cat = 'CAT'
# 商品信息编号的前缀
goo = 'GOO'
# 出库单编号的前缀
deliver = 'OUT'
# 入库单编号的前缀
storage = 'INS'

Loading…
Cancel
Save