feat: add create request
This commit is contained in:
@@ -5,6 +5,10 @@ from src.application.domain.entities.organization import PurchaseRequestEntity
|
||||
|
||||
|
||||
class IPurchaseRequestRepository(ABC):
|
||||
@abstractmethod
|
||||
async def create(self, values: dict[str, Any]) -> PurchaseRequestEntity:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def get_by_id(self, request_id: str) -> PurchaseRequestEntity:
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -21,6 +21,7 @@ from src.application.commands.organization_wallet_commands import (
|
||||
ListOrganizationWalletsCommand,
|
||||
)
|
||||
from src.application.commands.purchase_request_commands import (
|
||||
CreatePurchaseRequestCommand,
|
||||
ListPurchaseRequestsCommand,
|
||||
GetPurchaseRequestCommand,
|
||||
UpdatePurchaseRequestCommand,
|
||||
@@ -40,6 +41,7 @@ __all__ = [
|
||||
'GetOrganizationCommand',
|
||||
'SearchPartiesCommand',
|
||||
'UpdateOrganizationCommand',
|
||||
'CreatePurchaseRequestCommand',
|
||||
'ListPurchaseRequestsCommand',
|
||||
'GetPurchaseRequestCommand',
|
||||
'UpdatePurchaseRequestCommand',
|
||||
|
||||
@@ -54,6 +54,54 @@ class GetPurchaseRequestCommand:
|
||||
return await self._unit_of_work.purchase_request_repository.get_by_id(request_id)
|
||||
|
||||
|
||||
class CreatePurchaseRequestCommand:
|
||||
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
||||
self._unit_of_work = unit_of_work
|
||||
self._logger = logger
|
||||
|
||||
@transactional
|
||||
async def __call__(
|
||||
self,
|
||||
*,
|
||||
organization_id: str,
|
||||
usdt_amount: Decimal,
|
||||
status: str = 'submitted',
|
||||
rub_amount: Decimal | None = None,
|
||||
exchange_rate: Decimal | None = None,
|
||||
service_fee_percent: Decimal | None = None,
|
||||
comment: str | None = None,
|
||||
admin_comment: str | None = None,
|
||||
target_wallet_chain: str | None = 'ETH',
|
||||
target_wallet_address: str | None = None,
|
||||
tx_hash: str | None = None,
|
||||
assigned_to: str | None = None,
|
||||
) -> PurchaseRequestEntity:
|
||||
if status not in VALID_STATUSES:
|
||||
raise ApplicationException(status_code=400, message='Invalid status')
|
||||
|
||||
await self._unit_of_work.legal_entity_repository.get_by_id(organization_id)
|
||||
values: dict[str, Any] = {
|
||||
'organization_id': organization_id,
|
||||
'status': status,
|
||||
'usdt_amount': usdt_amount,
|
||||
'rub_amount': rub_amount,
|
||||
'exchange_rate': exchange_rate,
|
||||
'service_fee_percent': service_fee_percent,
|
||||
'comment': comment,
|
||||
'admin_comment': admin_comment,
|
||||
'target_wallet_chain': target_wallet_chain,
|
||||
'target_wallet_address': target_wallet_address,
|
||||
'tx_hash': tx_hash,
|
||||
'assigned_to': assigned_to,
|
||||
}
|
||||
if status == 'completed':
|
||||
values['completed_at'] = datetime.now(timezone.utc)
|
||||
|
||||
created = await self._unit_of_work.purchase_request_repository.create(values)
|
||||
self._logger.info(f'Purchase request created id={created.id} org={organization_id}')
|
||||
return created
|
||||
|
||||
|
||||
class UpdatePurchaseRequestStatusCommand:
|
||||
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
||||
self._unit_of_work = unit_of_work
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from ulid import ULID
|
||||
from sqlalchemy import func, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
@@ -45,6 +46,16 @@ class PurchaseRequestRepository(IPurchaseRequestRepository):
|
||||
stmt = stmt.where(PurchaseRequestModel.organization_id == organization_id)
|
||||
return stmt
|
||||
|
||||
async def create(self, values: dict[str, Any]) -> PurchaseRequestEntity:
|
||||
model = PurchaseRequestModel(id=str(ULID()), **values)
|
||||
self._session.add(model)
|
||||
try:
|
||||
await self._session.flush()
|
||||
return self._to_entity(model)
|
||||
except SQLAlchemyError as exc:
|
||||
self._logger.exception(str(exc))
|
||||
raise ApplicationException(status_code=500, message='Database error')
|
||||
|
||||
async def get_by_id(self, request_id: str) -> PurchaseRequestEntity:
|
||||
res = await self._session.execute(select(PurchaseRequestModel).where(PurchaseRequestModel.id == request_id))
|
||||
m = res.scalar_one_or_none()
|
||||
|
||||
@@ -7,6 +7,7 @@ from src.application.commands import (
|
||||
AdminLoginCommand,
|
||||
AdminLogoutCommand,
|
||||
AdminJwtRefreshCommand,
|
||||
CreatePurchaseRequestCommand,
|
||||
GetAdminMeCommand,
|
||||
CreateOrganizationCommand,
|
||||
CreateOrganizationWalletsCommand,
|
||||
@@ -173,6 +174,13 @@ def get_list_purchase_requests_command(
|
||||
return ListPurchaseRequestsCommand(uow, logger)
|
||||
|
||||
|
||||
def get_create_purchase_request_command(
|
||||
uow: IUnitOfWork = Depends(get_unit_of_work),
|
||||
logger: ILogger = Depends(get_logger),
|
||||
) -> CreatePurchaseRequestCommand:
|
||||
return CreatePurchaseRequestCommand(uow, logger)
|
||||
|
||||
|
||||
def get_get_purchase_request_command(
|
||||
uow: IUnitOfWork = Depends(get_unit_of_work),
|
||||
logger: ILogger = Depends(get_logger),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from fastapi import APIRouter, Depends, Query, status
|
||||
|
||||
from src.application.commands import (
|
||||
CreatePurchaseRequestCommand,
|
||||
GetPurchaseRequestCommand,
|
||||
ListPurchaseRequestsCommand,
|
||||
SetPurchaseRequestQuoteCommand,
|
||||
@@ -10,6 +11,7 @@ from src.application.commands import (
|
||||
from src.application.domain.dto import AdminAuthContext
|
||||
from src.presentation.decorators.admin_auth import require_admin_access, require_admin_role
|
||||
from src.presentation.dependencies.commands import (
|
||||
get_create_purchase_request_command,
|
||||
get_get_purchase_request_command,
|
||||
get_list_purchase_requests_command,
|
||||
get_set_purchase_request_quote_command,
|
||||
@@ -18,6 +20,7 @@ from src.presentation.dependencies.commands import (
|
||||
)
|
||||
from src.presentation.schemas.mappers import purchase_request_to_response
|
||||
from src.presentation.schemas.organization import (
|
||||
CreatePurchaseRequestBody,
|
||||
PurchaseRequestListResponse,
|
||||
PurchaseRequestResponse,
|
||||
SetPurchaseRequestQuoteBody,
|
||||
@@ -49,6 +52,29 @@ async def list_purchase_requests(
|
||||
)
|
||||
|
||||
|
||||
@purchase_requests_router.post('', response_model=PurchaseRequestResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_purchase_request(
|
||||
body: CreatePurchaseRequestBody,
|
||||
auth: AdminAuthContext = Depends(require_admin_role('compliance', 'superadmin')),
|
||||
command: CreatePurchaseRequestCommand = Depends(get_create_purchase_request_command),
|
||||
):
|
||||
item = await command(
|
||||
organization_id=body.organization_id,
|
||||
usdt_amount=body.usdt_amount,
|
||||
status=body.status,
|
||||
rub_amount=body.rub_amount,
|
||||
exchange_rate=body.exchange_rate,
|
||||
service_fee_percent=body.service_fee_percent,
|
||||
comment=body.comment,
|
||||
admin_comment=body.admin_comment,
|
||||
target_wallet_chain=body.target_wallet_chain,
|
||||
target_wallet_address=body.target_wallet_address,
|
||||
tx_hash=body.tx_hash,
|
||||
assigned_to=body.assigned_to,
|
||||
)
|
||||
return purchase_request_to_response(item)
|
||||
|
||||
|
||||
@purchase_requests_router.get('/{request_id}', response_model=PurchaseRequestResponse)
|
||||
async def get_purchase_request(
|
||||
request_id: str,
|
||||
|
||||
@@ -114,6 +114,21 @@ class DocumentResponse(BaseModel):
|
||||
download_url: str | None = None
|
||||
|
||||
|
||||
class CreatePurchaseRequestBody(BaseModel):
|
||||
organization_id: str
|
||||
usdt_amount: Decimal = Field(gt=0)
|
||||
status: str = 'submitted'
|
||||
rub_amount: Decimal | None = Field(default=None, gt=0)
|
||||
exchange_rate: Decimal | None = Field(default=None, gt=0)
|
||||
service_fee_percent: Decimal | None = Field(default=None, ge=0)
|
||||
comment: str | None = None
|
||||
admin_comment: str | None = None
|
||||
target_wallet_chain: str | None = Field(default='ETH', max_length=16)
|
||||
target_wallet_address: str | None = Field(default=None, max_length=128)
|
||||
tx_hash: str | None = Field(default=None, max_length=128)
|
||||
assigned_to: str | None = None
|
||||
|
||||
|
||||
class UpdatePurchaseRequestStatusBody(BaseModel):
|
||||
status: str
|
||||
admin_comment: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user