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
+235
View File
@@ -0,0 +1,235 @@
"""完整财务 serializers:
- 往来:应收单、应付单、收款单、付款单、核销明细
- 总账:科目、期间、凭证(含分录)、凭证创建
"""
from rest_framework import serializers
from apps.core.serializers import AsyncModelSerializer
from .models import (
Account, Period, Voucher, VoucherEntry,
Receivable, Payable, Receipt, Payment, Allocation,
)
# ============================================================
# 1. 往来序列化(AR / AP)
# ============================================================
class ReceivableSerializer(AsyncModelSerializer):
customer_code = serializers.CharField(source="customer.code", read_only=True)
customer_name = serializers.CharField(source="customer.name", read_only=True)
balance = serializers.DecimalField(max_digits=18, decimal_places=4, read_only=True)
class Meta:
model = Receivable
fields = [
"id", "bill_no", "customer", "customer_code", "customer_name",
"source_type", "source_ref", "bill_date", "due_date",
"total_amount", "paid_amount", "balance", "status", "remark",
"created_at", "updated_at",
]
read_only_fields = [
"id", "bill_no", "paid_amount", "balance", "status",
"created_at", "updated_at",
]
class PayableSerializer(AsyncModelSerializer):
supplier_code = serializers.CharField(source="supplier.code", read_only=True)
supplier_name = serializers.CharField(source="supplier.name", read_only=True)
balance = serializers.DecimalField(max_digits=18, decimal_places=4, read_only=True)
class Meta:
model = Payable
fields = [
"id", "bill_no", "supplier", "supplier_code", "supplier_name",
"source_type", "source_ref", "bill_date", "due_date",
"total_amount", "paid_amount", "balance", "status", "remark",
"created_at", "updated_at",
]
read_only_fields = [
"id", "bill_no", "paid_amount", "balance", "status",
"created_at", "updated_at",
]
class ReceiptSerializer(AsyncModelSerializer):
customer_code = serializers.CharField(source="customer.code", read_only=True)
customer_name = serializers.CharField(source="customer.name", read_only=True)
class Meta:
model = Receipt
fields = [
"id", "bill_no", "customer", "customer_code", "customer_name",
"bill_date", "amount", "method", "status", "remark",
"created_at", "updated_at",
]
read_only_fields = ["id", "status", "created_at", "updated_at"]
class PaymentSerializer(AsyncModelSerializer):
supplier_code = serializers.CharField(source="supplier.code", read_only=True)
supplier_name = serializers.CharField(source="supplier.name", read_only=True)
class Meta:
model = Payment
fields = [
"id", "bill_no", "supplier", "supplier_code", "supplier_name",
"bill_date", "amount", "method", "status", "remark",
"created_at", "updated_at",
]
read_only_fields = ["id", "status", "created_at", "updated_at"]
class AllocationSerializer(AsyncModelSerializer):
receivable_no = serializers.CharField(source="receivable.bill_no", read_only=True, default=None)
payable_no = serializers.CharField(source="payable.bill_no", read_only=True, default=None)
receipt_no = serializers.CharField(source="receipt.bill_no", read_only=True, default=None)
payment_no = serializers.CharField(source="payment.bill_no", read_only=True, default=None)
class Meta:
model = Allocation
fields = [
"id", "kind", "amount",
"receivable", "receivable_no",
"payable", "payable_no",
"receipt", "receipt_no",
"payment", "payment_no",
"created_at",
]
read_only_fields = ["id", "created_at"]
class _AllocationItemInputSerializer(serializers.Serializer):
"""公共核销行输入。
``*_id`` 是显式 API 形式;保留无后缀字段以便客户端沿用模型字段命名。
"""
amount = serializers.DecimalField(max_digits=18, decimal_places=4)
def _document_id(self, attrs, field_name):
plain_name = field_name
id_name = f"{field_name}_id"
plain = attrs.pop(plain_name, None)
explicit = attrs.pop(id_name, None)
if plain is not None and explicit is not None and plain != explicit:
raise serializers.ValidationError(
{field_name: f"{plain_name} 与 {id_name} 不能同时指定不同值"}
)
document_id = explicit if explicit is not None else plain
if document_id is None:
raise serializers.ValidationError({field_name: "必填"})
attrs[field_name] = document_id
return attrs
class ReceiptAllocationItemSerializer(_AllocationItemInputSerializer):
receivable = serializers.IntegerField(required=False, min_value=1)
receivable_id = serializers.IntegerField(required=False, min_value=1, write_only=True)
def validate(self, attrs):
return self._document_id(attrs, "receivable")
class PaymentAllocationItemSerializer(_AllocationItemInputSerializer):
payable = serializers.IntegerField(required=False, min_value=1)
payable_id = serializers.IntegerField(required=False, min_value=1, write_only=True)
def validate(self, attrs):
return self._document_id(attrs, "payable")
class ReceiptAllocationInputSerializer(serializers.Serializer):
allocations = ReceiptAllocationItemSerializer(many=True, allow_empty=False)
class PaymentAllocationInputSerializer(serializers.Serializer):
allocations = PaymentAllocationItemSerializer(many=True, allow_empty=False)
# ============================================================
# 2. 总账序列化(GL)
# ============================================================
class AccountSerializer(AsyncModelSerializer):
category_name = serializers.CharField(source="get_category_display", read_only=True)
balance_type_name = serializers.CharField(source="get_balance_type_display", read_only=True)
class Meta:
model = Account
fields = [
"id", "code", "name", "category", "category_name",
"balance_type", "balance_type_name", "parent",
"is_active", "is_system", "aux_customer", "aux_supplier", "remark",
]
read_only_fields = ["id", "is_system"]
class PeriodSerializer(AsyncModelSerializer):
status_name = serializers.CharField(source="get_status_display", read_only=True)
class Meta:
model = Period
fields = [
"id", "code", "start_date", "end_date",
"status", "status_name", "closed_at", "closed_by",
]
read_only_fields = ["id", "status", "status_name", "closed_at", "closed_by"]
class VoucherEntrySerializer(AsyncModelSerializer):
account_code = serializers.CharField(source="account.code", read_only=True)
account_name = serializers.CharField(source="account.name", read_only=True)
customer_code = serializers.CharField(source="customer.code", read_only=True, default=None)
customer_name = serializers.CharField(source="customer.name", read_only=True, default=None)
supplier_code = serializers.CharField(source="supplier.code", read_only=True, default=None)
supplier_name = serializers.CharField(source="supplier.name", read_only=True, default=None)
class Meta:
model = VoucherEntry
fields = [
"id", "account", "account_code", "account_name",
"customer", "customer_code", "customer_name",
"supplier", "supplier_code", "supplier_name",
"summary", "debit", "credit",
]
read_only_fields = ["id"]
class VoucherSerializer(AsyncModelSerializer):
period_code = serializers.CharField(source="period.code", read_only=True)
source_type_name = serializers.CharField(source="get_source_type_display", read_only=True)
status_name = serializers.CharField(source="get_status_display", read_only=True)
entries = VoucherEntrySerializer(many=True, read_only=True)
class Meta:
model = Voucher
fields = [
"id", "bill_no", "period", "period_code",
"source_type", "source_type_name", "source_ref", "voucher_date",
"total_debit", "total_credit", "status", "status_name",
"summary", "posted_at", "posted_by",
"entries", "created_at", "updated_at",
]
read_only_fields = [
"id", "bill_no", "period", "total_debit",
"total_credit", "status", "posted_at", "posted_by",
"created_at", "updated_at",
]
class VoucherEntryInputSerializer(serializers.Serializer):
account_code = serializers.CharField(max_length=32)
debit = serializers.DecimalField(max_digits=18, decimal_places=4, default=0)
credit = serializers.DecimalField(max_digits=18, decimal_places=4, default=0)
summary = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")
customer_id = serializers.IntegerField(required=False, allow_null=True, default=None)
supplier_id = serializers.IntegerField(required=False, allow_null=True, default=None)
class VoucherCreateInputSerializer(serializers.Serializer):
voucher_date = serializers.DateField()
summary = serializers.CharField(max_length=255, required=False, allow_blank=True, default="")
auto_post = serializers.BooleanField(default=False)
entries = VoucherEntryInputSerializer(many=True)