from __future__ import annotations from ulid import ULID from src.application.abstractions import IUnitOfWork from src.application.contracts import ILogger,IQueueMessanger from src.application.domain.enums import PaymentStatus from src.application.domain.exceptions import PaymentMetadataException from src.infrastructure.config import settings from src.infrastructure.database.decorators import transactional from src.presentation.schemas.itpay_payment_models import ItpayPaymentData class CreatePaymentCommand: def __init__(self, *, unit_of_work: IUnitOfWork, logger: ILogger, queue_messanger: IQueueMessanger): self._unit_of_work = unit_of_work self._logger = logger self._queue_messanger = queue_messanger @transactional async def __call__(self, payment: ItpayPaymentData) -> None: if str(payment.status).strip().lower() != 'completed': return metadata = payment.metadata or {} order_id = str(metadata.get('order_id') or '') user_id = str(metadata.get('user_id') or '') trace_id = str(metadata.get('trace_id') or self._logger.get_trace_id()) self._logger.set_trace_id(trace_id) if not order_id: raise PaymentMetadataException(message='Itpay webhook metadata missing order_id') if not user_id: raise PaymentMetadataException(message='Itpay webhook metadata missing user_id') payment_created = await self._unit_of_work.payment_repository.create_completed( user_id=user_id, order_id=order_id, itpay_payment_id=str(payment.id), itpay_paid_amount=str(payment.amount) if payment.amount is not None else None, transaction_id=str(payment.transaction_id) if payment.transaction_id is not None else None, paid_at=str(payment.paid) if payment.paid is not None else None, expired_date=str(payment.expired_date) if payment.expired_date is not None else None, ) if not payment_created: return message_id = str(ULID()) message: dict[str,str] = { 'order_id': order_id, 'user_id': user_id, 'trace_id': trace_id, 'message_id': message_id, } await self._queue_messanger.publish_to_queue( queue=settings.RABBIT_CRYPTO_TRANSFER_QUEUE, message=message, message_id=message_id, correlation_id=message['trace_id'], headers={'trace_id': trace_id}, ) await self._unit_of_work.payment_repository.update_status( order_id=order_id, status=PaymentStatus.WEB3_PROCESSING, )