forked from erp-dev/erp
213 lines
8.6 KiB
Python
213 lines
8.6 KiB
Python
"""
|
||
Shipment API 序列化器
|
||
"""
|
||
from rest_framework import serializers
|
||
|
||
from shipment.models import ExternalFinishedProduct, SalesItem, Shipment
|
||
|
||
|
||
class ShipmentSerializer(serializers.ModelSerializer):
|
||
"""
|
||
出货单序列化器(只读,用于返回数据)
|
||
"""
|
||
customer_name = serializers.CharField(source='customer.name', read_only=True)
|
||
created_by_id = serializers.IntegerField(source='created_by.id', read_only=True, allow_null=True)
|
||
created_by_name = serializers.SerializerMethodField()
|
||
items_count = serializers.SerializerMethodField()
|
||
cancelled_by_id = serializers.IntegerField(source='cancelled_by.id', read_only=True, allow_null=True)
|
||
cancelled_by_name = serializers.SerializerMethodField()
|
||
status_display = serializers.CharField(source='get_status_display', read_only=True)
|
||
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
|
||
fields = [
|
||
'id', 'merchant_id', 'merchant_name',
|
||
'customer', 'customer_name', 'shipment_date', 'area', 'remark',
|
||
'status', 'status_display',
|
||
'external_id',
|
||
'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']
|
||
|
||
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
|
||
|
||
def get_items_count(self, obj):
|
||
return obj.items.count()
|
||
|
||
def get_cancelled_by_name(self, obj):
|
||
if obj.cancelled_by:
|
||
employee = getattr(obj.cancelled_by, 'employee', None)
|
||
if employee:
|
||
return employee.name
|
||
return obj.cancelled_by.username
|
||
return None
|
||
|
||
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',
|
||
'remark',
|
||
'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):
|
||
"""
|
||
出货单创建序列化器(普通版)
|
||
"""
|
||
customer = serializers.IntegerField(help_text='客户ID')
|
||
shipment_date = serializers.DateField(help_text='出货日期')
|
||
area = serializers.CharField(max_length=30, required=False, default='', allow_blank=True, help_text='出货地区(可选)')
|
||
remark = serializers.CharField(required=False, default='', allow_blank=True, help_text='备注')
|
||
sales_items = serializers.ListField(
|
||
child=serializers.IntegerField(),
|
||
required=False,
|
||
default=list,
|
||
help_text='要关联的销售品ID列表'
|
||
)
|
||
|
||
def validate_sales_items(self, value):
|
||
# 去重
|
||
return list(set(value)) if value else []
|
||
|
||
class ExternalFinishedProductInputSerializer(serializers.Serializer):
|
||
"""外部成品表写入结构(external create 专用)"""
|
||
style_name = serializers.CharField(max_length=200)
|
||
num_of_rolls = serializers.IntegerField(min_value=0)
|
||
remark = serializers.CharField(max_length=200, required=False, allow_blank=True, allow_null=True, default='')
|
||
|
||
|
||
class ShipmentCreateExternalSerializer(serializers.Serializer):
|
||
"""
|
||
出货单创建序列化器(external 版)
|
||
|
||
特点:
|
||
- 不绑定任何 SalesItem
|
||
- 必须提供 external_id
|
||
- 同时写入 ExternalFinishedProduct 列表并关联到 Shipment
|
||
"""
|
||
customer = serializers.IntegerField(help_text='客户ID')
|
||
shipment_date = serializers.DateField(help_text='出货日期')
|
||
area = serializers.CharField(max_length=30, required=False, default='', allow_blank=True, help_text='出货地区(可选)')
|
||
remark = serializers.CharField(required=False, default='', allow_blank=True, help_text='备注')
|
||
external_id = serializers.CharField(max_length=120, help_text='外部订单号(必填)')
|
||
external_finished_products = serializers.ListField(
|
||
child=ExternalFinishedProductInputSerializer(),
|
||
required=True,
|
||
help_text='外部成品表结构数组(必填)'
|
||
)
|
||
|
||
def validate_external_id(self, value):
|
||
value = (value or '').strip()
|
||
if not value:
|
||
raise serializers.ValidationError('external_id 不能为空')
|
||
return value
|
||
|
||
def validate_external_finished_products(self, value):
|
||
if not value:
|
||
raise serializers.ValidationError('external_finished_products 不能为空')
|
||
return value
|
||
|
||
|
||
class ShipmentUpdateSerializer(serializers.Serializer):
|
||
"""
|
||
出货单更新序列化器(PATCH/PUT)
|
||
|
||
说明:本次新增字段 area,需要保证更新入口可写入并回显。
|
||
"""
|
||
customer = serializers.IntegerField(required=False, help_text='客户ID(可选)')
|
||
shipment_date = serializers.DateField(required=False, help_text='出货日期(可选)')
|
||
area = serializers.CharField(max_length=30, required=False, allow_blank=True, help_text='出货地区(可选)')
|
||
remark = serializers.CharField(required=False, allow_blank=True, help_text='备注(可选)')
|
||
external_id = serializers.CharField(max_length=120, required=False, allow_blank=True, allow_null=True, help_text='外部订单号(可选)')
|
||
|
||
|
||
class SalesItemSerializer(serializers.Serializer):
|
||
"""
|
||
销售品序列化器(只读)
|
||
|
||
用于返回销售品数据
|
||
"""
|
||
id = serializers.IntegerField(read_only=True)
|
||
name = serializers.CharField(read_only=True)
|
||
quantity = serializers.DecimalField(max_digits=12, decimal_places=2, read_only=True)
|
||
unit = serializers.IntegerField(read_only=True)
|
||
unit_display = serializers.SerializerMethodField()
|
||
position = serializers.CharField(read_only=True)
|
||
remark = serializers.CharField(read_only=True)
|
||
printing_job_id = serializers.IntegerField(read_only=True)
|
||
customer_id = serializers.IntegerField(read_only=True)
|
||
shipment_id = serializers.IntegerField(source='shipment.id', read_only=True, allow_null=True)
|
||
shipment_date = serializers.DateField(source='shipment.shipment_date', read_only=True, allow_null=True)
|
||
created_at = serializers.DateTimeField(read_only=True)
|
||
created_by_id = serializers.IntegerField(source='created_by.id', read_only=True, allow_null=True)
|
||
created_by_name = serializers.SerializerMethodField()
|
||
|
||
def get_unit_display(self, obj):
|
||
return obj.get_unit_display()
|
||
|
||
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
|