Expose independent material defect grades

This commit is contained in:
caoqianming 2026-07-30 11:15:29 +08:00
parent 298a32f744
commit 6068f2315d
3 changed files with 96 additions and 2 deletions

View File

@ -132,7 +132,8 @@ class WMaterialFilter(filters.FilterSet):
"notok_sign": ["exact", "in", "isnull"], "notok_sign": ["exact", "in", "isnull"],
"count_xtest": ["gte", "isnull"], "count_xtest": ["gte", "isnull"],
"supplier": ["exact"], "supplier": ["exact"],
"defect": ["exact", "isnull"] "defect": ["exact", "isnull"],
"defect__okcate": ["exact", "in"],
} }
class MlogFilter(filters.FilterSet): class MlogFilter(filters.FilterSet):

View File

@ -190,12 +190,20 @@ class WMaterialSerializer(CustomModelSerializer):
notok_sign_name = serializers.SerializerMethodField() notok_sign_name = serializers.SerializerMethodField()
defect_name = serializers.CharField(source="defect.name", read_only=True) defect_name = serializers.CharField(source="defect.name", read_only=True)
defect_okcate = serializers.IntegerField(source="defect.okcate", read_only=True) defect_okcate = serializers.IntegerField(source="defect.okcate", read_only=True)
defect_grade = serializers.SerializerMethodField()
defect_grade_name = serializers.SerializerMethodField()
count_working = serializers.SerializerMethodField(label='在制数量') count_working = serializers.SerializerMethodField(label='在制数量')
count_handovering = serializers.SerializerMethodField(label='正在交送的数量') count_handovering = serializers.SerializerMethodField(label='正在交送的数量')
def get_notok_sign_name(self, obj): def get_notok_sign_name(self, obj):
return getattr(NotOkOption, obj.notok_sign, NotOkOption.qt).label if obj.notok_sign else None return getattr(NotOkOption, obj.notok_sign, NotOkOption.qt).label if obj.notok_sign else None
def get_defect_grade(self, obj):
return obj.defect.okcate if obj.defect else None
def get_defect_grade_name(self, obj):
return obj.defect.get_okcate_display() if obj.defect else None
def get_count_working(self, obj): def get_count_working(self, obj):
# 列表接口 queryset 已注解(单次聚合); 嵌套等无注解场景回退模型属性 # 列表接口 queryset 已注解(单次聚合); 嵌套等无注解场景回退模型属性
# 保留 decimal 精度(原 IntegerField 会截断在途量, 导致可用/可交接量偏大) # 保留 decimal 精度(原 IntegerField 会截断在途量, 导致可用/可交接量偏大)

View File

@ -13,7 +13,11 @@ from apps.qm.models import Defect
from apps.system.models import Dept, User from apps.system.models import Dept, User
from apps.wpm.filters import HandoverFilter, WMaterialFilter from apps.wpm.filters import HandoverFilter, WMaterialFilter
from apps.wpm.models import Handover, WMaterial from apps.wpm.models import Handover, WMaterial
from apps.wpm.serializers import HandoverSerializer, WMaterialCreateSerializer from apps.wpm.serializers import (
HandoverSerializer,
WMaterialCreateSerializer,
WMaterialSerializer,
)
from apps.wpm.services import restore_mlog_wpr_defects, snapshot_mlog_wpr_defects from apps.wpm.services import restore_mlog_wpr_defects, snapshot_mlog_wpr_defects
from apps.wpm.views import MlogbwViewSet from apps.wpm.views import MlogbwViewSet
from apps.wpmw.models import Wpr, WprDefect from apps.wpmw.models import Wpr, WprDefect
@ -100,6 +104,87 @@ class HandoverFilterTests(TestCase):
]) ])
class WMaterialDefectGradeTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.material = Material.objects.create(name="缺陷等级测试物料")
cls.defect_b = Defect.objects.create(
name="B类缺陷",
cate=Defect.cate_list[0],
okcate=Defect.DEFECT_OK_B,
)
cls.defect_notok = Defect.objects.create(
name="不合格缺陷",
cate=Defect.cate_list[0],
okcate=Defect.DEFECT_NOTOK,
)
cls.normal_with_notok_defect = WMaterial.objects.create(
material=cls.material,
batch="NORMAL-NOTOK",
count=1,
state=WMaterial.WM_OK,
defect=cls.defect_notok,
)
cls.notok_with_b_defect = WMaterial.objects.create(
material=cls.material,
batch="NOTOK-B",
count=1,
state=WMaterial.WM_NOTOK,
defect=cls.defect_b,
)
cls.normal_without_defect = WMaterial.objects.create(
material=cls.material,
batch="NORMAL-NONE",
count=1,
state=WMaterial.WM_OK,
)
def test_serializer_exposes_nullable_defect_grade_without_using_state(self):
normal_notok_data = WMaterialSerializer(
self.normal_with_notok_defect
).data
notok_b_data = WMaterialSerializer(self.notok_with_b_defect).data
no_defect_data = WMaterialSerializer(self.normal_without_defect).data
self.assertEqual(
normal_notok_data["defect_grade"], Defect.DEFECT_NOTOK
)
self.assertEqual(normal_notok_data["defect_grade_name"], "不合格")
self.assertEqual(
notok_b_data["defect_grade"], Defect.DEFECT_OK_B
)
self.assertEqual(notok_b_data["defect_grade_name"], "合格B类")
self.assertIsNone(no_defect_data["defect_grade"])
self.assertIsNone(no_defect_data["defect_grade_name"])
def test_filtering_state_and_defect_grade_are_independent(self):
normal_notok = WMaterialFilter(
{
"state": WMaterial.WM_OK,
"defect__okcate": Defect.DEFECT_NOTOK,
},
queryset=WMaterial.objects.all(),
).qs
notok_b = WMaterialFilter(
{
"state": WMaterial.WM_NOTOK,
"defect__okcate": Defect.DEFECT_OK_B,
},
queryset=WMaterial.objects.all(),
).qs
self.assertQuerySetEqual(
normal_notok,
[self.normal_with_notok_defect],
transform=lambda item: item,
)
self.assertQuerySetEqual(
notok_b,
[self.notok_with_b_defect],
transform=lambda item: item,
)
class MlogbwViewSetTests(SimpleTestCase): class MlogbwViewSetTests(SimpleTestCase):
@patch("apps.wpm.views.MlogViewSet.lock_and_check_can_update") @patch("apps.wpm.views.MlogViewSet.lock_and_check_can_update")
@patch("apps.wpm.views.Mlogbw.cal_count_notok") @patch("apps.wpm.views.Mlogbw.cal_count_notok")