baseline: 批次A-D 成果 + membership 半成品(测试红)
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user