feat(marketplace): purchase service with atomic escrow, 30/70 fee splitting and refunds
This commit is contained in:
@@ -78,6 +78,7 @@ class WalletService:
|
||||
reference_id: str | None = None,
|
||||
idempotency_key: str | None = None,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
commit: bool = True,
|
||||
) -> tuple[Wallet, Transaction]:
|
||||
"""Credit a user's wallet atomically with row locking.
|
||||
|
||||
@@ -113,9 +114,12 @@ class WalletService:
|
||||
metadata_json=metadata,
|
||||
)
|
||||
db.add(tx)
|
||||
await db.commit()
|
||||
await db.refresh(wallet)
|
||||
await db.refresh(tx)
|
||||
if commit:
|
||||
await db.commit()
|
||||
await db.refresh(wallet)
|
||||
await db.refresh(tx)
|
||||
else:
|
||||
await db.flush()
|
||||
return wallet, tx
|
||||
|
||||
@classmethod
|
||||
@@ -129,6 +133,7 @@ class WalletService:
|
||||
reference_id: str | None = None,
|
||||
idempotency_key: str | None = None,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
commit: bool = True,
|
||||
) -> tuple[Wallet, Transaction]:
|
||||
"""Debit a user's wallet atomically with row locking and balance check.
|
||||
|
||||
@@ -154,7 +159,8 @@ class WalletService:
|
||||
wallet = await cls.get_or_create_wallet(db, user_id, for_update=True)
|
||||
cur_balance = wallet.balance
|
||||
if cur_balance < amount:
|
||||
await db.rollback()
|
||||
if commit:
|
||||
await db.rollback()
|
||||
raise InsufficientFundsError(
|
||||
f"Insufficient funds: available {cur_balance}, required {amount}"
|
||||
)
|
||||
@@ -172,9 +178,12 @@ class WalletService:
|
||||
metadata_json=metadata,
|
||||
)
|
||||
db.add(tx)
|
||||
await db.commit()
|
||||
await db.refresh(wallet)
|
||||
await db.refresh(tx)
|
||||
if commit:
|
||||
await db.commit()
|
||||
await db.refresh(wallet)
|
||||
await db.refresh(tx)
|
||||
else:
|
||||
await db.flush()
|
||||
return wallet, tx
|
||||
|
||||
@staticmethod
|
||||
|
||||
Reference in New Issue
Block a user