94 lines
4.2 KiB
Python
94 lines
4.2 KiB
Python
from __future__ import annotations
|
|
from decimal import Decimal
|
|
from src.application.abstractions import IUnitOfWork
|
|
from src.application.contracts import ILogger,IReceipt
|
|
from src.application.domain.enums import PaymentStatus
|
|
from src.application.domain.exceptions import ApplicationException,NotFoundException,PaymentMetadataException,ReceiptDataException
|
|
from src.infrastructure.database.decorators import transactional
|
|
|
|
|
|
class CreateCryptoTransferCompletedCommand:
|
|
def __init__(self, *, unit_of_work: IUnitOfWork, receipt: IReceipt, logger: ILogger):
|
|
self._unit_of_work = unit_of_work
|
|
self._receipt = receipt
|
|
self._logger = logger
|
|
|
|
|
|
@transactional
|
|
async def __call__(self, *, order_id: str, user_id: str, web3_transaction_hash: str | None = None) -> None:
|
|
if not order_id:
|
|
raise PaymentMetadataException(message='Crypto transfer completed message missing order_id')
|
|
if not user_id:
|
|
raise PaymentMetadataException(message='Crypto transfer completed message missing user_id')
|
|
await self._unit_of_work.payment_repository.update_crypto_transfer_completed(
|
|
order_id=order_id,
|
|
web3_transaction_hash=web3_transaction_hash,
|
|
)
|
|
user = await self._unit_of_work.user_repository.get(user_id)
|
|
if user is None:
|
|
raise NotFoundException(message='User not found')
|
|
email = str(user.email or '').strip()
|
|
if not email:
|
|
raise ReceiptDataException(message='User email missing')
|
|
customer_info = ' '.join(
|
|
part
|
|
for part in (
|
|
str(user.last_name or '').strip(),
|
|
str(user.first_name or '').strip(),
|
|
str(user.middle_name or '').strip(),
|
|
)
|
|
if part
|
|
)
|
|
if not customer_info:
|
|
raise ReceiptDataException(message='User full name missing')
|
|
customer_inn = str(user.inn or '').strip()
|
|
if not customer_inn:
|
|
raise ReceiptDataException(message='User inn missing')
|
|
if user.birth_date is None:
|
|
raise ReceiptDataException(message='User birth date missing')
|
|
customer_birthday = f'{user.birth_date.isoformat()}T12:00:00.000Z'
|
|
|
|
order = await self._unit_of_work.order_repository.get_by_id(order_id)
|
|
if order is None:
|
|
raise NotFoundException(message='Order not found')
|
|
if order.total_price is None:
|
|
raise ReceiptDataException(message='Order total price missing for receipt')
|
|
if order.service_fee is None:
|
|
raise ReceiptDataException(message='Order service fee missing for receipt')
|
|
|
|
total_amount = Decimal(str(order.total_price)).quantize(Decimal('0.01'))
|
|
service_fee = Decimal(str(order.service_fee)).quantize(Decimal('0.01'))
|
|
principal_amount = (total_amount - service_fee).quantize(Decimal('0.01'))
|
|
|
|
if principal_amount < 0:
|
|
raise ReceiptDataException(message='Invalid receipt amounts: principal negative')
|
|
|
|
try:
|
|
receipt_response = await self._receipt.create_receipt(
|
|
order_id=order_id,
|
|
user_id=user_id,
|
|
email=email,
|
|
total_amount=total_amount,
|
|
principal_amount=principal_amount,
|
|
service_fee=service_fee,
|
|
customer_info=customer_info,
|
|
customer_inn=customer_inn,
|
|
customer_birthday=customer_birthday,
|
|
request_id=self._logger.get_trace_id(),
|
|
)
|
|
except ApplicationException as exception:
|
|
self._logger.error({'event':'receipt_create_failed','order_id':order_id,'error':exception.message})
|
|
await self._unit_of_work.payment_repository.update_status(
|
|
order_id=order_id,
|
|
status=PaymentStatus.RECEIPT_ERROR,
|
|
)
|
|
return
|
|
receipt_model = receipt_response.get('Model')
|
|
if not isinstance(receipt_model, dict):
|
|
receipt_model = {}
|
|
await self._unit_of_work.payment_repository.update_receipt(
|
|
order_id=order_id,
|
|
receipt_cloudekassir_id=str(receipt_model.get('Id') or '') or None,
|
|
receipt_cloudekassir_link=str(receipt_model.get('ReceiptLocalUrl') or '') or None,
|
|
)
|