diff --git a/api_v1/views/printing/serializers.py b/api_v1/views/printing/serializers.py index 4e59090..d136838 100644 --- a/api_v1/views/printing/serializers.py +++ b/api_v1/views/printing/serializers.py @@ -143,6 +143,10 @@ class PrintingOrderListSerializer(serializers.ModelSerializer): created_by = serializers.IntegerField(source='created_by_id', read_only=True) created_by_name = serializers.SerializerMethodField() merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True) + external_order_id = serializers.CharField(read_only=True) + external_customer_id = serializers.CharField(read_only=True) + external_customer_name = serializers.CharField(read_only=True) + external_employee_name = serializers.CharField(read_only=True) class Meta: model = models.PrintingOrder @@ -152,6 +156,7 @@ class PrintingOrderListSerializer(serializers.ModelSerializer): 'is_fabric_received', 'outgoing_date', 'is_invalid', 'new_curve', 'process', 'process_name', 'progress', 'position', 'print_count', 'jobs_status_summary', 'jobs_last_status_summary', + 'external_order_id', 'external_customer_id', 'external_customer_name', 'external_employee_name', 'created_by', 'created_by_name', 'created_at', 'updated_at', ] @@ -231,6 +236,10 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer): created_by_name = serializers.SerializerMethodField() progress = serializers.IntegerField(read_only=True) merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=True) + external_order_id = serializers.CharField(read_only=True) + external_customer_id = serializers.CharField(read_only=True) + external_customer_name = serializers.CharField(read_only=True) + external_employee_name = serializers.CharField(read_only=True) class Meta: model = models.PrintingOrder @@ -240,6 +249,7 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer): 'is_fabric_received', 'craft', 'description', 'outgoing_date', 'curve', 'new_curve', 'position', 'created_by_name', 'printing_warn', 'rolling_warn', 'production_warn', + 'external_order_id', 'external_customer_id', 'external_customer_name', 'external_employee_name', 'is_invalid', 'process', 'process_name', 'progress', 'print_count', 'created_at', 'updated_at' ] @@ -323,6 +333,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer): """印染款式明细列表序列化器""" printing_order_id = serializers.CharField(source='printing_order.human_id', read_only=True) + external_order_id = serializers.CharField(source='printing_order.external_order_id', read_only=True) product_name = serializers.CharField(source='product.name', read_only=True) product_image_url = serializers.SerializerMethodField() status = serializers.CharField(read_only=True) @@ -339,7 +350,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer): class Meta: model = models.PrintingJob fields = [ - 'id', 'original_id', 'merchant_id', 'printing_order', 'printing_order_id', 'product', 'product_name', + 'id', 'original_id', 'merchant_id', 'printing_order', 'printing_order_id', 'external_order_id', 'product', 'product_name', 'product_image_url', 'has_started', 'quantity', 'unit', 'size', 'pieces', 'description', 'work_state', 'work_state_display', @@ -414,6 +425,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer): class PrintingJobDetailSerializer(serializers.ModelSerializer): """印染款式明细详情序列化器""" printing_order_id = serializers.CharField(source='printing_order.human_id', read_only=True) + external_order_id = serializers.CharField(source='printing_order.external_order_id', read_only=True) product_name = serializers.CharField(source='product.name', read_only=True) product_code = serializers.CharField(source='product.human_id', read_only=True) status = serializers.CharField(read_only=True) @@ -431,7 +443,7 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer): class Meta: model = models.PrintingJob fields = [ - 'id', 'original_id', 'merchant_id', 'printing_order', 'printing_order_id', 'product', 'product_name', 'product_code', + 'id', 'original_id', 'merchant_id', 'printing_order', 'printing_order_id', 'external_order_id', 'product', 'product_name', 'product_code', 'quantity', 'unit', 'size', 'pieces', 'description', 'work_state', 'work_state_display', 'status', 'status_id', 'is_completed', 'has_started', diff --git a/api_v1/views/printing/test_api.py b/api_v1/views/printing/test_api.py index 2cd1cff..40354ba 100644 --- a/api_v1/views/printing/test_api.py +++ b/api_v1/views/printing/test_api.py @@ -196,6 +196,40 @@ class PrintingOrderAPITestCase(TestCase): self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['results'][0]['is_invalid'], True) + + def test_filter_by_external_order_id_and_serializer_fields(self): + """支持按 external_order_id 过滤,且列表/详情返回外部字段""" + order1 = printing_models.PrintingOrder.objects.create( + merchant=self.merchant, + customer=self.customer, + fabric='布料A', + width='150cm', + external_order_id='KD20410611', + external_customer_id='KH00991', + external_customer_name='李泽柔', + external_employee_name='丽容', + ) + printing_models.PrintingOrder.objects.create( + merchant=self.merchant, + customer=self.customer, + fabric='布料B', + width='160cm', + external_order_id='KD20419999', + ) + + response = self.client.get('/api/v1/printing-orders/?external_order_id=KD20410611') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + item = response.data['results'][0] + self.assertEqual(item['external_order_id'], 'KD20410611') + self.assertEqual(item['external_customer_id'], 'KH00991') + self.assertEqual(item['external_customer_name'], '李泽柔') + self.assertEqual(item['external_employee_name'], '丽容') + + detail = self.client.get(f'/api/v1/printing-orders/{order1.id}/') + self.assertEqual(detail.status_code, status.HTTP_200_OK) + self.assertEqual(detail.data['external_order_id'], 'KD20410611') + self.assertEqual(detail.data['external_customer_id'], 'KH00991') def test_retrieve_printing_order(self): """测试获取订单详情""" diff --git a/api_v1/views/printing/test_printing_job_api.py b/api_v1/views/printing/test_printing_job_api.py index 76d3a52..36f2407 100644 --- a/api_v1/views/printing/test_printing_job_api.py +++ b/api_v1/views/printing/test_printing_job_api.py @@ -491,6 +491,45 @@ class PrintingJobAPITestCase(TestCase): self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['results'][0]['product'], self.product.id) + + def test_filter_by_external_order_id_and_serializer_field(self): + """测试按所属订单 external_order_id 过滤,并返回该字段""" + self.printing_order.external_order_id = 'KD20410611' + self.printing_order.save(update_fields=['external_order_id']) + + job = printing_models.PrintingJob.objects.create( + printing_order=self.printing_order, + product=self.product, + quantity=100, + unit='米', + size='50*60', + pieces=10 + ) + + other_order = printing_models.PrintingOrder.objects.create( + customer=self.customer, + fabric='其他布料', + width='160cm', + external_order_id='KD20419999' + ) + printing_models.PrintingJob.objects.create( + printing_order=other_order, + product=self.product, + quantity=200, + unit='米', + size='60*70', + pieces=20 + ) + + response = self.client.get('/api/v1/printing-jobs/?external_order_id=KD20410611') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data['count'], 1) + self.assertEqual(response.data['results'][0]['id'], job.id) + self.assertEqual(response.data['results'][0]['external_order_id'], 'KD20410611') + + detail = self.client.get(f'/api/v1/printing-jobs/{job.id}/') + self.assertEqual(detail.status_code, status.HTTP_200_OK) + self.assertEqual(detail.data['external_order_id'], 'KD20410611') def test_filter_by_quantity_range(self): """测试按数量范围过滤""" diff --git a/api_v1/views/printing/views.py b/api_v1/views/printing/views.py index 8cfd82e..2a6ea35 100644 --- a/api_v1/views/printing/views.py +++ b/api_v1/views/printing/views.py @@ -73,6 +73,7 @@ class HasActivatePrintingOrderPermission(BasePermission): class PrintingOrderFilterSet(django_filters.FilterSet): """印染订单过滤器""" + external_order_id = django_filters.CharFilter(lookup_expr='icontains') customer_name = django_filters.CharFilter(field_name='customer__name', lookup_expr='icontains') customer_phone = django_filters.CharFilter(field_name='customer__phone', lookup_expr='icontains') fabric = django_filters.CharFilter(lookup_expr='icontains') @@ -87,7 +88,7 @@ class PrintingOrderFilterSet(django_filters.FilterSet): class Meta: model = models.PrintingOrder - fields = ['customer', 'is_urgent', 'is_fabric_received', 'is_invalid'] + fields = ['customer', 'is_urgent', 'is_fabric_received', 'is_invalid', 'external_order_id'] @staticmethod def _parse_date_or_datetime(value: str | None) -> tuple[datetime | None, bool]: @@ -168,6 +169,7 @@ class PrintingOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet): 查询参数: - customer: 客户ID + - external_order_id: 外部订单编号(模糊查询) - customer_name: 客户名称(模糊查询) - customer_phone: 客户电话(模糊查询) - fabric: 面料(模糊查询) @@ -343,6 +345,7 @@ class PrintingOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet): class PrintingJobFilterSet(django_filters.FilterSet): """印染款式明细过滤器""" printing_order = django_filters.NumberFilter() + external_order_id = django_filters.CharFilter(field_name='printing_order__external_order_id', lookup_expr='icontains') product = django_filters.NumberFilter() product_name = django_filters.CharFilter(field_name='product__name', lookup_expr='icontains') unit = django_filters.CharFilter(lookup_expr='icontains') @@ -353,7 +356,7 @@ class PrintingJobFilterSet(django_filters.FilterSet): class Meta: model = models.PrintingJob - fields = ['printing_order', 'product'] + fields = ['printing_order', 'product', 'external_order_id'] class PrintingJobViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet): @@ -379,6 +382,7 @@ class PrintingJobViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet): 查询参数: - printing_order: 印染订单ID + - external_order_id: 外部订单编号(按所属订单模糊查询) - product: 产品ID - product_name: 产品名称(模糊查询) - unit: 单位(模糊查询) diff --git a/printing/admin.py b/printing/admin.py index 3ca183e..0435aea 100644 --- a/printing/admin.py +++ b/printing/admin.py @@ -186,19 +186,65 @@ class PrintingJobInline(admin.StackedInline): @admin.register(models.PrintingOrder) class PrintingOrderAdmin(admin.ModelAdmin): list_display = ( - 'oid', - 'customer_name', + 'oid', + 'external_order_id', + 'external_customer_name', + 'external_employee_name', + 'customer_name', 'progress_percent', - 'created_at', + 'created_at', 'outgoing_date', ) search_fields = ( '=id', + 'external_order_id', + 'external_customer_id', + 'external_customer_name', + 'external_employee_name', 'customer__name', 'fabric', 'craft', 'description', ) + readonly_fields = ('external_raw_pretty',) + fieldsets = ( + ('基础信息', { + 'fields': ( + 'customer', 'fabric', 'width', 'is_urgent', 'area', 'address', + 'fabric_source', 'is_fabric_received', 'craft', 'description', + 'outgoing_date', 'curve', 'new_curve', 'position', + 'printing_warn', 'rolling_warn', 'production_warn', + 'is_invalid', 'process', + ) + }), + ('外部同步信息', { + 'fields': ( + 'external_order_id', + 'external_customer_id', + 'external_customer_name', + 'external_employee_name', + 'external_raw_pretty', + ), + 'classes': ('collapse',), + }), + ) + + @admin.display(description='外部订单编号') + def external_order_id(self, obj): + return obj.external_order_id or '-' + + @admin.display(description='外部客户名') + def external_customer_name(self, obj): + return obj.external_customer_name or '-' + + @admin.display(description='外部员工名') + def external_employee_name(self, obj): + return obj.external_employee_name or '-' + + @admin.display(description='外部原始数据') + def external_raw_pretty(self, obj): + import json + return format_html('
{}', json.dumps(obj.external_raw or {}, ensure_ascii=False, indent=2))
def save_formset(self, request, form, formset, change):