Coverage for polar/held_balance/service.py: 51%
37 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 15:52 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 15:52 +0000
1import structlog 1a
2from sqlalchemy import or_, select 1a
3from sqlalchemy.orm import joinedload 1a
5from polar.config import settings 1a
6from polar.exceptions import PolarError 1a
7from polar.kit.services import ResourceServiceReader 1a
8from polar.logging import Logger 1a
9from polar.models import ( 1a
10 Account,
11 HeldBalance,
12 Transaction,
13)
14from polar.models.organization import Organization 1a
15from polar.postgres import AsyncSession 1a
16from polar.transaction.service.balance import ( 1a
17 balance_transaction as balance_transaction_service,
18)
19from polar.transaction.service.dispute import ( 1a
20 dispute_transaction as dispute_transaction_service,
21)
22from polar.transaction.service.platform_fee import ( 1a
23 platform_fee_transaction as platform_fee_transaction_service,
24)
25from polar.transaction.service.refund import ( 1a
26 refund_transaction as refund_transaction_service,
27)
29log: Logger = structlog.get_logger() 1a
32class HeldBalanceError(PolarError): ... 1a
35class HeldBalanceService(ResourceServiceReader[HeldBalance]): 1a
36 async def create( 1a
37 self, session: AsyncSession, *, held_balance: HeldBalance
38 ) -> HeldBalance:
39 session.add(held_balance)
40 await session.flush()
41 return held_balance
43 async def release_account( 1a
44 self, session: AsyncSession, account: Account
45 ) -> list[tuple[Transaction, Transaction]]:
46 statement = (
47 select(HeldBalance)
48 .join(
49 Organization,
50 onclause=HeldBalance.organization_id == Organization.id,
51 isouter=True,
52 )
53 .where(
54 or_(
55 HeldBalance.account_id == account.id,
56 Organization.account_id == account.id,
57 ),
58 HeldBalance.deleted_at.is_(None),
59 )
60 .options(
61 joinedload(HeldBalance.payment_transaction),
62 joinedload(HeldBalance.pledge),
63 joinedload(HeldBalance.order),
64 joinedload(HeldBalance.issue_reward),
65 )
66 )
67 held_balances = await session.stream_scalars(
68 statement,
69 execution_options={"yield_per": settings.DATABASE_STREAM_YIELD_PER},
70 )
72 balance_transactions_list: list[tuple[Transaction, Transaction]] = []
73 async for held_balance in held_balances:
74 balance_transactions = await balance_transaction_service.create_balance(
75 session,
76 source_account=None,
77 destination_account=account,
78 payment_transaction=held_balance.payment_transaction,
79 amount=held_balance.amount,
80 pledge=held_balance.pledge,
81 order=held_balance.order,
82 issue_reward=held_balance.issue_reward,
83 )
84 balance_transactions_list.append(balance_transactions)
86 platform_fee_transactions = (
87 await platform_fee_transaction_service.create_fees_reversal_balances(
88 session, balance_transactions=balance_transactions
89 )
90 )
91 if held_balance.order:
92 held_balance.order.platform_fee_amount = sum(
93 incoming.amount for _, incoming in platform_fee_transactions
94 )
95 session.add(held_balance.order)
97 await refund_transaction_service.create_reversal_balances_for_payment(
98 session, payment_transaction=held_balance.payment_transaction
99 )
100 await dispute_transaction_service.create_reversal_balances_for_payment(
101 session, payment_transaction=held_balance.payment_transaction
102 )
104 await session.delete(held_balance)
106 return balance_transactions_list
109held_balance = HeldBalanceService(HeldBalance) 1a