svc-infra 0.1.506__py3-none-any.whl → 0.1.654__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. svc_infra/apf_payments/README.md +732 -0
  2. svc_infra/apf_payments/alembic.py +11 -0
  3. svc_infra/apf_payments/models.py +339 -0
  4. svc_infra/apf_payments/provider/__init__.py +4 -0
  5. svc_infra/apf_payments/provider/aiydan.py +797 -0
  6. svc_infra/apf_payments/provider/base.py +270 -0
  7. svc_infra/apf_payments/provider/registry.py +31 -0
  8. svc_infra/apf_payments/provider/stripe.py +873 -0
  9. svc_infra/apf_payments/schemas.py +333 -0
  10. svc_infra/apf_payments/service.py +892 -0
  11. svc_infra/apf_payments/settings.py +67 -0
  12. svc_infra/api/fastapi/__init__.py +6 -0
  13. svc_infra/api/fastapi/admin/__init__.py +3 -0
  14. svc_infra/api/fastapi/admin/add.py +231 -0
  15. svc_infra/api/fastapi/apf_payments/__init__.py +0 -0
  16. svc_infra/api/fastapi/apf_payments/router.py +1082 -0
  17. svc_infra/api/fastapi/apf_payments/setup.py +73 -0
  18. svc_infra/api/fastapi/auth/add.py +15 -6
  19. svc_infra/api/fastapi/auth/gaurd.py +67 -5
  20. svc_infra/api/fastapi/auth/mfa/router.py +18 -9
  21. svc_infra/api/fastapi/auth/routers/account.py +3 -2
  22. svc_infra/api/fastapi/auth/routers/apikey_router.py +11 -5
  23. svc_infra/api/fastapi/auth/routers/oauth_router.py +82 -37
  24. svc_infra/api/fastapi/auth/routers/session_router.py +63 -0
  25. svc_infra/api/fastapi/auth/security.py +3 -1
  26. svc_infra/api/fastapi/auth/settings.py +2 -0
  27. svc_infra/api/fastapi/auth/state.py +1 -1
  28. svc_infra/api/fastapi/billing/router.py +64 -0
  29. svc_infra/api/fastapi/billing/setup.py +19 -0
  30. svc_infra/api/fastapi/cache/add.py +9 -5
  31. svc_infra/api/fastapi/db/nosql/mongo/add.py +33 -27
  32. svc_infra/api/fastapi/db/sql/add.py +40 -18
  33. svc_infra/api/fastapi/db/sql/crud_router.py +176 -14
  34. svc_infra/api/fastapi/db/sql/session.py +16 -0
  35. svc_infra/api/fastapi/db/sql/users.py +14 -2
  36. svc_infra/api/fastapi/dependencies/ratelimit.py +116 -0
  37. svc_infra/api/fastapi/docs/add.py +160 -0
  38. svc_infra/api/fastapi/docs/landing.py +1 -1
  39. svc_infra/api/fastapi/docs/scoped.py +254 -0
  40. svc_infra/api/fastapi/dual/dualize.py +38 -33
  41. svc_infra/api/fastapi/dual/router.py +48 -1
  42. svc_infra/api/fastapi/dx.py +3 -3
  43. svc_infra/api/fastapi/http/__init__.py +0 -0
  44. svc_infra/api/fastapi/http/concurrency.py +14 -0
  45. svc_infra/api/fastapi/http/conditional.py +33 -0
  46. svc_infra/api/fastapi/http/deprecation.py +21 -0
  47. svc_infra/api/fastapi/middleware/errors/handlers.py +45 -7
  48. svc_infra/api/fastapi/middleware/graceful_shutdown.py +87 -0
  49. svc_infra/api/fastapi/middleware/idempotency.py +116 -0
  50. svc_infra/api/fastapi/middleware/idempotency_store.py +187 -0
  51. svc_infra/api/fastapi/middleware/optimistic_lock.py +37 -0
  52. svc_infra/api/fastapi/middleware/ratelimit.py +119 -0
  53. svc_infra/api/fastapi/middleware/ratelimit_store.py +84 -0
  54. svc_infra/api/fastapi/middleware/request_id.py +23 -0
  55. svc_infra/api/fastapi/middleware/request_size_limit.py +36 -0
  56. svc_infra/api/fastapi/middleware/timeout.py +148 -0
  57. svc_infra/api/fastapi/openapi/mutators.py +768 -55
  58. svc_infra/api/fastapi/ops/add.py +73 -0
  59. svc_infra/api/fastapi/pagination.py +363 -0
  60. svc_infra/api/fastapi/paths/auth.py +14 -14
  61. svc_infra/api/fastapi/paths/prefix.py +0 -1
  62. svc_infra/api/fastapi/paths/user.py +1 -1
  63. svc_infra/api/fastapi/routers/ping.py +1 -0
  64. svc_infra/api/fastapi/setup.py +48 -15
  65. svc_infra/api/fastapi/tenancy/add.py +19 -0
  66. svc_infra/api/fastapi/tenancy/context.py +112 -0
  67. svc_infra/api/fastapi/versioned.py +101 -0
  68. svc_infra/app/README.md +5 -5
  69. svc_infra/billing/__init__.py +23 -0
  70. svc_infra/billing/async_service.py +147 -0
  71. svc_infra/billing/jobs.py +230 -0
  72. svc_infra/billing/models.py +131 -0
  73. svc_infra/billing/quotas.py +101 -0
  74. svc_infra/billing/schemas.py +33 -0
  75. svc_infra/billing/service.py +115 -0
  76. svc_infra/bundled_docs/README.md +5 -0
  77. svc_infra/bundled_docs/__init__.py +1 -0
  78. svc_infra/bundled_docs/getting-started.md +6 -0
  79. svc_infra/cache/__init__.py +4 -0
  80. svc_infra/cache/add.py +158 -0
  81. svc_infra/cache/backend.py +5 -2
  82. svc_infra/cache/decorators.py +19 -1
  83. svc_infra/cache/keys.py +24 -4
  84. svc_infra/cli/__init__.py +32 -8
  85. svc_infra/cli/__main__.py +4 -0
  86. svc_infra/cli/cmds/__init__.py +10 -0
  87. svc_infra/cli/cmds/db/nosql/mongo/mongo_cmds.py +4 -3
  88. svc_infra/cli/cmds/db/nosql/mongo/mongo_scaffold_cmds.py +4 -4
  89. svc_infra/cli/cmds/db/sql/alembic_cmds.py +120 -14
  90. svc_infra/cli/cmds/db/sql/sql_export_cmds.py +80 -0
  91. svc_infra/cli/cmds/db/sql/sql_scaffold_cmds.py +5 -4
  92. svc_infra/cli/cmds/docs/docs_cmds.py +140 -0
  93. svc_infra/cli/cmds/dx/__init__.py +12 -0
  94. svc_infra/cli/cmds/dx/dx_cmds.py +99 -0
  95. svc_infra/cli/cmds/help.py +4 -0
  96. svc_infra/cli/cmds/jobs/__init__.py +1 -0
  97. svc_infra/cli/cmds/jobs/jobs_cmds.py +43 -0
  98. svc_infra/cli/cmds/obs/obs_cmds.py +4 -3
  99. svc_infra/cli/cmds/sdk/__init__.py +0 -0
  100. svc_infra/cli/cmds/sdk/sdk_cmds.py +102 -0
  101. svc_infra/data/add.py +61 -0
  102. svc_infra/data/backup.py +53 -0
  103. svc_infra/data/erasure.py +45 -0
  104. svc_infra/data/fixtures.py +40 -0
  105. svc_infra/data/retention.py +55 -0
  106. svc_infra/db/inbox.py +67 -0
  107. svc_infra/db/nosql/mongo/README.md +13 -13
  108. svc_infra/db/outbox.py +104 -0
  109. svc_infra/db/sql/apikey.py +1 -1
  110. svc_infra/db/sql/authref.py +61 -0
  111. svc_infra/db/sql/core.py +2 -2
  112. svc_infra/db/sql/repository.py +52 -12
  113. svc_infra/db/sql/resource.py +5 -0
  114. svc_infra/db/sql/scaffold.py +16 -4
  115. svc_infra/db/sql/templates/models_schemas/auth/schemas.py.tmpl +1 -1
  116. svc_infra/db/sql/templates/setup/env_async.py.tmpl +199 -76
  117. svc_infra/db/sql/templates/setup/env_sync.py.tmpl +231 -79
  118. svc_infra/db/sql/tenant.py +79 -0
  119. svc_infra/db/sql/utils.py +18 -4
  120. svc_infra/db/sql/versioning.py +14 -0
  121. svc_infra/docs/acceptance-matrix.md +71 -0
  122. svc_infra/docs/acceptance.md +44 -0
  123. svc_infra/docs/admin.md +425 -0
  124. svc_infra/docs/adr/0002-background-jobs-and-scheduling.md +40 -0
  125. svc_infra/docs/adr/0003-webhooks-framework.md +24 -0
  126. svc_infra/docs/adr/0004-tenancy-model.md +42 -0
  127. svc_infra/docs/adr/0005-data-lifecycle.md +86 -0
  128. svc_infra/docs/adr/0006-ops-slos-and-metrics.md +47 -0
  129. svc_infra/docs/adr/0007-docs-and-sdks.md +83 -0
  130. svc_infra/docs/adr/0008-billing-primitives.md +143 -0
  131. svc_infra/docs/adr/0009-acceptance-harness.md +40 -0
  132. svc_infra/docs/adr/0010-timeouts-and-resource-limits.md +54 -0
  133. svc_infra/docs/adr/0011-admin-scope-and-impersonation.md +73 -0
  134. svc_infra/docs/api.md +59 -0
  135. svc_infra/docs/auth.md +11 -0
  136. svc_infra/docs/billing.md +190 -0
  137. svc_infra/docs/cache.md +76 -0
  138. svc_infra/docs/cli.md +74 -0
  139. svc_infra/docs/contributing.md +34 -0
  140. svc_infra/docs/data-lifecycle.md +52 -0
  141. svc_infra/docs/database.md +14 -0
  142. svc_infra/docs/docs-and-sdks.md +62 -0
  143. svc_infra/docs/environment.md +114 -0
  144. svc_infra/docs/getting-started.md +63 -0
  145. svc_infra/docs/idempotency.md +111 -0
  146. svc_infra/docs/jobs.md +67 -0
  147. svc_infra/docs/observability.md +16 -0
  148. svc_infra/docs/ops.md +37 -0
  149. svc_infra/docs/rate-limiting.md +125 -0
  150. svc_infra/docs/repo-review.md +48 -0
  151. svc_infra/docs/security.md +176 -0
  152. svc_infra/docs/tenancy.md +35 -0
  153. svc_infra/docs/timeouts-and-resource-limits.md +147 -0
  154. svc_infra/docs/versioned-integrations.md +146 -0
  155. svc_infra/docs/webhooks.md +112 -0
  156. svc_infra/dx/add.py +63 -0
  157. svc_infra/dx/changelog.py +74 -0
  158. svc_infra/dx/checks.py +67 -0
  159. svc_infra/http/__init__.py +13 -0
  160. svc_infra/http/client.py +72 -0
  161. svc_infra/jobs/builtins/outbox_processor.py +38 -0
  162. svc_infra/jobs/builtins/webhook_delivery.py +90 -0
  163. svc_infra/jobs/easy.py +32 -0
  164. svc_infra/jobs/loader.py +45 -0
  165. svc_infra/jobs/queue.py +81 -0
  166. svc_infra/jobs/redis_queue.py +191 -0
  167. svc_infra/jobs/runner.py +75 -0
  168. svc_infra/jobs/scheduler.py +41 -0
  169. svc_infra/jobs/worker.py +40 -0
  170. svc_infra/mcp/svc_infra_mcp.py +85 -28
  171. svc_infra/obs/README.md +2 -0
  172. svc_infra/obs/add.py +54 -7
  173. svc_infra/obs/grafana/dashboards/http-overview.json +45 -0
  174. svc_infra/obs/metrics/__init__.py +53 -0
  175. svc_infra/obs/metrics.py +52 -0
  176. svc_infra/security/add.py +201 -0
  177. svc_infra/security/audit.py +130 -0
  178. svc_infra/security/audit_service.py +73 -0
  179. svc_infra/security/headers.py +52 -0
  180. svc_infra/security/hibp.py +95 -0
  181. svc_infra/security/jwt_rotation.py +53 -0
  182. svc_infra/security/lockout.py +96 -0
  183. svc_infra/security/models.py +255 -0
  184. svc_infra/security/org_invites.py +128 -0
  185. svc_infra/security/passwords.py +77 -0
  186. svc_infra/security/permissions.py +149 -0
  187. svc_infra/security/session.py +98 -0
  188. svc_infra/security/signed_cookies.py +80 -0
  189. svc_infra/webhooks/__init__.py +16 -0
  190. svc_infra/webhooks/add.py +322 -0
  191. svc_infra/webhooks/fastapi.py +37 -0
  192. svc_infra/webhooks/router.py +55 -0
  193. svc_infra/webhooks/service.py +67 -0
  194. svc_infra/webhooks/signing.py +30 -0
  195. svc_infra-0.1.654.dist-info/METADATA +154 -0
  196. svc_infra-0.1.654.dist-info/RECORD +352 -0
  197. svc_infra/api/fastapi/deps.py +0 -3
  198. svc_infra-0.1.506.dist-info/METADATA +0 -78
  199. svc_infra-0.1.506.dist-info/RECORD +0 -213
  200. /svc_infra/{api/fastapi/schemas → apf_payments}/__init__.py +0 -0
  201. {svc_infra-0.1.506.dist-info → svc_infra-0.1.654.dist-info}/WHEEL +0 -0
  202. {svc_infra-0.1.506.dist-info → svc_infra-0.1.654.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def discover_packages() -> list[str]:
5
+ """
6
+ Packages Alembic should import so our models are registered with ModelBase.
7
+ Keep this stable so apps can reference it.
8
+ """
9
+ return [
10
+ "svc_infra.apf_payments.models", # SQLAlchemy models
11
+ ]
@@ -0,0 +1,339 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import Optional
5
+
6
+ from sqlalchemy import JSON, Boolean, DateTime, Index, Numeric, String, UniqueConstraint, text
7
+ from sqlalchemy.orm import Mapped, mapped_column
8
+
9
+ from svc_infra.db.sql.authref import user_fk_constraint, user_id_type
10
+ from svc_infra.db.sql.base import ModelBase
11
+
12
+ TENANT_ID_LEN = 64
13
+
14
+
15
+ class PayCustomer(ModelBase):
16
+ __tablename__ = "pay_customers"
17
+
18
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
19
+
20
+ # Tenant scoping
21
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
22
+
23
+ # Always typed to match the actual auth PK; FK is enforced at table level
24
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
25
+
26
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
27
+ provider_customer_id: Mapped[str] = mapped_column(
28
+ String(128), unique=True, index=True, nullable=False
29
+ )
30
+
31
+ created_at: Mapped[datetime] = mapped_column(
32
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
33
+ )
34
+
35
+ __table_args__ = (
36
+ user_fk_constraint("user_id", ondelete="SET NULL"),
37
+ Index("ix_pay_customers_user_provider", "user_id", "provider"),
38
+ Index("ix_pay_customers_tenant_provider", "tenant_id", "provider"),
39
+ )
40
+
41
+
42
+ class PayIntent(ModelBase):
43
+ __tablename__ = "pay_intents"
44
+
45
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
46
+
47
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
48
+
49
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
50
+
51
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
52
+ provider_intent_id: Mapped[str] = mapped_column(
53
+ String(128), unique=True, index=True, nullable=False
54
+ )
55
+ amount: Mapped[int] = mapped_column(Numeric(18, 0), nullable=False) # minor units
56
+ currency: Mapped[str] = mapped_column(String(8), nullable=False)
57
+ status: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
58
+ client_secret: Mapped[Optional[str]] = mapped_column(String(255))
59
+ created_at: Mapped[datetime] = mapped_column(
60
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
61
+ )
62
+ confirmed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
63
+ captured: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
64
+
65
+ __table_args__ = (
66
+ user_fk_constraint("user_id", ondelete="SET NULL"),
67
+ Index("ix_pay_intents_user_provider", "user_id", "provider"),
68
+ Index("ix_pay_intents_tenant_provider", "tenant_id", "provider"),
69
+ )
70
+
71
+
72
+ class PayEvent(ModelBase):
73
+ __tablename__ = "pay_events"
74
+
75
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
76
+
77
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
78
+
79
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
80
+ provider_event_id: Mapped[str] = mapped_column(
81
+ String(128), unique=True, index=True, nullable=False
82
+ )
83
+ type: Mapped[str] = mapped_column(String(64), index=True, nullable=False)
84
+ received_at: Mapped[datetime] = mapped_column(
85
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
86
+ )
87
+ payload_json: Mapped[dict] = mapped_column(JSON, nullable=False) # compact JSON string
88
+
89
+
90
+ class LedgerEntry(ModelBase):
91
+ __tablename__ = "ledger_entries"
92
+
93
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
94
+
95
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
96
+
97
+ ts: Mapped[datetime] = mapped_column(
98
+ DateTime(timezone=True),
99
+ server_default=text("CURRENT_TIMESTAMP"),
100
+ nullable=False,
101
+ index=True,
102
+ )
103
+
104
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
105
+ provider_ref: Mapped[Optional[str]] = mapped_column(String(128), index=True)
106
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
107
+ amount: Mapped[int] = mapped_column(Numeric(18, 0), nullable=False)
108
+ currency: Mapped[str] = mapped_column(String(8), nullable=False)
109
+ kind: Mapped[str] = mapped_column(String(24), nullable=False) # payment|refund|fee|payout...
110
+ status: Mapped[str] = mapped_column(String(24), nullable=False) # pending|posted|void
111
+
112
+ __table_args__ = (
113
+ user_fk_constraint("user_id", ondelete="SET NULL"),
114
+ Index("ix_ledger_user_ts", "user_id", "ts"),
115
+ Index("ix_ledger_tenant_provider", "tenant_id", "provider"),
116
+ UniqueConstraint(
117
+ "tenant_id",
118
+ "provider",
119
+ "provider_ref",
120
+ "kind",
121
+ name="uq_ledger_tenant_provider_ref_kind",
122
+ ),
123
+ )
124
+
125
+
126
+ class PayPaymentMethod(ModelBase):
127
+ __tablename__ = "pay_methods"
128
+
129
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
130
+
131
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
132
+
133
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
134
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
135
+ provider_customer_id: Mapped[str] = mapped_column(String(128), index=True, nullable=False)
136
+ provider_method_id: Mapped[str] = mapped_column(
137
+ String(128), unique=True, index=True, nullable=False
138
+ )
139
+ brand: Mapped[Optional[str]] = mapped_column(String(32))
140
+ last4: Mapped[Optional[str]] = mapped_column(String(8))
141
+ exp_month: Mapped[Optional[int]] = mapped_column(Numeric(2, 0))
142
+ exp_year: Mapped[Optional[int]] = mapped_column(Numeric(4, 0))
143
+ is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
144
+ created_at: Mapped[datetime] = mapped_column(
145
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
146
+ )
147
+
148
+ __table_args__ = (
149
+ user_fk_constraint("user_id", ondelete="SET NULL"),
150
+ Index(
151
+ "ix_pay_methods_tenant_provider_customer",
152
+ "tenant_id",
153
+ "provider",
154
+ "provider_customer_id",
155
+ ),
156
+ )
157
+
158
+
159
+ class PayProduct(ModelBase):
160
+ __tablename__ = "pay_products"
161
+
162
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
163
+
164
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
165
+
166
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
167
+ provider_product_id: Mapped[str] = mapped_column(
168
+ String(128), unique=True, index=True, nullable=False
169
+ )
170
+ name: Mapped[str] = mapped_column(String(128), nullable=False)
171
+ active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
172
+ created_at: Mapped[datetime] = mapped_column(
173
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
174
+ )
175
+
176
+
177
+ class PayPrice(ModelBase):
178
+ __tablename__ = "pay_prices"
179
+
180
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
181
+
182
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
183
+
184
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
185
+ provider_price_id: Mapped[str] = mapped_column(
186
+ String(128), unique=True, index=True, nullable=False
187
+ )
188
+ provider_product_id: Mapped[str] = mapped_column(String(128), index=True, nullable=False)
189
+ currency: Mapped[str] = mapped_column(String(8), nullable=False)
190
+ unit_amount: Mapped[int] = mapped_column(Numeric(18, 0), nullable=False) # minor units
191
+ interval: Mapped[Optional[str]] = mapped_column(String(16)) # month|year|week|day
192
+ trial_days: Mapped[Optional[int]] = mapped_column(Numeric(5, 0))
193
+ active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
194
+ created_at: Mapped[datetime] = mapped_column(
195
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
196
+ )
197
+
198
+
199
+ class PaySubscription(ModelBase):
200
+ __tablename__ = "pay_subscriptions"
201
+
202
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
203
+
204
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
205
+
206
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
207
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
208
+ provider_customer_id: Mapped[str] = mapped_column(String(128), index=True, nullable=False)
209
+ provider_subscription_id: Mapped[str] = mapped_column(
210
+ String(128), unique=True, index=True, nullable=False
211
+ )
212
+ provider_price_id: Mapped[str] = mapped_column(String(128), index=True, nullable=False)
213
+ status: Mapped[str] = mapped_column(
214
+ String(32), index=True, nullable=False
215
+ ) # active|trialing|canceled|past_due|incomplete
216
+ quantity: Mapped[int] = mapped_column(Numeric(10, 0), default=1, nullable=False)
217
+ cancel_at_period_end: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
218
+ current_period_end: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
219
+ created_at: Mapped[datetime] = mapped_column(
220
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
221
+ )
222
+
223
+ __table_args__ = (
224
+ user_fk_constraint("user_id", ondelete="SET NULL"),
225
+ Index(
226
+ "ix_pay_subscriptions_tenant_provider_customer",
227
+ "tenant_id",
228
+ "provider",
229
+ "provider_customer_id",
230
+ ),
231
+ )
232
+
233
+
234
+ class PayInvoice(ModelBase):
235
+ __tablename__ = "pay_invoices"
236
+
237
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
238
+
239
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
240
+
241
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
242
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
243
+ provider_invoice_id: Mapped[str] = mapped_column(
244
+ String(128), unique=True, index=True, nullable=False
245
+ )
246
+ provider_customer_id: Mapped[str] = mapped_column(String(128), index=True, nullable=False)
247
+ status: Mapped[str] = mapped_column(
248
+ String(24), index=True, nullable=False
249
+ ) # draft|open|paid|void|uncollectible
250
+ amount_due: Mapped[int] = mapped_column(Numeric(18, 0), nullable=False)
251
+ currency: Mapped[str] = mapped_column(String(8), nullable=False)
252
+ hosted_invoice_url: Mapped[Optional[str]] = mapped_column(String(255))
253
+ pdf_url: Mapped[Optional[str]] = mapped_column(String(255))
254
+ created_at: Mapped[datetime] = mapped_column(
255
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
256
+ )
257
+
258
+ __table_args__ = (
259
+ user_fk_constraint("user_id", ondelete="SET NULL"),
260
+ Index(
261
+ "ix_pay_invoices_tenant_provider_customer",
262
+ "tenant_id",
263
+ "provider",
264
+ "provider_customer_id",
265
+ ),
266
+ )
267
+
268
+
269
+ class PaySetupIntent(ModelBase):
270
+ __tablename__ = "pay_setup_intents"
271
+
272
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
273
+
274
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
275
+
276
+ user_id: Mapped[Optional[str]] = mapped_column(user_id_type(), index=True, nullable=True)
277
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
278
+ provider_setup_intent_id: Mapped[str] = mapped_column(
279
+ String(128), unique=True, index=True, nullable=False
280
+ )
281
+ status: Mapped[str] = mapped_column(
282
+ String(32), index=True, nullable=False
283
+ ) # requires_action|succeeded|canceled|processing
284
+ client_secret: Mapped[Optional[str]] = mapped_column(String(255))
285
+ created_at: Mapped[datetime] = mapped_column(
286
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
287
+ )
288
+
289
+ __table_args__ = (
290
+ user_fk_constraint("user_id", ondelete="SET NULL"),
291
+ Index("ix_pay_setup_intents_tenant_provider", "tenant_id", "provider"),
292
+ )
293
+
294
+
295
+ class PayDispute(ModelBase):
296
+ __tablename__ = "pay_disputes"
297
+
298
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
299
+
300
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
301
+
302
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
303
+ provider_dispute_id: Mapped[str] = mapped_column(
304
+ String(128), unique=True, index=True, nullable=False
305
+ )
306
+ provider_charge_id: Mapped[Optional[str]] = mapped_column(String(128), index=True)
307
+ amount: Mapped[int] = mapped_column(Numeric(18, 0), nullable=False)
308
+ currency: Mapped[str] = mapped_column(String(8), nullable=False)
309
+ reason: Mapped[Optional[str]] = mapped_column(String(64))
310
+ status: Mapped[str] = mapped_column(
311
+ String(32), index=True, nullable=False
312
+ ) # needs_response|under_review|won|lost|warning_closed
313
+ evidence_due_by: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
314
+ created_at: Mapped[datetime] = mapped_column(
315
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
316
+ )
317
+
318
+
319
+ class PayPayout(ModelBase):
320
+ __tablename__ = "pay_payouts"
321
+
322
+ id: Mapped[str] = mapped_column(String(64), primary_key=True)
323
+
324
+ tenant_id: Mapped[str] = mapped_column(String(TENANT_ID_LEN), index=True, nullable=False)
325
+
326
+ provider: Mapped[str] = mapped_column(String(32), index=True, nullable=False)
327
+ provider_payout_id: Mapped[str] = mapped_column(
328
+ String(128), unique=True, index=True, nullable=False
329
+ )
330
+ amount: Mapped[int] = mapped_column(Numeric(18, 0), nullable=False)
331
+ currency: Mapped[str] = mapped_column(String(8), nullable=False)
332
+ status: Mapped[str] = mapped_column(
333
+ String(32), index=True, nullable=False
334
+ ) # pending|in_transit|paid|canceled|failed
335
+ arrival_date: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
336
+ type: Mapped[Optional[str]] = mapped_column(String(32)) # bank_account|card|...
337
+ created_at: Mapped[datetime] = mapped_column(
338
+ DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP"), nullable=False
339
+ )
@@ -0,0 +1,4 @@
1
+ from .aiydan import AiydanAdapter # noqa: F401
2
+ from .stripe import StripeAdapter # noqa: F401
3
+
4
+ __all__ = ["AiydanAdapter", "StripeAdapter"]