├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.en.md ├── README.md ├── docs └── examples │ ├── 01-configuration.md │ ├── 02-payments.md │ ├── 03-refunds.md │ ├── 04-receipts.md │ ├── 05-deals.md │ ├── 06-payouts.md │ └── readme.md ├── noxfile.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── src └── yookassa │ ├── __init__.py │ ├── client.py │ ├── configuration.py │ ├── deal.py │ ├── domain │ ├── __init__.py │ ├── common │ │ ├── __init__.py │ │ ├── base_object.py │ │ ├── confirmation_type.py │ │ ├── context.py │ │ ├── data_context.py │ │ ├── http_verb.py │ │ ├── payment_method_type.py │ │ ├── receipt_type.py │ │ ├── request_object.py │ │ ├── response_object.py │ │ ├── security_helper.py │ │ ├── type_factory.py │ │ └── user_agent.py │ ├── exceptions │ │ ├── __init__.py │ │ ├── api_error.py │ │ ├── authorize_error.py │ │ ├── bad_request_error.py │ │ ├── forbidden_error.py │ │ ├── not_found_error.py │ │ ├── response_processing_error.py │ │ ├── too_many_request_error.py │ │ └── unauthorized_error.py │ ├── models │ │ ├── __init__.py │ │ ├── airline.py │ │ ├── amount.py │ │ ├── authorization_details.py │ │ ├── cancellation_details.py │ │ ├── confirmation │ │ │ ├── __init__.py │ │ │ ├── confirmation.py │ │ │ ├── confirmation_class_map.py │ │ │ ├── confirmation_factory.py │ │ │ ├── request │ │ │ │ ├── __init__.py │ │ │ │ ├── confirmation_embedded.py │ │ │ │ ├── confirmation_external.py │ │ │ │ ├── confirmation_mobile_application.py │ │ │ │ ├── confirmation_qr.py │ │ │ │ ├── confirmation_redirect.py │ │ │ │ └── confirmation_request.py │ │ │ └── response │ │ │ │ ├── __init__.py │ │ │ │ ├── confirmation_embedded.py │ │ │ │ ├── confirmation_external.py │ │ │ │ ├── confirmation_mobile_application.py │ │ │ │ ├── confirmation_qr.py │ │ │ │ └── confirmation_redirect.py │ │ ├── currency.py │ │ ├── deal.py │ │ ├── payment_data │ │ │ ├── __init__.py │ │ │ ├── card_type.py │ │ │ ├── payment_data.py │ │ │ ├── payment_data_class_map.py │ │ │ ├── payment_data_factory.py │ │ │ ├── request │ │ │ │ ├── __init__.py │ │ │ │ ├── credit_card.py │ │ │ │ ├── payment_data_alfabank.py │ │ │ │ ├── payment_data_applepay.py │ │ │ │ ├── payment_data_b2b_sberbank.py │ │ │ │ ├── payment_data_bank_card.py │ │ │ │ ├── payment_data_cash.py │ │ │ │ ├── payment_data_google_pay.py │ │ │ │ ├── payment_data_installments.py │ │ │ │ ├── payment_data_mobile_balance.py │ │ │ │ ├── payment_data_qiwi.py │ │ │ │ ├── payment_data_sberbank.py │ │ │ │ ├── payment_data_sbp.py │ │ │ │ ├── payment_data_tinkoff_bank.py │ │ │ │ ├── payment_data_webmoney.py │ │ │ │ ├── payment_data_wechat.py │ │ │ │ └── payment_data_yoomoney_wallet.py │ │ │ └── response │ │ │ │ ├── __init__.py │ │ │ │ ├── credit_card.py │ │ │ │ ├── payment_data_alfabank.py │ │ │ │ ├── payment_data_applepay.py │ │ │ │ ├── payment_data_b2b_sberbank.py │ │ │ │ ├── payment_data_bank_card.py │ │ │ │ ├── payment_data_cash.py │ │ │ │ ├── payment_data_google_pay.py │ │ │ │ ├── payment_data_installments.py │ │ │ │ ├── payment_data_mobile_balance.py │ │ │ │ ├── payment_data_psb.py │ │ │ │ ├── payment_data_qiwi.py │ │ │ │ ├── payment_data_sberbank.py │ │ │ │ ├── payment_data_sbp.py │ │ │ │ ├── payment_data_tinkoff_bank.py │ │ │ │ ├── payment_data_webmoney.py │ │ │ │ ├── payment_data_wechat.py │ │ │ │ └── payment_data_yoomoney_wallet.py │ │ ├── payout.py │ │ ├── payout_data │ │ │ ├── __init__.py │ │ │ ├── payout_destination.py │ │ │ ├── payout_destination_class_map.py │ │ │ ├── payout_destination_factory.py │ │ │ ├── request │ │ │ │ ├── __init__.py │ │ │ │ ├── credit_card.py │ │ │ │ ├── payout_destination_bank_card.py │ │ │ │ └── payout_destination_yoomoney_wallet.py │ │ │ └── response │ │ │ │ ├── __init__.py │ │ │ │ ├── credit_card.py │ │ │ │ ├── payout_destination_bank_card.py │ │ │ │ └── payout_destination_yoomoney_wallet.py │ │ ├── receipt.py │ │ ├── receipt_customer.py │ │ ├── receipt_item.py │ │ ├── receipt_item_supplier.py │ │ ├── recipient.py │ │ ├── refund_source.py │ │ ├── requestor.py │ │ ├── settlement.py │ │ └── transfer.py │ ├── notification │ │ ├── __init__.py │ │ ├── webhook_notification.py │ │ └── webhook_notification_types.py │ ├── request │ │ ├── __init__.py │ │ ├── capture_payment_builder.py │ │ ├── capture_payment_request.py │ │ ├── deal_request.py │ │ ├── deal_request_builder.py │ │ ├── payment_request.py │ │ ├── payment_request_builder.py │ │ ├── payout_request.py │ │ ├── payout_request_builder.py │ │ ├── receipt_item_request.py │ │ ├── receipt_request.py │ │ ├── receipt_request_builder.py │ │ ├── refund_request.py │ │ ├── refund_request_builder.py │ │ └── webhook_request.py │ └── response │ │ ├── __init__.py │ │ ├── deal_list_response.py │ │ ├── deal_response.py │ │ ├── payment_list_response.py │ │ ├── payment_response.py │ │ ├── payout_response.py │ │ ├── receipt_item_response.py │ │ ├── receipt_list_response.py │ │ ├── receipt_response.py │ │ ├── refund_list_response.py │ │ ├── refund_response.py │ │ ├── transfer_response.py │ │ └── webhook_response.py │ ├── payment.py │ ├── payout.py │ ├── receipt.py │ ├── refund.py │ ├── settings.py │ └── webhook.py └── test ├── __init__.py └── unit ├── __init__.py ├── test_airline.py ├── test_amount.py ├── test_any_list_response.py ├── test_base_object.py ├── test_capture_payment_builder.py ├── test_capture_payment_request.py ├── test_client.py ├── test_configuration.py ├── test_confirmation.py ├── test_confirmation_factory.py ├── test_context.py ├── test_credit_card.py ├── test_deal.py ├── test_deal_request.py ├── test_deal_request_builder.py ├── test_deal_response.py ├── test_payment_data.py ├── test_payment_data_factory.py ├── test_payment_facade.py ├── test_payment_request.py ├── test_payment_request_builder.py ├── test_payment_response.py ├── test_payout.py ├── test_payout_request.py ├── test_payout_request_builder.py ├── test_payout_response.py ├── test_receipt.py ├── test_receipt_model.py ├── test_receipt_request.py ├── test_receipt_request_builder.py ├── test_receipt_response.py ├── test_recepient.py ├── test_refund_facade.py ├── test_refund_request.py ├── test_refund_request_builder.py ├── test_refund_response.py ├── test_refund_source.py ├── test_requestor.py ├── test_security_helper.py ├── test_settings.py ├── test_transfer.py ├── test_transfer_response.py ├── test_user_agent.py ├── test_webhook.py └── test_webhook_notification.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Misc 2 | .idea 3 | 4 | # Distribution / packaging 5 | .Python 6 | env/ 7 | build/ 8 | develop-eggs/ 9 | dist/ 10 | downloads/ 11 | eggs/ 12 | .eggs/ 13 | lib/ 14 | lib64/ 15 | parts/ 16 | sdist/ 17 | var/ 18 | wheels/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | .nox/ 23 | 24 | # PyInstaller 25 | # Usually these files are written by a python script from a template 26 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 27 | *.manifest 28 | *.spec 29 | 30 | # Installer logs 31 | pip-log.txt 32 | pip-delete-this-directory.txt 33 | 34 | # Unit test / coverage reports 35 | htmlcov/ 36 | .tox/ 37 | .coverage 38 | .coverage.* 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | *.cover 43 | .hypothesis/ 44 | .pytest_cache/ 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | dist: bionic 3 | python: 4 | - "3.10" 5 | - "3.9" 6 | - "3.8" 7 | - "3.7" 8 | - "3.6" 9 | - "3.5" 10 | matrix: 11 | include: 12 | - python: 3.4 13 | dist: xenial 14 | - python: 2.7 15 | before_install: 16 | - pip install -U mock 17 | - pip install -U pytest 18 | # command to install dependencies 19 | install: 20 | - pip install -r requirements.txt && pip install -e . 21 | # command to run tests 22 | script: 23 | - pytest 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### v2.3.0 от 22.03.2022 2 | * Добавлен метод оплаты через СБП 3 | 4 | ### v2.2.3 от 30.12.2021 5 | * Небольшой рефакторинг 6 | 7 | ### v2.2.2 от 28.12.2021 8 | * Проверка IP для уведомлений 9 | 10 | ### v2.2.1 от 09.12.2021 11 | * Добавлена обработка параметра authorization_details.three_d_secure.applied в объекте платежа 12 | 13 | ### v2.2.0 от 16.11.2021 14 | * Добавлена поддержка Безопасной Сделки 15 | * Удалено поле Payment.requestor 16 | 17 | ### v2.1.5 от 29.10.2021 18 | * Добавлена поддержка Confirmation.mobile_application 19 | 20 | ### v2.1.4 от 19.10.2021 21 | * Добавлена поддержка параметра on_behalf_of для метода /me 22 | 23 | ### v2.1.3 от 10.09.2021 24 | * Добавлена обработка metadata в transfers 25 | 26 | ### v2.1.2 от 04.06.2021 27 | * Поправлена валидация чека 28 | 29 | ### v2.1.1 от 25.05.2021 30 | * Описание ошибки при превышении максимальной длины поля description 31 | 32 | ### v2.1.0 от 21.04.2021 33 | * Добавлены примеры работы с SDK 34 | 35 | ### v2.0.1 от 03.12.2020 36 | * Поправлен setup 37 | 38 | ### v2.0.0 от 03.12.2020 39 | * Обновленная версия SDK 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2020 "YooMoney", NBСO LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /docs/examples/06-payouts.md: -------------------------------------------------------------------------------- 1 | ## Работа с выплатами 2 | 3 | SDK позволяет создавать, подтверждать, отменять выплаты, а также получать информацию о них. 4 | 5 | Объект выплаты `PayoutResponse` содержит всю информацию о выплате, актуальную на текущий момент времени. 6 | Он формируется при создании выплаты и приходит в ответ на любой запрос, связанный с выплатами. 7 | 8 | * [Запрос на создание выплаты](#Запрос-на-создание-выплаты) 9 | * [Запрос на создание выплаты через билдер](#Запрос-на-создание-выплаты-через-билдер) 10 | * [Получить информацию о выплате](#Получить-информацию-о-выплате) 11 | 12 | --- 13 | 14 | ### Запрос на создание выплаты 15 | 16 | [Создание выплаты в документации](https://yookassa.ru/developers/api?lang=python#create_payout) 17 | 18 | Чтобы принять оплату, необходимо создать объект выплаты — `PayoutRequest`. Он содержит всю необходимую информацию 19 | для проведения оплаты (сумму, валюту и статус). У выплаты линейный жизненный цикл, 20 | он последовательно переходит из статуса в статус. 21 | 22 | В ответ на запрос придет объект выплаты - `PayoutResponse` в актуальном статусе. 23 | 24 | ```python 25 | import var_dump as var_dump 26 | from yookassa import Payout 27 | from yookassa.domain.common import PaymentMethodType 28 | from yookassa.domain.models.currency import Currency 29 | 30 | res = Payout.create({ 31 | "amount": {"value": 320.0, "currency": Currency.RUB}, 32 | "payout_destination_data": {'type': PaymentMethodType.YOO_MONEY, 'account_number': '41001614575714'}, 33 | "description": "Выплата по заказу №37", 34 | "metadata": { 35 | "order_id": "37" 36 | }, 37 | "deal": { 38 | "id": "dl-285e5ee7-0022-5000-8000-01516a44b147" 39 | } 40 | }) 41 | 42 | var_dump.var_dump(res) 43 | ``` 44 | --- 45 | 46 | ### Запрос на создание выплаты через билдер 47 | 48 | [Создание выплаты в документации](https://yookassa.ru/developers/api?lang=python#create_payout) 49 | 50 | Билдер позволяет создать объект выплаты — `PayoutRequest` программным способом, через объекты. 51 | 52 | ```python 53 | import var_dump as var_dump 54 | from yookassa import Payout 55 | from yookassa.domain.models.currency import Currency 56 | from yookassa.domain.request import PayoutRequestBuilder 57 | 58 | builder = PayoutRequestBuilder() 59 | builder.set_amount({'value': 0.1, 'currency': Currency.RUB}) \ 60 | .set_description('Выплата по заказу №77') \ 61 | .set_payout_token('99091209012') \ 62 | .set_metadata({'order_id': '77'}) \ 63 | .set_deal({ 64 | 'id': 'dl-285e5ee7-0022-5000-8000-01516a44b147' 65 | }) 66 | 67 | request = builder.build() 68 | # Можно что-то поменять, если нужно 69 | request.description = 'Выплата по заказу №77' 70 | res = Payout.create(request) 71 | 72 | var_dump.var_dump(res) 73 | ``` 74 | --- 75 | 76 | ### Получить информацию о выплате 77 | 78 | [Информация о выплате в документации](https://yookassa.ru/developers/api?lang=python#get_payout) 79 | 80 | Запрос позволяет получить информацию о текущем состоянии выплаты по его уникальному идентификатору. 81 | 82 | В ответ на запрос придет объект выплаты в актуальном статусе. 83 | 84 | ```python 85 | import var_dump as var_dump 86 | from yookassa import Payout 87 | 88 | res = Payout.find_one('po-21b23b5b-000f-5061-a000-0674e49a8c10') 89 | 90 | var_dump.var_dump(res) 91 | ``` 92 | -------------------------------------------------------------------------------- /docs/examples/readme.md: -------------------------------------------------------------------------------- 1 | ## Примеры использования SDK 2 | 3 | #### [Настройки SDK API ЮKassa](01-configuration.md) 4 | * [Аутентификация](01-configuration.md#Аутентификация) 5 | * [Статистические данные об используемом окружении](01-configuration.md#Статистические-данные-об-используемом-окружении) 6 | * [Получение информации о магазине](01-configuration.md#Получение-информации-о-магазине) 7 | * [Работа с Webhook](01-configuration.md#Работа-с-Webhook) 8 | * [Входящие уведомления](01-configuration.md#Входящие-уведомления) 9 | 10 | #### [Работа с платежами](02-payments.md) 11 | * [Запрос на создание платежа](02-payments.md#Запрос-на-создание-платежа) 12 | * [Запрос на создание платежа через билдер](02-payments.md#Запрос-на-создание-платежа-через-билдер) 13 | * [Запрос на частичное подтверждение платежа](02-payments.md#Запрос-на-частичное-подтверждение-платежа) 14 | * [Запрос на отмену незавершенного платежа](02-payments.md#Запрос-на-отмену-незавершенного-платежа) 15 | * [Получить информацию о платеже](02-payments.md#Получить-информацию-о-платеже) 16 | * [Получить список платежей с фильтрацией](02-payments.md#Получить-список-платежей-с-фильтрацией) 17 | 18 | #### [Работа с возвратами](03-refunds.md) 19 | * [Запрос на создание возврата](03-refunds.md#Запрос-на-создание-возврата) 20 | * [Запрос на создание возврата через билдер](03-refunds.md#Запрос-на-создание-возврата-через-билдер) 21 | * [Получить информацию о возврате](03-refunds.md#Получить-информацию-о-возврате) 22 | * [Получить список возвратов с фильтрацией](03-refunds.md#Получить-список-возвратов-с-фильтрацией) 23 | 24 | #### [Работа с чеками](04-receipts.md) 25 | * [Запрос на создание чека](04-receipts.md#Запрос-на-создание-чека) 26 | * [Запрос на создание чека через билдер](04-receipts.md#Запрос-на-создание-чека-через-билдер) 27 | * [Получить информацию о чеке](04-receipts.md#Получить-информацию-о-чеке) 28 | * [Получить список чеков с фильтрацией](04-receipts.md#Получить-список-чеков-с-фильтрацией) 29 | 30 | #### [Работа со сделками](05-deals.md) 31 | * [Запрос на создание сделки](05-deals.md#Запрос-на-создание-сделки) 32 | * [Запрос на создание сделки через билдер](05-deals.md#Запрос-на-создание-сделки-через-билдер) 33 | * [Получить информацию о сделке](05-deals.md#Получить-информацию-о-сделке) 34 | * [Получить список сделок с фильтрацией](05-deals.md#Получить-список-сделок-с-фильтрацией) 35 | 36 | #### [Работа с выплатами](06-payouts.md) 37 | * [Запрос на создание выплаты](06-payouts.md#Запрос-на-создание-выплаты) 38 | * [Запрос на создание выплаты через билдер](06-payouts.md#Запрос-на-создание-выплаты-через-билдер) 39 | * [Получить информацию о выплате](06-payouts.md#Получить-информацию-о-выплате) 40 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | import nox # type: ignore 2 | from pathlib import Path 3 | 4 | nox.options.sessions = ["tests"] # , "lint", "build" 5 | 6 | python = ["3.8", "3.9", "3.10"] # "2.7", "3.5", "3.6", "3.7", 7 | 8 | 9 | lint_dependencies = [ 10 | "-e", 11 | ".", 12 | "black", 13 | "flake8", 14 | "flake8-bugbear", 15 | "mypy", 16 | "check-manifest", 17 | ] 18 | 19 | 20 | @nox.session(python=python) 21 | def tests(session): 22 | version = session.python 23 | if version == "2.7": 24 | session.install("mock") 25 | 26 | session.install("-e", ".", "pytest", "pytest-cov") 27 | tests = session.posargs or ["test/unit"] 28 | session.run( 29 | "pytest", 30 | "--cov=yookassa", 31 | "--cov-config", 32 | ".coveragerc", 33 | "--cov-report=", 34 | *tests 35 | ) 36 | session.notify("cover") 37 | 38 | 39 | @nox.session 40 | def cover(session): 41 | """Coverage analysis""" 42 | session.install("coverage") 43 | session.run("coverage", "report", "--show-missing", "--fail-under=0") 44 | session.run("coverage", "erase") 45 | 46 | 47 | @nox.session(python="3.7") 48 | def lint(session): 49 | session.install(*lint_dependencies) 50 | files = ["test/unit"] + [str(p) for p in Path(".").glob("*.py")] 51 | session.run("black", "--check", *files) 52 | session.run("flake8", *files) 53 | session.run("mypy", *files) 54 | session.run("python", "setup.py", "check", "--metadata", "--strict") 55 | if "--skip_manifest_check" in session.posargs: 56 | pass 57 | else: 58 | session.run("check-manifest") 59 | 60 | 61 | @nox.session(python="3.7") 62 | def build(session): 63 | session.install("setuptools") 64 | session.install("wheel") 65 | session.install("twine") 66 | session.run("rm", "-rf", "dist", "build", external=True) 67 | session.run("python", "setup.py", "--quiet", "sdist", "bdist_wheel") 68 | 69 | 70 | @nox.session(python="3.7") 71 | def publish(session): 72 | build(session) 73 | print("REMINDER: Has the changelog been updated?") 74 | session.run("python", "-m", "twine", "upload", "dist/*") 75 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | setuptools 3 | urllib3 4 | netaddr 5 | distro 6 | deprecated 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | 4 | [metadata] 5 | license_files = LICENSE 6 | -------------------------------------------------------------------------------- /src/yookassa/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | 4 | from yookassa.configuration import Configuration 5 | from yookassa.deal import Deal 6 | from yookassa.payment import Payment 7 | from yookassa.payout import Payout 8 | from yookassa.receipt import Receipt 9 | from yookassa.refund import Refund 10 | from yookassa.settings import Settings 11 | from yookassa.webhook import Webhook 12 | 13 | __author__ = "YooMoney" 14 | __email__ = 'cms@yoomoney.ru' 15 | __version__ = '2.3.0' 16 | -------------------------------------------------------------------------------- /src/yookassa/configuration.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.user_agent import Version 3 | 4 | 5 | class ConfigurationError(Exception): 6 | pass 7 | 8 | 9 | class Configuration(object): 10 | """ 11 | A class representing the configuration. 12 | """ 13 | api_url = "https://api.yookassa.ru/v3" 14 | account_id = None 15 | secret_key = None 16 | timeout = 1800 17 | max_attempts = 3 18 | auth_token = None 19 | agent_framework = None 20 | agent_cms = None 21 | agent_module = None 22 | 23 | def __init__(self, **kwargs): 24 | self.assert_has_api_credentials() 25 | 26 | @staticmethod 27 | def configure(account_id, secret_key, **kwargs): 28 | Configuration.account_id = account_id 29 | Configuration.secret_key = secret_key 30 | Configuration.auth_token = None 31 | Configuration.timeout = kwargs.get("timeout", 1800) 32 | Configuration.max_attempts = kwargs.get("max_attempts", 3) 33 | 34 | @staticmethod 35 | def configure_auth_token(token, **kwargs): 36 | Configuration.account_id = None 37 | Configuration.secret_key = None 38 | Configuration.auth_token = token 39 | Configuration.timeout = kwargs.get("timeout", 1800) 40 | Configuration.max_attempts = kwargs.get("max_attempts", 3) 41 | 42 | @staticmethod 43 | def configure_user_agent(framework=None, cms=None, module=None): 44 | if isinstance(framework, Version): 45 | Configuration.agent_framework = framework 46 | if isinstance(cms, Version): 47 | Configuration.agent_cms = cms 48 | if isinstance(module, Version): 49 | Configuration.agent_module = module 50 | 51 | @staticmethod 52 | def instantiate(): 53 | return Configuration( 54 | shop_id=Configuration.account_id, 55 | shop_password=Configuration.secret_key, 56 | timeout=Configuration.timeout, 57 | max_attempts=Configuration.max_attempts, 58 | auth_token=Configuration.auth_token, 59 | agent_framework=Configuration.agent_framework, 60 | agent_cms=Configuration.agent_cms, 61 | agent_module=Configuration.agent_module 62 | ) 63 | 64 | @staticmethod 65 | def api_endpoint(): 66 | return Configuration.api_url 67 | 68 | def has_api_credentials(self): 69 | return self.account_id is not None and self.secret_key is not None 70 | 71 | def assert_has_api_credentials(self): 72 | if self.auth_token is None and not self.has_api_credentials(): 73 | raise ConfigurationError("account_id and secret_key are required") 74 | elif self.auth_token and self.has_api_credentials(): 75 | raise ConfigurationError("Could not configure authorization with auth_token and basic auth") 76 | -------------------------------------------------------------------------------- /src/yookassa/deal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import uuid 3 | 4 | from yookassa.client import ApiClient 5 | from yookassa.domain.common.http_verb import HttpVerb 6 | from yookassa.domain.request import DealRequest 7 | from yookassa.domain.response import DealResponse, DealListResponse 8 | 9 | 10 | class Deal: 11 | base_path = '/deals' 12 | 13 | def __init__(self): 14 | self.client = ApiClient() 15 | 16 | @classmethod 17 | def find_one(cls, deal_id): 18 | """ 19 | Get receipt information 20 | 21 | :param deal_id: 22 | :return: DealResponse 23 | """ 24 | instance = cls() 25 | if not isinstance(deal_id, str) or not deal_id: 26 | raise ValueError('Invalid payment_id value') 27 | 28 | path = instance.base_path + '/' + deal_id 29 | response = instance.client.request(HttpVerb.GET, path) 30 | return DealResponse(response) 31 | 32 | @classmethod 33 | def create(cls, params, idempotency_key=None): 34 | """ 35 | Create receipt 36 | 37 | :param params: data passed to API 38 | :param idempotency_key: 39 | :return: DealResponse 40 | """ 41 | instance = cls() 42 | path = cls.base_path 43 | 44 | if not idempotency_key: 45 | idempotency_key = uuid.uuid4() 46 | 47 | headers = { 48 | 'Idempotence-Key': str(idempotency_key) 49 | } 50 | 51 | if isinstance(params, dict): 52 | params_object = DealRequest(params) 53 | elif isinstance(params, DealRequest): 54 | params_object = params 55 | else: 56 | raise TypeError('Invalid params value type') 57 | 58 | response = instance.client.request(HttpVerb.POST, path, None, headers, params_object) 59 | return DealResponse(response) 60 | 61 | @classmethod 62 | def list(cls, params): 63 | instance = cls() 64 | path = cls.base_path 65 | 66 | response = instance.client.request(HttpVerb.GET, path, params) 67 | return DealListResponse(response) 68 | -------------------------------------------------------------------------------- /src/yookassa/domain/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | 4 | from yookassa.domain.common.base_object import BaseObject 5 | from yookassa.domain.common.confirmation_type import ConfirmationType 6 | from yookassa.domain.common.context import Context 7 | from yookassa.domain.common.data_context import DataContext 8 | from yookassa.domain.common.http_verb import HttpVerb 9 | from yookassa.domain.common.payment_method_type import PaymentMethodType 10 | from yookassa.domain.common.receipt_type import ReceiptType, ReceiptItemAgentType 11 | from yookassa.domain.common.request_object import RequestObject 12 | from yookassa.domain.common.response_object import ResponseObject 13 | from yookassa.domain.common.type_factory import TypeFactory 14 | from yookassa.domain.common.user_agent import UserAgent, Version 15 | from yookassa.domain.common.security_helper import SecurityHelper 16 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/base_object.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | from decimal import Decimal 4 | 5 | 6 | class BaseObject(object): 7 | """ 8 | Base class for data objects. 9 | A class provides cast to dictionary functionality and set up attributes from dictionary. 10 | """ 11 | 12 | def __init__(self, *args, **kwargs): 13 | for dictionary in args: 14 | for key in dictionary: 15 | setattr(self, key, dictionary[key]) 16 | for key in kwargs: 17 | setattr(self, key, kwargs[key]) 18 | 19 | def __iter__(self): 20 | property_names = [prop for prop in dir(self.__class__) if isinstance(getattr(self.__class__, prop), property)] 21 | properties = dict((value, getattr(self, value)) for value in property_names if getattr(self, value) is not None) 22 | for prop_name, prop_value in properties.items(): 23 | if isinstance(prop_value, BaseObject): 24 | yield prop_name, dict(prop_value) 25 | elif isinstance(prop_value, list): 26 | list_value = [] 27 | for value in prop_value: 28 | if isinstance(value, BaseObject): 29 | list_value.append(dict(value)) 30 | else: 31 | list_value.append(value) 32 | yield prop_name, list_value 33 | elif isinstance(prop_value, Decimal): 34 | yield prop_name, str(prop_value) 35 | else: 36 | yield prop_name, prop_value 37 | 38 | def json(self): 39 | return json.dumps(dict(self), default=str, ensure_ascii=False) 40 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/confirmation_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class ConfirmationType: 5 | """ 6 | Constants representing confirmation types. Available values are: 7 | 8 | * yookassa.domain.common.ConfirmationType.EXTERNAL 9 | * yookassa.domain.common.ConfirmationType.REDIRECT 10 | * yookassa.domain.common.ConfirmationType.EMBEDDED 11 | * yookassa.domain.common.ConfirmationType.QR 12 | * yookassa.domain.common.ConfirmationType.MOBILE_APPLICATION 13 | """ 14 | EMBEDDED = 'embedded' 15 | EXTERNAL = 'external' 16 | REDIRECT = 'redirect' 17 | QR = 'qr' 18 | MOBILE_APPLICATION = 'mobile_application' 19 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/context.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class Context(object): 5 | """ 6 | Base context class. 7 | """ 8 | def __init__(self, contexts): 9 | self.__contexts = contexts 10 | 11 | def get_context_data(self, context): 12 | """ 13 | Return context data 14 | :param context: mixed 15 | :return: mixed 16 | """ 17 | if context in self.__contexts: 18 | return getattr(self, context) 19 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/data_context.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.context import Context 3 | 4 | 5 | class DataContext(Context): 6 | """ 7 | Constants representing context data types. Available values are: 8 | 9 | * yookassa.domain.common.DataContext.REQUEST 10 | * yookassa.domain.common.DataContext.RESPONSE 11 | """ 12 | REQUEST = 'request' 13 | RESPONSE = 'response' 14 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/http_verb.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class HttpVerb(object): 5 | """ 6 | Constants representing http method verbs. Available values are: 7 | 8 | * yookassa.domain.common.HttpVerb.GET 9 | * yookassa.domain.common.HttpVerb.POST 10 | * yookassa.domain.common.HttpVerb.PUT 11 | * yookassa.domain.common.HttpVerb.PATCH 12 | * yookassa.domain.common.HttpVerb.HEAD 13 | * yookassa.domain.common.HttpVerb.OPTIONS 14 | * yookassa.domain.common.HttpVerb.DELETE 15 | """ 16 | GET = 'get' 17 | POST = 'post' 18 | PUT = 'put' 19 | PATCH = 'patch' 20 | HEAD = 'head' 21 | OPTIONS = 'options' 22 | DELETE = 'delete' 23 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/payment_method_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class PaymentMethodType: 5 | """ 6 | Constants representing payment_method_data values. Available values are: 7 | 8 | * yookassa.domain.common.PaymentMethodType.YOO_MONEY 9 | * yookassa.domain.common.PaymentMethodType.BANK_CARD 10 | * yookassa.domain.common.PaymentMethodType.SBERBANK 11 | * yookassa.domain.common.PaymentMethodType.CASH 12 | * yookassa.domain.common.PaymentMethodType.MOBILE_BALANCE 13 | * yookassa.domain.common.PaymentMethodType.PSB 14 | * yookassa.domain.common.PaymentMethodType.QIWI 15 | * yookassa.domain.common.PaymentMethodType.WEBMONEY 16 | * yookassa.domain.common.PaymentMethodType.ALFABANK 17 | * yookassa.domain.common.PaymentMethodType.APPLEPAY 18 | * yookassa.domain.common.PaymentMethodType.GOOGLE_PAY 19 | * yookassa.domain.common.PaymentMethodType.INSTALMENTS 20 | * yookassa.domain.common.PaymentMethodType.B2B_SBERBANK 21 | * yookassa.domain.common.PaymentMethodType.TINKOFF_BANK 22 | * yookassa.domain.common.PaymentMethodType.WECHAT 23 | * yookassa.domain.common.PaymentMethodType.SBP 24 | """ 25 | YOO_MONEY = 'yoo_money' 26 | BANK_CARD = 'bank_card' 27 | SBERBANK = 'sberbank' 28 | CASH = 'cash' 29 | MOBILE_BALANCE = 'mobile_balance' 30 | PSB = 'psb' 31 | QIWI = 'qiwi' 32 | WEBMONEY = 'webmoney' 33 | ALFABANK = 'alfabank' 34 | APPLEPAY = 'apple_pay' 35 | GOOGLE_PAY = 'google_pay' 36 | INSTALMENTS = 'installments' 37 | B2B_SBERBANK = 'b2b_sberbank' 38 | TINKOFF_BANK = 'tinkoff_bank' 39 | WECHAT = 'wechat' 40 | SBP = 'sbp' 41 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/receipt_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class ReceiptType: 5 | """ 6 | Constants representing receipt types. Available values are: 7 | """ 8 | PAYMENT = 'payment' 9 | REFUND = 'refund' 10 | 11 | 12 | class ReceiptItemAgentType: 13 | """ 14 | Constants representing receipt item agent types. Available values are: 15 | """ 16 | BANKING_PAYMENT_AGENT = 'banking_payment_agent' 17 | BANKING_PAYMENT_SUBAGENT = 'banking_payment_subagent' 18 | PAYMENT_AGENT = 'payment_agent' 19 | PAYMENT_SUBAGENT = 'payment_subagent' 20 | ATTORNEY = 'attorney' 21 | COMMISSIONER = 'commissioner' 22 | AGENT = 'agent' 23 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/request_object.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from yookassa.domain.common import BaseObject 4 | from yookassa.domain.common.data_context import DataContext 5 | 6 | 7 | class RequestObject(BaseObject): 8 | """ 9 | Base class for request objects 10 | """ 11 | @staticmethod 12 | def context(): 13 | return DataContext.REQUEST 14 | 15 | def validate(self): 16 | """ 17 | Validate request data 18 | """ 19 | pass 20 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/response_object.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.common.data_context import DataContext 4 | 5 | 6 | class ResponseObject(BaseObject): 7 | """ 8 | Base class for request objects 9 | """ 10 | @staticmethod 11 | def context(): 12 | return DataContext.RESPONSE 13 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/security_helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from netaddr import IPNetwork, IPAddress 3 | 4 | 5 | class SecurityHelper: 6 | """ 7 | """ 8 | 9 | def __init__(self): 10 | pass 11 | 12 | YOOKASSA_NETWORKS = [ 13 | '77.75.153.0/25', 14 | '77.75.156.11', 15 | '77.75.156.35', 16 | '77.75.154.128/25', 17 | '185.71.76.0/27', 18 | '185.71.77.0/27', 19 | '2a02:5180:0:1509::/64', 20 | '2a02:5180:0:2655::/64', 21 | '2a02:5180:0:1533::/64', 22 | '2a02:5180:0:2669::/64' 23 | ] 24 | 25 | @staticmethod 26 | def is_ip_in_network(ip, network): 27 | return IPAddress(ip) in IPNetwork(network) 28 | 29 | def is_ip_trusted(self, ip): 30 | return any(map(lambda net: self.is_ip_in_network(ip, net), self.YOOKASSA_NETWORKS)) 31 | -------------------------------------------------------------------------------- /src/yookassa/domain/common/type_factory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.context import Context 3 | 4 | 5 | class TypeFactory(object): 6 | """ 7 | Base factory class for object that has type property. 8 | """ 9 | def __init__(self, context): 10 | if isinstance(context, Context): 11 | self.__context = context 12 | else: 13 | TypeError('Parameter context should be Context instance') 14 | 15 | def create(self, data, context): 16 | """ 17 | Create instance from value and context 18 | 19 | :param data: dictionary that has type key 20 | :param context: data context 21 | :return: Typed object instance 22 | """ 23 | if isinstance(data, dict) and 'type' in data: 24 | return self.__get_instance(data, context) 25 | 26 | def __get_instance(self, data, context): 27 | class_object = self.__get_class_object(data, context) 28 | return class_object(data) 29 | 30 | def __get_class_object(self, data, context): 31 | class_object = self.__class_map(context).get(data['type']) 32 | return class_object 33 | 34 | def __class_map(self, context): 35 | return self.__context.get_context_data(context) 36 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | 4 | from yookassa.domain.exceptions.api_error import ApiError 5 | from yookassa.domain.exceptions.authorize_error import AuthorizeError 6 | from yookassa.domain.exceptions.bad_request_error import BadRequestError 7 | from yookassa.domain.exceptions.forbidden_error import ForbiddenError 8 | from yookassa.domain.exceptions.not_found_error import NotFoundError 9 | from yookassa.domain.exceptions.response_processing_error import ResponseProcessingError 10 | from yookassa.domain.exceptions.too_many_request_error import TooManyRequestsError 11 | from yookassa.domain.exceptions.unauthorized_error import UnauthorizedError 12 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/api_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class ApiError(Exception): 5 | pass 6 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/authorize_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class AuthorizeError(ApiError): 6 | pass 7 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/bad_request_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class BadRequestError(ApiError): 6 | HTTP_CODE = 400 7 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/forbidden_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class ForbiddenError(ApiError): 6 | HTTP_CODE = 403 7 | 8 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/not_found_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class NotFoundError(ApiError): 6 | HTTP_CODE = 404 7 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/response_processing_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class ResponseProcessingError(ApiError): 6 | HTTP_CODE = 202 7 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/too_many_request_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class TooManyRequestsError(ApiError): 6 | HTTP_CODE = 429 7 | -------------------------------------------------------------------------------- /src/yookassa/domain/exceptions/unauthorized_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.exceptions.api_error import ApiError 3 | 4 | 5 | class UnauthorizedError(ApiError): 6 | HTTP_CODE = 401 7 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/__init__.py: -------------------------------------------------------------------------------- 1 | from yookassa.domain.models.airline import Airline, Passenger, Leg 2 | from yookassa.domain.models.amount import Amount 3 | from yookassa.domain.models.authorization_details import AuthorizationDetails 4 | from yookassa.domain.models.cancellation_details import CancellationDetails, CancellationDetailsPartyCode, \ 5 | CancellationDetailsReasonCode, PayoutCancellationDetailsReasonCode 6 | from yookassa.domain.models.currency import Currency 7 | from yookassa.domain.models.receipt import Receipt, ReceiptCustomer, ReceiptItem 8 | from yookassa.domain.models.receipt_item_supplier import ReceiptItemSupplier 9 | from yookassa.domain.models.recipient import Recipient 10 | from yookassa.domain.models.refund_source import RefundSource 11 | from yookassa.domain.models.requestor import Requestor, RequestorType, RequestorMerchant, RequestorFactory, \ 12 | RequestorThirdPartyClient 13 | from yookassa.domain.models.settlement import Settlement, SettlementType, SettlementPayoutType 14 | from yookassa.domain.models.transfer import Transfer 15 | from yookassa.domain.models.deal import DealStatus, DealType, FeeMoment, PaymentDealInfo, PayoutDealInfo, \ 16 | RefundDealInfo, RefundDealData 17 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/amount.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from decimal import Decimal, ROUND_HALF_UP 3 | 4 | from yookassa.domain.common import BaseObject 5 | 6 | 7 | class Amount(BaseObject): 8 | """ 9 | Class representing amount data wrapper object 10 | """ 11 | __value = None 12 | 13 | __currency = None 14 | 15 | @property 16 | def value(self): 17 | """ 18 | :return Decimal: 19 | """ 20 | return self.__value 21 | 22 | @value.setter 23 | def value(self, value): 24 | self.__value = Decimal(str(float(value))).quantize(Decimal('1.11'), rounding=ROUND_HALF_UP) 25 | 26 | @property 27 | def currency(self): 28 | return self.__currency 29 | 30 | @currency.setter 31 | def currency(self, value): 32 | self.__currency = str(value) 33 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/authorization_details.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | 4 | 5 | class AuthorizationDetails(BaseObject): 6 | """ 7 | Class representing authorization details data wrapper object 8 | """ 9 | __rrn = None 10 | 11 | __auth_code = None 12 | 13 | __three_d_secure = None 14 | 15 | @property 16 | def rrn(self): 17 | return self.__rrn 18 | 19 | @rrn.setter 20 | def rrn(self, value): 21 | self.__rrn = str(value) 22 | 23 | @property 24 | def auth_code(self): 25 | return self.__auth_code 26 | 27 | @auth_code.setter 28 | def auth_code(self, value): 29 | self.__auth_code = str(value) 30 | 31 | @property 32 | def three_d_secure(self): 33 | return self.__three_d_secure 34 | 35 | @three_d_secure.setter 36 | def three_d_secure(self, value): 37 | if isinstance(value, dict): 38 | self.__three_d_secure = ThreeDSecure(value) 39 | elif isinstance(value, ThreeDSecure): 40 | self.__three_d_secure = value 41 | else: 42 | raise TypeError('Invalid three_d_secure value type') 43 | 44 | 45 | class ThreeDSecure(BaseObject): 46 | """ 47 | Class representing 3‑D Secure user authentication details data wrapper object 48 | """ 49 | __applied = None 50 | 51 | @property 52 | def applied(self): 53 | return self.__applied 54 | 55 | @applied.setter 56 | def applied(self, value): 57 | self.__applied = bool(value) 58 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/cancellation_details.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | 4 | 5 | class CancellationDetails(BaseObject): 6 | """ 7 | Class representing cancellation details data wrapper object 8 | """ 9 | __party = None 10 | 11 | __reason = None 12 | 13 | @property 14 | def party(self): 15 | return self.__party 16 | 17 | @party.setter 18 | def party(self, value): 19 | self.__party = str(value) 20 | 21 | @property 22 | def reason(self): 23 | return self.__reason 24 | 25 | @reason.setter 26 | def reason(self, value): 27 | self.__reason = str(value) 28 | 29 | 30 | class CancellationDetailsPartyCode(object): 31 | MERCHANT = 'merchant' 32 | YOO_KASSA = 'yoo_kassa' 33 | PAYMENT_NETWORK = 'payment_network' 34 | 35 | 36 | class CancellationDetailsReasonCode(object): 37 | THREE_D_SECURE_FAILED = '3d_secure_failed' 38 | CALL_ISSUER = 'call_issuer' 39 | CARD_EXPIRED = 'card_expired' 40 | COUNTRY_FORBIDDEN = 'country_forbidden' 41 | FRAUD_SUSPECTED = 'fraud_suspected' 42 | GENERAL_DECLINE = 'general_decline' 43 | IDENTIFICATION_REQUIRED = 'identification_required' 44 | INSUFFICIENT_FUNDS = 'insufficient_funds' 45 | INVALID_CARD_NUMBER = 'invalid_card_number' 46 | INVALID_CSC = 'invalid_csc' 47 | ISSUER_UNAVAILABLE = 'issuer_unavailable' 48 | PAYMENT_METHOD_LIMIT_EXCEEDED = 'payment_method_limit_exceeded' 49 | PAYMENT_METHOD_RESTRICTED = 'payment_method_restricted' 50 | PERMISSION_REVOKED = 'permission_revoked' 51 | INTERNAL_TIMEOUT = 'internal_timeout' 52 | CANCELED_BY_MERCHANT = 'canceled_by_merchant' 53 | PAYMENT_EXPIRED = 'payment_expired' 54 | EXPIRED_ON_CONFIRMATION = 'expired_on_confirmation' 55 | EXPIRED_ON_CAPTURE = 'expired_on_capture' 56 | 57 | 58 | class PayoutCancellationDetailsReasonCode(object): 59 | FRAUD_SUSPECTED = 'fraud_suspected' 60 | GENERAL_DECLINE = 'general_decline' 61 | ONE_TIME_LIMIT_EXCEEDED = 'one_time_limit_exceeded' 62 | PERIODIC_LIMIT_EXCEEDED = 'periodic_limit_exceeded' 63 | REJECTED_BY_PAYEE = 'rejected_by_payee' 64 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/confirmation/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/confirmation.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | 4 | 5 | class Confirmation(BaseObject): 6 | """ 7 | Base class confirmation data objects 8 | """ 9 | __type = None 10 | 11 | @property 12 | def type(self): 13 | return self.__type 14 | 15 | @type.setter 16 | def type(self, value): 17 | self.__type = str(value) 18 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/confirmation_class_map.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.common.data_context import DataContext 4 | from yookassa.domain.models.confirmation.request.confirmation_embedded import \ 5 | ConfirmationEmbedded as RequestConfirmationEmbedded 6 | from yookassa.domain.models.confirmation.request.confirmation_external import \ 7 | ConfirmationExternal as RequestConfirmationExternal 8 | from yookassa.domain.models.confirmation.request.confirmation_qr import \ 9 | ConfirmationQr as RequestConfirmationQr 10 | from yookassa.domain.models.confirmation.request.confirmation_redirect import \ 11 | ConfirmationRedirect as RequestConfirmationRedirect 12 | from yookassa.domain.models.confirmation.request.confirmation_mobile_application import \ 13 | ConfirmationMobileApplication as RequestConfirmationMobileApplication 14 | from yookassa.domain.models.confirmation.response.confirmation_embedded import \ 15 | ConfirmationEmbedded as ResponseConfirmationEmbedded 16 | from yookassa.domain.models.confirmation.response.confirmation_external import \ 17 | ConfirmationExternal as ResponseConfirmationExternal 18 | from yookassa.domain.models.confirmation.response.confirmation_qr import \ 19 | ConfirmationQr as ResponseConfirmationQr 20 | from yookassa.domain.models.confirmation.response.confirmation_redirect import \ 21 | ConfirmationRedirect as ResponseConfirmationRedirect 22 | from yookassa.domain.models.confirmation.response.confirmation_mobile_application import \ 23 | ConfirmationMobileApplication as ResponseConfirmationMobileApplication 24 | 25 | 26 | class ConfirmationClassMap(DataContext): 27 | def __init__(self): 28 | super(ConfirmationClassMap, self).__init__(('request', 'response')) 29 | 30 | @property 31 | def request(self): 32 | return { 33 | ConfirmationType.REDIRECT: RequestConfirmationRedirect, 34 | ConfirmationType.EXTERNAL: RequestConfirmationExternal, 35 | ConfirmationType.EMBEDDED: RequestConfirmationEmbedded, 36 | ConfirmationType.QR: RequestConfirmationQr, 37 | ConfirmationType.MOBILE_APPLICATION: RequestConfirmationMobileApplication 38 | } 39 | 40 | @property 41 | def response(self): 42 | return { 43 | ConfirmationType.REDIRECT: ResponseConfirmationRedirect, 44 | ConfirmationType.EXTERNAL: ResponseConfirmationExternal, 45 | ConfirmationType.EMBEDDED: ResponseConfirmationEmbedded, 46 | ConfirmationType.QR: ResponseConfirmationQr, 47 | ConfirmationType.MOBILE_APPLICATION: ResponseConfirmationMobileApplication 48 | } 49 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/confirmation_factory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.type_factory import TypeFactory 3 | from yookassa.domain.models.confirmation.confirmation_class_map import ConfirmationClassMap 4 | 5 | 6 | class ConfirmationFactory(TypeFactory): 7 | def __init__(self): 8 | super(ConfirmationFactory, self).__init__(ConfirmationClassMap()) 9 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/confirmation/request/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/confirmation_embedded.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.request.confirmation_request import ConfirmationRequest 4 | 5 | 6 | class ConfirmationEmbedded(ConfirmationRequest): 7 | """ 8 | Class representing embedded confirmation data object 9 | """ 10 | def __init__(self, *args, **kwargs): 11 | super(ConfirmationEmbedded, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not ConfirmationType.EMBEDDED: 13 | self.type = ConfirmationType.EMBEDDED 14 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/confirmation_external.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.request.confirmation_request import ConfirmationRequest 4 | 5 | 6 | class ConfirmationExternal(ConfirmationRequest): 7 | """ 8 | Class representing external confirmation data object 9 | """ 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(ConfirmationExternal, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not ConfirmationType.EXTERNAL: 14 | self.type = ConfirmationType.EXTERNAL 15 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/confirmation_mobile_application.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.request.confirmation_request import ConfirmationRequest 4 | 5 | 6 | class ConfirmationMobileApplication(ConfirmationRequest): 7 | """ 8 | Class representing mobile_application confirmation data object 9 | """ 10 | __return_url = None 11 | 12 | def __init__(self, *args, **kwargs): 13 | super(ConfirmationMobileApplication, self).__init__(*args, **kwargs) 14 | if self.type is None or self.type is not ConfirmationType.MOBILE_APPLICATION: 15 | self.type = ConfirmationType.MOBILE_APPLICATION 16 | 17 | @property 18 | def return_url(self): 19 | return self.__return_url 20 | 21 | @return_url.setter 22 | def return_url(self, value): 23 | cast_value = str(value) 24 | if cast_value: 25 | self.__return_url = cast_value 26 | else: 27 | raise ValueError('Invalid returnUrl value') 28 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/confirmation_qr.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.request.confirmation_request import ConfirmationRequest 4 | 5 | 6 | class ConfirmationQr(ConfirmationRequest): 7 | """ 8 | Class representing qr confirmation data object 9 | """ 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(ConfirmationQr, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not ConfirmationType.QR: 14 | self.type = ConfirmationType.QR 15 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/confirmation_redirect.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.request.confirmation_request import ConfirmationRequest 4 | 5 | 6 | class ConfirmationRedirect(ConfirmationRequest): 7 | """ 8 | Class representing redirect confirmation data object 9 | """ 10 | __return_url = None 11 | 12 | __enforce = None 13 | 14 | def __init__(self, *args, **kwargs): 15 | super(ConfirmationRedirect, self).__init__(*args, **kwargs) 16 | if self.type is None or self.type is not ConfirmationType.REDIRECT: 17 | self.type = ConfirmationType.REDIRECT 18 | 19 | @property 20 | def return_url(self): 21 | return self.__return_url 22 | 23 | @return_url.setter 24 | def return_url(self, value): 25 | cast_value = str(value) 26 | if cast_value: 27 | self.__return_url = cast_value 28 | else: 29 | raise ValueError('Invalid returnUrl value') 30 | 31 | @property 32 | def enforce(self): 33 | return self.__enforce 34 | 35 | @enforce.setter 36 | def enforce(self, value): 37 | self.__enforce = bool(value) 38 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/request/confirmation_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.models.confirmation.confirmation import Confirmation 3 | 4 | 5 | class ConfirmationRequest(Confirmation): 6 | """ 7 | Base class confirmation request data objects 8 | """ 9 | __locale = None 10 | 11 | @property 12 | def locale(self): 13 | return self.__locale 14 | 15 | @locale.setter 16 | def locale(self, value): 17 | self.__locale = str(value) 18 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/response/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/confirmation/response/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/response/confirmation_embedded.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.confirmation import Confirmation 4 | 5 | 6 | class ConfirmationEmbedded(Confirmation): 7 | """ 8 | Class representing embedded confirmation data object 9 | """ 10 | __confirmation_token = None 11 | 12 | def __init__(self, *args, **kwargs): 13 | super(ConfirmationEmbedded, self).__init__(*args, **kwargs) 14 | if self.type is None or self.type is not ConfirmationType.EMBEDDED: 15 | self.type = ConfirmationType.EMBEDDED 16 | 17 | @property 18 | def confirmation_token(self): 19 | return self.__confirmation_token 20 | 21 | @confirmation_token.setter 22 | def confirmation_token(self, value): 23 | cast_value = str(value) 24 | if cast_value: 25 | self.__confirmation_token = cast_value 26 | else: 27 | raise ValueError('Invalid confirmation_token value') 28 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/response/confirmation_external.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.confirmation import Confirmation 4 | 5 | 6 | class ConfirmationExternal(Confirmation): 7 | """ 8 | Class representing external confirmation data object 9 | """ 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(ConfirmationExternal, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not ConfirmationType.EXTERNAL: 14 | self.type = ConfirmationType.EXTERNAL 15 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/response/confirmation_mobile_application.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.confirmation import Confirmation 4 | 5 | 6 | class ConfirmationMobileApplication(Confirmation): 7 | """ 8 | Class representing mobile_application confirmation data object 9 | """ 10 | __confirmation_url = None 11 | 12 | def __init__(self, *args, **kwargs): 13 | super(ConfirmationMobileApplication, self).__init__(*args, **kwargs) 14 | if self.type is None or self.type is not ConfirmationType.MOBILE_APPLICATION: 15 | self.type = ConfirmationType.MOBILE_APPLICATION 16 | 17 | @property 18 | def confirmation_url(self): 19 | return self.__confirmation_url 20 | 21 | @confirmation_url.setter 22 | def confirmation_url(self, value): 23 | self.__confirmation_url = value 24 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/response/confirmation_qr.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.confirmation import Confirmation 4 | 5 | 6 | class ConfirmationQr(Confirmation): 7 | """ 8 | Class representing qr confirmation data object 9 | """ 10 | __confirmation_data = None 11 | 12 | def __init__(self, *args, **kwargs): 13 | super(ConfirmationQr, self).__init__(*args, **kwargs) 14 | if self.type is None or self.type is not ConfirmationType.QR: 15 | self.type = ConfirmationType.QR 16 | 17 | @property 18 | def confirmation_data(self): 19 | return self.__confirmation_data 20 | 21 | @confirmation_data.setter 22 | def confirmation_data(self, value): 23 | cast_value = str(value) 24 | if cast_value: 25 | self.__confirmation_data = cast_value 26 | else: 27 | raise ValueError('Invalid confirmation_data value') 28 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/confirmation/response/confirmation_redirect.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.confirmation_type import ConfirmationType 3 | from yookassa.domain.models.confirmation.confirmation import Confirmation 4 | 5 | 6 | class ConfirmationRedirect(Confirmation): 7 | """ 8 | Class representing redirect confirmation data object 9 | """ 10 | __return_url = None 11 | 12 | __enforce = None 13 | 14 | __confirmation_url = None 15 | 16 | def __init__(self, *args, **kwargs): 17 | super(ConfirmationRedirect, self).__init__(*args, **kwargs) 18 | if self.type is None or self.type is not ConfirmationType.REDIRECT: 19 | self.type = ConfirmationType.REDIRECT 20 | 21 | @property 22 | def return_url(self): 23 | return self.__return_url 24 | 25 | @return_url.setter 26 | def return_url(self, value): 27 | cast_value = str(value) 28 | if cast_value: 29 | self.__return_url = cast_value 30 | else: 31 | raise ValueError('Invalid returnUrl value') 32 | 33 | @property 34 | def enforce(self): 35 | return self.__enforce 36 | 37 | @enforce.setter 38 | def enforce(self, value): 39 | self.__enforce = bool(value) 40 | 41 | @property 42 | def confirmation_url(self): 43 | return self.__confirmation_url 44 | 45 | @confirmation_url.setter 46 | def confirmation_url(self, value): 47 | self.__confirmation_url = value 48 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/currency.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class Currency(object): 5 | """ 6 | Class representing currency enum 7 | """ 8 | RUB = "RUB" 9 | USD = "USD" 10 | EUR = "EUR" 11 | BYN = "BYN" 12 | CNY = "CNY" 13 | KZT = "KZT" 14 | UAH = "UAH" 15 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/payment_data/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/card_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class CardType: 5 | """ 6 | Class representing credit cards available types enum 7 | """ 8 | MASTER_CARD = 'MasterCard' 9 | VISA = 'Visa' 10 | MIR = 'MIR' 11 | UNION_PAY = 'UnionPay' 12 | CUP = 'CUP' 13 | JCB = 'JCB' 14 | AMERICAN_EXPRESS = 'AmericanExpress' 15 | DINERS_CLUB = 'DinersClub' 16 | UNKNOWN = 'Unknown' 17 | 18 | 19 | class CardSource: 20 | """ 21 | Class representing enum of available sources of credit cards 22 | """ 23 | APPLE_PAY = 'apple_pay' 24 | GOOGLE_PAY = 'google_pay' 25 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/payment_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | 4 | 5 | class PaymentData(BaseObject): 6 | """ 7 | Base class for Payment data objects 8 | """ 9 | __type = None 10 | 11 | @property 12 | def type(self): 13 | return self.__type 14 | 15 | @type.setter 16 | def type(self, value): 17 | self.__type = str(value) 18 | 19 | 20 | class ResponsePaymentData(PaymentData): 21 | __id = None 22 | 23 | __saved = None 24 | 25 | __title = None 26 | 27 | @property 28 | def id(self): 29 | return self.__id 30 | 31 | @id.setter 32 | def id(self, value): 33 | self.__id = str(value) 34 | 35 | @property 36 | def saved(self): 37 | return self.__saved 38 | 39 | @saved.setter 40 | def saved(self, value): 41 | self.__saved = bool(value) 42 | 43 | @property 44 | def title(self): 45 | return self.__title 46 | 47 | @title.setter 48 | def title(self, value): 49 | self.__title = str(value) 50 | 51 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/payment_data_factory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.type_factory import TypeFactory 3 | from yookassa.domain.models.payment_data.payment_data_class_map import PaymentDataClassMap 4 | 5 | 6 | class PaymentDataFactory(TypeFactory): 7 | """ 8 | Factory for payment data objects 9 | """ 10 | 11 | def __init__(self): 12 | super(PaymentDataFactory, self).__init__(PaymentDataClassMap()) 13 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/payment_data/request/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/credit_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common import BaseObject 5 | 6 | 7 | class CreditCard(BaseObject): 8 | __number = None 9 | 10 | __expiry_year = None 11 | 12 | __expiry_month = None 13 | 14 | __csc = None 15 | 16 | __cardholder = None 17 | 18 | @property 19 | def number(self): 20 | return self.__number 21 | 22 | @number.setter 23 | def number(self, value): 24 | cast_value = str(value) 25 | if re.match(r'^[0-9]{12,19}$', cast_value): 26 | self.__number = cast_value 27 | else: 28 | raise ValueError('Invalid card number value') 29 | 30 | @property 31 | def expiry_year(self): 32 | return self.__expiry_year 33 | 34 | @expiry_year.setter 35 | def expiry_year(self, value): 36 | cast_value = str(value) 37 | if re.match(r'^\d\d\d\d$', cast_value) and 2000 < int(cast_value) < 2200: 38 | self.__expiry_year = cast_value 39 | else: 40 | raise ValueError('Invalid card expiry year value') 41 | 42 | @property 43 | def expiry_month(self): 44 | return self.__expiry_month 45 | 46 | @expiry_month.setter 47 | def expiry_month(self, value): 48 | cast_value = str(value) 49 | if re.match(r'^\d\d$', cast_value) and 0 < int(cast_value) <= 12: 50 | self.__expiry_month = cast_value 51 | else: 52 | raise ValueError('Invalid card expiry month value') 53 | 54 | @property 55 | def csc(self): 56 | return self.__csc 57 | 58 | @csc.setter 59 | def csc(self, value): 60 | cast_value = str(value) 61 | if re.match(r'^\d{3,4}$', cast_value): 62 | self.__csc = cast_value 63 | else: 64 | raise ValueError('Invalid card CSC code value') 65 | 66 | @property 67 | def cardholder(self): 68 | return self.__cardholder 69 | 70 | @cardholder.setter 71 | def cardholder(self, value): 72 | cast_value = str(value) 73 | if re.match(r'^[a-zA-Z\s]{1,26}$', cast_value): 74 | self.__cardholder = cast_value 75 | else: 76 | raise ValueError('Invalid card holder value') 77 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_alfabank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataAlfabank(PaymentData): 7 | __login = None 8 | 9 | def __init__(self, *args, **kwargs): 10 | super(PaymentDataAlfabank, self).__init__(*args, **kwargs) 11 | if self.type is None or self.type is not PaymentMethodType.ALFABANK: 12 | self.type = PaymentMethodType.ALFABANK 13 | 14 | @property 15 | def login(self): 16 | return self.__login 17 | 18 | @login.setter 19 | def login(self, value): 20 | self.__login = str(value) 21 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_applepay.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataApplepay(PaymentData): 7 | __payment_data = None 8 | 9 | def __init__(self, *args, **kwargs): 10 | super(PaymentDataApplepay, self).__init__(*args, **kwargs) 11 | if self.type is None or self.type is not PaymentMethodType.APPLEPAY: 12 | self.type = PaymentMethodType.APPLEPAY 13 | 14 | @property 15 | def payment_data(self): 16 | return self.__payment_data 17 | 18 | @payment_data.setter 19 | def payment_data(self, value): 20 | self.__payment_data = str(value) 21 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_b2b_sberbank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.common.payment_method_type import PaymentMethodType 4 | from yookassa.domain.models.amount import Amount 5 | from yookassa.domain.models.payment_data.payment_data import PaymentData 6 | 7 | 8 | class PaymentDataB2bSberbank(PaymentData): 9 | __payment_purpose = None 10 | 11 | __vat_data = None 12 | 13 | def __init__(self, *args, **kwargs): 14 | super(PaymentDataB2bSberbank, self).__init__(*args, **kwargs) 15 | if self.type is None or self.type is not PaymentMethodType.B2B_SBERBANK: 16 | self.type = PaymentMethodType.B2B_SBERBANK 17 | 18 | @property 19 | def payment_purpose(self): 20 | return self.__payment_purpose 21 | 22 | @payment_purpose.setter 23 | def payment_purpose(self, value): 24 | self.__payment_purpose = str(value) 25 | 26 | @property 27 | def vat_data(self): 28 | return self.__vat_data 29 | 30 | @vat_data.setter 31 | def vat_data(self, value): 32 | if isinstance(value, dict): 33 | self.__vat_data = VatData(value) 34 | elif isinstance(value, VatData): 35 | self.__vat_data = value 36 | else: 37 | raise TypeError('Invalid vat_data value type') 38 | 39 | 40 | class VatData(BaseObject): 41 | __type = None 42 | 43 | __rate = None 44 | 45 | __amount = None 46 | 47 | @property 48 | def type(self): 49 | return self.__type 50 | 51 | @type.setter 52 | def type(self, value): 53 | if value in VatDataType.__dict__.values(): 54 | self.__type = str(value) 55 | else: 56 | raise ValueError('Invalid type value') 57 | 58 | @property 59 | def rate(self): 60 | return self.__rate 61 | 62 | @rate.setter 63 | def rate(self, value): 64 | if value in VatDataRate.__dict__.values(): 65 | self.__rate = int(value) 66 | else: 67 | raise ValueError('Invalid rate value') 68 | 69 | @property 70 | def amount(self): 71 | return self.__amount 72 | 73 | @amount.setter 74 | def amount(self, value): 75 | if isinstance(value, dict): 76 | self.__amount = Amount(value) 77 | elif isinstance(value, Amount): 78 | self.__amount = value 79 | else: 80 | raise TypeError('Invalid amount value type') 81 | 82 | 83 | class VatDataType: 84 | CALCULATED = 'calculated' 85 | MIXED = 'mixed' 86 | UNTAXED = 'untaxed' 87 | 88 | 89 | class VatDataRate: 90 | """ 91 | Class representing rates available types enum 92 | """ 93 | RATE_7 = 7 94 | RATE_10 = 10 95 | RATE_18 = 18 96 | RATE_20 = 20 97 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_bank_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | from yookassa.domain.models.payment_data.request.credit_card import CreditCard 5 | 6 | 7 | class PaymentDataBankCard(PaymentData): 8 | __card = None 9 | 10 | def __init__(self, *args, **kwargs): 11 | super(PaymentDataBankCard, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not PaymentMethodType.BANK_CARD: 13 | self.type = PaymentMethodType.BANK_CARD 14 | 15 | @property 16 | def card(self): 17 | return self.__card 18 | 19 | @card.setter 20 | def card(self, value): 21 | if isinstance(value, dict): 22 | self.__card = CreditCard(value) 23 | elif isinstance(value, CreditCard): 24 | self.__card = value 25 | else: 26 | raise TypeError('Invalid card value type in PaymentDataBankCard') 27 | 28 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_cash.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import PaymentData 6 | 7 | 8 | class PaymentDataCash(PaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataCash, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.CASH: 14 | self.type = PaymentMethodType.CASH 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_google_pay.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataGooglePay(PaymentData): 7 | __payment_method_token = None 8 | 9 | __google_transaction_id = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataGooglePay, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.GOOGLE_PAY: 14 | self.type = PaymentMethodType.GOOGLE_PAY 15 | 16 | @property 17 | def payment_method_token(self): 18 | return self.__payment_method_token 19 | 20 | @payment_method_token.setter 21 | def payment_method_token(self, value): 22 | self.__payment_method_token = str(value) 23 | 24 | @property 25 | def google_transaction_id(self): 26 | return self.__google_transaction_id 27 | 28 | @google_transaction_id.setter 29 | def google_transaction_id(self, value): 30 | self.__google_transaction_id = str(value) 31 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_installments.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataInstallments(PaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataInstallments, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.INSTALMENTS: 10 | self.type = PaymentMethodType.INSTALMENTS 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_mobile_balance.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import PaymentData 6 | 7 | 8 | class PaymentDataMobileBalance(PaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataMobileBalance, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.MOBILE_BALANCE: 14 | self.type = PaymentMethodType.MOBILE_BALANCE 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_qiwi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import PaymentData 6 | 7 | 8 | class PaymentDataQiwi(PaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataQiwi, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.QIWI: 14 | self.type = PaymentMethodType.QIWI 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_sberbank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import PaymentData 6 | 7 | 8 | class PaymentDataSberbank(PaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataSberbank, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.SBERBANK: 14 | self.type = PaymentMethodType.SBERBANK 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_sbp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataSbp(PaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataSbp, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.SBP: 10 | self.type = PaymentMethodType.SBP 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_tinkoff_bank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataTinkoffBank(PaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataTinkoffBank, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.TINKOFF_BANK: 10 | self.type = PaymentMethodType.TINKOFF_BANK 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_webmoney.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataWebmoney(PaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataWebmoney, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.WEBMONEY: 10 | self.type = PaymentMethodType.WEBMONEY 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_wechat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from deprecated import deprecated 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import PaymentData 6 | 7 | 8 | @deprecated("This class will be removed in one of future versions") 9 | class PaymentDataWechat(PaymentData): 10 | def __init__(self, *args, **kwargs): 11 | super(PaymentDataWechat, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not PaymentMethodType.WECHAT: 13 | self.type = PaymentMethodType.WECHAT 14 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/request/payment_data_yoomoney_wallet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import PaymentData 4 | 5 | 6 | class PaymentDataYooMoneyWallet(PaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataYooMoneyWallet, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.YOO_MONEY: 10 | self.type = PaymentMethodType.YOO_MONEY 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/payment_data/response/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/credit_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common import BaseObject 5 | 6 | 7 | class CreditCard(BaseObject): 8 | # Первые 6 цифр номера карты (BIN). 9 | __first6 = None 10 | # Последние 4 цифры номера карты. 11 | __last4 = None 12 | # Срок действия, год, YYYY. 13 | __expiry_year = None 14 | # Срок действия, месяц, MM. 15 | __expiry_month = None 16 | # Тип банковской карты. Возможные значения: 17 | # ~`MasterCard` (для карт Mastercard и Maestro), ~`Visa` (для карт Visa и Visa Electron), 18 | # ~`Mir`, ~`UnionPay`, ~`JCB`, ~`AmericanExpress`, ~`DinersClub` и ~`Unknown`. 19 | __card_type = None 20 | # Код страны, в которой выпущена карта. 21 | # Передается в формате [ISO-3166 alpha-2](https://www.iso.org/obp/ui/#iso:pub:PUB500001:en). 22 | # Пример: RU. 23 | __issuer_country = None 24 | # Наименование банка, выпустившего карту. 25 | __issuer_name = None 26 | # Источник данных банковской карты. 27 | # Возможные значения: ~`apple_pay`, ~`google_pay`. 28 | # Присутствует, если пользователь при оплате выбрал карту, сохраненную в Apple Pay или Google Pay. 29 | __source = None 30 | 31 | @property 32 | def first6(self): 33 | return self.__first6 34 | 35 | @first6.setter 36 | def first6(self, value): 37 | cast_value = str(value) 38 | if re.match('^[0-9]{6}$', cast_value): 39 | self.__first6 = cast_value 40 | else: 41 | raise ValueError('Invalid first6 value') 42 | 43 | @property 44 | def last4(self): 45 | return self.__last4 46 | 47 | @last4.setter 48 | def last4(self, value): 49 | cast_value = str(value) 50 | if re.match(r'^[\d]{4}$', cast_value): 51 | self.__last4 = cast_value 52 | else: 53 | raise ValueError('Invalid last4 value') 54 | 55 | @property 56 | def expiry_year(self): 57 | return self.__expiry_year 58 | 59 | @expiry_year.setter 60 | def expiry_year(self, value): 61 | cast_value = str(value) 62 | if re.match(r'^\d\d\d\d$', cast_value) and 2000 < int(cast_value) < 2200: 63 | self.__expiry_year = cast_value 64 | else: 65 | raise ValueError('Invalid card expiry year value') 66 | 67 | @property 68 | def expiry_month(self): 69 | return self.__expiry_month 70 | 71 | @expiry_month.setter 72 | def expiry_month(self, value): 73 | cast_value = str(value) 74 | if re.match(r'^\d\d$', cast_value) and 0 < int(cast_value) <= 12: 75 | self.__expiry_month = cast_value 76 | else: 77 | raise ValueError('Invalid card expiry month value') 78 | 79 | @property 80 | def card_type(self): 81 | return self.__card_type 82 | 83 | @card_type.setter 84 | def card_type(self, value): 85 | self.__card_type = value 86 | 87 | @property 88 | def issuer_country(self): 89 | return self.__issuer_country 90 | 91 | @issuer_country.setter 92 | def issuer_country(self, value): 93 | cast_value = str(value) 94 | if len(cast_value) == 2: 95 | self.__issuer_country = cast_value 96 | else: 97 | raise ValueError('Invalid card issuer country value') 98 | 99 | @property 100 | def issuer_name(self): 101 | return self.__issuer_name 102 | 103 | @issuer_name.setter 104 | def issuer_name(self, value): 105 | self.__issuer_name = str(value) 106 | 107 | @property 108 | def source(self): 109 | return self.__source 110 | 111 | @source.setter 112 | def source(self, value): 113 | self.__source = str(value) 114 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_alfabank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataAlfabank(ResponsePaymentData): 7 | __login = None 8 | 9 | def __init__(self, *args, **kwargs): 10 | super(PaymentDataAlfabank, self).__init__(*args, **kwargs) 11 | if self.type is None or self.type is not PaymentMethodType.ALFABANK: 12 | self.type = PaymentMethodType.ALFABANK 13 | 14 | @property 15 | def login(self): 16 | return self.__login 17 | 18 | @login.setter 19 | def login(self, value): 20 | self.__login = str(value) 21 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_applepay.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataApplepay(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataApplepay, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.APPLEPAY: 10 | self.type = PaymentMethodType.APPLEPAY 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_bank_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | from yookassa.domain.models.payment_data.response.credit_card import CreditCard 5 | 6 | 7 | class PaymentDataBankCard(ResponsePaymentData): 8 | __card = None 9 | 10 | def __init__(self, *args, **kwargs): 11 | super(PaymentDataBankCard, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not PaymentMethodType.BANK_CARD: 13 | self.type = PaymentMethodType.BANK_CARD 14 | 15 | @property 16 | def card(self): 17 | return self.__card 18 | 19 | @card.setter 20 | def card(self, value): 21 | if isinstance(value, dict): 22 | self.__card = CreditCard(value) 23 | elif isinstance(value, CreditCard): 24 | self.__card = value 25 | else: 26 | raise TypeError('Invalid card value type in PaymentDataBankCard') 27 | 28 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_cash.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 6 | 7 | 8 | class PaymentDataCash(ResponsePaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataCash, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.CASH: 14 | self.type = PaymentMethodType.CASH 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_google_pay.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataGooglePay(ResponsePaymentData): 7 | 8 | def __init__(self, *args, **kwargs): 9 | super(PaymentDataGooglePay, self).__init__(*args, **kwargs) 10 | if self.type is None or self.type is not PaymentMethodType.GOOGLE_PAY: 11 | self.type = PaymentMethodType.GOOGLE_PAY 12 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_installments.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataInstallments(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataInstallments, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.INSTALMENTS: 10 | self.type = PaymentMethodType.INSTALMENTS 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_mobile_balance.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 6 | 7 | 8 | class PaymentDataMobileBalance(ResponsePaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataMobileBalance, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.MOBILE_BALANCE: 14 | self.type = PaymentMethodType.MOBILE_BALANCE 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_psb.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataPsb(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataPsb, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.PSB: 10 | self.type = PaymentMethodType.PSB 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_qiwi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 6 | 7 | 8 | class PaymentDataQiwi(ResponsePaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataQiwi, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.QIWI: 14 | self.type = PaymentMethodType.QIWI 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_sberbank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 6 | 7 | 8 | class PaymentDataSberbank(ResponsePaymentData): 9 | __phone = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PaymentDataSberbank, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.SBERBANK: 14 | self.type = PaymentMethodType.SBERBANK 15 | 16 | @property 17 | def phone(self): 18 | return self.__phone 19 | 20 | @phone.setter 21 | def phone(self, value): 22 | cast_value = str(value) 23 | if re.match('^[0-9]{4,15}$', cast_value): 24 | self.__phone = cast_value 25 | else: 26 | raise ValueError('Invalid phone value type') 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_sbp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataSbp(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataSbp, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.SBP: 10 | self.type = PaymentMethodType.SBP 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_tinkoff_bank.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataTinkoffBank(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataTinkoffBank, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.TINKOFF_BANK: 10 | self.type = PaymentMethodType.TINKOFF_BANK 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_webmoney.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataWebmoney(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataWebmoney, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.WEBMONEY: 10 | self.type = PaymentMethodType.WEBMONEY 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_wechat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from deprecated import deprecated 3 | 4 | from yookassa.domain.common.payment_method_type import PaymentMethodType 5 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 6 | 7 | 8 | @deprecated("This class will be removed in one of future versions") 9 | class PaymentDataWechat(ResponsePaymentData): 10 | def __init__(self, *args, **kwargs): 11 | super(PaymentDataWechat, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not PaymentMethodType.WECHAT: 13 | self.type = PaymentMethodType.WECHAT 14 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payment_data/response/payment_data_yoomoney_wallet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payment_data.payment_data import ResponsePaymentData 4 | 5 | 6 | class PaymentDataYooMoneyWallet(ResponsePaymentData): 7 | def __init__(self, *args, **kwargs): 8 | super(PaymentDataYooMoneyWallet, self).__init__(*args, **kwargs) 9 | if self.type is None or self.type is not PaymentMethodType.YOO_MONEY: 10 | self.type = PaymentMethodType.YOO_MONEY 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class PayoutStatus: 5 | """ 6 | Constants representing payout statuses. Available values are: 7 | """ 8 | PENDING = 'pending' 9 | SUCCEEDED = 'succeeded' 10 | CANCELED = 'canceled' 11 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/payout_data/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/payout_destination.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | 4 | 5 | class PayoutDestination(BaseObject): 6 | """ 7 | Base class for PayoutDestination objects 8 | """ 9 | __type = None 10 | 11 | @property 12 | def type(self): 13 | return self.__type 14 | 15 | @type.setter 16 | def type(self, value): 17 | self.__type = str(value) 18 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/payout_destination_class_map.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.data_context import DataContext 3 | from yookassa.domain.common.payment_method_type import PaymentMethodType 4 | from yookassa.domain.models.payout_data.request.payout_destination_bank_card import \ 5 | PayoutDestinationBankCard as RequestPayoutDestinationBankCard 6 | from yookassa.domain.models.payout_data.request.payout_destination_yoomoney_wallet import \ 7 | PayoutDestinationYooMoneyWallet as RequestPayoutDestinationYooMoneyWallet 8 | from yookassa.domain.models.payout_data.response.payout_destination_bank_card import \ 9 | PayoutDestinationBankCard as ResponsePayoutDestinationBankCard 10 | from yookassa.domain.models.payout_data.response.payout_destination_yoomoney_wallet import \ 11 | PayoutDestinationYooMoneyWallet as ResponsePayoutDestinationYooMoneyWallet 12 | 13 | 14 | class PayoutDestinationClassMap(DataContext): 15 | def __init__(self): 16 | super(PayoutDestinationClassMap, self).__init__(('request', 'response')) 17 | 18 | @property 19 | def request(self): 20 | return { 21 | PaymentMethodType.BANK_CARD: RequestPayoutDestinationBankCard, 22 | PaymentMethodType.YOO_MONEY: RequestPayoutDestinationYooMoneyWallet, 23 | } 24 | 25 | @property 26 | def response(self): 27 | return { 28 | PaymentMethodType.BANK_CARD: ResponsePayoutDestinationBankCard, 29 | PaymentMethodType.YOO_MONEY: ResponsePayoutDestinationYooMoneyWallet, 30 | } 31 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/payout_destination_factory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.type_factory import TypeFactory 3 | from yookassa.domain.models.payout_data.payout_destination_class_map import PayoutDestinationClassMap 4 | 5 | 6 | class PayoutDestinationFactory(TypeFactory): 7 | """ 8 | Factory for payment data objects 9 | """ 10 | 11 | def __init__(self): 12 | super(PayoutDestinationFactory, self).__init__(PayoutDestinationClassMap()) 13 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/request/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/payout_data/request/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/request/credit_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common import BaseObject 5 | 6 | 7 | class CreditCard(BaseObject): 8 | 9 | __number = None 10 | 11 | @property 12 | def number(self): 13 | return self.__number 14 | 15 | @number.setter 16 | def number(self, value): 17 | cast_value = str(value) 18 | if re.match(r'^[0-9]{12,19}$', cast_value): 19 | self.__number = cast_value 20 | else: 21 | raise ValueError('Invalid card number value') 22 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/request/payout_destination_bank_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payout_data.payout_destination import PayoutDestination 4 | from yookassa.domain.models.payout_data.request.credit_card import CreditCard 5 | 6 | 7 | class PayoutDestinationBankCard(PayoutDestination): 8 | 9 | __card = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PayoutDestinationBankCard, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.BANK_CARD: 14 | self.type = PaymentMethodType.BANK_CARD 15 | 16 | @property 17 | def card(self): 18 | return self.__card 19 | 20 | @card.setter 21 | def card(self, value): 22 | if isinstance(value, dict): 23 | self.__card = CreditCard(value) 24 | elif isinstance(value, CreditCard): 25 | self.__card = value 26 | else: 27 | raise TypeError('Invalid card value type in PaymentDestinationBankCard') 28 | 29 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/request/payout_destination_yoomoney_wallet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payout_data.payout_destination import PayoutDestination 4 | 5 | 6 | class PayoutDestinationYooMoneyWallet(PayoutDestination): 7 | 8 | __account_number = None 9 | 10 | def __init__(self, *args, **kwargs): 11 | super(PayoutDestinationYooMoneyWallet, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not PaymentMethodType.YOO_MONEY: 13 | self.type = PaymentMethodType.YOO_MONEY 14 | 15 | @property 16 | def account_number(self): 17 | return self.__account_number 18 | 19 | @account_number.setter 20 | def account_number(self, value): 21 | self.__account_number = str(value) 22 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/response/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/src/yookassa/domain/models/payout_data/response/__init__.py -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/response/credit_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common import BaseObject 5 | 6 | 7 | class CreditCard(BaseObject): 8 | # Первые 6 цифр номера карты (BIN). 9 | __first6 = None 10 | # Последние 4 цифры номера карты. 11 | __last4 = None 12 | # Тип банковской карты. Возможные значения: 13 | # ~`MasterCard` (для карт Mastercard и Maestro), ~`Visa` (для карт Visa и Visa Electron), 14 | # ~`Mir`, ~`UnionPay`, ~`JCB`, ~`AmericanExpress`, ~`DinersClub` и ~`Unknown`. 15 | __card_type = None 16 | # Код страны, в которой выпущена карта. 17 | # Передается в формате [ISO-3166 alpha-2](https://www.iso.org/obp/ui/#iso:pub:PUB500001:en). 18 | # Пример: RU. 19 | __issuer_country = None 20 | # Наименование банка, выпустившего карту. 21 | __issuer_name = None 22 | 23 | @property 24 | def first6(self): 25 | return self.__first6 26 | 27 | @first6.setter 28 | def first6(self, value): 29 | cast_value = str(value) 30 | if re.match('^[0-9]{6}$', cast_value): 31 | self.__first6 = cast_value 32 | else: 33 | raise ValueError('Invalid first6 value') 34 | 35 | @property 36 | def last4(self): 37 | return self.__last4 38 | 39 | @last4.setter 40 | def last4(self, value): 41 | cast_value = str(value) 42 | if re.match(r'^[\d]{4}$', cast_value): 43 | self.__last4 = cast_value 44 | else: 45 | raise ValueError('Invalid last4 value') 46 | 47 | @property 48 | def card_type(self): 49 | return self.__card_type 50 | 51 | @card_type.setter 52 | def card_type(self, value): 53 | self.__card_type = value 54 | 55 | @property 56 | def issuer_country(self): 57 | return self.__issuer_country 58 | 59 | @issuer_country.setter 60 | def issuer_country(self, value): 61 | cast_value = str(value) 62 | if len(cast_value) == 2: 63 | self.__issuer_country = cast_value 64 | else: 65 | raise ValueError('Invalid card issuer country value') 66 | 67 | @property 68 | def issuer_name(self): 69 | return self.__issuer_name 70 | 71 | @issuer_name.setter 72 | def issuer_name(self, value): 73 | self.__issuer_name = str(value) 74 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/response/payout_destination_bank_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payout_data.payout_destination import PayoutDestination 4 | from yookassa.domain.models.payout_data.response.credit_card import CreditCard 5 | 6 | 7 | class PayoutDestinationBankCard(PayoutDestination): 8 | 9 | __card = None 10 | 11 | def __init__(self, *args, **kwargs): 12 | super(PayoutDestinationBankCard, self).__init__(*args, **kwargs) 13 | if self.type is None or self.type is not PaymentMethodType.BANK_CARD: 14 | self.type = PaymentMethodType.BANK_CARD 15 | 16 | @property 17 | def card(self): 18 | return self.__card 19 | 20 | @card.setter 21 | def card(self, value): 22 | if isinstance(value, dict): 23 | self.__card = CreditCard(value) 24 | elif isinstance(value, CreditCard): 25 | self.__card = value 26 | else: 27 | raise TypeError('Invalid card value type in PayoutDestinationBankCard') 28 | 29 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/payout_data/response/payout_destination_yoomoney_wallet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.payment_method_type import PaymentMethodType 3 | from yookassa.domain.models.payout_data.payout_destination import PayoutDestination 4 | 5 | 6 | class PayoutDestinationYooMoneyWallet(PayoutDestination): 7 | 8 | __account_number = None 9 | 10 | def __init__(self, *args, **kwargs): 11 | super(PayoutDestinationYooMoneyWallet, self).__init__(*args, **kwargs) 12 | if self.type is None or self.type is not PaymentMethodType.YOO_MONEY: 13 | self.type = PaymentMethodType.YOO_MONEY 14 | 15 | @property 16 | def account_number(self): 17 | return self.__account_number 18 | 19 | @account_number.setter 20 | def account_number(self, value): 21 | self.__account_number = str(value) 22 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/receipt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.models.receipt_customer import ReceiptCustomer 4 | from yookassa.domain.models.receipt_item import ReceiptItem 5 | 6 | 7 | class Receipt(BaseObject): 8 | """ 9 | Class representing receipt data wrapper object 10 | """ 11 | __customer = None 12 | 13 | __items = [] 14 | 15 | __tax_system_code = None 16 | 17 | @property 18 | def customer(self): 19 | return self.__customer 20 | 21 | @customer.setter 22 | def customer(self, value): 23 | if isinstance(value, dict): 24 | self.__customer = ReceiptCustomer(value) 25 | elif isinstance(value, ReceiptCustomer): 26 | self.__customer = value 27 | else: 28 | raise TypeError('Invalid customer value type') 29 | 30 | @property 31 | def items(self): 32 | return self.__items 33 | 34 | @items.setter 35 | def items(self, value): 36 | if isinstance(value, list): 37 | items = [] 38 | for item in value: 39 | if isinstance(item, dict): 40 | items.append(ReceiptItem(item)) 41 | elif isinstance(item, ReceiptItem): 42 | items.append(item) 43 | else: 44 | raise TypeError('Invalid item type in receipt.items') 45 | 46 | self.__items = items 47 | elif value is None: 48 | self.__items = [] 49 | else: 50 | raise TypeError('Invalid items value type in receipt') 51 | 52 | @property 53 | def tax_system_code(self): 54 | return self.__tax_system_code 55 | 56 | @tax_system_code.setter 57 | def tax_system_code(self, value): 58 | if isinstance(value, int): 59 | self.__tax_system_code = value 60 | else: 61 | raise TypeError('Invalid tax_system_code value type') 62 | 63 | @property 64 | def email(self): 65 | return self.__customer.email if self.__customer is not None else None 66 | 67 | @email.setter 68 | def email(self, value): 69 | if self.__customer is None: 70 | self.__customer = ReceiptCustomer() 71 | self.__customer.email = str(value) 72 | 73 | @property 74 | def phone(self): 75 | return self.__customer.phone if self.__customer is not None else None 76 | 77 | @phone.setter 78 | def phone(self, value): 79 | if self.__customer is None: 80 | self.__customer = ReceiptCustomer() 81 | self.__customer.phone = str(value) 82 | 83 | def has_items(self): 84 | return bool(self.items) 85 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/receipt_customer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | 4 | from yookassa.domain.common import BaseObject 5 | 6 | 7 | class ReceiptCustomer(BaseObject): 8 | """ 9 | Class representing receipt customer data wrapper object 10 | 11 | Used in Receipt 12 | """ 13 | __full_name = None 14 | 15 | __inn = None 16 | 17 | __email = None 18 | 19 | __phone = None 20 | 21 | @property 22 | def full_name(self): 23 | return self.__full_name 24 | 25 | @full_name.setter 26 | def full_name(self, value): 27 | self.__full_name = str(value) 28 | 29 | @property 30 | def inn(self): 31 | return self.__inn 32 | 33 | @inn.setter 34 | def inn(self, value): 35 | self.__inn = str(value) 36 | 37 | @property 38 | def email(self): 39 | return self.__email 40 | 41 | @email.setter 42 | def email(self, value): 43 | cast_value = str(value) 44 | if re.match(r"^[^@]+@[^@]+\.[^@]+$", cast_value): 45 | self.__email = cast_value 46 | else: 47 | raise ValueError('Invalid email value type') 48 | 49 | @property 50 | def phone(self): 51 | return self.__phone 52 | 53 | @phone.setter 54 | def phone(self, value): 55 | self.__phone = str(value) 56 | 57 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/receipt_item_supplier.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from yookassa.domain.common import BaseObject 4 | 5 | 6 | class ReceiptItemSupplier(BaseObject): 7 | """ 8 | Class representing receipt item supplier data wrapper object 9 | 10 | Used in Receipt 11 | """ 12 | __name = None 13 | 14 | __inn = None 15 | 16 | __phone = None 17 | 18 | @property 19 | def name(self): 20 | return self.__name 21 | 22 | @name.setter 23 | def name(self, value): 24 | self.__name = str(value) 25 | 26 | @property 27 | def inn(self): 28 | return self.__inn 29 | 30 | @inn.setter 31 | def inn(self, value): 32 | self.__inn = str(value) 33 | 34 | @property 35 | def phone(self): 36 | return self.__phone 37 | 38 | @phone.setter 39 | def phone(self, value): 40 | self.__phone = str(value) 41 | 42 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/recipient.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | 4 | 5 | class Recipient(BaseObject): 6 | """ 7 | Class representing recipient data wrapper object 8 | """ 9 | __account_id = None 10 | 11 | __gateway_id = None 12 | 13 | @property 14 | def account_id(self): 15 | return self.__account_id 16 | 17 | @account_id.setter 18 | def account_id(self, value): 19 | self.__account_id = str(value) 20 | 21 | @property 22 | def gateway_id(self): 23 | return self.__gateway_id 24 | 25 | @gateway_id.setter 26 | def gateway_id(self, value): 27 | self.__gateway_id = str(value) 28 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/refund_source.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.models.amount import Amount 4 | 5 | 6 | class RefundSource(BaseObject): 7 | """ 8 | Class representing refund source wrapper object 9 | 10 | Used in Refund 11 | """ 12 | __account_id = None 13 | 14 | __amount = None 15 | 16 | __platform_fee_amount = None 17 | 18 | @property 19 | def account_id(self): 20 | return self.__account_id 21 | 22 | @account_id.setter 23 | def account_id(self, value): 24 | self.__account_id = str(value) 25 | 26 | @property 27 | def amount(self): 28 | return self.__amount 29 | 30 | @amount.setter 31 | def amount(self, value): 32 | if isinstance(value, dict): 33 | self.__amount = Amount(value) 34 | elif isinstance(value, Amount): 35 | self.__amount = value 36 | else: 37 | raise TypeError('Invalid amount value type') 38 | 39 | @property 40 | def platform_fee_amount(self): 41 | return self.__platform_fee_amount 42 | 43 | @platform_fee_amount.setter 44 | def platform_fee_amount(self, value): 45 | if isinstance(value, dict): 46 | self.__platform_fee_amount = Amount(value) 47 | elif isinstance(value, Amount): 48 | self.__platform_fee_amount = value 49 | else: 50 | raise TypeError('Invalid platform_fee_amount value type') 51 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/requestor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from deprecated.classic import deprecated 3 | from yookassa.domain.common import BaseObject 4 | 5 | 6 | @deprecated("This class will be removed in one of future versions") 7 | class RequestorType(object): 8 | MERCHANT = "merchant" 9 | THIRD_PARTY_CLIENT = "third_party_client" 10 | 11 | 12 | @deprecated("This class will be removed in one of future versions") 13 | class Requestor(BaseObject): 14 | """ 15 | Class representing requestor data wrapper object 16 | """ 17 | __type = None 18 | 19 | @property 20 | def type(self): 21 | return self.__type 22 | 23 | @type.setter 24 | def type(self, value): 25 | self.__type = str(value) 26 | 27 | 28 | @deprecated("This class will be removed in one of future versions") 29 | class RequestorMerchant(Requestor): 30 | """ 31 | Class representing requestor_merchant data wrapper object 32 | """ 33 | __type = RequestorType.MERCHANT 34 | 35 | __account_id = None 36 | 37 | @property 38 | def account_id(self): 39 | return self.__account_id 40 | 41 | @account_id.setter 42 | def account_id(self, value): 43 | self.__account_id = str(value) 44 | 45 | 46 | @deprecated("This class will be removed in one of future versions") 47 | class RequestorThirdPartyClient(Requestor): 48 | """ 49 | Class representing requestor_third_party_client data wrapper object 50 | """ 51 | __type = RequestorType.THIRD_PARTY_CLIENT 52 | 53 | __client_id = None 54 | 55 | __client_name = None 56 | 57 | @property 58 | def client_id(self): 59 | return self.__client_id 60 | 61 | @client_id.setter 62 | def client_id(self, value): 63 | self.__client_id = str(value) 64 | 65 | @property 66 | def client_name(self): 67 | return self.__client_name 68 | 69 | @client_name.setter 70 | def client_name(self, value): 71 | self.__client_name = str(value) 72 | 73 | 74 | @deprecated("This class will be removed in one of future versions") 75 | class RequestorFactory(object): 76 | """ 77 | Base factory class for object that has type property. 78 | """ 79 | 80 | def create(self, data): 81 | """ 82 | Create instance from value 83 | 84 | :param data: dictionary that has type key 85 | :return: Typed object instance 86 | """ 87 | if isinstance(data, dict): 88 | if 'type' in data: 89 | return self.__get_instance(data) 90 | else: 91 | raise ValueError('Parameter "data" should contain "type" field') 92 | else: 93 | raise TypeError('Parameter "data" should be "dict"') 94 | 95 | def __get_instance(self, data): 96 | class_object = self.__get_class_object(data) 97 | return class_object(data) 98 | 99 | @staticmethod 100 | def __get_class_object(data): 101 | if data['type'] == RequestorType.MERCHANT: 102 | return RequestorMerchant 103 | elif data['type'] == RequestorType.THIRD_PARTY_CLIENT: 104 | return RequestorThirdPartyClient 105 | else: 106 | raise TypeError('Parameter "data" should contain "type" field') 107 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/settlement.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.models.amount import Amount 4 | 5 | 6 | class Settlement(BaseObject): 7 | """ 8 | Class representing receipt settlement data wrapper object 9 | 10 | Used in Receipt 11 | """ 12 | __type = None 13 | 14 | __amount = None 15 | 16 | @property 17 | def type(self): 18 | return self.__type 19 | 20 | @type.setter 21 | def type(self, value): 22 | self.__type = str(value) 23 | 24 | @property 25 | def amount(self): 26 | return self.__amount 27 | 28 | @amount.setter 29 | def amount(self, value): 30 | if isinstance(value, dict): 31 | self.__amount = Amount(value) 32 | elif isinstance(value, Amount): 33 | self.__amount = value 34 | else: 35 | raise TypeError('Invalid amount value type') 36 | 37 | 38 | class SettlementType(object): 39 | """ 40 | Class representing SettlementType values enum 41 | """ 42 | CASHLESS = 'cashless' 43 | PREPAYMENT = 'prepayment' 44 | POSTPAYMENT = 'postpayment' 45 | CONSIDERATION = 'consideration' 46 | 47 | 48 | class SettlementPayoutType(object): 49 | """ 50 | Class representing SettlementPayoutType values enum 51 | """ 52 | PAYOUT = 'payout' 53 | -------------------------------------------------------------------------------- /src/yookassa/domain/models/transfer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.models.amount import Amount 4 | 5 | 6 | class Transfer(BaseObject): 7 | """ 8 | Class representing payment transfer wrapper object 9 | 10 | Used in Payment 11 | """ 12 | __account_id = None 13 | 14 | __amount = None 15 | 16 | __platform_fee_amount = None 17 | 18 | __metadata = None 19 | 20 | @property 21 | def account_id(self): 22 | return self.__account_id 23 | 24 | @account_id.setter 25 | def account_id(self, value): 26 | self.__account_id = str(value) 27 | 28 | @property 29 | def amount(self): 30 | return self.__amount 31 | 32 | @amount.setter 33 | def amount(self, value): 34 | if isinstance(value, dict): 35 | self.__amount = Amount(value) 36 | elif isinstance(value, Amount): 37 | self.__amount = value 38 | else: 39 | raise TypeError('Invalid transfer.amount value type') 40 | 41 | @property 42 | def platform_fee_amount(self): 43 | return self.__platform_fee_amount 44 | 45 | @platform_fee_amount.setter 46 | def platform_fee_amount(self, value): 47 | if isinstance(value, dict): 48 | self.__platform_fee_amount = Amount(value) 49 | elif isinstance(value, Amount): 50 | self.__platform_fee_amount = value 51 | else: 52 | raise TypeError('Invalid transfer.platform_fee_amount value type') 53 | 54 | @property 55 | def metadata(self): 56 | return self.__metadata 57 | 58 | @metadata.setter 59 | def metadata(self, value): 60 | if type(value) is dict: 61 | self.__metadata = value 62 | -------------------------------------------------------------------------------- /src/yookassa/domain/notification/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | 4 | from yookassa.domain.notification.webhook_notification import * 5 | from yookassa.domain.notification.webhook_notification_types import * 6 | -------------------------------------------------------------------------------- /src/yookassa/domain/notification/webhook_notification_types.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class WebhookNotificationType: 5 | """ 6 | """ 7 | NOTIFICATION = 'notification' 8 | 9 | 10 | class WebhookNotificationEventType: 11 | """ 12 | """ 13 | PAYMENT_WAITING_FOR_CAPTURE = 'payment.waiting_for_capture' 14 | PAYMENT_SUCCEEDED = 'payment.succeeded' 15 | PAYMENT_CANCELED = 'payment.canceled' 16 | REFUND_SUCCEEDED = 'refund.succeeded' 17 | 18 | DEAL_CLOSED = 'deal.closed' 19 | PAYOUT_CANCELED = 'payout.canceled' 20 | PAYOUT_SUCCEEDED = 'payout.succeeded' 21 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | 4 | from yookassa.domain.request.capture_payment_builder import CapturePaymentBuilder 5 | from yookassa.domain.request.capture_payment_request import CapturePaymentRequest 6 | from yookassa.domain.request.payment_request import PaymentRequest 7 | from yookassa.domain.request.payment_request_builder import PaymentRequestBuilder 8 | from yookassa.domain.request.receipt_item_request import ReceiptItemRequest 9 | from yookassa.domain.request.receipt_request import ReceiptRequest 10 | from yookassa.domain.request.receipt_request_builder import ReceiptRequestBuilder 11 | from yookassa.domain.request.refund_request import RefundRequest 12 | from yookassa.domain.request.refund_request_builder import RefundRequestBuilder 13 | from yookassa.domain.request.webhook_request import WebhookRequest 14 | from yookassa.domain.request.deal_request import DealRequest 15 | from yookassa.domain.request.deal_request_builder import DealRequestBuilder 16 | from yookassa.domain.request.payout_request import PayoutRequest 17 | from yookassa.domain.request.payout_request_builder import PayoutRequestBuilder 18 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/capture_payment_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.request.capture_payment_request import CapturePaymentRequest 3 | 4 | 5 | class CapturePaymentBuilder(object): 6 | 7 | def __init__(self): 8 | self.__request = CapturePaymentRequest() 9 | 10 | def set_amount(self, value): 11 | self.__request.amount = value 12 | return self 13 | 14 | def set_receipt(self, value): 15 | self.__request.receipt = value 16 | return self 17 | 18 | def set_airline(self, value): 19 | self.__request.airline = value 20 | return self 21 | 22 | def set_metadata(self, value): 23 | self.__request.metadata = value 24 | return self 25 | 26 | def set_transfers(self, value): 27 | self.__request.transfers = value 28 | return self 29 | 30 | def build(self): 31 | return self.__request 32 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/capture_payment_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.request_object import RequestObject 3 | from yookassa.domain.models.airline import Airline 4 | from yookassa.domain.models.amount import Amount 5 | from yookassa.domain.models.receipt import Receipt 6 | from yookassa.domain.models.transfer import Transfer 7 | 8 | 9 | class CapturePaymentRequest(RequestObject): 10 | 11 | __amount = None 12 | 13 | __receipt = None 14 | 15 | __airline = None 16 | 17 | __transfers = [] 18 | 19 | @property 20 | def amount(self): 21 | return self.__amount 22 | 23 | @amount.setter 24 | def amount(self, value): 25 | if isinstance(value, dict): 26 | self.__amount = Amount(value) 27 | elif isinstance(value, Amount): 28 | self.__amount = value 29 | else: 30 | raise TypeError('Invalid amount value type') 31 | 32 | @property 33 | def receipt(self): 34 | return self.__receipt 35 | 36 | @receipt.setter 37 | def receipt(self, value): 38 | if isinstance(value, dict): 39 | self.__receipt = Receipt(value) 40 | elif isinstance(value, Receipt): 41 | self.__receipt = value 42 | else: 43 | raise TypeError('Invalid receipt value type') 44 | 45 | @property 46 | def airline(self): 47 | return self.__airline 48 | 49 | @airline.setter 50 | def airline(self, value): 51 | if isinstance(value, dict): 52 | self.__airline = Airline(value) 53 | elif isinstance(value, Airline): 54 | self.__airline = value 55 | else: 56 | raise TypeError('Invalid airline type') 57 | 58 | @property 59 | def transfers(self): 60 | return self.__transfers 61 | 62 | @transfers.setter 63 | def transfers(self, value): 64 | if isinstance(value, list): 65 | self.__transfers = [Transfer(item) for item in value] 66 | elif value is None: 67 | self.__transfers = [] 68 | else: 69 | raise TypeError('Invalid transfers data type in capture_payment_request.transfers') 70 | 71 | def validate(self): 72 | if self.amount: 73 | value = self.amount.value 74 | if not value or value <= 0.0: 75 | self.__set_validation_error('Invalid amount value: ' + str(value)) 76 | if self.receipt is not None and self.receipt.has_items: 77 | email = self.receipt.email 78 | phone = self.receipt.phone 79 | if not email and not phone: 80 | self.__set_validation_error('Both email and phone values are empty in receipt') 81 | 82 | if not self.receipt.tax_system_code and any(not item.vat_code for item in self.receipt.items): 83 | self.__set_validation_error('Item vat_id and receipt tax_system_id not specified') 84 | 85 | def __set_validation_error(self, message): 86 | raise ValueError(message) 87 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/deal_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.request_object import RequestObject 3 | 4 | DESCRIPTION_MAX_LENGTH = 128 5 | 6 | 7 | class DealRequest(RequestObject): 8 | 9 | __type = None 10 | 11 | __fee_moment = None 12 | 13 | __description = None 14 | 15 | __metadata = None 16 | 17 | @property 18 | def type(self): 19 | return self.__type 20 | 21 | @type.setter 22 | def type(self, value): 23 | self.__type = str(value) 24 | 25 | @property 26 | def fee_moment(self): 27 | return self.__fee_moment 28 | 29 | @fee_moment.setter 30 | def fee_moment(self, value): 31 | self.__fee_moment = str(value) 32 | 33 | @property 34 | def description(self): 35 | return self.__description 36 | 37 | @description.setter 38 | def description(self, value): 39 | cast_value = str(value) 40 | if cast_value: 41 | if len(cast_value) <= DESCRIPTION_MAX_LENGTH: 42 | self.__description = cast_value 43 | else: 44 | raise ValueError('The value of the description parameter is too long. Max length is {}'.format( 45 | DESCRIPTION_MAX_LENGTH)) 46 | else: 47 | raise ValueError('Invalid description value') 48 | 49 | @property 50 | def metadata(self): 51 | return self.__metadata 52 | 53 | @metadata.setter 54 | def metadata(self, value): 55 | if type(value) is dict: 56 | self.__metadata = value 57 | 58 | def validate(self): 59 | if self.type is None: 60 | self.__set_validation_error('Deal type not specified') 61 | 62 | if self.fee_moment is None: 63 | self.__set_validation_error('Deal fee_moment not specified') 64 | 65 | def __set_validation_error(self, message): 66 | raise ValueError(message) 67 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/deal_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.request import DealRequest 3 | 4 | 5 | class DealRequestBuilder(object): 6 | def __init__(self): 7 | self.__request = DealRequest() 8 | 9 | def set_type(self, value): 10 | self.__request.type = value 11 | return self 12 | 13 | def set_fee_moment(self, value): 14 | self.__request.fee_moment = value 15 | return self 16 | 17 | def set_description(self, value): 18 | self.__request.description = value 19 | return self 20 | 21 | def set_metadata(self, value): 22 | self.__request.metadata = value 23 | return self 24 | 25 | def build(self): 26 | return self.__request 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/payment_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.request.payment_request import PaymentRequest 3 | 4 | 5 | class PaymentRequestBuilder(object): 6 | def __init__(self): 7 | self.__request = PaymentRequest() 8 | 9 | def set_recipient(self, value): 10 | self.__request.recipient = value 11 | return self 12 | 13 | def set_amount(self, value): 14 | self.__request.amount = value 15 | return self 16 | 17 | def set_description(self, value): 18 | self.__request.description = value 19 | return self 20 | 21 | def set_receipt(self, value): 22 | self.__request.receipt = value 23 | return self 24 | 25 | def set_payment_token(self, value): 26 | self.__request.payment_token = value 27 | return self 28 | 29 | def set_payment_method_id(self, value): 30 | self.__request.payment_method_id = value 31 | return self 32 | 33 | def set_payment_method_data(self, value): 34 | self.__request.payment_method_data = value 35 | return self 36 | 37 | def set_confirmation(self, value): 38 | self.__request.confirmation = value 39 | return self 40 | 41 | def set_save_payment_method(self, value): 42 | self.__request.save_payment_method = value 43 | return self 44 | 45 | def set_capture(self, value): 46 | self.__request.capture = value 47 | return self 48 | 49 | def set_client_ip(self, value): 50 | self.__request.client_ip = value 51 | return self 52 | 53 | def set_airline(self, value): 54 | self.__request.airline = value 55 | return self 56 | 57 | def set_metadata(self, value): 58 | self.__request.metadata = value 59 | return self 60 | 61 | def set_transfers(self, value): 62 | self.__request.transfers = value 63 | return self 64 | 65 | def set_deal(self, value): 66 | self.__request.deal = value 67 | return self 68 | 69 | def set_merchant_customer_id(self, value): 70 | self.__request.merchant_customer_id = value 71 | return self 72 | 73 | def build(self): 74 | return self.__request 75 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/payout_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.request import PayoutRequest 3 | 4 | 5 | class PayoutRequestBuilder(object): 6 | def __init__(self): 7 | self.__request = PayoutRequest() 8 | 9 | def set_amount(self, value): 10 | self.__request.amount = value 11 | return self 12 | 13 | def set_description(self, value): 14 | self.__request.description = value 15 | return self 16 | 17 | def set_payout_token(self, value): 18 | self.__request.payout_token = value 19 | return self 20 | 21 | def set_payout_destination_data(self, value): 22 | self.__request.payout_destination_data = value 23 | return self 24 | 25 | def set_deal(self, value): 26 | self.__request.deal = value 27 | return self 28 | 29 | def set_metadata(self, value): 30 | self.__request.metadata = value 31 | return self 32 | 33 | def build(self): 34 | return self.__request 35 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/receipt_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.request.receipt_request import ReceiptRequest 3 | 4 | 5 | class ReceiptRequestBuilder(object): 6 | def __init__(self): 7 | self.__request = ReceiptRequest() 8 | 9 | def set_type(self, value): 10 | self.__request.type = value 11 | return self 12 | 13 | def set_send(self, value): 14 | self.__request.send = value 15 | return self 16 | 17 | def set_customer(self, value): 18 | self.__request.customer = value 19 | return self 20 | 21 | def set_tax_system_code(self, value): 22 | self.__request.tax_system_code = value 23 | return self 24 | 25 | def set_items(self, value): 26 | self.__request.items = value 27 | return self 28 | 29 | def set_settlements(self, value): 30 | self.__request.settlements = value 31 | return self 32 | 33 | def set_payment_id(self, value): 34 | self.__request.payment_id = value 35 | return self 36 | 37 | def set_refund_id(self, value): 38 | self.__request.refund_id = value 39 | return self 40 | 41 | def set_on_behalf_of(self, value): 42 | self.__request.on_behalf_of = value 43 | return self 44 | 45 | def build(self): 46 | return self.__request 47 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/refund_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.request_object import RequestObject 3 | from yookassa.domain.models.amount import Amount 4 | from yookassa.domain.models.deal import RefundDealData 5 | from yookassa.domain.models.receipt import Receipt 6 | from yookassa.domain.models.refund_source import RefundSource 7 | 8 | 9 | class RefundRequest(RequestObject): 10 | """ 11 | Class representing response object. 12 | 13 | Contains data 14 | """ 15 | __payment_id = None 16 | 17 | __amount = None 18 | 19 | __description = None 20 | 21 | __receipt = None 22 | 23 | __sources = [] 24 | 25 | __deal = None 26 | 27 | @property 28 | def payment_id(self): 29 | return self.__payment_id 30 | 31 | @payment_id.setter 32 | def payment_id(self, value): 33 | cast_value = str(value) 34 | if len(cast_value) == 36: 35 | self.__payment_id = cast_value 36 | else: 37 | raise ValueError('Invalid payment id value') 38 | 39 | @property 40 | def amount(self): 41 | return self.__amount 42 | 43 | @amount.setter 44 | def amount(self, value): 45 | if isinstance(value, dict): 46 | self.__amount = Amount(value) 47 | elif isinstance(value, Amount): 48 | self.__amount = value 49 | else: 50 | raise TypeError('Invalid amount value type') 51 | 52 | @property 53 | def description(self): 54 | return self.__description 55 | 56 | @description.setter 57 | def description(self, value): 58 | cast_value = str(value) 59 | if cast_value and len(cast_value) < 256: 60 | self.__description = cast_value 61 | else: 62 | raise ValueError('Invalid commend value') 63 | 64 | @property 65 | def sources(self): 66 | return self.__sources 67 | 68 | @sources.setter 69 | def sources(self, value): 70 | if isinstance(value, list): 71 | self.__sources = [RefundSource(item) for item in value] 72 | elif value is None: 73 | self.__sources = [] 74 | else: 75 | raise TypeError('Invalid sources data type in refund_request.sources') 76 | 77 | @property 78 | def receipt(self): 79 | return self.__receipt 80 | 81 | @receipt.setter 82 | def receipt(self, value): 83 | if isinstance(value, dict): 84 | self.__receipt = Receipt(value) 85 | elif isinstance(value, Receipt): 86 | self.__receipt = value 87 | else: 88 | raise TypeError('Invalid receipt value type') 89 | 90 | @property 91 | def deal(self): 92 | return self.__deal 93 | 94 | @deal.setter 95 | def deal(self, value): 96 | if isinstance(value, dict): 97 | self.__deal = RefundDealData(value) 98 | elif isinstance(value, RefundDealData): 99 | self.__deal = value 100 | else: 101 | raise TypeError('Invalid deal value type') 102 | 103 | def validate(self): 104 | if not self.payment_id: 105 | self.__set_validation_error('Payment id not specified') 106 | 107 | if not self.amount: 108 | self.__set_validation_error('Amount not specified') 109 | 110 | if self.amount.value <= 0.0: 111 | self.__set_validation_error('Invalid amount value: ' + str(self.amount.value)) 112 | 113 | if self.receipt and self.receipt.has_items(): 114 | email = self.receipt.email 115 | phone = self.receipt.phone 116 | if not email and not phone: 117 | self.__set_validation_error('Both email and phone values are empty in receipt') 118 | 119 | if not self.receipt.tax_system_code and any(not item.vat_code for item in self.receipt.items): 120 | self.__set_validation_error('Item vat_id and receipt tax_system_id not specified') 121 | 122 | def __set_validation_error(self, message): 123 | raise ValueError(message) 124 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/refund_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.request.refund_request import RefundRequest 3 | 4 | 5 | class RefundRequestBuilder(object): 6 | def __init__(self): 7 | self.__request = RefundRequest() 8 | 9 | def set_payment_id(self, value): 10 | self.__request.payment_id = value 11 | return self 12 | 13 | def set_amount(self, value): 14 | self.__request.amount = value 15 | return self 16 | 17 | def set_description(self, value): 18 | self.__request.description = value 19 | return self 20 | 21 | def set_receipt(self, value): 22 | self.__request.receipt = value 23 | return self 24 | 25 | def set_sources(self, value): 26 | self.__request.sources = value 27 | return self 28 | 29 | def set_deal(self, value): 30 | self.__request.deal = value 31 | return self 32 | 33 | def build(self): 34 | return self.__request 35 | -------------------------------------------------------------------------------- /src/yookassa/domain/request/webhook_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.request_object import RequestObject 3 | 4 | 5 | class WebhookRequest(RequestObject): 6 | __event = None 7 | 8 | __url = None 9 | 10 | @property 11 | def event(self): 12 | return self.__event 13 | 14 | @event.setter 15 | def event(self, value): 16 | cast_value = str(value) 17 | self.__event = cast_value 18 | 19 | @property 20 | def url(self): 21 | return self.__url 22 | 23 | @url.setter 24 | def url(self, value): 25 | cast_value = str(value) 26 | self.__url = cast_value 27 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | 4 | from yookassa.domain.response.payment_list_response import PaymentListResponse 5 | from yookassa.domain.response.payment_response import PaymentResponse 6 | from yookassa.domain.response.receipt_item_response import ReceiptItemResponse 7 | from yookassa.domain.response.receipt_list_response import ReceiptListResponse 8 | from yookassa.domain.response.receipt_response import ReceiptResponse 9 | from yookassa.domain.response.refund_list_response import RefundListResponse 10 | from yookassa.domain.response.refund_response import RefundResponse 11 | from yookassa.domain.response.transfer_response import TransferResponse, TransferStatus 12 | from yookassa.domain.response.webhook_response import WebhookResponse, WebhookList 13 | from yookassa.domain.response.deal_response import DealResponse 14 | from yookassa.domain.response.deal_list_response import DealListResponse 15 | from yookassa.domain.response.payout_response import PayoutResponse 16 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/deal_list_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.response_object import ResponseObject 3 | from yookassa.domain.response.deal_response import DealResponse 4 | 5 | 6 | class DealListResponse(ResponseObject): 7 | 8 | __type = None 9 | 10 | __next_cursor = None 11 | 12 | __items = None 13 | 14 | @property 15 | def type(self): 16 | return self.__type 17 | 18 | @type.setter 19 | def type(self, value): 20 | self.__type = value 21 | 22 | @property 23 | def next_cursor(self): 24 | return self.__next_cursor 25 | 26 | @next_cursor.setter 27 | def next_cursor(self, value): 28 | self.__next_cursor = value 29 | 30 | @property 31 | def items(self): 32 | return self.__items 33 | 34 | @items.setter 35 | def items(self, value): 36 | if isinstance(value, list): 37 | self.__items = [DealResponse(payment) for payment in value] 38 | else: 39 | self.__items = value 40 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/deal_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import ResponseObject 3 | from yookassa.domain.models import Amount 4 | 5 | 6 | class DealResponse(ResponseObject): 7 | """ 8 | Class representing response object. 9 | 10 | Contains data 11 | """ 12 | __id = None 13 | 14 | __type = None 15 | 16 | __status = None 17 | 18 | __balance = None 19 | 20 | __payout_balance = None 21 | 22 | __description = None 23 | 24 | __fee_moment = None 25 | 26 | __created_at = None 27 | 28 | __expires_at = None 29 | 30 | __test = None 31 | 32 | __metadata = None 33 | 34 | @property 35 | def id(self): 36 | return self.__id 37 | 38 | @id.setter 39 | def id(self, value): 40 | self.__id = value 41 | 42 | @property 43 | def status(self): 44 | return self.__status 45 | 46 | @status.setter 47 | def status(self, value): 48 | self.__status = value 49 | 50 | @property 51 | def balance(self): 52 | return self.__balance 53 | 54 | @balance.setter 55 | def balance(self, value): 56 | self.__balance = Amount(value) 57 | 58 | @property 59 | def payout_balance(self): 60 | return self.__payout_balance 61 | 62 | @payout_balance.setter 63 | def payout_balance(self, value): 64 | self.__payout_balance = Amount(value) 65 | 66 | @property 67 | def description(self): 68 | return self.__description 69 | 70 | @description.setter 71 | def description(self, value): 72 | self.__description = value 73 | 74 | @property 75 | def fee_moment(self): 76 | return self.__fee_moment 77 | 78 | @fee_moment.setter 79 | def fee_moment(self, value): 80 | self.__fee_moment = str(value) 81 | 82 | @property 83 | def created_at(self): 84 | return self.__created_at 85 | 86 | @created_at.setter 87 | def created_at(self, value): 88 | self.__created_at = value 89 | 90 | @property 91 | def expires_at(self): 92 | return self.__expires_at 93 | 94 | @expires_at.setter 95 | def expires_at(self, value): 96 | self.__expires_at = value 97 | 98 | @property 99 | def test(self): 100 | return self.__test 101 | 102 | @test.setter 103 | def test(self, value): 104 | self.__test = bool(value) 105 | 106 | @property 107 | def metadata(self): 108 | return self.__metadata 109 | 110 | @metadata.setter 111 | def metadata(self, value): 112 | self.__metadata = value 113 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/payment_list_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.response_object import ResponseObject 3 | from yookassa.domain.response.payment_response import PaymentResponse 4 | 5 | 6 | class PaymentListResponse(ResponseObject): 7 | 8 | __type = None 9 | 10 | __next_cursor = None 11 | 12 | __items = None 13 | 14 | @property 15 | def type(self): 16 | return self.__type 17 | 18 | @type.setter 19 | def type(self, value): 20 | self.__type = value 21 | 22 | @property 23 | def next_cursor(self): 24 | return self.__next_cursor 25 | 26 | @next_cursor.setter 27 | def next_cursor(self, value): 28 | self.__next_cursor = value 29 | 30 | @property 31 | def items(self): 32 | return self.__items 33 | 34 | @items.setter 35 | def items(self, value): 36 | if isinstance(value, list): 37 | self.__items = [PaymentResponse(payment) for payment in value] 38 | else: 39 | self.__items = value 40 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/payout_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import ResponseObject 3 | from yookassa.domain.models import Amount, CancellationDetails 4 | from yookassa.domain.models.deal import PayoutDealInfo 5 | from yookassa.domain.models.payout_data.payout_destination_factory import PayoutDestinationFactory 6 | 7 | 8 | class PayoutResponse(ResponseObject): 9 | """ 10 | Class representing response object. 11 | 12 | Contains data 13 | """ 14 | __id = None 15 | 16 | __amount = None 17 | 18 | __status = None 19 | 20 | __payout_destination = None 21 | 22 | __description = None 23 | 24 | __created_at = None 25 | 26 | __deal = None 27 | 28 | __cancellation_details = None 29 | 30 | __metadata = None 31 | 32 | __test = None 33 | 34 | @property 35 | def id(self): 36 | return self.__id 37 | 38 | @id.setter 39 | def id(self, value): 40 | self.__id = value 41 | 42 | @property 43 | def amount(self): 44 | return self.__amount 45 | 46 | @amount.setter 47 | def amount(self, value): 48 | self.__amount = Amount(value) 49 | 50 | @property 51 | def status(self): 52 | return self.__status 53 | 54 | @status.setter 55 | def status(self, value): 56 | self.__status = value 57 | 58 | @property 59 | def payout_destination(self): 60 | return self.__payout_destination 61 | 62 | @payout_destination.setter 63 | def payout_destination(self, value): 64 | self.__payout_destination = PayoutDestinationFactory().create(value, self.context()) 65 | 66 | @property 67 | def description(self): 68 | return self.__description 69 | 70 | @description.setter 71 | def description(self, value): 72 | self.__description = value 73 | 74 | @property 75 | def created_at(self): 76 | return self.__created_at 77 | 78 | @created_at.setter 79 | def created_at(self, value): 80 | self.__created_at = value 81 | 82 | @property 83 | def deal(self): 84 | return self.__deal 85 | 86 | @deal.setter 87 | def deal(self, value): 88 | self.__deal = PayoutDealInfo(value) 89 | 90 | @property 91 | def cancellation_details(self): 92 | return self.__cancellation_details 93 | 94 | @cancellation_details.setter 95 | def cancellation_details(self, value): 96 | self.__cancellation_details = CancellationDetails(value) 97 | 98 | @property 99 | def metadata(self): 100 | return self.__metadata 101 | 102 | @metadata.setter 103 | def metadata(self, value): 104 | self.__metadata = value 105 | 106 | @property 107 | def test(self): 108 | return self.__test 109 | 110 | @test.setter 111 | def test(self, value): 112 | self.__test = bool(value) 113 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/receipt_item_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from decimal import Decimal 3 | 4 | from yookassa.domain.common import ResponseObject 5 | from yookassa.domain.models import Amount, ReceiptItemSupplier 6 | 7 | 8 | class ReceiptItemResponse(ResponseObject): 9 | 10 | __description = None 11 | 12 | __quantity = None 13 | 14 | __amount = None 15 | 16 | __vat_code = None 17 | 18 | __payment_subject = None 19 | 20 | __payment_mode = None 21 | 22 | __supplier = None 23 | 24 | __agent_type = None 25 | 26 | @property 27 | def description(self): 28 | return self.__description 29 | 30 | @description.setter 31 | def description(self, value): 32 | self.__description = value 33 | 34 | @property 35 | def quantity(self): 36 | """ 37 | :return Decimal: 38 | """ 39 | return self.__quantity 40 | 41 | @quantity.setter 42 | def quantity(self, value): 43 | self.__quantity = Decimal(str(float(value))) 44 | 45 | @property 46 | def amount(self): 47 | return self.__amount 48 | 49 | @amount.setter 50 | def amount(self, value): 51 | self.__amount = Amount(value) 52 | 53 | @property 54 | def vat_code(self): 55 | return self.__vat_code 56 | 57 | @vat_code.setter 58 | def vat_code(self, value): 59 | self.__vat_code = int(value) 60 | 61 | @property 62 | def payment_subject(self): 63 | return self.__payment_subject 64 | 65 | @payment_subject.setter 66 | def payment_subject(self, value): 67 | self.__payment_subject = str(value) 68 | 69 | @property 70 | def payment_mode(self): 71 | return self.__payment_mode 72 | 73 | @payment_mode.setter 74 | def payment_mode(self, value): 75 | self.__payment_mode = str(value) 76 | 77 | @property 78 | def supplier(self): 79 | return self.__supplier 80 | 81 | @supplier.setter 82 | def supplier(self, value): 83 | if isinstance(value, dict): 84 | self.__supplier = ReceiptItemSupplier(value) 85 | elif isinstance(value, ReceiptItemSupplier): 86 | self.__supplier = value 87 | else: 88 | raise TypeError('Invalid supplier value type') 89 | 90 | @property 91 | def agent_type(self): 92 | return self.__agent_type 93 | 94 | @agent_type.setter 95 | def agent_type(self, value): 96 | self.__agent_type = str(value) 97 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/receipt_list_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.response_object import ResponseObject 3 | from yookassa.domain.response.receipt_response import ReceiptResponse 4 | 5 | 6 | class ReceiptListResponse(ResponseObject): 7 | 8 | __type = None 9 | 10 | __items = None 11 | 12 | __next_cursor = None 13 | 14 | @property 15 | def type(self): 16 | return self.__type 17 | 18 | @type.setter 19 | def type(self, value): 20 | self.__type = value 21 | 22 | @property 23 | def next_cursor(self): 24 | return self.__next_cursor 25 | 26 | @next_cursor.setter 27 | def next_cursor(self, value): 28 | self.__next_cursor = value 29 | 30 | @property 31 | def items(self): 32 | return self.__items 33 | 34 | @items.setter 35 | def items(self, value): 36 | if isinstance(value, list): 37 | self.__items = [ReceiptResponse(receipt) for receipt in value] 38 | else: 39 | self.__items = value 40 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/refund_list_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.response_object import ResponseObject 3 | from yookassa.domain.response.refund_response import RefundResponse 4 | 5 | 6 | class RefundListResponse(ResponseObject): 7 | 8 | __type = None 9 | 10 | __next_cursor = None 11 | 12 | __items = None 13 | 14 | @property 15 | def type(self): 16 | return self.__type 17 | 18 | @type.setter 19 | def type(self, value): 20 | self.__type = value 21 | 22 | @property 23 | def next_cursor(self): 24 | return self.__next_cursor 25 | 26 | @next_cursor.setter 27 | def next_cursor(self, value): 28 | self.__next_cursor = value 29 | 30 | @property 31 | def items(self): 32 | return self.__items 33 | 34 | @items.setter 35 | def items(self, value): 36 | if isinstance(value, list): 37 | self.__items = [RefundResponse(refund) for refund in value] 38 | else: 39 | self.__items = value 40 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/refund_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.response_object import ResponseObject 3 | from yookassa.domain.models.amount import Amount 4 | from yookassa.domain.models.deal import RefundDealInfo 5 | from yookassa.domain.models.refund_source import RefundSource 6 | 7 | 8 | class RefundResponse(ResponseObject): 9 | """ 10 | Class representing response object. 11 | 12 | Contains data 13 | """ 14 | __id = None 15 | 16 | __payment_id = None 17 | 18 | __status = None 19 | 20 | __receipt_registration = None 21 | 22 | __created_at = None 23 | 24 | __amount = None 25 | 26 | __description = None 27 | 28 | __sources = None 29 | 30 | __deal = None 31 | 32 | @property 33 | def id(self): 34 | return self.__id 35 | 36 | @id.setter 37 | def id(self, value): 38 | self.__id = value 39 | 40 | @property 41 | def payment_id(self): 42 | return self.__payment_id 43 | 44 | @payment_id.setter 45 | def payment_id(self, value): 46 | self.__payment_id = value 47 | 48 | @property 49 | def status(self): 50 | return self.__status 51 | 52 | @status.setter 53 | def status(self, value): 54 | self.__status = value 55 | 56 | @property 57 | def receipt_registration(self): 58 | return self.__receipt_registration 59 | 60 | @receipt_registration.setter 61 | def receipt_registration(self, value): 62 | self.__receipt_registration = value 63 | 64 | @property 65 | def created_at(self): 66 | return self.__created_at 67 | 68 | @created_at.setter 69 | def created_at(self, value): 70 | self.__created_at = value 71 | 72 | @property 73 | def amount(self): 74 | return self.__amount 75 | 76 | @amount.setter 77 | def amount(self, value): 78 | self.__amount = Amount(value) 79 | 80 | @property 81 | def description(self): 82 | return self.__description 83 | 84 | @description.setter 85 | def description(self, value): 86 | self.__description = value 87 | 88 | @property 89 | def sources(self): 90 | return self.__sources 91 | 92 | @sources.setter 93 | def sources(self, value): 94 | if isinstance(value, list): 95 | self.__sources = [RefundSource(item) for item in value] 96 | else: 97 | self.__sources = value 98 | 99 | @property 100 | def deal(self): 101 | return self.__deal 102 | 103 | @deal.setter 104 | def deal(self, value): 105 | self.__deal = RefundDealInfo(value) 106 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/transfer_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common import BaseObject 3 | from yookassa.domain.models.amount import Amount 4 | 5 | 6 | class TransferResponse(BaseObject): 7 | """ 8 | Class representing payment transfer wrapper object 9 | 10 | Used in Payment 11 | """ 12 | __account_id = None 13 | 14 | __amount = None 15 | 16 | __platform_fee_amount = None 17 | 18 | __status = None 19 | 20 | __metadata = None 21 | 22 | @property 23 | def account_id(self): 24 | return self.__account_id 25 | 26 | @account_id.setter 27 | def account_id(self, value): 28 | self.__account_id = str(value) 29 | 30 | @property 31 | def amount(self): 32 | return self.__amount 33 | 34 | @amount.setter 35 | def amount(self, value): 36 | if isinstance(value, dict): 37 | self.__amount = Amount(value) 38 | elif isinstance(value, Amount): 39 | self.__amount = value 40 | else: 41 | raise TypeError('Invalid amount value type') 42 | 43 | @property 44 | def platform_fee_amount(self): 45 | return self.__platform_fee_amount 46 | 47 | @platform_fee_amount.setter 48 | def platform_fee_amount(self, value): 49 | if isinstance(value, dict): 50 | self.__platform_fee_amount = Amount(value) 51 | elif isinstance(value, Amount): 52 | self.__platform_fee_amount = value 53 | else: 54 | raise TypeError('Invalid platform_fee_amount value type') 55 | 56 | @property 57 | def status(self): 58 | return self.__status 59 | 60 | @status.setter 61 | def status(self, value): 62 | self.__status = str(value) 63 | 64 | @property 65 | def metadata(self): 66 | return self.__metadata 67 | 68 | @metadata.setter 69 | def metadata(self, value): 70 | if type(value) is dict: 71 | self.__metadata = value 72 | 73 | 74 | class TransferStatus(object): 75 | """ 76 | Class representing transfer.status values enum 77 | """ 78 | PENDING = 'pending' 79 | WAITING_FOR_CAPTURE = 'waiting_for_capture' 80 | SUCCEEDED = 'succeeded' 81 | CANCELED = 'canceled' 82 | -------------------------------------------------------------------------------- /src/yookassa/domain/response/webhook_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.domain.common.response_object import ResponseObject 3 | 4 | 5 | class WebhookResponse(ResponseObject): 6 | __id = None 7 | 8 | __url = None 9 | 10 | __event = None 11 | 12 | @property 13 | def id(self): 14 | return self.__id 15 | 16 | @id.setter 17 | def id(self, value): 18 | self.__id = value 19 | 20 | @property 21 | def event(self): 22 | return self.__event 23 | 24 | @event.setter 25 | def event(self, value): 26 | self.__event = value 27 | 28 | @property 29 | def url(self): 30 | return self.__event 31 | 32 | @url.setter 33 | def url(self, value): 34 | self.__url = value 35 | 36 | 37 | class WebhookList(ResponseObject): 38 | __type = None 39 | 40 | __items = None 41 | 42 | @property 43 | def type(self): 44 | return self.__type 45 | 46 | @type.setter 47 | def type(self, value): 48 | self.__type = value 49 | 50 | @property 51 | def items(self): 52 | return self.__items 53 | 54 | @items.setter 55 | def items(self, value): 56 | if isinstance(value, list): 57 | self.__items = [WebhookResponse(webhook) for webhook in value] 58 | else: 59 | self.__items = value 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/yookassa/payout.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import uuid 3 | 4 | from yookassa.client import ApiClient 5 | from yookassa.domain.common.http_verb import HttpVerb 6 | from yookassa.domain.request import PayoutRequest 7 | from yookassa.domain.response import PayoutResponse 8 | 9 | 10 | class Payout: 11 | base_path = '/payouts' 12 | 13 | def __init__(self): 14 | self.client = ApiClient() 15 | 16 | @classmethod 17 | def find_one(cls, payout_id): 18 | """ 19 | Get receipt information 20 | 21 | :param payout_id: 22 | :return: PayoutResponse 23 | """ 24 | instance = cls() 25 | if not isinstance(payout_id, str) or not payout_id: 26 | raise ValueError('Invalid payment_id value') 27 | 28 | path = instance.base_path + '/' + payout_id 29 | response = instance.client.request(HttpVerb.GET, path) 30 | return PayoutResponse(response) 31 | 32 | @classmethod 33 | def create(cls, params, idempotency_key=None): 34 | """ 35 | Create receipt 36 | 37 | :param params: data passed to API 38 | :param idempotency_key: 39 | :return: PayoutResponse 40 | """ 41 | instance = cls() 42 | path = cls.base_path 43 | 44 | if not idempotency_key: 45 | idempotency_key = uuid.uuid4() 46 | 47 | headers = { 48 | 'Idempotence-Key': str(idempotency_key) 49 | } 50 | 51 | if isinstance(params, dict): 52 | params_object = PayoutRequest(params) 53 | elif isinstance(params, PayoutRequest): 54 | params_object = params 55 | else: 56 | raise TypeError('Invalid params value type') 57 | 58 | response = instance.client.request(HttpVerb.POST, path, None, headers, params_object) 59 | return PayoutResponse(response) 60 | -------------------------------------------------------------------------------- /src/yookassa/receipt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import uuid 3 | 4 | from yookassa.client import ApiClient 5 | from yookassa.domain.common.http_verb import HttpVerb 6 | from yookassa.domain.request.receipt_request import ReceiptRequest 7 | from yookassa.domain.response.receipt_list_response import ReceiptListResponse 8 | from yookassa.domain.response.receipt_response import ReceiptResponse 9 | 10 | 11 | class Receipt: 12 | base_path = '/receipts' 13 | 14 | def __init__(self): 15 | self.client = ApiClient() 16 | 17 | @classmethod 18 | def find_one(cls, receipt_id): 19 | """ 20 | Get receipt information 21 | 22 | :param receipt_id: 23 | :return: ReceiptResponse 24 | """ 25 | instance = cls() 26 | if not isinstance(receipt_id, str) or not receipt_id: 27 | raise ValueError('Invalid payment_id value') 28 | 29 | path = instance.base_path + '/' + receipt_id 30 | response = instance.client.request(HttpVerb.GET, path) 31 | return ReceiptResponse(response) 32 | 33 | @classmethod 34 | def create(cls, params, idempotency_key=None): 35 | """ 36 | Create receipt 37 | 38 | :param params: data passed to API 39 | :param idempotency_key: 40 | :return: ReceiptResponse 41 | """ 42 | instance = cls() 43 | path = cls.base_path 44 | 45 | if not idempotency_key: 46 | idempotency_key = uuid.uuid4() 47 | 48 | headers = { 49 | 'Idempotence-Key': str(idempotency_key) 50 | } 51 | 52 | if isinstance(params, dict): 53 | params_object = ReceiptRequest(params) 54 | elif isinstance(params, ReceiptRequest): 55 | params_object = params 56 | else: 57 | raise TypeError('Invalid params value type') 58 | 59 | response = instance.client.request(HttpVerb.POST, path, None, headers, params_object) 60 | return ReceiptResponse(response) 61 | 62 | @classmethod 63 | def list(cls, params): 64 | instance = cls() 65 | path = cls.base_path 66 | 67 | response = instance.client.request(HttpVerb.GET, path, params) 68 | return ReceiptListResponse(response) 69 | -------------------------------------------------------------------------------- /src/yookassa/refund.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import uuid 3 | 4 | from yookassa.client import ApiClient 5 | from yookassa.domain.common.http_verb import HttpVerb 6 | from yookassa.domain.request.refund_request import RefundRequest 7 | from yookassa.domain.response.refund_list_response import RefundListResponse 8 | from yookassa.domain.response.refund_response import RefundResponse 9 | 10 | 11 | class Refund: 12 | base_path = '/refunds' 13 | 14 | def __init__(self): 15 | self.client = ApiClient() 16 | 17 | @classmethod 18 | def create(cls, params, idempotency_key=None): 19 | """ 20 | Create refund 21 | 22 | :param params: data passed to API 23 | :param idempotency_key: 24 | :return: 25 | """ 26 | instance = cls() 27 | path = cls.base_path 28 | if not idempotency_key: 29 | idempotency_key = uuid.uuid4() 30 | headers = { 31 | 'Idempotence-Key': str(idempotency_key) 32 | } 33 | 34 | if isinstance(params, dict): 35 | params_object = RefundRequest(params) 36 | elif isinstance(params, RefundRequest): 37 | params_object = params 38 | else: 39 | raise TypeError('Invalid params value type') 40 | 41 | response = instance.client.request(HttpVerb.POST, path, None, headers, params_object) 42 | return RefundResponse(response) 43 | 44 | @classmethod 45 | def find_one(cls, refund_id): 46 | """ 47 | Get refund information 48 | 49 | :param refund_id: 50 | :return: RefundResponse 51 | """ 52 | instance = cls() 53 | if not isinstance(refund_id, str) or not refund_id: 54 | raise ValueError('Invalid payment_id value') 55 | path = instance.base_path + '/' + refund_id 56 | response = instance.client.request(HttpVerb.GET, path) 57 | return RefundResponse(response) 58 | 59 | @classmethod 60 | def list(cls, params): 61 | instance = cls() 62 | path = cls.base_path 63 | 64 | response = instance.client.request(HttpVerb.GET, path, params) 65 | return RefundListResponse(response) 66 | -------------------------------------------------------------------------------- /src/yookassa/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from yookassa.client import ApiClient 3 | from yookassa.domain.common.http_verb import HttpVerb 4 | 5 | 6 | class Settings: 7 | base_path = '/me' 8 | 9 | def __init__(self): 10 | self.client = ApiClient() 11 | 12 | @classmethod 13 | def get_account_settings(cls, params=None): 14 | """ 15 | Shop Info 16 | 17 | :param params: (dict | None) Параметры поиска. 18 | В настоящее время доступен только {'on_behalf_of': account_id} 19 | :return: dict 20 | """ 21 | instance = cls() 22 | path = cls.base_path 23 | 24 | response = instance.client.request(HttpVerb.GET, path, params) 25 | return response 26 | -------------------------------------------------------------------------------- /src/yookassa/webhook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import uuid 3 | 4 | from yookassa.client import ApiClient 5 | from yookassa.domain.common.http_verb import HttpVerb 6 | from yookassa.domain.request.webhook_request import WebhookRequest 7 | from yookassa.domain.response.webhook_response import WebhookResponse, WebhookList 8 | 9 | 10 | class Webhook: 11 | base_path = '/webhooks' 12 | 13 | def __init__(self): 14 | self.client = ApiClient() 15 | 16 | """ 17 | Get list of installed webhooks 18 | 19 | :return: WebhookList 20 | """ 21 | @classmethod 22 | def list(cls): 23 | instance = cls() 24 | path = cls.base_path 25 | 26 | response = instance.client.request(HttpVerb.GET, path) 27 | return WebhookList(response) 28 | 29 | """ 30 | Add webhook 31 | 32 | :param params: data passed to API 33 | :param idempotency_key: 34 | :return: WebhookResponse 35 | """ 36 | @classmethod 37 | def add(cls, params, idempotency_key=None): 38 | instance = cls() 39 | path = cls.base_path 40 | if not idempotency_key: 41 | idempotency_key = uuid.uuid4() 42 | headers = { 43 | 'Idempotence-Key': str(idempotency_key) 44 | } 45 | 46 | if isinstance(params, dict): 47 | params_object = WebhookRequest(params) 48 | elif isinstance(params, WebhookRequest): 49 | params_object = params 50 | else: 51 | raise TypeError('Invalid params value type') 52 | 53 | response = instance.client.request(HttpVerb.POST, path, None, headers, params_object) 54 | return WebhookResponse(response) 55 | 56 | """ 57 | Remove webhook 58 | 59 | :param webhook_id: 60 | :param idempotency_key: 61 | :return: WebhookResponse 62 | """ 63 | @classmethod 64 | def remove(cls, webhook_id, idempotency_key=None): 65 | instance = cls() 66 | path = cls.base_path + '/' + webhook_id 67 | if not idempotency_key: 68 | idempotency_key = uuid.uuid4() 69 | headers = { 70 | 'Idempotence-Key': str(idempotency_key) 71 | } 72 | 73 | response = instance.client.request(HttpVerb.DELETE, path, None, headers) 74 | return WebhookResponse(response) 75 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoomoney/yookassa-sdk-python/bde5a2750140c86ec4e642eb7de44c521e5ffc53/test/__init__.py -------------------------------------------------------------------------------- /test/unit/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Top-level package for YooKassa API Python Client Library.""" 3 | -------------------------------------------------------------------------------- /test/unit/test_airline.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models import Airline, Passenger, Leg 5 | 6 | 7 | class TestAirline(unittest.TestCase): 8 | def test_setters_inline_data(self): 9 | airline = Airline() 10 | airline.booking_reference = '123123' 11 | airline.ticket_number = '5551238432721' 12 | airline.passengers = [ 13 | { 14 | 'first_name': 'Joe', 15 | 'last_name': 'Doe' 16 | } 17 | ] 18 | airline.legs = [ 19 | { 20 | 'departure_airport': 'IVA', 21 | 'destination_airport': 'NYC', 22 | 'departure_date': '2017-01-02' 23 | } 24 | ] 25 | 26 | self.assertEqual({ 27 | 'booking_reference': '123123', 28 | 'ticket_number': '5551238432721', 29 | 'passengers': [ 30 | { 31 | 'first_name': 'Joe', 32 | 'last_name': 'Doe' 33 | } 34 | ], 35 | 'legs': [ 36 | { 37 | 'departure_airport': 'IVA', 38 | 'destination_airport': 'NYC', 39 | 'departure_date': '2017-01-02' 40 | } 41 | ] 42 | }, dict(airline)) 43 | 44 | def test_setters_objects_data(self): 45 | airline = Airline() 46 | airline.booking_reference = '123123' 47 | airline.ticket_number = '5551238432721' 48 | joe = Passenger() 49 | joe.first_name = 'Joe' 50 | joe.last_name = 'Doe' 51 | 52 | airline.passengers = [ 53 | joe 54 | ] 55 | 56 | leg = Leg() 57 | leg.departure_airport = 'IVA' 58 | leg.destination_airport = 'NYC' 59 | leg.departure_date = '2017-01-02' 60 | 61 | airline.legs = [ 62 | leg 63 | ] 64 | 65 | self.assertEqual({ 66 | 'booking_reference': '123123', 67 | 'ticket_number': '5551238432721', 68 | 'passengers': [ 69 | { 70 | 'first_name': 'Joe', 71 | 'last_name': 'Doe' 72 | } 73 | ], 74 | 'legs': [ 75 | { 76 | 'departure_airport': 'IVA', 77 | 'destination_airport': 'NYC', 78 | 'departure_date': '2017-01-02' 79 | } 80 | ] 81 | }, dict(airline)) 82 | -------------------------------------------------------------------------------- /test/unit/test_amount.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models import Amount 5 | from yookassa.domain.models import Currency 6 | 7 | 8 | class TestAmount(unittest.TestCase): 9 | 10 | def test_amount_cast(self): 11 | amount = Amount() 12 | amount.value = 0.1 13 | amount.currency = Currency.RUB 14 | 15 | self.assertEqual({'value': '0.10', 'currency': Currency.RUB}, dict(amount)) 16 | self.assertEqual(0.1, float(amount.value)) 17 | 18 | def test_amount_value(self): 19 | amount = Amount({ 20 | "value": '100.01', 21 | "currency": Currency.RUB 22 | }) 23 | 24 | self.assertEqual({"value": "100.01", "currency": Currency.RUB}, dict(amount)) 25 | self.assertEqual(float(amount.value), 100.01) 26 | -------------------------------------------------------------------------------- /test/unit/test_base_object.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import unittest 4 | 5 | from yookassa.domain.common import BaseObject 6 | 7 | 8 | class MyBaseObject(BaseObject): 9 | __test = None 10 | __int_value = None 11 | __float_value = None 12 | __base_object = None 13 | __values_list = None 14 | __base_objects_list = None 15 | 16 | @property 17 | def test(self): 18 | return self.__test 19 | 20 | @test.setter 21 | def test(self, value): 22 | self.__test = value 23 | 24 | @property 25 | def int_value(self): 26 | return self.__int_value 27 | 28 | @int_value.setter 29 | def int_value(self, value): 30 | self.__int_value = value 31 | 32 | @property 33 | def float_value(self): 34 | return self.__float_value 35 | 36 | @float_value.setter 37 | def float_value(self, value): 38 | self.__float_value = value 39 | 40 | @property 41 | def base_object(self): 42 | return self.__base_object 43 | 44 | @base_object.setter 45 | def base_object(self, value): 46 | self.__base_object = MyBaseObject(value) 47 | 48 | @property 49 | def values_list(self): 50 | return self.__values_list 51 | 52 | @values_list.setter 53 | def values_list(self, value): 54 | self.__values_list = value 55 | 56 | @property 57 | def base_objects_list(self): 58 | return self.__base_objects_list 59 | 60 | @base_objects_list.setter 61 | def base_objects_list(self, value): 62 | self.__base_objects_list = [MyBaseObject(item) for item in value] 63 | 64 | 65 | class TestBaseObject(unittest.TestCase): 66 | def setUp(self): 67 | self.fixture_args = { 68 | 'test': 'test', 69 | 'int_value': 123, 70 | 'float_value': 1.01, 71 | 'base_object': { 72 | 'test': 'test' 73 | }, 74 | 'values_list': [1, 2, 3], 75 | 'base_objects_list': [{'test': 'test'}, {'test': 'test'}, {'test': 'test'}] 76 | } 77 | 78 | def test_cas_to_dict_args(self): 79 | base_object = MyBaseObject(self.fixture_args) 80 | self.assertIsInstance(base_object.base_object, MyBaseObject) 81 | for item in base_object.base_objects_list: 82 | self.assertIsInstance(item, MyBaseObject) 83 | self.assertEqual(self.fixture_args, dict(base_object)) 84 | 85 | def test_cas_to_dict_kwargs(self): 86 | base_object = MyBaseObject(**self.fixture_args) 87 | self.assertIsInstance(base_object.base_object, MyBaseObject) 88 | for item in base_object.base_objects_list: 89 | self.assertIsInstance(item, MyBaseObject) 90 | self.assertEqual(self.fixture_args, dict(base_object)) 91 | 92 | def test_json(self): 93 | base_object = MyBaseObject(**self.fixture_args) 94 | my_json = base_object.json() 95 | 96 | self.assertIsInstance(my_json, str) 97 | self.assertEqual(dict(base_object), dict(json.loads(my_json))) 98 | -------------------------------------------------------------------------------- /test/unit/test_capture_payment_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.currency import Currency 5 | from yookassa.domain.request.capture_payment_builder import CapturePaymentBuilder 6 | from yookassa.domain.request.capture_payment_request import CapturePaymentRequest 7 | 8 | 9 | class TestCapturePaymentBuilder(unittest.TestCase): 10 | def test_build_object(self): 11 | builder = CapturePaymentBuilder() 12 | builder \ 13 | .set_amount({'value': 0.1, 'currency': Currency.RUB}) \ 14 | .set_receipt({ 15 | 'phone': '79990000000', 'email': 'test@email.com', 16 | 'tax_system_code': 1, 17 | 'items': [ 18 | { 19 | "description": "Product 1", 20 | "quantity": 2.0, 21 | "amount": { 22 | "value": 250.0, 23 | "currency": Currency.RUB 24 | }, 25 | "vat_code": 2 26 | }, 27 | { 28 | "description": "Product 2", 29 | "quantity": 1.0, 30 | "amount": { 31 | "value": 100.0, 32 | "currency": Currency.RUB 33 | }, 34 | "vat_code": 2 35 | } 36 | ] 37 | }) 38 | 39 | request = builder.build() 40 | 41 | self.assertIsInstance(request, CapturePaymentRequest) 42 | self.assertEqual( 43 | { 44 | 'amount': {'value': '0.10', 'currency': Currency.RUB}, 45 | 'receipt': { 46 | 'customer': {'phone': '79990000000', 'email': 'test@email.com'}, 47 | 'phone': '79990000000', 48 | 'email': 'test@email.com', 49 | 'items': [ 50 | { 51 | "description": "Product 1", 52 | "quantity": "2.0", 53 | "amount": { 54 | "value": "250.00", 55 | "currency": Currency.RUB 56 | }, 57 | "vat_code": 2 58 | }, 59 | { 60 | "description": "Product 2", 61 | "quantity": "1.0", 62 | "amount": { 63 | "value": "100.00", 64 | "currency": Currency.RUB 65 | }, 66 | "vat_code": 2 67 | } 68 | ], 69 | 'tax_system_code': 1 70 | }, 71 | 'transfers': [] 72 | }, dict(request)) 73 | -------------------------------------------------------------------------------- /test/unit/test_client.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | import unittest 4 | 5 | from requests import Response 6 | 7 | from yookassa.domain.common.user_agent import Version 8 | 9 | if sys.version_info >= (3, 3): 10 | from unittest.mock import patch 11 | else: 12 | from mock import patch 13 | 14 | from yookassa.client import ApiClient 15 | from yookassa.configuration import Configuration 16 | from yookassa.domain.common.http_verb import HttpVerb 17 | from yookassa.domain.common.request_object import RequestObject 18 | 19 | 20 | class TestClient(unittest.TestCase): 21 | 22 | def setUp(self): 23 | Configuration.configure(account_id='test_account_id', secret_key='test_secret_key') 24 | Configuration.agent_framework = Version('YooMoney.Framework', '0.0.1') 25 | Configuration.agent_cms = Version('YooMoney.Cms', '0.0.2') 26 | Configuration.agent_module = Version('YooMoney.Module', '0.0.3') 27 | 28 | def test_request(self): 29 | client = ApiClient() 30 | with patch('yookassa.client.ApiClient.request') as request_mock: 31 | request_mock.return_value = { 32 | 'amount': {'currency': 'RUB', 'value': 1.0}, 33 | 'created_at': '2017-11-30T15:45:31.130Z', 34 | 'id': '21b23b5b-000f-5061-a000-0674e49a8c10', 35 | 'metadata': {'float_value': '123.32', 'key': 'data'}, 36 | 'paid': False, 37 | 'payment_method': {'type': 'bank_card'}, 38 | 'recipient': {'account_id': '156833', 'gateway_id': '468284'}, 39 | 'status': 'canceled' 40 | } 41 | 42 | client.request(HttpVerb.POST, '/path', RequestObject(), {'header': 'header'}) 43 | 44 | def test_execute(self): 45 | client = ApiClient() 46 | with patch('yookassa.client.ApiClient.execute') as request_mock: 47 | res = Response() 48 | res.status_code = 200 49 | res._content = b"{}" 50 | request_mock.return_value = res 51 | 52 | client.request(HttpVerb.POST, '/path', RequestObject({"param": "param"}), {'header': 'header'}) 53 | -------------------------------------------------------------------------------- /test/unit/test_configuration.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.configuration import Configuration, ConfigurationError 5 | 6 | 7 | class TestConfiguration(unittest.TestCase): 8 | def test_configuration(self): 9 | Configuration.configure(account_id='test_account', secret_key='test_key', timeout=1000, max_attempts=2) 10 | configuration = Configuration.instantiate() 11 | 12 | self.assertEqual(configuration.account_id, 'test_account') 13 | self.assertEqual(configuration.secret_key, 'test_key') 14 | self.assertEqual(configuration.timeout, 1000) 15 | self.assertEqual(configuration.max_attempts, 2) 16 | 17 | def test_empty_credentials(self): 18 | with self.assertRaises(ConfigurationError): 19 | Configuration.configure(account_id=None, secret_key=None) 20 | configuration = Configuration.instantiate() 21 | -------------------------------------------------------------------------------- /test/unit/test_confirmation.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common.confirmation_type import ConfirmationType 5 | from yookassa.domain.models.confirmation.request.confirmation_redirect import \ 6 | ConfirmationRedirect as RequestConfirmationRedirect 7 | from yookassa.domain.models.confirmation.response.confirmation_qr import \ 8 | ConfirmationQr as ResponseConfirmationQr 9 | from yookassa.domain.models.confirmation.response.confirmation_redirect import \ 10 | ConfirmationRedirect as ResponseConfirmationRedirect 11 | 12 | 13 | class TestConfirmation(unittest.TestCase): 14 | def test_confirmation_request(self): 15 | confirmation = RequestConfirmationRedirect() 16 | confirmation.type = ConfirmationType.REDIRECT 17 | confirmation.locale = 'ru_RU' 18 | confirmation.enforce = True 19 | confirmation.return_url = 'return.url' 20 | 21 | self.assertEqual(confirmation.type, ConfirmationType.REDIRECT) 22 | self.assertTrue(confirmation.enforce) 23 | self.assertEqual( 24 | {'type': ConfirmationType.REDIRECT, 'locale': 'ru_RU', 'enforce': True, 'return_url': 'return.url'}, 25 | dict(confirmation) 26 | ) 27 | 28 | with self.assertRaises(ValueError): 29 | confirmation.return_url = '' 30 | 31 | def test_confirmation_response(self): 32 | confirmation = ResponseConfirmationRedirect() 33 | confirmation.type = ConfirmationType.REDIRECT 34 | confirmation.enforce = True 35 | confirmation.return_url = 'return.url' 36 | confirmation.confirmation_url = 'confirmation.url' 37 | self.assertEqual(confirmation.type, ConfirmationType.REDIRECT) 38 | self.assertTrue(confirmation.enforce) 39 | self.assertEqual( 40 | { 41 | 'type': ConfirmationType.REDIRECT, 42 | 'enforce': True, 43 | 'return_url': 'return.url', 44 | 'confirmation_url': 'confirmation.url' 45 | }, 46 | dict(confirmation) 47 | ) 48 | 49 | with self.assertRaises(ValueError): 50 | confirmation.return_url = '' 51 | 52 | def test_confirmation_response_qr(self): 53 | confirmation = ResponseConfirmationQr() 54 | confirmation.type = ConfirmationType.QR 55 | confirmation.confirmation_data = 'confirmation.url' 56 | self.assertEqual(confirmation.type, ConfirmationType.QR) 57 | self.assertEqual( 58 | { 59 | 'type': ConfirmationType.QR, 60 | 'confirmation_data': 'confirmation.url' 61 | }, 62 | dict(confirmation) 63 | ) 64 | 65 | with self.assertRaises(ValueError): 66 | confirmation.confirmation_data = '' 67 | -------------------------------------------------------------------------------- /test/unit/test_confirmation_factory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common.confirmation_type import ConfirmationType 5 | from yookassa.domain.common.data_context import DataContext 6 | from yookassa.domain.models.confirmation.confirmation_factory import ConfirmationFactory 7 | from yookassa.domain.models.confirmation.request.confirmation_embedded import \ 8 | ConfirmationEmbedded as RequestConfirmationEmbedded 9 | from yookassa.domain.models.confirmation.request.confirmation_external import \ 10 | ConfirmationExternal as RequestConfirmationExternal 11 | from yookassa.domain.models.confirmation.request.confirmation_qr import \ 12 | ConfirmationQr as RequestConfirmationQr 13 | from yookassa.domain.models.confirmation.request.confirmation_redirect import \ 14 | ConfirmationRedirect as RequestConfirmationRedirect 15 | from yookassa.domain.models.confirmation.response.confirmation_embedded import \ 16 | ConfirmationEmbedded as ResponseConfirmationEmbedded 17 | from yookassa.domain.models.confirmation.response.confirmation_external import \ 18 | ConfirmationExternal as ResponseConfirmationExternal 19 | from yookassa.domain.models.confirmation.response.confirmation_qr import \ 20 | ConfirmationQr as ResponseConfirmationQr 21 | from yookassa.domain.models.confirmation.response.confirmation_redirect import \ 22 | ConfirmationRedirect as ResponseConfirmationRedirect 23 | 24 | 25 | class TestConfirmationFactory(unittest.TestCase): 26 | def test_factory_method(self): 27 | req_redirect_instance = ConfirmationFactory().create({'type': ConfirmationType.REDIRECT}, DataContext.REQUEST) 28 | self.assertIsInstance(req_redirect_instance, RequestConfirmationRedirect) 29 | 30 | res_redirect_instance = ConfirmationFactory().create({'type': ConfirmationType.REDIRECT}, DataContext.RESPONSE) 31 | self.assertIsInstance(res_redirect_instance, ResponseConfirmationRedirect) 32 | 33 | req_external_instance = ConfirmationFactory().create({'type': ConfirmationType.EXTERNAL}, DataContext.REQUEST) 34 | self.assertIsInstance(req_external_instance, RequestConfirmationExternal) 35 | 36 | res_external_instance = ConfirmationFactory().create({'type': ConfirmationType.EXTERNAL}, DataContext.RESPONSE) 37 | self.assertIsInstance(res_external_instance, ResponseConfirmationExternal) 38 | 39 | res_redirect_instance = ConfirmationFactory().create({'type': ConfirmationType.EMBEDDED}, DataContext.REQUEST) 40 | self.assertIsInstance(res_redirect_instance, RequestConfirmationEmbedded) 41 | 42 | res_external_instance = ConfirmationFactory().create({'type': ConfirmationType.EMBEDDED}, DataContext.RESPONSE) 43 | self.assertIsInstance(res_external_instance, ResponseConfirmationEmbedded) 44 | 45 | res_redirect_instance = ConfirmationFactory().create({'type': ConfirmationType.QR}, DataContext.REQUEST) 46 | self.assertIsInstance(res_redirect_instance, RequestConfirmationQr) 47 | 48 | res_external_instance = ConfirmationFactory().create({'type': ConfirmationType.QR}, DataContext.RESPONSE) 49 | self.assertIsInstance(res_external_instance, ResponseConfirmationQr) 50 | -------------------------------------------------------------------------------- /test/unit/test_context.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common.context import Context 5 | 6 | 7 | class MyContext(Context): 8 | @property 9 | def property1(self): 10 | return 'property1' 11 | 12 | @property 13 | def property2(self): 14 | return 'property2' 15 | 16 | 17 | class TestContext(unittest.TestCase): 18 | def test_get_context_data(self): 19 | context = MyContext(contexts=('property1', 'property2')) 20 | self.assertEqual('property1', context.get_context_data('property1')) 21 | self.assertEqual('property2', context.get_context_data('property2')) 22 | -------------------------------------------------------------------------------- /test/unit/test_credit_card.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.payment_data.card_type import CardType, CardSource 5 | from yookassa.domain.models.payment_data.request.credit_card import CreditCard as RequestCreditCard 6 | from yookassa.domain.models.payment_data.response.credit_card import CreditCard as ResponseCreditCard 7 | 8 | 9 | class TestCreditCard(unittest.TestCase): 10 | def test_credit_card_valid_params(self): 11 | credit_card = RequestCreditCard() 12 | credit_card.number = '8888888888880000' 13 | credit_card.expiry_year = '2018' 14 | credit_card.expiry_month = '10' 15 | credit_card.csc = '111' 16 | credit_card.cardholder = 'test' 17 | 18 | self.assertEqual({ 19 | 'number': '8888888888880000', 20 | 'expiry_year': '2018', 21 | 'expiry_month': '10', 22 | 'csc': '111', 23 | 'cardholder': 'test' 24 | }, dict(credit_card)) 25 | 26 | credit_card = ResponseCreditCard() 27 | credit_card.last4 = '0000' 28 | credit_card.expiry_year = '2010' 29 | credit_card.expiry_month = '02' 30 | credit_card.card_type = CardType.VISA 31 | credit_card.issuer_country = 'RU' 32 | credit_card.issuer_name = 'Sberbank' 33 | credit_card.source = CardSource.APPLE_PAY 34 | 35 | self.assertEqual({ 36 | 'last4': '0000', 37 | 'expiry_year': '2010', 38 | 'expiry_month': '02', 39 | 'card_type': CardType.VISA, 40 | 'issuer_country': 'RU', 41 | 'issuer_name': 'Sberbank', 42 | 'source': 'apple_pay' 43 | }, dict(credit_card)) 44 | 45 | def test_credit_card_invalid_params(self): 46 | credit_card = RequestCreditCard() 47 | 48 | with self.assertRaises(ValueError): 49 | credit_card.number = 'invalid number' 50 | 51 | with self.assertRaises(ValueError): 52 | credit_card.expiry_year = 'invalid expiry_year' 53 | 54 | with self.assertRaises(ValueError): 55 | credit_card.expiry_month = 'invalid expiry_month' 56 | 57 | with self.assertRaises(ValueError): 58 | credit_card.csc = 'invalid csc' 59 | 60 | with self.assertRaises(ValueError): 61 | credit_card.cardholder = '123' 62 | 63 | credit_card = ResponseCreditCard() 64 | 65 | with self.assertRaises(ValueError): 66 | credit_card.last4 = '00001' 67 | 68 | with self.assertRaises(ValueError): 69 | credit_card.expiry_year = 'invalid expiry_year' 70 | 71 | with self.assertRaises(ValueError): 72 | credit_card.expiry_month = 'invalid expiry_month' 73 | 74 | with self.assertRaises(ValueError): 75 | credit_card.issuer_country = 'invalid issuer_country' 76 | -------------------------------------------------------------------------------- /test/unit/test_deal_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from yookassa.domain.models.deal import DealType, FeeMoment 4 | from yookassa.domain.request import DealRequest 5 | 6 | 7 | class TestDealRequest(unittest.TestCase): 8 | 9 | def test_request_cast(self): 10 | self.maxDiff = None 11 | request = DealRequest() 12 | request.type = DealType.SAFE_DEAL 13 | request.fee_moment = FeeMoment.DEAL_CLOSED 14 | request.description = 'Test description' 15 | request.metadata = {'key': 'value'} 16 | 17 | self.assertEqual({ 18 | 'type': 'safe_deal', 19 | 'fee_moment': 'deal_closed', 20 | 'description': 'Test description', 21 | 'metadata': {'key': 'value'}, 22 | }, dict(request)) 23 | 24 | def test_request_setters(self): 25 | request = DealRequest({ 26 | 'type': 'safe_deal', 27 | 'fee_moment': 'deal_closed', 28 | 'description': 'Test description', 29 | 'metadata': {'key': 'value'}, 30 | }) 31 | 32 | with self.assertRaises(ValueError): 33 | request.description = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ' \ 34 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ' 35 | 36 | def test_request_validate(self): 37 | request = DealRequest() 38 | 39 | with self.assertRaises(ValueError): 40 | request.validate() 41 | 42 | request.description = 'Test description' 43 | 44 | with self.assertRaises(ValueError): 45 | request.validate() 46 | 47 | request.metadata = {'key': 'value'} 48 | with self.assertRaises(ValueError): 49 | request.validate() 50 | 51 | request.fee_moment = FeeMoment.DEAL_CLOSED 52 | with self.assertRaises(ValueError): 53 | request.validate() 54 | 55 | request = DealRequest() 56 | request.type = DealType.SAFE_DEAL 57 | request.description = 'Test description' 58 | request.metadata = {'key': 'value'} 59 | with self.assertRaises(ValueError): 60 | request.validate() 61 | 62 | request = DealRequest() 63 | request.fee_moment = FeeMoment.DEAL_CLOSED 64 | request.description = 'Test description' 65 | request.metadata = {'key': 'value'} 66 | with self.assertRaises(ValueError): 67 | request.validate() 68 | -------------------------------------------------------------------------------- /test/unit/test_deal_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.deal import DealType, FeeMoment 5 | from yookassa.domain.request import DealRequestBuilder 6 | 7 | 8 | class TestDealRequestBuilder(unittest.TestCase): 9 | 10 | def test_build_object(self): 11 | self.maxDiff = None 12 | request = None 13 | builder = DealRequestBuilder() \ 14 | .set_type(DealType.SAFE_DEAL) \ 15 | .set_fee_moment(FeeMoment.PAYMENT_SUCCEEDED) \ 16 | .set_description('SAFE_DEAL 123554642-2432FF344R') \ 17 | .set_metadata({'order_id': '37'}) 18 | 19 | request = builder.build() 20 | 21 | self.assertEqual({ 22 | "type": "safe_deal", 23 | "fee_moment": "payment_succeeded", 24 | "metadata": { 25 | "order_id": "37" 26 | }, 27 | "description": "SAFE_DEAL 123554642-2432FF344R" 28 | }, dict(request)) 29 | -------------------------------------------------------------------------------- /test/unit/test_deal_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | from decimal import Decimal 4 | 5 | from yookassa.domain.models.amount import Amount 6 | from yookassa.domain.response.deal_response import DealResponse 7 | 8 | 9 | class TestDealResponse(unittest.TestCase): 10 | 11 | def test_response_cast(self): 12 | self.maxDiff = None 13 | response = DealResponse({ 14 | "type": "safe_deal", 15 | "fee_moment": "payment_succeeded", 16 | "id": "dl-285e5ee7-0022-5000-8000-01516a44b147", 17 | "balance": { 18 | "value": "800.00", 19 | "currency": "RUB" 20 | }, 21 | "payout_balance": { 22 | "value": "800.00", 23 | "currency": "RUB" 24 | }, 25 | "status": "opened", 26 | "created_at": "2021-06-18T07:28:39.390497Z", 27 | "expires_at": "2021-09-16T07:28:39.390513Z", 28 | "metadata": { 29 | "order_id": "37" 30 | }, 31 | "description": "SAFE_DEAL 123554642-2432FF344R", 32 | "test": False 33 | }) 34 | 35 | self.assertIsInstance(response.balance, Amount) 36 | self.assertIsInstance(response.balance, Amount) 37 | 38 | self.assertEqual(response.metadata, { 39 | "order_id": "37" 40 | }) 41 | self.assertFalse(response.test) 42 | self.assertEqual(response.id, "dl-285e5ee7-0022-5000-8000-01516a44b147") 43 | self.assertEqual(response.status, "opened") 44 | self.assertEqual(response.balance.value, 800.00) 45 | self.assertEqual(response.payout_balance.value, 800.00) 46 | self.assertEqual(response.description, "SAFE_DEAL 123554642-2432FF344R") 47 | self.assertEqual(response.created_at, "2021-06-18T07:28:39.390497Z") 48 | self.assertEqual(response.expires_at, "2021-09-16T07:28:39.390513Z") 49 | self.assertEqual(dict(response.payout_balance), { 50 | "value": "800.00", 51 | "currency": "RUB" 52 | }) 53 | 54 | -------------------------------------------------------------------------------- /test/unit/test_payment_data_factory.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common.data_context import DataContext 5 | from yookassa.domain.common.payment_method_type import PaymentMethodType 6 | from yookassa.domain.models.payment_data.payment_data_factory import PaymentDataFactory 7 | from yookassa.domain.models.payment_data.request.payment_data_yoomoney_wallet import PaymentDataYooMoneyWallet 8 | from yookassa.domain.models.payment_data.response.payment_data_webmoney import PaymentDataWebmoney 9 | from yookassa.domain.models.payment_data.response.payment_data_sbp import PaymentDataSbp 10 | 11 | 12 | class TestPaymentDataFactory(unittest.TestCase): 13 | def test_factory_method(self): 14 | factory = PaymentDataFactory() 15 | request_payment_data = factory.create({'type': PaymentMethodType.YOO_MONEY}, DataContext.REQUEST) 16 | self.assertIsInstance(request_payment_data, PaymentDataYooMoneyWallet) 17 | 18 | response_payment_data = factory.create({'type': PaymentMethodType.WEBMONEY}, DataContext.RESPONSE) 19 | self.assertIsInstance(response_payment_data, PaymentDataWebmoney) 20 | 21 | response_payment_data = factory.create({'type': PaymentMethodType.SBP}, DataContext.RESPONSE) 22 | self.assertIsInstance(response_payment_data, PaymentDataSbp) 23 | -------------------------------------------------------------------------------- /test/unit/test_payout_request.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common import PaymentMethodType 5 | from yookassa.domain.models.amount import Amount 6 | from yookassa.domain.models.currency import Currency 7 | from yookassa.domain.models.deal import PayoutDealInfo 8 | 9 | from yookassa.domain.models.payout_data.request.payout_destination_yoomoney_wallet import \ 10 | PayoutDestinationYooMoneyWallet 11 | from yookassa.domain.request import PayoutRequest 12 | 13 | 14 | class TestPayoutRequest(unittest.TestCase): 15 | 16 | def test_request_cast(self): 17 | self.maxDiff = None 18 | request = PayoutRequest() 19 | request.amount = Amount({"value": "320.00", "currency": "RUB"}) 20 | request.description = "Выплата по заказу №37" 21 | request.payout_token = "<Синоним банковской карты>" 22 | request.metadata = {"order_id": "37"} 23 | request.deal = PayoutDealInfo({'id': 'dl-285e5ee7-0022-5000-8000-01516a44b147'}) 24 | 25 | self.assertEqual({ 26 | "amount": { 27 | "value": "320.00", 28 | "currency": Currency.RUB 29 | }, 30 | "payout_token": "<Синоним банковской карты>", 31 | "description": "Выплата по заказу №37", 32 | "metadata": { 33 | "order_id": "37" 34 | }, 35 | "deal": { 36 | "id": "dl-285e5ee7-0022-5000-8000-01516a44b147" 37 | } 38 | }, dict(request)) 39 | 40 | def test_request_setters(self): 41 | request = PayoutRequest({ 42 | "amount": {"value": 320.0, "currency": Currency.RUB}, 43 | "payout_destination_data": {'type': PaymentMethodType.YOO_MONEY, 'account_number': '41001614575714'}, 44 | "description": "Выплата по заказу №37", 45 | "metadata": { 46 | "order_id": "37" 47 | }, 48 | "deal": { 49 | "id": "dl-285e5ee7-0022-5000-8000-01516a44b147" 50 | } 51 | }) 52 | 53 | self.assertIsInstance(request.amount, Amount) 54 | self.assertIsInstance(request.payout_destination_data, PayoutDestinationYooMoneyWallet) 55 | self.assertIsInstance(request.deal, PayoutDealInfo) 56 | 57 | with self.assertRaises(TypeError): 58 | request.amount = 'invalid amount' 59 | 60 | with self.assertRaises(TypeError): 61 | request.payout_destination_data = 'invalid payout_destination_data' 62 | 63 | with self.assertRaises(TypeError): 64 | request.payout_token = '' 65 | 66 | with self.assertRaises(ValueError): 67 | request.description = 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ' \ 68 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ' 69 | 70 | def test_request_validate(self): 71 | request = PayoutRequest() 72 | 73 | with self.assertRaises(ValueError): 74 | request.validate() 75 | 76 | request.amount = Amount({'value': 0.0, 'currency': Currency.RUB}) 77 | 78 | with self.assertRaises(ValueError): 79 | request.validate() 80 | 81 | request.amount = Amount({'value': 0.1, 'currency': Currency.RUB}) 82 | request.description = "Выплата по заказу №37" 83 | with self.assertRaises(ValueError): 84 | request.validate() 85 | 86 | request = PayoutRequest() 87 | request.amount = Amount({'value': 0.1, 'currency': Currency.RUB}) 88 | with self.assertRaises(ValueError): 89 | request.validate() 90 | 91 | request = PayoutRequest() 92 | request.amount = Amount({'value': 0.1, 'currency': Currency.RUB}) 93 | request.payout_token = '123' 94 | request.payout_destination_data = PayoutDestinationYooMoneyWallet() 95 | with self.assertRaises(ValueError): 96 | request.validate() 97 | -------------------------------------------------------------------------------- /test/unit/test_payout_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.currency import Currency 5 | from yookassa.domain.request import PayoutRequestBuilder 6 | 7 | 8 | class TestPayoutRequestBuilder(unittest.TestCase): 9 | 10 | def test_build_object(self): 11 | self.maxDiff = None 12 | 13 | builder = PayoutRequestBuilder() 14 | builder.set_amount({'value': 0.1, 'currency': Currency.RUB}) \ 15 | .set_description('Выплата по заказу №37') \ 16 | .set_payout_token('99091209012') \ 17 | .set_metadata({'key': 'value'}) \ 18 | .set_deal({ 19 | 'id': 'dl-285e5ee7-0022-5000-8000-01516a44b147' 20 | }) 21 | 22 | request = builder.build() 23 | 24 | self.assertEqual({ 25 | 'amount': {'value': '0.10', 'currency': Currency.RUB}, 26 | 'description': 'Выплата по заказу №37', 27 | 'payout_token': '99091209012', 28 | 'metadata': {'key': 'value'}, 29 | 'deal': { 30 | 'id': 'dl-285e5ee7-0022-5000-8000-01516a44b147' 31 | }, 32 | }, dict(request)) 33 | -------------------------------------------------------------------------------- /test/unit/test_payout_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.amount import Amount 5 | from yookassa.domain.models.cancellation_details import CancellationDetails 6 | from yookassa.domain.models.currency import Currency 7 | from yookassa.domain.models.deal import PayoutDealInfo 8 | from yookassa.domain.models.payout import PayoutStatus 9 | from yookassa.domain.models.payout_data.response.payout_destination_bank_card import PayoutDestinationBankCard 10 | from yookassa.domain.response.payout_response import PayoutResponse 11 | 12 | 13 | class TestPayoutResponse(unittest.TestCase): 14 | 15 | def test_response_cast(self): 16 | self.maxDiff = None 17 | response = PayoutResponse({ 18 | "id": "po-2855a19a-0003-5000-a000-0efa9e7f4264", 19 | "amount": { 20 | "value": "320.00", 21 | "currency": Currency.RUB 22 | }, 23 | "status": "succeeded", 24 | "payout_destination": { 25 | "type": "bank_card", 26 | "card": { 27 | "first6": "220220", 28 | "last4": "2537", 29 | "card_type": "MIR", 30 | "issuer_country": "RU", 31 | "issuer_name": "Sberbank Of Russia" 32 | } 33 | }, 34 | "cancellation_details": { 35 | "party": "yookassa", 36 | "reason": "one_time_limit_exceeded" 37 | }, 38 | "description": "Выплата по заказу №37", 39 | "created_at": "2021-06-21T16:22:50.512Z", 40 | "deal": { 41 | "id": "dl-285e5ee7-0022-5000-8000-01516a44b147" 42 | }, 43 | "metadata": { 44 | "order_id": "37" 45 | }, 46 | "test": False 47 | }) 48 | 49 | self.assertIsInstance(response.amount, Amount) 50 | self.assertIsInstance(response.payout_destination, PayoutDestinationBankCard) 51 | self.assertIsInstance(response.cancellation_details, CancellationDetails) 52 | self.assertIsInstance(response.deal, PayoutDealInfo) 53 | 54 | self.assertEqual(response.metadata, { 55 | "order_id": "37" 56 | }) 57 | self.assertFalse(response.test) 58 | self.assertEqual(response.id, "po-2855a19a-0003-5000-a000-0efa9e7f4264") 59 | self.assertEqual(response.status, PayoutStatus.SUCCEEDED) 60 | self.assertEqual(response.amount.value, 320.00) 61 | 62 | self.assertEqual(response.description, "Выплата по заказу №37") 63 | self.assertEqual(response.created_at, "2021-06-21T16:22:50.512Z") 64 | -------------------------------------------------------------------------------- /test/unit/test_receipt_request_builder.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common.receipt_type import ReceiptType 5 | from yookassa.domain.models.currency import Currency 6 | from yookassa.domain.models.settlement import Settlement, SettlementType 7 | from yookassa.domain.request.receipt_request_builder import ReceiptRequestBuilder 8 | 9 | 10 | class TestReceiptRequestBuilder(unittest.TestCase): 11 | 12 | def test_build_object(self): 13 | self.maxDiff = None 14 | builder = ReceiptRequestBuilder() 15 | builder.set_customer({'phone': '79990000000', 'email': 'test@email.com'}) \ 16 | .set_type(ReceiptType.PAYMENT) \ 17 | .set_send(True) \ 18 | .set_tax_system_code(1) \ 19 | .set_items([ 20 | { 21 | "description": "Product 1", 22 | "quantity": 2.0, 23 | "amount": { 24 | "value": 250.0, 25 | "currency": Currency.RUB 26 | }, 27 | "vat_code": 2 28 | }, 29 | { 30 | "description": "Product 2", 31 | "quantity": 1.0, 32 | "amount": { 33 | "value": 100.0, 34 | "currency": Currency.RUB 35 | }, 36 | "vat_code": 2 37 | } 38 | ]) \ 39 | .set_settlements([ 40 | Settlement({ 41 | 'type': SettlementType.CASHLESS, 42 | 'amount': { 43 | 'value': 350.0, 44 | 'currency': Currency.RUB 45 | } 46 | }) 47 | ]) \ 48 | .set_payment_id('215d8da0-000f-50be-b000-0003308c89be') 49 | 50 | request = builder.build() 51 | 52 | self.assertEqual({ 53 | 'customer': {'email': 'test@email.com', 'phone': '79990000000'}, 54 | 'type': 'payment', 55 | 'send': True, 56 | 'tax_system_code': 1, 57 | 'email': 'test@email.com', 58 | 'phone': '79990000000', 59 | 'items': [ 60 | { 61 | 'description': 'Product 1', 62 | 'quantity': '2.0', 63 | 'amount': { 64 | 'value': '250.00', 65 | 'currency': Currency.RUB 66 | }, 67 | 'vat_code': 2 68 | }, 69 | { 70 | 'description': 'Product 2', 71 | 'quantity': '1.0', 72 | 'amount': { 73 | 'value': '100.00', 74 | 'currency': Currency.RUB 75 | }, 76 | 'vat_code': 2 77 | } 78 | ], 79 | 'settlements': [ 80 | { 81 | 'type': 'cashless', 82 | 'amount': { 83 | 'value': '350.00', 84 | 'currency': 'RUB' 85 | } 86 | } 87 | ], 88 | 'payment_id': '215d8da0-000f-50be-b000-0003308c89be' 89 | }, dict(request)) 90 | -------------------------------------------------------------------------------- /test/unit/test_recepient.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.recipient import Recipient 5 | 6 | 7 | class TestRecipient(unittest.TestCase): 8 | def test_recipient_cast(self): 9 | recipient = Recipient() 10 | recipient.account_id = '213' 11 | recipient.gateway_id = '123' 12 | 13 | self.assertEqual({ 14 | 'account_id': '213', 15 | 'gateway_id': '123' 16 | }, dict(recipient)) 17 | -------------------------------------------------------------------------------- /test/unit/test_refund_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models import Amount, Currency, RefundSource, Settlement 5 | from yookassa.domain.models import RefundDealInfo 6 | from yookassa.domain.response import RefundResponse 7 | 8 | 9 | class TestRefundResponse(unittest.TestCase): 10 | def test_response_cast(self): 11 | response = RefundResponse({ 12 | 'id': '21b23b5b-000f-5061-a000-0674e49a8c10', 13 | 'payment_id': '21b23365-000f-500b-9000-070fa3554403', 14 | 'created_at': "2017-11-30T15:11:33+00:00", 15 | 'amount': { 16 | "value": 250.0, 17 | "currency": Currency.RUB 18 | }, 19 | 'receipt_registration': 'pending', 20 | 'description': 'test comment', 21 | 'status': 'pending', 22 | 'sources': [ 23 | { 24 | 'account_id': '79990000000', 25 | "amount": { 26 | "value": 100.01, 27 | "currency": Currency.RUB 28 | }, 29 | "platform_fee_amount": { 30 | "value": 10.01, 31 | "currency": Currency.RUB 32 | } 33 | } 34 | ], 35 | 'deal': { 36 | 'id': 'dl-28646d17-0022-5000-8000-01e154d1324b', 37 | 'refund_settlements': [{ 38 | 'type': 'payout', 39 | 'amount': { 40 | 'value': 80.0, 41 | 'currency': 'RUB' 42 | } 43 | }] 44 | } 45 | }) 46 | 47 | self.assertEqual(response.id, '21b23b5b-000f-5061-a000-0674e49a8c10') 48 | self.assertEqual(response.payment_id, '21b23365-000f-500b-9000-070fa3554403') 49 | self.assertEqual(response.created_at, "2017-11-30T15:11:33+00:00") 50 | self.assertEqual(response.receipt_registration, 'pending') 51 | self.assertEqual(response.description, 'test comment') 52 | self.assertIsInstance(response.amount, Amount) 53 | self.assertIsInstance(response.sources[0], RefundSource) 54 | self.assertEqual(response.status, 'pending') 55 | self.assertIsInstance(response.deal, RefundDealInfo) 56 | self.assertEqual(response.deal.id, 'dl-28646d17-0022-5000-8000-01e154d1324b') 57 | self.assertIsInstance(response.deal.refund_settlements[0], Settlement) 58 | 59 | with self.assertRaises(TypeError): 60 | response.deal.refund_settlements = 'invalid settlements' 61 | 62 | response.deal.refund_settlements = None 63 | self.assertEqual(response.deal.refund_settlements, []) 64 | -------------------------------------------------------------------------------- /test/unit/test_refund_source.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.amount import Amount 5 | from yookassa.domain.models.currency import Currency 6 | from yookassa.domain.models.refund_source import RefundSource 7 | 8 | 9 | class TestRefundSource(unittest.TestCase): 10 | 11 | def test_refund_source_cast(self): 12 | self.maxDiff = None 13 | src = RefundSource() 14 | src.account_id = '79990000000' 15 | src.amount = Amount({ 16 | "value": 100.01, 17 | "currency": Currency.RUB 18 | }) 19 | 20 | self.assertEqual({ 21 | 'account_id': '79990000000', 22 | "amount": { 23 | "value": "100.01", 24 | "currency": Currency.RUB 25 | } 26 | }, dict(src)) 27 | 28 | self.assertEqual('79990000000', src.account_id) 29 | 30 | self.assertEqual({"value": "100.01", "currency": Currency.RUB}, dict(src.amount)) 31 | self.assertEqual(float(src.amount.value), 100.01) 32 | 33 | with self.assertRaises(TypeError): 34 | src.amount = 'invalid type' 35 | -------------------------------------------------------------------------------- /test/unit/test_security_helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common import SecurityHelper 5 | 6 | 7 | class TestSecurityHelper(unittest.TestCase): 8 | 9 | def test_check_ip(self): 10 | sh = SecurityHelper() 11 | 12 | self.assertTrue(sh.is_ip_trusted('77.75.156.35')) 13 | self.assertTrue(sh.is_ip_trusted('77.75.153.75')) 14 | self.assertTrue(sh.is_ip_trusted('2a02:5180:0:2669::2a:dc6a')) 15 | 16 | self.assertFalse(sh.is_ip_trusted('77.75.156.36')) 17 | self.assertFalse(sh.is_ip_trusted('192.168.1.1')) 18 | self.assertFalse(sh.is_ip_trusted('2a02:4180:0:2969::2a:006a')) 19 | -------------------------------------------------------------------------------- /test/unit/test_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | import unittest 4 | 5 | if sys.version_info >= (3, 3): 6 | from unittest.mock import patch 7 | else: 8 | from mock import patch 9 | 10 | from yookassa import Settings, Configuration 11 | 12 | 13 | class TestSettings(unittest.TestCase): 14 | 15 | def setUp(self): 16 | Configuration.configure(account_id='test_account_id', secret_key='test_secret_key') 17 | 18 | def test_get_account_settings(self): 19 | self.maxDiff = None 20 | with patch('yookassa.client.ApiClient.request') as request_mock: 21 | request_mock.return_value = { 22 | "account_id": Configuration.account_id, 23 | "test": False, 24 | "fiscalization_enabled": False, 25 | "payment_methods": [ 26 | "yoo_money", 27 | "cash", 28 | "bank_card" 29 | ] 30 | } 31 | settings = Settings.get_account_settings() 32 | 33 | self.assertIsInstance(settings, dict) 34 | self.assertIsInstance(settings['payment_methods'], list) 35 | self.assertListEqual(settings['payment_methods'], ["yoo_money", "cash", "bank_card"]) 36 | self.assertEqual(settings['account_id'], Configuration.account_id) 37 | -------------------------------------------------------------------------------- /test/unit/test_transfer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models.amount import Amount 5 | from yookassa.domain.models.currency import Currency 6 | from yookassa.domain.models.transfer import Transfer 7 | 8 | 9 | class TestTransfer(unittest.TestCase): 10 | 11 | def test_receipt_cast(self): 12 | self.maxDiff = None 13 | transfer = Transfer() 14 | transfer.account_id = '79990000000' 15 | transfer.amount = Amount({ 16 | "value": '100.01', 17 | "currency": Currency.RUB 18 | }) 19 | transfer.metadata = { 20 | "meta1": 'metatest 1', 21 | "meta2": 'metatest 2' 22 | } 23 | 24 | self.assertEqual({ 25 | 'account_id': '79990000000', 26 | "amount": { 27 | "value": "100.01", 28 | "currency": Currency.RUB 29 | }, 30 | "metadata": { 31 | "meta1": 'metatest 1', 32 | "meta2": 'metatest 2' 33 | } 34 | }, dict(transfer)) 35 | 36 | self.assertEqual('79990000000', transfer.account_id) 37 | 38 | self.assertEqual({"value": "100.01", "currency": Currency.RUB}, dict(transfer.amount)) 39 | self.assertEqual(float(transfer.amount.value), 100.01) 40 | self.assertEqual({"meta1": 'metatest 1', "meta2": 'metatest 2'}, dict(transfer.metadata)) 41 | 42 | with self.assertRaises(TypeError): 43 | transfer.amount = 'invalid type' 44 | -------------------------------------------------------------------------------- /test/unit/test_transfer_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.models import Amount, Currency 5 | from yookassa.domain.response import TransferResponse, TransferStatus 6 | 7 | 8 | class TestTransferResponse(unittest.TestCase): 9 | 10 | def test_transfer_cast(self): 11 | self.maxDiff = None 12 | transfer = TransferResponse() 13 | transfer.status = TransferStatus.SUCCEEDED 14 | transfer.account_id = '79990000000' 15 | transfer.amount = Amount({ 16 | "value": '100.01', 17 | "currency": Currency.RUB 18 | }) 19 | transfer.metadata = { 20 | "meta1": 'metatest 1', 21 | "meta2": 'metatest 2' 22 | } 23 | 24 | self.assertEqual({ 25 | "account_id": "79990000000", 26 | "amount": { 27 | "value": "100.01", 28 | "currency": Currency.RUB 29 | }, 30 | "status": TransferStatus.SUCCEEDED, 31 | "metadata": { 32 | "meta1": 'metatest 1', 33 | "meta2": 'metatest 2' 34 | } 35 | }, dict(transfer)) 36 | 37 | self.assertEqual('79990000000', transfer.account_id) 38 | self.assertEqual(TransferStatus.SUCCEEDED, transfer.status) 39 | 40 | self.assertEqual({"value": "100.01", "currency": Currency.RUB}, dict(transfer.amount)) 41 | self.assertEqual(float(transfer.amount.value), 100.01) 42 | self.assertEqual({"meta1": 'metatest 1', "meta2": 'metatest 2'}, dict(transfer.metadata)) 43 | 44 | with self.assertRaises(TypeError): 45 | transfer.amount = 'invalid type' 46 | 47 | def test_transfer_value(self): 48 | self.maxDiff = None 49 | transfer = TransferResponse({ 50 | "account_id": "79990000000", 51 | "amount": { 52 | "value": 100.01, 53 | "currency": Currency.RUB 54 | }, 55 | "status": TransferStatus.SUCCEEDED, 56 | "metadata": { 57 | "meta1": 'metatest 1', 58 | "meta2": 'metatest 2' 59 | } 60 | }) 61 | 62 | self.assertEqual({ 63 | "account_id": "79990000000", 64 | "amount": { 65 | "value": "100.01", 66 | "currency": Currency.RUB 67 | }, 68 | "status": TransferStatus.SUCCEEDED, 69 | "metadata": { 70 | "meta1": 'metatest 1', 71 | "meta2": 'metatest 2' 72 | } 73 | }, dict(transfer)) 74 | 75 | self.assertEqual('79990000000', transfer.account_id) 76 | self.assertEqual(TransferStatus.SUCCEEDED, transfer.status) 77 | 78 | self.assertEqual({"value": "100.01", "currency": Currency.RUB}, dict(transfer.amount)) 79 | self.assertEqual(float(transfer.amount.value), 100.01) 80 | self.assertEqual({"meta1": 'metatest 1', "meta2": 'metatest 2'}, dict(transfer.metadata)) 81 | -------------------------------------------------------------------------------- /test/unit/test_user_agent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import unittest 3 | 4 | from yookassa.domain.common import UserAgent 5 | 6 | 7 | class TestUserAgent(unittest.TestCase): 8 | def test_create_version(self): 9 | agent = UserAgent() 10 | 11 | agent.set_framework('Django', '1.2.3').set_module('Payment Gateway', '0.1.2') 12 | 13 | self.assertEqual(str(agent.framework), 'Django/1.2.3') 14 | self.assertEqual(str(agent.module), 'Payment.Gateway/0.1.2') 15 | 16 | self.assertIsNone(agent.cms) 17 | 18 | agent.set_cms('Word/Press', '1 2 3') 19 | self.assertEqual(str(agent.cms), 'Word.Press/1.2.3') 20 | -------------------------------------------------------------------------------- /test/unit/test_webhook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import sys 3 | import unittest 4 | 5 | from yookassa.domain.request import WebhookRequest 6 | from yookassa.domain.response import WebhookList, WebhookResponse 7 | 8 | if sys.version_info >= (3, 3): 9 | from unittest.mock import patch 10 | else: 11 | from mock import patch 12 | 13 | from yookassa import Configuration, Webhook 14 | 15 | 16 | class TestWebhook(unittest.TestCase): 17 | 18 | def setUp(self): 19 | Configuration.configure(account_id='test_account_id', secret_key='test_secret_key') 20 | 21 | def test_list(self): 22 | self.maxDiff = None 23 | with patch('yookassa.client.ApiClient.request') as request_mock: 24 | request_mock.return_value = { 25 | "type": "list", 26 | "items": [ 27 | { 28 | "id": "wh-e44e8088-bd73-43b1-959a-954f3a7d0c54", 29 | "event": "payment.canceled", 30 | "url": "https://www.merchant-website.com/notification_url" 31 | }, 32 | { 33 | "id": "wh-22d6d597-000f-5000-9000-145f6df21d6f", 34 | "event": "payment.succeeded", 35 | "url": "https://www.merchant-website.com/notification_url" 36 | } 37 | ] 38 | } 39 | wh_list = Webhook.list() 40 | 41 | self.assertIsInstance(wh_list, WebhookList) 42 | self.assertEqual(wh_list.type, "list") 43 | self.assertIsInstance(wh_list.items[0], WebhookResponse) 44 | 45 | def test_add(self): 46 | self.maxDiff = None 47 | with patch('yookassa.client.ApiClient.request') as request_mock: 48 | request_mock.return_value = { 49 | "id": "wh-22d6d597-000f-5000-9000-145f6df21d6f", 50 | "event": "payment.succeeded", 51 | "url": "https://www.merchant-website.com/notification_url" 52 | } 53 | 54 | params = WebhookRequest({ 55 | "event": "payment.succeeded", 56 | "url": "https://www.merchant-website.com/notification_url", 57 | }) 58 | wh = Webhook.add(params) 59 | 60 | self.assertIsInstance(wh, WebhookResponse) 61 | self.assertEqual(wh.event, "payment.succeeded") 62 | 63 | params = { 64 | "event": "payment.succeeded", 65 | "url": "https://www.merchant-website.com/notification_url", 66 | } 67 | wh = Webhook.add(params) 68 | 69 | self.assertIsInstance(wh, WebhookResponse) 70 | self.assertEqual(wh.event, "payment.succeeded") 71 | 72 | with self.assertRaises(TypeError): 73 | Webhook.add('invalid data') 74 | 75 | def test_remove(self): 76 | self.maxDiff = None 77 | with patch('yookassa.client.ApiClient.request') as request_mock: 78 | request_mock.return_value = {} 79 | 80 | response = Webhook.remove("wh-22d6d597-000f-5000-9000-145f6df21d6f") 81 | 82 | self.assertIsInstance(response, WebhookResponse) 83 | --------------------------------------------------------------------------------