feat: 支持不合格品处理/添加不合格品存储字段

This commit is contained in:
caoqianming 2024-07-17 16:58:28 +08:00
parent 83ec822f9d
commit c058fe9338
5 changed files with 93 additions and 45 deletions

View File

@ -0,0 +1,44 @@
# Generated by Django 3.2.12 on 2024-07-17 08:53
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0034_route_batch_bind'),
('wpm', '0054_mlog_fill_way'),
]
operations = [
migrations.AddField(
model_name='mlog',
name='wm_in',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mlog_wm_in', to='wpm.wmaterial', verbose_name='投入物料所在库存'),
),
migrations.AddField(
model_name='mlogb',
name='wm_in',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wpm.wmaterial', verbose_name='投入物料所在库存'),
),
migrations.AddField(
model_name='wmaterial',
name='material_origin',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wm_mo', to='mtm.material', verbose_name='原始物料'),
),
migrations.AddField(
model_name='wmaterial',
name='notok_sign',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='不合格标记'),
),
migrations.AlterField(
model_name='wmaterial',
name='material',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wm_m', to='mtm.material', verbose_name='物料'),
),
migrations.AlterUniqueTogether(
name='wmaterial',
unique_together=set(),
),
]

View File

@ -89,14 +89,14 @@ class WMaterial(CommonBDModel):
belong_dept是所在车间
"""
material = models.ForeignKey(
Material, verbose_name='物料', on_delete=models.CASCADE)
Material, verbose_name='物料', on_delete=models.CASCADE, related_name='wm_m')
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)
notok_sign = models.CharField('不合格标记', max_length=10, null=True, blank=True)
material_origin = models.ForeignKey(Material, verbose_name='原始物料', on_delete=models.SET_NULL, null=True, blank=True, related_name='wm_mo')
class Meta:
unique_together = ('material', 'batch', 'belong_dept', 'mgroup')
class Mlog(CommonADModel):
"""
@ -115,6 +115,7 @@ class Mlog(CommonADModel):
Mtask, verbose_name='关联任务', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_mtask')
mgroup = models.ForeignKey(
Mgroup, verbose_name='工段', on_delete=models.CASCADE, null=True, blank=True)
wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_wm_in')
material_in = models.ForeignKey(
Material, verbose_name='消耗物', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_material_in')
material_out = models.ForeignKey(
@ -133,10 +134,10 @@ class Mlog(CommonADModel):
count_use = models.PositiveIntegerField('领用数', default=0)
count_real = models.PositiveIntegerField('实际生产数', default=0)
count_real_eweight = models.FloatField('单数重量', default=0)
count_break = models.PositiveIntegerField('加工碎料数', default=0)
count_ok = models.PositiveIntegerField('合格数', default=0)
count_notok = models.PositiveIntegerField('不合格数', default=0)
count_break = models.PositiveIntegerField('加工碎料数', default=0)
count_break_t = models.PositiveIntegerField('检验碎料数', default=0)
count_n_zw = models.PositiveIntegerField('炸纹', default=0)
@ -210,12 +211,14 @@ class Mlogb(BaseModel):
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)
wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, 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', null=True, blank=True)
count_use = models.PositiveIntegerField('领用数量', default=0)
count_break = models.PositiveIntegerField('加工破碎数', default=0)
count_break_t = models.PositiveIntegerField('检验碎料数', default=0)
count_real = models.PositiveIntegerField('实际生产数', default=0)
count_ok = models.PositiveIntegerField('合格数量', default=0)

View File

@ -361,19 +361,21 @@ class MlogChangeSerializer(CustomModelSerializer):
class MlogbInSerializer(CustomModelSerializer):
class Meta:
model = Mlogb
fields = ['id', 'mlog', 'mtask', 'batch', 'count_use']
extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'batch': {'required': True, 'allow_blank': False}}
fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use']
extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}}
def validate(self, attrs):
mlog: Mlog = attrs['mlog']
mtask: Mtask = attrs['mtask']
wm_in: WMaterial = attrs['wm_in']
if mlog.route != mtask.route:
raise ValidationError('工序不匹配')
route = mlog.route
attrs['material_in'] = wm_in.material_in
attrs['batch'] = wm_in.batch
if route.batch_bind:
if not Mlogb.objects.filter(mtask__utask=mtask.utask, mlog__submit_time__isnull=False, material_out__isnull=False, batch=attrs['batch']).exists():
raise ValidationError('批次号不匹配')
attrs['material_in'] = mlog.material_in
return attrs
def create(self, validated_data):

View File

@ -146,9 +146,9 @@ def do_in(mio: MIO):
for al in action_list:
xmaterial, xbatch, xcount = al
# 优先从车间库存里拿
wm_qs = WMaterial.objects.filter(batch=xbatch, material=xmaterial, belong_dept=belong_dept, mgroup=None)
wm_qs = WMaterial.objects.filter(batch=xbatch, material=xmaterial, belong_dept=belong_dept, mgroup=None, notok_sign=None)
if not wm_qs.exists():
wm_qs = WMaterial.objects.filter(batch=xbatch, material=xmaterial, belong_dept=belong_dept, mgroup__isnull=False)
wm_qs = WMaterial.objects.filter(batch=xbatch, material=xmaterial, belong_dept=belong_dept, mgroup__isnull=False, notok_sign=None)
count_x = wm_qs.count()
if count_x == 1:
@ -161,12 +161,10 @@ def do_in(mio: MIO):
f'{str(xmaterial)}-{xbatch}-存在多个相同批次!')
new_count = wm.count - xcount
if new_count > 0:
if new_count >= 0:
wm.count = new_count
wm.update_by = do_user
wm.save()
elif new_count == 0:
wm.delete()
else:
raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不足')
@ -189,16 +187,19 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if material_in: # 需要进行车间库存管理
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()]
m_ins_list = [(mi.material_in, mi.batch, mi.count_use, mi.wm_in) for mi in m_ins.all()]
else:
m_ins_list = [(material_in, mlog.batch, mlog.count_use)]
m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)]
for mi in m_ins_list:
mi_ma, mi_batch, mi_count = mi
mi_ma, mi_batch, mi_count, mi_wm_in = mi
# 需要判断领用数是否合理
# 优先使用工段库存
wm_qs = WMaterial.objects.filter(batch=mi_batch, material=mi_ma, mgroup=mgroup)
if not wm_qs.exists():
wm_qs = WMaterial.objects.filter(batch=mi_batch, material=mi_ma, belong_dept=belong_dept, mgroup=None)
if mi_wm_in:
wm_qs = WMaterial.objects.filter(id=mi_wm_in.id)
else:
wm_qs = WMaterial.objects.filter(batch=mi_batch, material=mi_ma, mgroup=mgroup, notok_sign=None)
if not wm_qs.exists():
wm_qs = WMaterial.objects.filter(batch=mi_batch, material=mi_ma, belong_dept=belong_dept, mgroup=None, notok_sign=None)
count_x = wm_qs.count()
if count_x == 1:
@ -215,11 +216,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
f'{str(mi_ma)}-{mi_batch}-该批次车间库存不足!')
else:
wm.count = wm.count - mi_count
if wm.count == 0:
wm.delete()
else:
wm.update_by = user
wm.save()
wm.update_by = user
wm.save()
if material_out: # 需要入车间库存
into_wm_mgroup = material_out.process.into_wm_mgroup if material_out.process else False
m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
@ -230,7 +228,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
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}
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': None}
if into_wm_mgroup:
lookup['mgroup'] = mgroup
else:
@ -263,21 +261,28 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
into_wm_mgroup = material_in.process.into_wm_mgroup if material_in.process else False
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()]
m_ins_list = [(mi.material_in, mi.batch, mi.count_use, mi.wm_in) for mi in m_ins.all()]
else:
m_ins_list = [(material_in, mlog.batch, mlog.count_use)]
m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)]
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
mi_ma, mi_batch, mi_count, mi_wm_in = mi
if mi_wm_in:
mi_wm_in.count = mi_wm_in.count + mi_count
mi_wm_in.update_by = user
mi_wm_in.save()
else:
lookup['belong_dept'] = belong_dept
lookup = {'batch': mi_batch, 'material': mi_ma, 'mgroup': None, 'notok_sign': None}
if mi_wm_in:
lookup['id']
if into_wm_mgroup:
lookup['mgroup'] = mgroup
else:
lookup['belong_dept'] = belong_dept
wm, _ = WMaterial.objects.get_or_create(**lookup, defaults=lookup)
wm.count = wm.count + mi_count
wm.update_by = user
wm.save()
wm, _ = WMaterial.objects.get_or_create(**lookup, defaults=lookup)
wm.count = wm.count + mi_count
wm.update_by = user
wm.save()
if material_out: # 产物退回
# 有多个产物的情况
into_wm_mgroup = material_out.process.into_wm_mgroup if material_out.process else False
@ -289,7 +294,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
for mo in m_outs_list:
mo_ma, mo_batch, mo_count, _ = mo
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None}
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': None}
if into_wm_mgroup:
lookup['mgroup'] = mgroup
else:
@ -307,9 +312,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
wm.count = wm.count - mo_count
if wm.count < 0:
raise ParseError('车间库存不足, 产物无法回退')
elif wm.count == 0:
wm.delete()
else:
elif wm.count >= 0:
wm.update_by = user
wm.save()
mlog.submit_time = None
@ -465,8 +468,6 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime
count_x = wm_from.count - handover.count
if count_x < 0:
raise ParseError('车间库存不足!')
elif count_x == 0:
wm_from_need_delete = True
else:
wm_from.count = count_x
wm_from.save()
@ -485,5 +486,3 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime
handover.submit_user = user
handover.submit_time = now
handover.save()
if wm_from_need_delete:
wm_from.delete()

View File

@ -110,7 +110,7 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet):
车间库存
"""
perms_map = {'get': '*'}
queryset = WMaterial.objects.all()
queryset = WMaterial.objects.filter(count__gt=0)
serializer_class = WMaterialSerializer
select_related_fields = ['material', 'belong_dept', 'material__process']
search_fields = ['material__name',
@ -441,7 +441,7 @@ class MlogbViewSet(ListModelMixin, CustomGenericViewSet):
class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, CustomGenericViewSet):
perms_map = {'post': 'mlog.update', 'delete': 'mlog.update'}
perms_map = {'post': 'mlog.update', 'delete': 'mlog.update', 'put': 'mlog.update'}
queryset = Mlogb.objects.filter(material_in__isnull=False)
serializer_class = MlogbInSerializer
update_serializer_class = MlogbInUpdateSerializer