Skip to content

Commit 71ff563

Browse files
Alexander Viktorchikpayuru
authored andcommitted
details-field
1 parent e9d1f4a commit 71ff563

13 files changed

+695
-4
lines changed

example.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
case 'simpleGetPaymentLink':
2121
case 'getPaymentLink':
2222
case 'getPaymentLinkMarketplace':
23+
case 'getPaymentLinkMarketplaceWithReceipts':
2324
case 'getToken':
2425
case 'paymentByToken':
2526
case 'paymentCapture':
@@ -37,6 +38,7 @@
3738
case 'getReportOrder':
3839
case 'getReportOrderDetails':
3940
case 'getFasterPayment':
41+
case 'getFasterPaymentWithReceipts':
4042
case 'getBindingFasterPayment':
4143
case 'paymentByFasterBinding':
4244
case 'qstCreateOrg':

example_list.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
'docLink' => 'https://ypmn.ru/ru/documentation/',
3535
'link' => '',
3636
],
37+
'getFasterPaymentWithReceipts' => [
38+
'name' => 'Оплата через СБП с регистрацией чека',
39+
'about' => 'Пример платежа через систему быстрых платежей с регистрацией чека',
40+
'docLink' => 'https://ypmn.ru/ru/documentation/',
41+
'link' => '',
42+
],
3743
'getBindingFasterPayment' => [
3844
'name' => 'Создание подписки СБП',
3945
'about' => 'В этом примере отправляется запрос на создание подписки СБП с одновременной оплатой',
@@ -52,6 +58,12 @@
5258
'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-split-api',
5359
'link' => '',
5460
],
61+
'getPaymentLinkMarketplaceWithReceipts' => [
62+
'name' => 'Платёж со сплитом и регистрацией чеков',
63+
'about' => 'Это пример платежа со сплитом (разделением оплаты на несколько плательщиков) и регистрацией чеков.',
64+
'docLink' => 'https://ypmn.ru/ru/documentation/#tag/payment-split-api',
65+
'link' => '',
66+
],
5567
'getToken' => [
5668
'name' => 'Создание токена',
5769
'about' => 'Приложение передаёт номер успешно оплаченного заказа в YPMN API, и получает в ответ платёжный токен.<br><br>Это называется "Токенизация карты" (чтобы запомнить карту клиента и не вводить повторно.<br><br>Очень полезная функция для подписок и регулярных платежей.',

src/Capture.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use JsonSerializable;
66

7-
class Capture implements CaptureInterface, JsonSerializable, TransactionInterface
7+
class Capture implements CaptureInterface, JsonSerializable, TransactionInterface, PaymentDetailsInterface
88
{
99
/** @var string Номер платежа Ypmn */
1010
private string $payuPaymentReference;
@@ -18,6 +18,9 @@ class Capture implements CaptureInterface, JsonSerializable, TransactionInterfac
1818
/** @var string Валюта */
1919
private string $currency;
2020

21+
/** @var Details|null Данные с расширенными сведениями в парах ключ/значение */
22+
private ?Details $details = null;
23+
2124
/** @inheritDoc */
2225
public function setYpmnPaymentReference(string $paymentIdString): CaptureInterface
2326
{
@@ -97,6 +100,19 @@ public function setSandboxMode(bool $isOn): CaptureInterface
97100
return $this;
98101
}
99102

103+
/** @inheritDoc */
104+
public function getDetails(): ?Details
105+
{
106+
return $this->details;
107+
}
108+
109+
/** @inheritDoc */
110+
public function setDetails(?Details $details): self
111+
{
112+
$this->details = $details;
113+
return $this;
114+
}
115+
100116
#[\ReturnTypeWillChange]
101117
/** @inheritDoc */
102118
public function jsonSerialize()
@@ -109,6 +125,10 @@ public function jsonSerialize()
109125
'currency' => $this->getCurrency()
110126
];
111127

128+
if ($this->details) {
129+
$requestData['details'] = $this->details->toArray();
130+
}
131+
112132
return json_encode($requestData, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_LINE_TERMINATORS);
113133
}
114134
}

src/Details.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Ypmn;
6+
7+
use Exception;
8+
9+
/**
10+
* Расширенные данные по транзакции
11+
*/
12+
class Details
13+
{
14+
/** @var string|SubmerchantReceipt[]|null */
15+
private $receipts = null;
16+
17+
/**
18+
* Получить:
19+
* - массив объектов, каждый из которых содержит мерчант код и строку с данными для регистрации чеков
20+
* - строку с данными для регистрации чеков (для остальных мерчантов)
21+
* @return string|SubmerchantReceipt[]|null
22+
*/
23+
public function getReceipts()
24+
{
25+
return $this->receipts;
26+
}
27+
28+
/**
29+
* Установить строку с данными для регистрации чеков
30+
* @param string|SubmerchantReceipt[]|null $receipts
31+
* @return $this
32+
* @throws Exception
33+
*/
34+
public function setReceipts($receipts): self
35+
{
36+
if (is_string($receipts)) {
37+
json_decode($receipts);
38+
39+
if (json_last_error() !== JSON_ERROR_NONE) {
40+
throw new Exception('Строка должна быть закодированной в JSON строкой');
41+
}
42+
}
43+
44+
$this->receipts = $receipts;
45+
46+
return $this;
47+
}
48+
49+
/**
50+
* Преобразовать объект в строку
51+
* @return array
52+
*/
53+
public function toArray(): array
54+
{
55+
$array = [];
56+
57+
if (is_string($this->getReceipts())) {
58+
$array += [
59+
'receipts' => $this->getReceipts()
60+
];
61+
} else {
62+
$array += ['receipts' => []];
63+
/** @var SubmerchantReceipt[] $receipts */
64+
$receipts = $this->getReceipts();
65+
foreach ($receipts as $submerchantReceipt) {
66+
$array['receipts'][] = $submerchantReceipt->toArray();
67+
}
68+
}
69+
70+
return array_filter($array, static fn ($value) => $value !== null);
71+
}
72+
}

src/Examples/getFasterPayment.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
$delivery = new Delivery;
7272
// Установим документ, подтверждающий право приёма доставки
7373
$delivery->setIdentityDocument(
74-
new IdentityDocument('123456', 'PERSONALID')
74+
new IdentityDocument(123456, 'PERSONALID')
7575
);
7676
$delivery->setCountryCode('RU'); // Установим Код страны
7777
$delivery->setCity('Москва'); // Установим Город
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<?php
2+
/**
3+
* getFasterPayment.php
4+
*/
5+
declare(strict_types=1);
6+
7+
use Ypmn\Details;
8+
use Ypmn\Product;
9+
use Ypmn\ApiRequest;
10+
use Ypmn\Billing;
11+
use Ypmn\Delivery;
12+
use Ypmn\IdentityDocument;
13+
use Ypmn\Client;
14+
use Ypmn\Payment;
15+
use Ypmn\Authorization;
16+
use Ypmn\PaymentException;
17+
use Ypmn\Std;
18+
19+
// Подключим файл, в котором заданы параметры мерчанта
20+
include_once 'start.php';
21+
22+
/*
23+
* Оплата через СБП
24+
* Нам надо оплатить три позиции: Блондинку, Брюнетку и Азиатку
25+
*/
26+
27+
/* Опишем первую позицию */
28+
$product1 = new Product();
29+
$product1->setName('Круассаны Цезарь'); // Установим Наименование товара или услуги
30+
$product1->setSku('toy-01'); // Установим Артикул
31+
$product1->setVat(20); // Установим НДС
32+
$product1->setUnitPrice(10); // Установим Стоимость за единицу
33+
$product1->setQuantity(1); // Установим Количество
34+
35+
/* Опишем вторую позицию с помощью сокращённого синтаксиса */
36+
$product2 = new Product([
37+
'name' => 'Ассорти рулетиков Нежность',
38+
'sku' => 'toy-02',
39+
'unitPrice' => 8,
40+
'quantity' => 3,
41+
'vat' => 10,
42+
]);
43+
44+
/* Опишем третью позицию с помощью JSON */
45+
$product3 = new Product(
46+
json_decode(
47+
'{
48+
"name": "Ассорти мини-десертов",
49+
"sku": "toy-03",
50+
"unitPrice": 12,
51+
"quantity": 2,
52+
"vat": 0
53+
}',
54+
true
55+
)
56+
);
57+
58+
/* Опишем Биллинговую (платёжную) информацию */
59+
$billing = new Billing;
60+
$billing->setCountryCode('RU'); // Установим Код страны
61+
$billing->setCity('Москва'); // Установим Город
62+
$billing->setState('Центральный регион'); // Установим Регион
63+
$billing->setAddressLine1('Улица Старый Арбат, дом 10'); // Установим Адрес Плательщика (первая строка)
64+
$billing->setAddressLine2('Офис Ypmn'); // Установим Адрес Плательщика (вторая строка)
65+
$billing->setZipCode('121000'); // Установим Почтовый Индекс Плательщика
66+
$billing->setFirstName('Иван'); // Установим Имя Плательщика
67+
$billing->setLastName('Петров'); // Установим Фамилия Плательщика
68+
$billing->setPhone('9670660742'); // Установим Телефон Плательщика
69+
$billing->setEmail('develop@ypmn.ru'); // Установим Email Плательщика
70+
71+
/* Опишем Доствку и принимающее лицо (необязательно) */
72+
$delivery = new Delivery;
73+
// Установим документ, подтверждающий право приёма доставки
74+
$delivery->setIdentityDocument(
75+
new IdentityDocument(123456, 'PERSONALID')
76+
);
77+
$delivery->setCountryCode('RU'); // Установим Код страны
78+
$delivery->setCity('Москва'); // Установим Город
79+
$delivery->setState('Центральный регион'); // Установим Регион
80+
$delivery->setAddressLine1('Улица Старый Арбат, дом 10'); // Установим Адрес Лица, принимающего заказ (первая строка)
81+
$delivery->setAddressLine2('Офис Ypmn'); // Установим Адрес Лица, принимающего заказ (вторая строка)
82+
$delivery->setZipCode('121000'); // Установим Почтовый Индекс Лица, принимающего заказ
83+
$delivery->setFirstName('Мария'); // Установим Имя Лица, принимающего заказ
84+
$delivery->setLastName('Петрова'); // Установим Фамилия Лица, принимающего заказ
85+
$delivery->setPhone('89670660743'); // Установим Телефон Лица, принимающего заказ
86+
$delivery->setEmail('develop@ypmn.ru'); // Установим Email Лица, принимающего заказ
87+
$delivery->setCompanyName('ООО "Вектор"'); // Установим Название Компании, в которой можно оставить заказ
88+
89+
/* Создадим клиентское подключение */
90+
$client = new Client;
91+
$client->setBilling($billing); // Установим биллинг
92+
$client->setDelivery($delivery); // Установим доставку
93+
$client->setCurrentClientIp(); // Установим IP (автоматически)
94+
$client->setCurrentClientTime(); // И Установим время (автоматически)
95+
96+
/* Создадим платёж */
97+
$payment = new Payment;
98+
$payment->addProduct($product1); // Установим товарную позицию 1
99+
$payment->addProduct($product2); // Установим товарную позицию 2
100+
$payment->addProduct($product3); // Установим товарную позицию 3
101+
$payment->setCurrency('RUB'); // Установим валюту
102+
103+
/* Создадим авторизацию по типу платежа */
104+
$authorization = new Authorization('FASTER_PAYMENTS',false);
105+
106+
// Назначим авторизацию для нашего платежа //
107+
$payment->setAuthorization($authorization);
108+
// Установим номер заказа (должен быть уникальным в вашей системе) //
109+
$payment->setMerchantPaymentReference('primer_nomer__' . time());
110+
// Установим адрес перенаправления пользователя после оплаты //
111+
$payment->setReturnUrl('http://' . $_SERVER['SERVER_NAME'] . '/php-api-client/?function=returnPage');
112+
$payment->setClient($client); // Установим клиентское подключение
113+
114+
// Создадим объект расширенных данных по транзакции
115+
$details = new Details();
116+
117+
// Ниже пример данных для регистрации чека в онлайн кассе АТОЛ
118+
// Подробнее см. в документации АТОЛ
119+
$receiptsArr = [
120+
'external_id' => $payment->getMerchantPaymentReference(),
121+
'receipt' => [
122+
'client' => ['email' => $billing->getEmail()],
123+
'company' => [
124+
'email' => 'chek@romashka.ru', // Электронная почта отправителя чека
125+
'sno' => 'osn', // Система налогообложения
126+
'inn' => '5544332219', // ИНН организации
127+
'payment_address' => 'https://v4.online.atol.ru' // место расчетов
128+
],
129+
'items' => [],
130+
'payments' => [
131+
[
132+
'type' => 1,
133+
'sum' => 0,
134+
]
135+
],
136+
'vats' => [],
137+
'total' => 0,
138+
],
139+
'timestamp' => (new DateTime())->format('d.m.Y H:i:s')
140+
];
141+
142+
foreach ($payment->getProducts() as $product) {
143+
$receiptsArr['receipt']['items'][] = [
144+
'name' => $product->getName(),
145+
'price' => $product->getUnitPrice(),
146+
'quantity' => $product->getQuantity(),
147+
'sum' => $product->getUnitPrice() * $product->getQuantity(),
148+
'measurement_unit' => 'кг',
149+
'payment_method' => 'full_payment',
150+
'payment_object' => 'commodity',
151+
'vat' => ['type' => 'vat120'],
152+
];
153+
$receiptsArr['receipt']['vats'][] = ['type' => 'vat120'];
154+
$receiptsArr['receipt']['payments'][0]['sum'] += $product->getUnitPrice() * $product->getQuantity();
155+
$receiptsArr['receipt']['total'] += $product->getUnitPrice() * $product->getQuantity();
156+
}
157+
158+
// Закодируем данные для онлайн кассы АТОЛ в JSON строку
159+
$receipts = json_encode($receiptsArr);
160+
161+
// Установим данные для передачи в АТОЛ для регистрации чеков
162+
$details->setReceipts($receipts);
163+
// Добавим расширенные данные по транзакции в запрос на авторизацию платежа
164+
$payment->setDetails($details);
165+
166+
/* Создадим HTTP-запрос к API */
167+
$apiRequest = new ApiRequest($merchant);
168+
169+
// Включить режим отладки (закомментируйте или удалите в рабочей программе!) //
170+
$apiRequest->setDebugMode();
171+
// Переключиться на тестовый сервер (закомментируйте или удалите в рабочей программе!) //
172+
$apiRequest->setSandboxMode();
173+
174+
// Отправим запрос //
175+
$responseData = $apiRequest->sendAuthRequest($payment, $merchant);
176+
177+
/* Преобразуем ответ из JSON в массив */
178+
try {
179+
$responseData = json_decode((string) $responseData["response"], true);
180+
181+
// Нарисуем кнопку оплаты
182+
echo Std::drawYpmnButton([
183+
'url' => $responseData["paymentResult"]['url'] ?? "",
184+
'sum' => $payment->sumProductsAmount() ?? 0,
185+
]);
186+
187+
// Либо сделаем редирект (перенаправление) браузера по адресу оплаты:
188+
// echo Std::redirect($responseData["paymentResult"]['url']);
189+
} catch (Exception $exception) {
190+
//TODO: обработка исключения
191+
echo Std::alert([
192+
'text' => '
193+
Извините, платёжный метод временно недоступен.<br>
194+
Вы можете попробовать другой способ оплаты, либо свяжитесь с продавцом.<br>
195+
<br>
196+
<pre>' . $exception->getMessage() . '</pre>',
197+
'type' => 'danger',
198+
]);
199+
200+
throw new PaymentException('Платёжный метод временно недоступен');
201+
}

0 commit comments

Comments
 (0)