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 = 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',
|
||||||
|
|||||||
@@ -196,6 +196,40 @@ class PrintingOrderAPITestCase(TestCase):
|
|||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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):
|
||||||
"""测试获取订单详情"""
|
"""测试获取订单详情"""
|
||||||
|
|||||||
@@ -491,6 +491,45 @@ class PrintingJobAPITestCase(TestCase):
|
|||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
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):
|
||||||
"""测试按数量范围过滤"""
|
"""测试按数量范围过滤"""
|
||||||
|
|||||||
@@ -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: 单位(模糊查询)
|
||||||
|
|||||||
@@ -186,19 +186,65 @@ class PrintingJobInline(admin.StackedInline):
|
|||||||
@admin.register(models.PrintingOrder)
|
@admin.register(models.PrintingOrder)
|
||||||
class PrintingOrderAdmin(admin.ModelAdmin):
|
class PrintingOrderAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'oid',
|
'oid',
|
||||||
'customer_name',
|
'external_order_id',
|
||||||
|
'external_customer_name',
|
||||||
|
'external_employee_name',
|
||||||
|
'customer_name',
|
||||||
'progress_percent',
|
'progress_percent',
|
||||||
'created_at',
|
'created_at',
|
||||||
'outgoing_date',
|
'outgoing_date',
|
||||||
)
|
)
|
||||||
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):
|
||||||
|
|||||||
Reference in New Issue
Block a user