baseline: 批次A-D 成果 + membership 半成品(测试红)

This commit is contained in:
agent
2026-09-11 23:11:35 +08:00
commit b3f3095d53
311 changed files with 40540 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
"""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"]