Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
eaea0cdb7c
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-17 06:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inm', '0016_auto_20211112_1124'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='iproduct',
|
||||||
|
name='number',
|
||||||
|
field=models.CharField(default=1, max_length=50, unique=True, verbose_name='物品编号'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -97,7 +97,7 @@ class IProduct(BaseModel):
|
||||||
"""
|
"""
|
||||||
具体产品条目
|
具体产品条目
|
||||||
"""
|
"""
|
||||||
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
number = models.CharField('物品编号', unique=True, max_length=50)
|
||||||
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||||
batch = models.CharField('所属批次号', max_length=100, default='')
|
batch = models.CharField('所属批次号', max_length=100, default='')
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,14 @@ class MaterialBatchSerializer(serializers. ModelSerializer):
|
||||||
model = MaterialBatch
|
model = MaterialBatch
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class IProductListSerializer(serializers.ModelSerializer):
|
||||||
|
material_= MaterialSimpleSerializer(source='material', read_only=True)
|
||||||
|
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = IProduct
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class FIFOListSerializer(serializers.ModelSerializer):
|
class FIFOListSerializer(serializers.ModelSerializer):
|
||||||
auditor_ = UserSimpleSerializer(source='auditor', read_only=True)
|
auditor_ = UserSimpleSerializer(source='auditor', read_only=True)
|
||||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from apps.inm.models import FIFOItemProduct, Inventory, MaterialBatch, FIFO, FIFOItem
|
from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem
|
||||||
|
|
||||||
|
|
||||||
def update_inm(instance:FIFO, type:int=1):
|
def update_inm(instance:FIFO, type:int=1):
|
||||||
|
|
@ -23,6 +23,19 @@ def update_inm(instance:FIFO, type:int=1):
|
||||||
o2.save()
|
o2.save()
|
||||||
material.count = material.count + i.count
|
material.count = material.count + i.count
|
||||||
material.save()
|
material.save()
|
||||||
|
|
||||||
|
# 创建IProduct
|
||||||
|
ips2 = []
|
||||||
|
for m in FIFOItemProduct.objects.filter(fifoitem=i):
|
||||||
|
ip = {}
|
||||||
|
ip['warehouse'] = warehouse
|
||||||
|
ip['batch'] = i.batch
|
||||||
|
ip['wproduct'] = m.wproduct
|
||||||
|
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]: # 生产领料
|
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT]: # 生产领料
|
||||||
# 更新相关表
|
# 更新相关表
|
||||||
for i in FIFOItem.objects.filter(fifo=instance):
|
for i in FIFOItem.objects.filter(fifo=instance):
|
||||||
|
|
@ -36,4 +49,8 @@ def update_inm(instance:FIFO, type:int=1):
|
||||||
o2.save()
|
o2.save()
|
||||||
material.count = material.count - i.count
|
material.count = material.count - i.count
|
||||||
material.save()
|
material.save()
|
||||||
|
|
||||||
|
# 删除IProduct
|
||||||
|
numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True)
|
||||||
|
IProduct.objects.filter(number__in=numbers).delete()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db.models import base
|
from django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
from rest_framework import urlpatterns
|
||||||
from apps.inm.views import FIFOItemViewSet, FIFOViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet
|
from apps.inm.views import FIFOItemViewSet, FIFOViewSet, IProductViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
|
@ -10,6 +10,7 @@ router.register('inventory', InventoryViewSet, basename='inventory')
|
||||||
router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch')
|
router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch')
|
||||||
router.register('fifo', FIFOViewSet, basename='fifo'),
|
router.register('fifo', FIFOViewSet, basename='fifo'),
|
||||||
router.register('fifoitem', FIFOItemViewSet, basename='fifoitem')
|
router.register('fifoitem', FIFOItemViewSet, basename='fifoitem')
|
||||||
|
router.register('iproduct', IProductViewSet, basename='iproduct')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveMod
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
from apps.inm.filters import MbFilterSet
|
from apps.inm.filters import MbFilterSet
|
||||||
|
|
||||||
from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse,Inventory
|
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
|
||||||
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
|
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
|
||||||
from apps.inm.signals import update_inm
|
from apps.inm.signals import update_inm
|
||||||
from apps.qm.models import TestRecordItem
|
from apps.qm.models import TestRecordItem
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
|
|
@ -160,4 +160,16 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
|
||||||
obj.save()
|
obj.save()
|
||||||
update_inm(obj) # 更新库存
|
update_inm(obj) # 更新库存
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
|
class IProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
半成品库存表
|
||||||
|
"""
|
||||||
|
perms_map = {'*': '*'}
|
||||||
|
queryset = IProduct.objects.select_related('material', 'warehouse').all()
|
||||||
|
serializer_class = IProductListSerializer
|
||||||
|
filterset_fields = ['material', 'warehouse', 'batch']
|
||||||
|
search_fields = []
|
||||||
|
ordering_fields = ['create_time']
|
||||||
|
ordering = ['-create_time']
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-16 08:03
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0033_alter_recordformfield_rule_expression'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='recordformfield',
|
||||||
|
name='boolean_field_display',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='recordformfield',
|
||||||
|
name='display_expression',
|
||||||
|
field=models.TextField(blank=True, null=True, verbose_name='字段展现表达式'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='recordformfield',
|
||||||
|
name='help_text',
|
||||||
|
field=models.TextField(blank=True, null=True, verbose_name='说明'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='recordformfield',
|
||||||
|
name='is_hidden',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='是否隐藏'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='recordformfield',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='父'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='recordformfield',
|
||||||
|
name='field_choice',
|
||||||
|
field=models.JSONField(blank=True, default=list, help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号', null=True, verbose_name='radio、checkbox、select的选项'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -144,17 +144,23 @@ class RecordFormField(CommonAModel):
|
||||||
field_type = models.CharField('类型', max_length=50, choices=field_type_choices)
|
field_type = models.CharField('类型', max_length=50, choices=field_type_choices)
|
||||||
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
|
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
|
||||||
field_name = models.CharField('字段名称', max_length=50)
|
field_name = models.CharField('字段名称', max_length=50)
|
||||||
boolean_field_display = models.JSONField('布尔类型显示名', default=dict, blank=True, null=True,
|
field_choice = models.JSONField('radio、checkbox、select的选项', default=list, blank=True, null=True,
|
||||||
help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"是","0":"否"}或{"1":"需要","0":"不需要"},注意数字也需要引号')
|
|
||||||
field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True, null=True,
|
|
||||||
help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
|
help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
|
||||||
|
|
||||||
|
help_text = models.TextField('说明', null=True, blank=True)
|
||||||
sort = models.IntegerField('排序号', default=1)
|
sort = models.IntegerField('排序号', default=1)
|
||||||
need_judge = models.BooleanField('需要判定项目', default=False)
|
|
||||||
high_limit = models.FloatField('上限值', null=True, blank=True)
|
high_limit = models.FloatField('上限值', null=True, blank=True)
|
||||||
high_rule = models.IntegerField('上限规则', choices=high_rule_choices, null=True, blank=True)
|
high_rule = models.IntegerField('上限规则', choices=high_rule_choices, null=True, blank=True)
|
||||||
low_limit = models.FloatField('下限值', null=True, blank=True)
|
low_limit = models.FloatField('下限值', null=True, blank=True)
|
||||||
low_rule = models.IntegerField('下限规则', choices=low_rule_choices, null=True, blank=True)
|
low_rule = models.IntegerField('下限规则', choices=low_rule_choices, null=True, blank=True)
|
||||||
|
|
||||||
|
need_judge = models.BooleanField('需要判定项目', default=False)
|
||||||
rule_expression = models.TextField('判定表达式', null=True, blank=True)
|
rule_expression = models.TextField('判定表达式', null=True, blank=True)
|
||||||
|
display_expression = models.TextField('字段展现表达式', null=True, blank=True)
|
||||||
|
is_hidden = models.BooleanField('是否隐藏', default=False)
|
||||||
|
parent = models.ForeignKey('self', verbose_name='父', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '记录表格字段'
|
verbose_name = '记录表格字段'
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ class RecordFormDetailSerializer(serializers.ModelSerializer):
|
||||||
class RecordFormFieldCreateSerializer(serializers.ModelSerializer):
|
class RecordFormFieldCreateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RecordFormField
|
model = RecordFormField
|
||||||
fields = ['form', 'field_type', 'field_key', 'field_name', 'boolean_field_display', 'field_choice', 'sort', 'need_judge', 'high_limit', 'high_rule', 'low_limit', 'low_rule', 'rule_expression']
|
fields = '__all__'
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
if RecordFormField.objects.filter(field_key=data['field_key'], form=data['form'], is_deleted=False).exists():
|
if RecordFormField.objects.filter(field_key=data['field_key'], form=data['form'], is_deleted=False).exists():
|
||||||
|
|
@ -225,7 +225,7 @@ class RecordFormFieldCreateSerializer(serializers.ModelSerializer):
|
||||||
class RecordFormFieldUpdateSerializer(serializers.ModelSerializer):
|
class RecordFormFieldUpdateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RecordFormField
|
model = RecordFormField
|
||||||
fields = ['field_type', 'field_name', 'boolean_field_display', 'field_choice', 'sort', 'need_judge', 'high_limit', 'high_rule', 'low_limit', 'low_rule', 'rule_expression']
|
exclude = ['field_key']
|
||||||
|
|
||||||
class RecordFormFieldSimpleSerializer(serializers.ModelSerializer):
|
class RecordFormFieldSimpleSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ class SubProductionPlan(CommonAModel):
|
||||||
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
|
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
|
||||||
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
|
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
|
||||||
is_picked = models.BooleanField('是否已领料', default=False)
|
is_picked = models.BooleanField('是否已领料', default=False)
|
||||||
|
|
||||||
|
# wproducts = models.JSONField('半成品表', default=list, blank=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = '子生产计划'
|
verbose_name = '子生产计划'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ def update_subplan_main(sender, instance, created, **kwargs):
|
||||||
subplan.main_product = instance.material
|
subplan.main_product = instance.material
|
||||||
subplan.main_count = instance.count
|
subplan.main_count = instance.count
|
||||||
subplan.main_count_real = instance.count_real
|
subplan.main_count_real = instance.count_real
|
||||||
if subplan.main_count == instance.count_real:
|
if subplan.main_count >= instance.count_real:
|
||||||
subplan.state = 4
|
subplan.state = 4
|
||||||
subplan.save()
|
subplan.save()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from rest_framework.exceptions import APIException
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
|
from utils.tools import ranstr
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
def updateOrderPlanedCount(order):
|
def updateOrderPlanedCount(order):
|
||||||
|
|
@ -59,7 +60,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise APIException('排产数量错误')
|
raise APIException('排产数量错误')
|
||||||
instance = serializer.save(create_by=request.user, product=order.product)
|
instance = serializer.save(create_by=request.user, product=order.product, number='JH-'+ranstr(7))
|
||||||
updateOrderPlanedCount(instance.order)
|
updateOrderPlanedCount(instance.order)
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class WMaterial(BaseModel):
|
||||||
|
|
||||||
class WProduct(CommonAModel):
|
class WProduct(CommonAModel):
|
||||||
"""
|
"""
|
||||||
半成品/成品
|
动态半成品/成品表
|
||||||
"""
|
"""
|
||||||
WPR_ACT_STATE_DOING = 1
|
WPR_ACT_STATE_DOING = 1
|
||||||
WPR_ACT_STATE_TOTEST = 2
|
WPR_ACT_STATE_TOTEST = 2
|
||||||
|
|
@ -45,7 +45,6 @@ class WProduct(CommonAModel):
|
||||||
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
|
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
|
||||||
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
|
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
class Operation(CommonAModel):
|
class Operation(CommonAModel):
|
||||||
"""
|
"""
|
||||||
生产操作
|
生产操作
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from rest_framework import serializers, exceptions
|
from rest_framework import serializers, exceptions
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse
|
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
|
||||||
from apps.inm.signals import update_inm
|
from apps.inm.signals import update_inm
|
||||||
from apps.mtm.models import Material, RecordForm, Step
|
from apps.mtm.models import Material, RecordForm, Step
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer
|
||||||
|
|
@ -13,15 +13,21 @@ from apps.system.serializers import UserSimpleSerializer
|
||||||
from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem
|
from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
|
class PickHalfSerializer(serializers.Serializer):
|
||||||
|
wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'),
|
||||||
|
required=False) # 从半成品表里直接修改状态
|
||||||
class PickDetailSerializer(serializers.Serializer):
|
class PickDetailSerializer(serializers.Serializer):
|
||||||
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
||||||
batch = serializers.CharField(label='物料批次', allow_blank=True)
|
batch = serializers.CharField(label='物料批次', allow_blank=True)
|
||||||
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
||||||
pick_count = serializers.IntegerField(label="领料数量", required=False)
|
pick_count = serializers.IntegerField(label="领料数量", required=False)
|
||||||
|
iproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID'),
|
||||||
|
required=False)
|
||||||
|
|
||||||
class PickSerializer(serializers.Serializer):
|
class PickSerializer(serializers.Serializer):
|
||||||
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
||||||
picks = PickDetailSerializer(many=True)
|
picks = PickDetailSerializer(many=True) # 从库存里拿
|
||||||
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
picks = validated_data.pop('picks')
|
picks = validated_data.pop('picks')
|
||||||
|
|
@ -38,16 +44,33 @@ class PickSerializer(serializers.Serializer):
|
||||||
# except:
|
# except:
|
||||||
# raise exceptions.ValidationError('物料不存在')
|
# raise exceptions.ValidationError('物料不存在')
|
||||||
# 创建出库记录
|
# 创建出库记录
|
||||||
|
|
||||||
with transaction.atomic():
|
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)
|
||||||
for i in picks:
|
for i in picks:
|
||||||
# 更新出库详情
|
# 更新出库详情
|
||||||
i['count'] = i.pop('pick_count', 0)
|
i['count'] = i.pop('pick_count', 0)
|
||||||
|
# 是否勾选每一个
|
||||||
|
if 'iproducts' in i and len(i['iproducts'])>0:
|
||||||
|
i['count'] = len(i['iproducts'])
|
||||||
|
isLowLevel = True
|
||||||
if i['count']>0:
|
if i['count']>0:
|
||||||
i['fifo'] = fifo
|
i['fifo'] = fifo
|
||||||
i['is_testok'] = True # 默认检测合格
|
i['is_testok'] = True # 默认检测合格
|
||||||
i['subproduction_plan'] = sp
|
i['subproduction_plan'] = sp
|
||||||
FIFOItem.objects.create(**i)
|
fifoitem = FIFOItem.objects.create(**i)
|
||||||
|
# 创建再下一个层级
|
||||||
|
if isLowLevel:
|
||||||
|
mls = []
|
||||||
|
for m in i['iproducts']:
|
||||||
|
ml = {}
|
||||||
|
ml['material'] = m.material
|
||||||
|
ml['number'] = m.number
|
||||||
|
ml['wproduct'] = m.wproduct
|
||||||
|
ml['fifoitem'] = fifoitem
|
||||||
|
mls.append(FIFOItemProduct(**ml))
|
||||||
|
FIFOItemProduct.objects.bulk_create(mls)
|
||||||
|
|
||||||
# 更新车间物料
|
# 更新车间物料
|
||||||
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
|
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
|
||||||
subproduction_plan=sp,defaults={
|
subproduction_plan=sp,defaults={
|
||||||
|
|
@ -62,6 +85,12 @@ class PickSerializer(serializers.Serializer):
|
||||||
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1)
|
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1)
|
||||||
spp.count_pick = spp.count_pick + i['count']
|
spp.count_pick = spp.count_pick + i['count']
|
||||||
spp.save()
|
spp.save()
|
||||||
|
# 更新半成品表
|
||||||
|
wproducts = WProduct.objects.filter(pk__in=[x.wproduct for x in i['iproducts']])
|
||||||
|
first_step = Step.objects.get(pk=sp.steps[0].id)
|
||||||
|
wproducts.update(p_state=first_step, is_executed=False,
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None,
|
||||||
|
subproduction_plan=sp, production_plan=sp.production_plan)
|
||||||
sp.is_picked=True
|
sp.is_picked=True
|
||||||
sp.state = 3 #生产中
|
sp.state = 3 #生产中
|
||||||
sp.state_date_real = timezone.now() #实际开工日期
|
sp.state_date_real = timezone.now() #实际开工日期
|
||||||
|
|
@ -183,7 +212,7 @@ class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||||
class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
|
class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
|
||||||
record_data = WpmTestRecordItemCreateSerializer(many=True)
|
record_data = WpmTestRecordItemCreateSerializer(many=True)
|
||||||
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
|
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
|
||||||
is_testok = serializers.BooleanField()
|
is_testok = serializers.BooleanField(required=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestRecord
|
model = TestRecord
|
||||||
fields = ['form', 'record_data', 'is_testok', 'wproduct']
|
fields = ['form', 'record_data', 'is_testok', 'wproduct']
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from rest_framework.utils import serializer_helpers
|
||||||
from rest_framework.utils.field_mapping import get_relation_kwargs
|
from rest_framework.utils.field_mapping import get_relation_kwargs
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct
|
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
|
||||||
from apps.inm.signals import update_inm
|
from apps.inm.signals import update_inm
|
||||||
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial
|
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial
|
||||||
from apps.mtm.serializers import RecordFormDetailSerializer
|
from apps.mtm.serializers import RecordFormDetailSerializer
|
||||||
|
|
@ -17,13 +17,14 @@ from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
||||||
|
|
||||||
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
|
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from rest_framework import exceptions, serializers
|
from rest_framework import exceptions, serializers
|
||||||
|
|
||||||
from apps.wpm.services import WpmServies
|
from apps.wpm.services import WpmServies
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from utils.tools import ranstr
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class WPlanViewSet(ListModelMixin, GenericViewSet):
|
class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -37,6 +38,33 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
ordering_fields = []
|
ordering_fields = []
|
||||||
ordering = ['-id']
|
ordering = ['-id']
|
||||||
|
|
||||||
|
@action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def pick_half(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
领半成品
|
||||||
|
"""
|
||||||
|
sp = self.get_object()
|
||||||
|
if request.method=='GET':
|
||||||
|
"""
|
||||||
|
领半成品
|
||||||
|
"""
|
||||||
|
mIds = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
|
||||||
|
material__type=Material.MA_TYPE_HALFGOOD).values_list('material', flat=True)
|
||||||
|
queyset = WProduct.objects.filter(is_hidden=False, m_state__in=mIds, act_state=WProduct.WPR_ACT_STATE_OK)
|
||||||
|
return Response(WProductListSerializer(instance=queyset, many=True).data)
|
||||||
|
elif request.method=='POST':
|
||||||
|
serializer= PickHalfSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.data
|
||||||
|
wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']])
|
||||||
|
first_step = Step.objects.get(pk=sp.steps[0].id)
|
||||||
|
wps.update(p_state=first_step, is_executed=False,
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None,
|
||||||
|
subproduction_plan=sp, production_plan=sp.production_plan)
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer)
|
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def putin(self, request, pk=None):
|
def putin(self, request, pk=None):
|
||||||
|
|
@ -49,6 +77,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
subplan = self.get_object()
|
subplan = self.get_object()
|
||||||
material = subplan.main_product
|
material = subplan.main_product
|
||||||
batch = subplan.production_plan.number
|
batch = subplan.production_plan.number
|
||||||
|
warehouse = WareHouse.objects.get(id=vdata['warehouse'])
|
||||||
wproducts = WProduct.objects.filter(subproduction_plan=subplan,
|
wproducts = WProduct.objects.filter(subproduction_plan=subplan,
|
||||||
act_state=WProduct.WPR_ACT_STATE_OK, m_state=material, is_deleted=False)
|
act_state=WProduct.WPR_ACT_STATE_OK, m_state=material, is_deleted=False)
|
||||||
if wproducts.exists():
|
if wproducts.exists():
|
||||||
|
|
@ -60,7 +89,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
fifoitem = FIFOItem()
|
fifoitem = FIFOItem()
|
||||||
fifoitem.is_tested = True
|
fifoitem.is_tested = True
|
||||||
fifoitem.is_testok = True
|
fifoitem.is_testok = True
|
||||||
fifoitem.warehouse = vdata['warehouse']
|
fifoitem.warehouse = warehouse
|
||||||
fifoitem.material = material
|
fifoitem.material = material
|
||||||
fifoitem.count = wproducts.count()
|
fifoitem.count = wproducts.count()
|
||||||
fifoitem.batch = batch
|
fifoitem.batch = batch
|
||||||
|
|
@ -81,7 +110,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
ips2 = []
|
ips2 = []
|
||||||
for i in wproducts:
|
for i in wproducts:
|
||||||
ip = {}
|
ip = {}
|
||||||
ip['warehouse'] = vdata['warehouse']
|
ip['warehouse'] = warehouse
|
||||||
ip['batch'] = batch
|
ip['batch'] = batch
|
||||||
ip['wproduct'] = i
|
ip['wproduct'] = i
|
||||||
ip['number'] = i.number
|
ip['number'] = i.number
|
||||||
|
|
@ -90,7 +119,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
IProduct.objects.bulk_create(ips2)
|
IProduct.objects.bulk_create(ips2)
|
||||||
# 更新库存并修改半成品进行状态
|
# 更新库存并修改半成品进行状态
|
||||||
update_inm(fifo)
|
update_inm(fifo)
|
||||||
wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=vdata['warehouse'])
|
wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse)
|
||||||
|
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
@ -116,63 +145,6 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
|
|
||||||
@transaction.atomic
|
|
||||||
def putin(self, request, pk=None):
|
|
||||||
"""
|
|
||||||
半成品入库
|
|
||||||
"""
|
|
||||||
serializer= WproductPutInSerializer(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
vdata = serializer.data
|
|
||||||
wproduct = self.get_object()
|
|
||||||
if wproduct.act_state != WProduct.WPR_ACT_STATE_OK:
|
|
||||||
raise exceptions.APIException('半成品不可入库')
|
|
||||||
material = wproduct.m_state
|
|
||||||
batch = wproduct.production_plan.number
|
|
||||||
# 创建入库记录
|
|
||||||
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)
|
|
||||||
# 创建入库明细
|
|
||||||
fifoitem = FIFOItem()
|
|
||||||
fifoitem.is_tested = True
|
|
||||||
fifoitem.is_testok = True
|
|
||||||
fifoitem.warehouse = vdata['warehouse']
|
|
||||||
fifoitem.material = material
|
|
||||||
fifoitem.count = 1 # 单个半成品入库
|
|
||||||
fifoitem.batch = batch
|
|
||||||
fifoitem.fifo = fifo
|
|
||||||
fifoitem.subproduction_plan = wproduct.subproduction_plan
|
|
||||||
fifoitem.save()
|
|
||||||
# 创建入库明细半成品
|
|
||||||
ips = []
|
|
||||||
for i in [wproduct]:
|
|
||||||
ip = {}
|
|
||||||
ip['fifoitem'] = fifoitem
|
|
||||||
ip['wproduct'] = i
|
|
||||||
ip['number'] = i.number
|
|
||||||
ip['material'] = material
|
|
||||||
ips.append(FIFOItemProduct(**ip))
|
|
||||||
FIFOItemProduct.objects.bulk_create(ips)
|
|
||||||
# 创建IProduct
|
|
||||||
ips2 = []
|
|
||||||
for i in [wproduct]:
|
|
||||||
ip = {}
|
|
||||||
ip['warehouse'] = vdata['warehouse']
|
|
||||||
ip['batch'] = batch
|
|
||||||
ip['wproduct'] = i
|
|
||||||
ip['number'] = i.number
|
|
||||||
ip['material'] = material
|
|
||||||
ips2.append(IProduct(**ip))
|
|
||||||
IProduct.objects.bulk_create(ips2)
|
|
||||||
# 更新库存并修改半成品进行状态
|
|
||||||
update_inm(fifo)
|
|
||||||
wproduct.act_state=WProduct.WPR_ACT_STATE_INM
|
|
||||||
wproduct.warehouse=vdata['warehouse']
|
|
||||||
wproduct.save()
|
|
||||||
return Response()
|
|
||||||
|
|
||||||
class WProductViewSet(ListModelMixin, GenericViewSet):
|
class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
半成品
|
半成品
|
||||||
|
|
@ -221,20 +193,66 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
if obj.is_testok:
|
if obj.is_testok:
|
||||||
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
|
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
|
||||||
if wproduct.number is None: # 产生半成品编号
|
if wproduct.number is None: # 产生半成品编号
|
||||||
wproduct.number = 'BCP' + str(timezone.now())
|
wproduct.number = 'WP-'+ranstr(7)
|
||||||
wproduct.save()
|
wproduct.save()
|
||||||
# 更新子计划状态
|
# 更新子计划状态
|
||||||
# 获取该子计划主产品数, 更新进度
|
# 更新子计划主产品数
|
||||||
main_count = WProduct.objects.filter(subproduction_plan=wproduct.subproduction_plan, act_stae=WProduct.WPR_ACT_STATE_OK).count()
|
|
||||||
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
|
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
|
||||||
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||||
instance.count_real = main_count
|
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题
|
||||||
instance.save()
|
instance.save()
|
||||||
else:# 如果不合格
|
else:# 如果不合格
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
|
||||||
|
@transaction.atomic
|
||||||
|
def putin(self, request, pk=None):
|
||||||
|
"""
|
||||||
|
半成品入库
|
||||||
|
"""
|
||||||
|
serializer= WproductPutInSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.data
|
||||||
|
wproduct = self.get_object()
|
||||||
|
warehouse = WareHouse.objects.get(id=vdata['warehouse'])
|
||||||
|
if wproduct.act_state != WProduct.WPR_ACT_STATE_OK:
|
||||||
|
raise exceptions.APIException('半成品不可入库')
|
||||||
|
material = wproduct.m_state
|
||||||
|
batch = wproduct.production_plan.number
|
||||||
|
# 创建入库记录
|
||||||
|
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)
|
||||||
|
# 创建入库明细
|
||||||
|
fifoitem = FIFOItem()
|
||||||
|
fifoitem.is_tested = True
|
||||||
|
fifoitem.is_testok = True
|
||||||
|
fifoitem.warehouse = warehouse
|
||||||
|
fifoitem.material = material
|
||||||
|
fifoitem.count = 1 # 单个半成品入库
|
||||||
|
fifoitem.batch = batch
|
||||||
|
fifoitem.fifo = fifo
|
||||||
|
fifoitem.subproduction_plan = wproduct.subproduction_plan
|
||||||
|
fifoitem.save()
|
||||||
|
# 创建入库明细半成品
|
||||||
|
ips = []
|
||||||
|
for i in [wproduct]:
|
||||||
|
ip = {}
|
||||||
|
ip['fifoitem'] = fifoitem
|
||||||
|
ip['wproduct'] = i
|
||||||
|
ip['number'] = i.number
|
||||||
|
ip['material'] = material
|
||||||
|
ips.append(FIFOItemProduct(**ip))
|
||||||
|
FIFOItemProduct.objects.bulk_create(ips)
|
||||||
|
# 更新库存并修改半成品进行状态
|
||||||
|
update_inm(fifo)
|
||||||
|
wproduct.act_state=WProduct.WPR_ACT_STATE_INM
|
||||||
|
wproduct.warehouse=warehouse
|
||||||
|
wproduct.save()
|
||||||
|
return Response()
|
||||||
|
|
||||||
class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
生产操作记录
|
生产操作记录
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
def ranstr(num):
|
||||||
|
salt = ''.join(random.sample(string.ascii_letters + string.digits, num))
|
||||||
|
return salt
|
||||||
|
ranstr(10)
|
||||||
Loading…
Reference in New Issue