50 lines
1.4 KiB
Python
50 lines
1.4 KiB
Python
import uuid
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.exc import IntegrityError
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models import OutboxEvent, Payment
|
|
from app.schemas import PaymentCreate, PaymentCreatedEvent
|
|
|
|
|
|
async def create_payment(
|
|
session: AsyncSession,
|
|
request: PaymentCreate,
|
|
idempotency_key: str,
|
|
) -> Payment:
|
|
payment_id = uuid.uuid4()
|
|
payment = Payment(
|
|
id=payment_id,
|
|
amount=request.amount,
|
|
currency=request.currency,
|
|
description=request.description,
|
|
metadata_=request.metadata,
|
|
idempotency_key=idempotency_key,
|
|
webhook_url=str(request.webhook_url),
|
|
)
|
|
event = PaymentCreatedEvent(payment_id=payment_id)
|
|
outbox_event = OutboxEvent(
|
|
aggregate_id=payment_id,
|
|
event_type="payment.created",
|
|
payload=event.model_dump(mode="json"),
|
|
)
|
|
session.add_all((payment, outbox_event))
|
|
|
|
try:
|
|
await session.commit()
|
|
except IntegrityError:
|
|
await session.rollback()
|
|
existing = await session.scalar(
|
|
select(Payment).where(Payment.idempotency_key == idempotency_key)
|
|
)
|
|
if existing is None:
|
|
raise
|
|
return existing
|
|
|
|
return payment
|
|
|
|
|
|
async def get_payment(session: AsyncSession, payment_id: uuid.UUID) -> Payment | None:
|
|
return await session.get(Payment, payment_id)
|