1
0
forked from erp-dev/erp

feat: shipment change && version modelize

This commit is contained in:
2026-07-09 23:03:22 +08:00
parent 36e4bb6de6
commit 48e4782e1e
23 changed files with 947 additions and 36 deletions

View File

@@ -7,6 +7,7 @@ from rest_framework import serializers
from rest_framework.fields import empty
from api_v1.models import UploadedFile
from api_v1.external_datetime import parse_external_china_datetime
from api_v1.utils.media import build_public_media_url
from api_v1.views.shipment.serializers import SalesItemSerializer
from printing import models
@@ -54,7 +55,11 @@ def resolve_printing_order_kd_riqi(obj):
value = getattr(obj, 'kd_riqi', None)
if value is not None:
return serializers.DateTimeField().to_representation(value)
return _resolve_printing_order_external_first_record_field(obj, 'KdRiQi')
raw_value = _resolve_printing_order_external_first_record_field(obj, 'KdRiQi')
parsed = parse_external_china_datetime(raw_value)
if parsed is None:
return raw_value
return serializers.DateTimeField().to_representation(parsed)
def _serialize_plate_images(raw_value, request):
@@ -354,13 +359,24 @@ class PrintingOrderCreateUpdateSerializer(serializers.ModelSerializer):
],
help_text="出货日期时间(可仅传 YYYY-MM-DD将自动视为 00:00:00",
)
kd_riqi = serializers.DateTimeField(
required=False,
allow_null=True,
input_formats=[
"iso-8601",
"%Y-%m-%d",
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M",
],
help_text="外部开单日期时间(可仅传 YYYY-MM-DD将自动视为 00:00:00",
)
class Meta:
model = models.PrintingOrder
fields = [
'id', 'customer', 'fabric', 'width', 'is_urgent', 'area', 'address',
'fabric_source', 'is_fabric_received', 'craft', 'description',
'outgoing_date', 'curve', 'new_curve', 'position',
'outgoing_date', 'kd_riqi', 'curve', 'new_curve', 'position',
'printing_warn', 'rolling_warn', 'production_warn', 'is_invalid',
'process', 'external_order_id',
]

View File

@@ -94,6 +94,7 @@ class PrintingOrderAPITestCase(TestCase):
'craft': '活性印花',
'description': '测试订单描述',
'outgoing_date': '2025-11-20',
'kd_riqi': '2025-11-19 13:14:15',
'printing_warn': '注意颜色',
'rolling_warn': '注意温度',
'production_warn': '质量检查'
@@ -120,6 +121,9 @@ class PrintingOrderAPITestCase(TestCase):
self.assertEqual(str(local_dt.date()), '2025-11-20')
self.assertEqual(local_dt.hour, 0)
self.assertEqual(local_dt.minute, 0)
self.assertIsNotNone(order.kd_riqi)
local_kd_riqi = timezone.localtime(order.kd_riqi)
self.assertEqual(local_kd_riqi.isoformat(), '2025-11-19T13:14:15+08:00')
def test_filter_outgoing_date_to_includes_whole_day(self):
"""
@@ -284,14 +288,14 @@ class PrintingOrderAPITestCase(TestCase):
self.assertEqual(item['external_customer_name'], '李泽柔')
self.assertEqual(item['external_employee_name'], '丽容')
self.assertEqual(item['bianhao_kd'], '7.07')
self.assertEqual(item['kd_riqi'], '2026-07-06T21:48:58Z')
self.assertEqual(item['kd_riqi'], '2026-07-06T21:48:58+08:00')
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')
self.assertEqual(detail.data['bianhao_kd'], '7.07')
self.assertEqual(detail.data['kd_riqi'], '2026-07-06T21:48:58Z')
self.assertEqual(detail.data['kd_riqi'], '2026-07-06T21:48:58+08:00')
def test_bianhao_kd_returns_null_without_external_order_id(self):
order = printing_models.PrintingOrder.objects.create(
@@ -342,6 +346,39 @@ class PrintingOrderAPITestCase(TestCase):
result_ids = [item['id'] for item in response.data['results']]
self.assertEqual(result_ids, [older.id, newer.id])
self.assertEqual(response.data['results'][0]['kd_riqi'], '2026-07-01T18:00:00+08:00')
def test_order_by_kd_riqi_puts_nulls_last(self):
null_order = printing_models.PrintingOrder.objects.create(
merchant=self.merchant,
customer=self.customer,
fabric='空开单时间',
width='150cm',
external_order_id='KD-NULL',
)
older = printing_models.PrintingOrder.objects.create(
merchant=self.merchant,
customer=self.customer,
fabric='旧开单时间',
width='150cm',
external_order_id='KD-OLDER-NULLS-LAST',
kd_riqi=datetime(2026, 7, 1, 10, 0, tzinfo=dt_timezone.utc),
)
newer = printing_models.PrintingOrder.objects.create(
merchant=self.merchant,
customer=self.customer,
fabric='新开单时间',
width='150cm',
external_order_id='KD-NEWER-NULLS-LAST',
kd_riqi=datetime(2026, 7, 2, 10, 0, tzinfo=dt_timezone.utc),
)
asc_response = self.client.get('/api/v1/printing-orders/?ordering=kd_riqi&limit=3')
desc_response = self.client.get('/api/v1/printing-orders/?ordering=-kd_riqi&limit=3')
self.assertEqual(asc_response.status_code, status.HTTP_200_OK)
self.assertEqual(desc_response.status_code, status.HTTP_200_OK)
self.assertEqual([item['id'] for item in asc_response.data['results']], [older.id, newer.id, null_order.id])
self.assertEqual([item['id'] for item in desc_response.data['results']], [newer.id, older.id, null_order.id])
def test_retrieve_printing_order(self):
"""测试获取订单详情"""
@@ -418,7 +455,8 @@ class PrintingOrderAPITestCase(TestCase):
patch_data = {
'is_urgent': True,
'craft': '新工艺'
'craft': '新工艺',
'kd_riqi': '2025-11-21 09:30:00',
}
response = self.client.patch(
@@ -431,6 +469,7 @@ class PrintingOrderAPITestCase(TestCase):
order.refresh_from_db()
self.assertEqual(order.is_urgent, True)
self.assertEqual(order.craft, '新工艺')
self.assertEqual(timezone.localtime(order.kd_riqi).isoformat(), '2025-11-21T09:30:00+08:00')
self.assertEqual(order.fabric, '原布料') # 未修改字段保持不变
def test_delete_printing_order_forbidden(self):

View File

@@ -10,7 +10,7 @@ from rest_framework.permissions import BasePermission
from rest_framework.permissions import DjangoModelPermissions
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from django.core.exceptions import ValidationError
from django.db.models import CharField, Exists, OuterRef, Prefetch, Subquery
from django.db.models import CharField, Exists, F, OuterRef, Prefetch, Subquery
from django.db.models.functions import Cast, Coalesce
from django.views.decorators.cache import cache_page
from django.views.decorators.http import condition
@@ -38,6 +38,23 @@ from .serializers import (
from .mixins import CustomerVisibilityFilterMixin
class PrintingOrderOrderingFilter(filters.OrderingFilter):
def filter_queryset(self, request, queryset, view):
ordering = self.get_ordering(request, queryset, view)
if not ordering:
return queryset
expressions = []
for field in ordering:
if field == "kd_riqi":
expressions.append(F("kd_riqi").asc(nulls_last=True))
elif field == "-kd_riqi":
expressions.append(F("kd_riqi").desc(nulls_last=True))
else:
expressions.append(field)
return queryset.order_by(*expressions)
class IsPrintingFactory(BasePermission):
"""自定义权限类,允许印染工厂用户访问"""
@@ -276,7 +293,7 @@ class PrintingOrderViewSet(CustomerVisibilityFilterMixin, LimitedModelViewSet):
filter_backends = [
DjangoFilterBackend,
filters.SearchFilter,
filters.OrderingFilter,
PrintingOrderOrderingFilter,
]
filterset_class = PrintingOrderFilterSet
search_fields = ["customer__name", "fabric", "area", "craft", "description"]