feat: batchlog数据链
This commit is contained in:
parent
23ad849e36
commit
108116342e
|
@ -6,7 +6,7 @@ from apps.mtm.models import Material, Process
|
||||||
from apps.utils.tools import ranstr
|
from apps.utils.tools import ranstr
|
||||||
from apps.utils.thread import MyThread
|
from apps.utils.thread import MyThread
|
||||||
from apps.mtm.services_2 import cal_material_count
|
from apps.mtm.services_2 import cal_material_count
|
||||||
from apps.wpm.models import WMaterial
|
from apps.wpm.models import WMaterial, BatchSt, BatchLog
|
||||||
from apps.wpm.services_2 import get_alldata_with_batch_and_store
|
from apps.wpm.services_2 import get_alldata_with_batch_and_store
|
||||||
from apps.wpmw.models import Wpr
|
from apps.wpmw.models import Wpr
|
||||||
from apps.qm.models import Ftest, Defect
|
from apps.qm.models import Ftest, Defect
|
||||||
|
@ -236,10 +236,22 @@ class InmService:
|
||||||
|
|
||||||
if instance.type == MIO.MIO_TYPE_PUR_IN: # 需要更新订单
|
if instance.type == MIO.MIO_TYPE_PUR_IN: # 需要更新订单
|
||||||
# 这里还需要对入厂检验进行处理
|
# 这里还需要对入厂检验进行处理
|
||||||
|
if is_reverse:
|
||||||
|
BatchLog.clear(mio=instance)
|
||||||
|
else:
|
||||||
|
batches = [item.batch for item in MIOItem.objects.filter(mio=instance)]
|
||||||
|
for item in batches:
|
||||||
|
BatchSt.create(batch=item, mio=instance)
|
||||||
from apps.pum.services import PumService
|
from apps.pum.services import PumService
|
||||||
cls.update_mb(instance, in_or_out)
|
cls.update_mb(instance, in_or_out)
|
||||||
PumService.mio_purin(instance, is_reverse)
|
PumService.mio_purin(instance, is_reverse)
|
||||||
elif instance.type == MIO.MIO_TYPE_OTHER_IN:
|
elif instance.type == MIO.MIO_TYPE_OTHER_IN:
|
||||||
|
if is_reverse:
|
||||||
|
BatchLog.clear(mio=instance)
|
||||||
|
else:
|
||||||
|
batches = [item.batch for item in MIOItem.objects.filter(mio=instance)]
|
||||||
|
for item in batches:
|
||||||
|
BatchSt.create(batch=item, mio=instance)
|
||||||
cls.update_mb(instance, in_or_out)
|
cls.update_mb(instance, in_or_out)
|
||||||
elif instance.type == MIO.MIO_TYPE_DO_IN:
|
elif instance.type == MIO.MIO_TYPE_DO_IN:
|
||||||
mioitems = MIOItem.objects.filter(mio=instance)
|
mioitems = MIOItem.objects.filter(mio=instance)
|
||||||
|
@ -319,6 +331,7 @@ class InmService:
|
||||||
if xcount > 0:
|
if xcount > 0:
|
||||||
defect = defects_map[defect_id]
|
defect = defects_map[defect_id]
|
||||||
m_list.append((material, warehouse, i.batch, xcount, defect, i))
|
m_list.append((material, warehouse, i.batch, xcount, defect, i))
|
||||||
|
|
||||||
for material, warehouse, batch, change_count, defect, mioitem in m_list:
|
for material, warehouse, batch, change_count, defect, mioitem in m_list:
|
||||||
if change_count <= 0:
|
if change_count <= 0:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-03-21 06:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inm', '0029_alter_mioitem_batch'),
|
||||||
|
('wpm', '0100_auto_20250317_0955'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='batchst',
|
||||||
|
name='handover',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.handover', verbose_name='由何交接记录创建'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='batchst',
|
||||||
|
name='mio',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='inm.mio', verbose_name='由何出入库记录创建'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='batchst',
|
||||||
|
name='mlog',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.mlog', verbose_name='由何日志创建'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='batchst',
|
||||||
|
name='batch',
|
||||||
|
field=models.TextField(db_index=True, unique=True, verbose_name='批次号'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BatchLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, 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='删除标记')),
|
||||||
|
('source_b', models.TextField(db_index=True, verbose_name='来源批次')),
|
||||||
|
('target_b', models.TextField(db_index=True, verbose_name='目标批次')),
|
||||||
|
('relation_type', models.CharField(default='split', help_text='split/merge', max_length=20, verbose_name='关联类型')),
|
||||||
|
('handover', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.handover', verbose_name='关联交接记录')),
|
||||||
|
('mlog', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.mlog', verbose_name='关联生产记录')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -13,15 +13,6 @@ from rest_framework.exceptions import ParseError
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
class BatchSt(BaseModel):
|
|
||||||
"""
|
|
||||||
TN: 产品批次统计
|
|
||||||
"""
|
|
||||||
batch = models.TextField("批次号")
|
|
||||||
last_time = models.DateTimeField("最后操作时间", null=True, blank=True)
|
|
||||||
data = models.JSONField("数据", default=list, blank=True)
|
|
||||||
|
|
||||||
class SfLog(CommonADModel):
|
class SfLog(CommonADModel):
|
||||||
"""TN: 值班记录
|
"""TN: 值班记录
|
||||||
"""
|
"""
|
||||||
|
@ -581,3 +572,64 @@ class OtherLog(CommonADModel):
|
||||||
count_real = models.PositiveIntegerField('实际生产数', default=0)
|
count_real = models.PositiveIntegerField('实际生产数', default=0)
|
||||||
count_ok = models.PositiveIntegerField('合格数', default=0)
|
count_ok = models.PositiveIntegerField('合格数', default=0)
|
||||||
count_delivered = models.PositiveIntegerField('交付数', default=0)
|
count_delivered = models.PositiveIntegerField('交付数', default=0)
|
||||||
|
|
||||||
|
class BatchSt(BaseModel):
|
||||||
|
"""
|
||||||
|
TN: 产品批次统计
|
||||||
|
"""
|
||||||
|
batch = models.TextField("批次号", unique=True, db_index=True)
|
||||||
|
last_time = models.DateTimeField("最后操作时间", null=True, blank=True)
|
||||||
|
data = models.JSONField("数据", default=list, blank=True)
|
||||||
|
mio = models.ForeignKey("inm.mio", verbose_name="由何出入库记录创建", on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
handover = models.ForeignKey(Handover, verbose_name='由何交接记录创建', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
mlog = models.ForeignKey(Mlog, verbose_name='由何日志创建', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, batch:str, mio=None, handover=None, mlog=None):
|
||||||
|
"""
|
||||||
|
创建新的批次
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
BatchSt.objects.get(batch=batch)
|
||||||
|
raise ParseError(f"{batch} 该批号不可使用")
|
||||||
|
except BatchSt.DoesNotExist:
|
||||||
|
if mio is None and handover is None and mlog is None:
|
||||||
|
raise ParseError("mio or handover or mlog must be provided")
|
||||||
|
BatchSt.objects.create(batch=batch, mio=mio, handover=handover, mlog=mlog)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BatchLog(BaseModel):
|
||||||
|
"""
|
||||||
|
TN: 拆合批变更记录
|
||||||
|
"""
|
||||||
|
# source = models.ForeignKey(BatchSt, verbose_name='来源批次', on_delete=models.CASCADE, related_name="batch_p")
|
||||||
|
# target = models.ForeignKey(BatchSt, verbose_name='目标批次', on_delete=models.CASCADE, related_name="batch_c")
|
||||||
|
source_b = models.TextField("来源批次", db_index=True)
|
||||||
|
target_b = models.TextField("目标批次", db_index=True)
|
||||||
|
handover = models.ForeignKey(Handover, verbose_name='关联交接记录', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
mlog = models.ForeignKey(Mlog, verbose_name='关联生产记录', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
relation_type = models.CharField('关联类型', max_length=20, help_text="split/merge", default="split")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def g_create(cls, source_b:str, target_b:str=None, relation_type="split", handover=None, mlog=None):
|
||||||
|
"""
|
||||||
|
创建新的关系
|
||||||
|
"""
|
||||||
|
if relation_type not in ["split", "merge"]:
|
||||||
|
raise ParseError("relation_type must be split or merge")
|
||||||
|
if handover is None and mlog is None:
|
||||||
|
raise ParseError("handover or mlog must be provided")
|
||||||
|
cls.objects.get_or_create(source_b=source_b, target_b=target_b, relation_type=relation_type, handover=handover, mlog=mlog)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear(cls, handover=None, mlog=None, mio=None):
|
||||||
|
if handover:
|
||||||
|
cls.objects.filter(handover=handover).delete()
|
||||||
|
BatchSt.objects.filter(handover=handover).delete()
|
||||||
|
if mlog:
|
||||||
|
cls.objects.filter(mlog=mlog).delete()
|
||||||
|
BatchSt.objects.filter(mlog=mlog).delete()
|
||||||
|
if mio:
|
||||||
|
BatchSt.objects.filter(mio=mio).delete()
|
|
@ -11,7 +11,7 @@ from apps.system.models import User
|
||||||
from apps.pm.models import Mtask
|
from apps.pm.models import Mtask
|
||||||
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
|
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
|
||||||
|
|
||||||
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect
|
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect, BatchLog, BatchSt
|
||||||
from apps.mtm.services_2 import cal_material_count
|
from apps.mtm.services_2 import cal_material_count
|
||||||
from apps.wf.models import Ticket
|
from apps.wf.models import Ticket
|
||||||
from apps.utils.thread import MyThread
|
from apps.utils.thread import MyThread
|
||||||
|
@ -166,6 +166,17 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
||||||
is_fix = mlog.is_fix
|
is_fix = mlog.is_fix
|
||||||
m_ins_list = []
|
m_ins_list = []
|
||||||
m_ins_bl_list = []
|
m_ins_bl_list = []
|
||||||
|
|
||||||
|
# 建立关系链
|
||||||
|
m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
|
||||||
|
for item in m_outs:
|
||||||
|
if item.mlogb_from and item.batch != item.mlogb_from.batch:
|
||||||
|
BatchSt.create(batch=item.batch, mlog=mlog)
|
||||||
|
BatchLog.g_create(source_b=item.mlogb_from.batch, target_b=item.batch, mlog=mlog)
|
||||||
|
if item.mlogbw_from and item.batch != item.mlogbw_from.mlogb.batch:
|
||||||
|
BatchSt.create(batch=item.batch, mlog=mlog)
|
||||||
|
BatchLog.g_create(source_b=item.mlogbw_from.mlogb.batch, target_b=item.batch, mlog=mlog)
|
||||||
|
|
||||||
if material_in or is_fix: # 需要进行车间库存管理
|
if material_in or is_fix: # 需要进行车间库存管理
|
||||||
m_ins_list = []
|
m_ins_list = []
|
||||||
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
|
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
|
||||||
|
@ -542,6 +553,9 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
||||||
# 更新物料数量
|
# 更新物料数量
|
||||||
cal_material_count_from_mlog(mlog)
|
cal_material_count_from_mlog(mlog)
|
||||||
|
|
||||||
|
# 清除关系链
|
||||||
|
BatchLog.clear(mlog=mlog)
|
||||||
|
|
||||||
# 触发批次统计分析
|
# 触发批次统计分析
|
||||||
if mlog.batch:
|
if mlog.batch:
|
||||||
MyThread(target=get_alldata_with_batch_and_store, args=(mlog.batch,)).start()
|
MyThread(target=get_alldata_with_batch_and_store, args=(mlog.batch,)).start()
|
||||||
|
@ -702,8 +716,12 @@ def handover_submit(handover:Handover, user: User, now: Union[datetime.datetime,
|
||||||
# 合并为新批
|
# 合并为新批
|
||||||
if mtype == Handover.H_MERGE:
|
if mtype == Handover.H_MERGE:
|
||||||
batch = new_batch
|
batch = new_batch
|
||||||
|
BatchSt.create(batch=batch, handover=handover)
|
||||||
|
BatchLog.g_create(source_b=wm_from.batch, target_b=batch, handover=handover, relation_type="merge")
|
||||||
elif mtype == Handover.H_DIV:
|
elif mtype == Handover.H_DIV:
|
||||||
batch = handover_or_b.batch
|
batch = handover_or_b.batch
|
||||||
|
BatchSt.create(batch=batch, handover=handover)
|
||||||
|
BatchLog.g_create(source_b=handover.wm.batch, target_b=batch, handover=handover, relation_type="split")
|
||||||
else:
|
else:
|
||||||
batch = wm_from.batch
|
batch = wm_from.batch
|
||||||
batches.append(batch)
|
batches.append(batch)
|
||||||
|
@ -840,6 +858,7 @@ def handover_submit(handover:Handover, user: User, now: Union[datetime.datetime,
|
||||||
MyThread(target=get_alldata_with_batch_and_store, args=(batch,)).start()
|
MyThread(target=get_alldata_with_batch_and_store, args=(batch,)).start()
|
||||||
|
|
||||||
def handover_revert(handover:Handover):
|
def handover_revert(handover:Handover):
|
||||||
|
BatchLog.clear(handover=handover)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def mlog_submit_validate(ins: Mlog):
|
def mlog_submit_validate(ins: Mlog):
|
||||||
|
|
Loading…
Reference in New Issue