From a61bbaf4614db3b8cfc21ae4c04a728c1e544f57 Mon Sep 17 00:00:00 2001 From: Ivan Shamatov Date: Sat, 20 Nov 2021 14:14:59 +0300 Subject: [PATCH] Initial setup for docs (#22) * Initial setup for docs * running payments endpoints * documentation for deals and payouts --- docs/01-configuration.md | 214 ++++++++++++++++++++++++++ docs/02-payments.md | 229 ++++++++++++++++++++++++++++ docs/03-refunds.md | 128 ++++++++++++++++ docs/04-receipts.md | 180 ++++++++++++++++++++++ docs/05-deals.md | 103 +++++++++++++ docs/06-payouts.md | 73 +++++++++ docs/readme.md | 39 +++++ lib/yookassa/client.rb | 4 + lib/yookassa/entity/confirmation.rb | 8 +- lib/yookassa/partner_api.rb | 52 ------- 10 files changed, 974 insertions(+), 56 deletions(-) create mode 100644 docs/01-configuration.md create mode 100644 docs/02-payments.md create mode 100644 docs/03-refunds.md create mode 100644 docs/04-receipts.md create mode 100644 docs/05-deals.md create mode 100644 docs/06-payouts.md create mode 100644 docs/readme.md delete mode 100644 lib/yookassa/partner_api.rb diff --git a/docs/01-configuration.md b/docs/01-configuration.md new file mode 100644 index 0000000..a4913c4 --- /dev/null +++ b/docs/01-configuration.md @@ -0,0 +1,214 @@ +## Настройки SDK API ЮKassa + +[Справочник API ЮKassa](https://yookassa.ru/developers/api) + +С помощью этого SDK вы можете работать с онлайн-платежами: отправлять запросы на оплату, +сохранять платежную информацию для повторных списаний, совершать возвраты и многое другое. + +* [Аутентификация](#Аутентификация) +* [Статистические данные об используемом окружении](#Статистические-данные-об-используемом-окружении) +* [Получение информации о магазине](#Получение-информации-о-магазине) +* [Работа с Webhook](#Работа-с-Webhook) +* [Входящие уведомления](#Входящие-уведомления) + +--- + +### Аутентификация + +Для работы с API необходимо прописать в конфигурации данные аутентификации. Существует два способа аутентификации: +- shopId + секретный ключ +- OAuth-токен. [Подробнее в документации к API](https://yookassa.ru/developers/partners-api/basics) + +```ruby +# singleton +# shopId + секретный ключ +Yookassa.configure do |c| + c.shop_id = "XXXXXX" + c.api_key = "test_XXXXXXXX" +end + +# instance +client = Yookassa::Payments.new(shop_id: "XXXXXX", api_key: "test_XXXXXXXX") + +# или OAuth-токен +client = Yokassa::Webhooks.new(oauth_token: "token-XXXXXXXX") +``` + +--- + +### Статистические данные об используемом окружении (NOT IMPLEMENTED YET) + +Для поддержки качества, а также быстром реагировании на ошибки, SDK передает статистику в запросах к API ЮKassa. + +По молчанию, SDK передает в запросах версию операционной системы, версию Python, а также версию SDK. +Но вы можете передать дополнительные данные об используемом фреймворке, CMS, а также модуле в CMS. + +Например, это может выглядеть так: +```ruby + +Configuration.configure_user_agent( + framework=Version('Django', '2.2.3'), + cms=Version('Wagtail', '2.6.2'), + module=Version('Y.CMS', '0.0.1') +) +``` + +--- + +### Получение информации о магазине + +После установки конфигурации можно проверить корректность данных, а также получить информацию о магазине. + +```ruby +store = Yokassa::Stores.new(oauth_token: "token-XXXXXXXX") + +store_info = store.info +``` +В результате мы увидим примерно следующее: +```ruby +#0 dict(5) + ['account_id'] => str(6) "XXXXXX" + ['test'] => bool(True) + ['fiscalization_enabled'] => bool(True) + ['payment_methods'] => list(2) + [0] => str(9) "yoo_money" + [1] => str(9) "bank_card" + ['status'] => str(7) "enabled" +``` +[Подробнее в документации к API](https://yookassa.ru/developers/api?lang=ruby#me_object) + +--- + +### Работа с Webhook + +Если вы подключаетесь к API через Oauth-токен, то можете настроить получение уведомлений о смене статуса платежа или возврата. + +Например, ЮKassa может сообщить, когда объект платежа, созданный в вашем приложении, перейдет в статус `waiting_for_capture`. + +В данном примере мы устанавливаем вебхуки для succeeded и canceled уведомлений. +А так же проверяем, не установлены ли уже вебхуки. И если установлены на неверный адрес, удаляем. + +```ruby +url = "https://merchant-site.ru/payment-notification" +expected_events = [ + "payment.succeeded", + "payment.canceled" +] + +webhooks_client = Yokassa::Webhoooks.new(oauth_token: "token-XXXXXXXX") +webhooks = webhooks_client.list + +expected_events.each do |event| + hook_exists = false + + webhooks.items.each do |hook| + next if hook.event != event + + if url == hook.url + hook_exists = true + else + webhooks_client.delete(webhook_id: hook.id) + end + end + + webhooks_client.create(payload: {event: event, url: url}) unless hook_exists +end +``` + +В результате мы увидим примерно следующее: +```ruby +#0 object(WebhookList) (2) + _WebhookList__items => list(2) + [0] => object(WebhookResponse) (3) + _WebhookResponse__id => str(39) "wh-52e51c6e-29a2-4a0d-800b-01cf022b5613" + _WebhookResponse__event => str(16) "payment.canceled" + _WebhookResponse__url => str(66) "https://merchant-site.ru/payment-notification" + [1] => object(WebhookResponse) (3) + _WebhookResponse__id => str(39) "wh-c331b3ee-fb65-428d-b008-1b837d9c4d93" + _WebhookResponse__event => str(17) "payment.succeeded" + _WebhookResponse__url => str(66) "https://merchant-site.ru/payment-notification" + _WebhookList__type => str(4) "list" +``` +[Подробнее в документации к API](https://yookassa.ru/developers/api?lang=ruby#webhook) + +### Входящие уведомления + +Если вы хотите отслеживать состояние платежей и возвратов, вы можете подписаться на уведомления ([webhook](#Работа-с-Webhook), callback). + +Уведомления пригодятся в тех случаях, когда объект API изменяется без вашего участия. +Например, если пользователю нужно подтвердить платеж, процесс оплаты может занять от нескольких минут до нескольких часов. +Вместо того чтобы всё это время периодически отправлять GET-запросы, чтобы узнать статус платежа, вы можете просто дожидаться уведомления от ЮKassa. + +[Входящие уведомления в документации](https://yookassa.ru/developers/using-api/webhooks?lang=ruby) + +#### Использование + +Как только произойдет событие, на которое вы подписались, на URL, который вы указали при настройке, придет уведомление. +В нем будут все данные об объекте на момент, когда произошло событие. + +Вам нужно подтвердить, что вы получили уведомление. Для этого ответьте HTTP-кодом 200. ЮKassa проигнорирует всё, +что будет находиться в теле или заголовках ответа. Ответы с любыми другими HTTP-кодами будут считаться невалидными, +и ЮKassa продолжит доставлять уведомление в течение 24 часов, начиная с момента, когда событие произошло. + +#### Пример обработки уведомления с помощью SDK + +```ruby +def my_webhook_handler(request): + # Извлечение JSON объекта из тела запроса + event_json = json.loads(request.body) + try: + # Создание объекта класса уведомлений в зависимости от события + notification_object = WebhookNotification(event_json) + response_object = notification_object.object + if notification_object.event == WebhookNotificationEventType.PAYMENT_SUCCEEDED: + some_data = { + 'paymentId': response_object.id, + 'paymentStatus': response_object.status, + } + # Специфичная логика + # ... + elif notification_object.event == WebhookNotificationEventType.PAYMENT_WAITING_FOR_CAPTURE: + some_data = { + 'paymentId': response_object.id, + 'paymentStatus': response_object.status, + } + # Специфичная логика + # ... + elif notification_object.event == WebhookNotificationEventType.PAYMENT_CANCELED: + some_data = { + 'paymentId': response_object.id, + 'paymentStatus': response_object.status, + } + # Специфичная логика + # ... + elif notification_object.event == WebhookNotificationEventType.REFUND_SUCCEEDED: + some_data = { + 'refundId': response_object.id, + 'refundStatus': response_object.status, + 'paymentId': response_object.payment_id, + } + # Специфичная логика + # ... + else: + # Обработка ошибок + return HttpResponse(status=400) # Сообщаем кассе об ошибке + + # Специфичная логика + # ... + Configuration.configure('XXXXXX', 'test_XXXXXXXX') + # Получим актуальную информацию о платеже + payment_info = Payment.find_one(some_data['paymentId']) + if payment_info: + payment_status = payment_info.status + # Специфичная логика + # ... + else: + # Обработка ошибок + return HttpResponse(status=400) # Сообщаем кассе об ошибке + + except Exception: + # Обработка ошибок + return HttpResponse(status=400) # Сообщаем кассе об ошибке + + return HttpResponse(status=200) # Сообщаем кассе, что все хорошо +``` diff --git a/docs/02-payments.md b/docs/02-payments.md new file mode 100644 index 0000000..967629d --- /dev/null +++ b/docs/02-payments.md @@ -0,0 +1,229 @@ +## Работа с платежами + +SDK позволяет создавать, подтверждать, отменять платежи, а также получать информацию о них. + +Объект платежа `PaymentResponse` содержит всю информацию о платеже, актуальную на текущий момент времени. +Он формируется при создании платежа и приходит в ответ на любой запрос, связанный с платежами. + +* [Запрос на создание платежа](#Запрос-на-создание-платежа) +* [Запрос на создание платежа через билдер](#Запрос-на-создание-платежа-через-билдер) +* [Запрос на частичное подтверждение платежа](#Запрос-на-частичное-подтверждение-платежа) +* [Запрос на отмену незавершенного платежа](#Запрос-на-отмену-незавершенного-платежа) +* [Получить информацию о платеже](#Получить-информацию-о-платеже) +* [Получить список платежей с фильтрацией](#Получить-список-платежей-с-фильтрацией) + +--- + +### Запрос на создание платежа + +[Создание платежа в документации](https://yookassa.ru/developers/api?lang=ruby#create_payment) + +Чтобы принять оплату, необходимо создать объект платежа — `PaymentRequest`. Он содержит всю необходимую информацию +для проведения оплаты (сумму, валюту и статус). У платежа линейный жизненный цикл, +он последовательно переходит из статуса в статус. + +В ответ на запрос придет объект платежа - `PaymentResponse` в актуальном статусе. + +```ruby + +payload = { + "amount": { + "value": 1000, + "currency": "RUB" + }, + "confirmation": { + "type": "redirect", + "return_url": "https://merchant-site.ru/return_url" + }, + "capture": true, + "description": "Заказ №72", + "metadata": { + "orderNumber": "72" + }, + "receipt": { + "customer": { + "full_name": "Ivanov Ivan Ivanovich", + "email": "email@email.ru", + "phone": "79211234567", + "inn": "6321341814" + }, + "items": [ + { + "description": "Переносное зарядное устройство Хувей", + "quantity": "1.00", + "amount": { + "value": 1000, + "currency": "RUB" + }, + "vat_code": "2", + "payment_mode": "full_payment", + "payment_subject": "commodity", + "country_of_origin_code": "CN", + "product_code": "44 4D 01 00 21 FA 41 00 23 05 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 00 AB 00", + "customs_declaration_number": "10714040/140917/0090376", + "excise": "20.00", + "supplier": { + "name": "string", + "phone": "string", + "inn": "string" + } + } + ] + } +} + +idempotency_key = SecureRandom.hex(10) +res = Yookassa.payments.create(payload: payload, idempotency_key: idempotency_key) +``` +--- + +### Запрос на создание платежа через билдер + +[Создание платежа в документации](https://yookassa.ru/developers/api?lang=ruby#create_payment) + +Билдер позволяет создать объект платежа — `PaymentRequest` программным способом, через объекты. + +```ruby +receipt = Receipt() +receipt.customer = {"phone": "79990000000", "email": "test@email.com"} +receipt.tax_system_code = 1 +receipt.items = [ + ReceiptItem({ + "description": "Product 1", + "quantity": 2.0, + "amount": { + "value": 250.0, + "currency": Currency.RUB + }, + "vat_code": 2 + }), + { + "description": "Product 2", + "quantity": 1.0, + "amount": { + "value": 100.0, + "currency": Currency.RUB + }, + "vat_code": 2 + } +] + +builder = PaymentRequestBuilder() +builder.set_amount({"value": 1000, "currency": Currency.RUB}) \ + .set_confirmation({"type": ConfirmationType.REDIRECT, "return_url": "https://merchant-site.ru/return_url"}) \ + .set_capture(False) \ + .set_description("Заказ №72") \ + .set_metadata({"orderNumber": "72"}) \ + .set_receipt(receipt) + +request = builder.build() +# Можно что-то поменять, если нужно +request.client_ip = '1.2.3.4' +res = Yookassa.payments.create(request) +``` +--- + +### Запрос на частичное подтверждение платежа + +[Подтверждение платежа в документации](https://yookassa.ru/developers/api?lang=ruby#capture_payment) + +Подтверждает вашу готовность принять платеж. После подтверждения платеж перейдет в статус succeeded. +Это значит, что вы можете выдать товар или оказать услугу пользователю. + +Подтвердить можно только платеж в статусе `waiting_for_capture` и только в течение определенного времени +(зависит от способа оплаты). Если вы не подтвердите платеж в отведенное время, он автоматически перейдет +в статус `canceled`, и деньги вернутся пользователю. + +В ответ на запрос придет объект платежа в актуальном статусе. +```ruby +payment_id = "21b23b5b-000f-5061-a000-0674e49a8c10" +res = Yookassa.payments.capture(payment_id: payment_id, { + "amount": { + "value": "1000.00", + "currency": "RUB" + }, + "transfers": [ + { + "account_id": "123", + "amount": { + "value": "300.00", + "currency": "RUB" + } + }, + { + "account_id": "456", + "amount": { + "value": "700.00", + "currency": "RUB" + } + } + ] +}) + +``` +[Подробнее о подтверждении и отмене платежей](https://yookassa.ru/developers/payments/payment-process#capture-and-cancel) + +--- + +### Запрос на отмену незавершенного платежа + +[Отмена платежа в документации](https://yookassa.ru/developers/api?lang=ruby#cancel_payment) + +Отменяет платеж, находящийся в статусе `waiting_for_capture`. Отмена платежа значит, что вы не готовы +выдать пользователю товар или оказать услугу. Как только вы отменяете платеж, мы начинаем возвращать деньги на счет плательщика. Для платежей банковскими картами или из кошелька ЮMoney отмена происходит мгновенно. Для остальных способов оплаты возврат может занимать до нескольких дней. + +В ответ на запрос придет объект платежа в актуальном статусе. +```ruby +res = Yookassa.payments.cancel(payment_id: "21b23b5b-000f-5061-a000-0674e49a8c10") +``` +[Подробнее о подтверждении и отмене платежей](https://yookassa.ru/developers/payments/payment-process#capture-and-cancel) + +--- + +### Получить информацию о платеже + +[Информация о платеже в документации](https://yookassa.ru/developers/api?lang=ruby#get_payment) + +Запрос позволяет получить информацию о текущем состоянии платежа по его уникальному идентификатору. + +В ответ на запрос придет объект платежа в актуальном статусе. + +```ruby +res = Yookassa.payments.find(payment_id: "21b23b5b-000f-5061-a000-0674e49a8c10") +``` +--- + +### Получить список платежей с фильтрацией + +[Список платежей в документации](https://yookassa.ru/developers/api?lang=ruby#get_payments_list) + +Запрос позволяет получить список платежей, отфильтрованный по заданным критериям. + +В ответ на запрос вернется список платежей с учетом переданных параметров. В списке будет информация о платежах, +созданных за последние 3 года. Список будет отсортирован по времени создания платежей в порядке убывания. + +Если результатов больше, чем задано в `limit`, список будет выводиться фрагментами. В этом случае в ответе на запрос +вернется фрагмент списка и параметр `next_cursor` с указателем на следующий фрагмент. + +```ruby + +cursor = nil +filters = { + "limit": 2, # Ограничиваем размер выборки + "payment_method": "yoo_money", # Выбираем только оплату через кошелек + "created_at.gte": "2020-08-08T00:00:00.000Z", # Созданы начиная с 2020-08-08 + "created_at.lt": "2020-10-20T00:00:00.000Z" # И до 2020-10-20 +} + +def get_items(filters:, next_cursor: nil, items: []) + result = Yookassa.payments.list(filters.merge(next_cursor: next_cursor)) + accumulated_items = result.items + items + + return accumulated_items if result.next_cursor.nil? + + get_items(filters: filters, next_cursor: result.next_cursor, items: accumulated_items) +end + +get_items(filters: filters, next_cursor: cursor) +``` +[Подробнее о работе со списками](https://yookassa.ru/developers/using-api/lists) diff --git a/docs/03-refunds.md b/docs/03-refunds.md new file mode 100644 index 0000000..f9da215 --- /dev/null +++ b/docs/03-refunds.md @@ -0,0 +1,128 @@ +## Работа с возвратами + +С помощью SDK можно возвращать платежи — полностью или частично. Порядок возврата зависит от способа оплаты +(`payment_method`) исходного платежа. При оплате банковской картой деньги возвращаются на карту, +которая была использована для проведения платежа. [Как проводить возвраты](https://yookassa.ru/developers/payments/refunds) + +Часть способов оплаты (например, наличные) не поддерживают возвраты. [Какие платежи можно вернуть](https://yookassa.ru/developers/payment-methods/overview#all) + +* [Запрос на создание возврата](#Запрос-на-создание-возврата) +* [Запрос на создание возврата через билдер](#Запрос-на-создание-возврата-через-билдер) +* [Получить информацию о возврате](#Получить-информацию-о-возврате) +* [Получить список возвратов с фильтрацией](#Получить-список-возвратов-с-фильтрацией) + +--- + +### Запрос на создание возврата + +[Создание возврата в документации](https://yookassa.ru/developers/api?lang=ruby#create_refund) + +Создает возврат успешного платежа на указанную сумму. Платеж можно вернуть только в течение трех лет с момента его создания. +Комиссия ЮKassa за проведение платежа не возвращается. + +В ответ на запрос придет объект возврата - `Refund` в актуальном статусе. + +```ruby +res = Yookassa.refunds.create({ + "payment_id": "24e89cb0-000f-5000-9000-1de77fa0d6df", + "description": "Не подошел размер", + "amount": { + "value": "9000.00", + "currency": "RUB" + }, + "sources": [ + { + "account_id": "456", + "amount": { + "value": "9000.00", + "currency": "RUB" + } + } + ] +}) + +``` + +--- + +### Запрос на создание возврата через билдер + +[Информация о создании возврата в документации](https://yookassa.ru/developers/api?lang=ruby#create_refund) + +Билдер позволяет создать объект платежа — `RefundRequest` программным способом, через объекты. + +```ruby +builder = RefundRequestBuilder() +builder.set_payment_id('24e89cb0-000f-5000-9000-1de77fa0d6df') \ + .set_description("Не подошел размер") \ + .set_amount({"value": 9000.0, "currency": Currency.RUB}) \ + .set_sources([ + RefundSource({ + 'account_id': 456, + 'amount': { + 'value': 9000.0, + 'currency': Currency.RUB + }, + "platform_fee_amount": { + "value": 10.01, + "currency": Currency.RUB + } + }) + ]) + +request = builder.build() +# Можно что-то поменять, если нужно +request.description = "Не подошел цвет и размер" + +res = Yokassa.refunds.create(request) +``` + +--- + +### Получить информацию о возврате + +[Информация о возврате в документации](https://yookassa.ru/developers/api?lang=ruby#get_refund) + +Запрос позволяет получить информацию о текущем состоянии возврата по его уникальному идентификатору. + +В ответ на запрос придет объект возврата - `Refund` в актуальном статусе. + +```ruby +res = Yookassa.refunds.find(refund_id: "7894e5e2-a22e-434b-b6c1-e355ff096d1c") +``` + +--- + +### Получить список возвратов с фильтрацией + +[Список возвратов в документации](https://yookassa.ru/developers/api?lang=ruby#get_refunds_list) + +Запрос позволяет получить список возвратов, отфильтрованный по заданным критериям. + +В ответ на запрос вернется список возвратов с учетом переданных параметров. В списке будет информация о возвратах, +созданных за последние 3 года. Список будет отсортирован по времени создания возвратов в порядке убывания. + +Если результатов больше, чем задано в `limit`, список будет выводиться фрагментами. В этом случае в ответе на запрос +вернется фрагмент списка и параметр `next_cursor` с указателем на следующий фрагмент. + +```ruby +cursor = nil +filters = { + "limit": 2, # Ограничиваем размер выборки + "payment_id": "21b23b5b-000f-5061-a000-0674e49a8c10", # Выбираем только по конкретному платежу + "created_at.gte": "2020-08-08T00:00:00.000Z", # Созданы начиная с 2020-08-08 + "created_at.lt": "2020-10-20T00:00:00.000Z" # И до 2020-10-20 +} + +def get_items(filters:, next_cursor: nil, items: []) + result = Yookassa.refunds.list(filters.merge(next_cursor: next_cursor)) + accumulated_items = result.items + items + + return accumulated_items if result.next_cursor.nil? + + get_items(filters: filters, next_cursor: result.next_cursor, items: accumulated_items) +end + +get_items(filters: filters, next_cursor: cursor) +``` +[Подробнее о работе со списками](https://yookassa.ru/developers/using-api/lists) diff --git a/docs/04-receipts.md b/docs/04-receipts.md new file mode 100644 index 0000000..a5c0407 --- /dev/null +++ b/docs/04-receipts.md @@ -0,0 +1,180 @@ +## Работа с чеками + +> Для тех, кто использует [решение ЮKassa для 54-ФЗ](https://yookassa.ru/developers/54fz/basics). + +С помощью SDK можно получать информацию о чеках, для которых вы отправили данные через ЮKassa. + +* [Запрос на создание чека](#Запрос-на-создание-чека) +* [Запрос на создание чека через билдер](#Запрос-на-создание-чека-через-билдер) +* [Получить информацию о чеке](#Получить-информацию-о-чеке) +* [Получить список чеков с фильтрацией](#Получить-список-чеков-с-фильтрацией) + +--- + +### Запрос на создание чека + +[Информация о создании чека в документации](https://yookassa.ru/developers/api?lang=ruby#create_receipt) + +Запрос позволяет передать онлайн-кассе данные для формирования [чека зачета предоплаты](https://yookassa.ru/developers/54fz/payments#settlement-receipt). + +Если вы работаете по сценарию [Сначала платеж, потом чек](https://yookassa.ru/developers/54fz/basics#receipt-after-payment), +в запросе также нужно передавать данные для формирования чека прихода и чека возврата прихода. + +```ruby +res = Yookassa.receipts.create({ + "customer": { + "full_name": "Ivanov Ivan Ivanovich", + "email": "email@email.ru", + "phone": "+79211234567", + "inn": "6321341814" + }, + "payment_id": "24b94598-000f-5000-9000-1b68e7b15f3f", + "type": "payment", + "send": true, + "items": [ + { + "description": "Наименование товара 1", + "quantity": 1.000, + "amount": { + "value": "14000.00", + "currency": "RUB" + }, + "vat_code": "2", + "payment_mode": "full_payment", + "payment_subject": "commodity", + "country_of_origin_code": "CN", + }, + { + "description": "Наименование товара 2", + "quantity": 1.000, + "amount": { + "value": "1000.00", + "currency": "RUB" + }, + "vat_code": "2", + "payment_mode": "full_payment", + "payment_subject": "commodity", + "country_of_origin_code": "CN", + }, + ], + "settlements": [ + { + "type": "prepayment", + "amount": { + "value": "8000.00", + "currency": "RUB" + }, + }, + { + "type": "prepayment", + "amount": { + "value": "7000.00", + "currency": "RUB" + }, + } + ] +}) +``` + +--- + +### Запрос на создание чека через билдер + +[Информация о создании чека в документации](https://yookassa.ru/developers/api?lang=ruby#create_receipt) + +Билдер позволяет создать объект платежа — `Receipt` программным способом, через объекты. + +```ruby + +builder = ReceiptRequestBuilder() +builder.set_type(ReceiptType.PAYMENT) \ + .set_payment_id('215d8da0-000f-50be-b000-0003308c89be') \ + .set_customer({'phone': '79990000000', 'email': 'test@email.com'}) \ + .set_tax_system_code(1) \ + .set_items([ + { + "description": "Product 1", + "quantity": 2.0, + "amount": { + "value": 250.0, + "currency": Currency.RUB + }, + "vat_code": 2 + }, + ReceiptItem({ + "description": "Product 2", + "quantity": 1.0, + "amount": { + "value": 100.0, + "currency": Currency.RUB + }, + "vat_code": 2 + }) + ]) \ + .set_settlements([ + Settlement({ + 'type': SettlementType.CASHLESS, + 'amount': { + 'value': 350.0, + 'currency': Currency.RUB + } + }) + ]) + +request = builder.build() +# Можно что-то поменять, если нужно +request.on_behalf_of = 123456 + +Yokassa.receipts.create(request) +``` + +--- + +### Получить информацию о чеке + +[Информация о чеке в документации](https://yookassa.ru/developers/api?lang=ruby#get_receipt) + +Запрос позволяет получить информацию о текущем состоянии чека по его уникальному идентификатору. + +В ответ на запрос придет объект чека - `Receipt` в актуальном статусе. + +```ruby +Yookassa.receipts.find('rt-2da5c87d-0384-50e8-a7f3-8d5646dd9e10') +``` + +--- + +### Получить список чеков с фильтрацией + +[Список чеков в документации](https://yookassa.ru/developers/api?lang=ruby#get_receipts_list) + +Запрос позволяет получить список чеков, отфильтрованный по заданным критериям. +Можно запросить чеки по конкретному платежу, чеки по конкретному возврату или все чеки магазина. + +В ответ на запрос вернется список чеков с учетом переданных параметров. В списке будет информация о чеках, +созданных за последние 3 года. Список будет отсортирован по времени создания чеков в порядке убывания. + +Если результатов больше, чем задано в `limit`, список будет выводиться фрагментами. +В этом случае в ответе на запрос вернется фрагмент списка и параметр `next_cursor` с указателем на следующий фрагмент. + +```ruby +cursor = nil +filters = { + "limit": 2, # Ограничиваем размер выборки + "payment_id": "21b23b5b-000f-5061-a000-0674e49a8c10", # Выбираем только по конкретному платежу + "created_at.gte": "2020-08-08T00:00:00.000Z", # Созданы начиная с 2020-08-08 + "created_at.lt": "2020-10-20T00:00:00.000Z" # И до 2020-10-20 +} + +def get_items(filters:, next_cursor: nil, items: []) + result = Yookassa.receipts.list(filters.merge(next_cursor: next_cursor)) + accumulated_items = result.items + items + + return accumulated_items if result.next_cursor.nil? + + get_items(filters: filters, next_cursor: result.next_cursor, items: accumulated_items) +end + +get_items(filters: filters, next_cursor: cursor) +``` +[Подробнее о работе со списками](https://yookassa.ru/developers/using-api/lists) diff --git a/docs/05-deals.md b/docs/05-deals.md new file mode 100644 index 0000000..6d87d82 --- /dev/null +++ b/docs/05-deals.md @@ -0,0 +1,103 @@ +## Работа со сделками + +SDK позволяет создавать сделки, а также получать информацию о них. + +Объект сделки `DealResponse` содержит всю информацию о сделке, актуальную на текущий момент времени. +Он формируется при создании сделки и приходит в ответ на любой запрос, связанный со сделками. + +* [Запрос на создание сделки](#Запрос-на-создание-сделки) +* [Запрос на создание сделки через билдер](#Запрос-на-создание-сделки-через-билдер) +* [Получить информацию о сделке](#Получить-информацию-о-сделке) +* [Получить список сделок с фильтрацией](#Получить-список-сделок-с-фильтрацией) + +--- + +### Запрос на создание сделки + +[Создание сделки в документации](https://yookassa.ru/developers/api?lang=ruby#create_deal) + +Чтобы создать сделку, необходимо создать объект сделки — `DealRequest`. Он позволяет создать сделку, в рамках которой +необходимо принять оплату от покупателя и перечислить ее продавцу. + +В ответ на запрос придет объект сделки - `DealResponse` в актуальном статусе. + +```ruby +res = Yookassa.deals.create({ + "type": "safe_deal", + "fee_moment": "payment_succeeded", + "metadata": { + "order_id": "88" + }, + "description": "SAFE_DEAL PYTHON 123554642-2432FF344R" +}) + +``` +--- + +### Запрос на создание сделки через билдер + +[СоздCание сделки в документации](https://yookassa.ru/developers/api?lang=ruby#create_deal) + +Билдер позволяет создать объект сделки — `DealRequest` программным способом, через объекты. + +```ruby +builder = DealRequestBuilder() \ + .set_type(DealType.SAFE_DEAL) \ + .set_fee_moment(FeeMoment.PAYMENT_SUCCEEDED) \ + .set_description('SAFE_DEAL 123554642-2432FF344R') \ + .set_metadata({'order_id': '37'}) + +request = builder.build() +# Можно что-то поменять, если нужно +request.description = 'SAFE_DEAL PYTHON 123554642-2432FF344R' +res = Yookassa.deals.create(request) +``` +--- + +### Получить информацию о сделке + +[Информация о сделке в документации](https://yookassa.ru/developers/api?lang=ruby) + +Запрос позволяет получить информацию о текущем состоянии сделки по его уникальному идентификатору. + +В ответ на запрос придет объект сделки - `DealResponse` в актуальном статусе. + +```ruby +res = Yookassa.deals.find_one('dl-285e5ee7-0022-5000-8000-01516a44b147') +``` +--- + +### Получить список сделок с фильтрацией + +[Список сделок в документации](https://yookassa.ru/developers/api?lang=ruby#get_deals_list) + +Запрос позволяет получить список сделок, отфильтрованный по заданным критериям. + +В ответ на запрос вернется список сделок с учетом переданных параметров. В списке будет информация о сделках, +созданных за последние 3 года. Список будет отсортирован по времени создания сделок в порядке убывания. + +Если результатов больше, чем задано в `limit`, список будет выводиться фрагментами. В этом случае в ответе на запрос +вернется фрагмент списка и параметр `next_cursor` с указателем на следующий фрагмент. + +```ruby +cursor = nil +filters = { + "limit": 10, # Ограничиваем размер выборки + "status": "closed", # Выбираем только открытые сделки + "full_text_search": "PYTHON", # Фильтр по описанию сделки — параметру description + "created_at.gte": "2021-08-01T00:00:00.000Z", # Созданы начиная с 2021-08-01 + "created_at.lt": "2021-11-20T00:00:00.000Z" # И до 2021-11-20 +} + +def get_items(filters:, next_cursor: nil, items: []) + result = Yookassa.deals.list(filters.merge(next_cursor: next_cursor)) + accumulated_items = result.items + items + + return accumulated_items if result.next_cursor.nil? + + get_items(filters: filters, next_cursor: result.next_cursor, items: accumulated_items) +end + +get_items(filters: filters, next_cursor: cursor) +``` +[Подробнее о работе со списками](https://yookassa.ru/developers/using-api/lists) diff --git a/docs/06-payouts.md b/docs/06-payouts.md new file mode 100644 index 0000000..0d5af81 --- /dev/null +++ b/docs/06-payouts.md @@ -0,0 +1,73 @@ +## Работа с выплатами + +SDK позволяет создавать, подтверждать, отменять выплаты, а также получать информацию о них. + +Объект выплаты `PayoutResponse` содержит всю информацию о выплате, актуальную на текущий момент времени. +Он формируется при создании выплаты и приходит в ответ на любой запрос, связанный с выплатами. + +* [Запрос на создание выплаты](#Запрос-на-создание-выплаты) +* [Запрос на создание выплаты через билдер](#Запрос-на-создание-выплаты-через-билдер) +* [Получить информацию о выплате](#Получить-информацию-о-выплате) + +--- + +### Запрос на создание выплаты + +[Создание выплаты в документации](https://yookassa.ru/developers/api?lang=ruby#create_payout) + +Чтобы принять оплату, необходимо создать объект выплаты — `PayoutRequest`. Он содержит всю необходимую информацию +для проведения оплаты (сумму, валюту и статус). У выплаты линейный жизненный цикл, +он последовательно переходит из статуса в статус. + +В ответ на запрос придет объект выплаты - `PayoutResponse` в актуальном статусе. + +```ruby +res = Yookassa.payouts.create({ + "amount": {"value": 320.0, "currency": Currency.RUB}, + "payout_destination_data": {'type': PaymentMethodType.YOO_MONEY, 'account_number': '41001614575714'}, + "description": "Выплата по заказу №37", + "metadata": { + "order_id": "37" + }, + "deal": { + "id": "dl-285e5ee7-0022-5000-8000-01516a44b147" + } +}) +``` +--- + +### Запрос на создание выплаты через билдер + +[Создание выплаты в документации](https://yookassa.ru/developers/api?lang=ruby#create_payout) + +Билдер позволяет создать объект выплаты — `PayoutRequest` программным способом, через объекты. + +```ruby + +builder = PayoutRequestBuilder() +builder.set_amount({'value': 0.1, 'currency': Currency.RUB}) \ + .set_description('Выплата по заказу №77') \ + .set_payout_token('99091209012') \ + .set_metadata({'order_id': '77'}) \ + .set_deal({ + 'id': 'dl-285e5ee7-0022-5000-8000-01516a44b147' + }) + +request = builder.build() +# Можно что-то поменять, если нужно +request.description = 'Выплата по заказу №77' +res = Yookassa.payouts.create(request) +``` +--- + +### Получить информацию о выплате + +[Информация о выплате в документации](https://yookassa.ru/developers/api?lang=ruby#get_payout) + +Запрос позволяет получить информацию о текущем состоянии выплаты по его уникальному идентификатору. + +В ответ на запрос придет объект выплаты в актуальном статусе. + +```ruby +res = Yookassa.payouts.find_one('po-21b23b5b-000f-5061-a000-0674e49a8c10') +``` diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 0000000..523b0d8 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,39 @@ +## Примеры использования SDK + +#### [Настройки SDK API ЮKassa](01-configuration.md) +* [Аутентификация](01-configuration.md#Аутентификация) +* [Статистические данные об используемом окружении](01-configuration.md#Статистические-данные-об-используемом-окружении) +* [Получение информации о магазине](01-configuration.md#Получение-информации-о-магазине) +* [Работа с Webhook](01-configuration.md#Работа-с-Webhook) +* [Входящие уведомления](01-configuration.md#Входящие-уведомления) + +#### [Работа с платежами](02-payments.md) +* [Запрос на создание платежа](02-payments.md#Запрос-на-создание-платежа) +* [Запрос на создание платежа через билдер](02-payments.md#Запрос-на-создание-платежа-через-билдер) +* [Запрос на частичное подтверждение платежа](02-payments.md#Запрос-на-частичное-подтверждение-платежа) +* [Запрос на отмену незавершенного платежа](02-payments.md#Запрос-на-отмену-незавершенного-платежа) +* [Получить информацию о платеже](02-payments.md#Получить-информацию-о-платеже) +* [Получить список платежей с фильтрацией](02-payments.md#Получить-список-платежей-с-фильтрацией) + +#### [Работа с возвратами](03-refunds.md) +* [Запрос на создание возврата](03-refunds.md#Запрос-на-создание-возврата) +* [Запрос на создание возврата через билдер](03-refunds.md#Запрос-на-создание-возврата-через-билдер) +* [Получить информацию о возврате](03-refunds.md#Получить-информацию-о-возврате) +* [Получить список возвратов с фильтрацией](03-refunds.md#Получить-список-возвратов-с-фильтрацией) + +#### [Работа с чеками](04-receipts.md) +* [Запрос на создание чека](04-receipts.md#Запрос-на-создание-чека) +* [Запрос на создание чека через билдер](04-receipts.md#Запрос-на-создание-чека-через-билдер) +* [Получить информацию о чеке](04-receipts.md#Получить-информацию-о-чеке) +* [Получить список чеков с фильтрацией](04-receipts.md#Получить-список-чеков-с-фильтрацией) + +#### [Работа со сделками](05-deals.md) +* [Запрос на создание сделки](05-deals.md#Запрос-на-создание-сделки) +* [Запрос на создание сделки через билдер](05-deals.md#Запрос-на-создание-сделки-через-билдер) +* [Получить информацию о сделке](05-deals.md#Получить-информацию-о-сделке) +* [Получить список сделок с фильтрацией](05-deals.md#Получить-список-сделок-с-фильтрацией) + +#### [Работа с выплатами](06-payouts.md) +* [Запрос на создание выплаты](06-payouts.md#Запрос-на-создание-выплаты) +* [Запрос на создание выплаты через билдер](06-payouts.md#Запрос-на-создание-выплаты-через-билдер) +* [Получить информацию о выплате](06-payouts.md#Получить-информацию-о-выплате) diff --git a/lib/yookassa/client.rb b/lib/yookassa/client.rb index b1a5463..1522405 100644 --- a/lib/yookassa/client.rb +++ b/lib/yookassa/client.rb @@ -33,6 +33,10 @@ module Yookassa api_call { http.headers("Idempotence-Key" => idempotency_key).post("#{API_URL}#{endpoint}", json: payload) } end + def delete(endpoint, idempotency_key:) + api_call { http.headers("Idempotence-Key" => idempotency_key).delete("#{API_URL}#{endpoint}") } + end + def api_call response = yield if block_given? body = JSON.parse(response.body.to_s, symbolize_names: true) diff --git a/lib/yookassa/entity/confirmation.rb b/lib/yookassa/entity/confirmation.rb index 4d498c6..4010a68 100644 --- a/lib/yookassa/entity/confirmation.rb +++ b/lib/yookassa/entity/confirmation.rb @@ -16,7 +16,7 @@ module Yookassa attribute :type, Types.Value("embedded") # Token for the YooMoney Checkout Widget initialization. - attribute? :confirmation_token, Types::String + attribute :confirmation_token, Types::String end class External < Base @@ -39,14 +39,14 @@ module Yookassa attribute :type, Types.Value("qr") # Data for generating the QR code. - attribute? :confirmation_data, Types::String + attribute :confirmation_data, Types::String end class Redirect < Base attribute :type, Types.Value("redirect") # The URL that the user will be redirected to for payment confirmation. - attribute? :confirmation_url, Types::String + attribute :confirmation_url, Types::String # A request for making a payment with authentication by 3-D Secure. It works if you accept # bank card payments without user confirmation by default. In other cases, the 3-D Secure @@ -56,7 +56,7 @@ module Yookassa # The URL that the user will return to after confirming or canceling the payment on the webpage. # Maximum 2048 characters. - attribute :return_url, Types::String + attribute? :return_url, Types::String end end diff --git a/lib/yookassa/partner_api.rb b/lib/yookassa/partner_api.rb deleted file mode 100644 index ed01db1..0000000 --- a/lib/yookassa/partner_api.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require "http" - -require_relative "./stores" -require_relative "./webhooks" -require_relative "./entity/error" - -module Yookassa - class PartnerAPI - API_URL = "https://api.yookassa.ru/v3/" - - def initialize(oauth_token:) - @http = HTTP.headers("Authorization" => "Bearer #{oauth_token}") - .headers(accept: "application/json") - end - - def stores - @stores ||= Stores.new(self) - end - - def webhooks - @webhooks ||= Webhooks.new(self) - end - - def get(endpoint) - api_call { get("#{API_URL}#{endpoint}", params: query) } - end - - def post(endpoint, idempotency_key:, payload: {}) - api_call { http.headers("Idempotence-Key" => idempotency_key).post("#{API_URL}#{endpoint}", json: payload) } - end - - def delete(endpoint, idempotency_key:) - HTTP.headers("Authorization" => "Bearer #{oauth_token}") - .headers("Idempotence-Key" => idempotency_key) - .delete("#{API_URL}#{endpoint}") - end - - private - - attr_reader :http - - def api_call - response = yield if block_given? - body = JSON.parse(response.body.to_s, symbolize_names: true) - return body if response.status.success? - - Entity::Error.new(**body) - end - end -end