feat: 返修逻辑完成
This commit is contained in:
parent
553fbcc826
commit
2663f20953
|
@ -8,14 +8,14 @@ class Process(CommonBModel):
|
|||
工序
|
||||
"""
|
||||
PRO_PROD = 10
|
||||
RPO_TEST = 20
|
||||
PRO_TEST = 20
|
||||
|
||||
|
||||
PRO_NORMAL = 10
|
||||
PRO_DIV = 20
|
||||
PRO_MERGE = 30
|
||||
name = models.CharField('工序名称', max_length=100)
|
||||
type = models.PositiveSmallIntegerField("工序类型", default=PRO_PROD, choices=((PRO_PROD, '生产工序'), (RPO_TEST, '检验工序')))
|
||||
type = models.PositiveSmallIntegerField("工序类型", default=PRO_PROD, choices=((PRO_PROD, '生产工序'), (PRO_TEST, '检验工序')))
|
||||
mtype = models.PositiveSmallIntegerField("工序生产类型", default=PRO_NORMAL, choices=((PRO_NORMAL, '常规'), (PRO_DIV, '切分'), (PRO_MERGE, '合并')))
|
||||
cate = models.CharField('大类', max_length=10, default='')
|
||||
sort = models.PositiveSmallIntegerField('排序', default=1)
|
||||
|
|
|
@ -107,6 +107,7 @@ class WMaterial(CommonBDModel):
|
|||
WM_OK = 10
|
||||
WM_NOTOK = 20
|
||||
WM_REPAIR = 30
|
||||
WM_REPAIRED = 34
|
||||
WM_TEST = 40
|
||||
WM_SCRAP = 50
|
||||
state = models.PositiveSmallIntegerField('状态', default=10, choices=WmStateOption.choices)
|
||||
|
|
|
@ -486,25 +486,33 @@ class MlogInitSerializer(CustomModelSerializer):
|
|||
model = Mlog
|
||||
fields = ['id',
|
||||
'work_start_time', 'work_end_time', 'mgroup', 'reminder_interval_list',
|
||||
'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier', 'test_file', 'test_user', 'test_time', 'oinfo_json']
|
||||
'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier', 'test_file', 'test_user', 'test_time', 'oinfo_json', 'is_fix']
|
||||
extra_kwargs = {
|
||||
'work_start_time': {'required': True},
|
||||
'route':{'required': True},
|
||||
'route':{'required': False},
|
||||
'mgroup': {'required': True},
|
||||
'mtype': {'required': True}
|
||||
}
|
||||
|
||||
def validate(self, attrs):
|
||||
mtype = attrs['mtype']
|
||||
route: Route = attrs['route']
|
||||
route: Route = attrs.get('route', None)
|
||||
mgroup: Mgroup = attrs['mgroup']
|
||||
if route is None:
|
||||
is_fix:bool = attrs.get('is_fix', False)
|
||||
if is_fix:
|
||||
attrs["route"] = None
|
||||
elif route is None:
|
||||
raise ParseError('缺少工艺路线')
|
||||
if route.process != mgroup.process:
|
||||
if route and route.process != mgroup.process:
|
||||
raise ParseError('工序不匹配')
|
||||
attrs['hour_work'] = route.hour_work
|
||||
attrs['material_in'] = route.material_in
|
||||
attrs['material_out'] = route.material_out
|
||||
if is_fix:
|
||||
attrs['hour_work'] = None
|
||||
attrs['material_in'] = None
|
||||
attrs['material_out'] = None
|
||||
if route:
|
||||
attrs['hour_work'] = route.hour_work
|
||||
attrs['material_in'] = route.material_in
|
||||
attrs['material_out'] = route.material_out
|
||||
attrs['fill_way'] = Mlog.MLOG_23
|
||||
if mtype == Mlog.MTYPE_OUT:
|
||||
supplier = attrs.get('supplier', None)
|
||||
|
@ -535,14 +543,16 @@ class MlogbInSerializer(CustomModelSerializer):
|
|||
|
||||
def validate(self, attrs):
|
||||
mlog: Mlog = attrs['mlog']
|
||||
is_fix = mlog.is_fix
|
||||
mtask: Mtask = attrs.get("mtask", None)
|
||||
if mtask and mtask.state != Mtask.MTASK_ASSGINED:
|
||||
raise ParseError('该任务非下达中不可选择')
|
||||
wm_in: WMaterial = attrs['wm_in']
|
||||
if wm_in is None:
|
||||
raise ParseError("请选择相应车间库存!")
|
||||
if wm_in.state in [WMaterial.WM_OK, WMaterial.WM_REPAIR]:
|
||||
pass
|
||||
if wm_in.state in [WMaterial.WM_OK, WMaterial.WM_REPAIR, WMaterial.WM_REPAIRED]:
|
||||
if is_fix and wm_in.state not in [WMaterial.WM_REPAIR, WMaterial.WM_REPAIRED]:
|
||||
raise ParseError('需要使用返修品')
|
||||
else:
|
||||
raise ParseError('非合格/返修品不可使用')
|
||||
if mtask and mlog.route != mtask.route:
|
||||
|
@ -552,14 +562,15 @@ class MlogbInSerializer(CustomModelSerializer):
|
|||
attrs['batch'] = wm_in.batch
|
||||
attrs["batch_ofrom"] = wm_in.batch_ofrom
|
||||
attrs["material_ofrom"] = wm_in.material_ofrom
|
||||
if route.batch_bind:
|
||||
if route.batch_bind and mtask is not None:
|
||||
if not WMaterial.mat_in_qs(mtask).filter(id=wm_in.id).exists():
|
||||
raise ParseError('该车间库存非本任务使用')
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
mlog: Mlog = validated_data['mlog']
|
||||
if Mlogb.objects.filter(mlog=mlog, mtask=validated_data['mtask'], wm_in=validated_data['wm_in'], parent=None).exists():
|
||||
mtask: Mtask = validated_data.get("mtask", None)
|
||||
if Mlogb.objects.filter(mlog=mlog, mtask=mtask, wm_in=validated_data['wm_in'], parent=None).exists():
|
||||
raise ParseError('该记录已存在')
|
||||
if mlog.submit_time is not None:
|
||||
raise ParseError('生产日志已提交不可编辑')
|
||||
|
@ -567,7 +578,8 @@ class MlogbInSerializer(CustomModelSerializer):
|
|||
|
||||
def update(self, instance, validated_data):
|
||||
mlog: Mlog = instance.mlog
|
||||
if Mlogb.objects.filter(mlog=mlog, mtask=validated_data['mtask'], wm_in=validated_data['wm_in'], parent=None).exclude(id=instance.id).exists():
|
||||
mtask: Mtask = instance.mtask
|
||||
if Mlogb.objects.filter(mlog=mlog, mtask=mtask, wm_in=validated_data['wm_in'], parent=None).exclude(id=instance.id).exists():
|
||||
raise ParseError('该记录已存在')
|
||||
if mlog.submit_time is not None:
|
||||
raise ParseError('生产日志已提交不可编辑')
|
||||
|
|
|
@ -22,6 +22,7 @@ from apps.wpmw.models import Wpr, WprDefect
|
|||
from ..qm.models import Defect, Ftest
|
||||
from django.db.models import Count, Q
|
||||
from apps.utils.tasks import ctask_run
|
||||
from apps.mtm.models import Process
|
||||
|
||||
myLogger = logging.getLogger('log')
|
||||
|
||||
|
@ -269,7 +270,13 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
mo_ma, mo_batch, mo_count, mo_count_eweight, notok_sign_or_defect, mlog_or_b = mo
|
||||
if mo_count <= 0:
|
||||
continue
|
||||
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
|
||||
if mlog.is_fix:
|
||||
if mlog.mgroup.process == Process.PRO_PROD:
|
||||
wm_state = WMaterial.WM_REPAIRED # 返修只有返修完成品
|
||||
elif mlog.mgroup.process == Process.PRO_TEST:
|
||||
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
|
||||
else:
|
||||
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
|
||||
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None,
|
||||
'notok_sign': None, 'defect': None, 'state': wm_state}
|
||||
if isinstance(notok_sign_or_defect, Defect):
|
||||
|
@ -344,7 +351,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
material_in:Material = mlog.material_in
|
||||
stored_notok = mlog.stored_notok
|
||||
stored_mgroup = mlog.stored_mgroup
|
||||
|
||||
is_fix = mlog.is_fix
|
||||
# 先回退产物
|
||||
if material_out: # 产物退回
|
||||
# 有多个产物的情况
|
||||
|
@ -386,7 +393,13 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
mo_ma, mo_batch, mo_count, _, notok_sign_or_defect, mlog_or_b = mo
|
||||
if mo_count == 0:
|
||||
continue
|
||||
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
|
||||
if is_fix:
|
||||
if mgroup.process.type == Process.PRO_PROD:
|
||||
wm_state = WMaterial.WM_REPAIRED
|
||||
else: # 检验工序正常生成
|
||||
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
|
||||
else:
|
||||
wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK
|
||||
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': None, 'defect': None, 'state': wm_state}
|
||||
if isinstance(notok_sign_or_defect, Defect):
|
||||
lookup['defect'] = notok_sign_or_defect
|
||||
|
@ -516,10 +529,11 @@ def cal_mtask_progress_from_mlog(mlog):
|
|||
caled_mtask = []
|
||||
for item in m_outs_qs.all():
|
||||
mtask = item.mtask
|
||||
if mtask in caled_mtask:
|
||||
continue
|
||||
update_mtask(mtask, fill_way=mlog.fill_way)
|
||||
caled_mtask.append(mtask)
|
||||
if mtask:
|
||||
if mtask in caled_mtask:
|
||||
continue
|
||||
update_mtask(mtask, fill_way=mlog.fill_way)
|
||||
caled_mtask.append(mtask)
|
||||
|
||||
def cal_mlog_count_from_mlogb(mlog: Mlog):
|
||||
"""
|
||||
|
@ -685,7 +699,12 @@ def handover_submit(handover:Handover, user: User, now: Union[datetime.datetime,
|
|||
)
|
||||
elif handover.type == Handover.H_REPAIR:
|
||||
# 返修交接
|
||||
if handover.recive_mgroup:
|
||||
recive_mgroup = handover.recive_mgroup
|
||||
if recive_mgroup:
|
||||
if recive_mgroup.process == Process.PRO_TEST:
|
||||
wm_state = WMaterial.WM_REPAIRED
|
||||
else:
|
||||
wm_state = WMaterial.WM_REPAIR
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=material,
|
||||
|
@ -694,7 +713,7 @@ def handover_submit(handover:Handover, user: User, now: Union[datetime.datetime,
|
|||
notok_sign=wm_from.notok_sign,
|
||||
defect=wm_from.defect,
|
||||
material_origin=material,
|
||||
state=WMaterial.WM_REPAIR,
|
||||
state=wm_state,
|
||||
defaults={
|
||||
"batch_ofrom": wm_from.batch_ofrom,
|
||||
"material_ofrom": wm_from.material_ofrom,
|
||||
|
|
|
@ -541,27 +541,30 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
|
|||
mlogbin: Mlogb = serializer.save()
|
||||
mlog:Mlog = mlogbin.mlog
|
||||
route:Route = mlog.route
|
||||
mgroup:Mgroup = mlog.mgroup
|
||||
is_fix = mlog.is_fix
|
||||
# 以及mlogbw
|
||||
if mlogbin.material_in:
|
||||
material_in:Material = mlogbin.material_in
|
||||
material_out:Material = mlog.material_out
|
||||
if material_out is None:
|
||||
raise ParseError('产物不可为空')
|
||||
# 如果是主要输入物料且是主批次,才需生成输出
|
||||
if route.material_in != material_in or mlogbin.parent is not None:
|
||||
return
|
||||
m_dict = {
|
||||
"mtask": mlogbin.mtask,
|
||||
"mlog": mlog,
|
||||
"material_out": material_out,
|
||||
}
|
||||
m_dict['batch'] = generate_new_batch(mlogbin.batch, mlog)
|
||||
wm_in: WMaterial = mlogbin.wm_in
|
||||
mlogbout, is_create = Mlogb.objects.get_or_create(**m_dict, defaults=
|
||||
{"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom})
|
||||
if is_create and route:
|
||||
d_count_real = 0
|
||||
d_count_ok = 0
|
||||
material_in:Material = mlogbin.material_in
|
||||
# 如果是返修,则输出和输入相同
|
||||
material_out:Material = mlog.material_out if is_fix is False else material_in
|
||||
if material_out is None:
|
||||
raise ParseError('产物不可为空')
|
||||
# 如果是主要输入物料且是主批次,才需生成输出
|
||||
if route and route.material_in != material_in or mlogbin.parent is not None:
|
||||
return
|
||||
m_dict = {
|
||||
"mtask": mlogbin.mtask,
|
||||
"mlog": mlog,
|
||||
"material_out": material_out,
|
||||
}
|
||||
m_dict['batch'] = generate_new_batch(mlogbin.batch, mlog)
|
||||
wm_in: WMaterial = mlogbin.wm_in
|
||||
mlogbout, is_create = Mlogb.objects.get_or_create(**m_dict, defaults=
|
||||
{"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom})
|
||||
if is_create:
|
||||
d_count_real = 0
|
||||
d_count_ok = 0
|
||||
if route:
|
||||
if route.process.mtype == Process.PRO_NORMAL:
|
||||
d_count_real = mlogbin.count_use
|
||||
d_count_ok = mlogbin.count_use
|
||||
|
@ -573,26 +576,33 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
|
|||
xcount = math.floor( mlogbin.count_use / route.div_number)
|
||||
d_count_real = xcount
|
||||
d_count_ok = xcount
|
||||
# 找寻质检表
|
||||
if material_out.tracking == Material.MA_TRACKING_SINGLE:
|
||||
elif is_fix:
|
||||
d_count_real = mlogbin.count_use
|
||||
d_count_ok = mlogbin.count_use
|
||||
# 找寻质检表
|
||||
if material_out.tracking == Material.MA_TRACKING_SINGLE:
|
||||
if is_fix and mgroup.process.type == Process.PRO_PROD:
|
||||
# 如果是生产返修,则忽略质检
|
||||
pass
|
||||
else:
|
||||
qctmat = QctMat.objects.filter(material=material_out, qct__is_deleted=False).order_by("-create_time").first()
|
||||
mlogbout.qct = qctmat.qct if qctmat else None
|
||||
mlogbout.count_real = d_count_real
|
||||
mlogbout.count_ok = d_count_ok
|
||||
mlogbout.save()
|
||||
mlogbin.mlogb_to = mlogbout
|
||||
mlogbin.save()
|
||||
if material_in.tracking == Material.MA_TRACKING_SINGLE:
|
||||
m_out_t = material_out.tracking
|
||||
if mlogbin.count_use == wm_in.count: # 自动创建mlogbw
|
||||
for wpr in Wpr.objects.filter(wm=wm_in).order_by("number"):
|
||||
Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbin, defaults={"number": wpr.number})
|
||||
if m_out_t == Material.MA_TRACKING_SINGLE:
|
||||
if route.process.mtype == Process.PRO_NORMAL:
|
||||
Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number})
|
||||
elif route.process.mtype == Process.PRO_DIV:
|
||||
for i in range(route.div_number):
|
||||
Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr.number}-{i+1}')
|
||||
mlogbout.count_real = d_count_real
|
||||
mlogbout.count_ok = d_count_ok
|
||||
mlogbout.save()
|
||||
mlogbin.mlogb_to = mlogbout
|
||||
mlogbin.save()
|
||||
if material_in.tracking == Material.MA_TRACKING_SINGLE:
|
||||
m_out_t = material_out.tracking
|
||||
if mlogbin.count_use == wm_in.count: # 自动创建mlogbw
|
||||
for wpr in Wpr.objects.filter(wm=wm_in).order_by("number"):
|
||||
Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbin, defaults={"number": wpr.number})
|
||||
if m_out_t == Material.MA_TRACKING_SINGLE:
|
||||
if route.process.mtype == Process.PRO_NORMAL:
|
||||
Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number})
|
||||
elif route.process.mtype == Process.PRO_DIV:
|
||||
for i in range(route.div_number):
|
||||
Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr.number}-{i+1}')
|
||||
|
||||
|
||||
class MlogbOutViewSet(UpdateModelMixin, CustomGenericViewSet):
|
||||
|
|
Loading…
Reference in New Issue