采购入库bug,领料需求

This commit is contained in:
caoqianming 2021-10-29 10:26:56 +08:00
parent 2a79fa9f2b
commit 1e361b5a6a
15 changed files with 185 additions and 26 deletions

View File

@ -0,0 +1,9 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material
from .models import MaterialBatch
class MbFilterSet(filters.FilterSet):
material = filters.ModelMultipleChoiceFilter(field_name="material", queryset=Material.objects.all())
class Meta:
model = MaterialBatch
fields = ['material', 'warehouse']

View File

@ -10,7 +10,6 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('wpm', '__first__'),
('mtm', '0025_outputmaterial_is_main'),
('pm', '0007_auto_20211025_1533'),
('inm', '0004_auto_20210929_0842'),
@ -57,7 +56,6 @@ class Migration(migrations.Migration):
('batch', models.CharField(blank=True, max_length=100, null=True, verbose_name='所属批次号')),
('fifos', models.JSONField(blank=True, default=list, verbose_name='关联出入库记录')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='iproduct_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('d_product', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='wpm.product', verbose_name='关联的动态产品')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料类型')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='iproduct_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inm.warehouse', verbose_name='所在仓库')),

View File

@ -7,7 +7,6 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '__first__'),
('inm', '0005_auto_20211025_1533'),
]
@ -18,9 +17,4 @@ class Migration(migrations.Migration):
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='inm.fifo', verbose_name='关联出入库'),
preserve_default=False,
),
migrations.AlterField(
model_name='iproduct',
name='d_product',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.product', verbose_name='关联的动态产品'),
),
]

View File

@ -91,7 +91,7 @@ class IProduct(BaseModel):
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, null=True, blank=True)
d_product = models.ForeignKey('wpm.product', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
fifos = models.JSONField('关联出入库记录', default=list, blank=True)

View File

@ -59,6 +59,11 @@ class FIFODetailInPurSerializer(serializers.ModelSerializer):
model = FIFODetail
fields = ['material', 'count', 'batch', 'details']
class MaterialBatchQuerySerializer(serializers.Serializer):
warehouse = serializers.IntegerField(label="仓库ID", required=False)
materials = serializers.ListField(child=serializers.IntegerField(label="物料ID"), required=False)
class FIFOInPurSerializer(serializers.ModelSerializer):
"""
采购入库序列化

View File

@ -18,6 +18,7 @@ def update_by_fifodetail(sender, instance, created, **kwargs):
o1.save()
o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=instance.batch,\
defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':instance.batch})
o2.count = o2.count + instance.count
o2.save()
material.count = material.count + 1
material.save()

View File

@ -2,9 +2,10 @@ from django.shortcuts import render
from rest_framework import serializers
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.filters import MbFilterSet
from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse,Inventory
from apps.inm.serializers import FIFODetailSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.inm.serializers import FIFODetailSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
from rest_framework.response import Response
@ -43,11 +44,22 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
perms_map = {'*': '*'}
queryset = MaterialBatch.objects.select_related('material', 'warehouse').all()
serializer_class = MaterialBatchSerializer
filterset_fields = ['material', 'warehouse']
# filterset_fields = ['material', 'warehouse']
filterset_class = MbFilterSet
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
# @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=MaterialBatchQuerySerializer)
# def query(self, request, pk=None):
# """
# 复杂查询
# """
# serializer = MaterialBatchQuerySerializer(data=request.data)
# serializer.is_valid(raise_exception=True)
# queryset = self.queryset.filter()
# return Response()
class FIFODetailViewSet(ListModelMixin, GenericViewSet):
"""
出入库记录详情表
@ -66,11 +78,13 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
"""
perms_map = {'*': '*'}
queryset = FIFO.objects.select_related('warehouse', 'operator')
serializer_class = FIFOListSerializer
filterset_fields = ['warehouse']
def get_serializer_class(self):
if self.action == 'list':
return FIFOListSerializer
return super().get_serializer_class()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=FIFOInPurSerializer)
def in_pur(self, request, pk=None):

View File

@ -0,0 +1,27 @@
# Generated by Django 3.2.6 on 2021-10-29 02:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0008_subproductionprogress_count_current'),
]
operations = [
migrations.RemoveField(
model_name='subproductionprogress',
name='count_current',
),
migrations.AddField(
model_name='subproductionplan',
name='is_picked',
field=models.BooleanField(default=False, verbose_name='是否已领料'),
),
migrations.AlterField(
model_name='subproductionprogress',
name='count',
field=models.FloatField(verbose_name='应出入数'),
),
]

View File

@ -49,6 +49,7 @@ class SubProductionPlan(CommonAModel):
state = models.IntegerField('状态', default=0)
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
is_picked = models.BooleanField('是否已领料', default=False)
class Meta:
verbose_name = '子生产计划'
verbose_name_plural = verbose_name
@ -64,6 +65,5 @@ class SubProductionProgress(BaseModel):
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, related_name='progress_subplan')
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
type = models.IntegerField('物料应用类型', default=1)
count = models.IntegerField('应出入数')
count = models.FloatField('应出入数')
count_real = models.IntegerField('实际出入数', default=0)
count_current = models.IntegerField('当前数量', default=0)

View File

@ -44,3 +44,6 @@ class SubProductionProgressSerializer(serializers.ModelSerializer):
class Meta:
model = SubProductionProgress
fields = '__all__'
class PickNeedSerializer(serializers.Serializer):
warehouse = serializers.IntegerField(label="仓库ID")

View File

@ -3,9 +3,11 @@ from rest_framework import serializers
from rest_framework.views import APIView
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSerializer
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import InputMaterial, OutputMaterial, Step, SubProduction, UsedStep
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet
@ -78,9 +80,9 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
workshop=i.process.workshop, process=i.process, create_by=request.user,
steps = list(steps))
for m in InputMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
SubProductionProgress.objects.create(material=m.material, type=1, count=m.count, subproduction_plan=instance)
SubProductionProgress.objects.create(material=m.material, type=1, count=m.count*production_plan.count, subproduction_plan=instance)
for m in OutputMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
SubProductionProgress.objects.create(material=m.material, type=2, count=m.count, subproduction_plan=instance)
SubProductionProgress.objects.create(material=m.material, type=2, count=m.count*production_plan.count, subproduction_plan=instance)
production_plan.is_planed=True
production_plan.save()
return Response()
@ -92,6 +94,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
perms_map = {'*': '*'}
queryset = SubProductionPlan.objects.select_related('process', 'workshop')
search_fields = []
serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan']
ordering_fields = ['process__number']
ordering = ['process__number']
@ -101,7 +104,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
return SubProductionPlanListSerializer
elif self.action == 'update':
return SubProductionPlanUpdateSerializer
return SubProductionPlanListSerializer
return super().get_serializer_class()
@action(methods=['get'], detail=True, perms_map={'get':'*'}, serializer_class=SubProductionProgressSerializer)
def progress(self, request, pk=None):
@ -137,15 +140,21 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
return Response()
raise APIException('计划状态有误')
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=PickNeedSerializer)
def pick_need(self, request, pk=None):
"""
领料需求清单
领料需求清单/库存数
"""
obj = self.get_object()
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=1)
serializer = SubProductionProgressSerializer(instance=instance, many=True)
return Response(serializer.data)
need = serializer.data
materials = []
for i in need:
materials.append(i['material'])
objs = MaterialBatch.objects.filter(warehouse=request.data['warehouse'], material__id__in=materials)
have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have})
class ResourceViewSet(GenericViewSet):

View File

@ -0,0 +1,86 @@
# Generated by Django 3.2.6 on 2021-10-29 02:19
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('pm', '0009_auto_20211029_1017'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0025_outputmaterial_is_main'),
]
operations = [
migrations.CreateModel(
name='WProduct',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('number', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='物品编号')),
('act_state', models.IntegerField(default=0, verbose_name='进行状态')),
('remark', models.CharField(blank=True, max_length=200, null=True, verbose_name='备注')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproduct_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('m_state', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所属物料状态')),
('p_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='所在步骤')),
('parent', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='上一级')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子生产计划')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproduct_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='WProductForm',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('data', models.JSONField(blank=True, default=dict, verbose_name='记录的数据')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductform_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('record_form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.recordform', verbose_name='所用表格')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductform_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='WProductFlow',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('wproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='产品')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='WMaterial',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('batch', models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号')),
('count', models.IntegerField(default=0, verbose_name='当前数量')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='关联物料')),
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子计划')),
],
options={
'abstract': False,
},
),
]

View File

@ -8,9 +8,18 @@ from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
from apps.mtm.models import Material, Step, RecordForm
class Product(CommonAModel):
class WMaterial(BaseModel):
"""
产品(所有生产过程中出现过的)
车间生产物料
"""
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE)
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
count = models.IntegerField('当前数量', default=0)
class WProduct(CommonAModel):
"""
半成品/成品
"""
act_state_choices=(
(0, '待执行'),
@ -25,7 +34,7 @@ class Product(CommonAModel):
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE)
class ProductForm(CommonAModel):
class WProductForm(CommonAModel):
"""
记录表格
"""
@ -33,8 +42,8 @@ class ProductForm(CommonAModel):
data = models.JSONField('记录的数据', default=dict, blank=True)
class ProductFlow(BaseModel):
class WProductFlow(BaseModel):
"""
产品流转日志
"""
product = models.ForeignKey(Product, verbose_name='产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey(WProduct, verbose_name='产品', on_delete=models.CASCADE)

View File

@ -1,6 +1,10 @@
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
class PickDetailSerializer(serializers.Serializer):
material = serializers.IntegerField(label='物料ID')
batch = serializers.CharField(label='物料批次')
pick_count = serializers.IntegerField(label="领料数量")
class PickSerializer(serializers.Serializer):
warehouse = serializers.IntegerField()
warehouse = serializers.IntegerField(label="仓库ID")