|
@@ -0,0 +1,519 @@
|
|
|
|
|
+from datetime import UTC, date, datetime
|
|
|
|
|
+
|
|
|
|
|
+from sqlalchemy import (
|
|
|
|
|
+ JSON,
|
|
|
|
|
+ BigInteger,
|
|
|
|
|
+ Column,
|
|
|
|
|
+ Date,
|
|
|
|
|
+ ForeignKey,
|
|
|
|
|
+ Index,
|
|
|
|
|
+ String,
|
|
|
|
|
+ Table,
|
|
|
|
|
+ Text,
|
|
|
|
|
+ UniqueConstraint,
|
|
|
|
|
+)
|
|
|
|
|
+from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
|
|
|
|
+
|
|
|
|
|
+from app.infrastructure.mysql.types import UTCDateTime
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def utc_now() -> datetime:
|
|
|
|
|
+ return datetime.now(UTC)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class CoreBase(DeclarativeBase):
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+admin_user_roles = Table(
|
|
|
|
|
+ "admin_user_roles",
|
|
|
|
|
+ CoreBase.metadata,
|
|
|
|
|
+ Column("admin_user_id", String(26), ForeignKey("admin_users.id"), primary_key=True),
|
|
|
|
|
+ Column("role_id", String(26), ForeignKey("roles.id"), primary_key=True),
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+role_permissions = Table(
|
|
|
|
|
+ "role_permissions",
|
|
|
|
|
+ CoreBase.metadata,
|
|
|
|
|
+ Column("role_id", String(26), ForeignKey("roles.id"), primary_key=True),
|
|
|
|
|
+ Column(
|
|
|
|
|
+ "permission_id",
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("permissions.id"),
|
|
|
|
|
+ primary_key=True,
|
|
|
|
|
+ ),
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class H5UserRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "h5_users"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ Index("ix_h5_users_status_created", "status", "created_at"),
|
|
|
|
|
+ Index("ix_h5_users_source", "source_code"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ mobile: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
|
|
|
|
|
+ mobile_masked: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ display_name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ region_code: Mapped[str | None] = mapped_column(String(12))
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
|
|
|
|
|
+ source_code: Mapped[str] = mapped_column(String(64), nullable=False, default="DIRECT")
|
|
|
|
|
+ last_login_at: Mapped[datetime | None] = mapped_column(UTCDateTime())
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+ updated_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
+ UTCDateTime(), nullable=False, default=utc_now, onupdate=utc_now
|
|
|
|
|
+ )
|
|
|
|
|
+ version: Mapped[int] = mapped_column(nullable=False, default=1)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class PermissionRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "permissions"
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ code: Mapped[str] = mapped_column(String(128), unique=True, nullable=False)
|
|
|
|
|
+ name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ resource: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ action: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class RoleRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "roles"
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ code: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
|
|
|
|
|
+ name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ data_scope: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
|
|
|
|
|
+ permissions: Mapped[list[PermissionRecord]] = relationship(
|
|
|
|
|
+ secondary=role_permissions,
|
|
|
|
|
+ lazy="selectin",
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class AdminUserRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "admin_users"
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ username: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
|
|
|
|
|
+ password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
|
|
|
+ display_name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
|
|
|
|
|
+ roles: Mapped[list[RoleRecord]] = relationship(
|
|
|
|
|
+ secondary=admin_user_roles,
|
|
|
|
|
+ lazy="selectin",
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class AuthSessionRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "auth_sessions"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ Index(
|
|
|
|
|
+ "ix_auth_sessions_subject",
|
|
|
|
|
+ "subject_type",
|
|
|
|
|
+ "subject_id",
|
|
|
|
|
+ "revoked_at",
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ subject_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
|
|
|
+ subject_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ refresh_jti_hash: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
|
|
|
|
|
+ expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ revoked_at: Mapped[datetime | None] = mapped_column(UTCDateTime())
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class SalespersonRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "salespersons"
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ admin_user_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("admin_users.id"),
|
|
|
|
|
+ unique=True,
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ salesperson_code: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(32),
|
|
|
|
|
+ unique=True,
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
+ UTCDateTime(),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ default=utc_now,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class PromotionCodeRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "promotion_codes"
|
|
|
|
|
+ __table_args__ = (Index("ix_promotion_codes_salesperson", "salesperson_id", "status"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ code: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
|
|
|
|
|
+ salesperson_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("salespersons.id"),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ channel: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(
|
|
|
|
|
+ UTCDateTime(),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ default=utc_now,
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class LeadAttributionRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "lead_attributions"
|
|
|
|
|
+ __table_args__ = (Index("ix_lead_attributions_salesperson", "salesperson_id", "last_touch_at"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("h5_users.id"),
|
|
|
|
|
+ unique=True,
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ salesperson_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("salespersons.id"),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ promotion_code_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("promotion_codes.id"),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ source_code: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ visit_count: Mapped[int] = mapped_column(nullable=False, default=1)
|
|
|
|
|
+ first_touch_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ last_touch_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class OrderAttributionRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "order_attributions"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ Index("ix_order_attributions_salesperson", "salesperson_id", "attributed_at"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ order_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("enrollment_orders.id"),
|
|
|
|
|
+ unique=True,
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("h5_users.id"),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ salesperson_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("salespersons.id"),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ promotion_code_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26),
|
|
|
|
|
+ ForeignKey("promotion_codes.id"),
|
|
|
|
|
+ nullable=False,
|
|
|
|
|
+ )
|
|
|
|
|
+ source_code: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ amount_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
|
|
|
+ attributed_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class ProductRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "products"
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ product_code: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
|
|
|
|
|
+ name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
|
|
|
+ category: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ summary: Mapped[str] = mapped_column(String(500), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class ProductVersionRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "product_versions"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ UniqueConstraint("product_id", "version_no", name="uq_product_version"),
|
|
|
|
|
+ Index("ix_product_versions_availability", "status", "effective_from", "effective_to"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ product_id: Mapped[str] = mapped_column(String(26), ForeignKey("products.id"), nullable=False)
|
|
|
|
|
+ version_no: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ effective_from: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ effective_to: Mapped[datetime | None] = mapped_column(UTCDateTime())
|
|
|
|
|
+ rule_version: Mapped[str] = mapped_column(String(32), nullable=False, default="eligibility-v1")
|
|
|
|
|
+ rate_version: Mapped[str] = mapped_column(String(32), nullable=False, default="rate-v1")
|
|
|
|
|
+ terms_summary: Mapped[str] = mapped_column(Text, nullable=False, default="")
|
|
|
|
|
+ plans: Mapped[list["PlanRecord"]] = relationship(
|
|
|
|
|
+ back_populates="product_version",
|
|
|
|
|
+ cascade="all, delete-orphan",
|
|
|
|
|
+ lazy="selectin",
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class PlanRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "plans"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ UniqueConstraint("product_version_id", "plan_code", name="uq_plan_version_code"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ product_version_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("product_versions.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ plan_code: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
|
|
|
+ summary: Mapped[str] = mapped_column(String(500), nullable=False, default="")
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
|
|
|
|
|
+ premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0)
|
|
|
|
|
+ coverage_amount_cents: Mapped[int] = mapped_column(
|
|
|
|
|
+ BigInteger, nullable=False, default=0
|
|
|
|
|
+ )
|
|
|
|
|
+ min_age: Mapped[int] = mapped_column(nullable=False, default=0)
|
|
|
|
|
+ max_age: Mapped[int] = mapped_column(nullable=False, default=100)
|
|
|
|
|
+ product_version: Mapped[ProductVersionRecord] = relationship(back_populates="plans")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class ProductChangeLogRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "product_change_logs"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ Index("ix_product_change_logs_product_created", "product_id", "created_at"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ product_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("products.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ version_id: Mapped[str | None] = mapped_column(String(26))
|
|
|
|
|
+ action: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ actor_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ actor_name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ detail_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class EligibilityRuleRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "eligibility_rules"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ UniqueConstraint("product_version_id", "rule_code", name="uq_eligibility_rule"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ product_version_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("product_versions.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ rule_code: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ rule_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ operator: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
|
|
|
+ parameters_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ failure_code: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ failure_message: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class RateTableRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "rate_tables"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ UniqueConstraint("product_version_id", "rate_code", name="uq_rate_code"),
|
|
|
|
|
+ Index(
|
|
|
|
|
+ "ix_rate_lookup",
|
|
|
|
|
+ "product_version_id",
|
|
|
|
|
+ "plan_id",
|
|
|
|
|
+ "region_group",
|
|
|
|
|
+ "min_age",
|
|
|
|
|
+ "max_age",
|
|
|
|
|
+ "effective_from",
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ product_version_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("product_versions.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ plan_id: Mapped[str] = mapped_column(String(26), ForeignKey("plans.id"), nullable=False)
|
|
|
|
|
+ rate_code: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ min_age: Mapped[int] = mapped_column(nullable=False)
|
|
|
|
|
+ max_age: Mapped[int] = mapped_column(nullable=False)
|
|
|
|
|
+ region_group: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ occupation_group: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
|
|
|
+ currency: Mapped[str] = mapped_column(String(3), nullable=False, default="CNY")
|
|
|
|
|
+ effective_from: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ effective_to: Mapped[datetime | None] = mapped_column(UTCDateTime())
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class QuoteRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "quotes"
|
|
|
|
|
+ __table_args__ = (Index("ix_quotes_user_status", "h5_user_id", "status", "expires_at"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
|
|
|
|
|
+ product_id: Mapped[str] = mapped_column(String(26), ForeignKey("products.id"), nullable=False)
|
|
|
|
|
+ product_version_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("product_versions.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ plan_id: Mapped[str] = mapped_column(String(26), ForeignKey("plans.id"), nullable=False)
|
|
|
|
|
+ insured_age: Mapped[int] = mapped_column(nullable=False)
|
|
|
|
|
+ insured_region_code: Mapped[str] = mapped_column(String(12), nullable=False)
|
|
|
|
|
+ occupation_code: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ relationship: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
|
|
|
+ currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
|
|
|
+ rule_version: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ rate_version: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class EnrollmentDraftRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "enrollment_drafts"
|
|
|
|
|
+ __table_args__ = (Index("ix_drafts_user_status", "h5_user_id", "status", "created_at"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
|
|
|
|
|
+ quote_id: Mapped[str] = mapped_column(String(26), ForeignKey("quotes.id"), nullable=False)
|
|
|
|
|
+ applicant_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ insured_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ contact_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class UserConfirmationRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "user_confirmations"
|
|
|
|
|
+ __table_args__ = (Index("ix_confirmations_subject", "draft_id", "status"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
|
|
|
|
|
+ draft_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("enrollment_drafts.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ token_hash: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class EnrollmentOrderRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "enrollment_orders"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ UniqueConstraint(
|
|
|
|
|
+ "h5_user_id",
|
|
|
|
|
+ "idempotency_key",
|
|
|
|
|
+ name="uq_orders_user_idempotency",
|
|
|
|
|
+ ),
|
|
|
|
|
+ Index("ix_orders_user_status", "h5_user_id", "status", "created_at"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ order_no: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
|
|
|
|
|
+ quote_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("quotes.id"), unique=True, nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ draft_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("enrollment_drafts.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ confirmation_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("user_confirmations.id"), unique=True, nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ idempotency_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ product_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ product_version_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ plan_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ applicant_snapshot_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ insured_snapshot_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ amount_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
|
|
|
+ currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class PaymentTransactionRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "payment_transactions"
|
|
|
|
|
+ __table_args__ = (
|
|
|
|
|
+ UniqueConstraint(
|
|
|
|
|
+ "order_id",
|
|
|
|
|
+ "idempotency_key",
|
|
|
|
|
+ name="uq_payments_order_idempotency",
|
|
|
|
|
+ ),
|
|
|
|
|
+ Index("ix_payments_order_status", "order_id", "status"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ payment_no: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
|
|
|
|
|
+ order_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("enrollment_orders.id"), nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ transaction_type: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
|
|
|
+ provider: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ idempotency_key: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
|
|
|
+ amount_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
|
|
|
+ currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ provider_transaction_no: Mapped[str | None] = mapped_column(String(64), unique=True)
|
|
|
|
|
+ succeeded_at: Mapped[datetime | None] = mapped_column(UTCDateTime())
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class PolicyRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "policies"
|
|
|
|
|
+ __table_args__ = (Index("ix_policies_user_status", "h5_user_id", "status", "coverage_end"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ policy_no: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
|
|
|
|
|
+ order_id: Mapped[str] = mapped_column(
|
|
|
|
|
+ String(26), ForeignKey("enrollment_orders.id"), unique=True, nullable=False
|
|
|
|
|
+ )
|
|
|
|
|
+ h5_user_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ product_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ product_version_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ plan_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
|
|
|
|
|
+ currency: Mapped[str] = mapped_column(String(3), nullable=False)
|
|
|
|
|
+ coverage_start: Mapped[date] = mapped_column(Date, nullable=False)
|
|
|
|
|
+ coverage_end: Mapped[date] = mapped_column(Date, nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ issued_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class OutboxEventRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "outbox_events"
|
|
|
|
|
+ __table_args__ = (Index("ix_outbox_dispatch", "status", "created_at"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ aggregate_type: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ aggregate_id: Mapped[str] = mapped_column(String(26), nullable=False)
|
|
|
|
|
+ event_type: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
|
|
|
+ payload_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class AsyncTaskRecord(CoreBase):
|
|
|
|
|
+ __tablename__ = "async_tasks"
|
|
|
|
|
+ __table_args__ = (Index("ix_async_tasks_claim", "status", "created_at"),)
|
|
|
|
|
+
|
|
|
|
|
+ id: Mapped[str] = mapped_column(String(26), primary_key=True)
|
|
|
|
|
+ task_type: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
|
|
|
+ business_key: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
|
|
|
+ idempotency_key: Mapped[str] = mapped_column(String(128), unique=True, nullable=False)
|
|
|
|
|
+ payload_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
|
|
|
|
|
+ status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
|
|
|
+ attempt_count: Mapped[int] = mapped_column(nullable=False, default=0)
|
|
|
|
|
+ created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
|