Coverage for polar/payout/tasks.py: 40%
53 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 17:15 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 17:15 +0000
1import uuid 1a
3import sentry_sdk 1a
4import stripe as stripe_lib 1a
5import structlog 1a
7from polar.enums import AccountType 1a
8from polar.exceptions import PolarTaskError 1a
9from polar.logging import Logger 1a
10from polar.worker import AsyncSessionMaker, CronTrigger, TaskPriority, actor 1a
12from .repository import PayoutRepository 1a
13from .service import PayoutAlreadyTriggered 1a
14from .service import payout as payout_service 1a
16log: Logger = structlog.get_logger() 1a
19class PayoutTaskError(PolarTaskError): ... 1a
22class PayoutDoesNotExist(PayoutTaskError): 1a
23 def __init__(self, payout_id: uuid.UUID) -> None: 1a
24 self.payout_id = payout_id
25 message = f"The payout with id {payout_id} does not exist."
26 super().__init__(message)
29@actor(actor_name="payout.created", priority=TaskPriority.LOW) 1a
30async def payout_created(payout_id: uuid.UUID) -> None: 1a
31 async with AsyncSessionMaker() as session:
32 repository = PayoutRepository(session)
33 payout = await repository.get_by_id(
34 payout_id, options=repository.get_eager_options()
35 )
36 if payout is None:
37 raise PayoutDoesNotExist(payout_id)
39 if payout.processor == AccountType.stripe:
40 await payout_service.transfer_stripe(session, payout)
43@actor( 1a
44 actor_name="payout.trigger_stripe_payouts",
45 cron_trigger=CronTrigger(minute=15),
46 priority=TaskPriority.LOW,
47)
48async def trigger_stripe_payouts() -> None: 1a
49 async with AsyncSessionMaker() as session:
50 await payout_service.trigger_stripe_payouts(session)
53@actor(actor_name="payout.trigger_stripe_payout", priority=TaskPriority.LOW) 1a
54async def trigger_payout(payout_id: uuid.UUID) -> None: 1a
55 async with AsyncSessionMaker() as session:
56 repository = PayoutRepository(session)
57 payout = await repository.get_by_id(
58 payout_id, options=repository.get_eager_options()
59 )
60 if payout is None:
61 raise PayoutDoesNotExist(payout_id)
63 try:
64 await payout_service.trigger_stripe_payout(session, payout)
65 except PayoutAlreadyTriggered:
66 # Swallow it, since it's likely a task that's being retried
67 # while the payout has already been triggered.
68 pass
69 except stripe_lib.InvalidRequestError as e:
70 # Capture exception in Sentry for debugging purposes
71 sentry_sdk.capture_exception(
72 e,
73 extras={"payout_id": str(payout_id)},
74 )
75 # Do not raise an error here: we know it happens often, because Stripe
76 # has many hidden rules on payout creation that we cannot control.
77 pass
80@actor(actor_name="payout.invoice", priority=TaskPriority.LOW) 1a
81async def order_invoice(payout_id: uuid.UUID) -> None: 1a
82 async with AsyncSessionMaker() as session:
83 repository = PayoutRepository(session)
84 payout = await repository.get_by_id(
85 payout_id, options=repository.get_eager_options()
86 )
87 if payout is None:
88 raise PayoutDoesNotExist(payout_id)
90 await payout_service.generate_invoice(session, payout)