# Быстрый старт {#ru_pp_quickstart} инструкция по оперативной организации приёма платежей через Payment Page, с использованием SDK и примеров исходного кода **На уровень выше:**[Payment Page](ru_PP_about.md) ## Введение {#ru_pp_quickstart_overview} Эта инструкция — о том, как организовать приём платежей через Payment Page. С тем, чтобы платёжная форма вызывалась из веб-сервиса и возвращала пользователей к нему. И чтобы при этом можно было использовать проверенные быстрые решения — с чёткими инструкциями, библиотеками и примерами кодана одном из трёх популярных языков программирования — PHP, Python или JavaScript. ![](images/ecommpay/ru_pp_quickstart_1.svg) Если вам актуально что-то другое, можно сориентироваться в вариантах. - Если надо научиться делать платёжные ссылки для открытия Payment Page, можно разобраться с тем, как работать с ними вручную [через Dashboard](ru_dbl_payments.md#) и автоматически [через Gate](ru_gate_invoice.md#). - Если надо основательно разобраться со схемой и возможностями работы с Payment Page, можно пройти [сюда](ru_pp_interaction_organisation.md#). - Если актуально что-то ещё, можно обратиться к другим разделам \(например, начав [здесь](ru_PP_general.md#)\) и к специалистам Ecommpay. На этом с вводными всё. Можно переходить к делу. ## Краткая теория {#ru_pp_quickstart_theory} ### Проекты и ключи {#section_wpk_bnd_4tb .section} Работу с платёжной платформой Ecommpayможно сравнить с использованием услуг гостиницы. Так, для заселения в гостиницу обычно необходимо получить номер и ключ от него, а для начала работы с платформой надо получить... *проект и ключ* от него. И как с номерами в гостиницах, в платформе может предоставляться разное количество проектов для одного клиента — под разные цели и задачи — при этом для каждого проекта \(как и для каждого гостиничного номера\) необходим свой ключ. Как правило, для работы достаточно одного тестового и одного рабочего проектов. Это типичный случай, и в рамках быстрого старта мы исходим из него. Если вам по какой-либо причине необходимо больше проектов, это стоит обсудить с курирующим менеджером, но начать всё также можно с одного тестового проекта. Если у вас уже есть идентификатор тестового проекта \(`project_id`\) и секретный ключ для него \(`secret_key`\), можно приготовиться к их использованию и переходить дальше. Если же вы ещё не бронировали тестовый проект, самое время сделать это[через заявку](https://ecommpay.com/sign-up/) на основном сайте компании и вернуться сюда. ### Схема работы {#section_idx_mnd_4tb .section} Чтобы корректно вызывать Payment Page, надо настроить сбор параметров, их подписывание и вызов формы. При этом подписывание данных \(для которого необходим секретный ключ\) важно выполнять в серверной части веб-сервиса, а вызов формы — в клиентской. Также для оперативного контроля результатов полезно настроить в серверной части приём оповещений от платёжной платформы. В целом это выглядит так. | |В клиентской части веб‑сервиса|В серверной части веб‑сервиса|В платёжной платформе| |--|------------------------------|-----------------------------|---------------------| |1|Формируем заказ. Фиксируем параметры платежа и передаём их в серверную часть \(чтобы подписать\)|–|–| |2|–|Дополняем \(если это актуально\) и подписываем параметры платежа, после чего передаём информацию в клиентскую часть|–| |3|Формируем и отправляем в платёжную платформу запрос на открытие Payment Page|–|–| |4|–|–|Принимаем запрос, готовим и открываем форму пользователю, обрабатываем его действия и проводим платёж, после чего отправляем оповещение о результате платежа и возвращаем пользователя к веб-сервису| |5|–|Принимаем оповещение о результате платежа и обновляем статус заказа|–| |6|Отображаем пользователю информацию об оплате заказа и дальнейших действиях \(если они необходимы, например для доставки товара\)|–|–| В отдельных случаях, например при работе с облегчённой редакцией платёжной формы, взаимодействие веб-сервиса с платформой может строиться иначе. Реализовывать эту схему в клиентской и серверной частях веб-сервиса в общем случае можно самыми разными способами. Здесь, в рамках быстрого старта, для удобства и скорости запуска все необходимые процедуры описываются с максимальным использованием уже готовых компонентов \(таких как SDK\) и примеров кода. Но вы всегда можете варьировать наши готовые компоненты со своими решениями. ### Параметры вызова формы {#section_ol1_v4d_4tb .section} Чтобы открыть пользователю платёжную форму, в простейшем случае достаточно определиться с суммой и валютой платежа и добавить к этим двум параметрам три идентификатора: проекта, платежа и пользователя. Таким образом, обязательных параметров всего пять.\(И технически к ним ещё обязательна подпись.\) |Параметр|Описание| |--------|--------| |`project_id` integer |Идентификатор проекта. Его вместе с ключом выдаёт Ecommpay и его важно точно указывать даже в тестовых запросах. Иначе… стоит ждать реакцию, как при попытке зайти в чужой гостиничный номер. Пример: `57123 ` | |`payment_id` string |Идентификатор платежа. Он может быть произвольным, но каждый раз должен быть уникальным в рамках используемого проекта. Иначе стоит ждать ошибку вызова. Пример: `payment_443 ` | |`payment_amount` integer |Сумма платежа. В тестовых запросах может быть произвольной, а в реальных должна точно соответствовать сумме заказа. Приводится в дробных единицах валюты. Пример: `1815` \(для суммы `18,15`\) | |`payment_currency` string |Код валюты платежа. Приводится в трёхбуквенном формате ISO 4217 alpha-3.В тестовых запросах могут использоваться любые из действующих кодов, а в реальных каждый раз должен использоваться код той валюты, в которой инициируется платёж. Для сверки можно использовать [справочник валют](ru_currency_codes.md). Пример: `EUR` | |`customer_id` string |Идентификатор пользователя.Может быть произвольным и повторяемым в разных запросах, но для каждого реального пользователя должен быть однозначно сопоставляемым с его учётной записью в веб-сервисе и уникальным в рамках проекта.Иначе возможны различные коллизии, в том числе с отображением сохранённых данных платёжных инструментов одного пользователя другому. Пример: `customer_112` | При работе с облегчённой редакцией платёжной формы обязательный набор параметров дополняется: в этом случае вместе с перечисленными параметрами также необходимо передавать доменное имя веб-сервиса \(`merchant_domain`\), служебный код платёжного метода \(`force_payment_method` со значением `card`\) и указатель режима работы Payment Page \(`mode` со значением `purchase`\). Как именно собирать эти параметры\(и в том числе, какие из них задавать в клиентской части, а какие в серверной\) — решать вам\(с оглядкой на архитектуру вашего веб-сервиса и иные факторы\). При этом для первых тестовых вызовов сбор параметров можно не автоматизировать вовсе, если что, этим можно заняться и после первичного тестирования работы с формой. Здесь же остаётся сказать, что в дополнение к обязательным параметрам можно использовать и другие, для управления видом и поведением платёжной формы, но поскольку с этими параметрами лучше разбираться после того, как настроен базовый вызов Payment Page, предметный разговор о них [дальше](ru_pp_quickstart.md#section_um4_xf2_4tb). ## Базовая реализация {#ru_pp_quickstart_basic_implementation} ### Варианты работы {#section_c2x_wqd_4tb .section} Реализовывать функции веб-сервиса для работы с платёжной формой и оповещениями можно по-разному, в том числе за счёт создания своих программных решенийи за счёт применения CMS-модулей. В рамках быстрого старта мы рассматриваем два варианта реализации: - с применением в серверной части веб-сервиса SDK от Ecommpay; - с использованием в серверной части веб-сервиса готового кода от Ecommpay Различия между этими вариантами можно считать вкусовыми.С SDK может быть чуть проще, а также доступнее при работе с другими языками программирования \(полный набор материалов о работе с SDK представлен [в отдельном разделе](ru_sdk_overview.md)\). С примерами кода же может быть чуть прозрачнее и гибче в плане встраивания в свои решения \(в том числе при работе с подписыванием данных\). Но оба варианта достаточно быстры и полноценны, и вы можете выбрать любой из них. Вместе с тем, независимо от варианта реализации серверных функций, в клиентской части веб-сервиса в рамках быстрого старта мы рассматриваем разные варианты вызова платёжной формы, в том числе с использованием библиотек от Ecommpay. И в целом задачи реализации сводятся к следующим. |В серверной части|В клиентской части| |-----------------|------------------| |- подключить библиотеки \(при работе с SDK\) - обеспечить дополнение параметров \(насколько актуально\) - обеспечить подписывание данных - обеспечить приём оповещений |- подключить библиотеки \(если актуально\) - обеспечить сбор параметров \(насколько актуально\) - обеспечить вызов формы - реализовать функции для обработки интерфейсных событий \(если актуально\) | Сбор и дополнение параметров, как и было сказано в теоретическом обзоре, могут выполняться разными способами\(для первичного тестирования допустимо и вручную\) и остаются за вами. Остальные действия разобраны далее. ### Работа с SDK {#section_kj3_kvd_4tb .section} Подключаем и настраиваем. **1 Подключаем SDK** 1. Если не делали этого ранее, загружаем, устанавливаем и настраиваем менеджер зависимостей Composer \([https://getcomposer.org/](https://getcomposer.org/)\). 2. В командной строке операционной системы переходим в каталог с исходным кодом веб-сервиса и выполняем команду `composer require ecommpay/paymentpage-sdk`. 3. Подключаем скрипт `autoload.php` в исходном коде веб-сервиса. ```language-php // Подключение библиотек require` __DIR__.'../../vendor.autoload.php'; ```   **2 Обеспечиваем подписывание данных** Когда для всех необходимых параметров определены их значения\(и только в таком случае\), можно собирать эти данные в серверной части веб-сервиса и формировать подпись и URL для вызова платёжной формы. Как это делать, можно разобрать на примере. ```language-php // Подписывание данных и формирование ссылки // создание объекта класса Payment и указание идентификаторов проекта и платежа $payment = new ecommpay Payment('57123', 'payment_443'); // указание других обязательных параметров $payment->setPaymentAmount(1815)->setPaymentCurrency('EUR'); // сумма и валюта платежа $payment->setCustomerId('customer_112'); // идентификатор пользователя // создание объекта класса Gate и указание секретного ключа $gate = new ecommpay\Gate(''); // формирование ссылки для вызова платёжной формы $url = $gate->getPurchasePaymentPageUrl($payment); ```   **3 Настраиваем приём оповещений** Чтобы оперативно узнавать о результатах платежей и получать другую значимую информацию, следует настроить приём и обработку программных оповещений от платёжной платформы. Это делается в три шага: 1. Определяем и задаём в платёжной платформе адрес для приёма веб-сервисом оповещений по проекту\(сначала можно задать один общий адрес, а после — несколько, под разные события\). Для этого открываем в интерфейсе Dashboard раздел **Проекты** и используем инструменты на вкладке **Оповещения**. 2. Настраиваем проверку целостности и разбор оповещений, поступающих на указанный URL, с использованием SDK. 3. Настраиваем отправку синхронных HTTP-ответов о приёме оповещений: `200 ОК` если подпись корректна и `400 Bad Request` если подпись некорректна. ```language-php // Работа с оповещениями // создание объекта класса Gate и указание секретного ключа $gate = new ecommpay\Gate(''); // создание объекта класса Callback и указание JSON-строки с данными // из оповещения ($data), с проверкой целостности данных $callback = $gate->handleCallback($data); // использование методов для работы с оповещениями Callback::getPaymentId(); // получение идентификатора платежа Callback::getPaymentStatus(); // получение статуса платежа Callback::getPayment(); // получение всей информации из оповещения ``` Описания используемых статусов платежей можно найти [в отдельном разделе](ru_platform_payment_model.md), а описание оповещений и работы с ними — [в отдельной статье](ru_platform_callbacks.md#). При этом важно помнить, что в случаях, когда пользователь не подтверждает оплату в платёжной форме, платёж не регистрируется \(и статуса по нему тоже нет\). Извлечённую из оповещений информацию можно использовать для оперативного обновления статусов заказов в веб-сервисе, информирования пользователей и других целей — в соответствии с моделью работы вашего веб-сервиса. **1 Подключаем SDK** 1. Если не делали этого ранее, загружаем, устанавливаем и настраиваем систему управления пакетами pip \([https://pip.pypa.io/en/stable/](https://pip.pypa.io/en/stable/)\). 2. В командной строке операционной системы переходим в каталог с исходным кодом веб-сервиса и выполняем команду `pip install ecommpay-sdk`. 3. Подключаем библиотеки из SDK в исходном коде веб-сервиса. ```language-python # Подключение библиотек from payment_page_sdk.gate import Gate from payment_page_sdk.payment import Payment ```   **2 Обеспечиваем подписывание данных** Когда для всех необходимых параметров определены их значения\(и только в таком случае\), можно собирать эти данные в серверной части веб-сервиса и формировать подпись и URL для вызова платёжной формы. Как это делать, можно разобрать на примере. ```language-python # Подписывание данных и формирование ссылки # создание объекта класса Payment и указание идентификаторов проекта и платежа payment = Payment('57123', 'payment_443') # указание других обязательных параметров payment.payment_amount = 1815 # сумма платежа payment.payment_currency = 'EUR' # валюта платежа payment.customer_id = 'customer_112' # идентификатор пользователя # создание объекта класса Gate и указание секретного ключа gate = Gate('') # формированием ссылки для вызова платёжной формы payment_url = gate.get_purchase_payment_page_url(payment) ```   **3 Настраиваем приём оповещений** Чтобы оперативно узнавать о результатах платежей и получать другую значимую информацию, следует настроить приём и обработку программных оповещений от платёжной платформы. Это делается в три шага: 1. Определяем и задаём в платёжной платформе адрес для приёма веб-сервисом оповещений по проекту\(сначала можно задать один общий адрес, а после — несколько, под разные события\). Для этого открываем в интерфейсе Dashboard раздел **Проекты** и используем инструменты на вкладке **Оповещения**. 2. Настраиваем проверку целостности и разбор оповещений, поступающих на указанный URL, с использованием SDK. 3. Настраиваем отправку синхронных HTTP-ответов о приёме оповещений: `200 ОК` если подпись корректна и `400 Bad Request` если подпись некорректна. ```language-python # Работа с оповещениями # создание объекта класса Gate и указание секретного ключа gate = Gate('') # создание объекта класса Callback и указание JSON-строки с данными # из оповещения (data), с проверкой целостности данных callback = gate.handle_callback(data) # использование методов для работы с оповещениями callback.get_payment_id() # получение идентификатора платежа callback.get_payment_status() # получение статуса платежа callback.get_payment() # получение всей информации из оповещения ``` Описания используемых статусов платежей можно найти [в отдельном разделе](ru_platform_payment_model.md), а описание оповещений и работы с ними — [в отдельной статье](ru_platform_callbacks.md#). При этом важно помнить, что в случаях, когда пользователь не подтверждает оплату в платёжной форме, платёж не регистрируется \(и статуса по нему тоже нет\). Извлечённую из оповещений информацию можно использовать для оперативного обновления статусов заказов в веб-сервисе, информирования пользователей и других целей — в соответствии с моделью работы вашего веб-сервиса. **1 Подключаем SDK** 1. Если не делали этого ранее, загружаем, устанавливаем и настраиваем систему управления пакетами: Yarn \([https://yarnpkg.com/en/docs/getting-started](https://yarnpkg.com/en/docs/getting-started)\) или npm \([https://www.npmjs.com/package/ecommpay](https://www.npmjs.com/package/ecommpay)\). 2. В командной строке операционной системы переходим в каталог с исходным кодом веб-сервиса и выполняем одну из команд: `yarn add ecommpay` или `npm install ecommpay`. 3. Подключаем модули в исходном коде веб-сервиса. ``` {#codeblock_bdr_mnx_w1c .language-javascript} const { Payment } = require('ecommpay'); const { Callback } = require('ecommpay'); ```   **2 Обеспечиваем подписывание данных** Когда для всех необходимых параметров определены их значения\(и только в таком случае\), можно собирать эти данные в серверной части веб-сервиса и формировать подпись и URL для вызова платёжной формы. Как это делать, можно разобрать на примере. ```language-javascript // Подписывание данных и формирование ссылки // создание объекта класса Payment и указание идентификатора проекта и секретного ключа const payment = new Payment('57123', 'payment_443'); // указание идентификатора платежа payment.paymentId = 'payment_443; // указание других обязательных параметров payment.paymentAmount = 1815 // сумма платежа payment.paymentCurrency = 'EUR' // валюта платежа payment.customerId = 'customer_112' // идентификатор пользователя // получение ссылки для вызова платёжной формы const url = payment.getUrl(); ```   **3 Настраиваем приём оповещений** Чтобы оперативно узнавать о результатах платежей и получать другую значимую информацию, следует настроить приём и обработку программных оповещений от платёжной платформы. Это делается в три шага: 1. Определяем и задаём в платёжной платформе адрес для приёма веб-сервисом оповещений по проекту\(сначала можно задать один общий адрес, а после — несколько, под разные события\). Для этого открываем в интерфейсе Dashboard раздел **Проекты** и используем инструменты на вкладке **Оповещения**. 2. Настраиваем проверку целостности и разбор оповещений, поступающих на указанный URL, с использованием SDK. 3. Настраиваем отправку синхронных HTTP-ответов о приёме оповещений: `200 ОК` если подпись корректна и `400 Bad Request` если подпись некорректна. ```language-javascript // Работа с оповещениями // создние объекта класса Callback и указание секретного ключа const callback = new Callback(, req.body); // использование методов для работы с оповещениями app.post('/payment/callback', function(req, res) { const callback = new Callback(<*secret\_key*>, req.body); if (callback.isPaymentSuccess()) { const paymentCont = callback.payment(); // получение всей информации о платеже const paymentId = callback.getPaymentId(); // получение идентификатора платежа // Здесь размещается исходный код для обработки оповещения проведённого платежа } }); ``` Описания используемых статусов платежей можно найти [в отдельном разделе](ru_platform_payment_model.md), а описание оповещений и работы с ними — [в отдельной статье](ru_platform_callbacks.md#). При этом важно помнить, что в случаях, когда пользователь не подтверждает оплату в платёжной форме, платёж не регистрируется \(и статуса по нему тоже нет\). Извлечённую из оповещений информацию можно использовать для оперативного обновления статусов заказов в веб-сервисе, информирования пользователей и других целей — в соответствии с моделью работы вашего веб-сервиса. ### Работа с кодом {#section_k1p_t12_4tb .section} Встраиваем и используем. **1 Обеспечиваем подписывание данных** ```language-php // Кодирование алгоритма class Signer { const ALGORITHM = 'sha512'; const ITEMS_DELIMITER = ';'; /** * Generate signature * * @param array $params * @param string $secretKey * @param array $ignoreParamKeys * @param bool $doNotHash * * @return string */ public static function sign(array $params, string $secretKey, array $ignoreParamKeys = [], bool $doNotHash = false): string { $paramsPrepared = self::getParamsToSign($params, $ignoreParamKeys, 1, ''); $stringToSign = implode(self::ITEMS_DELIMITER, $paramsPrepared); return $doNotHash ? $stringToSign : base64_encode(hash_hmac(self::ALGORITHM, $stringToSign, $secretKey, true)); } /** * Get parameters to sign * * @param array $params * @param array $ignoreParamKeys * @param int $currentLevel * @param string $prefix * * @return array */ private static function getParamsToSign( array $params, array $ignoreParamKeys = [], int $currentLevel = 1, string $prefix = '' ): array { $paramsToSign = []; foreach ($params as $key => $value) { if (in_array($key, $ignoreParamKeys, true)) { continue; } $paramKey = ($prefix ? $prefix . ':' : '') . $key; if (is_object($value)) { $value = get_object_vars($value); } if (is_array($value)) { $subArray = self::getParamsToSign($value, $ignoreParamKeys, $currentLevel + 1, $paramKey); $paramsToSign = array_merge($paramsToSign, $subArray); } else { if (is_bool($value)) { $value = $value ? '1' : '0'; } else { $value = (string)$value; } $paramsToSign[$paramKey] = (string)$paramKey . ':' . $value; } } if ($currentLevel == 1) { ksort($paramsToSign, SORT_NATURAL); } return $paramsToSign; } // Пример использования // указание секретного ключа и параметров вызова платёжной формы $secretKey = "jwfbfjhewbrw33383kr3js9d987"; $params = [ 'project_id' => 57123, 'payment_amount' => 1815, 'payment_currency' => 'EUR', 'customer_id' => 'customer_112', 'payment_id' => 'payment_443', ]; // формирование подписи $params['signature'] = Signer::sign($params, $secretKey); // получение ссылки для вызова платёжной формы $uriParams = http_build_query($params); $link = implode('?', ['https://paymentpage.ecommpay.com/payment', $uriParams]); ```   **2 Обеспечиваем приём оповещений** Чтобы оперативно узнавать о результатах платежей и получать другую значимую информацию, следует настроить приём и обработку программных оповещений от платёжной платформы. Это делается в три шага: 1. Определяем и задаём в платёжной платформе адрес для приёма веб-сервисом оповещений по проекту\(сначала можно задать один общий адрес, а после — несколько, под разные события\). Для этого открываем в интерфейсе Dashboard раздел **Проекты** и используем инструменты на вкладке **Оповещения**. 2. Настраиваем проверку целостности и разбор оповещений, поступающих на указанный URL, с использованием SDK. 3. Настраиваем отправку синхронных HTTP-ответов о приёме оповещений: `200 ОК` если подпись корректна и `400 Bad Request` если подпись некорректна. ```language-php // Работа с оповещениями. Пример сверки полученной подписи с расчётной require_once 'Signer.php'; $secretKey = ''; $requestBody = '{ "project_id": 57123, "payment": { "id": "payment_443", "type": "purchase", "status": "success", "date": "2022-03-03T10:50:29+0000", "method": "card", "sum": { "amount": 1815, "currency": "EUR" }, "description": "Test payment" }, "customer": { "id": "customer_112", "ip": "127.0.0.1", "phone": "60358490238", "email": "jane.doe@testmail.com" }, "operation": { "id": 15788000002076, "type": "sale", "status": "success", "date": "2022-03-03T10:50:29+0000", "sum_initial": { "amount": 1815, "currency": "EUR" }, "code": "0", "message": "Success" }, "signature": "zwoFECy7H+WZFziw9IgR9031Uu878TuIv3dhFyHvCuvzIdRAzDQA==" }'; $requestBodyArray = json_decode($requestBody, true); $actualSignature = $requestBodyArray['signature']; unset($requestBodyArray['signature']); $expectedSignature = Signer::sign($requestBodyArray, $secretKey); print_r('Actual signature: ' . $actualSignature . PHP_EOL); print_r('Expected signature: ' . $expectedSignature . PHP_EOL); if ($expectedSignature === $actualSignature) { print_r('Signatures are equal'); } else { print_r('Signatures are not equal'); } print_r(PHP_EOL); ``` Описания используемых статусов платежей можно найти [в отдельном разделе](ru_platform_payment_model.md), а описание оповещений и работы с ними — [в отдельной статье](ru_platform_callbacks.md#). При этом важно помнить, что в случаях, когда пользователь не подтверждает оплату в платёжной форме, платёж не регистрируется \(и статуса по нему тоже нет\). Извлечённую из оповещений информацию можно использовать для оперативного обновления статусов заказов в веб-сервисе, информирования пользователей и других целей — в соответствии с моделью работы вашего веб-сервиса. **1 Обеспечиваем подписывание данных** ```language-python # Кодирование алгоритма import hmac import base64 import hashlib class Signer: def getSign(self, params, key): byteKey = key.encode() paramsPrepared = self.getParamsToSign(params) toSignString = ';'.join(paramsPrepared.values()) hmacObj = hmac.new(byteKey, toSignString.encode(), hashlib.sha512) return base64.b64encode(hmacObj.digest()) def getParamsToSign(self, params, currentLevel = 1, prefix = ''): paramsToSign = dict() for paramKey in params.keys(): newParamKey = (prefix + ':' if prefix else '') + paramKey if isinstance(params[paramKey], (dict)): subDict = self.getParamsToSign(params[paramKey], currentLevel + 1, newParamKey) paramsToSign.update(subDict) else: if isinstance(params[paramKey], (bool)): value = '1' if params[paramKey] == True else '0' else: value = str(params[paramKey]) paramsToSign[newParamKey] = str(newParamKey + ':' + value) sortedParams = dict() for key in sorted(paramsToSign.keys()): sortedParams[key] = paramsToSign[key] return sortedParams # Пример использования # указание параметров вызова платёжной формы и секретного ключа import urllib.parse import Signer params = { 'project_id': 57123, 'payment_amount': 1815, 'payment_currency': 'EUR', 'customer_id': 'customer_112', 'payment_id': 'payment_443', } # формирование подписи signer = Signer.Signer() params['signature'] = signer.getSign(params, '') print(params['signature']) # получение ссылки для вызова платёжной формы jointParams = urllib.parse.urlencode(params) link = '?'.join(['https://paymentpage.ecommpay.com/payment', jointParams]) ```   **2 Обеспечиваем приём оповещений** Чтобы оперативно узнавать о результатах платежей и получать другую значимую информацию, следует настроить приём и обработку программных оповещений от платёжной платформы. Это делается в три шага: 1. Определяем и задаём в платёжной платформе адрес для приёма веб-сервисом оповещений по проекту\(сначала можно задать один общий адрес, а после — несколько, под разные события\). Для этого открываем в интерфейсе Dashboard раздел **Проекты** и используем инструменты на вкладке **Оповещения**. 2. Настраиваем проверку целостности и разбор оповещений, поступающих на указанный URL, с использованием SDK. 3. Настраиваем отправку синхронных HTTP-ответов о приёме оповещений: `200 ОК` если подпись корректна и `400 Bad Request` если подпись некорректна. ```language-python # Работа с оповещениями. Пример сверки полученной подписи с расчётной from Signer import Signer import base64 secretKey = '' params = { "project_id": 57123, "payment": { "id": "payment_443", "type": "purchase", "status": "success", "date": "2022-03-03T10:50:29+0000", "method": "card", "sum": { "amount": 1815, "currency": "EUR" }, "description": "Gagarin set" }, "customer": { "id": "customer_112", "ip": "127.0.0.1", "phone": "60358490238", "email": "jane.doe@testmail.com" }, "operation": { "id": 15788000002076, "type": "sale", "status": "success", "date": "2022-03-03T10:50:29+0000", "sum_initial": { "amount": 1815, "currency": "EUR" }, "code": "0", "message": "Success" }, "signature": "zwoFECy7H+WZFziw9IgR90SEmC+o3qXD7OIaHqgQuqcSwBC09W6yQA==" } signer = Signer() actualSign = params['signature'] del params['signature'] expectedSign = signer.getSign(params, secretKey).decode() print('Actual signature:' + actualSign) print('Expected signature:' + expectedSign) if (expectedSign == actualSign): print('Signature is correct') else: print('Signature is incorrect') ``` Описания используемых статусов платежей можно найти [в отдельном разделе](ru_platform_payment_model.md), а описание оповещений и работы с ними — [в отдельной статье](ru_platform_callbacks.md#). При этом важно помнить, что в случаях, когда пользователь не подтверждает оплату в платёжной форме, платёж не регистрируется \(и статуса по нему тоже нет\). Извлечённую из оповещений информацию можно использовать для оперативного обновления статусов заказов в веб-сервисе, информирования пользователей и других целей — в соответствии с моделью работы вашего веб-сервиса. **1 Обеспечиваем подписывание данных** ```language-javascript // Кодирование алгоритма import hmacSHA512 from 'crypto-js/hmac-sha512'; import encBase64 from 'crypto-js/enc-base64'; export class Signer { getSign(params, key) { const paramsPrepared = this.getParamsToSign(params, 1); const joinedString = Object.values(paramsPrepared).join(';'); const hash = hmacSHA512(joinedString, key); return hash.toString(encBase64); } getParamsToSign( params, prefix = '', ) { let paramsToSign = {}; let value = ''; let keys = Object.keys(params); let key = ''; for (let i = 0; i < keys.length; i++) { key = keys[i]; let paramKey = (prefix ? prefix + ':' : '') + key; if (typeof params[key] === 'object') { let subParams = this.getParamsToSign( params[key], paramKey, ); Object.assign(paramsToSign, subParams); } else { if (typeof params[key] === 'boolean') { value = params[key] === true ? '1' : '0'; } else { value = params[key].toString(); } paramsToSign[paramKey] = paramKey + ':' + value; } } let orderedKeys = Object.keys(paramsToSign).sort(); let ordered = {}; for (let k = 0; k < orderedKeys.length; k++) { ordered[orderedKeys[k]] = paramsToSign[orderedKeys[k]]; } return ordered; } } // Пример использования import { Signer } from './signer.js'; // указание параметров вызова платёжной формы и секретного ключа let params = { project_id: 57123, payment_amount: 1815, payment_currency: 'EUR', customer_id: 'customer_112', payment_id: 'payment_443', }; // формирование подписи params['signature'] = new signer().getSign(params, ''); // получение ссылки для вызова платёжной формы const uriParams = Object.keys(params) .sort() .reduce((paramsArray, key) => { paramsArray.push(key + '=' + encodeURIComponent(params[key])); return paramsArray; }, []); const link = [ 'https://paymentpage.ecommpay.com/payment', uriParams.join('&'), ].join('?'); ```   **2 Обеспечиваем приём оповещений** Чтобы оперативно узнавать о результатах платежей и получать другую значимую информацию, следует настроить приём и обработку программных оповещений от платёжной платформы. Это делается в три шага: 1. Определяем и задаём в платёжной платформе адрес для приёма веб-сервисом оповещений по проекту\(сначала можно задать один общий адрес, а после — несколько, под разные события\). Для этого открываем в интерфейсе Dashboard раздел **Проекты** и используем инструменты на вкладке **Оповещения**. 2. Настраиваем проверку целостности и разбор оповещений, поступающих на указанный URL, с использованием SDK. 3. Настраиваем отправку синхронных HTTP-ответов о приёме оповещений: `200 ОК` если подпись корректна и `400 Bad Request` если подпись некорректна. ```language-java // Работа с оповещениями. Пример сверки полученной подписи с расчётной import { Signer } from './Signer'; const secretKey = ''; const params = { "project_id": 57123, "payment": { "id": "payment_443", "type": "purchase", "status": "success", "date": "2022-03-03T10:50:29+0000", "method": "card", "sum": { "amount": 1815, "currency": "EUR" }, "description": "Gagarin set" }, "customer": { "id": "customer_112", "ip": "127.0.0.1", "phone": "60358490238", "email": "jane.doe@testmail.com" }, "operation": { "id": 15788000002076, "type": "sale", "status": "success", "date": "2022-03-03T10:50:29+0000", "sum_initial": { "amount": 1815, "currency": "EUR" }, "code": "0", "message": "Success" }, "signature": "zwoFECy7H+WZFziw9IgR90SHvCuvqXD7OIaHqgQuqcSwBC09W6yQA==" }; const actualSignature = params['signature']; delete params.signature; const expectedSignature = (new signer()).getSign(params, secretKey); console.log('Actual: ' + actualSignature); console.log('Expected: '+expectedSignature); if (actualSignature == expectedSignature) { console.log('Signatures is correct'); } else { console.log('Signature is incorrect'); } ``` Описания используемых статусов платежей можно найти [в отдельном разделе](ru_platform_payment_model.md), а описание оповещений и работы с ними — [в отдельной статье](ru_platform_callbacks.md#). При этом важно помнить, что в случаях, когда пользователь не подтверждает оплату в платёжной форме, платёж не регистрируется \(и статуса по нему тоже нет\). Извлечённую из оповещений информацию можно использовать для оперативного обновления статусов заказов в веб-сервисе, информирования пользователей и других целей — в соответствии с моделью работы вашего веб-сервиса. ### Действия в клиентской части {#section_ch3_gc2_4tb .section} Открывать Payment Page в клиентской части веб-сервиса можно по-разному, и для наглядности можно попробовать несколько способов даже в рамках быстрого старта. Самый простой способ — открывать платёжную форму в отдельной вкладке браузера. Чтобы открыть платёжную форму в виде отдельной HTML-страницы, следует использовать ссылку, полученную при подписывании данных.Это ссылка формата `https://paymentpage.ecommpay.com/payment?`, где `` — строка с названиями и значениями параметров вызова. HTTP-запрос с применением метода GET в таком случае может выглядеть следующим образом: ```language-xml GET /payment?payment_currency=EUR&project_id=42&payment_amount=1000& customer_id=123&payment_id=4438&signature=AE5hmtzdP0Dt7qGTg... HTTP/1.1 Host: https://paymentpage.ecommpay.com ``` Для использования других способов — с открытием платёжной формы в модальном окне и в элементе iframe — необходимо подключить две библиотеки: CSS для корректного отображения формы и JavaScript для вызова формы.Это делается через добавление ссылок на библиотеки в заголовочной части HTML-страницы. ```language-xml ... // подключение CSS-библиотеки // подключение JavaScript-библиотеки ... ``` Также для вызова платёжной формы с помощью JavaScript-библиотеки необходимо использовать подписанный набор параметров в виде JavaScript-объекта. Его можно формировать из ссылки, полученной при подписывании данных\(в PHP для этого можно использовать функции `parse_url` и `parse_str`\), или используя серверный код для формирования подписи \(без составления ссылки\)и добавляя подпись к остальным параметрам. Подключив библиотеки и разобравшись с параметрами, можно пробовать. Чтобы открыть Payment Page в модальном окне, можно использовать метод `run` JavaScript-объекта `EPayWidget`. При обращениях к этому методу следует указывать объект с параметрами вызова Payment Page \(`configObj`\) и HTTP-метод отправки запросов \(`method`\): ```language-json EPayWidget.run( { payment_id: 'payment_443', // идентификатор платежа payment_amount: 1815, // сумма платежа payment_currency: 'EUR', // код валюты платежа project_id: 57123, // идентификатор проекта customer_id: 'customer_112', // идентификатор пользователя signature: 'YWb6Z20ByxpQ30hfTI' }, // подпись 'post') // HTTP-метод ``` Чтобы открыть Payment Page в элементе iframe, как и в случае с модальным окном, можно использовать метод `run` JavaScript-объекта `EPayWidget`. В этом случае следует указывать объект с параметрами вызова Payment Page \(`configObj`\), идентификатор элемента, в котором необходимо отобразить платёжную форму \(`target_element`\), и HTTP-метод отправки запросов \(`method`\): ```language-json EPayWidget.run( { payment_id: 'payment_443', // идентификатор платежа payment_amount: 1815, // сумма платежа payment_currency: 'EUR', // код валюты платежа project_id: 57123, // идентификатор проекта customer_id: 'customer_112', // идентификатор пользователя signature: 'YWb6Z20ByxpQ30hfTI', // подпись target_element: 'widget-container' }, // идентификатор элемента 'post') // HTTP-метод ``` Чтобы открыть облегчённую редакцию платёжной формы Payment Page, необходимо использовать метод `runEmbedded` JavaScript-объекта `EPayWidget`. В этом случае следует указывать объект с параметрами вызова Payment Page \(`configObj`\), идентификатор элемента \(`target_element`\) и доменное имя веб-сервиса \(`merchant_domain`\), в которых необходимо отобразить платёжную форму: ``` {#codeblock_drm_f4d_33c .language-json} const configObj = { target_element: "widget-container-card-embedded", payment_id: "X03937", payment_amount: 1960, payment_currency: "EUR", project_id: 22, merchant_domain: "cosmoshop.jupiter.example", force_payment_method : "card", signature: "0ByxpQ30hfTIjaCCsVIwVyabcDEF123" }; ``` Следует учитывать, что для работы с облегчённой редакцией платёжной формы необходимо реализовать специализированные функции обработки интерфейсных событий. Для начального знакомства этих способов вызова и открытия может быть вполне достаточно. Если же необходима более тонкая настройка, можно обращаться [к документации](ru_PP_Integration.md) и к нашим специалистам. ## Тестирование {#ru_pp_quickstart_testing} Когда мы открываем платёжную форму в рабочем режиме, с ней работает пользователь. А в тестовом режиме можно почувствовать себя на его месте и протестировать разные сценарии оплаты с его позиции. Главный вопрос при этом — какие реквизиты указывать? При работе с тестовым проектом можно использовать два вида платёжных реквизитов: *специальные* тестовые, позволяющие тестировать заданные сценарии работы, и *произвольные* реалистичные, позволяющие дополнительно проверить работу формы в разных случаях. В базовом случае можно использовать следующие тестовые номера платёжных карт\(для проведения платежей по заданным кратчайшим сценариям, без эмулирования аутентификации 3‑D Secure\): - `4000 0000 0000 0077` — для проведения оплаты; - `4111 1111 1111 1111` — для отклонения оплаты. ![](images/ecommpay/ru_pp_quickstart_2.svg) Для более масштабного тестирования можно использовать расширенный набор тестовых данных для [карточных](ru_test_cards.md) \(в том числе с аутентификацией 3‑D Secure\)и различных [альтернативных](ru_pm_testing.md)платежей, а также произвольные данные, включая реквизиты реальных карт, кошельков и других платёжных инструментов. Это безопасно, поскольку для всех данных в тестовой среде обеспечивается тот же уровень защиты, что и в рабочей, но реальные платежи при этом не проводятся. По итогам тестирования, убедившись в корректной работе с формой, можно считать реализованными базовые функции по проведению оплат и при желании переходить дальше — к различным дополнениям, которые могут быть полезны уже на первых порах работы с платёжной платформой, и к запуску решения в работу. ## Дополнения {#ru_pp_quickstart_additional_aspects} ### Контроль проведения платежей {#section_j4g_s22_4tb .section} После проведения нескольких тестовыхплатежей можно разобраться с тем, как контролировать общую ситуацию по платежам. Для этого следует открыть Dashboard и ознакомиться там с реестром и карточками платежей. ![](images/ecommpay/dbl/ru_quickstart_dbl_overview.svg "Реестр платежей") ![](images/ecommpay/dbl/ru_quickstart_dbl_payment_details.svg "Карточка платежа") При возникновении вопросов по работе с этим интерфейсом, как и в иных случаях, можно обращаться [к документации](ru_dbl_payments.md#) и к нашим специалистам. ### Возврат средств {#section_c4b_pf2_4tb .section} Если по какой-либо проведённой оплате необходимо выполнить возврат, для этого также можно использовать Dashboard. При тестировании работы с платёжной платформой можно попробовать выполнить полные и частичные возвраты из карточек платежей. Для более глубокого освоения работы с возвратами, в том числе с массовыми, можно использовать [отдельную статью](ru_dbl_payments.md#).Кроме того, полезно иметь в виду возвраты [через Gate](ru_Gate_Refund.md). ### Возможности управления формой {#section_um4_xf2_4tb .section} При работе с Payment Page можно оперировать различными возможностями, чтобы управлять видом и поведением формы, например, задавая подходящий язык, фильтруя методы оплаты или управляя способами возвращения пользователя к веб-сервису. Некоторые из таких возможностей требуют подключения через специалистов Ecommpay, иные можно использовать без обращений к кому-либо, просто настроив их через Dashboard или передавая дополнительные параметры в запросах на открытие Payment Page. При тестировании работы с Payment Page мы рекомендуем попробовать следующее: - *Настроить оформление платёжной формы с помощью конструктора*. Для этого следует перейти в раздел **Проекты** интерфейса Dashboard и воспользоваться инструментами вкладки **Payment Page Designer** \(подробнее — в статье [Индивидуальное оформление](ru_PP__design_customisation.md#)\). - *Попробовать вызов платёжной формы на разных языках*. Чтобы открыть Payment Page на определённом языке, его код \(в двухбуквенном формате ISO 639-1 alpha-2\) следует передать в значении соответствующего параметра: `language_code`. Список поддерживаемых Ecommpay языков можно найти [здесь](ru_PP_WigetLanguages.md). - *Возвращать пользователя к веб-сервису после проведения платежей*. После проведения платежей в зависимости от их результатов можно перенаправлять пользователей к разным страницам веб-сервиса. Адреса таких страниц можно задать в разделе **Проекты** интерфейса Dashboard \(во вкладке **Ссылки для перенаправления**\), либо передавать их в конкретных запросах в значении параметров `merchant_success_url` и `merchant_fail_url`. - *И далее на ваш вкус*. Информацию о разных возможностях можно найти [в общем обзоре](ru_PP_general.md#) и [в специализированном разделе](ru_PP_Additional.md), а полный перечень параметров вызова — [в отдельной статье](ru_PP_Parameters.md). С вопросами же, как обычно, можно обращаться к нашим специалистам. ## Запуск {#ru_pp_quickstart_launch_project} После реализации базовых функций, тестирования разных возможностей и определения необходимых вам сценариев работы можно переходить к запуску рабочего проекта. Важно, чтобы к этому моменту были решены организационные вопросы. В таком случае вопросы технические сводятся к настройке свойств проекта на стороне платёжной платформы и к началу использования идентификатора и ключа рабочего проекта. Успехов!