from datetime import datetime from decimal import Decimal from sqlalchemy import DateTime, Integer, Numeric, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.common.enums import PermissionFilterStrategy from app.core.base_model import PaymentModelMixin, TenantMixin, EnterpriseMixin from .enums import QuotaStatusEnum class QuotaModel(PaymentModelMixin, TenantMixin, EnterpriseMixin): """额度模型""" __tablename__ = "pay_expense_quota" __table_args__ = {"comment": "额度表"} __permission_strategy__ = PermissionFilterStrategy.ENTERPRISE_BASED employee_id: Mapped[str] = mapped_column( String(64), index=True, comment="员工ID" ) institution_id: Mapped[str] = mapped_column( String(64), index=True, comment="制度ID" ) out_biz_no: Mapped[str | None] = mapped_column( String(64), unique=True, index=True, comment="外部业务编号" ) quota_id: Mapped[str | None] = mapped_column( String(64), comment="额度ID(支付宝返回)或关联的发放规则ID(issue_rule_id)" ) total_amount: Mapped[Decimal | None] = mapped_column( Numeric(12, 2), default=0, comment="总金额" ) available_amount: Mapped[Decimal | None] = mapped_column( Numeric(12, 2), default=0, comment="可用金额" ) valid_from: Mapped[datetime | None] = mapped_column( DateTime, comment="有效期开始" ) valid_to: Mapped[datetime | None] = mapped_column( DateTime, comment="有效期结束" ) quota_type: Mapped[str | None] = mapped_column( String(32), default="CAP", comment="额度类型: CAP(余额)/COUPON(点券)/COUNT(次卡)" ) target_type: Mapped[str | None] = mapped_column( String(32), comment="额度维度: INSTITUTION(制度)/EXPENSE_TYPE(费用类型)" ) target_id: Mapped[str | None] = mapped_column( String(64), comment="额度维度ID" ) status: Mapped[str] = mapped_column( String(32), default=QuotaStatusEnum.QUOTA_ACTIVE.value, comment="状态: QUOTA_ACTIVE/QUOTA_FROZEN/QUOTA_EXHAUSTED/QUOTA_EXPIRED" ) class IssueBatchModel(PaymentModelMixin, TenantMixin, EnterpriseMixin): """手工发放批次模型""" __tablename__ = "pay_expense_issue_batch" __table_args__ = {"comment": "手工发放批次表"} __permission_strategy__ = PermissionFilterStrategy.ENTERPRISE_BASED issue_batch_id: Mapped[str | None] = mapped_column( String(64), unique=True, index=True, comment="发放批次ID(支付宝返回)" ) batch_no: Mapped[str] = mapped_column( String(64), unique=True, index=True, comment="发放批次号(幂等)" ) institution_id: Mapped[str] = mapped_column( String(64), index=True, comment="制度ID" ) issue_name: Mapped[str] = mapped_column( String(64), comment="发放名称" ) quota_type: Mapped[str] = mapped_column( String(32), default="COUPON", comment="额度类型" ) share_mode: Mapped[str] = mapped_column( String(8), default="0", comment="是否可转赠: 0/1" ) total_count: Mapped[int] = mapped_column( Integer, default=0, comment="发放总人数" ) total_amount: Mapped[Decimal | None] = mapped_column( Numeric(12, 2), default=0, comment="发放总金额" ) status: Mapped[str] = mapped_column( String(32), default="ACTIVE", comment="状态: ACTIVE/CANCELLED" ) effective_start_date: Mapped[datetime | None] = mapped_column( DateTime, comment="额度有效起始时间" ) effective_end_date: Mapped[datetime | None] = mapped_column( DateTime, comment="额度有效结束时间" ) issue_desc: Mapped[str | None] = mapped_column( Text, comment="发放说明" ) class QuotaChangeLogModel(PaymentModelMixin, TenantMixin, EnterpriseMixin): """额度变更记录表""" __tablename__ = "pay_expense_quota_change_log" __table_args__ = {"comment": "额度变更记录表"} __permission_strategy__ = PermissionFilterStrategy.ENTERPRISE_BASED quota_id: Mapped[str] = mapped_column( String(64), index=True, comment="额度ID" ) employee_id: Mapped[str] = mapped_column( String(64), comment="员工ID" ) institution_id: Mapped[str] = mapped_column( String(64), comment="制度ID" ) change_type: Mapped[str] = mapped_column( String(32), comment="变更类型: ISSUE(发放)/ADJUST(调整)/CANCEL(作废)" ) coupon_name: Mapped[str | None] = mapped_column( String(128), comment="点券名称" ) change_amount: Mapped[Decimal] = mapped_column( Numeric(12, 2), default=0, comment="变更金额(正为增加,负为减少)" ) before_amount: Mapped[Decimal | None] = mapped_column( Numeric(12, 2), comment="变更前金额" ) after_amount: Mapped[Decimal | None] = mapped_column( Numeric(12, 2), comment="变更后金额" ) change_desc: Mapped[str | None] = mapped_column( Text, comment="变更说明" )