svc-infra 0.1.577__py3-none-any.whl → 0.1.579__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.

@@ -20,11 +20,13 @@ from ..schemas import (
20
20
  ProductCreateIn,
21
21
  ProductOut,
22
22
  RefundIn,
23
+ SetupIntentCreateIn,
23
24
  SetupIntentOut,
24
25
  SubscriptionCreateIn,
25
26
  SubscriptionOut,
26
27
  SubscriptionUpdateIn,
27
28
  UsageRecordIn,
29
+ UsageRecordOut,
28
30
  )
29
31
 
30
32
 
@@ -43,12 +45,12 @@ class ProviderAdapter(Protocol):
43
45
  async def list_payment_methods(self, provider_customer_id: str) -> list[PaymentMethodOut]:
44
46
  pass
45
47
 
46
- async def detach_payment_method(self, provider_method_id: str) -> None:
48
+ async def detach_payment_method(self, provider_method_id: str) -> PaymentMethodOut:
47
49
  pass
48
50
 
49
51
  async def set_default_payment_method(
50
52
  self, provider_customer_id: str, provider_method_id: str
51
- ) -> None:
53
+ ) -> PaymentMethodOut:
52
54
  pass
53
55
 
54
56
  async def create_product(self, data: ProductCreateIn) -> ProductOut:
@@ -117,7 +119,7 @@ class ProviderAdapter(Protocol):
117
119
 
118
120
  async def add_invoice_line_item(
119
121
  self, provider_invoice_id: str, data: InvoiceLineItemIn
120
- ) -> dict[str, Any]:
122
+ ) -> InvoiceOut:
121
123
  pass
122
124
 
123
125
  async def list_invoices(
@@ -138,11 +140,11 @@ class ProviderAdapter(Protocol):
138
140
  ) -> InvoiceOut:
139
141
  pass
140
142
 
141
- async def create_usage_record(self, data: UsageRecordIn) -> dict[str, Any]:
143
+ async def create_usage_record(self, data: UsageRecordIn) -> UsageRecordOut:
142
144
  pass
143
145
 
144
146
  # --- Setup Intents ---
145
- async def create_setup_intent(self, payment_method_types: list[str]) -> SetupIntentOut:
147
+ async def create_setup_intent(self, data: SetupIntentCreateIn) -> SetupIntentOut:
146
148
  pass
147
149
 
148
150
  async def confirm_setup_intent(self, provider_setup_intent_id: str) -> SetupIntentOut:
@@ -248,3 +248,23 @@ class BalanceAmount(BaseModel):
248
248
  class BalanceSnapshotOut(BaseModel):
249
249
  available: list[BalanceAmount] = Field(default_factory=list)
250
250
  pending: list[BalanceAmount] = Field(default_factory=list)
251
+
252
+
253
+ class SetupIntentCreateIn(BaseModel):
254
+ payment_method_types: list[str] = Field(default_factory=lambda: ["card"])
255
+
256
+
257
+ class WebhookReplayOut(BaseModel):
258
+ replayed: int
259
+
260
+
261
+ class WebhookAckOut(BaseModel):
262
+ ok: bool
263
+
264
+
265
+ class UsageRecordOut(BaseModel):
266
+ id: str
267
+ quantity: int
268
+ timestamp: Optional[int] = None
269
+ subscription_item: Optional[str] = None
270
+ provider_price_id: Optional[str] = None
@@ -41,12 +41,14 @@ from .schemas import (
41
41
  ProductCreateIn,
42
42
  ProductOut,
43
43
  RefundIn,
44
+ SetupIntentCreateIn,
44
45
  SetupIntentOut,
45
46
  StatementRow,
46
47
  SubscriptionCreateIn,
47
48
  SubscriptionOut,
48
49
  SubscriptionUpdateIn,
49
50
  UsageRecordIn,
51
+ UsageRecordOut,
50
52
  )
51
53
  from .settings import get_payments_settings
52
54
 
@@ -259,13 +261,13 @@ class PaymentsService:
259
261
  async def list_payment_methods(self, provider_customer_id: str) -> list[PaymentMethodOut]:
260
262
  return await self._get_adapter().list_payment_methods(provider_customer_id)
261
263
 
262
- async def detach_payment_method(self, provider_method_id: str) -> None:
263
- await self._get_adapter().detach_payment_method(provider_method_id)
264
+ async def detach_payment_method(self, provider_method_id: str) -> PaymentMethodOut:
265
+ return await self._get_adapter().detach_payment_method(provider_method_id)
264
266
 
265
267
  async def set_default_payment_method(
266
268
  self, provider_customer_id: str, provider_method_id: str
267
- ) -> None:
268
- await self._get_adapter().set_default_payment_method(
269
+ ) -> PaymentMethodOut:
270
+ return await self._get_adapter().set_default_payment_method(
269
271
  provider_customer_id, provider_method_id
270
272
  )
271
273
 
@@ -436,7 +438,7 @@ class PaymentsService:
436
438
  # ---- Invoices: lines/list/get/preview ----
437
439
  async def add_invoice_line_item(
438
440
  self, provider_invoice_id: str, data: InvoiceLineItemIn
439
- ) -> dict:
441
+ ) -> InvoiceOut:
440
442
  return await self._get_adapter().add_invoice_line_item(provider_invoice_id, data)
441
443
 
442
444
  async def list_invoices(self, f: InvoicesListFilter) -> tuple[list[InvoiceOut], str | None]:
@@ -458,18 +460,17 @@ class PaymentsService:
458
460
  )
459
461
 
460
462
  # ---- Metered usage ----
461
- async def create_usage_record(self, data: UsageRecordIn) -> dict:
463
+ async def create_usage_record(self, data: UsageRecordIn) -> UsageRecordOut:
462
464
  return await self._get_adapter().create_usage_record(data)
463
465
 
464
466
  # --- Setup Intents --------------------------------------------------------
465
-
466
- async def create_setup_intent(self, payment_method_types: list[str]) -> SetupIntentOut:
467
- out = await self._get_adapter().create_setup_intent(payment_method_types)
467
+ async def create_setup_intent(self, data: SetupIntentCreateIn) -> SetupIntentOut:
468
+ out = await self._get_adapter().create_setup_intent(data)
468
469
  self.session.add(
469
470
  PaySetupIntent(
470
471
  provider=out.provider,
471
472
  provider_setup_intent_id=out.provider_setup_intent_id,
472
- user_id=None, # set if you thread a user_id; your router currently doesn't
473
+ user_id=None,
473
474
  status=out.status,
474
475
  client_secret=out.client_secret,
475
476
  )
@@ -26,6 +26,7 @@ from svc_infra.apf_payments.schemas import (
26
26
  ProductCreateIn,
27
27
  ProductOut,
28
28
  RefundIn,
29
+ SetupIntentCreateIn,
29
30
  SetupIntentOut,
30
31
  StatementRow,
31
32
  SubscriptionCreateIn,
@@ -33,6 +34,9 @@ from svc_infra.apf_payments.schemas import (
33
34
  SubscriptionUpdateIn,
34
35
  TransactionRow,
35
36
  UsageRecordIn,
37
+ UsageRecordOut,
38
+ WebhookAckOut,
39
+ WebhookReplayOut,
36
40
  )
37
41
  from svc_infra.apf_payments.service import PaymentsService
38
42
  from svc_infra.api.fastapi.db.sql.session import SqlSessionDep
@@ -73,6 +77,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
73
77
  "/customers",
74
78
  response_model=CustomerOut,
75
79
  name="payments_upsert_customer",
80
+ dependencies=[Depends(require_idempotency_key)],
76
81
  )
77
82
  async def upsert_customer(data: CustomerUpsertIn, svc: PaymentsService = Depends(get_service)):
78
83
  out = await svc.ensure_customer(data)
@@ -180,7 +185,11 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
180
185
  # PUBLIC webhooks
181
186
  pub = public_router(prefix=prefix, tags=["payments"])
182
187
 
183
- @pub.post("/webhooks/{provider}", name="payments_webhook")
188
+ @pub.post(
189
+ "/webhooks/{provider}",
190
+ name="payments_webhook",
191
+ response_model=WebhookAckOut,
192
+ )
184
193
  async def webhooks(
185
194
  provider: str,
186
195
  request: Request,
@@ -235,16 +244,18 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
235
244
  @prot.post(
236
245
  "/methods/{provider_method_id}/detach",
237
246
  name="payments_detach_method",
247
+ response_model=PaymentMethodOut,
238
248
  dependencies=[Depends(require_idempotency_key)],
239
249
  )
240
250
  async def detach_method(provider_method_id: str, svc: PaymentsService = Depends(get_service)):
241
- await svc.detach_payment_method(provider_method_id)
251
+ out = await svc.detach_payment_method(provider_method_id)
242
252
  await svc.session.flush()
243
- return {"ok": True}
253
+ return out
244
254
 
245
255
  @prot.post(
246
256
  "/methods/{provider_method_id}/default",
247
257
  name="payments_set_default_method",
258
+ response_model=PaymentMethodOut, # ADD
248
259
  dependencies=[Depends(require_idempotency_key)],
249
260
  )
250
261
  async def set_default_method(
@@ -252,9 +263,9 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
252
263
  customer_provider_id: str,
253
264
  svc: PaymentsService = Depends(get_service),
254
265
  ):
255
- await svc.set_default_payment_method(customer_provider_id, provider_method_id)
266
+ out = await svc.set_default_payment_method(customer_provider_id, provider_method_id)
256
267
  await svc.session.flush()
257
- return {"ok": True}
268
+ return out
258
269
 
259
270
  # PRODUCTS/PRICES
260
271
  @svc.post(
@@ -441,6 +452,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
441
452
  "/invoices/{provider_invoice_id}/lines",
442
453
  name="payments_add_invoice_line_item",
443
454
  status_code=status.HTTP_201_CREATED,
455
+ response_model=InvoiceOut,
444
456
  dependencies=[Depends(require_idempotency_key)],
445
457
  )
446
458
  async def add_invoice_line(
@@ -450,7 +462,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
450
462
  ):
451
463
  out = await svc.add_invoice_line_item(provider_invoice_id, data)
452
464
  await svc.session.flush()
453
- return {"ok": True, **out}
465
+ return out
454
466
 
455
467
  @prot.get(
456
468
  "/invoices",
@@ -501,6 +513,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
501
513
  name="payments_create_usage_record",
502
514
  status_code=status.HTTP_201_CREATED,
503
515
  dependencies=[Depends(require_idempotency_key)],
516
+ response_model=UsageRecordOut,
504
517
  )
505
518
  async def create_usage_record_endpoint(
506
519
  data: UsageRecordIn, svc: PaymentsService = Depends(get_service)
@@ -514,19 +527,21 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
514
527
  "/setup_intents",
515
528
  name="payments_create_setup_intent",
516
529
  status_code=status.HTTP_201_CREATED,
530
+ response_model=SetupIntentOut,
517
531
  dependencies=[Depends(require_idempotency_key)],
518
532
  )
519
533
  async def create_setup_intent(
520
- payment_method_types: list[str] = Body(default_factory=lambda: ["card"]),
534
+ data: SetupIntentCreateIn,
521
535
  svc: PaymentsService = Depends(get_service),
522
536
  ):
523
- out = await svc.create_setup_intent(payment_method_types)
537
+ out = await svc.create_setup_intent(data)
524
538
  await svc.session.flush()
525
539
  return out
526
540
 
527
541
  @prot.post(
528
542
  "/setup_intents/{provider_setup_intent_id}/confirm",
529
543
  name="payments_confirm_setup_intent",
544
+ response_model=SetupIntentOut,
530
545
  dependencies=[Depends(require_idempotency_key)],
531
546
  )
532
547
  async def confirm_setup_intent(
@@ -550,6 +565,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
550
565
  @prot.post(
551
566
  "/intents/{provider_intent_id}/resume",
552
567
  name="payments_resume_intent",
568
+ response_model=IntentOut,
553
569
  dependencies=[Depends(require_idempotency_key)],
554
570
  )
555
571
  async def resume_intent(
@@ -589,6 +605,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
589
605
  "/disputes/{provider_dispute_id}/submit_evidence",
590
606
  name="payments_submit_dispute_evidence",
591
607
  dependencies=[Depends(require_idempotency_key)],
608
+ response_model=DisputeOut,
592
609
  )
593
610
  async def submit_dispute_evidence(
594
611
  provider_dispute_id: str,
@@ -627,6 +644,7 @@ def build_payments_routers(prefix: str = "/payments") -> list[DualAPIRouter]:
627
644
  @svc.post(
628
645
  "/webhooks/replay",
629
646
  name="payments_replay_webhooks",
647
+ response_model=WebhookReplayOut,
630
648
  dependencies=[Depends(require_idempotency_key)],
631
649
  )
632
650
  async def replay_webhooks(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: svc-infra
3
- Version: 0.1.577
3
+ Version: 0.1.579
4
4
  Summary: Infrastructure for building and deploying prod-ready services
5
5
  License: MIT
6
6
  Keywords: fastapi,sqlalchemy,alembic,auth,infra,async,pydantic
@@ -3,16 +3,16 @@ svc_infra/apf_payments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
3
3
  svc_infra/apf_payments/alembic.py,sha256=XJIcCDOoaO1EeJbSx_qK9o4cBi430qyo5gECtjHIojw,299
4
4
  svc_infra/apf_payments/models.py,sha256=u4U5oszha5uulCIrNoajaFDIc5YmTlh2mtm-yJUvr9I,14251
5
5
  svc_infra/apf_payments/provider/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- svc_infra/apf_payments/provider/base.py,sha256=-PlFSSJBYRicW4YFnjzH1uUsMwMzTVHZAJYHH5e5IP4,4957
6
+ svc_infra/apf_payments/provider/base.py,sha256=sibrBvfULNPCPldokj2f_kDjxJo5zP06YHB1z5i4s3E,5016
7
7
  svc_infra/apf_payments/provider/registry.py,sha256=NZ4pUkFcbXNtqWEpFeI3NwoKRYGWe9fVQakmlrVLTKE,878
8
8
  svc_infra/apf_payments/provider/stripe.py,sha256=rZlQe1BBLBF1aMOqw98aDRZkA7pOgTqkGvXzSG8qE5c,11298
9
- svc_infra/apf_payments/schemas.py,sha256=rQWLR7ianGPy1dLNOkKlJpF8AIA-kTyT9SaGKq9rFA4,6338
10
- svc_infra/apf_payments/service.py,sha256=Pr-9VuLx7PpaAaMBpG1plfz7ZX0FanZ3apnyVEUFFf0,23858
9
+ svc_infra/apf_payments/schemas.py,sha256=BKzaKQaU4iEdT3onpP0dPfh33nU3AieHZLs_79cMp4M,6747
10
+ svc_infra/apf_payments/service.py,sha256=325Y118HWULmXX62S1wSrA8Guabtoa7Um0lzvMPDQZM,23872
11
11
  svc_infra/apf_payments/settings.py,sha256=VnNQbajbv843buUisqa82xOQ-f5JA8JzHD8o01-yhPQ,1239
12
12
  svc_infra/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  svc_infra/api/fastapi/__init__.py,sha256=VVdQjak74_wTDqmvL05_C97vIFugQxPVU-3JQEFBgR8,747
14
14
  svc_infra/api/fastapi/apf_payments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- svc_infra/api/fastapi/apf_payments/router.py,sha256=oSNuNvfX_qIdDqP1N8j8_28TBsTDX461vFIWa-VXqJg,21994
15
+ svc_infra/api/fastapi/apf_payments/router.py,sha256=ff2zYstk1XLSLDwXG0jBViZv624no5OPUSK1YLDJAH4,22464
16
16
  svc_infra/api/fastapi/apf_payments/setup.py,sha256=PX-LHDiyu2eDuaw2m98VPUkF6EmXXRkbjRqh_gL8Kls,2263
17
17
  svc_infra/api/fastapi/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  svc_infra/api/fastapi/auth/_cookies.py,sha256=U4heUmMnLezHx8U6ksuUEpSZ6sNMJcIO0gdLpmZ5FXw,1367
@@ -228,7 +228,7 @@ svc_infra/obs/templates/sidecars/railway/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
228
228
  svc_infra/obs/templates/sidecars/railway/agent.yaml,sha256=hYv35yG92XEP_4joMFmMcVTD-4fG_zHitmChjreUJh4,516
229
229
  svc_infra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
230
230
  svc_infra/utils.py,sha256=VX1yjTx61-YvAymyRhGy18DhybiVdPddiYD_FlKTbJU,952
231
- svc_infra-0.1.577.dist-info/METADATA,sha256=aRosq3LYSWllh1QSM3q1sBQAeUSqdtj2JmOzYQDuGvQ,3487
232
- svc_infra-0.1.577.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
233
- svc_infra-0.1.577.dist-info/entry_points.txt,sha256=6x_nZOsjvn6hRZsMgZLgTasaCSKCgAjsGhACe_CiP0U,48
234
- svc_infra-0.1.577.dist-info/RECORD,,
231
+ svc_infra-0.1.579.dist-info/METADATA,sha256=j_kXai0eMsASVgOLCR3hYP0Op-b_Pk3bu5QR_7DMfmY,3487
232
+ svc_infra-0.1.579.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
233
+ svc_infra-0.1.579.dist-info/entry_points.txt,sha256=6x_nZOsjvn6hRZsMgZLgTasaCSKCgAjsGhACe_CiP0U,48
234
+ svc_infra-0.1.579.dist-info/RECORD,,