1540 lines
70 KiB
Python
1540 lines
70 KiB
Python
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 ParseError
|
||
from datetime import datetime
|
||
|
||
from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog,
|
||
Handover, Handoverb, Mlogb, AttLog,
|
||
OtherLog, Fmlog, BatchSt, Mlogbw, Handoverbw, MlogbDefect, MlogUser, BatchLog)
|
||
from apps.system.models import Dept, User
|
||
from apps.system.serializers import UserSimpleSerializer
|
||
from apps.pm.models import Mtask, Mtaskb
|
||
from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change, cal_exp_duration_sec
|
||
from apps.wpm.services import get_sflog, find_material_can_change, generate_new_batch
|
||
from apps.mtm.models import Mgroup, TeamMember, Shift, Material, Route, Process
|
||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||
from django.db import transaction
|
||
from django.utils import timezone
|
||
from django.core.cache import cache
|
||
from django.utils.timezone import localdate
|
||
from apps.qm.models import NotOkOption, Qct
|
||
from apps.wf.serializers import TicketSimpleSerializer
|
||
from apps.wpmw.models import Wpr
|
||
from apps.qm.serializers import FtestProcessSerializer
|
||
import logging
|
||
from apps.qm.models import Defect
|
||
from apps.utils.snowflake import idWorker
|
||
from decimal import Decimal
|
||
from apps.em.models import Equipment
|
||
from django.db.models import Q
|
||
mylogger = logging.getLogger("log")
|
||
|
||
class OtherLogSerializer(CustomModelSerializer):
|
||
class Meta:
|
||
model = OtherLog
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS
|
||
|
||
|
||
class StLogSerializer(CustomModelSerializer):
|
||
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
||
current_sflog = serializers.CharField(label='当前处理值班', write_only=True)
|
||
current_note = serializers.CharField(
|
||
label='值班处理备注', write_only=True, allow_blank=True)
|
||
|
||
class Meta:
|
||
model = StLog
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS + \
|
||
['is_shutdown', 'sflog', 'duration']
|
||
|
||
def create(self, validated_data):
|
||
current_sflog_id = validated_data.pop('current_sflog')
|
||
current_note = validated_data.pop('current_note', '')
|
||
sflog = get_sflog(
|
||
validated_data['mgroup'], validated_data['start_time'])
|
||
if current_sflog_id != sflog.id:
|
||
raise ParseError('值班时间与发生时间不一致')
|
||
instance = super().create(validated_data)
|
||
instance.sflog = sflog
|
||
instance.save()
|
||
SfLogExp.objects.create(
|
||
sflog=sflog, stlog=instance, create_by=self.context['request'].user, note=current_note)
|
||
return instance
|
||
|
||
def update(self, instance, validated_data):
|
||
if instance.is_shutdown: # 停机不可编辑end_time
|
||
validated_data.pop('end_time', None)
|
||
validated_data.pop('mgroup', None)
|
||
validated_data.pop('start_time', None)
|
||
end_time = validated_data.pop('end_time', None)
|
||
current_sflog = validated_data.pop('current_sflog')
|
||
current_note = validated_data.pop('current_note', '')
|
||
instance = super().update(instance, validated_data)
|
||
if end_time: # 需要把涉及到的sflog都拉入
|
||
cal_exp_duration_sec(instance.id)
|
||
try:
|
||
sflogexp = SfLogExp.objects.get(
|
||
stlog=instance, sflog=current_sflog)
|
||
sflogexp.note = current_note
|
||
sflogexp.save()
|
||
except SfLogExp.DoesNotExist:
|
||
raise ParseError('该异常无需本班填写')
|
||
return instance
|
||
|
||
def validate(self, attrs):
|
||
now = timezone.now()
|
||
start_time: datetime = attrs['start_time']
|
||
end_time: datetime = attrs.get('end_time', None)
|
||
if start_time > now:
|
||
raise ParseError('开始时间应为历史时间')
|
||
if end_time:
|
||
if end_time > now:
|
||
raise ParseError('开始时间应为历史时间')
|
||
if end_time > start_time:
|
||
attrs['duration_sec'] = (
|
||
end_time - start_time).total_seconds()
|
||
else:
|
||
raise ParseError('结束时间应大于开始时间')
|
||
return super().validate(attrs)
|
||
|
||
|
||
class SfLogSerializer(CustomModelSerializer):
|
||
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
||
team_name = serializers.CharField(source='team.name', read_only=True)
|
||
shift_name = serializers.CharField(source='shift.name', read_only=True)
|
||
leader_name = serializers.CharField(source='leader.name', read_only=True)
|
||
|
||
class Meta:
|
||
model = SfLog
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS + \
|
||
['mgroup', 'start_time', 'end_time', 'belong_dept']
|
||
extra_kwargs = {
|
||
'team': {'required': True},
|
||
'leader': {'required': True}
|
||
}
|
||
|
||
def update(self, instance, validated_data):
|
||
old_pcoal_heat = instance.pcoal_heat
|
||
old_team = instance.team
|
||
instance: SfLog = super().update(instance, validated_data)
|
||
new_pcoal_heat = instance.pcoal_heat
|
||
new_team = instance.team
|
||
mgroup: Mgroup = instance.mgroup
|
||
|
||
# 更新煤粉热值触发计算
|
||
if instance.mgroup.name == '回转窑' and instance.shift.name in ['早班', '白班']:
|
||
mylogger.info(f'回转窑白班/早班{instance.get_ymd}更新{new_pcoal_heat}-{old_pcoal_heat}')
|
||
year_s, month_s, day_s = instance.get_ymd
|
||
if new_pcoal_heat: # 更新一下缓存
|
||
cache.set(f'pcoal_heat_{year_s}_{month_s}_{day_s}', new_pcoal_heat, timeout=60 * 60 * 48)
|
||
if new_pcoal_heat != old_pcoal_heat:
|
||
cal_enstat_when_pcoal_heat_change.delay(year_s, month_s, day_s)
|
||
|
||
# 更新班组触发计算
|
||
if new_team != old_team:
|
||
default_state = 'pending'
|
||
if timezone.now() > instance.end_time:
|
||
default_state = 'normal'
|
||
# 分配班组时创建人员到岗情况
|
||
for item in TeamMember.objects.filter(team=new_team, mgroup=instance.mgroup):
|
||
AttLog.objects.get_or_create(sflog=instance, user=item.user, defaults={
|
||
'sflog': instance, 'user': item.user, 'post': item.post, 'state': default_state, 'create_by': self.context['request'].user})
|
||
if mgroup.need_enm:
|
||
from apps.qm.tasks import cal_quastat_sflog
|
||
cal_enstat_when_team_change.delay(instance.id)
|
||
cal_quastat_sflog.delay(instance.id)
|
||
return instance
|
||
|
||
def to_representation(self, instance):
|
||
ret = super().to_representation(instance)
|
||
if "shut_sec" in ret:
|
||
ret["shut_hour"] = "{:.2f}".format(round(ret['shut_sec']/3600, 2))
|
||
return ret
|
||
# def to_internal_value(self, data):
|
||
# if hasattr(self.Meta, 'update_fields') and self.context['request'].method in ['PUT', 'PATCH']:
|
||
# u_fields = self.Meta.update_fields
|
||
# new_data = {key: data[key] for key in u_fields if key in data}
|
||
# return super().to_internal_value(new_data)
|
||
# return super().to_internal_value(data)
|
||
|
||
|
||
class SflogExpSerializer(CustomModelSerializer):
|
||
# mgroup = serializers.CharField(source='sflog.mgroup.id', read_only=True)
|
||
# mgroup_name = serializers.CharField(
|
||
# source='sflog.mgroup.name', read_only=True)
|
||
# stlog_ = StLogSerializer(source='stlog', read_only=True)
|
||
# happen_time = serializers.DateTimeField(required=True, label='发生时间')
|
||
# cate = serializers.CharField(required=True, label='原因类别')
|
||
sflog_ = SfLogSerializer(source='sflog', read_only=True)
|
||
stlog_ = StLogSerializer(source='stlog', read_only=True)
|
||
|
||
class Meta:
|
||
model = SfLogExp
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS + ['sflog', 'stlog', 'duration']
|
||
|
||
|
||
class WMaterialSerializer(CustomModelSerializer):
|
||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||
supplier_name = serializers.CharField(source='supplier.name', 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)
|
||
material_ofrom_name = serializers.StringRelatedField(source='material_ofrom', read_only=True)
|
||
material_origin_name = serializers.StringRelatedField(source='material_origin', read_only=True)
|
||
notok_sign_name = serializers.SerializerMethodField()
|
||
defect_name = serializers.CharField(source="defect.name", read_only=True)
|
||
count_working = serializers.IntegerField(read_only=True, label='在制数量')
|
||
count_handovering = serializers.IntegerField(read_only=True, label='正在交送的数量')
|
||
|
||
def get_notok_sign_name(self, obj):
|
||
return getattr(NotOkOption, obj.notok_sign, NotOkOption.qt).label if obj.notok_sign else None
|
||
|
||
class Meta:
|
||
model = WMaterial
|
||
fields = '__all__'
|
||
|
||
def to_representation(self, instance):
|
||
ret = super().to_representation(instance)
|
||
if 'count' in ret and 'count_working' in ret:
|
||
ret['count_cando'] = str(Decimal(ret['count']) - Decimal(ret['count_working']))
|
||
if 'count' in ret and 'count_handovering' in ret:
|
||
ret['count_canhandover'] = str(Decimal(ret['count']) - Decimal(ret['count_handovering']))
|
||
return ret
|
||
|
||
class MlogbDefectSerializer(CustomModelSerializer):
|
||
defect_name = serializers.CharField(source="defect.name", read_only=True)
|
||
defect_okcate = serializers.CharField(source="defect.okcate", read_only=True)
|
||
class Meta:
|
||
model = MlogbDefect
|
||
fields = ["id", "defect_name", "count", "mlogb", "defect", "defect_okcate", "count_has"]
|
||
read_only_fields = EXCLUDE_FIELDS_BASE + ["mlogb"]
|
||
extra_kwargs = {
|
||
'count_has': {'required': False},
|
||
}
|
||
|
||
def validate(self, attrs):
|
||
if attrs["count"] < 0:
|
||
raise serializers.ValidationError("存在负数!")
|
||
if "count_has" not in attrs or attrs["count_has"] < attrs["count"]:
|
||
attrs["count_has"] = attrs["count"]
|
||
return attrs
|
||
|
||
class MlogbSerializer(CustomModelSerializer):
|
||
material_out_ = MaterialSimpleSerializer(
|
||
source='material_out', read_only=True)
|
||
material_out_name = serializers.StringRelatedField(
|
||
source='material_out', read_only=True)
|
||
|
||
class Meta:
|
||
model = Mlogb
|
||
fields = ['id', 'material_out', 'count_ok',
|
||
'material_out_', 'material_out_name', "mlog"]
|
||
extra_kwargs = {
|
||
'material_out': {'required': True, 'allow_null': False}}
|
||
read_only_fields = EXCLUDE_FIELDS_BASE + ["mlog"]
|
||
|
||
|
||
class MlogListSerializer(CustomModelSerializer):
|
||
team_name = serializers.CharField(source="team.name", read_only=True)
|
||
mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True)
|
||
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
||
# routepack_name = serializers.CharField(source='route.routepack.name', read_only=True)
|
||
belong_dept = serializers.CharField(
|
||
source='mgroup.belong_dept.id', read_only=True)
|
||
belong_dept_name = serializers.CharField(
|
||
source='mgroup.belong_dept.name', read_only=True)
|
||
mgroup_name = serializers.CharField(
|
||
source='mgroup.name', read_only=True)
|
||
mtask_count = serializers.IntegerField(
|
||
source='mtask.count', read_only=True)
|
||
create_by_name = serializers.CharField(
|
||
source='create_by.name', read_only=True)
|
||
update_by_name = serializers.CharField(
|
||
source='update_by.name', read_only=True)
|
||
# + 0.3s
|
||
material_in_ = MaterialSimpleSerializer(
|
||
source='material_in', read_only=True)
|
||
material_out_ = MaterialSimpleSerializer(
|
||
source='material_out', read_only=True)
|
||
material_out_name = serializers.StringRelatedField(
|
||
source='material_out', read_only=True)
|
||
material_in_name = serializers.StringRelatedField(
|
||
source='material_in', read_only=True)
|
||
#
|
||
handle_user_name = serializers.CharField(
|
||
source='handle_user.name', read_only=True)
|
||
handle_user_2_name = serializers.CharField(
|
||
source='handle_user_2.name', read_only=True)
|
||
handle_leader_name = serializers.CharField(
|
||
source='handle_leader.name', read_only=True)
|
||
equipment_name = serializers.StringRelatedField(
|
||
source='equipment', read_only=True)
|
||
equipment_2_name = serializers.StringRelatedField(
|
||
source='equipment_2', read_only=True)
|
||
shift_name = serializers.CharField(source='shift.name', read_only=True)
|
||
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
|
||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||
submit_user_name = serializers.CharField(source='submit_user.name', read_only=True)
|
||
|
||
handle_users_ = UserSimpleSerializer(
|
||
source='handle_users', many=True, read_only=True)
|
||
|
||
class Meta:
|
||
model = Mlog
|
||
fields = '__all__'
|
||
# exclude = ["equipments","handle_users", "material_outs"]
|
||
|
||
|
||
class MlogbDetailSerializer(CustomModelSerializer):
|
||
material_out_name = serializers.StringRelatedField(
|
||
source='material_out', read_only=True)
|
||
material_in_name = serializers.StringRelatedField(source='material_in', read_only=True)
|
||
material_out_tracking = serializers.IntegerField(source="material_out.tracking", read_only=True)
|
||
mlogbdefect = MlogbDefectSerializer(many=True, read_only=True)
|
||
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
|
||
|
||
class Meta:
|
||
model = Mlogb
|
||
fields = '__all__'
|
||
|
||
class MlogSerializer(CustomModelSerializer):
|
||
team_name = serializers.CharField(source="team.name", read_only=True)
|
||
mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True)
|
||
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
||
# routepack_name = serializers.CharField(source='route.routepack.name', read_only=True)
|
||
belong_dept = serializers.CharField(
|
||
source='mgroup.belong_dept.id', read_only=True)
|
||
belong_dept_name = serializers.CharField(
|
||
source='mgroup.belong_dept.name', read_only=True)
|
||
mgroup_name = serializers.CharField(
|
||
source='mgroup.name', read_only=True)
|
||
mtask_count = serializers.IntegerField(
|
||
source='mtask.count', read_only=True)
|
||
create_by_name = serializers.CharField(
|
||
source='create_by.name', read_only=True)
|
||
update_by_name = serializers.CharField(
|
||
source='update_by.name', read_only=True)
|
||
material_in_ = MaterialSimpleSerializer(
|
||
source='material_in', read_only=True)
|
||
material_out_ = MaterialSimpleSerializer(
|
||
source='material_out', read_only=True)
|
||
material_out_name = serializers.StringRelatedField(
|
||
source='material_out', read_only=True)
|
||
material_in_name = serializers.StringRelatedField(
|
||
source='material_in', read_only=True)
|
||
handle_user_name = serializers.CharField(
|
||
source='handle_user.name', read_only=True)
|
||
handle_user_2_name = serializers.CharField(
|
||
source='handle_user_2.name', read_only=True)
|
||
handle_leader_name = serializers.CharField(
|
||
source='handle_leader.name', read_only=True)
|
||
equipment_name = serializers.StringRelatedField(
|
||
source='equipment', read_only=True)
|
||
equipment_2_name = serializers.StringRelatedField(
|
||
source='equipment_2', read_only=True)
|
||
shift_name = serializers.CharField(source='shift.name', read_only=True)
|
||
mlogb = MlogbSerializer(
|
||
label='多产出件信息', many=True, required=False)
|
||
mlogb_full = MlogbDetailSerializer(
|
||
label='物料信息', many=True, read_only=True)
|
||
handle_users_ = UserSimpleSerializer(
|
||
source='handle_users', many=True, read_only=True)
|
||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
|
||
submit_user_name = serializers.CharField(source='submit_user.name', read_only=True)
|
||
|
||
mlogdefect = MlogbDefectSerializer(many=True, required=False)
|
||
mlogindefect = MlogbDefectSerializer(many=True, label="前道不良", required=False)
|
||
class Meta:
|
||
model = Mlog
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS + \
|
||
['submit_time', 'submit_user', 'material_outs', "handle_date", "shift"]
|
||
extra_kwargs = {
|
||
"batch": {"required": True},
|
||
"shift": {"required": False},
|
||
"material_out": {"required": True},
|
||
"work_start_time": {"required": False}
|
||
}
|
||
|
||
def create(self, validated_data):
|
||
material_out = validated_data['material_out']
|
||
mtask:Mtask = validated_data.get('mtask', None)
|
||
mlogdefect = validated_data.pop('mlogdefect', None)
|
||
mlogbindefect = validated_data.pop('mlogindefect', None)
|
||
if mtask and mtask.state != Mtask.MTASK_ASSGINED:
|
||
raise ParseError('该任务非下达中不可选择')
|
||
|
||
mlogb = validated_data.pop('mlogb', [])
|
||
instance: Mlog = super().create(validated_data)
|
||
## 返工没有加工前不良
|
||
if instance.is_fix and instance.count_pn_jgqbl >0:
|
||
raise ParseError("返工不支持加工前不良")
|
||
# 自动生成mlogb
|
||
batch_in = instance.batch
|
||
wm_in = instance.wm_in
|
||
if wm_in:
|
||
batch_in = wm_in.batch
|
||
instance.batch = batch_in
|
||
instance.save(update_fields=['batch'])
|
||
mlogbin = None
|
||
if instance.material_in: # 如果有消耗
|
||
add_dict = {
|
||
'mlog': instance, 'batch': batch_in, 'wm_in': wm_in,
|
||
'mtask': instance.mtask, 'material_in': instance.material_in,
|
||
'route': instance.route,
|
||
'count_use': instance.count_use, 'count_break': instance.count_break,
|
||
'count_pn_jgqbl': instance.count_pn_jgqbl
|
||
}
|
||
if wm_in:
|
||
add_dict['batch_ofrom'] = wm_in.batch_ofrom
|
||
add_dict['material_ofrom'] = wm_in.material_ofrom
|
||
mlogbin = Mlogb.objects.create(**add_dict)
|
||
if mlogbindefect is not None:
|
||
mlogbin_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": mlogbin, "id": idWorker.get_id()})
|
||
for item in mlogbindefect if item["count"] > 0
|
||
]
|
||
if mlogbin_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogbin_defect_objects)
|
||
mlogbin.cal_count_pn_jgqbl(cal_mlog=False)
|
||
|
||
# mlogb只用于组合件输出物填写
|
||
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:
|
||
mlogbx = Mlogb.objects.create(
|
||
mlog=instance,
|
||
batch=instance.batch,
|
||
route=instance.route,
|
||
mtask=instance.mtask,
|
||
material_out=item['material_out'],
|
||
count_ok=item['count_ok'])
|
||
if wm_in:
|
||
mlogbx.batch_ofrom = wm_in.batch_ofrom
|
||
mlogbx.material_ofrom = wm_in.material_ofrom
|
||
mlogbx.save(update_fields=["batch_ofrom", "material_ofrom"])
|
||
else:
|
||
raise ParseError('缺少产出物信息')
|
||
else:
|
||
# 生成产出物
|
||
batch_out = validated_data.get('batch', None)
|
||
if batch_out:
|
||
pass
|
||
else:
|
||
batch_out = generate_new_batch(batch_in, instance)
|
||
|
||
add_dict_2 = {
|
||
'mlog': instance, 'batch': batch_out,
|
||
'mtask': instance.mtask, 'material_out': instance.material_out,
|
||
'count_real': instance.count_real, 'route': instance.route,
|
||
'count_ok': instance.count_ok, 'count_notok': instance.count_notok,
|
||
'count_break_t': instance.count_break_t,
|
||
'qct': instance.qct
|
||
}
|
||
need_mdfect = False
|
||
if mlogdefect is not None:
|
||
need_mdfect = True
|
||
else:
|
||
for f in Mlogb._meta.fields:
|
||
if 'count_n_' in f.name:
|
||
add_dict_2[f.name] = getattr(instance, f.name)
|
||
ddict = {}
|
||
if wm_in:
|
||
ddict = {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom}
|
||
if mlogbin:
|
||
ddict["mlogb_from"] = mlogbin
|
||
mlogb, _ = Mlogb.objects.get_or_create(**add_dict_2, defaults=ddict)
|
||
if need_mdfect:
|
||
mlogb_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": mlogb, "id": idWorker.get_id()})
|
||
for item in mlogdefect if item["count"] > 0
|
||
]
|
||
if mlogb_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
|
||
mlogb.cal_count_notok(cal_mlog=False)
|
||
instance.cal_mlog_count_from_mlogb()
|
||
return instance
|
||
|
||
def update(self, instance, validated_data):
|
||
if instance.fill_way == Mlog.MLOG_23:
|
||
raise ParseError('不支持的填写类型')
|
||
validated_data.pop('mtask', None)
|
||
validated_data.pop('mgroup', None)
|
||
mlogdefect = validated_data.pop('mlogdefect', None)
|
||
mlogbindefect = validated_data.pop('mlogindefect', None)
|
||
if instance.mtask:
|
||
validated_data.pop('handle_date', None)
|
||
# validated_data.pop('handle_user', None)
|
||
|
||
mlogb = validated_data.pop('mlogb', [])
|
||
instance: Mlog = super().update(instance, validated_data)
|
||
## 返工没有加工前不良
|
||
if instance.is_fix and instance.count_pn_jgqbl >0:
|
||
raise ParseError("返工不支持加工前不良")
|
||
wm_in = instance.wm_in
|
||
batch_in = instance.batch
|
||
if wm_in:
|
||
batch_in = wm_in.batch
|
||
# 修改消耗
|
||
if instance.fill_way in [Mlog.MLOG_12, Mlog.MLOG_2]:
|
||
# 自动生成mlogb
|
||
if instance.material_in: # 有消耗的情况
|
||
minx, _ = Mlogb.objects.get_or_create(
|
||
mlog=instance,
|
||
batch=batch_in,
|
||
wm_in=instance.wm_in,
|
||
mtask=instance.mtask,
|
||
material_in=instance.material_in
|
||
)
|
||
if wm_in:
|
||
minx.batch_ofrom = wm_in.batch_ofrom
|
||
minx.material_ofrom = wm_in.material_ofrom
|
||
minx.count_use = instance.count_use
|
||
minx.count_break = instance.count_break
|
||
minx.count_pn_jgqbl = instance.count_pn_jgqbl
|
||
minx.qct = instance.qct
|
||
minx.save()
|
||
Mlogb.objects.filter(mlog=instance, material_in__isnull=False).exclude(id=minx.id).delete()
|
||
if mlogbindefect is not None:
|
||
mlogbin_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": minx, "id": idWorker.get_id()})
|
||
for item in mlogbindefect if item["count"] > 0
|
||
]
|
||
if mlogbin_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogbin_defect_objects)
|
||
minx.cal_count_pn_jgqbl(cal_mlog=False)
|
||
|
||
# 修改产出
|
||
if instance.fill_way == Mlog.MLOG_2 and instance.material_out.brothers:
|
||
# 针对兄弟件的情况
|
||
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).update(
|
||
batch=instance.batch, # 注意mlog的batch有可能会进行修改
|
||
count_ok=0)
|
||
for item in mlogb:
|
||
Mlogb.objects.filter(mlog=instance, material_out=item['material_out']).update(
|
||
batch=instance.batch,
|
||
count_ok=item['count_ok'])
|
||
|
||
elif instance.fill_way in [Mlog.MLOG_12, Mlog.MLOG_2]:
|
||
# 生成产出物
|
||
batch_out = instance.batch
|
||
if batch_out:
|
||
pass
|
||
else:
|
||
batch_out = generate_new_batch(batch_in, instance)
|
||
mox, _ = Mlogb.objects.get_or_create(mlog=instance, batch=batch_out,
|
||
mtask=instance.mtask, material_out=instance.material_out)
|
||
# 需要同步更新数量
|
||
mox.count_real = instance.count_real
|
||
mox.count_ok = instance.count_ok
|
||
mox.count_notok = instance.count_notok
|
||
mox.count_break_t = instance.count_break_t
|
||
if wm_in:
|
||
mox.batch_ofrom = wm_in.batch
|
||
mox.material_ofrom = wm_in.material_ofrom
|
||
need_mdefect=False
|
||
if mlogdefect is not None:
|
||
need_mdefect = True
|
||
else:
|
||
for f in Mlogb._meta.fields:
|
||
if 'count_n_' in f.name:
|
||
setattr(mox, f.name, getattr(instance, f.name))
|
||
mox.save()
|
||
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).exclude(id=mox.id).delete()
|
||
if need_mdefect:
|
||
MlogbDefect.objects.filter(mlogb__mlog=instance).delete()
|
||
mlogb_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": mox, "id": idWorker.get_id()})
|
||
for item in mlogdefect if item["count"] > 0
|
||
]
|
||
if mlogb_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
|
||
mox.cal_count_notok(cal_mlog=False)
|
||
instance.cal_mlog_count_from_mlogb()
|
||
return instance
|
||
|
||
def validate(self, attrs):
|
||
attrs['fill_way'] = Mlog.MLOG_2 # 只填第二级
|
||
attrs['mtype'] = Mlog.MTYPE_SELF # 默认为自生产
|
||
fmlog:Fmlog = attrs.get('fmlog', None)
|
||
mtaskb = attrs.get('mtaskb', None)
|
||
wm_in: WMaterial = attrs.get('wm_in', None)
|
||
if fmlog:
|
||
attrs['fill_way'] = Mlog.MLOG_12
|
||
if not wm_in:
|
||
raise ParseError('未提供消耗的车间物料')
|
||
attrs['mgroup'] = fmlog.mgroup
|
||
attrs['is_fix'] = fmlog.is_fix
|
||
attrs['mtask'] = fmlog.mtask
|
||
attrs['route'] = fmlog.route
|
||
attrs['mtype'] = fmlog.mgroup.mtype
|
||
if attrs['mtask'] and attrs['mtask'].route:
|
||
attrs['route'] = attrs['mtask'].route
|
||
if mtaskb and mtaskb.mtask != fmlog.mtask:
|
||
raise ParseError('子任务不一致')
|
||
if wm_in:
|
||
attrs["material_in"] = wm_in.material
|
||
attrs["batch"] = wm_in.batch
|
||
if attrs["is_fix"]:
|
||
attrs["material_out"] = attrs["material_in"]
|
||
if wm_in.state in [WMaterial.WM_REPAIR, WMaterial.WM_NOTOK]:
|
||
pass
|
||
else:
|
||
raise ParseError('返修或复检需使用返修品/不合格品')
|
||
elif wm_in.state != WMaterial.WM_OK:
|
||
raise ParseError('非合格品不可使用')
|
||
if attrs['route'] and wm_in.material != attrs['route'].material_in:
|
||
raise ParseError('消耗物料与工艺步骤不一致')
|
||
if attrs['mtype'] == Mlog.MTYPE_OUT:
|
||
supplier = attrs.get('supplier', None)
|
||
if not supplier:
|
||
raise ParseError('外协必须选择外协单位')
|
||
|
||
mtask = attrs.get('mtask', None)
|
||
mlogdefect = attrs.get('mlogdefect', None)
|
||
if mlogdefect is None:
|
||
count_notok = 0
|
||
for i in attrs:
|
||
if 'count_n_' in i:
|
||
if attrs[i] < 0:
|
||
raise ParseError(f'{attrs[i]}不能小于0')
|
||
count_notok = count_notok + attrs[i]
|
||
attrs['count_notok'] = count_notok
|
||
if attrs['count_ok'] < 0:
|
||
raise ParseError('合格数量不能小于0')
|
||
if attrs['count_real'] != attrs['count_ok'] + attrs['count_notok']:
|
||
raise ParseError('生产数量需等于合格数量+不合格数量')
|
||
|
||
mtaskb: Mtaskb = attrs.get('mtaskb', None)
|
||
if mtaskb:
|
||
mtask = mtaskb.mtask
|
||
attrs['mtask'] = mtask
|
||
attrs['handle_user'] = mtaskb.handle_user
|
||
if mtask:
|
||
attrs['mgroup'] = mtask.mgroup
|
||
attrs['material_in'] = mtask.material_in
|
||
material_out = mtask.material_out
|
||
if wm_in and wm_in.material != mtask.material_in:
|
||
raise ParseError('消耗物料与任务不一致')
|
||
attrs['material_out'] = material_out
|
||
else:
|
||
mgroup = attrs['mgroup']
|
||
material_out = attrs['material_out']
|
||
if not (mgroup and material_out):
|
||
raise ParseError('缺少工段或产物!')
|
||
|
||
# 时间
|
||
mgroup:Mgroup = attrs['mgroup']
|
||
work_start_time:datetime = attrs.get('work_start_time', None)
|
||
if work_start_time:
|
||
handle_date, attrs["shift"] = mgroup.get_shift(work_start_time)
|
||
else:
|
||
if "handle_date" in attrs and attrs["handle_date"]:
|
||
pass
|
||
else:
|
||
raise ParseError('缺少生产日期')
|
||
if mtask and mtask.start_date == mtask.end_date:
|
||
attrs['handle_date'] = mtask.end_date
|
||
if attrs['handle_date'] != handle_date:
|
||
raise ParseError('任务日期与生产日期不一致')
|
||
elif work_start_time:
|
||
attrs['handle_date'] = handle_date
|
||
|
||
handle_user = attrs.get('handle_user', None)
|
||
if handle_user is None and hasattr(self, "request"):
|
||
handle_user = self.request.user
|
||
return attrs
|
||
|
||
|
||
class MlogInitSerializer(CustomModelSerializer):
|
||
class Meta:
|
||
model = Mlog
|
||
fields = ['id',
|
||
'work_start_time', 'work_end_time', 'mgroup', 'reminder_interval_list',
|
||
'route', 'equipment', 'handle_user', 'note', 'supplier', 'test_file', 'test_user', 'test_time', 'oinfo_json', 'is_fix', "handle_users", "team", "handle_date"]
|
||
read_only_fields = ["mtype"]
|
||
extra_kwargs = {
|
||
'work_start_time': {'required': True},
|
||
'route':{'required': False},
|
||
'mgroup': {'required': True},
|
||
'mtype': {'required': True}
|
||
}
|
||
|
||
def validate(self, attrs):
|
||
mgroup: Mgroup = attrs['mgroup']
|
||
is_fix:bool = attrs.get('is_fix', False)
|
||
attrs['mtype'] = mgroup.mtype
|
||
if is_fix:
|
||
attrs["route"] = None
|
||
attrs['hour_work'] = None
|
||
attrs['material_in'] = None
|
||
attrs['material_out'] = None
|
||
else:
|
||
route: Route = attrs.get('route', None)
|
||
# if not route:
|
||
# raise ParseError('缺少工艺路线')
|
||
if route:
|
||
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
|
||
attrs['fill_way'] = Mlog.MLOG_23
|
||
if attrs['mtype'] == Mlog.MTYPE_OUT:
|
||
supplier = attrs.get('supplier', None)
|
||
if not supplier:
|
||
raise ParseError('外协必须选择外协单位')
|
||
# 如果已经确定产出,则自动获取qct
|
||
if attrs.get("material_out", None):
|
||
attrs["qct"] = Qct.get(attrs["material_out"], "process", "out")
|
||
|
||
attrs["handle_date"], attrs["shift"] = mgroup.get_shift(attrs['work_start_time'])
|
||
return attrs
|
||
|
||
class MlogChangeSerializer(CustomModelSerializer):
|
||
class Meta:
|
||
model = Mlog
|
||
fields = ['id', 'work_start_time', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file', 'test_user', 'test_time', 'equipment', "team"]
|
||
|
||
def update(self, instance, validated_data):
|
||
work_start_time = validated_data.get('work_start_time', None)
|
||
if work_start_time:
|
||
mgroup:Mgroup = instance.mgroup
|
||
validated_data["handle_date"], validated_data["shift"] = mgroup.get_shift(work_start_time)
|
||
return super().update(instance, validated_data)
|
||
|
||
|
||
class CountJsonSerializer(serializers.Serializer):
|
||
count_use = serializers.IntegerField(min_value=0, required=True)
|
||
floor = serializers.IntegerField(min_value=1, required=True)
|
||
count_test = serializers.IntegerField(min_value=0, required=True)
|
||
count_notok = serializers.IntegerField(min_value=0, required=True)
|
||
|
||
class CountJsonFromSerializer(serializers.Serializer):
|
||
start = serializers.IntegerField(min_value=0, required=True)
|
||
end = serializers.IntegerField(min_value=0, required=True)
|
||
count_t = serializers.IntegerField(min_value=0, required=True, label="总数")
|
||
|
||
class MlogbInSerializer(CustomModelSerializer):
|
||
mlogbdefect = MlogbDefectSerializer(many=True, required=False)
|
||
count_json_from = CountJsonFromSerializer(required=False, many=True)
|
||
wprs_in = serializers.ListField(child=serializers.CharField(), label="单个ID的列表", required=False)
|
||
|
||
class Meta:
|
||
model = Mlogb
|
||
fields = ['id', 'mlog', 'mtask', 'route', 'wm_in', 'count_use', 'count_pn_jgqbl',
|
||
'count_break', 'note', "parent", "mlogbdefect", "count_json_from", "wprs_in"]
|
||
extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': False},
|
||
'wm_in': {'required': True, "allow_empty": False}}
|
||
|
||
def validate(self, attrs):
|
||
if attrs["count_use"] < 0 or attrs.get("count_pn_jgqbl", 0) < 0 or attrs.get("count_break", 0) < 0:
|
||
raise ParseError('存在负数!')
|
||
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 is_fix: # 返修或复检
|
||
if wm_in.state in [WMaterial.WM_REPAIR, WMaterial.WM_NOTOK]:
|
||
pass
|
||
else:
|
||
raise ParseError('返修或复检需使用返修品/不合格品')
|
||
elif wm_in.state != WMaterial.WM_OK:
|
||
raise ParseError('非合格品不可使用')
|
||
|
||
route = None
|
||
mlog_route = mlog.route
|
||
if mlog_route is None:
|
||
if is_fix is False:
|
||
route = attrs.get("route", None)
|
||
if not route:
|
||
raise ParseError("缺少工艺步骤")
|
||
else:
|
||
attrs["route"] = route
|
||
else:
|
||
route = mlog_route
|
||
attrs["route"] = route
|
||
|
||
if mtask and route != mtask.route:
|
||
raise ParseError('工艺步骤与任务不匹配')
|
||
attrs['material_in'] = wm_in.material
|
||
attrs['batch'] = wm_in.batch
|
||
attrs["batch_ofrom"] = wm_in.batch_ofrom
|
||
attrs["material_ofrom"] = wm_in.material_ofrom
|
||
attrs["number_from"] = wm_in.number_from
|
||
if route and 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']
|
||
mtask: Mtask = validated_data.get("mtask", None)
|
||
mlogbdefect = validated_data.pop("mlogbdefect", None)
|
||
wprs_in = validated_data.pop("wprs_in", [])
|
||
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('生产日志已提交不可编辑')
|
||
|
||
ins:Mlogb = super().create(validated_data)
|
||
validated_data["wprs_in"] = wprs_in
|
||
if mlogbdefect is not None and ins.material_in.tracking == Material.MA_TRACKING_BATCH:
|
||
mlogb_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": ins, "id": idWorker.get_id()})
|
||
for item in mlogbdefect if item["count"] > 0
|
||
]
|
||
if mlogb_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
|
||
ins.cal_count_pn_jgqbl(cal_mlog=False)
|
||
return ins
|
||
|
||
class MlogbInUpdateSerializer(CustomModelSerializer):
|
||
mlogbdefect = MlogbDefectSerializer(many=True, required=False)
|
||
class Meta:
|
||
model = Mlogb
|
||
fields = ['id', 'count_use', 'count_pn_jgqbl', 'note', 'mlogbdefect', "need_inout"]
|
||
|
||
def validate(self, attrs):
|
||
if attrs["count_use"] < 0 or attrs.get("count_pn_jgqbl", 0) < 0:
|
||
raise ParseError('存在负数!')
|
||
return attrs
|
||
def update(self, instance, validated_data):
|
||
mlog: Mlog = instance.mlog
|
||
mlogbdefect = validated_data.pop("mlogbdefect", None)
|
||
if mlog.submit_time is not None:
|
||
raise ParseError('生产日志已提交不可编辑')
|
||
ins:Mlogb = super().update(instance, validated_data)
|
||
if mlogbdefect is not None and ins.material_in.tracking == Material.MA_TRACKING_BATCH:
|
||
MlogbDefect.objects.filter(mlogb=ins).delete()
|
||
mlogb_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": ins, "id": idWorker.get_id()})
|
||
for item in mlogbdefect if item["count"] > 0
|
||
]
|
||
if mlogb_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
|
||
ins.cal_count_pn_jgqbl(cal_mlog=False)
|
||
# 只有普通工序的才可联动
|
||
route:Route = ins.route if ins.route else ins.mlog.route
|
||
if route and route.process and route.process.mtype == Process.PRO_NORMAL:
|
||
if route.material_out.tracking == Material.MA_TRACKING_BATCH:
|
||
mlogbout_qs = Mlogb.objects.filter(mlog=ins.mlog, mlogb_from=ins)
|
||
if mlogbout_qs.count() == 1:
|
||
mlogbout = mlogbout_qs.first()
|
||
mlogbout.count_real = ins.count_use - ins.count_pn_jgqbl - ins.count_break
|
||
mlogbout.count_ok = mlogbout.count_real - mlogbout.count_notok
|
||
if mlogbout.count_real < 0 or mlogbout.count_ok < 0:
|
||
raise ParseError("对应的产出数异常")
|
||
mlogbout.save(update_fields=["count_real", "count_ok"])
|
||
mlogbout.cal_count_notok(cal_mlog=False)
|
||
return ins
|
||
|
||
class MlogbwCreateUpdateSerializer(CustomModelSerializer):
|
||
ftest = FtestProcessSerializer(required=False, allow_null=True)
|
||
equip_name = serializers.CharField(source='equip.name', read_only=True)
|
||
equip_number = serializers.CharField(source='equip.number', read_only=True)
|
||
wpr_number_out = serializers.CharField(source='wpr.number_out', read_only=True)
|
||
mlogb__batch = serializers.CharField(source='mlogb.batch', read_only=True)
|
||
class Meta:
|
||
model = Mlogbw
|
||
fields = ["id", "number", "wpr", "note",
|
||
"mlogb", "ftest", "equip", "work_start_time",
|
||
"work_end_time", "mlogbw_from", "equip_name", "equip_number", "wpr_number_out", "mlogb__batch"]
|
||
read_only_fields = ["mlogbw_from"]
|
||
|
||
def validate(self, attrs):
|
||
mlogb:Mlogb = attrs["mlogb"]
|
||
if mlogb.mlog.submit_time is not None:
|
||
raise ParseError('生产日志已提交不可编辑')
|
||
wpr:Wpr = attrs.get("wpr", None)
|
||
in_or_out, tracking = mlogb.get_tracking()
|
||
if tracking != Material.MA_TRACKING_SINGLE:
|
||
raise ParseError('非单件追踪不可使用')
|
||
if in_or_out == 'in':
|
||
if not wpr:
|
||
raise ParseError('请选择相应产品')
|
||
if mlogb.wm_in and wpr.wm != mlogb.wm_in:
|
||
raise ParseError(f'{wpr.number}-该产品非本批次')
|
||
return attrs
|
||
|
||
def save_ftest(self, mlogbw, ftest_data):
|
||
ftest = mlogbw.ftest
|
||
if not ftest:
|
||
ftest_sr = FtestProcessSerializer(data=ftest_data)
|
||
ftest = ftest_sr.create(ftest_data)
|
||
mlogbw.ftest = ftest
|
||
mlogbw.save()
|
||
else:
|
||
ftest_sr = FtestProcessSerializer()
|
||
ftest_sr.update(instance=ftest, validated_data=ftest_data)
|
||
return mlogbw
|
||
|
||
def create(self, validated_data):
|
||
wpr: Wpr = validated_data.get("wpr", None)
|
||
if wpr:
|
||
mlogb: Mlogb = validated_data["mlogb"]
|
||
if Mlogbw.objects.filter(mlogb=mlogb, wpr=wpr).exists():
|
||
raise ParseError(f'{wpr.number}-该产品已选入')
|
||
if Mlogbw.objects.filter(mlogb__mlog__submit_time__isnull=True, wpr=wpr).exists():
|
||
raise ParseError(f'{wpr.number}-该产品已在其他日志中选入')
|
||
ftest_data = validated_data.pop("ftest", None)
|
||
mlogbw = super().create(validated_data)
|
||
if ftest_data:
|
||
mlogbw = self.save_ftest(mlogbw, ftest_data)
|
||
return mlogbw
|
||
|
||
def update(self, instance, validated_data):
|
||
validated_data.pop("mlogb")
|
||
ftest_data = validated_data.pop("ftest", None)
|
||
mlogbw:Mlogbw = super().update(instance, validated_data)
|
||
if ftest_data:
|
||
mlogbw = self.save_ftest(mlogbw, ftest_data)
|
||
elif ftest_data is None:
|
||
ftest = mlogbw.ftest
|
||
if ftest:
|
||
mlogbw.ftest = None
|
||
mlogbw.save()
|
||
ftest.delete()
|
||
return mlogbw
|
||
|
||
|
||
class MlogbwStartTestSerializer(serializers.Serializer):
|
||
mlogbw_ids = serializers.ListField(child=serializers.CharField(), label="mlogbwId列表")
|
||
test_equip = serializers.CharField(label="测试设备", allow_null=True, required=False, allow_blank=True)
|
||
test_user = serializers.CharField(label="测试人员")
|
||
defects = serializers.ListField(child=serializers.CharField(), required=False, allow_null=True, label="缺陷项列表")
|
||
testitems = serializers.ListField(child=serializers.CharField(), required=False, allow_null=True, label="测试项列表")
|
||
test_date = serializers.DateField(label="测试日期")
|
||
qct = serializers.CharField(label="检测表id")
|
||
|
||
def save(self, **kwargs):
|
||
from apps.qm.models import Ftest, FtestDefect, FtestItem
|
||
|
||
validated_data = self.validated_data
|
||
mlogbw_ids = validated_data["mlogbw_ids"]
|
||
test_equip_id = validated_data.get("test_equip")
|
||
test_user_id = validated_data["test_user"]
|
||
defect_ids = validated_data.get("defects", [])
|
||
testitem_ids = validated_data.get("testitems", [])
|
||
test_date = validated_data["test_date"]
|
||
qct_id = validated_data["qct"]
|
||
|
||
# 预加载相关对象
|
||
test_equip = Equipment.objects.get(id=test_equip_id) if test_equip_id else None
|
||
test_user = User.objects.get(id=test_user_id)
|
||
qct = Qct.objects.get(id=qct_id)
|
||
|
||
# 批量获取所有mlogbw对象
|
||
mlogbws = Mlogbw.objects.filter(id__in=mlogbw_ids).select_related('ftest')
|
||
|
||
# 预加载缺陷和测试项
|
||
defects = Defect.objects.filter(id__in=defect_ids) if defect_ids else []
|
||
testitems = FtestItem.objects.filter(id__in=testitem_ids) if testitem_ids else []
|
||
|
||
existing_ftests = {}
|
||
new_ftests = []
|
||
mlogbws_to_update = []
|
||
|
||
# 分离已存在和需要新建的ftest
|
||
for mlogbw in mlogbws:
|
||
if mlogbw.ftest:
|
||
existing_ftests[mlogbw.ftest_id] = mlogbw.ftest
|
||
else:
|
||
ftest = Ftest(test_date=test_date, qct=qct, test_user=test_user, type="process", id=idWorker.get_id(), is_ok=True)
|
||
new_ftests.append(ftest)
|
||
mlogbws_to_update.append(mlogbw)
|
||
|
||
# 批量创建新的ftest
|
||
if new_ftests:
|
||
Ftest.objects.bulk_create(new_ftests)
|
||
|
||
# 更新mlogbw的ftest关系
|
||
for mlogbw, ftest in zip(mlogbws_to_update, new_ftests):
|
||
mlogbw.ftest = ftest
|
||
Mlogbw.objects.bulk_update(mlogbws_to_update, ['ftest'])
|
||
|
||
# 将新创建的ftest添加到existing_ftests中
|
||
for ftest in new_ftests:
|
||
existing_ftests[ftest.id] = ftest
|
||
|
||
# 批量处理缺陷项(需要更新test_user)
|
||
if defects and existing_ftests:
|
||
# 获取所有现有的FtestDefect记录
|
||
existing_defect_ids = FtestDefect.objects.filter(
|
||
ftest_id__in=existing_ftests.keys(),
|
||
defect_id__in=[d.id for d in defects]
|
||
).values_list('defect_id', 'ftest_id')
|
||
|
||
existing_defect_map = {(defect_id, ftest_id) for defect_id, ftest_id in existing_defect_ids}
|
||
|
||
defects_to_create = []
|
||
defects_to_update = []
|
||
|
||
for ftest in existing_ftests.values():
|
||
for defect in defects:
|
||
if (defect.id, ftest.id) in existing_defect_map:
|
||
# 已有记录,需要更新
|
||
defects_to_update.append((ftest.id, defect.id))
|
||
else:
|
||
# 新记录,需要创建
|
||
defects_to_create.append(
|
||
FtestDefect(ftest=ftest, defect=defect, test_user=test_user, id=idWorker.get_id())
|
||
)
|
||
|
||
# 批量创建新记录
|
||
if defects_to_create:
|
||
FtestDefect.objects.bulk_create(defects_to_create)
|
||
|
||
# 批量更新已有记录的test_user
|
||
if defects_to_update:
|
||
FtestDefect.objects.filter(
|
||
ftest_id__in=[item[0] for item in defects_to_update],
|
||
defect_id__in=[item[1] for item in defects_to_update]
|
||
).update(test_user=test_user)
|
||
|
||
# 批量处理测试项(需要更新test_user和test_equip)
|
||
if testitems and existing_ftests:
|
||
# 获取所有现有的FtestItem记录
|
||
existing_testitem_ids = FtestItem.objects.filter(
|
||
ftest_id__in=existing_ftests.keys(),
|
||
testitem_id__in=[t.id for t in testitems]
|
||
).values_list('testitem_id', 'ftest_id')
|
||
|
||
existing_testitem_map = {(testitem_id, ftest_id) for testitem_id, ftest_id in existing_testitem_ids}
|
||
|
||
testitems_to_create = []
|
||
testitems_to_update_condition = Q()
|
||
|
||
for ftest in existing_ftests.values():
|
||
for testitem in testitems:
|
||
if (testitem.id, ftest.id) in existing_testitem_map:
|
||
# 已有记录,添加到更新条件
|
||
testitems_to_update_condition |= Q(ftest=ftest, testitem=testitem)
|
||
else:
|
||
# 新记录,需要创建
|
||
testitems_to_create.append(
|
||
FtestItem(
|
||
ftest=ftest,
|
||
testitem=testitem,
|
||
test_user=test_user,
|
||
test_equip=test_equip,
|
||
id=idWorker.get_id()
|
||
)
|
||
)
|
||
|
||
# 批量创建新记录
|
||
if testitems_to_create:
|
||
FtestItem.objects.bulk_create(testitems_to_create)
|
||
|
||
# 批量更新已有记录的test_user和test_equip
|
||
if testitems_to_update_condition:
|
||
FtestItem.objects.filter(testitems_to_update_condition).update(
|
||
test_user=test_user,
|
||
test_equip=test_equip
|
||
)
|
||
|
||
class MlogbOutUpdateSerializer(CustomModelSerializer):
|
||
mlogbdefect = MlogbDefectSerializer(many=True, required=False)
|
||
count_json = CountJsonSerializer(required=False, many=True)
|
||
|
||
class Meta:
|
||
model = Mlogb
|
||
fields = "__all__"
|
||
read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out',
|
||
'count_use', 'count_break', 'count_pn_jgqbl', 'mlogbdefect', "qct", "count_json"]
|
||
|
||
def update(self, instance, validated_data):
|
||
mlog:Mlog = instance.mlog
|
||
if mlog.submit_time is not None:
|
||
raise ParseError('生产日志已提交不可编辑')
|
||
mlogbdefect = validated_data.pop("mlogbdefect", None)
|
||
|
||
ins:Mlogb = super().update(instance, validated_data)
|
||
if ins.need_inout is False:
|
||
if ins.mlogb_from:
|
||
if Mlogb.objects.filter(mlog=ins.mlog, material_out__isnull=False, mlogb_from=ins.mlogb_from).count() == 1:
|
||
ins_from = ins.mlogb_from
|
||
ins_from.need_inout = False
|
||
ins_from.save(update_fields=["need_inout"])
|
||
else:
|
||
raise ParseError("对应消耗的产出有多个, 需手动指定消耗是否出库")
|
||
else:
|
||
raise ParseError("该产出需入库!")
|
||
else:
|
||
if ins.mlogb_from:
|
||
ins_from = ins.mlogb_from
|
||
ins_from.need_inout = True
|
||
ins_from.save(update_fields=["need_inout"])
|
||
if mlogbdefect is not None and ins.material_out.tracking == Material.MA_TRACKING_BATCH:
|
||
MlogbDefect.objects.filter(mlogb=ins).delete()
|
||
mlogb_defect_objects = [
|
||
MlogbDefect(**{**item, "mlogb": ins, "id": idWorker.get_id()})
|
||
for item in mlogbdefect if item["count"] > 0
|
||
]
|
||
if mlogb_defect_objects:
|
||
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
|
||
ins.cal_count_notok(cal_mlog=False)
|
||
return ins
|
||
|
||
def validate(self, attrs):
|
||
mlogbdefect = attrs.get("mlogbdefect", [])
|
||
if mlogbdefect:
|
||
attrs.pop("count_notok_json", None)
|
||
for k in list(attrs.keys()):
|
||
if 'count_n_' in k:
|
||
attrs.pop(k, None)
|
||
else:
|
||
count_notok_json = attrs.get('count_notok_json', [])
|
||
# count_notok_json字段处理
|
||
if count_notok_json:
|
||
# 先置0字段
|
||
for k in list(attrs.keys()):
|
||
if 'count_n_' in k:
|
||
attrs[k] = 0
|
||
count_notok_dict = {}
|
||
for item in count_notok_json:
|
||
notok = item['notok']
|
||
count = item['count']
|
||
full_notok = f'count_n_{notok}'
|
||
if not hasattr(Mlogb, full_notok):
|
||
raise ParseError(f'{notok}-该不合格项不存在')
|
||
if full_notok in count_notok_dict:
|
||
count_notok_dict[full_notok] = count_notok_dict[full_notok] + count
|
||
else:
|
||
count_notok_dict[full_notok] = count
|
||
for k, v in count_notok_dict.items():
|
||
attrs[k] = v
|
||
|
||
count_notok = 0
|
||
for k in list(attrs.keys()):
|
||
if 'count_n_' in k:
|
||
if not hasattr(Mlogb, k):
|
||
raise ParseError(f'{k}不存在')
|
||
count_notok = count_notok + attrs[k]
|
||
attrs['count_notok'] = count_notok
|
||
if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']:
|
||
pass
|
||
else:
|
||
raise ParseError('生产数量不能小于合格数量')
|
||
return attrs
|
||
|
||
class MlogRevertSerializer(serializers.Serializer):
|
||
change_reason = serializers.CharField(label='撤回原因')
|
||
|
||
|
||
class MlogRelatedSerializer(serializers.Serializer):
|
||
mtask = serializers.PrimaryKeyRelatedField(
|
||
label='小任务ID', queryset=Mtask.objects.all())
|
||
|
||
|
||
class DeptBatchSerializer(serializers.Serializer):
|
||
belong_dept_name = serializers.CharField(label='车间名称')
|
||
|
||
class Handoverbwserializer(CustomModelSerializer):
|
||
class Meta:
|
||
model = Handoverbw
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS_BASE + ["handoverb", "number"]
|
||
extra_kwargs = {'wpr': {'required': True}}
|
||
|
||
class HandoverbSerializer(CustomModelSerializer):
|
||
notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True)
|
||
defect_name = serializers.CharField(source="wm.defect.name", read_only=True)
|
||
handoverbw = Handoverbwserializer(many=True, required=False)
|
||
class Meta:
|
||
model = Handoverb
|
||
fields = "__all__"
|
||
read_only_fields = EXCLUDE_FIELDS_BASE + ['handover']
|
||
extra_kwargs = {'wm': {'required': True}}
|
||
|
||
class HandoverbListSerializer(CustomModelSerializer):
|
||
defect_name = serializers.CharField(source="wm.defect.name", read_only=True)
|
||
class Meta:
|
||
model = Handoverb
|
||
fields = "__all__"
|
||
|
||
class HandoverSerializer(CustomModelSerializer):
|
||
# 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(
|
||
source='recive_user.name', read_only=True)
|
||
recive_dept_name = serializers.CharField(
|
||
source='recive_dept', read_only=True)
|
||
send_mgroup_name = serializers.CharField(source='send_mgroup.name', read_only=True)
|
||
recive_mgroup_name = serializers.CharField(source='recive_mgroup.name', read_only=True)
|
||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||
material_name = serializers.StringRelatedField(
|
||
source='material', read_only=True)
|
||
wm_notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True)
|
||
handoverb = HandoverbSerializer(many=True, required=False)
|
||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||
|
||
def validate(self, attrs):
|
||
if "mtype" not in attrs:
|
||
attrs['mtype'] = Handover.H_NORMAL
|
||
mtype = attrs["mtype"]
|
||
if 'type' not in attrs:
|
||
attrs['type'] = Handover.H_NORMAL
|
||
if attrs["type"] == Handover.H_CHANGE:
|
||
if "material_changed" not in attrs:
|
||
raise ParseError("必须指定改版后的物料")
|
||
|
||
if mtype == Handover.H_MERGE:
|
||
new_state = None
|
||
new_wm:WMaterial = attrs.get("new_wm", None)
|
||
if new_wm:
|
||
attrs['new_batch'] = new_wm.batch
|
||
new_state = new_wm.state
|
||
new_defect = new_wm.defect
|
||
if not attrs.get("new_batch", None):
|
||
raise ParseError("必须指定合并后的批次")
|
||
|
||
|
||
wm:WMaterial = attrs.get('wm', None)
|
||
if wm:
|
||
attrs["batch"] = wm.batch
|
||
handoverb = attrs.get('handoverb', [])
|
||
if wm and not handoverb:
|
||
attrs['handoverb'] = [{"wm": wm, "count": attrs["count"] }]
|
||
handoverb = attrs['handoverb']
|
||
attrs['batch'] = wm.batch
|
||
elif handoverb:
|
||
wm: WMaterial = handoverb[0]["wm"]
|
||
if wm:
|
||
pass
|
||
else:
|
||
raise ParseError('必须指定车间库存')
|
||
attrs['material'] = wm.material
|
||
attrs['send_dept'] = wm.belong_dept
|
||
if wm.mgroup:
|
||
attrs['send_mgroup'] = wm.mgroup
|
||
if attrs['material'].process and attrs['material'].process.into_wm_mgroup and 'recive_mgroup' not in attrs:
|
||
raise ParseError('必须指定交接工段')
|
||
if 'recive_mgroup' in attrs and attrs['recive_mgroup']:
|
||
attrs['recive_dept'] = attrs['recive_mgroup'].belong_dept
|
||
if not attrs.get('recive_dept', None) and not attrs.get('recive_mgroup', None):
|
||
raise ParseError('必须指定收料车间或收料工段')
|
||
if not attrs.get('send_dept', None) and not attrs.get('send_mgroup', None):
|
||
raise ParseError('必须指定送料车间或送料工段')
|
||
|
||
if attrs["mtype"] == Handover.H_NORMAL and attrs.get("recive_mgroup", None) == attrs.get("send_mgroup", None):
|
||
raise ParseError('正常交接收料工段与送料工段不能相同')
|
||
t_count = 0
|
||
tracking = attrs["material"].tracking
|
||
for ind, item in enumerate(attrs['handoverb']):
|
||
if item["count"] > 0:
|
||
pass
|
||
else:
|
||
raise ParseError(f'第{ind+1}行-交接数量必须大于0')
|
||
wm = item["wm"]
|
||
if mtype == Handover.H_MERGE:
|
||
if new_state is None:
|
||
new_mat = wm.material
|
||
new_state = wm.state
|
||
new_defect = wm.defect
|
||
else:
|
||
if new_mat != wm.material:
|
||
raise ParseError(f'第{ind+1}行-合并的物料不一致')
|
||
if new_state != wm.state:
|
||
raise ParseError(f'第{ind+1}行-合并的物料状态不一致')
|
||
if new_defect != wm.defect:
|
||
raise ParseError(f'第{ind+1}行-合并的物料缺陷不一致')
|
||
if tracking == Material.MA_TRACKING_SINGLE:
|
||
handoverbw = item.get("handoverbw", [])
|
||
if handoverbw:
|
||
item["count"] = len(handoverbw)
|
||
t_count += len(handoverbw)
|
||
wprIds = [i["wpr"].id for i in handoverbw]
|
||
wm_ids = list(Wpr.objects.filter(id__in=wprIds).values_list("wm_id", flat=True).distinct())
|
||
if len(wm_ids) == 1 and wm_ids[0] == wm.id:
|
||
pass
|
||
else:
|
||
raise ParseError(f'{wm.batch}物料明细中存在{len(wm_ids)}个不同物料批次')
|
||
|
||
elif wm.count == item["count"]:
|
||
t_count += item["count"]
|
||
else:
|
||
raise ParseError(f'第{ind+1}行-请提供交接物料明细编号')
|
||
else:
|
||
t_count += item["count"]
|
||
# if wm.mgroup and wm.mgroup != attrs['send_mgroup']:
|
||
# raise ParseError(f'第{ind+1}物料与交接工段不一致')
|
||
# if wm.belong_dept and wm.belong_dept != attrs['send_dept']:
|
||
# raise ParseError(f'第{ind+1}物料与交接部门不一致')
|
||
if attrs["material"] != wm.material:
|
||
raise ParseError(f'第{ind+1}物料与交接物料不一致')
|
||
# if wm.state != WMaterial.WM_OK and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]:
|
||
# raise ParseError(f'第{ind+1}物料不合格,不能进行正常/检验交接')
|
||
if wm.count_xtest is not None:
|
||
raise ParseError(f'第{ind+1}物料检验中,不能进行交接')
|
||
attrs["count"] = t_count
|
||
if attrs['type'] == Handover.H_REPAIR:
|
||
# 返修时还是该物料
|
||
recive_mgroup = attrs.get("recive_mgroup", None)
|
||
if recive_mgroup is None:
|
||
raise ParseError('返工交接需指定工段')
|
||
return attrs
|
||
|
||
class Meta:
|
||
model = Handover
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS + ["mlog"]
|
||
extra_kwargs = {
|
||
"type": {"required": False},
|
||
"wm": {"required": False},
|
||
"send_dept": {"required": False},
|
||
"recive_mgroup": {"required": False},
|
||
"recive_dept": {"required": False},
|
||
"material": {"required": False},
|
||
"material_changed": {"required": False},
|
||
"batch": {"required": False},
|
||
"count": {"required": False},
|
||
"count_eweight": {"required": False}
|
||
}
|
||
|
||
def create(self, validated_data):
|
||
handoverb = validated_data.pop('handoverb', [])
|
||
ins = super().create(validated_data)
|
||
mtype = validated_data["mtype"]
|
||
for ind, item in enumerate(handoverb):
|
||
wm = item["wm"]
|
||
count = item["count"]
|
||
handoverbw = item.pop("handoverbw", [])
|
||
if mtype == Handover.H_DIV:
|
||
if not item["batch"]:
|
||
raise ParseError(f'第{ind+1}行-请提供拆批批次号')
|
||
if ins.wm is None:
|
||
raise ParseError("请提供拆批库存")
|
||
handoverb = Handoverb.objects.create(handover=ins, batch=item["batch"], count=count, wm=ins.wm)
|
||
else:
|
||
handoverb = Handoverb.objects.create(handover=ins, wm=wm, count=count, batch=wm.batch)
|
||
if wm.material.tracking == Material.MA_TRACKING_SINGLE:
|
||
if handoverbw:
|
||
handoverb.count = len(handoverbw)
|
||
handoverb.save()
|
||
for item in handoverbw:
|
||
wpr = item["wpr"]
|
||
Handoverbw.objects.get_or_create(wpr=wpr, handoverb=handoverb, defaults={"number":wpr.number, "note": item.get("note", None)})
|
||
elif count == wm.count:
|
||
for item in Wpr.get_qs_by_wm(wm):
|
||
Handoverbw.objects.get_or_create(wpr=item, handoverb=handoverb, defaults={"number":item.number})
|
||
else:
|
||
raise ParseError(f'第{ind+1}行-请提供交接物料明细编号')
|
||
return ins
|
||
|
||
def update(self, instance, validated_data):
|
||
handoverb = validated_data.pop('handoverb', [])
|
||
|
||
insx = super().update(instance, validated_data)
|
||
Handoverb.objects.filter(handover=instance).delete()
|
||
for ind, item in enumerate(handoverb):
|
||
wm = item["wm"]
|
||
count = item["count"]
|
||
handoverbw = item.pop("handoverbw", [])
|
||
if validated_data["mtype"] == Handover.H_DIV:
|
||
if not item["batch"]:
|
||
raise ParseError(f'第{ind+1}行-请提供拆批批次号')
|
||
if insx.wm is None:
|
||
raise ParseError("请提供拆批库存")
|
||
hb, _ = Handoverb.objects.get_or_create(handover=instance, batch=item["batch"], wm=insx.wm,
|
||
defaults={"count": count})
|
||
else:
|
||
hb, _ = Handoverb.objects.get_or_create(handover=instance, wm=wm, defaults={"count": count,
|
||
"batch": wm.batch})
|
||
if wm.material.tracking == Material.MA_TRACKING_SINGLE:
|
||
Handoverbw.objects.filter(handoverb=hb).delete()
|
||
if handoverbw:
|
||
hb.count = len(handoverbw)
|
||
hb.save()
|
||
for item in handoverbw:
|
||
wpr = item["wpr"]
|
||
Handoverbw.objects.get_or_create(wpr=wpr, handoverb=hb, defaults={"number": wpr.number, "note": item.get("note", None)})
|
||
elif count == wm.count:
|
||
wpr_qs = Wpr.get_qs_by_wm(wm)
|
||
for item in wpr_qs:
|
||
Handoverbw.objects.get_or_create(wpr=item, handoverb=handoverb,
|
||
defaults={"number": item.number})
|
||
else:
|
||
raise ParseError(f'第{ind+1}行-请提供交接物料明细')
|
||
return instance
|
||
|
||
class HandoverUpdateSerializer(CustomModelSerializer):
|
||
class Meta:
|
||
model = Handover
|
||
fields = ['id', 'send_date', 'send_user', 'count', 'count_eweight', 'recive_user', 'note']
|
||
|
||
class HandoverListSerializer(HandoverSerializer):
|
||
handoverb = HandoverbListSerializer(many=True, required=False)
|
||
|
||
|
||
class GenHandoverSerializer(serializers.Serializer):
|
||
mlogs = serializers.PrimaryKeyRelatedField(
|
||
label='mlog的ID列表', queryset=Mlog.objects.all(), many=True)
|
||
recive_dept = serializers.PrimaryKeyRelatedField(
|
||
label='交送车间', queryset=Dept.objects.all())
|
||
recive_user = serializers.PrimaryKeyRelatedField(
|
||
label='接收人', queryset=User.objects.all())
|
||
send_user = serializers.PrimaryKeyRelatedField(
|
||
label='交送人', queryset=User.objects.all())
|
||
send_date = serializers.DateField(label='交送日期')
|
||
|
||
|
||
class GenHandoverWmSerializer(serializers.Serializer):
|
||
wm = serializers.PrimaryKeyRelatedField(
|
||
label='车间物料ID', queryset=WMaterial.objects.all())
|
||
send_mgroup = serializers.PrimaryKeyRelatedField(
|
||
label='送料工段ID', queryset=Mgroup.objects.all())
|
||
recive_dept = serializers.PrimaryKeyRelatedField(
|
||
label='交送车间', queryset=Dept.objects.all())
|
||
recive_user = serializers.PrimaryKeyRelatedField(
|
||
label='接收人', queryset=User.objects.all())
|
||
send_user = serializers.PrimaryKeyRelatedField(
|
||
label='交送人', queryset=User.objects.all())
|
||
send_date = serializers.DateField(label='交送日期')
|
||
count = serializers.IntegerField(label='交送数量')
|
||
|
||
def validate(self, attrs):
|
||
if attrs['count'] <= 1:
|
||
raise ParseError('交送数量必须大于1')
|
||
return attrs
|
||
|
||
|
||
class MlogAnaSerializer(serializers.Serializer):
|
||
belong_dept_name = serializers.CharField(label='车间名', required=False)
|
||
start_date = serializers.DateField(label='开始日期', required=True)
|
||
end_date = serializers.DateField(label='结束日期', required=True)
|
||
material_cate = serializers.CharField(label='物料系列', required=False)
|
||
|
||
|
||
class AttLogSerializer(CustomModelSerializer):
|
||
mgroup_name = serializers.CharField(
|
||
source='sflog.mgroup.name', read_only=True)
|
||
user_name = serializers.CharField(source='user.name', read_only=True)
|
||
post_name = serializers.CharField(source='post.name', read_only=True)
|
||
belong_dept_name = serializers.CharField(
|
||
source='sflog.mgroup.belong_dept.name', read_only=True)
|
||
|
||
class Meta:
|
||
model = AttLog
|
||
fields = '__all__'
|
||
|
||
|
||
class FmlogSerializer(CustomModelSerializer):
|
||
# routepack_name = serializers.CharField(
|
||
# source='mtask.route.routepack.name', read_only=True)
|
||
route_name = serializers.StringRelatedField(source="route", read_only=True)
|
||
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
||
mtask_number = serializers.CharField(source='mtask.number', read_only=True)
|
||
class Meta:
|
||
model = Fmlog
|
||
fields = '__all__'
|
||
read_only_fields = EXCLUDE_FIELDS
|
||
|
||
def validate(self, attrs):
|
||
is_fix = attrs.get("is_fix", False)
|
||
if is_fix:
|
||
attrs["mtask"] = None
|
||
attrs['route'] = None
|
||
elif not attrs.get("mtask", None) and not attrs.get("route", None):
|
||
raise ParseError("请选择任务或工艺步骤")
|
||
mtask: Mtask = attrs['mtask']
|
||
if mtask and mtask.state != Mtask.MTASK_ASSGINED:
|
||
raise ParseError('该任务非下达中不可选择')
|
||
if mtask:
|
||
attrs["route"] = mtask.route
|
||
return attrs
|
||
|
||
class FmlogUpdateSerializer(CustomModelSerializer):
|
||
class Meta:
|
||
model = Fmlog
|
||
fields = ['id', 'note', 'enabled']
|
||
|
||
|
||
class MlogTCreateSerializer(CustomModelSerializer):
|
||
pass
|
||
|
||
|
||
class BatchStSerializer(CustomModelSerializer):
|
||
material_start_name = serializers.CharField(source='material_start.name', read_only=True)
|
||
material_start_model = serializers.CharField(source='material_start.model', read_only=True)
|
||
material_start_specification = serializers.CharField(source='material_start.specification', read_only=True)
|
||
class Meta:
|
||
model = BatchSt
|
||
fields = "__all__"
|
||
|
||
|
||
class HandoverMgroupSerializer(serializers.Serializer):
|
||
material = serializers.CharField(label="物料ID")
|
||
type = serializers.IntegerField(label="交送类型")
|
||
|
||
|
||
class MlogUserSerializer(CustomModelSerializer):
|
||
handle_user_name = serializers.CharField(source='handle_user.name', read_only=True)
|
||
process_name = serializers.CharField(source='process.name', read_only=True)
|
||
shift_name = serializers.CharField(source='shift.name', read_only=True)
|
||
class Meta:
|
||
model = MlogUser
|
||
fields = "__all__"
|
||
read_only_fields = EXCLUDE_FIELDS_BASE
|
||
|
||
def create(self, validated_data):
|
||
mlog:Mlog = validated_data["mlog"]
|
||
if mlog.submit_time is not None:
|
||
raise ParseError("该日志已提交")
|
||
process:Process = validated_data["process"]
|
||
if mlog.route:
|
||
p = mlog.route.process
|
||
if process.parent != p:
|
||
raise ParseError("该步骤不匹配")
|
||
else:
|
||
raise ParseError("该日志没有工艺步骤")
|
||
if MlogUser.objects.filter(mlog=mlog, process=process).exists():
|
||
raise ParseError("该工序已选择")
|
||
return super().create(validated_data)
|
||
|
||
|
||
class BatchLogSerializer(CustomModelSerializer):
|
||
source_batch = serializers.CharField(source='source.batch', read_only=True)
|
||
target_batch = serializers.CharField(source='target.batch', read_only=True)
|
||
class Meta:
|
||
model = BatchLog
|
||
fields = "__all__"
|
||
|
||
|
||
class BatchMgroupSerializer(serializers.Serializer):
|
||
# mgroup = serializers.PrimaryKeyRelatedField(
|
||
# label='工段', queryset=Mgroup.objects.all())
|
||
mgroup_name = serializers.CharField(label="工段名")
|
||
|
||
|
||
class MlogQuickSerializer(serializers.Serializer):
|
||
work_start_time = serializers.DateTimeField(label="开始时间")
|
||
# handle_date = serializers.DateField(label="操作日期")
|
||
work_end_time = serializers.DateTimeField(label="结束时间", required=False)
|
||
team = serializers.CharField(label="班组ID", required=False)
|
||
equipment = serializers.CharField(label="设备ID", required=False)
|
||
wm_in = serializers.CharField(label="输入车间库存ID")
|
||
wprs_in = serializers.ListField(child=serializers.CharField(), label="单个ID的列表", required=False)
|
||
count_use = serializers.IntegerField(label="领用数量")
|
||
is_fix = serializers.BooleanField(label="是否返修")
|
||
mgroup = serializers.CharField(label="工段ID")
|
||
route = serializers.CharField(label="工艺步骤ID", required=False)
|
||
mtask = serializers.CharField(label="任务ID", required=False)
|
||
handle_user = serializers.CharField(label="操作人员ID") |