采购入库基本完成

This commit is contained in:
caoqianming 2022-01-28 13:39:52 +08:00
parent 2d260e694d
commit ea587a3ddc
12 changed files with 185 additions and 132 deletions

View File

@ -2,7 +2,7 @@ from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
from apps.develop.views import CleanDataView, UpdateCuttingView, UpdateEquipState, UpdateFIFOItem, UpdateFIFONumber, UpdateLastTestResult, UpdateNeedToOrder, UpdateSpg
urlpatterns = [
path('cleandata/', CleanDataView.as_view()),
@ -12,6 +12,7 @@ urlpatterns = [
path('update_fifoitem/', UpdateFIFOItem.as_view()),
path('update_spg/', UpdateSpg.as_view()),
path('update_equip_state/', UpdateEquipState.as_view()),
path('update_need_to_order/', UpdateNeedToOrder.as_view())
path('update_need_to_order/', UpdateNeedToOrder.as_view()),
path('update_fifo_number/', UpdateFIFONumber.as_view())
]

View File

@ -105,4 +105,16 @@ class UpdateNeedToOrder(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
WProduct.objects.exclude(to_order=None).update(need_to_order=True)
return Response()
class UpdateFIFONumber(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
from utils.tools import ranstr
for i in FIFO.objects.all():
if i.type in [FIFO.FIFO_TYPE_DO_IN, FIFO.FIFO_TYPE_PUR_IN]:
i.number = 'RK'+ ranstr(7)
else:
i.number = 'CK' + ranstr(7)
i.save()
return Response()

View File

@ -2,7 +2,4 @@ from django.apps import AppConfig
class InmConfig(AppConfig):
name = 'apps.inm'
verbose_name = '库存管理'
def ready(self):
import apps.inm.signals
verbose_name = '库存管理'

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.9 on 2022-01-28 01:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('pum', '0004_puorder_puorderitem'),
('inm', '0029_fifo_pu_order'),
]
operations = [
migrations.AddField(
model_name='fifo',
name='number',
field=models.CharField(default=1, max_length=100, verbose_name='记录编号'),
preserve_default=False,
),
migrations.AddField(
model_name='fifo',
name='vendor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pum.vendor', verbose_name='供应商'),
),
migrations.AlterField(
model_name='fifoitemproduct',
name='fifoitem',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inm.fifoitem', verbose_name='关联出入库条目'),
),
]

View File

@ -2,7 +2,7 @@ from django.db import models
from django.db.models.base import Model
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.pum.models import PuOrder, Vendor
from apps.pum.models import PuOrder, PuOrderItem, Vendor
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
@ -73,6 +73,7 @@ class FIFO(CommonADModel):
(FIFO_TYPE_PUR_IN, '采购入库'),
(FIFO_TYPE_DO_IN, '生产入库')
)
number = models.CharField('记录编号', max_length=100)
type = models.IntegerField('出入库类型', default=1)
is_audited = models.BooleanField('是否审核', default=False)
auditor = models.ForeignKey(
@ -102,6 +103,8 @@ class FIFOItem(BaseModel):
subproduction_plan = models.ForeignKey(
SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, null=True, blank=True)
files = models.ManyToManyField(File, verbose_name='上传材料', blank=True)
pu_order_item = models.ForeignKey(PuOrderItem,
verbose_name='关联采购订单条目', null=True, blank=True, on_delete=models.CASCADE)
class IProduct(BaseModel):
@ -121,14 +124,17 @@ class IProduct(BaseModel):
class FIFOItemProduct(BaseModel):
"""
出入库产品
出入库记录具体产品
"""
fifoitem = models.ForeignKey(
FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True,
related_name='fifoitem_wproduct')
FIFOItem, verbose_name='关联出入库条目', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct',
on_delete=models.CASCADE, verbose_name='关联的动态产品',
db_constraint=False, null=True, blank=True,
related_name='fifoitem_wproduct')
number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(
Material, verbose_name='物料类型', on_delete=models.CASCADE)
iproduct = models.ForeignKey(
IProduct, verbose_name='关联库存产品', null=True, blank=True, on_delete=models.SET_NULL)
IProduct, verbose_name='关联库存产品',
null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -2,7 +2,7 @@ from rest_framework import exceptions
from rest_framework import serializers
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse, Inventory
from apps.pum.models import Vendor
from apps.pum.models import PuOrder, Vendor
from apps.qm.models import TestRecord, TestRecordItem
from apps.sam.serializers import OrderSimpleSerializer
@ -11,6 +11,8 @@ from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer
from django.db import transaction
from utils.mixins import DynamicFieldsSerializerMixin
from utils.tools import ranstr
from rest_framework.exceptions import ValidationError
@ -77,7 +79,20 @@ class FIFOListSerializer(serializers.ModelSerializer):
class FIFOItemCreateSerializer(serializers.ModelSerializer):
class Meta:
model = FIFOItem
fields = ['warehouse', 'material', 'batch', 'fifo', 'files']
fields = ['warehouse',
'material', 'batch', 'fifo', 'files', 'pu_order_item']
def create(self, validated_data):
fifo = validated_data['fifo']
pu_order_item = validated_data.get('pu_order_item', None)
if pu_order_item:
if fifo.pu_order != pu_order_item.pu_order:
raise ValidationError('项目与采购订单不一致')
validated_data['material']=pu_order_item.material
else:
if fifo.pu_order is not None:
raise ValidationError('非采购订单')
return super().create(validated_data)
class FIFOItemUpdateSerializer(serializers.ModelSerializer):
class Meta:
@ -93,14 +108,14 @@ class FIFOItemSerializer(serializers.ModelSerializer):
fields = '__all__'
class IProductInPurSerializer(serializers.ModelSerializer):
class FIFOItemProductCreateSerializer(serializers.ModelSerializer):
class Meta:
model = IProduct
fields = ['number']
class FIFODetailInPurSerializer(serializers.ModelSerializer):
details = IProductInPurSerializer(many=True, required=False)
details = FIFOItemProductCreateSerializer(many=True, required=False)
class Meta:
model = FIFOItem
@ -130,6 +145,7 @@ class FIFOInOtherSerializer(serializers.ModelSerializer):
obj.save()
for i in details:
if 'details' in i:
i['number'] = 'RK' + ranstr(7)
p_details = i.pop('details')
if len(p_details) != i['count']:
raise serializers.ValidationError('数目对不上')
@ -142,16 +158,9 @@ class FIFOInOtherSerializer(serializers.ModelSerializer):
x['fifoitem'] = fifoitem
p_list0.append(FIFOItemProduct(**x))
FIFOItemProduct.objects.bulk_create(p_list0)
p_list = []
for x in p_details:
x['material'] = i['material']
x['warehouse'] = validated_data['warehouse']
x['batch'] = i['batch']
p_list.append(IProduct(**x))
IProduct.objects.bulk_create(p_list)
else:
i['fifo'] = obj
i['number'] = 'RK' + ranstr(7)
FIFOItem.objects.create(**i)
return obj
@ -159,47 +168,18 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
"""
采购入库序列化
"""
details = FIFODetailInPurSerializer(many=True)
pu_order = serializers.PrimaryKeyRelatedField(label='采购订单ID',
queryset = PuOrder.objects.filter(is_audited=True))
class Meta:
model = FIFO
fields = ['details']
fields = ['pu_order']
def create(self, validated_data):
details = validated_data.pop('details')
if len(details) > 0:
pass
else:
raise serializers.ValidationError('没有入库内容')
with transaction.atomic():
validated_data['type'] = FIFO.FIFO_TYPE_PUR_IN
obj = FIFO(**validated_data)
obj.save()
for i in details:
if 'details' in i:
p_details = i.pop('details')
if len(p_details) != i['count']:
raise serializers.ValidationError('数目对不上')
else:
i['fifo'] = obj
fifoitem = FIFOItem.objects.create(**i)
p_list0 = []
for x in p_details:
x['material'] = i['material']
x['fifoitem'] = fifoitem
p_list0.append(FIFOItemProduct(**x))
FIFOItemProduct.objects.bulk_create(p_list0)
p_list = []
for x in p_details:
x['material'] = i['material']
x['warehouse'] = validated_data['warehouse']
x['batch'] = i['batch']
p_list.append(IProduct(**x))
IProduct.objects.bulk_create(p_list)
else:
i['fifo'] = obj
FIFOItem.objects.create(**i)
pu_order = validated_data['pu_order']
validated_data['vendor'] = pu_order.vendor
validated_data['number'] = 'RK' + ranstr(7)
obj = FIFO.objects.create(**validated_data)
return obj

View File

@ -0,0 +1,73 @@
from rest_framework.exceptions import ValidationError
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
class InmService:
@classmethod
def update_inm(cls, instance:FIFO, type:int=1):
"""
更新库存(正反)
"""
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
defaults={'material':material, 'warehouse':warehouse, 'count':0})
o1.count = o1.count + i.count
o1.save()
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch})
o2.count = o2.count + i.count
o2.save()
material.count = material.count + i.count
material.save()
# 创建IProduct
ips2 = []
for m in FIFOItemProduct.objects.filter(fifoitem=i):
ip = {}
ip['warehouse'] = warehouse
ip['batch'] = i.batch
wp = m.wproduct
ip['wproduct'] = wp
ip['number'] = m.number
ip['material'] = m.material
ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2)
# 如果是采购入库更新采购订单表
if instance.type == FIFO.FIFO_TYPE_PUR_IN:
pur_order_item = i.pur_order_item
pur_order_item.delivered_count = pur_order_item.delivered_count\
+ i.count
pur_order_item.save()
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
temp_count = o1.count - i.count
if temp_count < 0:
raise ValidationError('库存不足,操作失败')
o1.count = temp_count
o1.save()
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
temp_count = o2.count - i.count
if temp_count < 0:
raise ValidationError('库存不足,操作失败')
o2.count = temp_count
o2.save()
temp_count = material.count - i.count
if temp_count < 0:
raise ValidationError('库存不足,操作失败')
material.count = temp_count
material.save()
# 删除IProduct
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
# 生产领料的情况直接从IProduct中删除
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
IProduct.objects.filter(number__in=numbers).delete()

View File

@ -1,58 +0,0 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
def update_inm(instance:FIFO, type:int=1):
"""
更新库存(正反)
"""
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
defaults={'material':material, 'warehouse':warehouse, 'count':0})
o1.count = o1.count + i.count
o1.save()
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch})
o2.count = o2.count + i.count
o2.save()
material.count = material.count + i.count
material.save()
# 创建IProduct
ips2 = []
for m in FIFOItemProduct.objects.filter(fifoitem=i):
ip = {}
ip['warehouse'] = warehouse
ip['batch'] = i.batch
wp = m.wproduct
ip['wproduct'] = wp
ip['number'] = m.number
ip['material'] = m.material
ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2)
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT, FIFO.FIFO_TYPE_SALE_OUT]: # 生产领料 销售出库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material
warehouse = i.warehouse
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
o1.count = o1.count - i.count
o1.save()
o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch)
o2.count = o2.count - i.count
o2.save()
material.count = material.count - i.count
material.save()
# 删除IProduct
if instance.type == FIFO.FIFO_TYPE_DO_OUT:
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
IProduct.objects.filter(number__in=numbers).delete()

View File

@ -9,7 +9,7 @@ from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,
from apps.inm.serializers import FIFOInOtherSerializer, FIFOItemCreateSerializer, FIFOItemSerializer, FIFOInPurSerializer, FIFOItemUpdateSerializer, FIFOListSerializer, IProductListSerializer, \
InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, \
WareHouseCreateUpdateSerializer, InventorySerializer
from apps.inm.signals import update_inm
from apps.inm.services import InmService
from apps.qm.models import TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin
from rest_framework.decorators import action
@ -205,7 +205,7 @@ class FIFOViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
obj.auditor = request.user
obj.inout_date = timezone.now() # 也是审核日期
obj.save()
update_inm(obj) # 更新库存
InmService.update_inm(obj) # 更新库存
return Response()

View File

@ -2,6 +2,7 @@ from rest_framework.mixins import ListModelMixin, DestroyModelMixin, CreateModel
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.services import InmService
from apps.mtm.models import Material
from apps.sam.models import Sale, SaleProduct
from apps.sam.serializers_sale import SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer
@ -11,10 +12,11 @@ from rest_framework.decorators import action
from django.utils import timezone
from apps.system.mixins import CreateUpdateModelAMixin
from apps.inm.signals import update_inm
from rest_framework import serializers
from django.db.models import Count
from utils.tools import ranstr
class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
销售记录
@ -71,6 +73,7 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
fifo.auditor = request.user
fifo.inout_date = timezone.now()
fifo.create_by = request.user
fifo.number = 'CK' + ranstr(7)
fifo.save()
# 创建出库条目
ips = IProduct.objects.filter(sale_iproduct__sale=obj)
@ -104,7 +107,7 @@ class SaleViewSet(CreateUpdateModelAMixin, ListModelMixin, RetrieveModelMixin, C
WProduct.objects.filter(iproduct_wproduct__sale_iproduct__sale=obj).update(
act_state=WProduct.WPR_ACT_STATE_SELLED)
# 更新库存
update_inm(fifo)
InmService.update_inm(fifo)
# 变更审核状态
obj.is_audited = True
obj.save()

View File

@ -4,8 +4,8 @@ from rest_framework.serializers import ModelSerializer
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.inm.serializers import WareHouseSimpleSerializer
from apps.inm.services import InmService
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer
@ -21,6 +21,7 @@ from apps.wpm.models import Operation, OperationEquip, OperationMaterial, Operat
from django.db import transaction
from apps.sam.models import Order
from utils.mixins import DynamicFieldsSerializerMixin
from utils.tools import ranstr
class PickHalfSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
@ -29,12 +30,14 @@ class PickHalfSerializer(serializers.Serializer):
class PickHalfsSerializer(serializers.ListSerializer):
child = PickHalfSerializer()
class PickDetailSerializer(serializers.Serializer):
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
batch = serializers.CharField(label='物料批次', allow_blank=True)
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
pick_count = serializers.IntegerField(label="领料数量", required=False)
iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',required=False, many=True)
iproducts = serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID',
required=False, many=True)
class PickSerializer(serializers.Serializer):
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
@ -58,7 +61,9 @@ class PickSerializer(serializers.Serializer):
# 创建出库记录
with transaction.atomic():
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user)
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT,
inout_date=timezone.now(), create_by=self.context['request'].user,
number = 'CK' + ranstr(7))
for i in picks:
isLowLevel = False
# 更新出库详情
@ -123,7 +128,7 @@ class PickSerializer(serializers.Serializer):
# 更新库存
fifo.is_audited = True
fifo.save()
update_inm(fifo)
InmService.update_inm(fifo)
return fifo
class WMaterialListSerializer(serializers.ModelSerializer):

View File

@ -3,7 +3,7 @@ from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, \
ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.viewsets import GenericViewSet
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct
from apps.inm.signals import update_inm
from apps.inm.services import InmService
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
@ -37,6 +37,8 @@ from django.utils import timezone
from rest_framework import status
from django.db.models import Count
from utils.tools import ranstr
# Create your views here.
@ -242,9 +244,10 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
'subproduction_plan', 'material', 'subproduction_plan__number').annotate(total=Count('id'))
# 创建入库记录
remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
is_audited=True, auditor=request.user, inout_date=timezone.now(),
create_by=request.user, remark=remark)
fifo = FIFO.objects.create(
type=FIFO.FIFO_TYPE_DO_IN,
is_audited=True, auditor=request.user, inout_date=timezone.now(),
create_by=request.user, remark=remark, number='RK'+ranstr(7))
# 创建入库明细
for i in wproducts_a:
spi = SubProductionPlan.objects.get(pk=i['subproduction_plan'])
@ -270,7 +273,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态
update_inm(fifo)
InmService.update_inm(fifo)
for i in wproducts:
i.act_state = WProduct.WPR_ACT_STATE_INM
i.warehouse = warehouse
@ -320,7 +323,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 更新库存并修改半成品进行状态
update_inm(fifo)
InmService.update_inm(fifo)
wproduct.act_state = WProduct.WPR_ACT_STATE_INM
wproduct.warehouse = warehouse
wproduct.save()