1
0
forked from erp-dev/erp

feat: added sales_items and external_products into shipments list api

This commit is contained in:
2026-01-15 17:27:30 +08:00
parent a0cd168397
commit 13c440a7fe
4 changed files with 68 additions and 2 deletions

View File

@@ -3,7 +3,7 @@ Shipment API 序列化器
"""
from rest_framework import serializers
from shipment.models import Shipment
from shipment.models import ExternalFinishedProduct, SalesItem, Shipment
class ShipmentSerializer(serializers.ModelSerializer):
@@ -20,6 +20,8 @@ class ShipmentSerializer(serializers.ModelSerializer):
external_finished_products_count = serializers.SerializerMethodField()
merchant_id = serializers.IntegerField(source='merchant.id', read_only=True)
merchant_name = serializers.CharField(source='merchant.name', read_only=True)
sales_items = serializers.SerializerMethodField()
external_finished_products = serializers.SerializerMethodField()
class Meta:
model = Shipment
@@ -31,6 +33,8 @@ class ShipmentSerializer(serializers.ModelSerializer):
'cancelled_at', 'cancelled_by_id', 'cancelled_by_name',
'items_count', 'created_by_id', 'created_by_name',
'external_finished_products_count',
'sales_items',
'external_finished_products',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at']
@@ -57,6 +61,51 @@ class ShipmentSerializer(serializers.ModelSerializer):
def get_external_finished_products_count(self, obj):
return obj.external_finished_products.count()
def get_sales_items(self, obj):
"""
出货单关联的销售品明细(无则返回空数组)。
"""
# 优先使用 prefetch 的 related manager兜底为 none()
rel = getattr(obj, 'items', None)
items = list(rel.all()) if rel is not None else []
return SalesItemSerializer(items, many=True).data
def get_external_finished_products(self, obj):
"""
出货单关联的外部成品表明细(无则返回空数组)。
"""
rel = getattr(obj, 'external_finished_products', None)
products = list(rel.all()) if rel is not None else []
return ExternalFinishedProductSerializer(products, many=True).data
class ExternalFinishedProductSerializer(serializers.ModelSerializer):
"""
外部成品表序列化器(只读)
"""
created_by_id = serializers.IntegerField(source='created_by.id', read_only=True, allow_null=True)
created_by_name = serializers.SerializerMethodField()
class Meta:
model = ExternalFinishedProduct
fields = [
'id',
'style_name',
'num_of_rolls',
'created_at',
'created_by_id',
'created_by_name',
]
read_only_fields = fields
def get_created_by_name(self, obj):
if obj.created_by:
employee = getattr(obj.created_by, 'employee', None)
if employee:
return employee.name
return obj.created_by.username
return None
class ShipmentCreateNormalSerializer(serializers.Serializer):
"""

View File

@@ -638,10 +638,22 @@ class ShipmentQueryAPITestCase(TestCase):
self.assertIn(self.shipment1.id, ids)
self.assertNotIn(self.shipment2.id, ids)
# 关键:列表序列化器必须稳定输出明细数组字段(即使为空)
item = next(it for it in data['results'] if it['id'] == self.shipment1.id)
self.assertIn('sales_items', item)
self.assertIsInstance(item['sales_items'], list)
self.assertIn('external_finished_products', item)
self.assertIsInstance(item['external_finished_products'], list)
def test_retrieve_shipment_success(self):
resp = self.client.get(f'/api/v1/shipment/shipments/{self.shipment1.id}/')
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp.json()['id'], self.shipment1.id)
result = resp.json()
self.assertEqual(result['id'], self.shipment1.id)
self.assertIn('sales_items', result)
self.assertIsInstance(result['sales_items'], list)
self.assertIn('external_finished_products', result)
self.assertIsInstance(result['external_finished_products'], list)
def test_retrieve_other_merchant_shipment_404(self):
resp = self.client.get(f'/api/v1/shipment/shipments/{self.shipment2.id}/')