79 lines
3.4 KiB
Python
79 lines
3.4 KiB
Python
"""sales 序列化器(async 兼容)。"""
|
||
|
||
from rest_framework import serializers
|
||
from apps.core.serializers import AsyncModelSerializer
|
||
from .models import SalesOrder, SalesOrderLine, SalesBill, SalesBillLine
|
||
|
||
|
||
class SalesOrderLineSerializer(AsyncModelSerializer):
|
||
product_code = serializers.CharField(source="product.code", read_only=True)
|
||
product_name = serializers.CharField(source="product.name", read_only=True)
|
||
|
||
class Meta:
|
||
model = SalesOrderLine
|
||
fields = ["id", "product", "product_code", "product_name",
|
||
"quantity", "unit_price", "amount", "delivered_qty"]
|
||
read_only_fields = ["id", "amount", "delivered_qty"]
|
||
|
||
|
||
class SalesOrderSerializer(AsyncModelSerializer):
|
||
customer_code = serializers.CharField(source="customer.code", read_only=True)
|
||
warehouse_code = serializers.CharField(source="warehouse.code", read_only=True)
|
||
lines = SalesOrderLineSerializer(many=True, required=False)
|
||
|
||
class Meta:
|
||
model = SalesOrder
|
||
fields = [
|
||
"id", "bill_no", "customer", "customer_code",
|
||
"warehouse", "warehouse_code",
|
||
"bill_date", "expected_date", "total_amount", "state", "remark",
|
||
"lines",
|
||
]
|
||
read_only_fields = ["id", "bill_no", "total_amount", "state"]
|
||
|
||
|
||
class SalesBillLineSerializer(AsyncModelSerializer):
|
||
product_code = serializers.CharField(source="product.code", read_only=True)
|
||
product_name = serializers.CharField(source="product.name", read_only=True)
|
||
unit_name = serializers.SerializerMethodField()
|
||
|
||
class Meta:
|
||
model = SalesBillLine
|
||
fields = ["id", "product", "product_code", "product_name",
|
||
"quantity", "source_unit", "source_quantity", "unit_name",
|
||
"unit_price", "amount", "tax_rate", "tax_amount"]
|
||
read_only_fields = ["id", "amount", "tax_amount"]
|
||
|
||
def get_unit_name(self, obj):
|
||
unit = obj.source_unit or getattr(obj.product, "base_unit", None)
|
||
return unit.name if unit else ""
|
||
|
||
|
||
class SalesBillSerializer(AsyncModelSerializer):
|
||
customer_code = serializers.CharField(source="customer.code", read_only=True)
|
||
customer_name = serializers.CharField(source="customer.name", read_only=True)
|
||
warehouse_code = serializers.CharField(source="warehouse.code", read_only=True)
|
||
round_off = serializers.DecimalField(max_digits=18, decimal_places=4, read_only=True)
|
||
# 单据税额合计 = 各行 tax_amount 之和(D4;前端展示"其中税额")
|
||
tax_total = serializers.SerializerMethodField()
|
||
lines = SalesBillLineSerializer(many=True, required=False)
|
||
|
||
def get_tax_total(self, obj):
|
||
"""在内存里汇总已预取的行,避免每张单一次 aggregate(N+1)。
|
||
|
||
旧实现 `obj.lines.aggregate(Sum("tax_amount"))` 对列表页的每一行都发一条 SQL
|
||
(实测 50 张单 = 50 次聚合)。列表接口已 prefetch `lines`,
|
||
这里直接遍历内存对象即可。详情接口若未预取,all() 也只多一次查询。
|
||
"""
|
||
return str(sum((ln.tax_amount or 0) for ln in obj.lines.all()))
|
||
|
||
class Meta:
|
||
model = SalesBill
|
||
fields = [
|
||
"id", "bill_no", "customer", "customer_code", "customer_name",
|
||
"warehouse", "warehouse_code", "order",
|
||
"bill_date", "total_amount", "round_off", "tax_total", "state", "remark",
|
||
"lines",
|
||
]
|
||
read_only_fields = ["id", "bill_no", "total_amount", "state"]
|