factory/apps/wpm/serializers.py

614 lines
26 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 ValidationError, ParseError
from datetime import datetime
from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog, Fmlog
from apps.system.models import Dept, User
from apps.system.serializers import UserSimpleSerializer
from apps.pm.models import Mtask
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
from apps.mtm.models import Mgroup, TeamMember, Shift, Material, Route
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
from apps.wf.serializers import TicketSimpleSerializer
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.stlog, 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):
with transaction.atomic():
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 == '回转窑' and instance.shift.name in ['早班', '白班']:
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)
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_origin_name = serializers.StringRelatedField(source='material_origin', read_only=True)
notok_sign_name = serializers.SerializerMethodField()
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__'
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']
extra_kwargs = {
'material_out': {'required': True, 'allow_null': False}}
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)
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)
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)
handovers = serializers.PrimaryKeyRelatedField(
source='handover_mlog', read_only=True, many=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 = serializers.PrimaryKeyRelatedField(
label='班次ID', queryset=Shift.objects.all(), required=True)
mgroup = serializers.PrimaryKeyRelatedField(
label='工段ID', queryset=Mgroup.objects.all(), required=True
)
material_out = serializers.PrimaryKeyRelatedField(
label='产物ID', queryset=Material.objects.all(), required=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)
equipments_name = serializers.StringRelatedField(
source='equipments', read_only=True, many=True)
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
class Meta:
model = Mlog
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS + \
['submit_time', 'submit_user', 'material_outs']
extra_kwargs = {
"batch": {"required": True}
}
def create(self, validated_data):
mtask: Mtask = validated_data.get('mtask', None)
if mtask:
validated_data['mgroup'] = mtask.mgroup
validated_data['material_in'] = mtask.material_in
material_out = mtask.material_out
validated_data['material_out'] = material_out
validated_data['handle_date'] = mtask.end_date
else:
mgroup = validated_data['mgroup']
material_out = validated_data['material_out']
if not (mgroup and material_out):
raise ValidationError('缺少工段或产物!')
with transaction.atomic():
mlogb = validated_data.pop('mlogb', [])
instance: Mlog = super().create(validated_data)
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:
Mlogb.objects.create(
mlog=instance, batch=instance.batch, mtask=instance.mtask, material_out=item['material_out'], count_ok=item['count_ok'])
else:
raise ValidationError('缺少产出物信息')
return instance
def update(self, instance, validated_data):
validated_data.pop('mtask', None)
validated_data.pop('mgroup', 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 = super().update(instance, validated_data)
if mlogb:
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).update(count_ok=0)
for item in mlogb:
Mlogb.objects.filter(mlog=instance, material_out=item['material_out']).update(
count_ok=item['count_ok'])
return instance
def validate(self, attrs):
attrs['fill_way'] = Mlog.MLOG_ONETIME
attrs['mtype'] = Mlog.MTYPE_SELF # 默认为自生产
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 ValidationError('生产数量不能小于合格数量')
if mtask:
if mtask.start_date == mtask.end_date:
attrs['handle_date'] = mtask.start_date
else:
if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date:
pass
else:
raise ValidationError('操作日期错误')
return attrs
class MlogInitSerializer(CustomModelSerializer):
class Meta:
model = Mlog
fields = ['id', 'work_start_time', 'mgroup', 'reminder_interval_list', 'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier']
extra_kwargs = {
'work_start_time': {'required': True},
'route':{'required': True},
'mgroup': {'required': True},
'mtype': {'required': True}
}
def validate(self, attrs):
mtype = attrs['mtype']
route: Route = attrs['route']
mgroup: Mgroup = attrs['mgroup']
if route.process != mgroup.process:
raise ValidationError('工序不匹配')
attrs['hour_work'] = route.hour_work
attrs['material_in'] = route.material_in
attrs['material_out'] = route.material_out
attrs['fill_way'] = Mlog.MLOG_STEP
if mtype == Mlog.MTYPE_OUT:
supplier = attrs.get('supplier', None)
if not supplier:
raise ValidationError('外协必须选择外协单位')
return attrs
class MlogChangeSerializer(CustomModelSerializer):
class Meta:
model = Mlog
fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file']
def validate(self, attrs):
if attrs.get('work_end_time', None):
attrs['handle_date'] = localdate(attrs['work_end_time'])
return attrs
class MlogbInSerializer(CustomModelSerializer):
class Meta:
model = Mlogb
fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jgqbl', 'count_break', 'note']
extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}}
def validate(self, attrs):
mlog: Mlog = attrs['mlog']
mtask: Mtask = attrs['mtask']
wm_in: WMaterial = attrs['wm_in']
if wm_in.state != WMaterial.WM_OK:
raise ValidationError('非合格品不可使用')
if mlog.route != mtask.route:
raise ValidationError('工序不匹配')
route = mlog.route
attrs['material_in'] = wm_in.material
attrs['batch'] = wm_in.batch
if route.batch_bind:
if not Mlogb.objects.filter(mtask__utask=mtask.utask, mlog__submit_time__isnull=False, material_out__isnull=False, batch=attrs['batch']).exists():
raise ValidationError('批次号不匹配')
return attrs
def create(self, validated_data):
mlog: Mlog = validated_data['mlog']
if Mlogb.objects.filter(mlog=mlog, mtask=validated_data['mtask'], wm_in=validated_data['wm_in']).exists():
raise ValidationError('该记录已存在')
if mlog.submit_time is not None:
raise ParseError('生产日志已提交不可编辑')
return super().create(validated_data)
def update(self, instance, validated_data):
mlog: Mlog = instance.mlog
if Mlogb.objects.filter(mlog=mlog, mtask=validated_data['mtask'], wm_in=validated_data['wm_in']).exclude(id=instance.id).exists():
raise ValidationError('该记录已存在')
if mlog.submit_time is not None:
raise ParseError('生产日志已提交不可编辑')
return super().update(instance, validated_data)
class MlogbInUpdateSerializer(CustomModelSerializer):
class Meta:
model = Mlogb
fields = ['id', 'count_use', 'count_break', 'count_n_jgqbl', 'note']
class MlogbOutUpdateSerializer(CustomModelSerializer):
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_n_jgqbl']
def validate(self, attrs):
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 ValidationError(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 ValidationError(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 ValidationError('生产数量不能小于合格数量')
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 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)
def validate(self, attrs):
if 'type' not in attrs:
attrs['type'] = Handover.H_NORMAL
wm:WMaterial = attrs['wm']
material = wm.material
attrs['material'] = wm.material
attrs['batch'] = wm.batch
attrs['send_dept'] = wm.belong_dept
if attrs['wm'].mgroup:
attrs['send_mgroup'] = wm.mgroup
if material.process and material.process.into_wm_mgroup and 'recive_mgroup' not in attrs:
raise ValidationError('必须指定交接工段')
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 ValidationError('收料车间和收料工段必须有一个')
if 'send_dept' not in attrs and 'send_mgroup' not in attrs:
raise ValidationError('送料车间和送料工段必须有一个')
if wm.notok_sign is not None and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]:
raise ValidationError('物料不合格,不能进行正常/检验交接')
if wm.count_xtest is not None:
raise ValidationError('物料检验中,不能进行交接')
return attrs
class Meta:
model = Handover
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS + ["mlog"]
extra_kwargs = {
"type": {"required": False},
"wm": {"required": True},
"send_dept": {"required": False},
"recive_mgroup": {"required": False},
"recive_dept": {"required": False},
"material": {"required": False},
"batch": {"required": False},
}
def create(self, validated_data):
type = validated_data['type']
if type == Handover.H_REPAIR:
recive_mgroup = validated_data.get("recive_mgroup", None)
if recive_mgroup is None:
raise ParseError('返工交接需指定工段')
validated_data['material_changed'] = find_material_can_change(validated_data['material'], recive_mgroup)
return super().create(validated_data)
class HandoverUpdateSerializer(CustomModelSerializer):
class Meta:
model = Handover
fields = ['id', 'send_date', 'send_user', 'count', 'count_eweight', 'recive_user']
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 ValidationError('交送数量必须大于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='route.routepack.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
class FmlogUpdateSerializer(CustomModelSerializer):
class Meta:
model = Fmlog
fields = ['id', 'note']