Files
pay-service/src/infrastructure/database/repositories/sbp_withdrawal_repository.py
2026-07-02 13:13:07 +03:00

141 lines
5.5 KiB
Python

from __future__ import annotations
from dataclasses import replace
from datetime import datetime,timezone
from sqlalchemy import desc,select
from sqlalchemy.ext.asyncio import AsyncSession
from src.application.abstractions.repositories import ISbpWithdrawalRepository
from src.application.contracts import ILogger
from src.application.domain.entities import SbpWithdrawalEntity
from src.application.domain.enums import SbpWithdrawalStatus
from src.infrastructure.database.models.sbp_withdrawal import SbpWithdrawal
class SbpWithdrawalRepository(ISbpWithdrawalRepository):
def __init__(self,session: AsyncSession,logger: ILogger):
self._session=session
self._logger=logger
@staticmethod
def _to_entity(model: SbpWithdrawal) -> SbpWithdrawalEntity:
return SbpWithdrawalEntity(
id=model.id,
created_at=model.created_at,
updated_at=model.updated_at,
user_id=model.user_id,
bank_id=model.bank_id,
bank_name=model.bank_name,
phone=model.phone,
usdt_amount=model.usdt_amount,
rub_amount=model.rub_amount,
usdt_exchange_rate=model.usdt_exchange_rate,
service_fee_rate=model.service_fee_rate,
service_fee_usdt=model.service_fee_usdt,
mozen_order_id=model.mozen_order_id,
trace_id=model.trace_id,
status=model.status,
provider_error=model.provider_error,
usdt_received_at=model.usdt_received_at,
payout_created_at=model.payout_created_at,
payout_completed_at=model.payout_completed_at,
)
async def create(self,withdrawal: SbpWithdrawalEntity) -> SbpWithdrawalEntity:
values={
'user_id':withdrawal.user_id,
'bank_id':withdrawal.bank_id,
'bank_name':withdrawal.bank_name,
'phone':withdrawal.phone,
'usdt_amount':withdrawal.usdt_amount,
'rub_amount':withdrawal.rub_amount,
'usdt_exchange_rate':withdrawal.usdt_exchange_rate,
'service_fee_rate':withdrawal.service_fee_rate,
'service_fee_usdt':withdrawal.service_fee_usdt,
'mozen_order_id':withdrawal.mozen_order_id,
'trace_id':withdrawal.trace_id,
'status':withdrawal.status or SbpWithdrawalStatus.CREATED,
'provider_error':withdrawal.provider_error,
'usdt_received_at':withdrawal.usdt_received_at,
'payout_created_at':withdrawal.payout_created_at,
'payout_completed_at':withdrawal.payout_completed_at,
}
if withdrawal.id is not None:
values['id']=withdrawal.id
model=SbpWithdrawal(**values)
self._session.add(model)
await self._session.flush()
return replace(withdrawal,id=model.id,created_at=model.created_at,updated_at=model.updated_at)
async def get_by_id(self,withdraw_id: str) -> SbpWithdrawalEntity | None:
stmt=select(SbpWithdrawal).where(SbpWithdrawal.id==withdraw_id)
model=await self._session.scalar(stmt)
if model is None:
return None
return self._to_entity(model)
async def get_by_id_for_user(self,*,withdraw_id: str,user_id: str) -> SbpWithdrawalEntity | None:
stmt=select(SbpWithdrawal).where(SbpWithdrawal.id==withdraw_id,SbpWithdrawal.user_id==user_id)
model=await self._session.scalar(stmt)
if model is None:
return None
return self._to_entity(model)
async def list_by_user_id(self,*,user_id: str,limit: int,offset: int,cursor_created_at=None) -> list[SbpWithdrawalEntity]:
stmt=(
select(SbpWithdrawal)
.where(SbpWithdrawal.user_id==user_id)
.order_by(desc(SbpWithdrawal.created_at))
.limit(limit)
)
if cursor_created_at is not None:
stmt=stmt.where(SbpWithdrawal.created_at < cursor_created_at)
else:
stmt=stmt.offset(offset)
result=await self._session.scalars(stmt)
return [self._to_entity(model) for model in result.all()]
async def update_status(
self,
*,
withdraw_id: str,
status: SbpWithdrawalStatus,
provider_error: str | None = None,
) -> None:
model=await self._session.get(SbpWithdrawal,withdraw_id)
if model is None:
return
model.status=status
model.provider_error=provider_error
if status==SbpWithdrawalStatus.USDT_RECEIVED:
model.usdt_received_at=datetime.now(timezone.utc)
if status==SbpWithdrawalStatus.PAYOUT_PROCESSING:
model.payout_created_at=datetime.now(timezone.utc)
if status==SbpWithdrawalStatus.PAYOUT_COMPLETED:
model.payout_completed_at=datetime.now(timezone.utc)
await self._session.flush()
async def update_payout_created(
self,
*,
withdraw_id: str,
mozen_order_id: str | None,
status: SbpWithdrawalStatus,
provider_error: str | None,
) -> None:
model=await self._session.get(SbpWithdrawal,withdraw_id)
if model is None:
return
model.mozen_order_id=mozen_order_id
model.status=status
model.provider_error=provider_error
model.payout_created_at=datetime.now(timezone.utc)
if status==SbpWithdrawalStatus.PAYOUT_COMPLETED:
model.payout_completed_at=datetime.now(timezone.utc)
await self._session.flush()