-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Stierlitz
committed
May 4, 2023
1 parent
a37309d
commit ab93967
Showing
6 changed files
with
461 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# Проста бібліотека для [MonobankPay](https://api.monobank.ua/) | ||
Документація по REST API [тут](https://api.monobank.ua/docs/acquiring.html) | ||
|
||
Для ведення запитів вам знадобиться токен з особистого кабінету [https://fop.monobank.ua/](https://fop.monobank.ua/) або тестовий токен з [https://api.monobank.ua/](https://api.monobank.ua/) | ||
|
||
Встановити бібліотеку: | ||
```bash | ||
composer require stierlitz/monobank-pay | ||
``` | ||
|
||
### Мінімальні вимоги: | ||
* php >=7.4 | ||
* guzzlehttp/guzzle >= 7.0 | ||
* starkbank/ecdsa >= 0.0.5 | ||
|
||
### Приклади використання: | ||
```php | ||
require_once('vendor/autoload.php'); | ||
|
||
//створили клієнта - через нього запити будуть слатись | ||
$monoClient = new \MonoPay\Client('YOUR_TOKEN_HERE'); | ||
|
||
//із клієнта можна отримати id та назву мерчанта | ||
echo $monoClient->getMerchantId(); | ||
echo $monoClient->getMerchantName(); | ||
|
||
//для створення платежів створюємо цей об'єкт | ||
$monoPayment = new \MonoPay\Payment($monoClient); | ||
|
||
//створення платежу | ||
$invoice = $monoPayment->create(1000,[ | ||
'merchantPaymInfo' => [ //деталі оплати | ||
'reference' => 'my_shop_order_28142', //Номер чека, замовлення, тощо; визначається мерчантом (вами) | ||
'destination' => 'Оплата за замовлення #28142', //Призначення платежу | ||
'basketOrder' => [ //Склад замовлення, використовується для відображення кошика замовлення | ||
[ | ||
'name' => 'Товар1', //Назва товару | ||
'qty' => 2, //Кількість | ||
'sum' => 500, //Сума у мінімальних одиницях валюти за одиницю товару | ||
'icon' => 'https://example.com/images/product1.jpg', //Посилання на зображення товару | ||
'unit' => 'уп.', //Назва одиниці вимiру товару | ||
] | ||
] | ||
], | ||
'redirectUrl' => 'https://example.com/order-result', //Адреса для повернення (GET) - на цю адресу буде переадресовано користувача після завершення оплати (у разі успіху або помилки) | ||
'webHookUrl' => 'https://example.com/mono-webhook', //Адреса для CallBack (POST) – на цю адресу буде надіслано дані про стан платежу при кожній зміні статусу. Зміст тіла запиту ідентичний відповіді запиту “перевірки статусу рахунку” | ||
'validity' => 3600*24*7, //Строк дії в секундах, за замовчуванням рахунок перестає бути дійсним через 24 години | ||
'paymentType' => 'debit', //debit | hold. Тип операції. Для значення hold термін складає 9 днів. Якщо через 9 днів холд не буде фіналізовано — він скасовується | ||
]); | ||
print_r($invoice); | ||
|
||
//інформація про платіж | ||
$invoice = $monoPayment->info('2305046jUBEj8WfyaBdB'); | ||
print_r($invoice); | ||
|
||
//відшкодування | ||
$result = $monoPayment->refund('2305046jUBEj8WfyaBdB'); | ||
print_r($result); | ||
|
||
//скасування посилання на оплату | ||
$result = $monoPayment->cancel('2305046jUBEj8WfyaBdB'); | ||
print_r($result); | ||
|
||
//деталі успішної оплати | ||
$invoiceDetails = $monoPayment->successDetails('2305046jUBEj8WfyaBdB'); | ||
print_r($invoiceDetails); | ||
|
||
//списати заблоковану сумму | ||
//зверніть увагу: списати можна тільки таку самму або меншу сумму яку ви заблокували | ||
$result = $monoPayment->captureHold('2305046jUBEj8WfyaBdB',500); | ||
print_r($result); | ||
|
||
//список успішних оплат за останні сутки | ||
$list = $monoPayment->items(time()-60*60*24); | ||
print_r($list); | ||
``` | ||
|
||
### Отримання вебхуку: | ||
```php | ||
require_once('vendor/autoload.php'); | ||
|
||
//створили клієнта - через нього запити будуть слатись | ||
$monoClient = new \MonoPay\Client('YOUR_TOKEN_HERE'); | ||
|
||
//отримання публічного ключа (бажано закешувати) | ||
$publicKey = $monoClient->getPublicKey(); | ||
|
||
//класс для роботи з вебхуком | ||
$monoWebhook = new \MonoPay\Webhook($monoClient,$publicKey,$_SERVER['HTTP_X_SIGN']); | ||
//отримуємо вхідні дані | ||
$body = file_get_contents('php://input'); | ||
//валідуємо дані | ||
if($monoWebhook->verify($body)){ | ||
echo "Ці дані прислав монобанк, можна обробляти"; | ||
}else{ | ||
echo "Дані прислав шахрай, ігноруємо"; | ||
} | ||
``` | ||
|
||
#### TODO List: | ||
* Доробити методи стосовно токенізації карт | ||
* Переробити вхідні параметри і вихідні дані на класи з описаними методами | ||
* Попросити в Гороховського баночку пива |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "plakidan/monobank-pay", | ||
"description": "This is simple library for Monobank Acquiring called \"MonoPay\" based on REST API (v2304) docs located at https://api.monobank.ua/docs/acquiring.html", | ||
"type": "library", | ||
"license": "Apache-2.0", | ||
"authors": [ | ||
{ | ||
"name": "Stierlitz", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"minimum-stability": "dev", | ||
"require": { | ||
"php": ">=7.4", | ||
"guzzlehttp/guzzle": "^7.0", | ||
"starkbank/ecdsa": "0.0.5" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"MonoPay\\": "src/" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
|
||
|
||
namespace MonoPay; | ||
|
||
class Client extends RequestBuilder | ||
{ | ||
private ?string $merchantId; | ||
private ?string $merchantName; | ||
public string $apiEndpoint = 'https://api.monobank.ua/'; | ||
private \GuzzleHttp\Client $httpClient; | ||
|
||
/** | ||
* Створює клієнт з ключем для запитів до серверу Mono і отримує дані про мерчант | ||
* @param string $token Токен з особистого кабінету https://fop.monobank.ua/ або тестовий токен з https://api.monobank.ua/ | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1details/get Так отримуються деталі мерчанту | ||
*/ | ||
public function __construct(string $token) | ||
{ | ||
$this->httpClient = new \GuzzleHttp\Client([ | ||
'base_uri' => $this->apiEndpoint, | ||
\GuzzleHttp\RequestOptions::TIMEOUT => 5, | ||
\GuzzleHttp\RequestOptions::HEADERS => [ | ||
'X-Token' => $token, | ||
], | ||
\GuzzleHttp\RequestOptions::HTTP_ERRORS => false | ||
]); | ||
$response = $this->httpClient->request('GET', '/api/merchant/details'); | ||
$json = $response->getBody()->getContents(); | ||
$data = json_decode($json, true); | ||
if ($response->getStatusCode() == '200') { | ||
if ($data && isset($data['merchantId']) && isset($data['merchantName'])) { | ||
$this->merchantId = $data['merchantId']; | ||
$this->merchantName = $data['merchantName']; | ||
} else { | ||
throw new \Exception('Cannot decode json response from Mono', 500); | ||
} | ||
} else { | ||
throw new \Exception($data['errorDescription'] ?? 'Unknown error response: ' . $json, $response->getStatusCode()); | ||
} | ||
} | ||
|
||
public function getMerchantId(): string | ||
{ | ||
return $this->merchantId; | ||
} | ||
|
||
public function getMerchantName(): string | ||
{ | ||
return $this->merchantName; | ||
} | ||
|
||
public function getClient(): \GuzzleHttp\Client | ||
{ | ||
return $this->httpClient; | ||
} | ||
|
||
/** | ||
* Відкритий ключ для верифікації підписів | ||
* Отримання відкритого ключа для перевірки підпису, який включено у вебхуки. Ключ можна кешувати і робити запит на отримання нового, коли верифікація підпису з поточним ключем перестане працювати. Кожного разу робити запит на отримання ключа не треба | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1pubkey/get | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
*/ | ||
public function getPublicKey(): string | ||
{ | ||
$response = $this->getClient()->request('GET','/api/merchant/pubkey'); | ||
$data = $this->getDataFromGuzzleResponse($response); | ||
if(!isset($data['key'])){ | ||
throw new \Exception('Invalid response from Mono API',500); | ||
} | ||
return $data['key']; | ||
} | ||
|
||
/** | ||
* Дані мерчанта | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1details/get | ||
* @return array Масив з ключами merchantId та merchantName | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
*/ | ||
public function getMerchant(): array | ||
{ | ||
$response = $this->getClient()->request('GET','/api/merchant/details'); | ||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
<?php | ||
|
||
|
||
namespace MonoPay; | ||
|
||
|
||
class Payment extends RequestBuilder | ||
{ | ||
private \MonoPay\Client $client; | ||
|
||
public function __construct(\MonoPay\Client $client) | ||
{ | ||
$this->client = $client; | ||
} | ||
|
||
/** | ||
* Створення рахунку | ||
* Створення рахунку для оплати | ||
* @param int $amount Сума оплати у мінімальних одиницях (копійки для гривні) | ||
* @param array $options Додаткові параметри (Див. посилання) | ||
* @return array | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1invoice~1create/post | ||
*/ | ||
public function create(int $amount, array $options=[]): array | ||
{ | ||
if($amount < 1){ | ||
throw new \Exception('Amount must be a natural number',500); | ||
} | ||
$options['amount']=$amount; | ||
$response = $this->client->getClient()->request('POST','/api/merchant/invoice/create',[ | ||
\GuzzleHttp\RequestOptions::JSON => $options | ||
]); | ||
|
||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
|
||
/** | ||
* Статус рахунку | ||
* Метод перевірки статусу рахунку при розсинхронізації з боку продавця або відсутності webHookUrl при створенні рахунку. | ||
* @param string $invoiceId ID рахунку | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1invoice~1status?invoiceId=%7BinvoiceId%7D/get | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
*/ | ||
public function info(string $invoiceId): array | ||
{ | ||
$response = $this->client->getClient()->request('GET','/api/merchant/invoice/status',[ | ||
\GuzzleHttp\RequestOptions::QUERY => [ | ||
'invoiceId' => $invoiceId | ||
] | ||
]); | ||
|
||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
|
||
/** | ||
* Скасування оплати | ||
* Скасування успішної оплати рахунку | ||
* @param string $invoiceId ID рахунку | ||
* @param array $options Додаткові параметри (Див. посилання) | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1invoice~1cancel/post | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
*/ | ||
public function refund(string $invoiceId, array $options=[]): array | ||
{ | ||
$options['invoiceId'] = $invoiceId; | ||
|
||
$response = $this->client->getClient()->request('POST','/api/merchant/invoice/cancel',[ | ||
\GuzzleHttp\RequestOptions::JSON => $options | ||
]); | ||
|
||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
|
||
/** | ||
* Інвалідація рахунку | ||
* Інвалідація рахунку, якщо за ним ще не було здіснено оплати | ||
* @param string $invoiceId ID рахунку | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1invoice~1remove/post | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
*/ | ||
public function cancel(string $invoiceId): array | ||
{ | ||
$response = $this->client->getClient()->request('POST','/api/merchant/invoice/remove',[ | ||
\GuzzleHttp\RequestOptions::JSON => [ | ||
'invoiceId' => $invoiceId | ||
] | ||
]); | ||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
|
||
/** | ||
* Розширена інформація про успішну оплату | ||
* Дані про успішну оплату, якщо вона була здійснена | ||
* @param string $invoiceId Ідентифікатор рахунку | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
*@link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1invoice~1payment-info?invoiceId=%7BinvoiceId%7D/get | ||
*/ | ||
public function successDetails(string $invoiceId): array | ||
{ | ||
$response = $this->client->getClient()->request('GET','/api/merchant/invoice/payment-info',[ | ||
\GuzzleHttp\RequestOptions::QUERY => [ | ||
'invoiceId' => $invoiceId | ||
] | ||
]); | ||
|
||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
|
||
/** | ||
* Фіналізація суми холду | ||
* Фінальна сумма списання має бути нижчою або дорівнювати суммі холду | ||
* @param string $invoiceId Ідентифікатор рахунку | ||
* @param int|null $amount Сума у мінімальних одиницях, якщо бажаєте змінити сумму списання | ||
* @return array | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1invoice~1finalize/post | ||
*/ | ||
public function captureHold(string $invoiceId, int $amount = null): array | ||
{ | ||
$body = [ | ||
'invoiceId' => $invoiceId | ||
]; | ||
if(isset($amount)){ | ||
$body['amount'] = $amount; | ||
} | ||
$response = $this->client->getClient()->request('POST','/api/merchant/invoice/finalize',[ | ||
\GuzzleHttp\RequestOptions::JSON => $body | ||
]); | ||
|
||
return $this->getDataFromGuzzleResponse($response); | ||
} | ||
|
||
/** | ||
* Виписка за період | ||
* Список платежів за вказаний період | ||
* @param int $fromTimestamp UTC Unix timestamp | ||
* @param int|null $toTimestamp UTC Unix timestamp | ||
* @return array | ||
* @throws \GuzzleHttp\Exception\GuzzleException | ||
* @throws \Exception | ||
* @link https://api.monobank.ua/docs/acquiring.html#/paths/~1api~1merchant~1statement/get | ||
*/ | ||
public function items(int $fromTimestamp, int $toTimestamp=null): array | ||
{ | ||
$query = [ | ||
'from' => $fromTimestamp | ||
]; | ||
if(isset($toTimestamp)){ | ||
$query['to'] = $toTimestamp; | ||
} | ||
$response = $this->client->getClient()->request('GET','/api/merchant/statement',[ | ||
\GuzzleHttp\RequestOptions::QUERY => $query | ||
]); | ||
|
||
$data = $this->getDataFromGuzzleResponse($response); | ||
return $data['list']??[]; | ||
} | ||
|
||
} |
Oops, something went wrong.