diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..7568f7d
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,11 @@
+# Main project pipeline
+variables:
+ GIT_STRATEGY: none
+
+stages:
+ - code-approve-reset
+ - mr-approve-check
+
+include:
+ - local: 'ci/code-approve-reset.yml'
+ - local: 'ci/mr-approve-check.yml'
diff --git a/README.md b/README.md
index 4a6a779..b598cd9 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,111 @@
# «Твои Платежи»: Интеграция на PHP
-Готовая библиотека + подробные примеры с комментариями. Требования: [PHP 7.4 и выше](https://github.com/yourpayments/php-api-client/blob/main/composer.json)
+Готовая библиотека PHP API Client для YourPayments +
+подробные примеры с комментариями

-[Пакет Composer](https://packagist.org/packages/yourpayments/php-api-client) может
-использоваться с любыми фреймворками, платформами и CMS, включая, но не ограничиваясь: Laravel, Bitrix, Wordpress, Yii, Symfony, и др.
+## Оглавление
+- [Описание](#описание)
+- [Требования](#требования)
+- [Установка](#установка)
+ - [Запуск встроенного сервера](#запуск-встроенного-сервера)
+ - [Запуск в контейнере docker](#запуск-в-контейнере-docker)
+- [Примеры использования](#примеры-использования)
+ - [Начало работы: настройка интеграции](#1-начало-работы-настройка-интеграции)
+ - [Приём платежей](#2-приём-платежей)
+ - [Подписки](#3-подписки) (рекуррентные платежи)
+ - [Токенизация](#4-токенизация) (запомнить данные плательщика, чтобы не запрашивать и не вводить их повторно)
+ - [Отчёты и статусы платежей](#5-отчёты)
+ - [Возврат средств плательщику](#6-возврат-средств-плательщику-refund) (refunds, рефанды)
+ - [Выплаты](#7-выплаты) (отправка денег по номеру карты или телефона)
+ - [Подключение продавцов](#8-подключение-продавцов)
+ - [Обработка вебхуков](#9-обработка-вебхуков)
+ - [Страница после оплаты](#10-страница-после-оплаты)
+ - [Безопасные поля](#11-безопасные-поля-secure-fields) (отдельный вид интеграции карточной формы)
+ - [Обработка ошибок](#12-обработка-ошибок)
+- [Обновление библиотеки](#обновление)
+- [Поддержка и контакты](#ссылки-поддержка-и-контакты)
+
+## Описание
+`yourpayments/php-api-client` — это PHP библиотека для быстрой и удобной интеграции с платежным шлюзом YourPayments.
+С её помощью можно принимать оплаты и создавать выплаты, получать отчёты, делать возвраты и работать с подпискам.
+
+Библиотека ориентирована на простое и надёжное использование, подходит как для опытных, так и для начинающих разработчиков.
+
+Особенностями этой системы являются:
+- мульти-эквайринг (работа сразу со многими банками)
+- поддержка сплитования (много получателей платежа в одном чеке)
+- безопасность и точность расчётов
+
+Библиотека содержит:
+- Сам клиент API
+- Простой встроенный сервер с примерами
+- Описание контейнера для запуска в Docker
+
+---
+
+## Требования
+
+- PHP 7.4 и выше (рекомендуется PHP 8.1+)
+- Расширения PHP: `curl`, `json`, `mbstring`
+- Рекомендуется: Composer для управления зависимостями
+
+---
+
+## Установка
+Установка с [пакета composer](https://packagist.org/packages/yourpayments/php-api-client) -- самый простой и рекомендуемый способ:
-## Установка и обновление за 1 минуту
```shell
composer require yourpayments/php-api-client
```
+
+Если на вашем проекте нет Composer,
+склонируйте или скачайте, а затем подключите файлы этого репозитория,
+([пример](src/Examples/autoload.php))
+
+### Запуск встроенного сервера
```shell
-composer update yourpayments/php-api-client
+php -S localhost:8081 index.php
```
-(если на вашем проекте нет composer, слонируйте или скачайте, а затем подключите ([require](https://www.php.net/manual/ru/function.require.php)) файлы этого репозитория)
-## Запуск в контейнере docker
+После запуска по адресу http://localhost:8081 будут доступны интерактивные примеры в следующем виде:
+
+
+
+### Запуск в контейнере docker
Создайте и запустите docker контейнер следующей командой:
```shell
docker compose up
```
-либо в фоновом режиме командой:
+
+Либо в фоновом режиме командой:
```shell
docker compose up --detach
```
После выполнения сервис с документацией и примерами будет доступен по адресу http://localhost:8080/
+
+---
-## Примеры с комментариями на русском языке:
+## Примеры использования:
##### 1. [Начало работы: настройка интеграции](src/Examples/start.php)
-##### 2. Платежи
+##### 2. Приём платежей
1. [Cамый простой платёж](src/Examples/simpleGetPaymentLink.php)
-2. [Подробный платёж](src/Examples/getPaymentLink.php)
-3. [Платёж через СБП (Систему Быстрых Платежей)](src/Examples/getFasterPayment.php)
-4. [Платёж со сплитом (разделением платежа)](src/Examples/getPaymentLinkMarketplace.php)
-5. [Списание средств](src/Examples/paymentCapture.php)
+1. [Подробный платёж](src/Examples/getPaymentLink.php)
+1. [Платёж со сплитом (разделением платежа для нескольких получателей)](src/Examples/getPaymentLinkMarketplace.php)
+1. [Платёж через СБП (Систему Быстрых Платежей)](src/Examples/getFasterPayment.php)
+1. [Списание средств (только для двустадийной оплаты)](src/Examples/paymentCapture.php)
+1. [Встраивание QR-кода без страницы оплаты](/src/Examples/payQrCode.php)
-##### 3. Подписки СБП
+##### 3. Подписки
+Рекуррентные платежи
1. [Создание подписки СБП](src/Examples/getBindingFasterPayment.php)
-2. [Оплата по подписке СБП](src/Examples/paymentByFasterBinding.php)
+1. [Оплата по подписке СБП](src/Examples/paymentByFasterBinding.php)
+1. [Создание подписки SberPay, T-Pay, Картой не РФ](src/Examples/getBindingPays.php)
+1. [Оплата по подписке SberPay, T-Pay, Картой не РФ](src/Examples/paymentByBindingPays.php)
-##### 4. Токенизация карты (чтобы запомнить карту клиента и не вводить повторно)
+##### 4. Токенизация
+Запомнить данные клиента, чтобы не запрашивать и не вводить их повторно
1. [Создание платёжного токена ](src/Examples/getToken.php)
2. [Оплата токеном](src/Examples/paymentByToken.php)
@@ -57,28 +122,48 @@ docker compose up --detach
##### 7. Выплаты
1. [Выплаты на банковские карты](src/Examples/payoutCreate.php)
+2. [Запрос баланса для выплаты](src/Examples/payoutGetBalance.php)
-##### 8. [Безопасные поля (Secure fields)](src/Examples/secureFields.php)
-2. [Создание сессии](src/Examples/getSession.php)
-3. [Оплата одноразовым токеном](src/Examples/oneTimeTokenPayment.php)
-
-##### 9. [Страница после оплаты](src/Examples/returnPage.php)
-
-##### 10. Подключение продавцов (сабмерчантов маркетплейсов)
+##### 8. Подключение продавцов
+Добавление сабмерчантов маркетплейсов по API
1. [Подключение продавца-юридического лица (отправка анкеты)](src/Examples/qstCreateOrg.php)
2. [Подключение продавца-ИП (отправка анкеты)](src/Examples/qstCreateIp.php)
3. [Получение статуса анкеты](src/Examples/qstStatus.php)
4. [Печать анкеты](src/Examples/qstPrint.php)
5. [Список анкет](src/Examples/qstList.php)
-##### 11. Виджет
-- [Подключение виджета](src/Examples/getWidget.php)
+##### 9. [Обработка вебхуков](src/Examples/webhookProcessing.php)
+Вебхуки -- HTTP запросы, оповещающие ваш сервер о событиях (успешные и неуспешные оплаты, списания)
+
+##### 10. [Страница после оплаты](src/Examples/returnPage.php)
+
+##### 11. [Безопасные поля (Secure fields)](src/Examples/secureFields.php)
+2. [Создание сессии](src/Examples/getSession.php)
+3. [Оплата одноразовым токеном](src/Examples/oneTimeTokenPayment.php)
+
+##### 12. Обработка ошибок
+Библиотека выбрасывает один вид исключений: [Ypmn\PaymentException](/src/PaymentException.php).
+
+Пример перехвата исключения можно посмотреть в примере: [Cамый простой платёж](src/Examples/simpleGetPaymentLink.php)
+
+---
+
+## Обновление
+
+Обновления библиотеки позволяют быстро исправлять ошибки и получать доступ к новым функциям
+
+```shell
+composer update yourpayments/php-api-client
+```
+
+---
-## Ссылки
-- [НКО «Твои Платежи»](https://YPMN.ru/)
-- [Докуметация API](https://ypmn.ru/ru/documentation/)
-- [Тестовые банковские карты](https://ypmn.ru/ru/documentation/#tag/testing)
+## Ссылки, поддержка и контакты
+- [НКО «Твои Платежи»](https://YPMN.ru/?utm_source=php-api-client)
+- [Докуметация API](https://ypmn.ru/ru/documentation/?utm_source=php-api-client)
+- [Тестовые банковские карты](https://ypmn.ru/ru/documentation/?utm_source=php-api-client#tag/testing)
+- [FAQ, ответы на частые вопросы](https://ypmn.ru/ru/support/?utm_source=php-api-client)
- [Задать вопрос или сообщить о проблеме](https://github.com/yourpayments/php-api-client/issues/new)
--------------
-🟢 [«Твои Платежи»](https://YPMN.ru/ "Платёжная система для сайтов, платформ и приложений") -- финтех-составляющая для сайтов, платформ и приложений
+---
+🟢 [«Твои Платежи»](https://YPMN.ru/ "Платёжная система для сайтов, платформ и приложений") -- финтех для сайтов, платформ и приложений
diff --git a/ci/code-approve-reset.yml b/ci/code-approve-reset.yml
new file mode 100644
index 0000000..e994d37
--- /dev/null
+++ b/ci/code-approve-reset.yml
@@ -0,0 +1,7 @@
+## Removes all previously applied approvers in MR
+clear_code_approved:
+ stage: code-approve-reset
+ rules:
+ - if: $CI_MERGE_REQUEST_ID
+ script:
+ - 'curl -f -X PUT -H "PRIVATE-TOKEN: $REMOVE_APPROVE_TOKEN" -H "Content-Type: application/json" "http://gtl01.dev.ruo.payudc.net/api/v4/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/reset_approvals"'
diff --git a/ci/mr-approve-check.yml b/ci/mr-approve-check.yml
new file mode 100644
index 0000000..592fbb8
--- /dev/null
+++ b/ci/mr-approve-check.yml
@@ -0,0 +1,48 @@
+## Blocks the pipeline if MR is not approved by any
+## of defined gitlab users (ALLOWED_APPROVERS)
+
+mr-approve-check:
+ stage: mr-approve-check
+ needs: ["clear_code_approved"]
+ tags:
+ - mr-check
+ variables:
+ TARGET_BRANCH: main
+ script:
+ - |
+ # Fetch the merge request ID from the environment variable
+ # $merge_request_iid variable is set in gitlab webhook payload
+ if [[ "$CI_PIPELINE_SOURCE" == "trigger" ]]; then
+ MR_ID=${merge_request_iid}
+ else
+ MR_ID=${CI_MERGE_REQUEST_IID}
+ fi
+
+ # Check if MR_ID is set
+ if [ -z "$MR_ID" ]; then
+ echo "This job is not running in a merge request context."
+ exit 0
+ fi
+
+ # Get the list of approvals for the merge request
+ APPROVALS=$(curl --silent -H "PRIVATE-TOKEN: $REMOVE_APPROVE_TOKEN" -H "Content-Type: application/json" "http://gtl01.dev.ruo.payudc.net/api/v4/projects/$CI_PROJECT_ID/merge_requests/$MR_ID/approvals")
+
+ # Define a list of allowed approvers
+ ALLOWED_APPROVERS=("alexander.viktorchik" "alexey.babak" "roman.zimin")
+
+ # Check if any of the allowed users have approved the merge request
+ APPROVED=false
+ for USER in "${ALLOWED_APPROVERS[@]}"; do
+ if echo "$APPROVALS" | grep -q "$USER"; then
+ APPROVED=true
+ echo "Merge request approved by allowed user: $USER."
+ break
+ fi
+ done
+
+ if [ "$APPROVED" = false ]; then
+ echo "Merge request not approved by any allowed users. Blocking the merge request."
+ exit 1
+ fi
+ rules:
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $TARGET_BRANCH'
diff --git a/example.php b/example.php
index 964e2dc..92f5b53 100644
--- a/example.php
+++ b/example.php
@@ -26,6 +26,7 @@
case 'paymentCapture':
case 'paymentGetStatus':
case 'payoutCreate':
+ case 'payoutGetBalance':
case 'paymentWebhook':
case 'paymentRefund':
case 'paymentRefundMarketplace':
@@ -41,12 +42,16 @@
case 'getFasterPaymentWithReceipts':
case 'getBindingFasterPayment':
case 'paymentByFasterBinding':
+ case 'paymentByBindingPays':
+ case 'getBindingPays':
case 'qstCreateOrg':
case 'qstCreateIp':
case 'qstStatus':
case 'qstPrint':
case 'SOMGetPaymentLink':
case 'qstList':
+ case 'webhookProcessing':
+ case 'payQrCode':
require './src/Examples/start.php';
@include './src/Examples/'.$_GET['function'] . '__prepend.php';
require './src/Examples/'.$_GET['function'] . '.php';
diff --git a/example_list.php b/example_list.php
index e961d69..7f9b537 100644
--- a/example_list.php
+++ b/example_list.php
@@ -31,13 +31,19 @@
'getFasterPayment' => [
'name' => 'Оплата через СБП',
'about' => 'Пример платежа через систему быстрых платежей',
- 'docLink' => 'https://ypmn.ru/ru/documentation/',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-api/paths/~1v4~1payments~1authorize/post',
'link' => '',
],
'getFasterPaymentWithReceipts' => [
'name' => 'Оплата через СБП с регистрацией чека',
'about' => 'Пример платежа через систему быстрых платежей с регистрацией чека',
- 'docLink' => 'https://ypmn.ru/ru/documentation/',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-api/paths/~1v4~1payments~1authorize/post',
+ 'link' => '',
+ ],
+ 'payQrCode' => [
+ 'name' => 'QR-код на примере TPay',
+ 'about' => 'Пример отображение QR-кода Pay-метода без платёжной формы',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-api/paths/~1v4~1payments~1authorize/post',
'link' => '',
],
'getBindingFasterPayment' => [
@@ -52,6 +58,18 @@
'docLink' => 'https://ypmn.ru/ru/documentation/',
'link' => '',
],
+ 'getBindingPays' => [
+ 'name' => 'Создание токена SberPay',
+ 'about' => 'В этом примере отправляется запрос на создание токена SberPay с одновременной оплатой',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-api/paths/~1v4~1payments~1authorize/post',
+ 'link' => '',
+ ],
+ 'paymentByBindingPays' => [
+ 'name' => 'Оплата по токену SberPay',
+ 'about' => 'Это пример демонстрирует оплату через SberPay по средством ранее созданного токена',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-api/paths/~1v4~1payments~1authorize/post',
+ 'link' => '',
+ ],
'getPaymentLinkMarketplace' => [
'name' => 'Платёж со сплитом',
'about' => 'Это пример платежа со сплитом (разделением оплаты на несколько плательщиков).',
@@ -106,6 +124,12 @@
'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payouts-api',
'link' => '',
],
+ 'payoutGetBalance' => [
+ 'name' => 'Получение баланса для выплаты',
+ 'about' => 'Запрос к YPMN для проверки баланса на вылпату',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payouts-api/paths/~1v4~1payout~1balance/get',
+ 'link' => '',
+ ],
'getSession' => [
'name' => 'Создание сессии',
'about' => 'Создание уникальной сессии YPMN',
@@ -178,10 +202,10 @@
'docLink' => 'https://ypmn.ru/ru/documentation/#tag/qst-api/paths/~1v4~1qst~1list/get',
'link' => '',
],
- 'getWidget' => [
- 'name' => 'Получение виджета',
- 'about' => 'В этом примере показано получение виджета.',
- 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/widget-integration',
- 'link' => '',
- ],
+ 'webhookProcessing' => [
+ 'name' => 'Обработка вебхука',
+ 'about' => 'В этом примере показана обработка вебхука IPN',
+ 'docLink' => 'https://ypmn.ru/ru/documentation/#tag/webhooks',
+ 'link' => '',
+ ]
];
diff --git a/screenshot2.jpg b/screenshot2.jpg
new file mode 100644
index 0000000..2c5e9b4
Binary files /dev/null and b/screenshot2.jpg differ
diff --git a/src/ApiRequest.php b/src/ApiRequest.php
index bba673e..929ea33 100644
--- a/src/ApiRequest.php
+++ b/src/ApiRequest.php
@@ -19,6 +19,7 @@ class ApiRequest implements ApiRequestInterface
public const REFUND_API = '/api/v4/payments/refund';
public const STATUS_API = '/api/v4/payments/status';
public const PAYOUT_CREATE_API = '/api/v4/payout';
+ public const PAYOUT_GET_BALANCE_API = '/api/v4/payout/balance';
public const REPORTS_ORDERS_API = '/reports/orders';
public const SESSION_API = '/api/v4/payments/sessions';
public const REPORT_CHART_API = '/api/v4/reports/chart';
@@ -542,6 +543,31 @@ public function sendPayoutCreateRequest(PayoutInterface $payout): array
return $this->sendPostRequest($payout, self::PAYOUT_CREATE_API);
}
+ /**
+ * @inheritdoc
+ * @throws PaymentException
+ */
+ public function sendPayoutGetBalanceRequest(array $params = []): array
+ {
+ $url = self::PAYOUT_GET_BALANCE_API;
+
+ if (!empty($params)) {
+ $url .= '?' . http_build_query($params);
+ }
+
+ $responseData = $this->sendGetRequest($url);
+
+ if (mb_strlen($responseData['error']) > 0) {
+ throw new PaymentException($responseData['error']);
+ }
+
+ if ($responseData['response'] == null || strlen($responseData['response']) === 0) {
+ throw new PaymentException('Непредвиденная ошибка!.');
+ }
+
+ return $responseData;
+ }
+
/** @inheritdoc
* @throws PaymentException
*/
@@ -700,7 +726,7 @@ class="w-100 d-block"
border: 1px solid green;
white-space: pre-wrap;
"
- >' . print_r($mixedInput, true) . '';
+ >' . htmlspecialchars(print_r($mixedInput, true)) . '';
}
}
diff --git a/src/ApiRequestInterface.php b/src/ApiRequestInterface.php
index 4ae7e73..8033db7 100644
--- a/src/ApiRequestInterface.php
+++ b/src/ApiRequestInterface.php
@@ -104,6 +104,13 @@ public function sendTokenCreationRequest(PaymentReference $payuPaymentReference)
*/
public function sendTokenPaymentRequest(MerchantToken $tokenHash): array;
+ /**
+ * Отправить запрос на получение баланса
+ * @param array $params
+ * @return array
+ */
+ public function sendPayoutGetBalanceRequest(array $params = []): array;
+
/**
* Отправить запрос для получения графика
* @param array $params
diff --git a/src/Authorization.php b/src/Authorization.php
index 791a76a..7cbf549 100644
--- a/src/Authorization.php
+++ b/src/Authorization.php
@@ -49,7 +49,7 @@ public function setPaymentMethod(?string $paymentMethod = null) : self
switch ($paymentMethod) {
case PaymentMethods::CCVISAMC:
case PaymentMethods::FASTER_PAYMENTS:
- case PaymentMethods::SOM:
+ case PaymentMethods::INTCARD:
case PaymentMethods::MIRPAY:
case PaymentMethods::ALFAPAY:
case PaymentMethods::TPAY:
@@ -70,7 +70,7 @@ public function setPaymentMethod(?string $paymentMethod = null) : self
}
/** @inheritDoc */
- public function setUsePaymentPage(bool $isUsed) : self
+ public function setUsePaymentPage(?bool $isUsed) : self
{
if ($isUsed === true) {
if (is_null($this->merchantToken) && is_null($this->cardDetails)) {
diff --git a/src/AuthorizationInterface.php b/src/AuthorizationInterface.php
index f51e3ff..8f5d7df 100644
--- a/src/AuthorizationInterface.php
+++ b/src/AuthorizationInterface.php
@@ -20,10 +20,10 @@ public function getPaymentMethod(): ?string;
/**
* Установить Использование платёжной страницы
- * @param bool $isUsed Использовать платёжную страницу
+ * @param null|bool $isUsed Использовать платёжную страницу
* @return AuthorizationInterface
*/
- public function setUsePaymentPage(bool $isUsed): self;
+ public function setUsePaymentPage(?bool $isUsed): self;
/**
* Получить Данные Карты
diff --git a/src/Billing.php b/src/Billing.php
index 3f4c0a9..faa2594 100644
--- a/src/Billing.php
+++ b/src/Billing.php
@@ -47,9 +47,9 @@ class Billing implements BillingInterface
private ?IdentityDocumentInterface $identityDocument = null;
/** @inheritDoc */
- public function getFirstName(): string
+ public function getFirstName(): ?string
{
- return $this->firstName;
+ return $this->firstName ?? null;
}
/** @inheritDoc */
@@ -60,9 +60,9 @@ public function setFirstName(string $firstName): self
}
/** @inheritDoc */
- public function getLastName(): string
+ public function getLastName(): ?string
{
- return $this->lastName;
+ return $this->lastName ?? null;
}
/** @inheritDoc */
@@ -75,7 +75,7 @@ public function setLastName(string $lastName): self
/** @inheritDoc */
public function getEmail(): ?string
{
- return $this->email;
+ return $this->email ?? null;
}
/** @inheritDoc */
@@ -218,7 +218,7 @@ public function getIdentityDocument(): ?IdentityDocumentInterface
}
/** @inheritdoc */
- public function getType(): string
+ public function getType(): ?string
{
return $this->type;
}
diff --git a/src/BillingInterface.php b/src/BillingInterface.php
index 45f1aa3..18d6fd3 100644
--- a/src/BillingInterface.php
+++ b/src/BillingInterface.php
@@ -13,9 +13,9 @@ public function setFirstName(string $firstName) : self;
/**
* Получить Имя
- * @return string
+ * @return string|null
*/
- public function getFirstName() : string;
+ public function getFirstName() : ?string;
/**
* Установить Фамилия
@@ -26,9 +26,9 @@ public function setLastName(string $lastName) : self;
/**
* Получить Фамилия
- * @return string
+ * @return string|null
*/
- public function getLastName() : string;
+ public function getLastName() : ?string;
/**
* Установить Email
@@ -52,7 +52,7 @@ public function setPhone(string $phone) : self;
/**
* Получить Номер Телефона
- * @return string
+ * @return string|null
*/
public function getPhone() : ?string;
@@ -65,7 +65,7 @@ public function setCountryCode(string $countryCode) : self;
/**
* Получить Код Страны
- * @return string
+ * @return string|null
*/
public function getCountryCode() : ?string;
@@ -78,7 +78,7 @@ public function setCity(string $city) : self;
/**
* Получить Город
- * @return string
+ * @return string|null
*/
public function getCity() : ?string;
@@ -91,7 +91,7 @@ public function setState(string $state) : self;
/**
* Получить Регион
- * @return string
+ * @return string|null
*/
public function getState() : ?string;
@@ -176,9 +176,9 @@ public function getIdentityDocument(): ?IdentityDocumentInterface;
/**
* Получить тип биллинга
- * @return string
+ * @return string|null
*/
- public function getType(): string;
+ public function getType(): ?string;
/**
* Установить тип биллинга
diff --git a/src/CardDetails.php b/src/CardDetails.php
index a3994ff..1f0515e 100644
--- a/src/CardDetails.php
+++ b/src/CardDetails.php
@@ -38,7 +38,7 @@ class CardDetails implements CardDetailsInterface
private string $cardIssuerBank;
/** @inheritDoc */
- public function getNumber(): string
+ public function getNumber(): ?string
{
return $this->number;
}
@@ -53,9 +53,9 @@ public function setNumber(string $number): self
}
/** @inheritDoc */
- public function getExpiryMonth(): int
+ public function getExpiryMonth(): ?int
{
- return $this->expiryMonth;
+ return $this->expiryMonth ?? null;
}
/** @inheritDoc */
@@ -66,9 +66,9 @@ public function setExpiryMonth(int $expiryMonth): self
}
/** @inheritDoc */
- public function getYear(): int
+ public function getYear(): ?int
{
- return $this->year;
+ return $this->year ?? null;
}
/** @inheritDoc */
@@ -83,9 +83,9 @@ public function setYear(int $year): self
}
/** @inheritDoc */
- public function getExpiryYear(): int
+ public function getExpiryYear(): ?int
{
- return $this->expiryYear;
+ return $this->expiryYear ?? null;
}
/** @inheritDoc */
@@ -96,9 +96,9 @@ public function setExpiryYear(int $expiryYear): self
}
/** @inheritDoc */
- public function getCvv(): string
+ public function getCvv(): ?string
{
- return $this->cvv;
+ return $this->cvv ?? null;
}
/** @inheritDoc */
@@ -109,9 +109,9 @@ public function setCvv(string $cvv): self
}
/** @inheritDoc */
- public function getOwner(): string
+ public function getOwner(): ?string
{
- return $this->owner;
+ return $this->owner ?? null;
}
/** @inheritDoc */
@@ -122,9 +122,9 @@ public function setOwner(string $owner): self
}
/** @inheritDoc */
- public function getTimeSpentTypingNumber(): int
+ public function getTimeSpentTypingNumber(): ?int
{
- return $this->timeSpentTypingNumber;
+ return $this->timeSpentTypingNumber ?? null;
}
/** @inheritDoc */
@@ -135,9 +135,9 @@ public function setTimeSpentTypingNumber(int $timeSpentTypingNumber): self
}
/** @inheritDoc */
- public function getTimeSpentTypingOwner(): int
+ public function getTimeSpentTypingOwner(): ?int
{
- return $this->timeSpentTypingOwner;
+ return $this->timeSpentTypingOwner ?? null;
}
/** @inheritDoc */
@@ -148,9 +148,9 @@ public function setTimeSpentTypingOwner(int $timeSpentTypingOwner): self
}
/** @inheritDoc */
- public function getBin(): int
+ public function getBin(): ?int
{
- return $this->bin;
+ return $this->bin ?? null;
}
/** @inheritDoc */
@@ -161,9 +161,9 @@ public function setBin(int $bin): self
}
/** @inheritDoc */
- public function getPan(): string
+ public function getPan(): ?string
{
- return $this->pan;
+ return $this->pan ?? null;
}
/** @inheritDoc */
@@ -174,9 +174,9 @@ public function setPan(string $pan): self
}
/** @inheritDoc */
- public function getType(): string
+ public function getType(): ?string
{
- return $this->type;
+ return $this->type ?? null;
}
/** @inheritDoc */
@@ -187,9 +187,9 @@ public function setType(string $type): self
}
/** @inheritDoc */
- public function getCardIssuerBank(): string
+ public function getCardIssuerBank(): ?string
{
- return $this->cardIssuerBank;
+ return $this->cardIssuerBank ?? null;
}
/** @inheritDoc */
diff --git a/src/CardDetailsInterface.php b/src/CardDetailsInterface.php
index 13f3e35..73fae78 100644
--- a/src/CardDetailsInterface.php
+++ b/src/CardDetailsInterface.php
@@ -14,9 +14,9 @@ public function setExpiryMonth(int $expiryMonth) : self;
/**
* Получить Месяц прекращения действия Карты
- * @return int
+ * @return int|null
*/
- public function getExpiryMonth() : int;
+ public function getExpiryMonth() : ?int;
/**
* Установить Год прекращения действия Карты
@@ -28,9 +28,9 @@ public function setExpiryYear(int $expiryYear) : self;
/**
* Получить Год прекращения действия Карты
- * @return int Год прекращения действия Карты
+ * @return int|null Год прекращения действия Карты
*/
- public function getExpiryYear() : int;
+ public function getExpiryYear() : ?int;
/**
* Установить CVV Карты
@@ -41,9 +41,9 @@ public function setCvv(string $cvv) : self;
/**
* Получить CVV Карты
- * @return string CVV Карты
+ * @return string|null CVV Карты
*/
- public function getCvv() : string;
+ public function getCvv() : ?string;
/**
* Установить Имя Владельца Карты
@@ -54,9 +54,9 @@ public function setOwner(string $owner) : self;
/**
* Получить Имя Владельца Карты
- * @return string Имя Владельца Карты
+ * @return string|null Имя Владельца Карты
*/
- public function getOwner() : string;
+ public function getOwner() : ?string;
/**
* Установить Время набора Номера Карты (сек)
@@ -67,9 +67,9 @@ public function setTimeSpentTypingNumber(int $timeSpentTypingNumber) : self;
/**
* Получить Время набора номера Карты (сек)
- * @return int Время набора Номера Карты (сек)
+ * @return int|null Время набора Номера Карты (сек)
*/
- public function getTimeSpentTypingNumber() : int;
+ public function getTimeSpentTypingNumber() : ?int;
/**
* Установить Время набора Имени Владельца Карты (сек)
@@ -80,9 +80,9 @@ public function setTimeSpentTypingOwner(int $timeSpentTypingOwner) : self;
/**
* Получить Время набора Имени Владельца Карты
- * @return int Время набора Имени Владельца Карты (сек)
+ * @return int|null Время набора Имени Владельца Карты (сек)
*/
- public function getTimeSpentTypingOwner() : int;
+ public function getTimeSpentTypingOwner() : ?int;
/**
* Установить BIN (Bank Identification Number)
@@ -93,9 +93,9 @@ public function setBin(int $bin) : self;
/**
* Получить BIN (Bank Identification Number)
- * @return int BIN (Bank Identification Number)
+ * @return int|null BIN (Bank Identification Number)
*/
- public function getBin() : int;
+ public function getBin() : ?int;
/**
* Установить PAN (Permanent Account Number)
@@ -106,9 +106,9 @@ public function setPan(string $pan) : self;
/**
* Получить PAN (Permanent Account Number)
- * @return string PAN (Permanent Account Number)
+ * @return string|null PAN (Permanent Account Number)
*/
- public function getPan() : string;
+ public function getPan() : ?string;
/**
* Установить Тип Карты (например, Visa, MIR)
@@ -119,9 +119,9 @@ public function setType(string $type) : self;
/**
* Получить Тип Карты (например, Visa, MIR)
- * @return string Тип Карты
+ * @return string|null Тип Карты
*/
- public function getType() : string;
+ public function getType() : ?string;
/**
* Установить Банк, выпустивший карту
@@ -132,15 +132,15 @@ public function setCardIssuerBank(string $cardIssuerBank) : self;
/**
* Получить Банк, выпустивший карту
- * @return string Банк, выпустивший карту
+ * @return string|null Банк, выпустивший карту
*/
- public function getCardIssuerBank() : string;
+ public function getCardIssuerBank() : ?string;
/**
* Получить Год Карты
- * @return int Год Карты
+ * @return int|null Год Карты
*/
- public function getYear(): int;
+ public function getYear(): ?int;
/**
*
diff --git a/src/Details.php b/src/Details.php
index 95b0506..ad82b1f 100644
--- a/src/Details.php
+++ b/src/Details.php
@@ -14,6 +14,58 @@ class Details
/** @var string|SubmerchantReceipt[]|null */
private $receipts = null;
+ /** @var array динамические свойства */
+ private array $valuesContainer = [];
+
+ /**
+ * Установка динамических свойств по ключу
+ * @param mixed $keys
+ * @param mixed $values
+ * @return self
+ */
+ public function set($keys, $values) : self
+ {
+ if (is_array($keys) && is_array($values)) {
+ foreach ($keys as $i => $key) {
+ $this->valuesContainer[$key] = $values[$i];
+ }
+ } elseif (!is_array($keys) && !is_array($values)) {
+ $this->valuesContainer[$keys] = $values;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Перенаправим определение свойств
+ * @param $name
+ * @param $value
+ * @return void
+ */
+ public function __set($name, $value): void {
+ $this->valuesContainer[$name] = $value;
+ }
+
+ /**
+ * Запрос динамических свойств по ключу
+ * @param $key
+ * @return mixed|null
+ */
+ public function get($key)
+ {
+ return $this->valuesContainer[$key] ?? null;
+ }
+
+ /**
+ * Перенаправим запрос публичных свойств
+ * @param $key
+ * @return mixed|null
+ */
+ public function __get($key)
+ {
+ return $this->valuesContainer[$key] ?? null;
+ }
+
/**
* Получить:
* - массив объектов, каждый из которых содержит мерчант код и строку с данными для регистрации чеков
@@ -46,6 +98,8 @@ public function setReceipts($receipts): self
return $this;
}
+
+
/**
* Преобразовать объект в строку
* @return array
@@ -56,9 +110,9 @@ public function toArray(): array
if (is_string($this->getReceipts())) {
$array += [
- 'receipts' => $this->getReceipts()
+ 'receipts' => json_decode($this->getReceipts())
];
- } else {
+ } elseif(!empty($this->getReceipts())) {
$array += ['receipts' => []];
/** @var SubmerchantReceipt[] $receipts */
$receipts = $this->getReceipts();
@@ -67,6 +121,14 @@ public function toArray(): array
}
}
- return array_filter($array, static fn ($value) => $value !== null);
+ foreach ($this->valuesContainer as $key => $value) {
+ if ($key === 'receipts') {
+ break;
+ }
+
+ $array[$key] = $value;
+ }
+
+ return array_filter($array, static fn ($value) => !empty($value));
}
-}
\ No newline at end of file
+}
diff --git a/src/DetailsInterface.php b/src/DetailsInterface.php
index 175e52f..28c1baa 100644
--- a/src/DetailsInterface.php
+++ b/src/DetailsInterface.php
@@ -13,7 +13,7 @@ public function setNumber(string $number) : self;
/**
* Получить Номер карты
- * @return string Номер карты
+ * @return string|null Номер карты
*/
- public function getNumber() : string;
+ public function getNumber() : ?string;
}
diff --git a/src/Examples/autoload.php b/src/Examples/autoload.php
new file mode 100644
index 0000000..74eb8b6
--- /dev/null
+++ b/src/Examples/autoload.php
@@ -0,0 +1,125 @@
+/src");
+
+if (!$baseDir) {
+ throw new RuntimeException("Папка src не найдена!");
+}
+
+// Перечисление всех файлов в SDK
+$files = [
+ 'AirlineInfoInterface',
+ 'AmountInterface',
+ 'ApiCpanelArraySerializeInterface',
+ 'ApiRequestInterface',
+ 'AuthorizationInterface',
+ 'BillingInterface',
+ 'CaptureInterface',
+ 'ClientInterface',
+ 'DeliveryInterface',
+ 'DestinationInterface',
+ 'DetailsInterface',
+ 'CardDetailsInterface',
+ 'IdentityDocumentInterface',
+ 'MarketplaceSubmerchantInterface',
+ 'MerchantInterface',
+ 'MerchantTokenInterface',
+ 'OrderDataInterface',
+ 'PaymentDetailsInterface',
+ 'PaymentInterface',
+ 'PaymentPageOptionsInterface',
+ 'PaymentResultInterface',
+ 'PayoutDestinationInterface',
+ 'PayoutInterface',
+ 'PayoutSourceInterface',
+ 'ProductInterface',
+ 'QstInterface',
+ 'QstToArrayInterface',
+ 'QstSchemaAddressInterface',
+ 'QstSchemaBankAccountInterface',
+ 'QstSchemaCeoInterface',
+ 'QstSchemaIdentityDocInterface',
+ 'QstSchemaInterface',
+ 'QstSchemaOwnerInterface',
+ 'RefundInterface',
+ 'StoredCredentialsInterface',
+ 'TransactionInterface',
+ 'WebhookAuthorizationInterface',
+ 'WebhookInterface',
+ 'WebhookStoredCredentialsInterface',
+ 'Payout/PayoutCommissionInterface',
+ 'Payout/PayoutOrderDataInterface',
+ 'Payout/PayoutPaymentResultInterface',
+ 'Payout/PayoutRecipientInterface',
+ 'Payout/PayoutWebhookInterface',
+ 'ApiRequest',
+ 'Amount',
+ 'ApiCpanelUserException',
+ 'ApiCpanelUserRequest',
+ 'Authorization',
+ 'Billing',
+ 'Capture',
+ 'CaptureApiRequest',
+ 'CardDetails',
+ 'Client',
+ 'CpanelUser',
+ 'Delivery',
+ 'Details',
+ 'Group',
+ 'IdentityDocument',
+ 'MarketplaceSubmerchant',
+ 'Merchant',
+ 'MerchantToken',
+ 'OneTimeUseToken',
+ 'OrderData',
+ 'Payment',
+ 'PaymentException',
+ 'PaymentMethods',
+ 'PaymentPageOptions',
+ 'PaymentReference',
+ 'PaymentResult',
+ 'Payout',
+ 'PayoutDestination',
+ 'PayoutMobileDestination',
+ 'PayoutSource',
+ 'PhoneDetails',
+ 'PodeliMerchant',
+ 'PodeliMerchantAddress',
+ 'PodeliMerchantBankDetails',
+ 'Privilege',
+ 'Product',
+ 'Qst',
+ 'QstSchema',
+ 'QstSchemaAddressAbstract',
+ 'QstSchemaCheckableTrait',
+ 'QstSchemaActualAddress',
+ 'QstSchemaBankAccount',
+ 'QstSchemaCeo',
+ 'QstSchemaIdentityDoc',
+ 'QstSchemaLegalAddress',
+ 'QstSchemaOwner',
+ 'QstSchemaPostAddress',
+ 'Refund',
+ 'Role',
+ 'SessionRequest',
+ 'Std',
+ 'StoredCredentials',
+ 'SubmerchantReceipt',
+ 'Webhook',
+ 'WebhookAuthorization',
+ 'WebhookStoredCredentials',
+ 'Widget',
+ 'Payout/PayoutCommission',
+ 'Payout/PayoutPaymentResult',
+ 'Payout/PayoutPayoutOrderData',
+ 'Payout/PayoutRecipient',
+ 'Payout/PayoutWebhook'
+];
+
+// Подключение файлов к проекту
+foreach ($files as $file) {
+ require_once $baseDir . "/" . $file . ".php";
+}
+
+unset ($files);
+unset ($file);
\ No newline at end of file
diff --git a/src/Examples/getBindingPays.php b/src/Examples/getBindingPays.php
new file mode 100644
index 0000000..c1515b0
--- /dev/null
+++ b/src/Examples/getBindingPays.php
@@ -0,0 +1,157 @@
+setName('Круассаны Цезарь'); // Установим Наименование товара или услуги
+$product1->setSku('toy-01'); // Установим Артикул
+$product1->setVat(20); // Установим НДС
+$product1->setUnitPrice(10); // Установим Стоимость за единицу
+$product1->setQuantity(1); // Установим Количество
+
+/* Опишем вторую позицию с помощью сокращённого синтаксиса */
+$product2 = new Product([
+ 'name' => 'Ассорти рулетиков Нежность',
+ 'sku' => 'toy-02',
+ 'unitPrice' => 8,
+ 'quantity' => 3,
+ 'vat' => 10,
+]);
+
+/* Опишем третью позицию с помощью JSON */
+$product3 = new Product(
+ json_decode(
+ '{
+ "name": "Ассорти мини-десертов",
+ "sku": "toy-03",
+ "unitPrice": 12,
+ "quantity": 2,
+ "vat": 0
+ }',
+ true
+ )
+);
+
+/* Опишем Биллинговую (платёжную) информацию */
+$billing = new Billing;
+$billing->setCountryCode('RU'); // Установим Код страны
+$billing->setCity('Москва'); // Установим Город
+$billing->setState('Центральный регион'); // Установим Регион
+$billing->setAddressLine1('Улица Старый Арбат, дом 10'); // Установим Адрес Плательщика (первая строка)
+$billing->setAddressLine2('Офис Ypmn'); // Установим Адрес Плательщика (вторая строка)
+$billing->setZipCode('121000'); // Установим Почтовый Индекс Плательщика
+$billing->setFirstName('Иван'); // Установим Имя Плательщика
+$billing->setLastName('Петров'); // Установим Фамилия Плательщика
+$billing->setPhone('9670660742'); // Установим Телефон Плательщика
+$billing->setEmail('develop@ypmn.ru'); // Установим Email Плательщика
+
+/* Опишем Доствку и принимающее лицо (необязательно) */
+$delivery = new Delivery;
+// Установим документ, подтверждающий право приёма доставки
+$delivery->setIdentityDocument(
+ new IdentityDocument(123456, 'PERSONALID')
+);
+$delivery->setCountryCode('RU'); // Установим Код страны
+$delivery->setCity('Москва'); // Установим Город
+$delivery->setState('Центральный регион'); // Установим Регион
+$delivery->setAddressLine1('Улица Старый Арбат, дом 10'); // Установим Адрес Лица, принимающего заказ (первая строка)
+$delivery->setAddressLine2('Офис Ypmn'); // Установим Адрес Лица, принимающего заказ (вторая строка)
+$delivery->setZipCode('121000'); // Установим Почтовый Индекс Лица, принимающего заказ
+$delivery->setFirstName('Мария'); // Установим Имя Лица, принимающего заказ
+$delivery->setLastName('Петрова'); // Установим Фамилия Лица, принимающего заказ
+$delivery->setPhone('89670660743'); // Установим Телефон Лица, принимающего заказ
+$delivery->setEmail('develop@ypmn.ru'); // Установим Email Лица, принимающего заказ
+$delivery->setCompanyName('ООО "Вектор"'); // Установим Название Компании, в которой можно оставить заказ
+
+/* Создадим клиентское подключение */
+$client = new Client;
+$client->setBilling($billing); // Установим биллинг
+$client->setDelivery($delivery); // Установим доставку
+$client->setCurrentClientIp(); // Установим IP (автоматически)
+$client->setCurrentClientTime(); // И Установим время (автоматически)
+
+/* Создадим платёж */
+$payment = new Payment;
+$payment->addProduct($product1); // Установим товарную позицию 1
+$payment->addProduct($product2); // Установим товарную позицию 2
+$payment->addProduct($product3); // Установим товарную позицию 3
+$payment->setCurrency('RUB'); // Установим валюту
+
+/* Создадим авторизацию по типу платежа */
+$authorization = new Authorization('SBERPAY',false);
+
+/* Запрашиваем подписку */
+$storedCredentials = new StoredCredentials();
+$storedCredentials->setConsentType("recurring");
+$storedCredentials->setSubscriptionPurpose("Ежедневная доставка \"К Завтраку\"");
+
+// Назначим авторизацию для нашего платежа //
+$payment->setAuthorization($authorization);
+// Запросим подписку
+$payment->setStoredCredentials($storedCredentials);
+// Установим номер заказа (должен быть уникальным в вашей системе) //
+$payment->setMerchantPaymentReference('primer_nomer__' . time());
+// Установим адрес перенаправления пользователя после оплаты //
+$payment->setReturnUrl('http://' . $_SERVER['SERVER_NAME'] . '/php-api-client/?function=returnPage');
+$payment->setClient($client); // Установим клиентское подключение
+
+/* Создадим HTTP-запрос к API */
+$apiRequest = new ApiRequest($merchant);
+
+// Включить режим отладки (закомментируйте или удалите в рабочей программе!) //
+$apiRequest->setDebugMode();
+// Переключиться на тестовый сервер (закомментируйте или удалите в рабочей программе!) //
+$apiRequest->setSandboxMode();
+
+// Отправим запрос //
+$responseData = $apiRequest->sendAuthRequest($payment);
+
+/* Преобразуем ответ из JSON в массив */
+try {
+ $responseData = json_decode((string) $responseData["response"], true);
+
+ // Нарисуем кнопку оплаты
+ echo Std::drawYpmnButton([
+ 'url' => $responseData["paymentResult"]['url'] ?? "",
+ 'sum' => $payment->sumProductsAmount() ?? 0,
+ ]);
+
+ // Либо сделаем редирект (перенаправление) браузера по адресу оплаты:
+ // echo Std::redirect($responseData["paymentResult"]['url']);
+} catch (Exception $exception) {
+ //TODO: обработка исключения
+ echo Std::alert([
+ 'text' => '
+ Извините, платёжный метод временно недоступен.
+ Вы можете попробовать другой способ оплаты, либо свяжитесь с продавцом.
+
+
' . $exception->getMessage() . '', + 'type' => 'danger', + ]); + + throw new PaymentException('Платёжный метод временно недоступен'); +} diff --git a/src/Examples/getPaymentLink.php b/src/Examples/getPaymentLink.php index a9302c4..32d072d 100644 --- a/src/Examples/getPaymentLink.php +++ b/src/Examples/getPaymentLink.php @@ -14,6 +14,7 @@ use Ypmn\PaymentPageOptions; use Ypmn\Product; use Ypmn\Std; +use Ypmn\Details; // Подключим файл, в котором заданы параметры мерчанта include_once 'start.php'; @@ -72,6 +73,69 @@ $delivery->setIdentityDocument( new IdentityDocument(123456, 'PERSONALID') ); + +// (необязательно) Опишем поля для чеков +$details = new Details; +$details->setReceipts(<<
' . $exception->getMessage() . '', + 'type' => 'danger', + ]); + + throw new PaymentException('Платёжный метод временно недоступен'); +} diff --git a/src/Examples/paymentByBindingPays.php b/src/Examples/paymentByBindingPays.php new file mode 100644 index 0000000..18c06d8 --- /dev/null +++ b/src/Examples/paymentByBindingPays.php @@ -0,0 +1,162 @@ +setName('Круассаны Цезарь'); // Установим Наименование товара или услуги +$product1->setSku('toy-01'); // Установим Артикул +$product1->setVat(20); // Установим НДС +$product1->setUnitPrice(10); // Установим Стоимость за единицу +$product1->setQuantity(1); // Установим Количество + +/* Опишем вторую позицию с помощью сокращённого синтаксиса */ +$product2 = new Product([ + 'name' => 'Ассорти рулетиков Нежность', + 'sku' => 'toy-02', + 'unitPrice' => 8, + 'quantity' => 3, + 'vat' => 10, +]); + +/* Опишем третью позицию с помощью JSON */ +$product3 = new Product( + json_decode( + '{ + "name": "Ассорти мини-десертов", + "sku": "toy-03", + "unitPrice": 12, + "quantity": 2, + "vat": 0 + }', + true + ) +); + +/* Опишем Биллинговую (платёжную) информацию */ +$billing = new Billing; +$billing->setCountryCode('RU'); // Установим Код страны +$billing->setCity('Москва'); // Установим Город +$billing->setState('Центральный регион'); // Установим Регион +$billing->setAddressLine1('Улица Старый Арбат, дом 10'); // Установим Адрес Плательщика (первая строка) +$billing->setAddressLine2('Офис Ypmn'); // Установим Адрес Плательщика (вторая строка) +$billing->setZipCode('121000'); // Установим Почтовый Индекс Плательщика +$billing->setFirstName('Иван'); // Установим Имя Плательщика +$billing->setLastName('Петров'); // Установим Фамилия Плательщика +$billing->setPhone('9670660742'); // Установим Телефон Плательщика +$billing->setEmail('develop@ypmn.ru'); // Установим Email Плательщика + +/* Опишем Доствку и принимающее лицо (необязательно) */ +$delivery = new Delivery; +// Установим документ, подтверждающий право приёма доставки +$delivery->setIdentityDocument( + new IdentityDocument(123456, 'PERSONALID') +); +$delivery->setCountryCode('RU'); // Установим Код страны +$delivery->setCity('Москва'); // Установим Город +$delivery->setState('Центральный регион'); // Установим Регион +$delivery->setAddressLine1('Улица Старый Арбат, дом 10'); // Установим Адрес Лица, принимающего заказ (первая строка) +$delivery->setAddressLine2('Офис Ypmn'); // Установим Адрес Лица, принимающего заказ (вторая строка) +$delivery->setZipCode('121000'); // Установим Почтовый Индекс Лица, принимающего заказ +$delivery->setFirstName('Мария'); // Установим Имя Лица, принимающего заказ +$delivery->setLastName('Петрова'); // Установим Фамилия Лица, принимающего заказ +$delivery->setPhone('89670660743'); // Установим Телефон Лица, принимающего заказ +$delivery->setEmail('develop@ypmn.ru'); // Установим Email Лица, принимающего заказ +$delivery->setCompanyName('ООО "Вектор"'); // Установим Название Компании, в которой можно оставить заказ + +/* Создадим клиентское подключение */ +$client = new Client; +$client->setBilling($billing); // Установим биллинг +$client->setDelivery($delivery); // Установим доставку +$client->setCurrentClientIp(); // Установим IP (автоматически) +$client->setCurrentClientTime(); // И Установим время (автоматически) + +/* Создадим платёж */ +$payment = new Payment; +$payment->addProduct($product1); // Установим товарную позицию 1 +$payment->addProduct($product2); // Установим товарную позицию 2 +$payment->addProduct($product3); // Установим товарную позицию 3 +$payment->setCurrency('RUB'); // Установим валюту + +/* Создадим запись с токеном привязки */ +$merchantToken = new MerchantToken(); +$merchantToken->setYpmnBindingId("ab2bb91a-0012-4129-a2bf-cd18418bc726"); + +/* Создадим авторизацию по типу платежа */ +$authorization = new Authorization('SBERPAY',false); +$authorization->setMerchantToken($merchantToken); + +/* Запрашиваем подписку */ +$storedCredentials = new StoredCredentials(); +$storedCredentials->setUseType("merchant"); + +// Назначим авторизацию для нашего платежа // +$payment->setAuthorization($authorization); +// Запросим подписку +$payment->setStoredCredentials($storedCredentials); +// Установим номер заказа (должен быть уникальным в вашей системе) // +$payment->setMerchantPaymentReference('primer_nomer__' . time()); +// Установим адрес перенаправления пользователя после оплаты // +$payment->setReturnUrl('http://' . $_SERVER['SERVER_NAME'] . '/php-api-client/?function=returnPage'); +$payment->setClient($client); // Установим клиентское подключение + +/* Создадим HTTP-запрос к API */ +$apiRequest = new ApiRequest($merchant); + +// Включить режим отладки (закомментируйте или удалите в рабочей программе!) // +$apiRequest->setDebugMode(); +// Переключиться на тестовый сервер (закомментируйте или удалите в рабочей программе!) // +$apiRequest->setSandboxMode(); + +// Отправим запрос // +$responseData = $apiRequest->sendAuthRequest($payment, $merchant); + +/* Преобразуем ответ из JSON в массив */ +try { + $responseData = json_decode((string) $responseData["response"], true); + + // Нарисуем кнопку оплаты + echo Std::drawYpmnButton([ + 'url' => $responseData["paymentResult"]['url'] ?? "", + 'sum' => $payment->sumProductsAmount() ?? 0, + ]); + + // Либо сделаем редирект (перенаправление) браузера по адресу оплаты: + // echo Std::redirect($responseData["paymentResult"]['url']); +} catch (Exception $exception) { + //TODO: обработка исключения + echo Std::alert([ + 'text' => ' + Извините, платёжный метод временно недоступен.
' . $exception->getMessage() . '', + 'type' => 'danger', + ]); + + throw new PaymentException('Платёжный метод временно недоступен'); +} diff --git a/src/Examples/payoutGetBalance.php b/src/Examples/payoutGetBalance.php new file mode 100644 index 0000000..d869cde --- /dev/null +++ b/src/Examples/payoutGetBalance.php @@ -0,0 +1,30 @@ +setDebugMode(); +// Переключиться на тестовый сервер (закомментируйте или удалите в рабочей программе!) // +$apiRequest->setSandboxMode(); + +// Отправим запрос +$responseData = $apiRequest->sendPayoutGetBalanceRequest([ + 'merchantCodes' => 'test1,test2', // Массив кодов отправителя (если у Вас их несколько и необходимо получить отчет только по некоторым из них) + 'minValue' => 0, // Минимальная сумма баланса. + 'maxValue' => 100, // Максимальная сумма баланса. + 'currency' => 'RUB', // Код валюты, в которой выражены цены. Согласно ISO 4217 +]); diff --git a/src/Examples/webhookProcessing.php b/src/Examples/webhookProcessing.php new file mode 100644 index 0000000..76a9315 --- /dev/null +++ b/src/Examples/webhookProcessing.php @@ -0,0 +1,76 @@ +catchJsonRequest(); + + $paymentResult = $webhookHandler->getPaymentResult(); + $orderData = $webhookHandler->getOrderData(); + $authorization = $webhookHandler->getAuthorization(); + + + // Обозначим путь до папки и запишем вебхук в лог + $folder = __DIR__ . "/../../webhooks_log/"; + $filename = $folder . "ypmn" . date("Y-m-d H:i:s") ."_" . uniqid() . ".log"; + + if (!file_exists($folder)) { + mkdir($folder, 0777, true); + } + + file_put_contents($filename, json_encode([ + "orderData" => [ + "orderDate" => $orderData->getOrderDate(), + "payuPaymentReference" => $orderData->getPayuPaymentReference(), + "merchantPaymentReference" => $orderData->getMerchantPaymentReference(), + "status" => $orderData->getStatus(), + "currency" => $orderData->getCurrency(), + "amount" => $orderData->getAmount() ?? "null", + "commission" => $orderData->getCommission() ?? "null", + "loyaltyPointsAmount" => $orderData->getLoyaltyPointsAmount() ?? "null", + "loyaltyPointsDetails" => $orderData->getLoyaltyPointsDetails() ?? "null", + ], + + "paymentResult" => [ + "cardDetails" => [ + "bin" => $paymentResult->getCardDetails()->getBin(), + "owner" => $paymentResult->getCardDetails()->getOwner(), + "pan" => $paymentResult->getCardDetails()->getPan(), + "type" => $paymentResult->getCardDetails()->getType(), + "cardIssuerBank" => $paymentResult->getCardDetails()->getCardIssuerBank(), + ], + "paymentMethod" => $paymentResult->getPaymentMethod(), + "paymentDate" => $paymentResult->getPaymentDate(), + "authCode" => $paymentResult->getAuthCode(), + "merchantId" => $paymentResult->getMerchantId(), + ], + ])); + + +} catch (\Ypmn\PaymentException $e) { + // YourLogger::log(...); +} + diff --git a/src/MerchantToken.php b/src/MerchantToken.php index 118f046..b24a0e2 100644 --- a/src/MerchantToken.php +++ b/src/MerchantToken.php @@ -7,6 +7,9 @@ class MerchantToken implements MerchantTokenInterface, \JsonSerializable /** @var string Токен подписки СБП */ private string $bindingId; + /** @var string Токен подписки SberPay */ + private string $ypmnBindingId; + /** @var string Хэш Токен карты */ private string $tokenHash; @@ -68,6 +71,19 @@ public function setBindingId(string $bindingId): self return $this; } + /** @inheritDoc */ + public function getYpmnBindingId(): string + { + return $this->ypmnBindingId; + } + + /** @inheritDoc */ + public function setYpmnBindingId(string $ypmnBindingId): self + { + $this->ypmnBindingId = $ypmnBindingId; + return $this; + } + /** @inheritDoc */ public function toArray() : array diff --git a/src/MerchantTokenInterface.php b/src/MerchantTokenInterface.php index 23fba71..095855b 100644 --- a/src/MerchantTokenInterface.php +++ b/src/MerchantTokenInterface.php @@ -55,4 +55,17 @@ public function getBindingId(): string; * @return $this */ public function setBindingId(string $bindingId): self; + + /** + * Получить токен подписки SberPay + * @return string токен подписки + */ + public function getYpmnBindingId(): string; + + /** + * Установить токен подписки SberPay + * @param string $ypmnBindingId токен подписки SberPay + * @return $this + */ + public function setYpmnBindingId(string $ypmnBindingId): self; } diff --git a/src/OrderData.php b/src/OrderData.php index 0a1182d..8ebdc96 100644 --- a/src/OrderData.php +++ b/src/OrderData.php @@ -8,7 +8,7 @@ class OrderData implements OrderDataInterface private string $orderDate; /** @var string Номер платежа Ypmn */ - private string $ypmnPaymentReference; + private string $payUPaymentReference; /** @var string */ private string $merchantPaymentReference; @@ -35,9 +35,9 @@ class OrderData implements OrderDataInterface private array $loyaltyPointsDetails; /** @inheritDoc */ - public function getOrderDate(): string + public function getOrderDate(): ?string { - return $this->orderDate; + return $this->orderDate ?? null; } /** @inheritDoc */ @@ -51,21 +51,35 @@ public function setOrderDate(string $orderDate): self /** @inheritDoc */ public function setYpmnPaymentReference(string $ypmnPaymentReference): self { - $this->ypmnPaymentReference = $ypmnPaymentReference; + $this->payUPaymentReference = $ypmnPaymentReference; return $this; } /** @inheritDoc */ - public function getYpmnPaymentReference(): string + public function getYpmnPaymentReference(): ?string { - return $this->ypmnPaymentReference; + return $this->payUPaymentReference ?? null; } /** @inheritDoc */ - public function getMerchantPaymentReference(): string + public function setPayUPaymentReference(string $payUPaymentReference): self { - return $this->merchantPaymentReference; + $this->payUPaymentReference = $payUPaymentReference; + + return $this; + } + + /** @inheritDoc */ + public function getPayUPaymentReference(): ?string + { + return $this->payUPaymentReference ?? null; + } + + /** @inheritDoc */ + public function getMerchantPaymentReference(): ?string + { + return $this->merchantPaymentReference ?? null; } /** @inheritDoc */ @@ -77,9 +91,9 @@ public function setMerchantPaymentReference(string $merchantPaymentReference): s } /** @inheritDoc */ - public function getStatus(): string + public function getStatus(): ?string { - return $this->status; + return $this->status ?? null; } /** @inheritDoc */ @@ -91,9 +105,9 @@ public function setStatus(string $status): self } /** @inheritDoc */ - public function getCurrency(): string + public function getCurrency(): ?string { - return $this->currency; + return $this->currency ?? null; } /** @inheritDoc */ @@ -107,7 +121,7 @@ public function setCurrency(string $currency): self /** @inheritDoc */ public function getAmount(): ?float { - return $this->amount; + return $this->amount ?? null; } /** @inheritDoc */ @@ -121,7 +135,7 @@ public function setAmount(float $amount): self /** @inheritDoc */ public function getCommission(): ?float { - return $this->commission; + return $this->commission ?? null; } /** @inheritDoc */ @@ -137,7 +151,7 @@ public function setCommission(float $commission): self /** @inheritDoc */ public function getRefundRequestId(): ?string { - return $this->refundRequestId; + return $this->refundRequestId ?? null; } /** @inheritDoc */ @@ -150,7 +164,7 @@ public function setRefundRequestId(string $refundRequestId): self /** @inheritDoc */ public function getLoyaltyPointsAmount(): ?int { - return $this->loyaltyPointsAmount; + return $this->loyaltyPointsAmount ?? null; } /** @inheritDoc */ @@ -164,7 +178,7 @@ public function setLoyaltyPointsAmount(int $loyaltyPointsAmount): self /** @inheritDoc */ public function getLoyaltyPointsDetails(): ?array { - return $this->loyaltyPointsDetails; + return $this->loyaltyPointsDetails ?? null; } /** @inheritDoc */ diff --git a/src/OrderDataInterface.php b/src/OrderDataInterface.php index f87ad4c..f2cc060 100644 --- a/src/OrderDataInterface.php +++ b/src/OrderDataInterface.php @@ -7,9 +7,9 @@ interface OrderDataInterface /** * Получить Дату Заказа - * @return string Дата Заказа + * @return string|null Дата Заказа */ - public function getOrderDate(): string; + public function getOrderDate(): ?string; /** * Установть Дату Заказа @@ -20,22 +20,38 @@ public function setOrderDate(string $orderDate): self; /** * Получить Номер Заказа в Ypmn - * @return string Номер Заказа в Ypmn + * @return string|null Номер Заказа в Ypmn + * + * @deprecated Используйте getPayUPaymentReference */ - public function getYpmnPaymentReference(): string; + public function getYpmnPaymentReference(): ?string; /** * Установить Номер Заказа в Ypmn * @param string $ypmnPaymentReference Номер Заказа в Ypmn * @return $this + * + * @deprecated Используйте setPayUPaymentReference */ public function setYpmnPaymentReference(string $ypmnPaymentReference): self; + /** + * Получить Номер Заказа в Ypmn + * @return string|null Номер Заказа в Ypmn + */ + public function getPayUPaymentReference(): ?string; + /** + * Установить Номер Заказа в Ypmn + * @param string $payUPaymentReference Номер Заказа в Ypmn + * @return $this + */ + public function setPayUPaymentReference(string $payUPaymentReference): self; + /** * Получить Номер Заказа у Мерчанта - * @return string Номер Заказа у Мерчанта + * @return string|null Номер Заказа у Мерчанта */ - public function getMerchantPaymentReference(): string; + public function getMerchantPaymentReference(): ?string; /** * Установить Номер Заказа у Мерчанта @@ -46,9 +62,9 @@ public function setMerchantPaymentReference(string $merchantPaymentReference): s /** * Получить Состояние Платежа - * @return string Состояние Платежа + * @return string|null Состояние Платежа */ - public function getStatus(): string; + public function getStatus(): ?string; /** * Установить Состояние Платежа @@ -59,9 +75,9 @@ public function setStatus(string $status): self; /** * Получить Валюту Платежа - * @return string Валюта Платежа + * @return string|null Валюта Платежа */ - public function getCurrency(): string; + public function getCurrency(): ?string; /** * Установить Валюту Платежа @@ -97,13 +113,13 @@ public function getCommission(): ?float; public function setCommission(float $commission): self; /** - * Получить - * @return string + * Получить ID запроса возврата + * @return string|null */ public function getRefundRequestId(): ?string; /** - * Установить + * Установить ID запроса возврата * @param string $refundRequestId * @return $this */ diff --git a/src/PaymentMethods.php b/src/PaymentMethods.php index 809f6c6..06995ab 100644 --- a/src/PaymentMethods.php +++ b/src/PaymentMethods.php @@ -11,10 +11,11 @@ class PaymentMethods public const FASTER_PAYMENTS = 'FASTER_PAYMENTS'; // СБП public const PAYOUT = 'PAYOUT'; // Выплата по номеру карты public const PAYOUT_FP = 'PAYOUT_FP'; // Выплата по номеру телефона - public const MIRPAY = 'MIRPAY'; // MIR PAY public const BNPL = 'BNPL'; // Рассрочка - public const SOM = 'SOM'; + public const INTCARD = 'INTCARD'; + + public const ALFAPAY = 'ALFAPAY'; public const SBERPAY = 'SBERPAY'; + public const MIRPAY = 'MIRPAY'; // MIR PAY public const TPAY = 'TPAY'; - public const ALFAPAY = 'ALFAPAY'; } diff --git a/src/PaymentResult.php b/src/PaymentResult.php index 917c93b..9cc21fc 100644 --- a/src/PaymentResult.php +++ b/src/PaymentResult.php @@ -41,9 +41,9 @@ class PaymentResult implements PaymentResultInterface private CardDetailsInterface $cardDetails; /** @inheritDoc */ - public function getPaymentMethod(): string + public function getPaymentMethod(): ?string { - return $this->paymentMethod; + return $this->paymentMethod ?? null; } /** @inheritDoc */ @@ -54,9 +54,9 @@ public function setPaymentMethod(string $paymentMethod): self } /** @inheritDoc */ - public function getPaymentDate(): string + public function getPaymentDate(): ?string { - return $this->paymentDate; + return $this->paymentDate ?? null; } /** @inheritDoc */ @@ -67,9 +67,9 @@ public function setPaymentDate(string $paymentDate): self } /** @inheritDoc */ - public function getCaptureDate(): string + public function getCaptureDate(): ?string { - return $this->captureDate; + return $this->captureDate ?? null; } /** @inheritDoc */ @@ -80,9 +80,9 @@ public function setCaptureDate(string $captureDate): self } /** @inheritDoc */ - public function getCardProgramName(): string + public function getCardProgramName(): ?string { - return $this->cardProgramName; + return $this->cardProgramName ?? null; } /** @inheritDoc */ @@ -93,9 +93,9 @@ public function setCardProgramName(string $cardProgramName): self } /** @inheritDoc */ - public function getAuthCode(): string + public function getAuthCode(): ?string { - return $this->authCode; + return $this->authCode ?? null; } /** @inheritDoc */ @@ -106,9 +106,9 @@ public function setAuthCode(string $authCode): self } /** @inheritDoc */ - public function getMerchantId(): string + public function getMerchantId(): ?string { - return $this->merchantId; + return $this->merchantId ?? null; } /** @inheritDoc */ @@ -119,9 +119,9 @@ public function setMerchantId(string $merchantId): self } /** @inheritDoc */ - public function getRrn(): int + public function getRrn(): ?int { - return $this->rrn; + return $this->rrn ?? null; } /** @inheritDoc */ @@ -132,9 +132,9 @@ public function setRrn(int $rrn): self } /** @inheritDoc */ - public function getInstallmentsNumber(): string + public function getInstallmentsNumber(): ?string { - return $this->installmentsNumber; + return $this->installmentsNumber ?? null; } /** @inheritDoc */ @@ -152,15 +152,15 @@ public function setCardDetails(CardDetailsInterface $cardDetails): self } /** @inheritDoc */ - public function getCardDetails($cardDetails) : CardDetailsInterface + public function getCardDetails() : CardDetailsInterface { - return $this->cardDetails; + return $this->cardDetails ?? new CardDetails(); } /** @inheritDoc */ - public function getPaymentBankShortName(): string + public function getPaymentBankShortName(): ?string { - return $this->paymentBankShortName; + return $this->paymentBankShortName ?? null; } /** @inheritDoc */ @@ -171,9 +171,9 @@ public function setPaymentBankShortName(string $paymentBankShortName): self } /** @inheritDoc */ - public function getServiceProcessingType(): string + public function getServiceProcessingType(): ?string { - return $this->serviceProcessingType; + return $this->serviceProcessingType ?? null; } /** @inheritDoc */ diff --git a/src/PaymentResultInterface.php b/src/PaymentResultInterface.php index 75132a5..f82cfbc 100644 --- a/src/PaymentResultInterface.php +++ b/src/PaymentResultInterface.php @@ -6,9 +6,9 @@ interface PaymentResultInterface { /** * Получить Метод Оплаты - * @return string Метод Оплаты + * @return string|null Метод Оплаты */ - public function getPaymentMethod(): string; + public function getPaymentMethod(): ?string; /** * Установить Метод Оплаты @@ -19,9 +19,9 @@ public function setPaymentMethod(string $paymentMethod): self; /** * Получить Дату Авторизации платежа - * @return string Дата Авторизации платежа + * @return string|null Дата Авторизации платежа */ - public function getPaymentDate(): string; + public function getPaymentDate(): ?string; /** * Установить Дату Авторизации платежа @@ -32,9 +32,9 @@ public function setPaymentDate(string $paymentDate): self; /** * Получить Дату Списания денежных средств - * @return string Дата Списания денежных средств + * @return string|null Дата Списания денежных средств */ - public function getCaptureDate(): string; + public function getCaptureDate(): ?string; /** * Установить Дату Списания денежных средств @@ -44,9 +44,9 @@ public function getCaptureDate(): string; public function setCaptureDate(string $captureDate): self; /** - * @return string + * @return string|null */ - public function getCardProgramName(): string; + public function getCardProgramName(): ?string; /** * @param string $cardProgramName @@ -56,9 +56,9 @@ public function setCardProgramName(string $cardProgramName): self; /** * Получить Код Авторизации - * @return string Код Авторизации + * @return string|null Код Авторизации */ - public function getAuthCode(): string; + public function getAuthCode(): ?string; /** * Установить Код Авторизации @@ -69,9 +69,9 @@ public function setAuthCode(string $authCode): self; /** * Получить Идентификатор марчанта (Merchant ID) - * @return string Идентификатор марчанта (Merchant ID) + * @return string|null Идентификатор марчанта (Merchant ID) */ - public function getMerchantId(): string; + public function getMerchantId(): ?string; /** * Установить Идентификатор марчанта (Merchant ID) @@ -81,9 +81,9 @@ public function getMerchantId(): string; public function setMerchantId(string $merchantId): self; /** - * @return int + * @return int|null */ - public function getRrn(): int; + public function getRrn(): ?int; /** * @param int $rrn @@ -92,9 +92,9 @@ public function getRrn(): int; public function setRrn(int $rrn): self; /** - * @return string + * @return string|null */ - public function getInstallmentsNumber(): string; + public function getInstallmentsNumber(): ?string; /** * @param string $installmentsNumber @@ -110,18 +110,17 @@ public function setInstallmentsNumber(string $installmentsNumber): self; public function setCardDetails(CardDetailsInterface $cardDetails): self; /** - * Установить Информацию о Карте - * @param $cardDetails + * Получить информацию о Карте * @return CardDetailsInterface */ - public function getCardDetails($cardDetails) : CardDetailsInterface; + public function getCardDetails() : CardDetailsInterface; /** * Получить Краткую запись Названия Банка Плательщика - * @return string Краткая запись Названия Банка Плательщика + * @return string|null Краткая запись Названия Банка Плательщика */ - public function getPaymentBankShortName(): string; + public function getPaymentBankShortName(): ?string; /** * Установить Краткую запись Названия Банка Плательщика @@ -132,9 +131,9 @@ public function setPaymentBankShortName(string $paymentBankShortName): self; /** * Получить Тип Сервиса Процессинга - * @return string Тип Сервиса Процессинга + * @return string|null Тип Сервиса Процессинга */ - public function getServiceProcessingType(): string; + public function getServiceProcessingType(): ?string; /** * Установить Тип Сервиса Процессинга diff --git a/src/Std.php b/src/Std.php index c53d323..9b25d60 100644 --- a/src/Std.php +++ b/src/Std.php @@ -75,6 +75,7 @@ public static function drawYpmnButton(array $params): string } $allowedParams = [ + 'qr', 'url', 'shadow', 'currency', @@ -89,6 +90,39 @@ public static function drawYpmnButton(array $params): string } } + if (!empty($params['qr'])) { + $inner_block = self::data_img_tag($params['qr']); + } else { + $inner_block = ' +