69 lines
2.7 KiB
Python
69 lines
2.7 KiB
Python
from __future__ import annotations
|
|
from datetime import datetime, timezone
|
|
from decimal import Decimal
|
|
from ulid import ULID
|
|
from src.application.abstractions import IUnitOfWork
|
|
from src.application.contracts import ILogger
|
|
from src.application.contracts import IItPayService
|
|
from src.application.domain.entities.order import OrderEntity
|
|
from src.application.domain.enums import OrderStatus
|
|
from src.application.domain.exceptions import ApplicationException
|
|
from src.application.services import PaymentQuoteService
|
|
from src.infrastructure.database.decorators import transactional
|
|
from src.presentation.schemas.order import CreateOrder
|
|
|
|
|
|
class CreateOrderCommand:
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
unit_of_work: IUnitOfWork,
|
|
logger: ILogger,
|
|
payment_quote_service: PaymentQuoteService,
|
|
itpay_service: IItPayService,
|
|
) -> None:
|
|
self._unit_of_work = unit_of_work
|
|
self._logger = logger
|
|
self._payment_quote_service = payment_quote_service
|
|
self._itpay_service = itpay_service
|
|
|
|
|
|
@transactional
|
|
async def __call__(self, payment_data: CreateOrder, user_id: str) -> OrderEntity:
|
|
client_payment_id = str(ULID())
|
|
|
|
quote = await self._payment_quote_service.get_quote(payment_data.usdt_amount)
|
|
actual_gas_fee = quote.gas_fee
|
|
actual_usdt_exchange_rate = quote.usdt_exchange_rate
|
|
actual_service_fee = quote.service_fee
|
|
actual_total_price = quote.total_price
|
|
if actual_total_price > payment_data.total_price * Decimal('1.01'):
|
|
self._logger.error('Price has changed, please refresh and try again')
|
|
raise ApplicationException(status_code=409, message='Price has changed, please refresh and try again')
|
|
|
|
order = OrderEntity(
|
|
user_id=user_id,
|
|
usdt_amount=payment_data.usdt_amount,
|
|
usdt_exchange_rate=actual_usdt_exchange_rate,
|
|
gas_fee=actual_gas_fee,
|
|
service_fee=actual_service_fee,
|
|
total_price=actual_total_price,
|
|
status=OrderStatus.PENDING,
|
|
created_at=datetime.now(timezone.utc),
|
|
client_payment_id=client_payment_id,
|
|
)
|
|
|
|
saved = await self._unit_of_work.order_repository.create(order)
|
|
with_itpay = await self._itpay_service.create_payment(saved,self._logger.get_trace_id())
|
|
if with_itpay.status in (
|
|
OrderStatus.CANCELLED,
|
|
OrderStatus.REJECTED,
|
|
OrderStatus.ERROR,
|
|
):
|
|
await self._unit_of_work.order_repository.update_after_itpay_failure(with_itpay)
|
|
else:
|
|
await self._unit_of_work.order_repository.update_after_itpay_payment_created(with_itpay)
|
|
return with_itpay
|
|
|