Files
X-Financial/server/src/app/models/financial_record.py

119 lines
5.8 KiB
Python
Raw Normal View History

2026-05-11 03:51:24 +00:00
from __future__ import annotations
import uuid
from datetime import date, datetime
from decimal import Decimal
from typing import Any
from sqlalchemy import Date, DateTime, ForeignKey, Integer, Numeric, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.types import JSON
from app.db.base_class import Base
class ExpenseClaim(Base):
__tablename__ = "expense_claims"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
claim_no: Mapped[str] = mapped_column(String(50), unique=True, index=True)
employee_id: Mapped[str | None] = mapped_column(
ForeignKey("employees.id"), nullable=True, index=True
)
employee_name: Mapped[str] = mapped_column(String(100), index=True)
department_id: Mapped[str | None] = mapped_column(
ForeignKey("organization_units.id"), nullable=True, index=True
)
department_name: Mapped[str] = mapped_column(String(100), index=True)
project_code: Mapped[str | None] = mapped_column(String(50), nullable=True)
expense_type: Mapped[str] = mapped_column(String(50), index=True)
reason: Mapped[str] = mapped_column(Text())
location: Mapped[str] = mapped_column(String(100))
amount: Mapped[Decimal] = mapped_column(Numeric(12, 2))
currency: Mapped[str] = mapped_column(String(10), default="CNY")
invoice_count: Mapped[int] = mapped_column(Integer, default=0)
occurred_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True)
submitted_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True, index=True
)
status: Mapped[str] = mapped_column(String(30), index=True)
approval_stage: Mapped[str | None] = mapped_column(String(50), nullable=True)
risk_flags_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
items = relationship(
"ExpenseClaimItem",
back_populates="claim",
cascade="all, delete-orphan",
order_by="asc(ExpenseClaimItem.item_date)",
)
class ExpenseClaimItem(Base):
__tablename__ = "expense_claim_items"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
claim_id: Mapped[str] = mapped_column(ForeignKey("expense_claims.id"), index=True)
item_date: Mapped[date] = mapped_column(Date(), index=True)
item_type: Mapped[str] = mapped_column(String(50))
item_reason: Mapped[str] = mapped_column(Text())
item_location: Mapped[str] = mapped_column(String(100))
item_amount: Mapped[Decimal] = mapped_column(Numeric(12, 2))
invoice_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
claim = relationship("ExpenseClaim", back_populates="items")
class AccountsReceivableRecord(Base):
__tablename__ = "accounts_receivable"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
receivable_no: Mapped[str] = mapped_column(String(50), unique=True, index=True)
customer_id: Mapped[str] = mapped_column(String(64), index=True)
customer_name: Mapped[str] = mapped_column(String(120), index=True)
contract_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
invoice_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
amount_receivable: Mapped[Decimal] = mapped_column(Numeric(12, 2))
amount_received: Mapped[Decimal] = mapped_column(Numeric(12, 2))
amount_outstanding: Mapped[Decimal] = mapped_column(Numeric(12, 2))
currency: Mapped[str] = mapped_column(String(10), default="CNY")
posting_date: Mapped[date] = mapped_column(Date(), index=True)
due_date: Mapped[date] = mapped_column(Date(), index=True)
aging_days: Mapped[int] = mapped_column(Integer, default=0)
status: Mapped[str] = mapped_column(String(30), index=True)
risk_flags_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
class AccountsPayableRecord(Base):
__tablename__ = "accounts_payable"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
payable_no: Mapped[str] = mapped_column(String(50), unique=True, index=True)
vendor_id: Mapped[str] = mapped_column(String(64), index=True)
vendor_name: Mapped[str] = mapped_column(String(120), index=True)
invoice_no: Mapped[str | None] = mapped_column(String(100), nullable=True)
amount_payable: Mapped[Decimal] = mapped_column(Numeric(12, 2))
amount_paid: Mapped[Decimal] = mapped_column(Numeric(12, 2))
amount_outstanding: Mapped[Decimal] = mapped_column(Numeric(12, 2))
currency: Mapped[str] = mapped_column(String(10), default="CNY")
posting_date: Mapped[date] = mapped_column(Date(), index=True)
due_date: Mapped[date] = mapped_column(Date(), index=True)
aging_days: Mapped[int] = mapped_column(Integer, default=0)
status: Mapped[str] = mapped_column(String(30), index=True)
risk_flags_json: Mapped[list[Any]] = mapped_column(JSON, default=list)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)