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