This commit is contained in:
2026-06-03 13:52:45 +03:00
commit f7309c4b4a
140 changed files with 7134 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
from __future__ import annotations
from datetime import datetime, timezone
from decimal import Decimal
from typing import Any
from src.application.abstractions import IUnitOfWork
from src.application.contracts import ILogger
from src.application.domain.entities.organization import PurchaseRequestEntity
from src.application.domain.exceptions import ApplicationException
from src.infrastructure.database.decorators import transactional
VALID_STATUSES = frozenset({
'submitted', 'in_review', 'quote_sent', 'payment_pending',
'payment_received', 'usdt_sent', 'completed', 'rejected', 'cancelled',
})
class ListPurchaseRequestsCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work
self._logger = logger
@transactional
async def __call__(
self,
*,
status: str | None = None,
organization_id: str | None = None,
limit: int = 50,
offset: int = 0,
) -> tuple[list[PurchaseRequestEntity], int]:
items = await self._unit_of_work.purchase_request_repository.list_all(
status=status,
organization_id=organization_id,
limit=limit,
offset=offset,
)
total = await self._unit_of_work.purchase_request_repository.count_all(
status=status,
organization_id=organization_id,
)
return items, total
class GetPurchaseRequestCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work
self._logger = logger
@transactional
async def __call__(self, request_id: str) -> PurchaseRequestEntity:
return await self._unit_of_work.purchase_request_repository.get_by_id(request_id)
class UpdatePurchaseRequestStatusCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work
self._logger = logger
@transactional
async def __call__(
self,
request_id: str,
*,
status: str,
admin_comment: str | None = None,
assigned_to: str | None = None,
tx_hash: str | None = None,
) -> PurchaseRequestEntity:
if status not in VALID_STATUSES:
raise ApplicationException(status_code=400, message='Invalid status')
values: dict[str, Any] = {'status': status}
if admin_comment is not None:
values['admin_comment'] = admin_comment
if assigned_to is not None:
values['assigned_to'] = assigned_to
if tx_hash is not None:
values['tx_hash'] = tx_hash
if status == 'completed':
values['completed_at'] = datetime.now(timezone.utc)
return await self._unit_of_work.purchase_request_repository.update(request_id, values=values)
class SetPurchaseRequestQuoteCommand:
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
self._unit_of_work = unit_of_work
self._logger = logger
@transactional
async def __call__(
self,
request_id: str,
*,
rub_amount: Decimal,
exchange_rate: Decimal,
service_fee_percent: Decimal | None = None,
admin_comment: str | None = None,
) -> PurchaseRequestEntity:
values: dict[str, Any] = {
'rub_amount': rub_amount,
'exchange_rate': exchange_rate,
'status': 'quote_sent',
}
if service_fee_percent is not None:
values['service_fee_percent'] = service_fee_percent
if admin_comment is not None:
values['admin_comment'] = admin_comment
return await self._unit_of_work.purchase_request_repository.update(request_id, values=values)