diff --git a/apps/wpm/models.py b/apps/wpm/models.py index f4c87c76..e2ae0105 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -877,7 +877,7 @@ class Handoverb(BaseModel): @property def handoverbw(self): - return Handoverbw.objects.filter(handoverb=self) + return self.w_handoverb.all() class Handoverbw(BaseModel): """TN: 单个产品交接记录 diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 409269aa..91bfe6de 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -31,6 +31,16 @@ from apps.em.models import Equipment from django.db.models import Q mylogger = logging.getLogger("log") +WM_STATE_NAMES = { + WMaterial.WM_OK: "合格", + WMaterial.WM_NOTOK: "不合格", + WMaterial.WM_REPAIR: "返修", + WMaterial.WM_REPAIRED: "返修完成", + WMaterial.WM_TEST: "检验", + WMaterial.WM_SCRAP: "报废", +} + + class OtherLogSerializer(CustomModelSerializer): class Meta: model = OtherLog @@ -1286,8 +1296,35 @@ class HandoverbSerializer(CustomModelSerializer): ) ) notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True) + notok_sign_name = serializers.SerializerMethodField() defect_name = serializers.CharField(source="wm.defect.name", read_only=True) + defect_grade = serializers.SerializerMethodField() + defect_grade_name = serializers.SerializerMethodField() + material_name = serializers.StringRelatedField(source="wm.material", read_only=True) + state_name = serializers.SerializerMethodField() + mgroup_name = serializers.CharField(source="wm.mgroup.name", read_only=True) + belong_dept_name = serializers.CharField(source="wm.belong_dept.name", read_only=True) + count_available = serializers.SerializerMethodField() handoverbw = Handoverbwserializer(many=True, required=False) + + def get_notok_sign_name(self, obj): + return getattr(NotOkOption, obj.wm.notok_sign, NotOkOption.qt).label if obj.wm.notok_sign else None + + def get_defect_grade(self, obj): + return effective_defect_grade(obj.wm, "notok_sign") + + def get_defect_grade_name(self, obj): + return DEFECT_GRADE_NAMES[self.get_defect_grade(obj)] + + def get_state_name(self, obj): + return WM_STATE_NAMES.get(obj.wm.state, str(obj.wm.state)) + + def get_count_available(self, obj): + # 编辑未提交交接时,当前明细占用的数量仍应允许重新填写。 + if obj.handover.submit_time is not None: + return obj.count + return obj.wm.count - obj.wm.count_handovering + obj.count + class Meta: model = Handoverb fields = "__all__" @@ -1310,9 +1347,14 @@ class HandoverSerializer(CustomModelSerializer): recive_user_name = serializers.CharField( source='recive_user.name', read_only=True) recive_dept_name = serializers.CharField( - source='recive_dept', read_only=True) + source='recive_dept.name', read_only=True) + send_dept_name = serializers.CharField(source='send_dept.name', 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) + submit_user_name = serializers.CharField(source='submit_user.name', read_only=True) + type_name = serializers.CharField(source='get_type_display', read_only=True) + mtype_name = serializers.CharField(source='get_mtype_display', read_only=True) + state_changed_name = serializers.SerializerMethodField() material_ = MaterialSimpleSerializer(source='material', read_only=True) material_name = serializers.StringRelatedField( source='material', read_only=True) @@ -1321,6 +1363,9 @@ class HandoverSerializer(CustomModelSerializer): handoverb = HandoverbSerializer(many=True, required=False) ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) + def get_state_changed_name(self, obj): + return WM_STATE_NAMES.get(obj.state_changed) if obj.state_changed is not None else None + def to_internal_value(self, data): handoverb = data.get("handoverb", []) if hasattr(data, "get") else [] wm_ids = { diff --git a/apps/wpm/tests/test_handover_serializer.py b/apps/wpm/tests/test_handover_serializer.py index cd73a488..40d930e7 100644 --- a/apps/wpm/tests/test_handover_serializer.py +++ b/apps/wpm/tests/test_handover_serializer.py @@ -5,7 +5,7 @@ from django.test.utils import CaptureQueriesContext from apps.mtm.models import Material from apps.qm.models import Defect from apps.system.models import Dept, User -from apps.wpm.models import Handover, WMaterial +from apps.wpm.models import Handover, Handoverb, WMaterial from apps.wpm.serializers import HandoverSerializer @@ -56,3 +56,32 @@ class HandoverSerializerQueryTests(TestCase): if 'FROM "wpm_wmaterial"' in query["sql"] ] self.assertEqual(len(inventory_queries), 1, inventory_queries) + + def test_detail_contains_display_fields_for_handover_and_items(self): + handover = Handover.objects.create( + send_date="2026-08-07", + send_user=self.user, + send_dept=self.dept, + recive_dept=self.dept, + material=self.material, + wm=self.inventories[0], + count=1, + type=Handover.H_NORMAL, + mtype=Handover.H_NORMAL, + ) + Handoverb.objects.create( + handover=handover, + wm=self.inventories[0], + batch=self.inventories[0].batch, + count=1, + ) + + data = HandoverSerializer(handover).data + + self.assertEqual(data["send_dept_name"], self.dept.name) + self.assertEqual(data["recive_dept_name"], self.dept.name) + self.assertEqual(data["type_name"], "正常交接") + self.assertEqual(data["mtype_name"], "正常") + self.assertEqual(data["handoverb"][0]["material_name"], str(self.material)) + self.assertEqual(data["handoverb"][0]["state_name"], "合格") + self.assertEqual(data["handoverb"][0]["count_available"], 1) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 3c66404c..fb31d11b 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -592,7 +592,20 @@ class HandoverViewSet(CustomModelViewSet): select_related_fields = ["send_user", "send_mgroup", "send_dept", "recive_user", "recive_mgroup", "recive_dept", "wm", "material_changed", "material", "material__process"] filterset_class = HandoverFilter search_fields = ["material__name", "material__number", "material__specification", "batch", "material__model", "b_handover__batch", "new_batch", "wm__batch"] - prefetch_related_fields = [Prefetch("b_handover", queryset=Handoverb.objects.select_related("wm__defect")), "ticket__state"] + prefetch_related_fields = ["ticket__state"] + + def get_queryset_custom(self, queryset): + if self.action not in ["list", "retrieve"]: + return queryset + + detail_queryset = Handoverb.objects.select_related( + "handover", "wm__defect", "wm__material", "wm__mgroup", "wm__belong_dept" + ) + if self.action == "retrieve": + detail_queryset = detail_queryset.prefetch_related("w_handoverb") + return queryset.prefetch_related( + Prefetch("b_handover", queryset=detail_queryset) + ) def perform_destroy(self, instance: Handover): user = self.request.user @@ -680,7 +693,7 @@ class HandoverViewSet(CustomModelViewSet): m_qs = m_qs.filter(process__route_p__material_in__id=materialInId) | m_qs.filter(process__route_p__routemat_route__material__id=materialInId) elif type in [Handover.H_SCRAP]: m_qs = m_qs.filter(process=None) - return Response(list(m_qs.values("id", "name").distinct())) + return Response(list(m_qs.values("id", "name", "belong_dept").distinct())) @action(methods=["post"], detail=False, perms_map={"post": "handover.create"}, serializer_class=GenHandoverWmSerializer) @transaction.atomic