下料清单初步完成

This commit is contained in:
caoqianming 2022-01-04 16:43:32 +08:00
parent 8f1746f8a6
commit 4538c32834
5 changed files with 116 additions and 41 deletions

View File

@ -0,0 +1,59 @@
# Generated by Django 3.2.9 on 2022-01-04 08:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0042_alter_recordformfield_field_type'),
('wpm', '0043_auto_20211231_1130'),
]
operations = [
migrations.RemoveField(
model_name='operation',
name='use_scrap',
),
migrations.AddField(
model_name='operationmaterial',
name='from_batch',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='源批次'),
),
migrations.AddField(
model_name='operationmaterial',
name='from_material',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='om_fmaterial', to='mtm.material', verbose_name='源物料'),
),
migrations.AddField(
model_name='operationmaterial',
name='use_scrap',
field=models.BooleanField(default=False, verbose_name='是否使用的边角料'),
),
migrations.AddField(
model_name='operationwproduct',
name='ng_sign',
field=models.PositiveSmallIntegerField(blank=True, choices=[(10, '返工'), (20, '返修'), (30, '报废'), (40, '让步接收'), (50, '偏离许可'), (60, '降级使用'), (70, '退回供方'), (80, '召回')], null=True, verbose_name='当时的不合格标记'),
),
migrations.AddField(
model_name='wproduct',
name='coperation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wp_coperation', to='wpm.operation', verbose_name='创建所关联操作'),
),
migrations.AddField(
model_name='wproductflow',
name='coperation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wpf_coperation', to='wpm.operation', verbose_name='创建所关联操作'),
),
migrations.AlterField(
model_name='operationmaterial',
name='material',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='om_material', to='mtm.material', verbose_name='可能产出的产品'),
),
migrations.AlterField(
model_name='wproductflow',
name='operation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wpf_operation', to='wpm.operation', verbose_name='当前操作'),
),
]

View File

@ -96,6 +96,8 @@ class WProduct(CommonAModel):
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_coperation')
test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_test')
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
@ -144,7 +146,9 @@ class WproductFlow(CommonAModel):
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
on_delete=models.SET_NULL, null=True, blank=True)
on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_operation')
coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_coperation')
test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
on_delete=models.SET_NULL, null=True, blank=True)
ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
@ -183,7 +187,6 @@ class Operation(CommonADModel):
生产操作
"""
step = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True)
use_scrap = models.BooleanField('是否使用的边角料', default=False)
remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
is_submited = models.BooleanField('是否提交', default=False)
@ -196,7 +199,7 @@ class OperationWproduct(BaseModel):
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='ow_subplan')
ng_sign = models.PositiveSmallIntegerField('当时的不合格标记', choices= WProduct.ng_choices, null=True, blank=True)
class Meta:
unique_together = (
('operation','wproduct')
@ -209,7 +212,8 @@ class OperationMaterial(BaseModel):
type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True)
material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE,
null=True, blank=True, related_name='om_material')
count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True)
wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
@ -217,8 +221,12 @@ class OperationMaterial(BaseModel):
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, null=True, blank=True)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
use_scrap = models.BooleanField('是否使用的边角料', default=False)
#以下为冷加工下料清单所用字段
from_material = models.ForeignKey(Material, verbose_name='源物料', on_delete=models.CASCADE,
null=True, blank=True, related_name='om_fmaterial')
from_batch = models.CharField('源批次', max_length=100, null=True, blank=True)
count_cut = models.PositiveIntegerField('切裁片数', default=0)
count_real = models.PositiveIntegerField('生产片数', default=0)
count_ok = models.PositiveIntegerField('成品数量', default=0)
@ -226,6 +234,7 @@ class OperationMaterial(BaseModel):
count_podian = models.PositiveIntegerField('破点甩片', default=0)
count_hua = models.PositiveIntegerField('划伤甩片', default=0)
count_other = models.PositiveIntegerField('其他甩片', default=0)
class Meta:
unique_together = (
('operation','material', 'batch')

View File

@ -350,7 +350,7 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
wmaterial = serializers.PrimaryKeyRelatedField(required=True, queryset=WMaterial.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'wmaterial', 'count']
fields = ['operation', 'wmaterial', 'count', 'use_scrap']
def validate(self, attrs):
if attrs['count'] <=0:
@ -376,7 +376,7 @@ class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'subproduction_progress', 'count']
fields = ['operation', 'subproduction_progress', 'count', 'use_scrap']
def create(self, validated_data):
subproduction_progress = validated_data['subproduction_progress']
@ -448,7 +448,7 @@ class WproductTicketListSerializer(serializers.ModelSerializer):
class CuttingListSerializer(serializers.ModelSerializer):
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
material_ = MaterialSimpleSerializer(source='material', read_only=True)
from_material_ = MaterialSimpleSerializer(source='from_material', read_only=True)
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
class Meta:
model = OperationMaterial

View File

@ -154,28 +154,23 @@ class WpmServies(object):
"""
inputs = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
outputs = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
for i in inputs:
sp = i.subproduction_plan
i.count_cut = outputs.filter(subproduction_plan=sp).first().count
i.count_real = sp.count_real
i.count_ok = sp.count_ok
wpfs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True)
i.count_qipao = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_QIPAO).count()
i.count_podian = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_PODIAN).count()
i.count_hua = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_HUA).count()
i.count_other = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_OTHER).count()
i.is_cutting = True
i.save()
@classmethod
def update_cutting_list_with_sp(cls, sp:SubProductionPlan):
"""
根据子计划更新下料清单
"""
wpfs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True)
for i in OperationMaterial.objects.filter(subproduction_plan=sp, is_cutting=True):
i.count_real = sp.count_real
i.count_ok = sp.count_ok
for i in outputs:
if i.use_scrap: # 如果使用了边角料
i.count_cut = 0
i.from_material = SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
subproduction__subplan_subprod=i.subproduction_plan).first().material
else:
input_q = inputs.filter(subproduction_plan=i.subproduction_plan) # 同计划的消耗
i.from_material = input_q.first().matrial
count_cut = 0
from_batch = ''
for m in input_q:
count_cut = count_cut + m.count
from_batch = from_batch + ';' + m.batch if m.batch else from_batch
wpfs = WproductFlow.objects.filter(subproduction_plan=i.subproduction_plan,
is_lastlog=True, coperation=op)# 筛选本次操作下子计划的产品日志
i.count_real = wpfs.count()
i.count_ok = wpfs.exclude(scrap_reason=None).count()
i.count_qipao = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_QIPAO).count()
i.count_podian = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_PODIAN).count()
i.count_hua = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_HUA).count()

View File

@ -386,7 +386,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
obj.save()
WpmServies.add_wproduct_flow_log(obj, 'scrap')
if obj.step.process.id == 1: #如果是冷加工
WpmServies.update_cutting_list_with_sp(obj.subproduction_plan)
WpmServies.update_cutting_list_with_operation(obj.coperation)
return Response()
# @action(methods=['get'], detail=False, perms_map={'get':'*'})
@ -510,12 +510,13 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
owp['number'] = wpd.number
owp['material'] = wpd.material
owp['subproduction_plan'] = wpd.subproduction_plan
owp['ng_sign'] = wpd.ng_sign
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
else:
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
# 查询需要填写的自定义表格
forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO)
forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO, enabled=True)
for i in forms:
opr = OperationRecord()
opr.operation = op
@ -555,11 +556,22 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
step = op.step
if op.is_submited:
raise exceptions.APIException('该操作已提交')
# 校验消耗产出是否正确填写
omis = OperationMaterial.objects.filter(operation=op,
type=SubprodctionMaterial.SUB_MA_TYPE_IN)
sps_omi_l = omis.values_list('subproduction_plan', flat=True)
omos = OperationMaterial.objects.filter(operation=op,
type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
sps_omo_l = omos.filter(use_scrap=False).values_list('subproduction_plan', flat=True)
if set(list(sps_omi_l)) == set(list(sps_omo_l)):
pass
else:
raise exceptions.APIException('消耗与产出不一致')
# 检查自定义表单填写
if OperationRecord.objects.filter(operation=op, is_filled=False).exists():
raise exceptions.APIException('存在自定义表单未填写')
# 更新物料消耗进度
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_IN):
for i in omis:
# 更新车间物料
i_wmat = i.wmaterial
i_wmat.count = i_wmat.count- i.count
@ -570,7 +582,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
spp.count_real = spp.count_real + i.count
spp.save()
# 更新产出
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT):
for i in omos:
if not i.subproduction_progress.is_main:
# 更新车间物料产出情况
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i.subproduction_plan, material=i.material)
@ -607,24 +619,23 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
elif step.type == Step.STEP_TYPE_DIV:
# 更新物料产出情况
outputs = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
if not outputs.exists():
if not omos.exists():
raise exceptions.APIException('请选择物料产出')
for i in outputs:
for i in omos:
if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='',
subproduction_plan=i.subproduction_plan, create_by=request.user)
subproduction_plan=i.subproduction_plan,
create_by=request.user, coperation=op)
for x in range(i.count):
ins = WProduct.objects.create(**wpr)
# 添加日志
WpmServies.add_wproduct_flow_log(ins, 'operation_submit')
WpmServies.add_wproduct_flow_log(ins, 'wproduct_create')
# 更新进度
WpmServies.update_subproduction_progress_main(sp=i.subproduction_plan)
elif step.type == Step.STEP_TYPE_COMB:
oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT,
subproduction_progress__is_main=True)
oms_w = omos.filter(subproduction_progress__is_main=True)
if len(oms_w) == 1:
oms_w = oms_w[0]
# 校验单片数量是否正确, 暂时未写
@ -640,8 +651,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
# 更新子计划进度
WpmServies.update_subproduction_progress_main(sp=oms_w.subproduction_plan)
wproduct.create_by = request.user
wproduct.coperation = op
wproduct.save()
WpmServies.add_wproduct_flow_log(wproduct, 'operation_submit')
WpmServies.add_wproduct_flow_log(wproduct, 'wproduct_create')
# 隐藏原半成品
wps = WProduct.objects.filter(ow_wproduct__operation = op)
wps.update(is_hidden=True, child=wproduct, update_by=request.user, update_time=timezone.now())