Files

236 lines
9.4 KiB
Python
Raw Permalink 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.
"""完整财务 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)