1
0
forked from erp-dev/erp

feat: printing orders and jobs filter with external_order_id

This commit is contained in:
2026-03-20 22:36:31 +08:00
parent fa9721762c
commit b58667ca52
5 changed files with 142 additions and 7 deletions

View File

@@ -143,6 +143,10 @@ class PrintingOrderListSerializer(serializers.ModelSerializer):
created_by = serializers.IntegerField(source='created_by_id', read_only=True) created_by = serializers.IntegerField(source='created_by_id', read_only=True)
created_by_name = serializers.SerializerMethodField() created_by_name = serializers.SerializerMethodField()
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=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: class Meta:
model = models.PrintingOrder model = models.PrintingOrder
@@ -152,6 +156,7 @@ class PrintingOrderListSerializer(serializers.ModelSerializer):
'is_fabric_received', 'outgoing_date', 'is_invalid', 'new_curve', 'is_fabric_received', 'outgoing_date', 'is_invalid', 'new_curve',
'process', 'process_name', 'progress', 'position', 'print_count', 'process', 'process_name', 'progress', 'position', 'print_count',
'jobs_status_summary', 'jobs_last_status_summary', '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_by', 'created_by_name',
'created_at', 'updated_at', 'created_at', 'updated_at',
] ]
@@ -231,6 +236,10 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer):
created_by_name = serializers.SerializerMethodField() created_by_name = serializers.SerializerMethodField()
progress = serializers.IntegerField(read_only=True) progress = serializers.IntegerField(read_only=True)
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True, allow_null=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: class Meta:
model = models.PrintingOrder model = models.PrintingOrder
@@ -240,6 +249,7 @@ class PrintingOrderDetailSerializer(serializers.ModelSerializer):
'is_fabric_received', 'craft', 'description', 'outgoing_date', 'is_fabric_received', 'craft', 'description', 'outgoing_date',
'curve', 'new_curve', 'position', 'created_by_name', 'curve', 'new_curve', 'position', 'created_by_name',
'printing_warn', 'rolling_warn', 'production_warn', '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', 'is_invalid', 'process', 'process_name', 'progress', 'print_count',
'created_at', 'updated_at' '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) 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_name = serializers.CharField(source='product.name', read_only=True)
product_image_url = serializers.SerializerMethodField() product_image_url = serializers.SerializerMethodField()
status = serializers.CharField(read_only=True) status = serializers.CharField(read_only=True)
@@ -339,7 +350,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.PrintingJob model = models.PrintingJob
fields = [ 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', 'product_image_url', 'has_started',
'quantity', 'unit', 'size', 'pieces', 'description', 'quantity', 'unit', 'size', 'pieces', 'description',
'work_state', 'work_state_display', 'work_state', 'work_state_display',
@@ -414,6 +425,7 @@ class PrintingJobListSerializer(serializers.ModelSerializer):
class PrintingJobDetailSerializer(serializers.ModelSerializer): class PrintingJobDetailSerializer(serializers.ModelSerializer):
"""印染款式明细详情序列化器""" """印染款式明细详情序列化器"""
printing_order_id = serializers.CharField(source='printing_order.human_id', read_only=True) 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_name = serializers.CharField(source='product.name', read_only=True)
product_code = serializers.CharField(source='product.human_id', read_only=True) product_code = serializers.CharField(source='product.human_id', read_only=True)
status = serializers.CharField(read_only=True) status = serializers.CharField(read_only=True)
@@ -431,7 +443,7 @@ class PrintingJobDetailSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.PrintingJob model = models.PrintingJob
fields = [ 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', 'quantity', 'unit', 'size', 'pieces', 'description',
'work_state', 'work_state_display', 'work_state', 'work_state_display',
'status', 'status_id', 'is_completed', 'has_started', 'status', 'status_id', 'is_completed', 'has_started',

View File

@@ -197,6 +197,40 @@ class PrintingOrderAPITestCase(TestCase):
self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['is_invalid'], True) 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): def test_retrieve_printing_order(self):
"""测试获取订单详情""" """测试获取订单详情"""
order = printing_models.PrintingOrder.objects.create( order = printing_models.PrintingOrder.objects.create(

View File

@@ -492,6 +492,45 @@ class PrintingJobAPITestCase(TestCase):
self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['count'], 1)
self.assertEqual(response.data['results'][0]['product'], self.product.id) 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): def test_filter_by_quantity_range(self):
"""测试按数量范围过滤""" """测试按数量范围过滤"""
printing_models.PrintingJob.objects.create( printing_models.PrintingJob.objects.create(

View File

@@ -73,6 +73,7 @@ class HasActivatePrintingOrderPermission(BasePermission):
class PrintingOrderFilterSet(django_filters.FilterSet): 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_name = django_filters.CharFilter(field_name='customer__name', lookup_expr='icontains')
customer_phone = django_filters.CharFilter(field_name='customer__phone', lookup_expr='icontains') customer_phone = django_filters.CharFilter(field_name='customer__phone', lookup_expr='icontains')
fabric = django_filters.CharFilter(lookup_expr='icontains') fabric = django_filters.CharFilter(lookup_expr='icontains')
@@ -87,7 +88,7 @@ class PrintingOrderFilterSet(django_filters.FilterSet):
class Meta: class Meta:
model = models.PrintingOrder 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 @staticmethod
def _parse_date_or_datetime(value: str | None) -> tuple[datetime | None, bool]: def _parse_date_or_datetime(value: str | None) -> tuple[datetime | None, bool]:
@@ -168,6 +169,7 @@ class PrintingOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
查询参数: 查询参数:
- customer: 客户ID - customer: 客户ID
- external_order_id: 外部订单编号(模糊查询)
- customer_name: 客户名称(模糊查询) - customer_name: 客户名称(模糊查询)
- customer_phone: 客户电话(模糊查询) - customer_phone: 客户电话(模糊查询)
- fabric: 面料(模糊查询) - fabric: 面料(模糊查询)
@@ -343,6 +345,7 @@ class PrintingOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
class PrintingJobFilterSet(django_filters.FilterSet): class PrintingJobFilterSet(django_filters.FilterSet):
"""印染款式明细过滤器""" """印染款式明细过滤器"""
printing_order = django_filters.NumberFilter() 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 = django_filters.NumberFilter()
product_name = django_filters.CharFilter(field_name='product__name', lookup_expr='icontains') product_name = django_filters.CharFilter(field_name='product__name', lookup_expr='icontains')
unit = django_filters.CharFilter(lookup_expr='icontains') unit = django_filters.CharFilter(lookup_expr='icontains')
@@ -353,7 +356,7 @@ class PrintingJobFilterSet(django_filters.FilterSet):
class Meta: class Meta:
model = models.PrintingJob model = models.PrintingJob
fields = ['printing_order', 'product'] fields = ['printing_order', 'product', 'external_order_id']
class PrintingJobViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet): class PrintingJobViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
@@ -379,6 +382,7 @@ class PrintingJobViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
查询参数: 查询参数:
- printing_order: 印染订单ID - printing_order: 印染订单ID
- external_order_id: 外部订单编号(按所属订单模糊查询)
- product: 产品ID - product: 产品ID
- product_name: 产品名称(模糊查询) - product_name: 产品名称(模糊查询)
- unit: 单位(模糊查询) - unit: 单位(模糊查询)

View File

@@ -187,6 +187,9 @@ class PrintingJobInline(admin.StackedInline):
class PrintingOrderAdmin(admin.ModelAdmin): class PrintingOrderAdmin(admin.ModelAdmin):
list_display = ( list_display = (
'oid', 'oid',
'external_order_id',
'external_customer_name',
'external_employee_name',
'customer_name', 'customer_name',
'progress_percent', 'progress_percent',
'created_at', 'created_at',
@@ -194,11 +197,54 @@ class PrintingOrderAdmin(admin.ModelAdmin):
) )
search_fields = ( search_fields = (
'=id', '=id',
'external_order_id',
'external_customer_id',
'external_customer_name',
'external_employee_name',
'customer__name', 'customer__name',
'fabric', 'fabric',
'craft', 'craft',
'description', '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('<pre style="white-space: pre-wrap;">{}</pre>', json.dumps(obj.external_raw or {}, ensure_ascii=False, indent=2))
def save_formset(self, request, form, formset, change): def save_formset(self, request, form, formset, change):