svc-infra 0.1.706__py3-none-any.whl → 1.1.0__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.
Potentially problematic release.
This version of svc-infra might be problematic. Click here for more details.
- svc_infra/apf_payments/models.py +47 -108
- svc_infra/apf_payments/provider/__init__.py +2 -2
- svc_infra/apf_payments/provider/aiydan.py +42 -100
- svc_infra/apf_payments/provider/base.py +10 -26
- svc_infra/apf_payments/provider/registry.py +3 -5
- svc_infra/apf_payments/provider/stripe.py +63 -135
- svc_infra/apf_payments/schemas.py +82 -90
- svc_infra/apf_payments/service.py +40 -86
- svc_infra/apf_payments/settings.py +10 -13
- svc_infra/api/__init__.py +13 -13
- svc_infra/api/fastapi/__init__.py +19 -0
- svc_infra/api/fastapi/admin/add.py +13 -18
- svc_infra/api/fastapi/apf_payments/router.py +47 -84
- svc_infra/api/fastapi/apf_payments/setup.py +7 -13
- svc_infra/api/fastapi/auth/__init__.py +1 -1
- svc_infra/api/fastapi/auth/_cookies.py +3 -9
- svc_infra/api/fastapi/auth/add.py +4 -8
- svc_infra/api/fastapi/auth/gaurd.py +9 -26
- svc_infra/api/fastapi/auth/mfa/models.py +4 -7
- svc_infra/api/fastapi/auth/mfa/pre_auth.py +3 -3
- svc_infra/api/fastapi/auth/mfa/router.py +9 -15
- svc_infra/api/fastapi/auth/mfa/security.py +3 -5
- svc_infra/api/fastapi/auth/mfa/utils.py +3 -2
- svc_infra/api/fastapi/auth/mfa/verify.py +2 -9
- svc_infra/api/fastapi/auth/providers.py +4 -6
- svc_infra/api/fastapi/auth/routers/apikey_router.py +16 -18
- svc_infra/api/fastapi/auth/routers/oauth_router.py +37 -85
- svc_infra/api/fastapi/auth/routers/session_router.py +3 -6
- svc_infra/api/fastapi/auth/security.py +17 -28
- svc_infra/api/fastapi/auth/sender.py +1 -3
- svc_infra/api/fastapi/auth/settings.py +18 -19
- svc_infra/api/fastapi/auth/state.py +6 -7
- svc_infra/api/fastapi/auth/ws_security.py +2 -2
- svc_infra/api/fastapi/billing/router.py +6 -8
- svc_infra/api/fastapi/db/http.py +10 -11
- svc_infra/api/fastapi/db/nosql/mongo/add.py +5 -15
- svc_infra/api/fastapi/db/nosql/mongo/crud_router.py +14 -15
- svc_infra/api/fastapi/db/sql/add.py +6 -14
- svc_infra/api/fastapi/db/sql/crud_router.py +27 -40
- svc_infra/api/fastapi/db/sql/health.py +1 -3
- svc_infra/api/fastapi/db/sql/session.py +4 -5
- svc_infra/api/fastapi/db/sql/users.py +8 -11
- svc_infra/api/fastapi/dependencies/ratelimit.py +4 -6
- svc_infra/api/fastapi/docs/add.py +13 -23
- svc_infra/api/fastapi/docs/landing.py +6 -8
- svc_infra/api/fastapi/docs/scoped.py +34 -42
- svc_infra/api/fastapi/dual/dualize.py +1 -1
- svc_infra/api/fastapi/dual/protected.py +12 -21
- svc_infra/api/fastapi/dual/router.py +14 -31
- svc_infra/api/fastapi/ease.py +57 -13
- svc_infra/api/fastapi/http/conditional.py +3 -5
- svc_infra/api/fastapi/middleware/errors/catchall.py +2 -6
- svc_infra/api/fastapi/middleware/errors/exceptions.py +1 -4
- svc_infra/api/fastapi/middleware/errors/handlers.py +12 -18
- svc_infra/api/fastapi/middleware/graceful_shutdown.py +4 -13
- svc_infra/api/fastapi/middleware/idempotency.py +11 -16
- svc_infra/api/fastapi/middleware/idempotency_store.py +14 -14
- svc_infra/api/fastapi/middleware/optimistic_lock.py +5 -8
- svc_infra/api/fastapi/middleware/ratelimit.py +8 -8
- svc_infra/api/fastapi/middleware/ratelimit_store.py +7 -8
- svc_infra/api/fastapi/middleware/request_id.py +1 -3
- svc_infra/api/fastapi/middleware/timeout.py +9 -10
- svc_infra/api/fastapi/object_router.py +1060 -0
- svc_infra/api/fastapi/openapi/apply.py +5 -6
- svc_infra/api/fastapi/openapi/conventions.py +4 -4
- svc_infra/api/fastapi/openapi/mutators.py +13 -31
- svc_infra/api/fastapi/openapi/pipeline.py +2 -2
- svc_infra/api/fastapi/openapi/responses.py +4 -6
- svc_infra/api/fastapi/openapi/security.py +1 -3
- svc_infra/api/fastapi/ops/add.py +7 -9
- svc_infra/api/fastapi/pagination.py +25 -37
- svc_infra/api/fastapi/routers/__init__.py +16 -38
- svc_infra/api/fastapi/setup.py +13 -31
- svc_infra/api/fastapi/tenancy/add.py +3 -2
- svc_infra/api/fastapi/tenancy/context.py +8 -7
- svc_infra/api/fastapi/versioned.py +3 -2
- svc_infra/app/env.py +5 -7
- svc_infra/app/logging/add.py +2 -1
- svc_infra/app/logging/filter.py +1 -1
- svc_infra/app/logging/formats.py +3 -2
- svc_infra/app/root.py +3 -3
- svc_infra/billing/__init__.py +19 -2
- svc_infra/billing/async_service.py +27 -7
- svc_infra/billing/jobs.py +23 -33
- svc_infra/billing/models.py +21 -52
- svc_infra/billing/quotas.py +5 -7
- svc_infra/billing/schemas.py +4 -6
- svc_infra/cache/__init__.py +12 -5
- svc_infra/cache/add.py +6 -9
- svc_infra/cache/backend.py +6 -5
- svc_infra/cache/decorators.py +17 -28
- svc_infra/cache/keys.py +2 -2
- svc_infra/cache/recache.py +22 -35
- svc_infra/cache/resources.py +8 -16
- svc_infra/cache/ttl.py +2 -3
- svc_infra/cache/utils.py +5 -6
- svc_infra/cli/__init__.py +4 -12
- svc_infra/cli/cmds/db/nosql/mongo/mongo_cmds.py +11 -10
- svc_infra/cli/cmds/db/nosql/mongo/mongo_scaffold_cmds.py +6 -9
- svc_infra/cli/cmds/db/ops_cmds.py +3 -6
- svc_infra/cli/cmds/db/sql/alembic_cmds.py +24 -41
- svc_infra/cli/cmds/db/sql/sql_export_cmds.py +9 -17
- svc_infra/cli/cmds/db/sql/sql_scaffold_cmds.py +10 -10
- svc_infra/cli/cmds/docs/docs_cmds.py +7 -10
- svc_infra/cli/cmds/dx/dx_cmds.py +5 -11
- svc_infra/cli/cmds/jobs/jobs_cmds.py +2 -7
- svc_infra/cli/cmds/obs/obs_cmds.py +4 -7
- svc_infra/cli/cmds/sdk/sdk_cmds.py +5 -15
- svc_infra/cli/foundation/runner.py +6 -11
- svc_infra/cli/foundation/typer_bootstrap.py +1 -2
- svc_infra/data/__init__.py +83 -0
- svc_infra/data/add.py +5 -5
- svc_infra/data/backup.py +8 -10
- svc_infra/data/erasure.py +3 -2
- svc_infra/data/fixtures.py +3 -3
- svc_infra/data/retention.py +8 -13
- svc_infra/db/crud_schema.py +9 -8
- svc_infra/db/nosql/__init__.py +0 -1
- svc_infra/db/nosql/constants.py +1 -1
- svc_infra/db/nosql/core.py +7 -14
- svc_infra/db/nosql/indexes.py +11 -10
- svc_infra/db/nosql/management.py +3 -3
- svc_infra/db/nosql/mongo/client.py +3 -3
- svc_infra/db/nosql/mongo/settings.py +2 -6
- svc_infra/db/nosql/repository.py +27 -28
- svc_infra/db/nosql/resource.py +15 -20
- svc_infra/db/nosql/scaffold.py +13 -17
- svc_infra/db/nosql/service.py +3 -4
- svc_infra/db/nosql/service_with_hooks.py +4 -3
- svc_infra/db/nosql/types.py +2 -6
- svc_infra/db/nosql/utils.py +4 -4
- svc_infra/db/ops.py +14 -18
- svc_infra/db/outbox.py +15 -18
- svc_infra/db/sql/apikey.py +12 -21
- svc_infra/db/sql/authref.py +3 -7
- svc_infra/db/sql/constants.py +9 -9
- svc_infra/db/sql/core.py +11 -11
- svc_infra/db/sql/management.py +2 -6
- svc_infra/db/sql/repository.py +17 -24
- svc_infra/db/sql/resource.py +14 -13
- svc_infra/db/sql/scaffold.py +13 -17
- svc_infra/db/sql/service.py +7 -16
- svc_infra/db/sql/service_with_hooks.py +4 -3
- svc_infra/db/sql/tenant.py +6 -14
- svc_infra/db/sql/uniq.py +8 -7
- svc_infra/db/sql/uniq_hooks.py +14 -19
- svc_infra/db/sql/utils.py +24 -53
- svc_infra/db/utils.py +3 -3
- svc_infra/deploy/__init__.py +8 -15
- svc_infra/documents/add.py +7 -8
- svc_infra/documents/ease.py +8 -8
- svc_infra/documents/models.py +3 -3
- svc_infra/documents/storage.py +11 -13
- svc_infra/dx/__init__.py +58 -0
- svc_infra/dx/add.py +1 -3
- svc_infra/dx/changelog.py +2 -2
- svc_infra/dx/checks.py +1 -1
- svc_infra/health/__init__.py +15 -16
- svc_infra/http/client.py +10 -14
- svc_infra/jobs/__init__.py +79 -0
- svc_infra/jobs/builtins/outbox_processor.py +3 -5
- svc_infra/jobs/builtins/webhook_delivery.py +1 -3
- svc_infra/jobs/loader.py +4 -5
- svc_infra/jobs/queue.py +14 -24
- svc_infra/jobs/redis_queue.py +20 -34
- svc_infra/jobs/runner.py +7 -11
- svc_infra/jobs/scheduler.py +5 -5
- svc_infra/jobs/worker.py +1 -1
- svc_infra/loaders/base.py +5 -4
- svc_infra/loaders/github.py +1 -3
- svc_infra/loaders/url.py +3 -9
- svc_infra/logging/__init__.py +7 -6
- svc_infra/mcp/__init__.py +82 -0
- svc_infra/mcp/svc_infra_mcp.py +2 -2
- svc_infra/obs/add.py +4 -3
- svc_infra/obs/cloud_dash.py +1 -1
- svc_infra/obs/metrics/__init__.py +3 -3
- svc_infra/obs/metrics/asgi.py +9 -14
- svc_infra/obs/metrics/base.py +13 -13
- svc_infra/obs/metrics/http.py +5 -9
- svc_infra/obs/metrics/sqlalchemy.py +9 -12
- svc_infra/obs/metrics.py +3 -3
- svc_infra/obs/settings.py +2 -6
- svc_infra/resilience/__init__.py +44 -0
- svc_infra/resilience/circuit_breaker.py +328 -0
- svc_infra/resilience/retry.py +289 -0
- svc_infra/security/__init__.py +167 -0
- svc_infra/security/add.py +5 -9
- svc_infra/security/audit.py +14 -17
- svc_infra/security/audit_service.py +9 -9
- svc_infra/security/hibp.py +3 -6
- svc_infra/security/jwt_rotation.py +7 -10
- svc_infra/security/lockout.py +12 -11
- svc_infra/security/models.py +37 -46
- svc_infra/security/oauth_models.py +8 -8
- svc_infra/security/org_invites.py +11 -13
- svc_infra/security/passwords.py +4 -6
- svc_infra/security/permissions.py +8 -7
- svc_infra/security/session.py +6 -7
- svc_infra/security/signed_cookies.py +9 -9
- svc_infra/storage/add.py +5 -8
- svc_infra/storage/backends/local.py +13 -21
- svc_infra/storage/backends/memory.py +4 -7
- svc_infra/storage/backends/s3.py +17 -36
- svc_infra/storage/base.py +2 -2
- svc_infra/storage/easy.py +4 -8
- svc_infra/storage/settings.py +16 -18
- svc_infra/testing/__init__.py +36 -39
- svc_infra/utils.py +169 -8
- svc_infra/webhooks/__init__.py +1 -1
- svc_infra/webhooks/add.py +17 -29
- svc_infra/webhooks/encryption.py +2 -2
- svc_infra/webhooks/fastapi.py +2 -4
- svc_infra/webhooks/router.py +3 -3
- svc_infra/webhooks/service.py +5 -6
- svc_infra/webhooks/signing.py +5 -5
- svc_infra/websocket/add.py +2 -3
- svc_infra/websocket/client.py +3 -2
- svc_infra/websocket/config.py +6 -18
- svc_infra/websocket/manager.py +9 -10
- {svc_infra-0.1.706.dist-info → svc_infra-1.1.0.dist-info}/METADATA +11 -5
- svc_infra-1.1.0.dist-info/RECORD +364 -0
- svc_infra/billing/service.py +0 -123
- svc_infra-0.1.706.dist-info/RECORD +0 -357
- {svc_infra-0.1.706.dist-info → svc_infra-1.1.0.dist-info}/LICENSE +0 -0
- {svc_infra-0.1.706.dist-info → svc_infra-1.1.0.dist-info}/WHEEL +0 -0
- {svc_infra-0.1.706.dist-info → svc_infra-1.1.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, Protocol
|
|
4
4
|
|
|
5
5
|
from ..schemas import (
|
|
6
6
|
BalanceSnapshotOut,
|
|
@@ -42,14 +42,10 @@ class ProviderAdapter(Protocol):
|
|
|
42
42
|
async def ensure_customer(self, data: CustomerUpsertIn) -> CustomerOut:
|
|
43
43
|
pass
|
|
44
44
|
|
|
45
|
-
async def attach_payment_method(
|
|
46
|
-
self, data: PaymentMethodAttachIn
|
|
47
|
-
) -> PaymentMethodOut:
|
|
45
|
+
async def attach_payment_method(self, data: PaymentMethodAttachIn) -> PaymentMethodOut:
|
|
48
46
|
pass
|
|
49
47
|
|
|
50
|
-
async def list_payment_methods(
|
|
51
|
-
self, provider_customer_id: str
|
|
52
|
-
) -> list[PaymentMethodOut]:
|
|
48
|
+
async def list_payment_methods(self, provider_customer_id: str) -> list[PaymentMethodOut]:
|
|
53
49
|
pass
|
|
54
50
|
|
|
55
51
|
async def detach_payment_method(self, provider_method_id: str) -> PaymentMethodOut:
|
|
@@ -91,9 +87,7 @@ class ProviderAdapter(Protocol):
|
|
|
91
87
|
async def pay_invoice(self, provider_invoice_id: str) -> InvoiceOut:
|
|
92
88
|
pass
|
|
93
89
|
|
|
94
|
-
async def create_intent(
|
|
95
|
-
self, data: IntentCreateIn, *, user_id: str | None
|
|
96
|
-
) -> IntentOut:
|
|
90
|
+
async def create_intent(self, data: IntentCreateIn, *, user_id: str | None) -> IntentOut:
|
|
97
91
|
pass
|
|
98
92
|
|
|
99
93
|
async def confirm_intent(self, provider_intent_id: str) -> IntentOut:
|
|
@@ -113,9 +107,7 @@ class ProviderAdapter(Protocol):
|
|
|
113
107
|
) -> dict[str, Any]:
|
|
114
108
|
pass
|
|
115
109
|
|
|
116
|
-
async def capture_intent(
|
|
117
|
-
self, provider_intent_id: str, *, amount: int | None
|
|
118
|
-
) -> IntentOut:
|
|
110
|
+
async def capture_intent(self, provider_intent_id: str, *, amount: int | None) -> IntentOut:
|
|
119
111
|
pass
|
|
120
112
|
|
|
121
113
|
async def list_intents(
|
|
@@ -158,9 +150,7 @@ class ProviderAdapter(Protocol):
|
|
|
158
150
|
async def create_setup_intent(self, data: SetupIntentCreateIn) -> SetupIntentOut:
|
|
159
151
|
pass
|
|
160
152
|
|
|
161
|
-
async def confirm_setup_intent(
|
|
162
|
-
self, provider_setup_intent_id: str
|
|
163
|
-
) -> SetupIntentOut:
|
|
153
|
+
async def confirm_setup_intent(self, provider_setup_intent_id: str) -> SetupIntentOut:
|
|
164
154
|
pass
|
|
165
155
|
|
|
166
156
|
async def get_setup_intent(self, provider_setup_intent_id: str) -> SetupIntentOut:
|
|
@@ -179,9 +169,7 @@ class ProviderAdapter(Protocol):
|
|
|
179
169
|
async def get_dispute(self, provider_dispute_id: str) -> DisputeOut:
|
|
180
170
|
pass
|
|
181
171
|
|
|
182
|
-
async def submit_dispute_evidence(
|
|
183
|
-
self, provider_dispute_id: str, evidence: dict
|
|
184
|
-
) -> DisputeOut:
|
|
172
|
+
async def submit_dispute_evidence(self, provider_dispute_id: str, evidence: dict) -> DisputeOut:
|
|
185
173
|
pass
|
|
186
174
|
|
|
187
175
|
# --- Balance & Payouts ---
|
|
@@ -208,7 +196,7 @@ class ProviderAdapter(Protocol):
|
|
|
208
196
|
"""Optional: if not implemented, the service will list from local DB."""
|
|
209
197
|
pass
|
|
210
198
|
|
|
211
|
-
async def get_customer(self, provider_customer_id: str) ->
|
|
199
|
+
async def get_customer(self, provider_customer_id: str) -> CustomerOut | None:
|
|
212
200
|
pass
|
|
213
201
|
|
|
214
202
|
# --- Products / Prices ---
|
|
@@ -220,9 +208,7 @@ class ProviderAdapter(Protocol):
|
|
|
220
208
|
) -> tuple[list[ProductOut], str | None]:
|
|
221
209
|
pass
|
|
222
210
|
|
|
223
|
-
async def update_product(
|
|
224
|
-
self, provider_product_id: str, data: ProductUpdateIn
|
|
225
|
-
) -> ProductOut:
|
|
211
|
+
async def update_product(self, provider_product_id: str, data: ProductUpdateIn) -> ProductOut:
|
|
226
212
|
pass
|
|
227
213
|
|
|
228
214
|
async def get_price(self, provider_price_id: str) -> PriceOut:
|
|
@@ -238,9 +224,7 @@ class ProviderAdapter(Protocol):
|
|
|
238
224
|
) -> tuple[list[PriceOut], str | None]:
|
|
239
225
|
pass
|
|
240
226
|
|
|
241
|
-
async def update_price(
|
|
242
|
-
self, provider_price_id: str, data: PriceUpdateIn
|
|
243
|
-
) -> PriceOut:
|
|
227
|
+
async def update_price(self, provider_price_id: str, data: PriceUpdateIn) -> PriceOut:
|
|
244
228
|
pass
|
|
245
229
|
|
|
246
230
|
# --- Subscriptions ---
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Dict, Optional
|
|
4
|
-
|
|
5
3
|
from ..settings import get_payments_settings
|
|
6
4
|
from .base import ProviderAdapter
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
class ProviderRegistry:
|
|
10
8
|
def __init__(self):
|
|
11
|
-
self._adapters:
|
|
9
|
+
self._adapters: dict[str, ProviderAdapter] = {}
|
|
12
10
|
|
|
13
11
|
def register(self, adapter: ProviderAdapter):
|
|
14
12
|
self._adapters[adapter.name] = adapter
|
|
15
13
|
|
|
16
|
-
def get(self, name:
|
|
14
|
+
def get(self, name: str | None = None) -> ProviderAdapter:
|
|
17
15
|
settings = get_payments_settings()
|
|
18
16
|
key = (name or settings.default_provider).lower()
|
|
19
17
|
if key not in self._adapters:
|
|
@@ -21,7 +19,7 @@ class ProviderRegistry:
|
|
|
21
19
|
return self._adapters[key]
|
|
22
20
|
|
|
23
21
|
|
|
24
|
-
_REGISTRY:
|
|
22
|
+
_REGISTRY: ProviderRegistry | None = None
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
def get_provider_registry() -> ProviderRegistry:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from functools import partial
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
import anyio
|
|
7
7
|
|
|
@@ -60,9 +60,7 @@ def _pi_to_out(pi) -> IntentOut:
|
|
|
60
60
|
amount=int(pi.amount),
|
|
61
61
|
currency=str(pi.currency).upper(),
|
|
62
62
|
client_secret=getattr(pi, "client_secret", None),
|
|
63
|
-
next_action=NextAction(
|
|
64
|
-
type=getattr(getattr(pi, "next_action", None), "type", None)
|
|
65
|
-
),
|
|
63
|
+
next_action=NextAction(type=getattr(getattr(pi, "next_action", None), "type", None)),
|
|
66
64
|
)
|
|
67
65
|
|
|
68
66
|
|
|
@@ -136,9 +134,7 @@ def _sub_to_out(s) -> SubscriptionOut:
|
|
|
136
134
|
quantity=int(qty or 0),
|
|
137
135
|
cancel_at_period_end=bool(s.cancel_at_period_end),
|
|
138
136
|
current_period_end=(
|
|
139
|
-
str(s.current_period_end)
|
|
140
|
-
if getattr(s, "current_period_end", None)
|
|
141
|
-
else None
|
|
137
|
+
str(s.current_period_end) if getattr(s, "current_period_end", None) else None
|
|
142
138
|
),
|
|
143
139
|
)
|
|
144
140
|
|
|
@@ -167,9 +163,7 @@ def _dispute_to_out(d) -> DisputeOut:
|
|
|
167
163
|
reason=getattr(d, "reason", None),
|
|
168
164
|
status=d.status,
|
|
169
165
|
evidence_due_by=(
|
|
170
|
-
str(d.evidence_details.get("due_by"))
|
|
171
|
-
if getattr(d, "evidence_details", None)
|
|
172
|
-
else None
|
|
166
|
+
str(d.evidence_details.get("due_by")) if getattr(d, "evidence_details", None) else None
|
|
173
167
|
),
|
|
174
168
|
created_at=str(d.created) if getattr(d, "created", None) else None,
|
|
175
169
|
)
|
|
@@ -199,9 +193,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
199
193
|
raise RuntimeError("stripe SDK is not installed. pip install stripe")
|
|
200
194
|
stripe.api_key = st.stripe.secret_key.get_secret_value()
|
|
201
195
|
self._wh_secret = (
|
|
202
|
-
st.stripe.webhook_secret.get_secret_value()
|
|
203
|
-
if st.stripe.webhook_secret
|
|
204
|
-
else None
|
|
196
|
+
st.stripe.webhook_secret.get_secret_value() if st.stripe.webhook_secret else None
|
|
205
197
|
)
|
|
206
198
|
|
|
207
199
|
# -------- Customers --------
|
|
@@ -232,7 +224,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
232
224
|
name=c.get("name"),
|
|
233
225
|
)
|
|
234
226
|
|
|
235
|
-
async def get_customer(self, provider_customer_id: str) ->
|
|
227
|
+
async def get_customer(self, provider_customer_id: str) -> CustomerOut | None:
|
|
236
228
|
c = await _acall(stripe.Customer.retrieve, provider_customer_id)
|
|
237
229
|
return CustomerOut(
|
|
238
230
|
id=c.id,
|
|
@@ -266,15 +258,11 @@ class StripeAdapter(ProviderAdapter):
|
|
|
266
258
|
)
|
|
267
259
|
for c in res.data
|
|
268
260
|
]
|
|
269
|
-
next_cursor = (
|
|
270
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
271
|
-
)
|
|
261
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
272
262
|
return items, next_cursor
|
|
273
263
|
|
|
274
264
|
# -------- Payment Methods --------
|
|
275
|
-
async def attach_payment_method(
|
|
276
|
-
self, data: PaymentMethodAttachIn
|
|
277
|
-
) -> PaymentMethodOut:
|
|
265
|
+
async def attach_payment_method(self, data: PaymentMethodAttachIn) -> PaymentMethodOut:
|
|
278
266
|
pm = await _acall(
|
|
279
267
|
stripe.PaymentMethod.attach,
|
|
280
268
|
data.payment_method_token,
|
|
@@ -307,16 +295,12 @@ class StripeAdapter(ProviderAdapter):
|
|
|
307
295
|
)
|
|
308
296
|
return _pm_to_out(pm, is_default=is_default)
|
|
309
297
|
|
|
310
|
-
async def list_payment_methods(
|
|
311
|
-
self, provider_customer_id: str
|
|
312
|
-
) -> list[PaymentMethodOut]:
|
|
298
|
+
async def list_payment_methods(self, provider_customer_id: str) -> list[PaymentMethodOut]:
|
|
313
299
|
cust = await _acall(stripe.Customer.retrieve, provider_customer_id)
|
|
314
300
|
default_pm = getattr(
|
|
315
301
|
getattr(cust, "invoice_settings", None), "default_payment_method", None
|
|
316
302
|
)
|
|
317
|
-
res = await _acall(
|
|
318
|
-
stripe.PaymentMethod.list, customer=provider_customer_id, type="card"
|
|
319
|
-
)
|
|
303
|
+
res = await _acall(stripe.PaymentMethod.list, customer=provider_customer_id, type="card")
|
|
320
304
|
return [_pm_to_out(pm, is_default=(pm.id == default_pm)) for pm in res.data]
|
|
321
305
|
|
|
322
306
|
async def detach_payment_method(self, provider_method_id: str) -> PaymentMethodOut:
|
|
@@ -341,9 +325,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
341
325
|
)
|
|
342
326
|
pm = await _acall(stripe.PaymentMethod.retrieve, provider_method_id)
|
|
343
327
|
is_default = (
|
|
344
|
-
getattr(
|
|
345
|
-
getattr(cust, "invoice_settings", None), "default_payment_method", None
|
|
346
|
-
)
|
|
328
|
+
getattr(getattr(cust, "invoice_settings", None), "default_payment_method", None)
|
|
347
329
|
== pm.id
|
|
348
330
|
)
|
|
349
331
|
return _pm_to_out(pm, is_default=is_default)
|
|
@@ -387,9 +369,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
387
369
|
|
|
388
370
|
# -------- Products / Prices --------
|
|
389
371
|
async def create_product(self, data: ProductCreateIn) -> ProductOut:
|
|
390
|
-
p = await _acall(
|
|
391
|
-
stripe.Product.create, name=data.name, active=bool(data.active)
|
|
392
|
-
)
|
|
372
|
+
p = await _acall(stripe.Product.create, name=data.name, active=bool(data.active))
|
|
393
373
|
return _product_to_out(p)
|
|
394
374
|
|
|
395
375
|
async def get_product(self, provider_product_id: str) -> ProductOut:
|
|
@@ -406,14 +386,10 @@ class StripeAdapter(ProviderAdapter):
|
|
|
406
386
|
params["starting_after"] = cursor
|
|
407
387
|
res = await _acall(stripe.Product.list, **params)
|
|
408
388
|
items = [_product_to_out(p) for p in res.data]
|
|
409
|
-
next_cursor = (
|
|
410
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
411
|
-
)
|
|
389
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
412
390
|
return items, next_cursor
|
|
413
391
|
|
|
414
|
-
async def update_product(
|
|
415
|
-
self, provider_product_id: str, data: ProductUpdateIn
|
|
416
|
-
) -> ProductOut:
|
|
392
|
+
async def update_product(self, provider_product_id: str, data: ProductUpdateIn) -> ProductOut:
|
|
417
393
|
update: dict[str, Any] = {}
|
|
418
394
|
if data.name is not None:
|
|
419
395
|
update["name"] = data.name
|
|
@@ -427,12 +403,12 @@ class StripeAdapter(ProviderAdapter):
|
|
|
427
403
|
return _product_to_out(p)
|
|
428
404
|
|
|
429
405
|
async def create_price(self, data: PriceCreateIn) -> PriceOut:
|
|
430
|
-
kwargs: dict[str, Any] =
|
|
431
|
-
product
|
|
432
|
-
currency
|
|
433
|
-
unit_amount
|
|
434
|
-
active
|
|
435
|
-
|
|
406
|
+
kwargs: dict[str, Any] = {
|
|
407
|
+
"product": data.provider_product_id,
|
|
408
|
+
"currency": data.currency.lower(),
|
|
409
|
+
"unit_amount": int(data.unit_amount),
|
|
410
|
+
"active": bool(data.active),
|
|
411
|
+
}
|
|
436
412
|
if data.interval:
|
|
437
413
|
kwargs["recurring"] = {"interval": data.interval}
|
|
438
414
|
if data.trial_days is not None:
|
|
@@ -461,14 +437,10 @@ class StripeAdapter(ProviderAdapter):
|
|
|
461
437
|
params["starting_after"] = cursor
|
|
462
438
|
res = await _acall(stripe.Price.list, **params)
|
|
463
439
|
items = [_price_to_out(p) for p in res.data]
|
|
464
|
-
next_cursor = (
|
|
465
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
466
|
-
)
|
|
440
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
467
441
|
return items, next_cursor
|
|
468
442
|
|
|
469
|
-
async def update_price(
|
|
470
|
-
self, provider_price_id: str, data: PriceUpdateIn
|
|
471
|
-
) -> PriceOut:
|
|
443
|
+
async def update_price(self, provider_price_id: str, data: PriceUpdateIn) -> PriceOut:
|
|
472
444
|
# Stripe allows toggling `active` and updating metadata, but not amount/currency/product.
|
|
473
445
|
update: dict[str, Any] = {}
|
|
474
446
|
if data.active is not None:
|
|
@@ -482,11 +454,11 @@ class StripeAdapter(ProviderAdapter):
|
|
|
482
454
|
|
|
483
455
|
# -------- Subscriptions --------
|
|
484
456
|
async def create_subscription(self, data: SubscriptionCreateIn) -> SubscriptionOut:
|
|
485
|
-
kwargs: dict[str, Any] =
|
|
486
|
-
customer
|
|
487
|
-
items
|
|
488
|
-
proration_behavior
|
|
489
|
-
|
|
457
|
+
kwargs: dict[str, Any] = {
|
|
458
|
+
"customer": data.customer_provider_id,
|
|
459
|
+
"items": [{"price": data.price_provider_id, "quantity": int(data.quantity)}],
|
|
460
|
+
"proration_behavior": data.proration_behavior,
|
|
461
|
+
}
|
|
490
462
|
if data.trial_days is not None:
|
|
491
463
|
kwargs["trial_period_days"] = int(data.trial_days)
|
|
492
464
|
s = await _acall(stripe.Subscription.create, **kwargs)
|
|
@@ -495,9 +467,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
495
467
|
async def update_subscription(
|
|
496
468
|
self, provider_subscription_id: str, data: SubscriptionUpdateIn
|
|
497
469
|
) -> SubscriptionOut:
|
|
498
|
-
s = await _acall(
|
|
499
|
-
stripe.Subscription.retrieve, provider_subscription_id, expand=["items"]
|
|
500
|
-
)
|
|
470
|
+
s = await _acall(stripe.Subscription.retrieve, provider_subscription_id, expand=["items"])
|
|
501
471
|
items = s.items.data
|
|
502
472
|
update_kwargs: dict[str, Any] = {"proration_behavior": data.proration_behavior}
|
|
503
473
|
# update first item (simple plan model)
|
|
@@ -511,27 +481,21 @@ class StripeAdapter(ProviderAdapter):
|
|
|
511
481
|
update_kwargs["items"] = [item_update]
|
|
512
482
|
if data.cancel_at_period_end is not None:
|
|
513
483
|
update_kwargs["cancel_at_period_end"] = bool(data.cancel_at_period_end)
|
|
514
|
-
s2 = await _acall(
|
|
515
|
-
stripe.Subscription.modify, provider_subscription_id, **update_kwargs
|
|
516
|
-
)
|
|
484
|
+
s2 = await _acall(stripe.Subscription.modify, provider_subscription_id, **update_kwargs)
|
|
517
485
|
return _sub_to_out(s2)
|
|
518
486
|
|
|
519
487
|
async def cancel_subscription(
|
|
520
488
|
self, provider_subscription_id: str, at_period_end: bool = True
|
|
521
489
|
) -> SubscriptionOut:
|
|
522
490
|
s = await _acall(
|
|
523
|
-
stripe.Subscription.cancel
|
|
524
|
-
if not at_period_end
|
|
525
|
-
else stripe.Subscription.modify,
|
|
491
|
+
stripe.Subscription.cancel if not at_period_end else stripe.Subscription.modify,
|
|
526
492
|
provider_subscription_id,
|
|
527
493
|
**({} if not at_period_end else {"cancel_at_period_end": True}),
|
|
528
494
|
)
|
|
529
495
|
return _sub_to_out(s)
|
|
530
496
|
|
|
531
497
|
async def get_subscription(self, provider_subscription_id: str) -> SubscriptionOut:
|
|
532
|
-
s = await _acall(
|
|
533
|
-
stripe.Subscription.retrieve, provider_subscription_id, expand=["items"]
|
|
534
|
-
)
|
|
498
|
+
s = await _acall(stripe.Subscription.retrieve, provider_subscription_id, expand=["items"])
|
|
535
499
|
return _sub_to_out(s)
|
|
536
500
|
|
|
537
501
|
async def list_subscriptions(
|
|
@@ -551,9 +515,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
551
515
|
params["starting_after"] = cursor
|
|
552
516
|
res = await _acall(stripe.Subscription.list, **params)
|
|
553
517
|
items = [_sub_to_out(s) for s in res.data]
|
|
554
|
-
next_cursor = (
|
|
555
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
556
|
-
)
|
|
518
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
557
519
|
return items, next_cursor
|
|
558
520
|
|
|
559
521
|
# -------- Invoices --------
|
|
@@ -581,13 +543,13 @@ class StripeAdapter(ProviderAdapter):
|
|
|
581
543
|
self, provider_invoice_id: str, data: InvoiceLineItemIn
|
|
582
544
|
) -> InvoiceOut:
|
|
583
545
|
# attach an item to a DRAFT invoice
|
|
584
|
-
kwargs: dict[str, Any] =
|
|
585
|
-
invoice
|
|
586
|
-
customer
|
|
587
|
-
quantity
|
|
588
|
-
currency
|
|
589
|
-
description
|
|
590
|
-
|
|
546
|
+
kwargs: dict[str, Any] = {
|
|
547
|
+
"invoice": provider_invoice_id,
|
|
548
|
+
"customer": data.customer_provider_id,
|
|
549
|
+
"quantity": int(data.quantity or 1),
|
|
550
|
+
"currency": data.currency.lower(),
|
|
551
|
+
"description": data.description or None,
|
|
552
|
+
}
|
|
591
553
|
if data.provider_price_id:
|
|
592
554
|
kwargs["price"] = data.provider_price_id
|
|
593
555
|
else:
|
|
@@ -616,9 +578,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
616
578
|
params["starting_after"] = cursor
|
|
617
579
|
res = await _acall(stripe.Invoice.list, **params)
|
|
618
580
|
items = [_inv_to_out(inv) for inv in res.data]
|
|
619
|
-
next_cursor = (
|
|
620
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
621
|
-
)
|
|
581
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
622
582
|
return items, next_cursor
|
|
623
583
|
|
|
624
584
|
async def get_invoice(self, provider_invoice_id: str) -> InvoiceOut:
|
|
@@ -656,24 +616,20 @@ class StripeAdapter(ProviderAdapter):
|
|
|
656
616
|
provider_price_id=price_id,
|
|
657
617
|
)
|
|
658
618
|
)
|
|
659
|
-
next_cursor = (
|
|
660
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
661
|
-
)
|
|
619
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
662
620
|
return items, next_cursor
|
|
663
621
|
|
|
664
622
|
# -------- Intents --------
|
|
665
|
-
async def create_intent(
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
capture_method="manual" if data.capture_method == "manual" else "automatic",
|
|
673
|
-
automatic_payment_methods={"enabled": True}
|
|
623
|
+
async def create_intent(self, data: IntentCreateIn, *, user_id: str | None) -> IntentOut:
|
|
624
|
+
kwargs: dict[str, Any] = {
|
|
625
|
+
"amount": int(data.amount),
|
|
626
|
+
"currency": data.currency.lower(),
|
|
627
|
+
"description": data.description or None,
|
|
628
|
+
"capture_method": "manual" if data.capture_method == "manual" else "automatic",
|
|
629
|
+
"automatic_payment_methods": {"enabled": True}
|
|
674
630
|
if not data.payment_method_types
|
|
675
631
|
else None,
|
|
676
|
-
|
|
632
|
+
}
|
|
677
633
|
if data.payment_method_types:
|
|
678
634
|
kwargs["payment_method_types"] = data.payment_method_types
|
|
679
635
|
pi = await _acall(
|
|
@@ -709,9 +665,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
709
665
|
pi = await _acall(stripe.PaymentIntent.retrieve, provider_intent_id)
|
|
710
666
|
return _pi_to_out(pi)
|
|
711
667
|
|
|
712
|
-
async def capture_intent(
|
|
713
|
-
self, provider_intent_id: str, *, amount: int | None
|
|
714
|
-
) -> IntentOut:
|
|
668
|
+
async def capture_intent(self, provider_intent_id: str, *, amount: int | None) -> IntentOut:
|
|
715
669
|
kwargs = {}
|
|
716
670
|
if amount is not None:
|
|
717
671
|
kwargs["amount_to_capture"] = int(amount)
|
|
@@ -735,9 +689,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
735
689
|
params["starting_after"] = cursor
|
|
736
690
|
res = await _acall(stripe.PaymentIntent.list, **params)
|
|
737
691
|
items = [_pi_to_out(pi) for pi in res.data]
|
|
738
|
-
next_cursor = (
|
|
739
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
740
|
-
)
|
|
692
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
741
693
|
return items, next_cursor
|
|
742
694
|
|
|
743
695
|
# ---- Setup Intents (off-session readiness) ----
|
|
@@ -752,14 +704,10 @@ class StripeAdapter(ProviderAdapter):
|
|
|
752
704
|
provider_setup_intent_id=si.id,
|
|
753
705
|
status=si.status,
|
|
754
706
|
client_secret=getattr(si, "client_secret", None),
|
|
755
|
-
next_action=NextAction(
|
|
756
|
-
type=getattr(getattr(si, "next_action", None), "type", None)
|
|
757
|
-
),
|
|
707
|
+
next_action=NextAction(type=getattr(getattr(si, "next_action", None), "type", None)),
|
|
758
708
|
)
|
|
759
709
|
|
|
760
|
-
async def confirm_setup_intent(
|
|
761
|
-
self, provider_setup_intent_id: str
|
|
762
|
-
) -> SetupIntentOut:
|
|
710
|
+
async def confirm_setup_intent(self, provider_setup_intent_id: str) -> SetupIntentOut:
|
|
763
711
|
si = await _acall(stripe.SetupIntent.confirm, provider_setup_intent_id)
|
|
764
712
|
return SetupIntentOut(
|
|
765
713
|
id=si.id,
|
|
@@ -767,9 +715,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
767
715
|
provider_setup_intent_id=si.id,
|
|
768
716
|
status=si.status,
|
|
769
717
|
client_secret=getattr(si, "client_secret", None),
|
|
770
|
-
next_action=NextAction(
|
|
771
|
-
type=getattr(getattr(si, "next_action", None), "type", None)
|
|
772
|
-
),
|
|
718
|
+
next_action=NextAction(type=getattr(getattr(si, "next_action", None), "type", None)),
|
|
773
719
|
)
|
|
774
720
|
|
|
775
721
|
async def get_setup_intent(self, provider_setup_intent_id: str) -> SetupIntentOut:
|
|
@@ -780,9 +726,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
780
726
|
provider_setup_intent_id=si.id,
|
|
781
727
|
status=si.status,
|
|
782
728
|
client_secret=getattr(si, "client_secret", None),
|
|
783
|
-
next_action=NextAction(
|
|
784
|
-
type=getattr(getattr(si, "next_action", None), "type", None)
|
|
785
|
-
),
|
|
729
|
+
next_action=NextAction(type=getattr(getattr(si, "next_action", None), "type", None)),
|
|
786
730
|
)
|
|
787
731
|
|
|
788
732
|
# ---- 3DS/SCA resume ----
|
|
@@ -801,18 +745,14 @@ class StripeAdapter(ProviderAdapter):
|
|
|
801
745
|
params["starting_after"] = cursor
|
|
802
746
|
res = await _acall(stripe.Dispute.list, **params)
|
|
803
747
|
items = [_dispute_to_out(d) for d in res.data]
|
|
804
|
-
next_cursor = (
|
|
805
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
806
|
-
)
|
|
748
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
807
749
|
return items, next_cursor
|
|
808
750
|
|
|
809
751
|
async def get_dispute(self, provider_dispute_id: str) -> DisputeOut:
|
|
810
752
|
d = await _acall(stripe.Dispute.retrieve, provider_dispute_id)
|
|
811
753
|
return _dispute_to_out(d)
|
|
812
754
|
|
|
813
|
-
async def submit_dispute_evidence(
|
|
814
|
-
self, provider_dispute_id: str, evidence: dict
|
|
815
|
-
) -> DisputeOut:
|
|
755
|
+
async def submit_dispute_evidence(self, provider_dispute_id: str, evidence: dict) -> DisputeOut:
|
|
816
756
|
d = await _acall(stripe.Dispute.modify, provider_dispute_id, evidence=evidence)
|
|
817
757
|
# Some disputes require explicit submit call:
|
|
818
758
|
try:
|
|
@@ -828,9 +768,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
828
768
|
def _bucket(entries):
|
|
829
769
|
out = []
|
|
830
770
|
for b in entries or []:
|
|
831
|
-
out.append(
|
|
832
|
-
{"currency": str(b.currency).upper(), "amount": int(b.amount)}
|
|
833
|
-
)
|
|
771
|
+
out.append({"currency": str(b.currency).upper(), "amount": int(b.amount)})
|
|
834
772
|
return out
|
|
835
773
|
|
|
836
774
|
return BalanceSnapshotOut(
|
|
@@ -846,9 +784,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
846
784
|
params["starting_after"] = cursor
|
|
847
785
|
res = await _acall(stripe.Payout.list, **params)
|
|
848
786
|
items = [_payout_to_out(p) for p in res.data]
|
|
849
|
-
next_cursor = (
|
|
850
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
851
|
-
)
|
|
787
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
852
788
|
return items, next_cursor
|
|
853
789
|
|
|
854
790
|
async def get_payout(self, provider_payout_id: str) -> PayoutOut:
|
|
@@ -866,9 +802,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
866
802
|
params["starting_after"] = cursor
|
|
867
803
|
res = await _acall(stripe.Refund.list, **params)
|
|
868
804
|
items = [_refund_to_out(r) for r in res.data]
|
|
869
|
-
next_cursor = (
|
|
870
|
-
res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
871
|
-
)
|
|
805
|
+
next_cursor = res.data[-1].id if getattr(res, "has_more", False) and res.data else None
|
|
872
806
|
return items, next_cursor
|
|
873
807
|
|
|
874
808
|
async def get_refund(self, provider_refund_id: str) -> RefundOut:
|
|
@@ -909,9 +843,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
909
843
|
# Stripe exposes *summaries* per period. We surface them as list results.
|
|
910
844
|
sub_item = f.subscription_item
|
|
911
845
|
if not sub_item and f.provider_price_id:
|
|
912
|
-
items = await _acall(
|
|
913
|
-
stripe.SubscriptionItem.list, price=f.provider_price_id, limit=1
|
|
914
|
-
)
|
|
846
|
+
items = await _acall(stripe.SubscriptionItem.list, price=f.provider_price_id, limit=1)
|
|
915
847
|
sub_item = items.data[0].id if items.data else None
|
|
916
848
|
if not sub_item:
|
|
917
849
|
return [], None
|
|
@@ -938,9 +870,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
938
870
|
)
|
|
939
871
|
next_cursor = (
|
|
940
872
|
res.data[-1].id
|
|
941
|
-
if getattr(res, "has_more", False)
|
|
942
|
-
and res.data
|
|
943
|
-
and hasattr(res.data[-1], "id")
|
|
873
|
+
if getattr(res, "has_more", False) and res.data and hasattr(res.data[-1], "id")
|
|
944
874
|
else None
|
|
945
875
|
)
|
|
946
876
|
return usage_records, next_cursor
|
|
@@ -948,9 +878,7 @@ class StripeAdapter(ProviderAdapter):
|
|
|
948
878
|
async def get_usage_record(self, usage_record_id: str) -> UsageRecordOut:
|
|
949
879
|
# Stripe has no direct "retrieve usage record by id" API.
|
|
950
880
|
# You can reconstruct via list summaries or store records locally when creating.
|
|
951
|
-
raise NotImplementedError(
|
|
952
|
-
"Stripe does not support retrieving a single usage record by id"
|
|
953
|
-
)
|
|
881
|
+
raise NotImplementedError("Stripe does not support retrieving a single usage record by id")
|
|
954
882
|
|
|
955
883
|
# -------- Webhooks --------
|
|
956
884
|
async def verify_and_parse_webhook(
|