From d579a7358d90965298a5c57049da328fe759edc6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 1 Jul 2024 10:07:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=A0=B9=E6=8D=AE=E5=85=89=E8=8A=AF?= =?UTF-8?q?=E9=9C=80=E6=B1=82=E5=AF=B9wpm=E5=81=9A=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0031_process_into_wm_mgroup.py | 18 ++ apps/mtm/models.py | 2 + apps/wpm/filters.py | 11 +- .../wpm/migrations/0050_auto_20240701_0936.py | 81 +++++++++ apps/wpm/models.py | 28 ++- apps/wpm/serializers.py | 54 +++--- apps/wpm/services.py | 167 +++++++++++------- 7 files changed, 256 insertions(+), 105 deletions(-) create mode 100644 apps/mtm/migrations/0031_process_into_wm_mgroup.py create mode 100644 apps/wpm/migrations/0050_auto_20240701_0936.py diff --git a/apps/mtm/migrations/0031_process_into_wm_mgroup.py b/apps/mtm/migrations/0031_process_into_wm_mgroup.py new file mode 100644 index 00000000..29ed2299 --- /dev/null +++ b/apps/mtm/migrations/0031_process_into_wm_mgroup.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-06-28 10:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0030_route_hour_work'), + ] + + operations = [ + migrations.AddField( + model_name='process', + name='into_wm_mgroup', + field=models.BooleanField(default=False, verbose_name='交接到工段'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 43ebe4d5..377b2bec 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -8,12 +8,14 @@ class Process(CommonBModel): """ 工序 """ + name = models.CharField('工序名称', max_length=100) cate = models.CharField('大类', max_length=10, default='') sort = models.PositiveSmallIntegerField('排序', default=1) instruction = models.ForeignKey( File, verbose_name='指导书', on_delete=models.SET_NULL, null=True, blank=True) instruction_content = models.TextField('指导书内容', null=True, blank=True) + into_wm_mgroup = models.BooleanField('交接到工段', default=False) class Meta: verbose_name = '工序' diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 5d895dc3..83cce72a 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -1,6 +1,5 @@ from django_filters import rest_framework as filters from apps.wpm.models import SfLog, StLog, WMaterial, Mlog, Handover -['mgroup', 'shift', 'team', 'leader', 'team__belong_dept'] class SfLogFilter(filters.FilterSet): @@ -41,11 +40,12 @@ class WMaterialFilter(filters.FilterSet): "material__process__name": ["exact", "contains", "in"], "belong_dept": ["exact"], "belong_dept__name": ["exact", "in"], - "batch": ["exact", "in"], + "batch": ["exact", "contains"], + "mgroup": ["exact", "in"], + "mgroup__name": ["exact", "in"], "count": ["gte", "lte", "exact"] } - class MlogFilter(filters.FilterSet): class Meta: model = Mlog @@ -78,5 +78,8 @@ class HandoverFilter(filters.FilterSet): "material__type": ["exact", "in"], "submit_time": ["isnull"], "mlog": ["isnull"], - "send_mgroup": ["exact"] + "send_mgroup": ["exact"], + "send_mgroup__name": ["exact"], + "recive_mgroup": ["exact"], + "recive_mgroup__name": ["exact"], } diff --git a/apps/wpm/migrations/0050_auto_20240701_0936.py b/apps/wpm/migrations/0050_auto_20240701_0936.py new file mode 100644 index 00000000..9e356d2b --- /dev/null +++ b/apps/wpm/migrations/0050_auto_20240701_0936.py @@ -0,0 +1,81 @@ +# Generated by Django 3.2.12 on 2024-07-01 01:36 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0018_mtask_hour_work'), + ('mtm', '0031_process_into_wm_mgroup'), + ('system', '0004_auto_20240605_1011'), + ('wpm', '0049_auto_20240522_1447'), + ] + + operations = [ + migrations.AddField( + model_name='handover', + name='recive_mgroup', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='handover_recive_mgroup', to='mtm.mgroup', verbose_name='接收工段'), + ), + migrations.AddField( + model_name='mlog', + name='hour_work', + field=models.FloatField(blank=True, null=True, verbose_name='预计工时'), + ), + migrations.AddField( + model_name='mlog', + name='work_end_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='生产结束时间'), + ), + migrations.AddField( + model_name='mlog', + name='work_start_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='生产开始时间'), + ), + migrations.AddField( + model_name='mlogb', + name='batch', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='批次号'), + ), + migrations.AddField( + model_name='mlogb', + name='count_real', + field=models.PositiveIntegerField(default=0, verbose_name='实际生产数'), + ), + migrations.AddField( + model_name='mlogb', + name='count_use', + field=models.PositiveIntegerField(default=0, verbose_name='领用数量'), + ), + migrations.AddField( + model_name='mlogb', + name='material_in', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlogb_material_in', to='mtm.material', verbose_name='投入物料'), + ), + migrations.AddField( + model_name='mlogb', + name='mtask', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlogb_mtask', to='pm.mtask', verbose_name='关联任务'), + ), + migrations.AddField( + model_name='wmaterial', + name='mgroup', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.mgroup', verbose_name='所在工段'), + ), + migrations.AlterField( + model_name='mlog', + name='handle_date', + field=models.DateField(blank=True, null=True, verbose_name='操作日期'), + ), + migrations.AlterField( + model_name='mlogb', + name='material_out', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlogb_material_out', to='mtm.material', verbose_name='产物'), + ), + migrations.AlterUniqueTogether( + name='wmaterial', + unique_together={('material', 'batch', 'belong_dept', 'mgroup')}, + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 41901de7..d6ddb5a5 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -90,18 +90,23 @@ class WMaterial(CommonBDModel): """ material = models.ForeignKey( Material, verbose_name='物料', on_delete=models.CASCADE) + mgroup = models.ForeignKey(Mgroup, verbose_name='所在工段', on_delete=models.CASCADE, null=True, blank=True) batch = models.CharField('批次号', max_length=50) count = models.PositiveIntegerField('当前数量', default=0) count_eweight = models.FloatField('单数重量', default=0) class Meta: - unique_together = ('material', 'batch', 'belong_dept') - + unique_together = ('material', 'batch', 'belong_dept', 'mgroup') class Mlog(CommonADModel): """ 生产日志 """ + # 变成父级的字段 + work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True) + work_end_time = models.DateTimeField('生产结束时间', null=True, blank=True) + hour_work = models.FloatField('预计工时', null=True, blank=True) + mtask = models.ForeignKey( Mtask, verbose_name='关联任务', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_mtask') mgroup = models.ForeignKey( @@ -157,7 +162,7 @@ class Mlog(CommonADModel): count_n_thhs = models.PositiveIntegerField('退火后碎', default=0) count_n_qt = models.PositiveIntegerField('其他', default=0) - handle_date = models.DateField('操作日期') + handle_date = models.DateField('操作日期', null=True, blank=True) handle_user = models.ForeignKey( User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True) # 成型人 handle_user_2 = models.ForeignKey( @@ -168,7 +173,7 @@ class Mlog(CommonADModel): User, verbose_name='班长', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_handle_leader') note = models.TextField('备注', default='', blank=True) material_outs = models.ManyToManyField( - Material, verbose_name='多个产出', blank=True, through='wpm.mlogb', related_name='mlog_material_outs') + Material, verbose_name='多个产出', blank=True, through='wpm.mlogb', related_name='mlog_material_outs', through_fields=('mlog', 'material_out')) submit_time = models.DateTimeField('提交时间', null=True, blank=True) submit_user = models.ForeignKey( @@ -176,7 +181,7 @@ class Mlog(CommonADModel): @property def mlogb(self): - return Mlogb.objects.filter(mlog=self) + return Mlogb.objects.filter(mlog=self).exclude(material_out=None) @property def audit_ignore_fields(self): @@ -187,8 +192,15 @@ class Mlog(CommonADModel): class Mlogb(BaseModel): mlog = models.ForeignKey(Mlog, verbose_name='关联日志', on_delete=models.CASCADE, related_name='b_mlog') + batch = models.CharField('批次号', max_length=50, null=True, blank=True) + mtask = models.ForeignKey(Mtask, verbose_name='关联任务', + on_delete=models.CASCADE, related_name='mlogb_mtask', null=True, blank=True) + material_in = models.ForeignKey( + Material, verbose_name='投入物料', on_delete=models.CASCADE, related_name='mlogb_material_in', null=True, blank=True) material_out = models.ForeignKey( - Material, verbose_name='产物', on_delete=models.CASCADE, related_name='mlogb_material_out') + Material, verbose_name='产物', on_delete=models.CASCADE, related_name='mlogb_material_out', null=True, blank=True) + count_use = models.PositiveIntegerField('领用数量', default=0) + count_real = models.PositiveIntegerField('实际生产数', default=0) count_ok = models.PositiveIntegerField('合格数量', default=0) @@ -200,8 +212,7 @@ class Handover(CommonADModel): send_user = models.ForeignKey( User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user') send_mgroup = models.ForeignKey( - Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True - ) + Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True) send_dept = models.ForeignKey( Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept') batch = models.CharField('批次号', max_length=50) @@ -211,6 +222,7 @@ class Handover(CommonADModel): count_eweight = models.FloatField('单数重量', default=0) recive_dept = models.ForeignKey( Dept, verbose_name='接收部门', on_delete=models.CASCADE, related_name='handover_recive_dept') + recive_mgroup = models.ForeignKey(Mgroup, verbose_name='接收工段', on_delete=models.CASCADE, related_name='handover_recive_mgroup', null=True, blank=True) recive_user = models.ForeignKey( User, verbose_name='接收人', on_delete=models.CASCADE, related_name='handover_recive_user') wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL, diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 1688a6c9..de67c9a4 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -1,4 +1,4 @@ -from apps.utils.constants import EXCLUDE_FIELDS +from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers from rest_framework.exceptions import ValidationError, ParseError @@ -169,6 +169,7 @@ class WMaterialSerializer(CustomModelSerializer): material_ = MaterialSimpleSerializer(source='material', read_only=True) material_name = serializers.StringRelatedField( source='material', read_only=True) + mgroup_name = serializers.StringRelatedField(source='mgroup.name', read_only=True) belong_dept_name = serializers.CharField( source='belong_dept.name', read_only=True) @@ -187,7 +188,8 @@ class MlogbSerializer(CustomModelSerializer): model = Mlogb fields = ['id', 'material_out', 'count_ok', 'material_out_', 'material_out_name'] - + extra_kwargs = { + 'material_out': {'required': True, 'allow_null': False}} class MlogSerializer(CustomModelSerializer): belong_dept = serializers.CharField( @@ -244,38 +246,27 @@ class MlogSerializer(CustomModelSerializer): def create(self, validated_data): mtask: Mtask = validated_data.get('mtask', None) - # batch = validated_data['batch'] - # handle_date = validated_data['handle_date'] - # handle_user = validated_data.get('handle_user', None) if mtask: validated_data['mgroup'] = mtask.mgroup validated_data['material_in'] = mtask.material_in material_out = mtask.material_out validated_data['material_out'] = material_out - validated_data['handle_date'] = mtask.start_date - # if not WMaterial.objects.filter(batch=batch).exists(): - # raise ValidationError('批次号不存在') + validated_data['handle_date'] = mtask.end_date else: mgroup = validated_data['mgroup'] material_out = validated_data['material_out'] if not (mgroup and material_out): raise ValidationError('缺少工段或产物!') - # if handle_user: - # if Mlog.objects.filter(mtask=mtask, batch=batch, handle_date=handle_date, handle_user=handle_user).exists(): - # raise ValidationError('存在相同的日志记录') - # else: - # if Mlog.objects.filter(mtask=mtask, batch=batch, handle_date=handle_date).exists(): - # raise ValidationError('存在相同的日志记录') with transaction.atomic(): mlogb = validated_data.pop('mlogb', []) - instance = super().create(validated_data) + instance: Mlog = super().create(validated_data) brotherId_should_list = material_out.brothers if brotherId_should_list: if mlogb: for item in mlogb: if item['material_out'].id in brotherId_should_list: Mlogb.objects.create( - mlog=instance, material_out=item['material_out'], count_ok=item['count_ok']) + mlog=instance, batch=instance.batch, mtask=instance.mtask, material_out=item['material_out'], count_ok=item['count_ok']) else: raise ValidationError('缺少产出物信息') return instance @@ -290,7 +281,7 @@ class MlogSerializer(CustomModelSerializer): mlogb = validated_data.pop('mlogb', []) instance = super().update(instance, validated_data) if mlogb: - Mlogb.objects.filter(mlog=instance).update(count_ok=0) + Mlogb.objects.filter(mlog=instance, material_out__isnull=False).update(count_ok=0) for item in mlogb: Mlogb.objects.filter(mlog=instance, material_out=item['material_out']).update( count_ok=item['count_ok']) @@ -332,10 +323,10 @@ class DeptBatchSerializer(serializers.Serializer): class HandoverSerializer(CustomModelSerializer): - wm = serializers.PrimaryKeyRelatedField( - label='车间库存ID', queryset=WMaterial.objects.all()) - material = serializers.PrimaryKeyRelatedField( - required=True, label='物料ID', queryset=Material.objects.all()) + # wm = serializers.PrimaryKeyRelatedField( + # label='车间库存ID', queryset=WMaterial.objects.all()) + # material = serializers.PrimaryKeyRelatedField( + # required=True, label='物料ID', queryset=Material.objects.all()) send_user_name = serializers.CharField( source='send_user.name', read_only=True) recive_user_name = serializers.CharField( @@ -347,17 +338,26 @@ class HandoverSerializer(CustomModelSerializer): source='material', read_only=True) def validate(self, attrs): - if attrs.get('mlog', None): - attrs['send_mgroup'] = attrs['mlog'].mgroup - attrs['send_dept'] = attrs['mlog'].mgroup.belong_dept - elif attrs.get('wm', None): + material: Material = attrs['material'] + if material.process.into_wm_mgroup and 'recive_mgroup' not in attrs: + raise ValidationError('必须指定交接工段') + if attrs.get('wm', None): attrs['send_dept'] = attrs['wm'].belong_dept - return super().validate(attrs) + attrs['send_mgroup'] = attrs['wm'].mgroup + if attrs.get('recive_mgroup', None): + attrs['recive_dept'] = attrs['recive_mgroup'].belong_dept + if 'recive_dept' not in attrs and 'recive_mgroup' not in attrs: + raise ValidationError('交送车间和交送工段必须有一个') + return attrs class Meta: model = Handover fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + read_only_fields = EXCLUDE_FIELDS + ["batch", "material", "send_dept", "send_mgroup", "mlog"] + extra_kwargs = { + "wm": {"required": True}, + "recive_mgroup": {"required": False} + } class GenHandoverSerializer(serializers.Serializer): diff --git a/apps/wpm/services.py b/apps/wpm/services.py index b4fbc8cc..bcdeccc3 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -14,6 +14,7 @@ from apps.pm.models import Mtask from apps.mtm.models import Mgroup, Shift, Material, Route from .models import SfLog, SfLogExp, WMaterial, Mlog, Mlogb, Handover +from apps.mtm.models import Process def get_sflog(mgroup: Mgroup, happen_time: datetime): @@ -89,7 +90,7 @@ def do_out(mio: MIO): for item in mioitems: # 用于混料的原料不与车间库存交互 material = item.material - if material.type in [Material.MA_TYPE_MAINSO, Material.MA_TYPE_HELPSO]: + if material.type in [Material.MA_TYPE_MAINSO, Material.MA_TYPE_HELPSO]: # hard code continue action_list = [] mias = MIOItemA.objects.filter(mioitem=item) @@ -127,7 +128,7 @@ def do_in(mio: MIO): for item in mioitems: # 用于混料的原料不与车间库存交互 material = item.material - if material.type in [Material.MA_TYPE_MAINSO, Material.MA_TYPE_HELPSO]: + if material.type in [Material.MA_TYPE_MAINSO, Material.MA_TYPE_HELPSO]: # hard code continue action_list = [] mias = MIOItemA.objects.filter(mioitem=item) @@ -169,48 +170,65 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): now = timezone.now() if now.date() < mlog.handle_date: raise ParseError('不可提交未来的日志') - belong_dept = mlog.mgroup.belong_dept + + mgroup = mlog.mgroup + belong_dept = mgroup.belong_dept material_out = mlog.material_out material_in = mlog.material_in + if material_in: # 需要进行车间库存管理 - # 需要判断领用数是否合理 - material_has_qs = WMaterial.objects.filter( - batch=mlog.batch, material=material_in, belong_dept=belong_dept) - count_x = material_has_qs.count() - if count_x == 1: - material_has = material_has_qs.first() - elif count_x == 0: - raise ParseError( - f'{str(material_in)}-{mlog.batch}-批次库存不存在!') + into_wm_mgroup = material_in.process.into_wm_mgroup + m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False) + if m_ins.exists(): + m_ins_list = [(mi.material_in, mi.batch, mi.count_use) for mi in m_ins.all()] else: - raise ParseError( - f'{str(material_in)}-{mlog.batch}-存在多个相同批次!') - if mlog.count_use > material_has.count: - raise ParseError( - f'{str(material_in)}-{mlog.batch}-该批次车间库存不足!') - else: - material_has.count = material_has.count - mlog.count_use - if material_has.count == 0: - material_has.delete() + m_ins_list = [(material_in, mlog.batch, mlog.count_use)] + for mi in m_ins_list: + mi_ma, mi_batch, mi_count = mi + # 需要判断领用数是否合理 + lookup = {'batch': mi_batch, 'material': mi_ma, 'mgroup': None} + if into_wm_mgroup: + lookup['mgroup'] = mgroup else: - material_has.save() + lookup['belong_dept'] = belong_dept + material_has_qs = WMaterial.objects.filter(**lookup) + count_x = material_has_qs.count() + if count_x == 1: + material_has = material_has_qs.first() + elif count_x == 0: + raise ParseError( + f'{str(mi_ma)}-{mi_batch}-批次库存不存在!') + else: + raise ParseError( + f'{str(mi_ma)}-{mi_batch}-存在多个相同批次!') + if mi_count > material_has.count: + raise ParseError( + f'{str(mi_ma)}-{mi_batch}-该批次车间库存不足!') + else: + material_has.count = material_has.count - mi_count + if material_has.count == 0: + material_has.delete() + else: + material_has.save() if material_out: # 需要入车间库存 - # 有多个产物的情况 - if material_out.brothers and Mlogb.objects.filter(mlog=mlog).exists(): - for item in Mlogb.objects.filter(mlog=mlog): - wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=item.material_out, belong_dept=belong_dept, defaults={ - 'batch': mlog.batch, 'material': item.material_out, 'belong_dept': belong_dept - }) - wmaterial.count = wmaterial.count + item.count_ok - if hasattr(item, 'count_real_eweight'): - wmaterial.count_eweight = item.count_real_eweight - wmaterial.save() + into_wm_mgroup = material_out.process.into_wm_mgroup + m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) + if m_outs.exists(): + m_outs_list = [(mo.material, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight) for mo in m_outs.all()] else: - wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=material_out, belong_dept=belong_dept, defaults={ - 'batch': mlog.batch, 'material': material_out, 'belong_dept': belong_dept - }) - wmaterial.count = wmaterial.count + mlog.count_ok - wmaterial.count_eweight = mlog.count_real_eweight + m_outs_list = [(material_out, mlog.batch, mlog.count_ok, mlog.count_real_eweight)] + + for mo in m_outs_list: + mo_ma, mo_batch, mo_count, mo_count_eweight = mo + lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None} + if into_wm_mgroup: + lookup['mgroup'] = mgroup + else: + lookup['belong_dept'] = belong_dept + if mo_count > 0: + wmaterial, _ = WMaterial.objects.get_or_create(**lookup, defaults=lookup) + wmaterial.count = wmaterial.count + mo_count + wmaterial.count_eweight = mo_count_eweight wmaterial.save() mlog.submit_time = now mlog.submit_user = user @@ -224,34 +242,48 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): return if now is None: now = timezone.now() - belong_dept = mlog.mgroup.belong_dept + + mgroup = mlog.mgroup + belong_dept = mgroup.belong_dept material_out = mlog.material_out material_in = mlog.material_in if material_in: # 领用数退回 - wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=material_in, belong_dept=belong_dept, defaults={ - 'batch': mlog.batch, 'material': material_in, 'belong_dept': belong_dept}) - wmaterial.count = wmaterial.count + mlog.count_use - wmaterial.save() + into_wm_mgroup = material_in.process.into_wm_mgroup + m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False) + if m_ins.exists(): + m_ins_list = [(mi.material_in, mi.batch, mi.count_use) for mi in m_ins.all()] + else: + m_ins_list = [(material_in, mlog.batch, mlog.count_use)] + for mi in m_ins_list: + mi_ma, mi_batch, mi_count = mi + lookup = {'batch': mi_batch, 'material': mi_ma, 'mgroup': None} + if into_wm_mgroup: + lookup['mgroup'] = mgroup + else: + lookup['belong_dept'] = belong_dept + + wmaterial, _ = WMaterial.objects.get_or_create(**lookup, defaults=lookup) + wmaterial.count = wmaterial.count + mi_count + wmaterial.save() if material_out: # 产物退回 # 有多个产物的情况 - if material_out.brothers and Mlogb.objects.filter(mlog=mlog).exists(): - for item in Mlogb.objects.filter(mlog=mlog): - wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=item.material_out, belong_dept=belong_dept, defaults={ - 'batch': mlog.batch, 'material': item.material_out, 'belong_dept': belong_dept - }) - wmaterial.count = wmaterial.count - item.count_ok - if wmaterial.count < 0: - raise ParseError('车间库存不足, 产物无法回退') - elif wmaterial.count == 0: - wmaterial.delete() - else: - wmaterial.save() + into_wm_mgroup = material_out.process.into_wm_mgroup + m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) + if m_outs.exists(): + m_outs_list = [(mo.material, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight) for mo in m_outs.all()] else: - wmaterial, _ = WMaterial.objects.get_or_create(batch=mlog.batch, material=material_out, belong_dept=belong_dept, defaults={ - 'batch': mlog.batch, 'material': material_out, 'belong_dept': belong_dept - }) - wmaterial.count = wmaterial.count - mlog.count_ok + m_outs_list = [(material_out, mlog.batch, mlog.count_ok, mlog.count_real_eweight)] + + for mo in m_outs_list: + mo_ma, mo_batch, mo_count, _ = mo + lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None} + if into_wm_mgroup: + lookup['mgroup'] = mgroup + else: + lookup['belong_dept'] = belong_dept + wmaterial, _ = WMaterial.objects.get_or_create(**lookup, defaults=lookup) + wmaterial.count = wmaterial.count - mo_count if wmaterial.count < 0: raise ParseError('车间库存不足, 产物无法回退') elif wmaterial.count == 0: @@ -296,11 +328,9 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime wm_from_need_delete = False material = handover.material batch = handover.batch - try: - wm_from = WMaterial.objects.get( - material=material, batch=batch, belong_dept=handover.send_dept) - except Exception as e: - raise ParseError(f'找不到车间库存:{e}') + wm_from = handover.wm + if wm_from is None: + raise ParseError('找不到车间库存') if '混料' in material.name: # hard code need_add = False count_x = wm_from.count - handover.count @@ -312,9 +342,14 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime wm_from.count = count_x wm_from.save() if need_add: - wm_to, _ = WMaterial.objects.get_or_create(batch=batch, material=material, belong_dept=handover.recive_dept, defaults={ - 'batch': batch, 'material': material, 'belong_dept': handover.recive_dept - }) + if handover.recive_mgroup: + wm_to, _ = WMaterial.objects.get_or_create(batch=batch, material=material, mgroup=handover.recive_mgroup, defaults={ + 'batch': batch, 'material': material, 'mgroup': handover.recive_mgroup, 'belong_dept': handover.recive_dept + }) + else: + wm_to, _ = WMaterial.objects.get_or_create(batch=batch, material=material, belong_dept=handover.recive_dept, defaults={ + 'batch': batch, 'material': material, 'belong_dept': handover.recive_dept + }) wm_to.count = wm_to.count + handover.count wm_to.count_eweight = handover.count_eweight wm_to.save()