1
0
forked from erp-dev/erp
Files
erpnew/api_v1/views/shipment/serializers.py

213 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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