core_models.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. from datetime import UTC, date, datetime
  2. from sqlalchemy import (
  3. JSON,
  4. BigInteger,
  5. Column,
  6. Date,
  7. ForeignKey,
  8. Index,
  9. String,
  10. Table,
  11. Text,
  12. UniqueConstraint,
  13. )
  14. from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
  15. from app.infrastructure.mysql.types import UTCDateTime
  16. def utc_now() -> datetime:
  17. return datetime.now(UTC)
  18. class CoreBase(DeclarativeBase):
  19. pass
  20. admin_user_roles = Table(
  21. "admin_user_roles",
  22. CoreBase.metadata,
  23. Column("admin_user_id", String(26), ForeignKey("admin_users.id"), primary_key=True),
  24. Column("role_id", String(26), ForeignKey("roles.id"), primary_key=True),
  25. )
  26. role_permissions = Table(
  27. "role_permissions",
  28. CoreBase.metadata,
  29. Column("role_id", String(26), ForeignKey("roles.id"), primary_key=True),
  30. Column(
  31. "permission_id",
  32. String(26),
  33. ForeignKey("permissions.id"),
  34. primary_key=True,
  35. ),
  36. )
  37. class H5UserRecord(CoreBase):
  38. __tablename__ = "h5_users"
  39. __table_args__ = (
  40. Index("ix_h5_users_status_created", "status", "created_at"),
  41. Index("ix_h5_users_source", "source_code"),
  42. )
  43. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  44. mobile: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
  45. mobile_masked: Mapped[str] = mapped_column(String(32), nullable=False)
  46. display_name: Mapped[str] = mapped_column(String(64), nullable=False)
  47. region_code: Mapped[str | None] = mapped_column(String(12))
  48. status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
  49. source_code: Mapped[str] = mapped_column(String(64), nullable=False, default="DIRECT")
  50. last_login_at: Mapped[datetime | None] = mapped_column(UTCDateTime())
  51. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  52. updated_at: Mapped[datetime] = mapped_column(
  53. UTCDateTime(), nullable=False, default=utc_now, onupdate=utc_now
  54. )
  55. version: Mapped[int] = mapped_column(nullable=False, default=1)
  56. class PermissionRecord(CoreBase):
  57. __tablename__ = "permissions"
  58. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  59. code: Mapped[str] = mapped_column(String(128), unique=True, nullable=False)
  60. name: Mapped[str] = mapped_column(String(64), nullable=False)
  61. resource: Mapped[str] = mapped_column(String(64), nullable=False)
  62. action: Mapped[str] = mapped_column(String(32), nullable=False)
  63. class RoleRecord(CoreBase):
  64. __tablename__ = "roles"
  65. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  66. code: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
  67. name: Mapped[str] = mapped_column(String(64), nullable=False)
  68. data_scope: Mapped[str] = mapped_column(String(32), nullable=False)
  69. status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
  70. permissions: Mapped[list[PermissionRecord]] = relationship(
  71. secondary=role_permissions,
  72. lazy="selectin",
  73. )
  74. class AdminUserRecord(CoreBase):
  75. __tablename__ = "admin_users"
  76. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  77. username: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
  78. password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
  79. display_name: Mapped[str] = mapped_column(String(64), nullable=False)
  80. status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
  81. roles: Mapped[list[RoleRecord]] = relationship(
  82. secondary=admin_user_roles,
  83. lazy="selectin",
  84. )
  85. class AuthSessionRecord(CoreBase):
  86. __tablename__ = "auth_sessions"
  87. __table_args__ = (
  88. Index(
  89. "ix_auth_sessions_subject",
  90. "subject_type",
  91. "subject_id",
  92. "revoked_at",
  93. ),
  94. )
  95. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  96. subject_type: Mapped[str] = mapped_column(String(16), nullable=False)
  97. subject_id: Mapped[str] = mapped_column(String(26), nullable=False)
  98. refresh_jti_hash: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
  99. expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  100. revoked_at: Mapped[datetime | None] = mapped_column(UTCDateTime())
  101. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  102. class SalespersonRecord(CoreBase):
  103. __tablename__ = "salespersons"
  104. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  105. admin_user_id: Mapped[str] = mapped_column(
  106. String(26),
  107. ForeignKey("admin_users.id"),
  108. unique=True,
  109. nullable=False,
  110. )
  111. salesperson_code: Mapped[str] = mapped_column(
  112. String(32),
  113. unique=True,
  114. nullable=False,
  115. )
  116. name: Mapped[str] = mapped_column(String(64), nullable=False)
  117. status: Mapped[str] = mapped_column(String(32), nullable=False)
  118. created_at: Mapped[datetime] = mapped_column(
  119. UTCDateTime(),
  120. nullable=False,
  121. default=utc_now,
  122. )
  123. class PromotionCodeRecord(CoreBase):
  124. __tablename__ = "promotion_codes"
  125. __table_args__ = (Index("ix_promotion_codes_salesperson", "salesperson_id", "status"),)
  126. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  127. code: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
  128. salesperson_id: Mapped[str] = mapped_column(
  129. String(26),
  130. ForeignKey("salespersons.id"),
  131. nullable=False,
  132. )
  133. channel: Mapped[str] = mapped_column(String(32), nullable=False)
  134. status: Mapped[str] = mapped_column(String(32), nullable=False)
  135. created_at: Mapped[datetime] = mapped_column(
  136. UTCDateTime(),
  137. nullable=False,
  138. default=utc_now,
  139. )
  140. class LeadAttributionRecord(CoreBase):
  141. __tablename__ = "lead_attributions"
  142. __table_args__ = (Index("ix_lead_attributions_salesperson", "salesperson_id", "last_touch_at"),)
  143. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  144. h5_user_id: Mapped[str] = mapped_column(
  145. String(26),
  146. ForeignKey("h5_users.id"),
  147. unique=True,
  148. nullable=False,
  149. )
  150. salesperson_id: Mapped[str] = mapped_column(
  151. String(26),
  152. ForeignKey("salespersons.id"),
  153. nullable=False,
  154. )
  155. promotion_code_id: Mapped[str] = mapped_column(
  156. String(26),
  157. ForeignKey("promotion_codes.id"),
  158. nullable=False,
  159. )
  160. source_code: Mapped[str] = mapped_column(String(32), nullable=False)
  161. visit_count: Mapped[int] = mapped_column(nullable=False, default=1)
  162. first_touch_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  163. last_touch_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  164. class OrderAttributionRecord(CoreBase):
  165. __tablename__ = "order_attributions"
  166. __table_args__ = (
  167. Index("ix_order_attributions_salesperson", "salesperson_id", "attributed_at"),
  168. )
  169. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  170. order_id: Mapped[str] = mapped_column(
  171. String(26),
  172. ForeignKey("enrollment_orders.id"),
  173. unique=True,
  174. nullable=False,
  175. )
  176. h5_user_id: Mapped[str] = mapped_column(
  177. String(26),
  178. ForeignKey("h5_users.id"),
  179. nullable=False,
  180. )
  181. salesperson_id: Mapped[str] = mapped_column(
  182. String(26),
  183. ForeignKey("salespersons.id"),
  184. nullable=False,
  185. )
  186. promotion_code_id: Mapped[str] = mapped_column(
  187. String(26),
  188. ForeignKey("promotion_codes.id"),
  189. nullable=False,
  190. )
  191. source_code: Mapped[str] = mapped_column(String(32), nullable=False)
  192. amount_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
  193. attributed_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  194. class ProductRecord(CoreBase):
  195. __tablename__ = "products"
  196. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  197. product_code: Mapped[str] = mapped_column(String(32), unique=True, nullable=False)
  198. name: Mapped[str] = mapped_column(String(128), nullable=False)
  199. category: Mapped[str] = mapped_column(String(32), nullable=False)
  200. summary: Mapped[str] = mapped_column(String(500), nullable=False)
  201. status: Mapped[str] = mapped_column(String(32), nullable=False)
  202. class ProductVersionRecord(CoreBase):
  203. __tablename__ = "product_versions"
  204. __table_args__ = (
  205. UniqueConstraint("product_id", "version_no", name="uq_product_version"),
  206. Index("ix_product_versions_availability", "status", "effective_from", "effective_to"),
  207. )
  208. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  209. product_id: Mapped[str] = mapped_column(String(26), ForeignKey("products.id"), nullable=False)
  210. version_no: Mapped[str] = mapped_column(String(32), nullable=False)
  211. status: Mapped[str] = mapped_column(String(32), nullable=False)
  212. effective_from: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  213. effective_to: Mapped[datetime | None] = mapped_column(UTCDateTime())
  214. rule_version: Mapped[str] = mapped_column(String(32), nullable=False, default="eligibility-v1")
  215. rate_version: Mapped[str] = mapped_column(String(32), nullable=False, default="rate-v1")
  216. terms_summary: Mapped[str] = mapped_column(Text, nullable=False, default="")
  217. plans: Mapped[list["PlanRecord"]] = relationship(
  218. back_populates="product_version",
  219. cascade="all, delete-orphan",
  220. lazy="selectin",
  221. )
  222. class PlanRecord(CoreBase):
  223. __tablename__ = "plans"
  224. __table_args__ = (
  225. UniqueConstraint("product_version_id", "plan_code", name="uq_plan_version_code"),
  226. )
  227. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  228. product_version_id: Mapped[str] = mapped_column(
  229. String(26), ForeignKey("product_versions.id"), nullable=False
  230. )
  231. plan_code: Mapped[str] = mapped_column(String(32), nullable=False)
  232. name: Mapped[str] = mapped_column(String(128), nullable=False)
  233. summary: Mapped[str] = mapped_column(String(500), nullable=False, default="")
  234. status: Mapped[str] = mapped_column(String(32), nullable=False, default="ACTIVE")
  235. premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False, default=0)
  236. coverage_amount_cents: Mapped[int] = mapped_column(
  237. BigInteger, nullable=False, default=0
  238. )
  239. min_age: Mapped[int] = mapped_column(nullable=False, default=0)
  240. max_age: Mapped[int] = mapped_column(nullable=False, default=100)
  241. product_version: Mapped[ProductVersionRecord] = relationship(back_populates="plans")
  242. class ProductChangeLogRecord(CoreBase):
  243. __tablename__ = "product_change_logs"
  244. __table_args__ = (
  245. Index("ix_product_change_logs_product_created", "product_id", "created_at"),
  246. )
  247. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  248. product_id: Mapped[str] = mapped_column(
  249. String(26), ForeignKey("products.id"), nullable=False
  250. )
  251. version_id: Mapped[str | None] = mapped_column(String(26))
  252. action: Mapped[str] = mapped_column(String(32), nullable=False)
  253. actor_id: Mapped[str] = mapped_column(String(26), nullable=False)
  254. actor_name: Mapped[str] = mapped_column(String(64), nullable=False)
  255. detail_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  256. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  257. class EligibilityRuleRecord(CoreBase):
  258. __tablename__ = "eligibility_rules"
  259. __table_args__ = (
  260. UniqueConstraint("product_version_id", "rule_code", name="uq_eligibility_rule"),
  261. )
  262. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  263. product_version_id: Mapped[str] = mapped_column(
  264. String(26), ForeignKey("product_versions.id"), nullable=False
  265. )
  266. rule_code: Mapped[str] = mapped_column(String(64), nullable=False)
  267. rule_type: Mapped[str] = mapped_column(String(32), nullable=False)
  268. operator: Mapped[str] = mapped_column(String(16), nullable=False)
  269. parameters_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  270. failure_code: Mapped[str] = mapped_column(String(64), nullable=False)
  271. failure_message: Mapped[str] = mapped_column(String(255), nullable=False)
  272. class RateTableRecord(CoreBase):
  273. __tablename__ = "rate_tables"
  274. __table_args__ = (
  275. UniqueConstraint("product_version_id", "rate_code", name="uq_rate_code"),
  276. Index(
  277. "ix_rate_lookup",
  278. "product_version_id",
  279. "plan_id",
  280. "region_group",
  281. "min_age",
  282. "max_age",
  283. "effective_from",
  284. ),
  285. )
  286. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  287. product_version_id: Mapped[str] = mapped_column(
  288. String(26), ForeignKey("product_versions.id"), nullable=False
  289. )
  290. plan_id: Mapped[str] = mapped_column(String(26), ForeignKey("plans.id"), nullable=False)
  291. rate_code: Mapped[str] = mapped_column(String(64), nullable=False)
  292. min_age: Mapped[int] = mapped_column(nullable=False)
  293. max_age: Mapped[int] = mapped_column(nullable=False)
  294. region_group: Mapped[str] = mapped_column(String(32), nullable=False)
  295. occupation_group: Mapped[str] = mapped_column(String(32), nullable=False)
  296. premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
  297. currency: Mapped[str] = mapped_column(String(3), nullable=False, default="CNY")
  298. effective_from: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  299. effective_to: Mapped[datetime | None] = mapped_column(UTCDateTime())
  300. class QuoteRecord(CoreBase):
  301. __tablename__ = "quotes"
  302. __table_args__ = (Index("ix_quotes_user_status", "h5_user_id", "status", "expires_at"),)
  303. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  304. h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
  305. product_id: Mapped[str] = mapped_column(String(26), ForeignKey("products.id"), nullable=False)
  306. product_version_id: Mapped[str] = mapped_column(
  307. String(26), ForeignKey("product_versions.id"), nullable=False
  308. )
  309. plan_id: Mapped[str] = mapped_column(String(26), ForeignKey("plans.id"), nullable=False)
  310. insured_age: Mapped[int] = mapped_column(nullable=False)
  311. insured_region_code: Mapped[str] = mapped_column(String(12), nullable=False)
  312. occupation_code: Mapped[str] = mapped_column(String(32), nullable=False)
  313. relationship: Mapped[str] = mapped_column(String(32), nullable=False)
  314. premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
  315. currency: Mapped[str] = mapped_column(String(3), nullable=False)
  316. rule_version: Mapped[str] = mapped_column(String(32), nullable=False)
  317. rate_version: Mapped[str] = mapped_column(String(32), nullable=False)
  318. status: Mapped[str] = mapped_column(String(32), nullable=False)
  319. expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  320. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  321. class EnrollmentDraftRecord(CoreBase):
  322. __tablename__ = "enrollment_drafts"
  323. __table_args__ = (Index("ix_drafts_user_status", "h5_user_id", "status", "created_at"),)
  324. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  325. h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
  326. quote_id: Mapped[str] = mapped_column(String(26), ForeignKey("quotes.id"), nullable=False)
  327. applicant_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  328. insured_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  329. contact_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  330. status: Mapped[str] = mapped_column(String(32), nullable=False)
  331. expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  332. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  333. class UserConfirmationRecord(CoreBase):
  334. __tablename__ = "user_confirmations"
  335. __table_args__ = (Index("ix_confirmations_subject", "draft_id", "status"),)
  336. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  337. h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
  338. draft_id: Mapped[str] = mapped_column(
  339. String(26), ForeignKey("enrollment_drafts.id"), nullable=False
  340. )
  341. token_hash: Mapped[str] = mapped_column(String(64), unique=True, nullable=False)
  342. status: Mapped[str] = mapped_column(String(32), nullable=False)
  343. expires_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  344. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  345. class EnrollmentOrderRecord(CoreBase):
  346. __tablename__ = "enrollment_orders"
  347. __table_args__ = (
  348. UniqueConstraint(
  349. "h5_user_id",
  350. "idempotency_key",
  351. name="uq_orders_user_idempotency",
  352. ),
  353. Index("ix_orders_user_status", "h5_user_id", "status", "created_at"),
  354. )
  355. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  356. order_no: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
  357. h5_user_id: Mapped[str] = mapped_column(String(26), ForeignKey("h5_users.id"), nullable=False)
  358. quote_id: Mapped[str] = mapped_column(
  359. String(26), ForeignKey("quotes.id"), unique=True, nullable=False
  360. )
  361. draft_id: Mapped[str] = mapped_column(
  362. String(26), ForeignKey("enrollment_drafts.id"), nullable=False
  363. )
  364. confirmation_id: Mapped[str] = mapped_column(
  365. String(26), ForeignKey("user_confirmations.id"), unique=True, nullable=False
  366. )
  367. idempotency_key: Mapped[str] = mapped_column(String(64), nullable=False)
  368. product_id: Mapped[str] = mapped_column(String(26), nullable=False)
  369. product_version_id: Mapped[str] = mapped_column(String(26), nullable=False)
  370. plan_id: Mapped[str] = mapped_column(String(26), nullable=False)
  371. applicant_snapshot_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  372. insured_snapshot_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  373. amount_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
  374. currency: Mapped[str] = mapped_column(String(3), nullable=False)
  375. status: Mapped[str] = mapped_column(String(32), nullable=False)
  376. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  377. class PaymentTransactionRecord(CoreBase):
  378. __tablename__ = "payment_transactions"
  379. __table_args__ = (
  380. UniqueConstraint(
  381. "order_id",
  382. "idempotency_key",
  383. name="uq_payments_order_idempotency",
  384. ),
  385. Index("ix_payments_order_status", "order_id", "status"),
  386. )
  387. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  388. payment_no: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
  389. order_id: Mapped[str] = mapped_column(
  390. String(26), ForeignKey("enrollment_orders.id"), nullable=False
  391. )
  392. h5_user_id: Mapped[str] = mapped_column(String(26), nullable=False)
  393. transaction_type: Mapped[str] = mapped_column(String(16), nullable=False)
  394. provider: Mapped[str] = mapped_column(String(32), nullable=False)
  395. idempotency_key: Mapped[str] = mapped_column(String(64), nullable=False)
  396. amount_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
  397. currency: Mapped[str] = mapped_column(String(3), nullable=False)
  398. status: Mapped[str] = mapped_column(String(32), nullable=False)
  399. provider_transaction_no: Mapped[str | None] = mapped_column(String(64), unique=True)
  400. succeeded_at: Mapped[datetime | None] = mapped_column(UTCDateTime())
  401. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False, default=utc_now)
  402. class PolicyRecord(CoreBase):
  403. __tablename__ = "policies"
  404. __table_args__ = (Index("ix_policies_user_status", "h5_user_id", "status", "coverage_end"),)
  405. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  406. policy_no: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
  407. order_id: Mapped[str] = mapped_column(
  408. String(26), ForeignKey("enrollment_orders.id"), unique=True, nullable=False
  409. )
  410. h5_user_id: Mapped[str] = mapped_column(String(26), nullable=False)
  411. product_id: Mapped[str] = mapped_column(String(26), nullable=False)
  412. product_version_id: Mapped[str] = mapped_column(String(26), nullable=False)
  413. plan_id: Mapped[str] = mapped_column(String(26), nullable=False)
  414. premium_cents: Mapped[int] = mapped_column(BigInteger, nullable=False)
  415. currency: Mapped[str] = mapped_column(String(3), nullable=False)
  416. coverage_start: Mapped[date] = mapped_column(Date, nullable=False)
  417. coverage_end: Mapped[date] = mapped_column(Date, nullable=False)
  418. status: Mapped[str] = mapped_column(String(32), nullable=False)
  419. issued_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  420. class OutboxEventRecord(CoreBase):
  421. __tablename__ = "outbox_events"
  422. __table_args__ = (Index("ix_outbox_dispatch", "status", "created_at"),)
  423. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  424. aggregate_type: Mapped[str] = mapped_column(String(32), nullable=False)
  425. aggregate_id: Mapped[str] = mapped_column(String(26), nullable=False)
  426. event_type: Mapped[str] = mapped_column(String(128), nullable=False)
  427. payload_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  428. status: Mapped[str] = mapped_column(String(32), nullable=False)
  429. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)
  430. class AsyncTaskRecord(CoreBase):
  431. __tablename__ = "async_tasks"
  432. __table_args__ = (Index("ix_async_tasks_claim", "status", "created_at"),)
  433. id: Mapped[str] = mapped_column(String(26), primary_key=True)
  434. task_type: Mapped[str] = mapped_column(String(128), nullable=False)
  435. business_key: Mapped[str] = mapped_column(String(128), nullable=False)
  436. idempotency_key: Mapped[str] = mapped_column(String(128), unique=True, nullable=False)
  437. payload_json: Mapped[dict[str, object]] = mapped_column(JSON, nullable=False)
  438. status: Mapped[str] = mapped_column(String(32), nullable=False)
  439. attempt_count: Mapped[int] = mapped_column(nullable=False, default=0)
  440. created_at: Mapped[datetime] = mapped_column(UTCDateTime(), nullable=False)