1251 lines
56 KiB
Python
1251 lines
56 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
|
|
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', '')
|
|
with transaction.atomic():
|
|
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)
|
|
# if instance.end_time:
|
|
# raise ParseError('该异常已结束无需编辑')
|
|
with transaction.atomic():
|
|
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='在制数量')
|
|
|
|
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)
|
|
ret['count_cando'] = str(Decimal(ret['count']) - Decimal(ret['count_working']))
|
|
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"]
|
|
read_only_fields = EXCLUDE_FIELDS_BASE + ["mlogb"]
|
|
|
|
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):
|
|
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)
|
|
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
|
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
|
|
handle_users_ = UserSimpleSerializer(
|
|
source='handle_users', many=True, read_only=True)
|
|
|
|
class Meta:
|
|
model = Mlog
|
|
fields = '__all__'
|
|
|
|
|
|
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)
|
|
|
|
class Meta:
|
|
model = Mlogb
|
|
fields = '__all__'
|
|
|
|
class MlogSerializer(CustomModelSerializer):
|
|
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)
|
|
|
|
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']
|
|
extra_kwargs = {
|
|
"batch": {"required": True},
|
|
"shift": {"required": True},
|
|
"material_out": {"required": True}
|
|
}
|
|
|
|
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('该任务非下达中不可选择')
|
|
with transaction.atomic():
|
|
mlogb = validated_data.pop('mlogb', [])
|
|
instance: Mlog = super().create(validated_data)
|
|
# 自动生成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,
|
|
'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()
|
|
|
|
# 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,
|
|
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,
|
|
'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()
|
|
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)
|
|
with transaction.atomic():
|
|
mlogb = validated_data.pop('mlogb', [])
|
|
instance: Mlog = super().update(instance, validated_data)
|
|
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()
|
|
|
|
# 修改产出
|
|
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_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()
|
|
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)
|
|
if fmlog:
|
|
attrs['fill_way'] = Mlog.MLOG_12
|
|
wm_in: WMaterial = attrs.get('wm_in', None)
|
|
if wm_in:
|
|
pass
|
|
else:
|
|
raise ParseError('未提供消耗的车间物料')
|
|
attrs['mgroup'] = fmlog.mgroup
|
|
attrs['mtask'] = fmlog.mtask
|
|
attrs['mtype'] = fmlog.mgroup.mtype
|
|
if attrs['mtask'] and attrs['mtask'].route:
|
|
attrs['route'] = attrs['mtask'].route
|
|
# if attrs['mtask'].mtaskb and mtaskb is None:
|
|
# raise ParseError('子任务不能为空')
|
|
if mtaskb and mtaskb.mtask != fmlog.mtask:
|
|
raise ParseError('子任务不一致')
|
|
if wm_in.state in [WMaterial.WM_OK]:
|
|
pass
|
|
else:
|
|
raise ParseError('非合格品不可使用')
|
|
if wm_in.material != attrs['mtask'].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)
|
|
count_notok = 0
|
|
for i in attrs:
|
|
if 'count_n_' in i:
|
|
count_notok = count_notok + attrs[i]
|
|
attrs['count_notok'] = count_notok
|
|
if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']:
|
|
pass
|
|
else:
|
|
raise ParseError('生产数量不能小于合格数量')
|
|
if mtask:
|
|
if mtask.start_date == mtask.end_date:
|
|
attrs['handle_date'] = mtask.start_date
|
|
else:
|
|
if attrs.get('work_end_time', None):
|
|
attrs['handle_date'] = localdate(attrs['work_end_time'])
|
|
elif attrs.get('work_start_time', None):
|
|
attrs['handle_date'] = localdate(attrs['work_start_time'])
|
|
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
|
|
attrs['material_out'] = material_out
|
|
if mtask.start_date == mtask.end_date:
|
|
attrs['handle_date'] = mtask.end_date
|
|
else:
|
|
mgroup = attrs['mgroup']
|
|
material_out = attrs['material_out']
|
|
if not (mgroup and material_out):
|
|
raise ParseError('缺少工段或产物!')
|
|
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']
|
|
read_only_fields = ["mtype"]
|
|
extra_kwargs = {
|
|
'work_start_time': {'required': True},
|
|
'route':{'required': False},
|
|
'mgroup': {'required': True},
|
|
'mtype': {'required': True}
|
|
}
|
|
|
|
def validate(self, attrs):
|
|
route: Route = attrs.get('route', None)
|
|
mgroup: Mgroup = attrs['mgroup']
|
|
is_fix:bool = attrs.get('is_fix', False)
|
|
attrs['mtype'] = mgroup.mtype
|
|
if is_fix:
|
|
attrs["route"] = None
|
|
elif route is None:
|
|
raise ParseError('缺少工艺路线')
|
|
if route and route.process != mgroup.process:
|
|
raise ParseError('工序不匹配')
|
|
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 attrs['mtype'] == Mlog.MTYPE_OUT:
|
|
supplier = attrs.get('supplier', None)
|
|
if not supplier:
|
|
raise ParseError('外协必须选择外协单位')
|
|
if attrs.get('work_end_time', None):
|
|
attrs['handle_date'] = localdate(attrs['work_end_time'])
|
|
if attrs["material_out"]:
|
|
attrs["qct"] = Qct.get(attrs["material_out"], "process")
|
|
return attrs
|
|
|
|
class MlogChangeSerializer(CustomModelSerializer):
|
|
class Meta:
|
|
model = Mlog
|
|
fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file', 'test_user', 'test_time', 'equipment']
|
|
|
|
def validate(self, attrs):
|
|
if attrs.get('work_end_time', None):
|
|
attrs['handle_date'] = localdate(attrs['work_end_time'])
|
|
return attrs
|
|
|
|
|
|
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)
|
|
|
|
class Meta:
|
|
model = Mlogb
|
|
fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_pn_jgqbl',
|
|
'count_break', 'note', "parent", "mlogbdefect", "count_json_from"]
|
|
extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': False},
|
|
'wm_in': {'required': True, "allow_empty": False}}
|
|
|
|
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 is_fix: # 返修或复检
|
|
if wm_in.state in [WMaterial.WM_REPAIR, WMaterial.WM_NOTOK]:
|
|
raise ParseError('返修或复检需使用返修品/不合格品')
|
|
elif wm_in.state != WMaterial.WM_OK:
|
|
raise ParseError('非合格品不可使用')
|
|
if mtask and mlog.route != mtask.route:
|
|
raise ParseError('工序不匹配')
|
|
route = mlog.route
|
|
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
|
|
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)
|
|
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('生产日志已提交不可编辑')
|
|
with transaction.atomic():
|
|
ins:Mlogb = super().create(validated_data)
|
|
if mlog.is_fix:
|
|
if mlog.material_in is None:
|
|
mlog.material_in = ins.material_in
|
|
mlog.material_out = ins.material_in
|
|
mlog.save(update_fields=["material_in", "material_out"])
|
|
elif mlog.material_in != ins.material_in:
|
|
raise ParseError('该记录必须使用同一物料')
|
|
|
|
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()
|
|
return ins
|
|
|
|
class MlogbInUpdateSerializer(CustomModelSerializer):
|
|
mlogbdefect = MlogbDefectSerializer(many=True, required=False)
|
|
class Meta:
|
|
model = Mlogb
|
|
fields = ['id', 'count_use', 'count_pn_jgqbl', 'note', 'mlogbdefect']
|
|
|
|
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 = 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_notok()
|
|
return ins
|
|
|
|
class MlogbwCreateUpdateSerializer(CustomModelSerializer):
|
|
ftest = FtestProcessSerializer(required=False)
|
|
class Meta:
|
|
model = Mlogbw
|
|
fields = ["id", "number", "wpr", "note", "mlogb", "ftest", "equip", "work_start_time", "work_end_time", "mlogbw_from"]
|
|
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' and not wpr:
|
|
raise ParseError('请选择相应产品')
|
|
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
|
|
|
|
@transaction.atomic
|
|
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('该产品已选入')
|
|
ftest_data = validated_data.pop("ftest", None)
|
|
mlogbw = super().create(validated_data)
|
|
if ftest_data:
|
|
mlogbw = self.save_ftest(mlogbw, ftest_data)
|
|
return mlogbw
|
|
|
|
@transaction.atomic
|
|
def update(self, instance, validated_data):
|
|
validated_data.pop("mlogb")
|
|
ftest_data = validated_data.pop("ftest", None)
|
|
mlogbw = super().update(instance, validated_data)
|
|
if ftest_data:
|
|
mlogbw = self.save_ftest(mlogbw, ftest_data)
|
|
return mlogbw
|
|
|
|
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", "batch", "count_json"]
|
|
|
|
# def create(self, validated_data):
|
|
# material_out:Material = validated_data["material_out"]
|
|
# mlogbdefect = validated_data.pop("mlogbdefect", [])
|
|
# with transaction.atomic():
|
|
# ins = super().create(validated_data)
|
|
# if mlogbdefect and material_out.tracking == Material.MA_TRACKING_BATCH:
|
|
# count_notok = 0
|
|
# mlogbdefect_new = [item for item in mlogbdefect if item["count"] > 0]
|
|
# for item in mlogbdefect_new:
|
|
# defect:Defect = item["defect"]
|
|
# MlogbDefect.objects.create(mlogb=ins, **item)
|
|
# if defect.cate == Defect.DEFECT_NOTOK:
|
|
# count_notok +=1
|
|
# ins.count_notok = count_notok
|
|
# ins.count_ok = ins.count_real - ins.count_notok
|
|
# ins.save()
|
|
# else:
|
|
# raise ParseError("mlogbdefect仅支持批次件")
|
|
# return ins
|
|
@transaction.atomic
|
|
def update(self, instance, validated_data):
|
|
mlogbdefect = validated_data.pop("mlogbdefect", None)
|
|
with transaction.atomic():
|
|
ins:Mlogb = super().update(instance, validated_data)
|
|
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()
|
|
return ins
|
|
|
|
def validate(self, attrs):
|
|
mlogbdefect = attrs.get("mlogbdefect", [])
|
|
if mlogbdefect:
|
|
attrs.pop("count_notok_json", None)
|
|
for i in attrs:
|
|
if 'count_n_' in i:
|
|
attrs.pop(i, None)
|
|
else:
|
|
count_notok_json = attrs.get('count_notok_json', [])
|
|
# count_notok_json字段处理
|
|
if count_notok_json:
|
|
# 先置0字段
|
|
for i in attrs:
|
|
if 'count_n_' in i:
|
|
i = 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 i in attrs:
|
|
if 'count_n_' in i:
|
|
if not hasattr(Mlogb, i):
|
|
raise ParseError(f'{i}不存在')
|
|
count_notok = count_notok + attrs[i]
|
|
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 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)
|
|
|
|
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)
|
|
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 'recive_dept' not in attrs and 'recive_mgroup' not in attrs:
|
|
raise ParseError('收料车间和收料工段必须有一个')
|
|
if 'send_dept' not in attrs and 'send_mgroup' not in attrs:
|
|
raise ParseError('送料车间和送料工段必须有一个')
|
|
t_count = 0
|
|
tracking = attrs["material"].tracking
|
|
for ind, item in enumerate(attrs['handoverb']):
|
|
wm = item["wm"]
|
|
if mtype == Handover.H_MERGE:
|
|
if new_state is None:
|
|
new_state = wm.state
|
|
new_defect = wm.defect
|
|
else:
|
|
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:
|
|
t_count += len(handoverbw)
|
|
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', [])
|
|
with transaction.atomic():
|
|
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', [])
|
|
with transaction.atomic():
|
|
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 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
|
|
elif not attrs.get("mtask", None) or 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):
|
|
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__"
|
|
|