feat: add full pay path
This commit is contained in:
130
src/infrastructure/cloud_kassir/client.py
Normal file
130
src/infrastructure/cloud_kassir/client.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
from ulid import ULID
|
||||
import aiohttp
|
||||
from aiohttp import BasicAuth, ClientTimeout
|
||||
from src.application.contracts import IReceipt
|
||||
from src.application.domain.exceptions import ApplicationException
|
||||
|
||||
|
||||
class ClaudeKassirClient(IReceipt):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
public_id: str,
|
||||
api_secret: str,
|
||||
inn: str,
|
||||
api_base_url: str = 'https://api.cloudpayments.ru',
|
||||
success_url: str | None = None,
|
||||
fail_url: str | None = None,
|
||||
timeout_seconds: float = 30,
|
||||
) -> None:
|
||||
self._public_id = public_id
|
||||
self._api_secret = api_secret
|
||||
self._inn = inn
|
||||
self._api_base_url = api_base_url.rstrip('/')
|
||||
self._success_url = success_url
|
||||
self._fail_url = fail_url
|
||||
self._timeout = ClientTimeout(total=timeout_seconds)
|
||||
|
||||
async def create_receipt(
|
||||
self,
|
||||
*,
|
||||
order_id: str,
|
||||
user_id: str,
|
||||
email: str,
|
||||
total_amount: Decimal,
|
||||
principal_amount: Decimal,
|
||||
service_fee: Decimal,
|
||||
phone: str | None = None,
|
||||
customer_inn: str = '',
|
||||
success_url: str | None = None,
|
||||
fail_url: str | None = None,
|
||||
request_id: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
total = total_amount.quantize(Decimal('0.01'))
|
||||
principal = principal_amount.quantize(Decimal('0.01'))
|
||||
fee = service_fee.quantize(Decimal('0.01'))
|
||||
description = f'Исполнение поручения принципала по заявке №{order_id}'
|
||||
fee_description = f'Агентское вознаграждение за исполнение поручения по заявке №{order_id}'
|
||||
payload: dict[str, Any] = {
|
||||
'Inn': self._inn,
|
||||
'Type': 'Income',
|
||||
'InvoiceId': order_id,
|
||||
'AccountId': user_id,
|
||||
'Description': description,
|
||||
'CustomerReceipt': {
|
||||
'Items': [
|
||||
{
|
||||
'label': description,
|
||||
'price': float(principal),
|
||||
'quantity': 1.00,
|
||||
'amount': float(principal),
|
||||
'vat': 0,
|
||||
'method': 4,
|
||||
'object': 4,
|
||||
'measurement_unit': 'шт',
|
||||
'agent_info': {
|
||||
'type': 2,
|
||||
},
|
||||
'supplier_info': {
|
||||
'name': 'Принципал (физическое лицо)',
|
||||
'inn': '',
|
||||
'phones': [],
|
||||
},
|
||||
},
|
||||
{
|
||||
'label': fee_description,
|
||||
'price': float(fee),
|
||||
'quantity': 1.00,
|
||||
'amount': float(fee),
|
||||
'vat': 0,
|
||||
'method': 4,
|
||||
'object': 1,
|
||||
'measurement_unit': 'шт',
|
||||
},
|
||||
],
|
||||
'taxationSystem': 2,
|
||||
'email': email,
|
||||
'phone': phone,
|
||||
'customerInn': customer_inn,
|
||||
'agentSign': 2,
|
||||
'amounts': {
|
||||
'electronic': float(total),
|
||||
'advancePayment': 0.00,
|
||||
'credit': 0.00,
|
||||
'provision': 0.00,
|
||||
},
|
||||
},
|
||||
'Email': email,
|
||||
'SuccessUrl': success_url or self._success_url,
|
||||
'FailUrl': fail_url or self._fail_url,
|
||||
}
|
||||
if phone is None:
|
||||
payload['CustomerReceipt'].pop('phone')
|
||||
if payload['SuccessUrl'] is None:
|
||||
payload.pop('SuccessUrl')
|
||||
if payload['FailUrl'] is None:
|
||||
payload.pop('FailUrl')
|
||||
url = f'{self._api_base_url}/kkt/receipt'
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Request-ID': request_id or str(ULID()),
|
||||
}
|
||||
try:
|
||||
async with aiohttp.ClientSession(timeout=self._timeout) as session:
|
||||
auth = BasicAuth(self._public_id, self._api_secret)
|
||||
async with session.post(url, json=payload, headers=headers, auth=auth) as resp:
|
||||
body = await resp.json(content_type=None)
|
||||
if resp.status >= 400:
|
||||
raise ApplicationException(status_code=502, message='Receipt provider error')
|
||||
if body.get('Success') is False:
|
||||
raise ApplicationException(status_code=409, message=str(body.get('Message') or 'Receipt provider rejected receipt'))
|
||||
return body
|
||||
except ApplicationException:
|
||||
raise
|
||||
except aiohttp.ClientError:
|
||||
raise ApplicationException(status_code=502, message='Receipt provider unreachable')
|
||||
Reference in New Issue
Block a user