forked from erp-dev/erp
feat: printing orders and jobs filter with external_order_id
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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):
|
||||
"""测试获取订单详情"""
|
||||
|
||||
@@ -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):
|
||||
"""测试按数量范围过滤"""
|
||||
|
||||
@@ -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: 单位(模糊查询)
|
||||
|
||||
@@ -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('<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):
|
||||
|
||||
Reference in New Issue
Block a user