from rest_framework import serializers from rest_framework.exceptions import ValidationError, ParseError from apps.mtm.serializers import MaterialSerializer from apps.pum.models import PuOrder from apps.sam.models import Order from apps.system.models import Dept, User from apps.utils.constants import EXCLUDE_FIELDS_BASE, EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS from apps.utils.serializers import CustomModelSerializer from apps.mtm.models import Material from .models import MIO, MaterialBatch, MIOItem, WareHouse, MIOItemA, MaterialBatchA, MIOItemw from django.db import transaction from server.settings import get_sysconfig from apps.wpmw.models import Wpr class WareHourseSerializer(CustomModelSerializer): class Meta: model = WareHouse fields = '__all__' read_only_fields = EXCLUDE_FIELDS_DEPT class MaterialBatchAListSerializer(CustomModelSerializer): material_ = MaterialSerializer(source='material', read_only=True) class Meta: model = MaterialBatchA fields = ['material', 'batch', 'rate', 'mb', 'id', 'material_'] class MaterialBatchSerializer(CustomModelSerializer): warehouse_name = serializers.CharField( source='warehouse.name', read_only=True) material_name = serializers.StringRelatedField( source='material', read_only=True) supplier_name = serializers.StringRelatedField( source='supplier', read_only=True) material_ = MaterialSerializer(source='material', read_only=True) defect_name = serializers.CharField(source="defect.name", read_only=True) class Meta: model = MaterialBatch fields = '__all__' read_only_fields = EXCLUDE_FIELDS_BASE class MaterialBatchDetailSerializer(CustomModelSerializer): warehouse_name = serializers.CharField( source='warehouse.name', read_only=True) material_name = serializers.CharField( source='material.name', read_only=True) material_ = MaterialSerializer(source='material', read_only=True) assemb = MaterialBatchAListSerializer( source='a_mb', read_only=True, many=True) supplier_name = serializers.StringRelatedField( source='supplier', read_only=True) class Meta: model = MaterialBatch fields = '__all__' class MIOListSerializer(CustomModelSerializer): create_by_name = serializers.CharField( source='create_by.name', read_only=True) submit_user_name = serializers.CharField( source='submit_user.name', read_only=True) do_user_name = serializers.CharField( source='do_user.name', read_only=True) mio_user_name = serializers.CharField( source='mio_user.name', read_only=True) belong_dept_name = serializers.CharField( source='belong_dept.name', read_only=True) mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) supplier_name = serializers.CharField( source='supplier.name', read_only=True) customer_name = serializers.CharField( source='customer.name', read_only=True) order_number = serializers.CharField(source='order.number', read_only=True) pu_order_number = serializers.CharField( source='pu_order.number', read_only=True) class Meta: model = MIO fields = '__all__' read_only_fields = EXCLUDE_FIELDS + \ ['state', 'submit_time', 'submit_user', 'number'] class MIOItemACreateSerializer(CustomModelSerializer): class Meta: model = MIOItemA fields = ['material', 'batch', 'zhuidu', 'b_zuidawaijing', 'g_zuidaneijing'] class MIOItemwSerializer(CustomModelSerializer): class Meta: model = MIOItemw fields = "__all__" read_only_fields = EXCLUDE_FIELDS_BASE + ["mioitem"] class MIOItemCreateSerializer(CustomModelSerializer): assemb = MIOItemACreateSerializer( label='组合件信息', many=True, write_only=True, required=False) mioitemw = MIOItemwSerializer(many=True, required=False) class Meta: model = MIOItem fields = ['mio', 'warehouse', 'material', 'batch', 'count', 'assemb', 'is_testok', 'mioitemw', 'mb', 'wm'] extra_kwargs = { 'mio': {'required': True}, 'warehouse': {'required': False}, 'material': {'required': False}, 'batch': {'required': False}} def create(self, validated_data): mio:MIO = validated_data['mio'] mb = validated_data.get('mb', None) wm = validated_data.get('wm', None) if mio.type == MIO.MIO_TYPE_DO_IN: if not wm: raise ParseError('生产入库必须指定车间库存') elif mio.type == MIO.MIO_TYPE_DO_OUT: if not mb: raise ParseError('生产领料必须指定仓库库存') if mb: validated_data["material"] = mb.material validated_data["batch"] = mb.batch validated_data["warehouse"] = mb.warehouse elif wm: validated_data["material"] = wm.material validated_data["batch"] = wm.batch material: Material = validated_data['material'] batch = validated_data['batch'] if material.is_hidden: raise ParseError('隐式物料不可出入库') if mio.state != MIO.MIO_CREATE: raise ParseError('出入库记录非创建中不可新增') # 生产领料要校验是否进行检验 # 某些客户此处无需校验 check_test_when_do_out = get_sysconfig('mes.check_test_when_do_out', True) if check_test_when_do_out and mio.type == MIO.MIO_TYPE_DO_OUT: mis = MIOItem.objects.filter(batch=batch, material=material, mio__type__in=[MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN]) if mis.exists() and (not mis.exclude(test_date=None).exists()): raise ParseError('该批次的物料未经检验') with transaction.atomic(): count = validated_data["count"] batch = validated_data["batch"] assemb = validated_data.pop('assemb', []) mioitemw = validated_data.pop('mioitemw', []) instance = super().create(validated_data) assemb_dict = {} for i in assemb: assemb_dict[i['material'].id] = i if material.is_assemb and '_in' in mio.type: # 仅入库且是组合件的时候需要填写下一级 components = material.components for k, v in components.items(): if k in assemb_dict: mia = assemb_dict[k] MIOItemA.objects.create( mioitem=instance, rate=v, **mia) else: raise ParseError('缺少组合件') if material.tracking == Material.MA_TRACKING_SINGLE: if len(mioitemw) == 0: if mb: wpr_qs = Wpr.get_qs_by_mb(mb) if wpr_qs.count() == validated_data["count"]: for item in wpr_qs: MIOItemw.objects.create(mioitem=instance, number=item.number, wpr=item) else: raise ParseError('请提供产品明细编号') elif wm: wpr_qs = Wpr.get_qs_by_wm(wm) if wpr_qs.count() == validated_data["count"]: for item in wpr_qs: MIOItemw.objects.create(mioitem=instance, number=item.number, wpr=item) else: raise ParseError('请提供产品明细编号') elif mio.type in [MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_OTHER_IN] and count==1: MIOItemw.objects.create(mioitem=instance, number=batch) else: raise ParseError('不支持自动生成请提供产品明细') elif len(mioitemw) >= 1: mio_type = mio.type for item in mioitemw: if item.get("wpr", None) is None and mio_type != "pur_in": raise ParseError(f'{item["number"]}_请提供产品明细ID') else: MIOItemw.objects.create(mioitem=instance, **item) return instance class MIOItemAListSerializer(CustomModelSerializer): material_ = MaterialSerializer(source='material', read_only=True) material_name = serializers.StringRelatedField( source='material', read_only=True) class Meta: model = MIOItemA fields = ['material', 'batch', 'rate', 'mioitem', 'id', 'material_', 'material_name'] class MIOItemSerializer(CustomModelSerializer): warehouse_name = serializers.CharField( source='warehouse.name', read_only=True) material_ = MaterialSerializer(source='material', read_only=True) assemb = MIOItemAListSerializer( source='a_mioitem', read_only=True, many=True) material_name = serializers.StringRelatedField( source='material', read_only=True) inout_date = serializers.DateField(source='mio.inout_date', read_only=True) test_user_name = serializers.CharField(source='test_user.name', read_only=True) mioitemw = MIOItemwSerializer(many=True, required=False) class Meta: model = MIOItem fields = '__all__' class MIODoSerializer(CustomModelSerializer): belong_dept = serializers.PrimaryKeyRelatedField( label="车间", queryset=Dept.objects.all(), required=False) do_user = serializers.PrimaryKeyRelatedField( label="执行人", queryset=User.objects.all(), required=True) note = serializers.CharField( required=False, allow_blank=True) class Meta: model = MIO fields = ['id', 'number', 'note', 'do_user', 'belong_dept', 'type', 'inout_date', 'mgroup', 'mio_user'] extra_kwargs = {'inout_date': {'required': True}, 'do_user': {'required': True}, 'number': {"required": False, "allow_blank": True}} def validate(self, attrs): if 'mgroup' in attrs and attrs['mgroup']: attrs['belong_dept'] = attrs['mgroup'].belong_dept if not attrs.get("belong_dept", None): raise ParseError('请选择车间或工段') return attrs def create(self, validated_data): if not validated_data.get("number", None): validated_data["number"] = MIO.get_a_number(validated_data["type"]) if validated_data['type'] not in [MIO.MIO_TYPE_DO_OUT, MIO.MIO_TYPE_DO_IN]: raise ValidationError('出入库类型错误') return super().create(validated_data) def update(self, instance, validated_data): validated_data.pop('type', None) return super().update(instance, validated_data) class MIOSaleSerializer(CustomModelSerializer): # order = serializers.PrimaryKeyRelatedField( # label="订单", queryset=Order.objects.all(), required=True) note = serializers.CharField( required=False, allow_blank=True) class Meta: model = MIO fields = ['id', 'number', 'note', 'order', 'inout_date', 'customer', 'mio_user'] extra_kwargs = {'inout_date': {'required': True}, 'number': {"required": False, "allow_blank": True}} def create(self, validated_data): validated_data['type'] = MIO.MIO_TYPE_SALE_OUT order: Order = validated_data.get('order', None) if not validated_data.get("number", None): validated_data["number"] = MIO.get_a_number(validated_data["type"]) if order: if order.state in [Order.ORDER_CREATE, Order.ORDER_DELIVERED]: raise ValidationError('销售订单状态错误') validated_data['customer'] = order.customer if order.belong_dept: validated_data['belong_dept'] = order.belong_dept return super().create(validated_data) def update(self, instance, validated_data): validated_data.pop('type', None) return super().update(instance, validated_data) class MIOPurSerializer(CustomModelSerializer): # pu_order = serializers.PrimaryKeyRelatedField( # label="采购订单", queryset=PuOrder.objects.all(), required=True) note = serializers.CharField( required=False, allow_blank=True) class Meta: model = MIO fields = ['id', 'number', 'note', 'pu_order', 'inout_date', 'supplier', 'mio_user'] extra_kwargs = {'inout_date': {'required': True}, 'number': {"required": False, "allow_blank": True}} def create(self, validated_data): validated_data['type'] = MIO.MIO_TYPE_PUR_IN if not validated_data.get("number", None): validated_data["number"] = MIO.get_a_number(validated_data["type"]) pu_order: PuOrder = validated_data.get('pu_order', None) if pu_order: if pu_order.state in [PuOrder.PUORDER_CREATE, PuOrder.PUORDER_DONE]: raise ValidationError('采购订单状态错误') validated_data['supplier'] = pu_order.supplier if pu_order.belong_dept: validated_data['belong_dept'] = pu_order.belong_dept return super().create(validated_data) def update(self, instance, validated_data): validated_data.pop('type', None) return super().update(instance, validated_data) class MIOOtherSerializer(CustomModelSerializer): note = serializers.CharField( required=False, allow_blank=True) class Meta: model = MIO fields = ['id', 'number', 'note', 'supplier', 'customer', 'type', 'inout_date', 'mio_user'] extra_kwargs = {'inout_date': {'required': True}, 'number': {"required": False, "allow_blank": True}} def create(self, validated_data): if not validated_data.get("number", None): validated_data["number"] = MIO.get_a_number(validated_data["type"]) if validated_data['type'] not in [MIO.MIO_TYPE_OTHER_OUT, MIO.MIO_TYPE_OTHER_IN]: raise ValidationError('出入库类型错误') return super().create(validated_data) def update(self, instance, validated_data): validated_data.pop('type', None) return super().update(instance, validated_data) class MIODetailSerializer(MIOListSerializer): items = MIOItemSerializer(source='item_mio', many=True, read_only=True) class MIOItemTestSerializer(CustomModelSerializer): class Meta: model = MIOItem fields = ['id', 'test_date', 'test_user', 'count_notok', 'count_n_zw', 'count_n_tw', 'count_n_qp', 'count_n_wq', 'count_n_dl', 'count_n_pb', 'count_n_dxt', 'count_n_js', 'count_n_qx', 'count_n_zz', 'count_n_ysq', 'count_n_qt', 'count_n_hs', 'count_n_b', 'test_note'] extra_kwargs = { 'test_date': {'required': True}, 'test_user': {'required': True} } def validate(self, attrs): count_notok = 0 for i in attrs: if 'count_n_' in i: count_notok = count_notok + attrs[i] attrs['count_notok'] = count_notok return attrs class MioItemAnaSerializer(serializers.Serializer): start_date = serializers.DateField(label='开始日期', required=True) end_date = serializers.DateField(label='结束日期', required=True) material_cate = serializers.CharField(label='物料系列', required=True) class MIOItemPurInTestSerializer(CustomModelSerializer): class Meta: model = MIOItem fields = ['id', 'test_date', 'test_user', 'count_bag', 'count_sampling', 'weight_kgs', 'is_testok', 'test_note'] extra_kwargs = { 'test_date': {'required': True}, 'test_user': {'required': True} } def validate(self, attrs): if 'count_sampling' in attrs and attrs['count_sampling']: pass else: weight_kgs = attrs['weight_kgs'] attrs['weight_kgs'] = [float(i) for i in weight_kgs] attrs['count_sampling'] = len(attrs['weight_kgs']) return super().validate(attrs)