From bc1606e3bf201278d3548c4d26fc1fd93dd4968c Mon Sep 17 00:00:00 2001 From: Alexander Viktorchik Date: Thu, 25 Jul 2024 15:04:40 +0300 Subject: [PATCH 01/64] qst-api - comments --- src/Examples/qstCreateIp.php | 68 +++++++++++++++++++++----------- src/Examples/qstCreateOrg.php | 74 +++++++++++++++++++++++------------ 2 files changed, 96 insertions(+), 46 deletions(-) diff --git a/src/Examples/qstCreateIp.php b/src/Examples/qstCreateIp.php index ec03f68..6543cbf 100644 --- a/src/Examples/qstCreateIp.php +++ b/src/Examples/qstCreateIp.php @@ -14,54 +14,78 @@ // Подключим файл, в котором заданы параметры мерчанта include_once 'start.php'; -/* Создание и отправка анкеты для подключения продавца */ +/* Создание и отправка анкеты для подключения сабмерчанта (продавца) ИП */ -/* Создаем и заполняем объект анкеты */ +/* Создадим объект анкеты */ $qst = new Qst(); -/* ИНН продавца */ +/* Укажем ИНН добавляемого сабмерчанта */ $qst->setInn('773200328662'); -/* Данные продавца */ +/* Создадим объект данных анкеты добавляемого сабмерчанта */ $qstSchema = new QstSchema(); + +/* Добавим в данные анкеты номер телефона сабмерчанта */ $qstSchema->addPhone('+7 495 1234567, доб. 123'); + +/* Добавим в данные анкеты email сабмерчанта */ $qstSchema->addEmail('example@ypmn.com'); +/* Создадим и заполним объект юридического адреса сабмерчанта */ $qstLegalAddress = (new QstSchemaLegalAddress()) - ->setZip('123456') - ->setRegion('Москва') - ->setCity('Москва') - ->setStreet('ул. Охотный ряд') - ->setHouse('1'); + ->setZip('123456') // индекс + ->setRegion('Москва') // регион + ->setCity('Москва') // город + ->setStreet('ул. Охотный ряд') // улица + ->setHouse('1'); // дом +/* Укажем объект юридического адреса сабмерчанта в данных анкеты */ $qstSchema->setLegalAddress($qstLegalAddress); +/* + * Создадим объект фактического адреса сабмерчанта и отметим, что + * фактический адрес сабмерчанта соответствует юридическому + */ $qstActualAddress = (new QstSchemaActualAddress())->setChecked(true); +/* Укажем объект фактического адреса сабмерчанта в данных анкеты */ $qstSchema->setActualAddress($qstActualAddress); +/* + * Создадим объект почтового адреса сабмерчанта и отметим, что + * почтовый адрес сабмерчанта соответствует юридическому + */ $qstPostAddress = (new QstSchemaPostAddress())->setChecked(true); +/* Укажем объект почтового адреса сабмерчанта в данных анкеты */ $qstSchema->setPostAddress($qstPostAddress); +/* Создадим объект удостоверяющего документа и заполним его паспортными данными ИП */ $qstIdentityDoc = (new QstSchemaIdentityDoc()) - ->setSeries('1234') - ->setNumber('123456') - ->setIssueDate('2000-01-30') - ->setIssuedBy('МВД') - ->setIssuedByKP('123-456'); - + ->setSeries('1234') // номер паспорта + ->setNumber('123456') // серия + ->setIssueDate('2000-01-30') // дата выдачи + ->setIssuedBy('МВД') // кем выдан + ->setIssuedByKP('123-456'); // к/п + +/* + * Заполним дату и место рождения ИП в данных анкеты. + * Укажем объект с паспортными данным ИП в данных анкеты. + */ $qstSchema - ->setBirthDate('1969-02-23') - ->setBirthPlace('Москва') - ->setIdentityDoc($qstIdentityDoc); + ->setBirthDate('1969-02-23') // дата рождения ИП + ->setBirthPlace('Москва') // место рождения ИП + ->setIdentityDoc($qstIdentityDoc); // объект с паспортными данным ИП +/* Создадим и заполним объект с банковскими данными ИП */ $qstBankAccount = (new QstSchemaBankAccount()) - ->setBankBIK('044525700') - ->setBankCorAccount('30101810200000000700') - ->setBankAccount('40702810100002400756'); - + ->setBankBIK('044525700') // БИК + ->setBankCorAccount('30101810200000000700') // кор. счет + ->setBankAccount('40702810100002400756'); // расч. счет +/* Добавим объект с банковскими данными сабмерчанта в данные анкеты */ $qstSchema->addBankAccount($qstBankAccount); +/* Заполним дополнительное поле #1 (при наличии) */ $qstSchema->setAdditionalFieldByKey(1, 'Доп. поле'); +/* Установим объект с данными анкеты в объект анкеты */ $qst->setSchema($qstSchema); /* Создадим HTTP-запрос к API */ diff --git a/src/Examples/qstCreateOrg.php b/src/Examples/qstCreateOrg.php index 4a062fd..0c1d750 100644 --- a/src/Examples/qstCreateOrg.php +++ b/src/Examples/qstCreateOrg.php @@ -15,58 +15,84 @@ // Подключим файл, в котором заданы параметры мерчанта include_once 'start.php'; -/* Создание и отправка анкеты для подключения продавца */ +/* Создание и отправка анкеты для подключения сабмерчанта (продавца) организации */ -/* Создаем и заполняем объект анкеты */ +/* Создадим объект анкеты */ $qst = new Qst(); -/* ИНН продавца */ +/* Укажем ИНН добавляемого сабмерчанта */ $qst->setInn('7704217370'); -/* Данные продавца */ +/* Создадим объект данных анкеты добавляемого сабмерчанта */ $qstSchema = new QstSchema(); + +/* Добавим в данные анкеты номер телефона сабмерчанта */ $qstSchema->addPhone('+7 495 1234567, доб. 123'); +/* Добавим в данные анкеты еще один номер телефона сабмерчанта */ $qstSchema->addPhone('+7 499 7654321, доб. 321'); + +/* Добавим в данные анкеты email сабмерчанта */ $qstSchema->addEmail('example@ypmn.com'); +/* Создадим и заполним объект юридического адреса сабмерчанта */ $qstLegalAddress = (new QstSchemaLegalAddress()) - ->setZip('123112') - ->setRegion('Москва') - ->setCity('Москва') - ->setStreet('Пресненская наб.') - ->setHouse('д. 10') - ->setFlat('эт. 41, Пом. I, комн. 6'); + ->setZip('123112') // индекс + ->setRegion('Москва') // регион + ->setCity('Москва') // город + ->setStreet('Пресненская наб.') // улица + ->setHouse('д. 10') // дом + ->setFlat('эт. 41, Пом. I, комн. 6'); // офис +/* Установим объект юридического адреса сабмерчанта в данных анкеты */ $qstSchema->setLegalAddress($qstLegalAddress); +/* + * Создадим объект фактического адреса сабмерчанта и отметим, что + * фактический адрес сабмерчанта соответствует юридическому + */ $qstActualAddress = (new QstSchemaActualAddress())->setChecked(true); +/* Установим объект фактического адреса сабмерчанта в данных анкеты */ $qstSchema->setActualAddress($qstActualAddress); -$qstCeoIdentityDoc = (new QstSchemaIdentityDoc()) - ->setSeries('1234') - ->setNumber('123456') - ->setIssueDate('2000-01-30') - ->setIssuedBy('МВД') - ->setIssuedByKP('123-456'); +/* Создадим объект удостоверяющего документа и заполним его паспортными данными руководителя организации */ +$qstCeoIdentityDoc = (new QstSchemaIdentityDoc()) + ->setSeries('1234') // номер паспорта + ->setNumber('123456') // серия + ->setIssueDate('2000-01-30') // дата выдачи + ->setIssuedBy('МВД') // кем выдан + ->setIssuedByKP('123-456'); // к/п + +/* + * Создадим объект руководителя организации. + * Установим в него объект с паспортными данными руководителя. + * Заполним место и дату рождения, адрес регистрации руководителя + */ $qstCeo = (new QstSchemaCeo()) - ->setIdentityDoc($qstCeoIdentityDoc) - ->setBirthDate('1980-01-30') - ->setBirthPlace('Москва') - ->setRegistrationAddress('г. Москва, ул. Ленина, д. 1, кв. 1'); + ->setIdentityDoc($qstCeoIdentityDoc) // объект с паспортными данными руководителя + ->setBirthDate('1980-01-30') // дата рождения руководителя + ->setBirthPlace('Москва') // место рождения руководителя + ->setRegistrationAddress('г. Москва, ул. Ленина, д. 1, кв. 1'); // адрес регистрации руководителя + +/* Установим объект с данными руководителя организации в данных анкеты */ $qstSchema->setCeo($qstCeo); +/* Создадим объект собственника организации, заполним ФИО и долю собственника */ $qstOwner = (new QstSchemaOwner())->setOwner('Иванов Иван Иванович')->setShare('100'); +/* Добавим объект с данными собственника организации в объект данных анкеты */ $qstSchema->addOwner($qstOwner); +/* Создадим и заполним объект с банковскими данными организации */ $qstBankAccount = (new QstSchemaBankAccount()) - ->setBankBIK('044525700') - ->setBankCorAccount('30101810200000000700') - ->setBankAccount('40702810100002400756'); - + ->setBankBIK('044525700') // БИК + ->setBankCorAccount('30101810200000000700') // кор. счет + ->setBankAccount('40702810100002400756'); // расч. счет +/* Добавим объект с банковскими данными сабмерчанта в данные анкеты */ $qstSchema->addBankAccount($qstBankAccount); +/* Заполним дополнительное поле #1 (при наличии) */ $qstSchema->setAdditionalFieldByKey(1, 'Доп. поле'); +/* Установим объект с данными анкеты в объект анкеты */ $qst->setSchema($qstSchema); /* Создадим HTTP-запрос к API */ From 712391e21bc55302e9d58444a5430945b6edf277 Mon Sep 17 00:00:00 2001 From: Alexey Babak Date: Wed, 11 Sep 2024 18:54:03 +0300 Subject: [PATCH 02/64] YP-1013 --- src/ApiRequest.php | 18 +++++++++++-- src/ApiRequestInterface.php | 4 +++ src/Authorization.php | 47 ++++++++++++++++++---------------- src/AuthorizationInterface.php | 18 +++++++++++-- src/Examples/start.php | 2 +- src/Payment.php | 2 +- src/PaymentMethods.php | 20 +++++++++++++++ 7 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 src/PaymentMethods.php diff --git a/src/ApiRequest.php b/src/ApiRequest.php index 7a9aab8..3002056 100644 --- a/src/ApiRequest.php +++ b/src/ApiRequest.php @@ -307,7 +307,6 @@ public function sendPostRequest($data, string $api): array throw new PaymentException('Incorrect request body JSON'); } - $encodedJsonDataHash = md5($encodedJsonData); $curl = curl_init(); @@ -411,9 +410,24 @@ public function sendSessionRequest(SessionRequest $sessionRequest): array return $this->sendPostRequest($sessionRequest, self::SESSION_API); } - /** @inheritdoc */ + /** @inheritdoc */ public function sendAuthRequest(PaymentInterface $payment): array { + $paymentMethod = $payment->getAuthorization()->getPaymentMethod(); + $methodsWithPage = [ + PaymentMethods::CCVISAMC, + ]; + + if ( + !in_array($paymentMethod, $methodsWithPage) // если метод не подразумевает страницу + || empty($paymentMethod) // или метод не выборан + || !empty($payment->getAuthorization()->getCardDetails()->getNumber()) // или передаются данные PCI-DSS + || !empty($payment->getAuthorization()->getMerchantToken()) // или содержится токен мерчанта + || !empty($payment->getAuthorization()->getOneTimeUseToken()->getToken()) // или содержится однораз. токен + ) { + $payment->getAuthorization()->setUsePaymentPage(false); + } + return $this->sendPostRequest($payment, self::AUTHORIZE_API); } diff --git a/src/ApiRequestInterface.php b/src/ApiRequestInterface.php index eaed9f5..7629126 100644 --- a/src/ApiRequestInterface.php +++ b/src/ApiRequestInterface.php @@ -21,6 +21,7 @@ function sendSessionRequest(SessionRequest $sessionRequest): array; * Отправить Запрос на Оплату * @param PaymentInterface $payment Оплата * @return array + * @throws PaymentException */ public function sendAuthRequest(PaymentInterface $payment): array; @@ -28,6 +29,7 @@ public function sendAuthRequest(PaymentInterface $payment): array; * Отправить Запрос на Списание Средств * @param CaptureInterface $capture Списание Средств * @return array + * @throws PaymentException */ public function sendCaptureRequest(CaptureInterface $capture): array; @@ -35,6 +37,7 @@ public function sendCaptureRequest(CaptureInterface $capture): array; * Отправить Запрос на Возврат * @param RefundInterface $refund Возврат * @return array + * @throws PaymentException */ public function sendRefundRequest(RefundInterface $refund): array; @@ -42,6 +45,7 @@ public function sendRefundRequest(RefundInterface $refund): array; * Отправить Запрос о статусе платежа * @param string $merchantPaymentReference Номер транзакции на стороне мерчанта * @return array + * @throws PaymentException */ public function sendStatusRequest(string $merchantPaymentReference): array; diff --git a/src/Authorization.php b/src/Authorization.php index 627d874..e6933d9 100644 --- a/src/Authorization.php +++ b/src/Authorization.php @@ -7,22 +7,17 @@ */ class Authorization implements AuthorizationInterface { - const TYPE_CCVISAMC = 'CCVISAMC'; - const TYPE_FASTER_PAYMENTS = 'FASTER_PAYMENTS'; - - const TYPE_SOM = 'SOM'; - /** * включить страницу оплаты Ypmn * @var bool страница оплаты Ypmn включена? */ private bool $usePaymentPage = true; - private string $paymentMethod = self::TYPE_CCVISAMC; + private string $paymentMethod = PaymentMethods::CCVISAMC; /** @var CardDetailsInterface|null Данные карты */ private ?CardDetailsInterface $cardDetails = null; - /** @var MerchantTokenInterface|null Данные карты (в виде токена) */ + /** @var MerchantTokenInterface|null Данные карты (в виде объекта токена) */ private ?MerchantTokenInterface $merchantToken = null; /** @var OneTimeUseToken|null Одноразовый токен оплаты */ @@ -31,7 +26,6 @@ class Authorization implements AuthorizationInterface /** @var PaymentPageOptions|null */ private ?PaymentPageOptions $paymentPageOptions = null; - /** * Создать Платёжную Авторизацию * @param string $paymentMethodType Метод оплаты (из справочника) @@ -44,22 +38,24 @@ public function __construct(string $paymentMethodType, bool $isPaymentPageUsed) $this->setUsePaymentPage($isPaymentPageUsed); } - /** - * @inheritDoc - * @throws PaymentException Ошибка оплаты - */ - public function setPaymentMethod(string $paymentMethodType) : self + /** @inheritDoc */ + public function setPaymentMethod(string $paymentMethod) : self { - switch ($paymentMethodType) { - case 'CCVISAMC': - $this->paymentMethod = self::TYPE_CCVISAMC; - break; - case 'FASTER_PAYMENTS': - $this->paymentMethod = self::TYPE_FASTER_PAYMENTS; - break; - case 'SOM': - $this->paymentMethod = self::TYPE_SOM; + $paymentMethod = strtoupper($paymentMethod); + + switch ($paymentMethod) { + case PaymentMethods::CCVISAMC: + case PaymentMethods::FASTER_PAYMENTS: + case PaymentMethods::SOM: + case PaymentMethods::MIRPAY: + case PaymentMethods::ALFAPAY: + case PaymentMethods::TPAY: + case PaymentMethods::SBERPAY: + case PaymentMethods::PAYOUT: + case PaymentMethods::PAYOUT_FP: + $this->paymentMethod = $paymentMethod; break; + default: throw new PaymentException('Неверный тип оплаты в авторизации'); } @@ -119,6 +115,7 @@ public function getMerchantToken(): ?MerchantTokenInterface return $this->merchantToken; } + /** @inheritDoc */ public function setOneTimeUseToken(?OneTimeUseToken $oneTimeUseToken): self { $this->setCardDetails(null); @@ -128,6 +125,12 @@ public function setOneTimeUseToken(?OneTimeUseToken $oneTimeUseToken): self return $this; } + /** @inheritDoc */ + public function getOneTimeUseToken(): OneTimeUseToken + { + return $this->oneTimeUseToken; + } + /** * @inheritDoc * @throws PaymentException diff --git a/src/AuthorizationInterface.php b/src/AuthorizationInterface.php index 0b4eaca..63aaff7 100644 --- a/src/AuthorizationInterface.php +++ b/src/AuthorizationInterface.php @@ -6,10 +6,11 @@ interface AuthorizationInterface { /** * Установить Cпособ оплаты (из справочника) - * @param string $paymentMethodType Cпособ оплаты (из справочника) + * @param string $paymentMethod Cпособ оплаты (из справочника) * @return AuthorizationInterface + * @throws PaymentException Ошибка оплаты */ - public function setPaymentMethod(string $paymentMethodType) : self; + public function setPaymentMethod(string $paymentMethod) : self; /** * Получить Cпособ оплаты (из справочника) @@ -56,6 +57,19 @@ public function getMerchantToken(): ?MerchantTokenInterface; */ public function setMerchantToken(?MerchantTokenInterface $merchantToken): self; + /** + * Установить Одноразовый Токен + * @param OneTimeUseToken|null $oneTimeUseToken Одноразовый Токен + * @return self + */ + public function setOneTimeUseToken(?OneTimeUseToken $oneTimeUseToken): self; + + /** + * Получить Одноразовый Токен + * @return OneTimeUseToken|null Одноразовый Токен + */ + public function getOneTimeUseToken(): ?OneTimeUseToken; + /** * Установить настройки платёжной страницы * @param paymentPageOptionsInterface $paymentPageOptions diff --git a/src/Examples/start.php b/src/Examples/start.php index b6b5d32..251ae36 100644 --- a/src/Examples/start.php +++ b/src/Examples/start.php @@ -13,4 +13,4 @@ * https://sandbox.ypmn.ru/ * Убедитесь, что эти адреса разрешены в Firewall вашего приложения */ -$merchant = new Merchant('CC1', 'SECRET_KEY'); +$merchant = new Merchant('gitttest', 'vk0!K4(~9)1d69@0p4&N'); diff --git a/src/Payment.php b/src/Payment.php index a381c8e..21f1804 100644 --- a/src/Payment.php +++ b/src/Payment.php @@ -177,7 +177,7 @@ public function jsonSerialize() /* При создании привязки через СБП необходимо 2 поля consentType и subscriptionPurpose */ if ( empty($requestData['storedCredentials']['consentType']) === false && - $requestData['authorization']['paymentMethod'] === Authorization::TYPE_FASTER_PAYMENTS + $requestData['authorization']['paymentMethod'] === PaymentMethods::FASTER_PAYMENTS ) { $requestData['storedCredentials']['subscriptionPurpose'] = $this->getStoredCredentials()->getSubscriptionPurpose(); } diff --git a/src/PaymentMethods.php b/src/PaymentMethods.php new file mode 100644 index 0000000..70e5a3b --- /dev/null +++ b/src/PaymentMethods.php @@ -0,0 +1,20 @@ + Date: Thu, 12 Sep 2024 18:56:05 +0300 Subject: [PATCH 03/64] bug fixes, small improvements, payment methods select page --- example_header.php | 32 ++++++++++++++++++++++ src/ApiRequest.php | 21 ++++++++------ src/Authorization.php | 24 ++++++++++------ src/AuthorizationInterface.php | 4 +-- src/Examples/getPaymentLink.php | 9 ++++-- src/Examples/getPaymentLinkMarketplace.php | 2 +- src/Examples/simpleGetPaymentLink.php | 19 ++++++++++--- src/Payment.php | 8 ++++-- src/PaymentInterface.php | 4 +-- src/PaymentMethods.php | 2 +- 10 files changed, 92 insertions(+), 33 deletions(-) diff --git a/example_header.php b/example_header.php index 4a27f70..f2e442f 100644 --- a/example_header.php +++ b/example_header.php @@ -4,6 +4,10 @@ Твои Платежи | Сервис для работы с электронными платежами + @@ -31,6 +35,34 @@ } + diff --git a/src/ApiRequest.php b/src/ApiRequest.php index 3002056..4fcb4aa 100644 --- a/src/ApiRequest.php +++ b/src/ApiRequest.php @@ -416,16 +416,23 @@ public function sendAuthRequest(PaymentInterface $payment): array $paymentMethod = $payment->getAuthorization()->getPaymentMethod(); $methodsWithPage = [ PaymentMethods::CCVISAMC, + null, ]; if ( !in_array($paymentMethod, $methodsWithPage) // если метод не подразумевает страницу - || empty($paymentMethod) // или метод не выборан - || !empty($payment->getAuthorization()->getCardDetails()->getNumber()) // или передаются данные PCI-DSS + || (!empty($payment->getAuthorization()->getCardDetails()) + && !empty($payment->getAuthorization()->getCardDetails()->getNumber()) + ) // или передаются данные PCI-DSS || !empty($payment->getAuthorization()->getMerchantToken()) // или содержится токен мерчанта - || !empty($payment->getAuthorization()->getOneTimeUseToken()->getToken()) // или содержится однораз. токен + || (!empty($payment->getAuthorization()->getOneTimeUseToken()) + && !empty($payment->getAuthorization()->getOneTimeUseToken()->getToken()) + ) // или содержится одноразовый токен от "Secret Fields" ) { $payment->getAuthorization()->setUsePaymentPage(false); + } elseif (empty($paymentMethod)) { + $payment->getAuthorization()->setUsePaymentPage(true); // если метод не выборан + } return $this->sendPostRequest($payment, self::AUTHORIZE_API); @@ -531,11 +538,7 @@ public function sendReportOrderDetailsRequest(array $params): array private function getSignature(MerchantInterface $merchant, string $date, string $url, string $httpMethod, string $bodyHash): string { if (strlen($merchant->getCode()) < 2) { - throw new PaymentException('YPMN-001: No Merchant Code'); - } - - if (strlen($merchant->getCode()) < 2) { - throw new PaymentException('YPMN-001: No Merchant Code'); + throw new PaymentException('YPMN-001: не установлен код мерчанта, уточните его в личном кабинете или у Вашего менеджера'); } $urlParts = parse_url($url); @@ -630,7 +633,7 @@ class="w-100 d-block" border: 1px solid green; white-space: pre-wrap; " - >'.print_r($mixedInput, true).''; + >'.print_r($mixedInput, true).''; } } diff --git a/src/Authorization.php b/src/Authorization.php index e6933d9..6c28a29 100644 --- a/src/Authorization.php +++ b/src/Authorization.php @@ -12,7 +12,7 @@ class Authorization implements AuthorizationInterface * @var bool страница оплаты Ypmn включена? */ private bool $usePaymentPage = true; - private string $paymentMethod = PaymentMethods::CCVISAMC; + private ?string $paymentMethod = PaymentMethods::CCVISAMC; /** @var CardDetailsInterface|null Данные карты */ private ?CardDetailsInterface $cardDetails = null; @@ -28,20 +28,23 @@ class Authorization implements AuthorizationInterface /** * Создать Платёжную Авторизацию - * @param string $paymentMethodType Метод оплаты (из справочника) + * (можно указать метод из справочника PaymentMethods.php, + * или передать null, чтобы плательщик выбрал метод сам) + * @param string|null $paymentMethodType Метод оплаты (из справочника) * @param bool $isPaymentPageUsed страница оплаты Ypmn включена? - * @return void * @throws PaymentException Ошибка оплаты */ - public function __construct(string $paymentMethodType, bool $isPaymentPageUsed) { + public function __construct(?string $paymentMethodType = null, bool $isPaymentPageUsed = true) { $this->setPaymentMethod($paymentMethodType); $this->setUsePaymentPage($isPaymentPageUsed); } /** @inheritDoc */ - public function setPaymentMethod(string $paymentMethod) : self + public function setPaymentMethod(?string $paymentMethod) : self { - $paymentMethod = strtoupper($paymentMethod); + if (is_string($paymentMethod)) { + $paymentMethod = strtoupper($paymentMethod); + } switch ($paymentMethod) { case PaymentMethods::CCVISAMC: @@ -53,9 +56,12 @@ public function setPaymentMethod(string $paymentMethod) : self case PaymentMethods::SBERPAY: case PaymentMethods::PAYOUT: case PaymentMethods::PAYOUT_FP: + case null: $this->paymentMethod = $paymentMethod; break; - + case '': + $this->paymentMethod = null; + break; default: throw new PaymentException('Неверный тип оплаты в авторизации'); } @@ -86,7 +92,7 @@ public function getUsePaymentPage(): bool } /** @inheritDoc */ - public function getPaymentMethod(): string + public function getPaymentMethod(): ?string { return $this->paymentMethod; } @@ -126,7 +132,7 @@ public function setOneTimeUseToken(?OneTimeUseToken $oneTimeUseToken): self } /** @inheritDoc */ - public function getOneTimeUseToken(): OneTimeUseToken + public function getOneTimeUseToken(): ?OneTimeUseToken { return $this->oneTimeUseToken; } diff --git a/src/AuthorizationInterface.php b/src/AuthorizationInterface.php index 63aaff7..c9572c0 100644 --- a/src/AuthorizationInterface.php +++ b/src/AuthorizationInterface.php @@ -14,9 +14,9 @@ public function setPaymentMethod(string $paymentMethod) : self; /** * Получить Cпособ оплаты (из справочника) - * @return string Cпособ оплаты (из справочника) + * @return null|string Cпособ оплаты (из справочника) */ - public function getPaymentMethod(): string; + public function getPaymentMethod(): ?string; /** * Установить Использование платёжной страницы diff --git a/src/Examples/getPaymentLink.php b/src/Examples/getPaymentLink.php index 80f02ac..307008c 100644 --- a/src/Examples/getPaymentLink.php +++ b/src/Examples/getPaymentLink.php @@ -10,6 +10,7 @@ use Ypmn\Billing; use Ypmn\ApiRequest; use Ypmn\PaymentException; +use Ypmn\PaymentMethods; use Ypmn\PaymentPageOptions; use Ypmn\Product; use Ypmn\Std; @@ -113,8 +114,10 @@ // Установим валюту $payment->setCurrency('RUB'); -// Создадим авторизацию по типу платежа -$authorization = new Authorization('CCVISAMC',true); +// Создадим запрос на авторизацию платежа +// Здесь первым параметром можно передать конкретный способ оплаты из справочника +// PaymentMethods.php +$authorization = new Authorization(PaymentMethods::CCVISAMC); // Можно установить лимит времени для оплаты заказа (в секундах) $authorization->setPaymentPageOptions(new PaymentPageOptions(600)); // Назначим авторизацию для нашего платежа @@ -134,7 +137,7 @@ // Переключиться на тестовый сервер (закомментируйте или удалите в рабочей программе!) $apiRequest->setSandboxMode(); // Отправим запрос -$responseData = $apiRequest->sendAuthRequest($payment, $merchant); +$responseData = $apiRequest->sendAuthRequest($payment); // Преобразуем ответ из JSON в массив try { $responseData = json_decode((string) $responseData["response"], true); diff --git a/src/Examples/getPaymentLinkMarketplace.php b/src/Examples/getPaymentLinkMarketplace.php index 6e7ed7b..08d6e93 100644 --- a/src/Examples/getPaymentLinkMarketplace.php +++ b/src/Examples/getPaymentLinkMarketplace.php @@ -135,7 +135,7 @@ // Переключиться на тестовый сервер (закомментируйте или удалите в рабочей программе!) $apiRequest->setSandboxMode(); // Отправим запрос -$responseData = $apiRequest->sendAuthRequest($payment, $merchant); +$responseData = $apiRequest->sendAuthRequest($payment); // Преобразуем ответ из JSON в массив try { $responseData = json_decode((string) $responseData["response"], true); diff --git a/src/Examples/simpleGetPaymentLink.php b/src/Examples/simpleGetPaymentLink.php index 7dd50cf..d71d911 100644 --- a/src/Examples/simpleGetPaymentLink.php +++ b/src/Examples/simpleGetPaymentLink.php @@ -24,7 +24,7 @@ $orderAsProduct = new Product([ 'name' => 'Заказ №' . $merchantPaymentReference, 'sku' => $merchantPaymentReference, - 'unitPrice' => 200.42, + 'unitPrice' => 20.42, 'quantity' => 1, ]); @@ -54,8 +54,10 @@ $payment->addProduct($orderAsProduct); // Установим валюту $payment->setCurrency('RUB'); -// Создадим и установим авторизацию по типу платежа -$payment->setAuthorization(new Authorization('CCVISAMC',true)); +// Создадим запрос на авторизацию платежа +// здесь первым параметром можно передать конкретный способ оплаты из справочника +// PaymentMethods.php +$payment->setAuthorization(new Authorization()); // Установим номер заказа (должен быть уникальным в вашей системе) $payment->setMerchantPaymentReference($merchantPaymentReference); // Установим адрес перенаправления пользователя после оплаты @@ -72,14 +74,23 @@ // Отправим запрос $responseData = $apiRequest->sendAuthRequest($payment, $merchant); // Преобразуем ответ из JSON в массив +// TODO: перенести валидацию в функцию ApiClient try { $responseData = json_decode((string) $responseData["response"], true); - if ($responseData) { + if (isset($responseData['code']) + && $responseData['code'] === 429 + && $responseData['status'] === 'LIMIT_CALLS_EXCEEDED' + ) { + throw new PaymentException('YPMN-002: LIMIT_CALLS_EXCEEDED (превышена частота запросов к серверу)'); + } + + if (isset($responseData["paymentResult"])) { // Выведем кнопку оплаты echo Std::drawYpmnButton([ 'url' => $responseData["paymentResult"]['url'], 'sum' => $payment->sumProductsAmount(), + 'newpage' => true, ]); // .. или сделаем редирект на форму оплаты (опционально) diff --git a/src/Payment.php b/src/Payment.php index 21f1804..ae45c77 100644 --- a/src/Payment.php +++ b/src/Payment.php @@ -46,11 +46,15 @@ public function getMerchantPaymentReference() : string } /** @inheritDoc */ - public function setCurrency(string $currency) : self + public function setCurrency(?string $currency) : self { - // TODO: Implement Currency check method. + if($currency === null) { + $currency = 'RUB'; + } + $this->currency = $currency; + // TODO: Implement Currency check method. return $this; } diff --git a/src/PaymentInterface.php b/src/PaymentInterface.php index 9b0cc02..4587ca2 100644 --- a/src/PaymentInterface.php +++ b/src/PaymentInterface.php @@ -21,10 +21,10 @@ public function getMerchantPaymentReference() : string; * Установить Код валюты (например, RUB) * формат кодов валюты ISO 4217 * (https://en.wikipedia.org/wiki/ISO_4217) - * @param string $currency Код валюты + * @param string|null $currency Код валюты * @return $this */ - public function setCurrency(string $currency) : self; + public function setCurrency(?string $currency) : self; /** * Получить Код валюты diff --git a/src/PaymentMethods.php b/src/PaymentMethods.php index 70e5a3b..809f6c6 100644 --- a/src/PaymentMethods.php +++ b/src/PaymentMethods.php @@ -3,7 +3,7 @@ namespace Ypmn; /** - * Это класс для + * Это класс-справочник платёжных методов **/ class PaymentMethods { From 3f1ad2110232f9773431ddd4c555ac1b588232a1 Mon Sep 17 00:00:00 2001 From: Alexey Babak Date: Fri, 13 Sep 2024 13:27:10 +0300 Subject: [PATCH 04/64] review & strict types fixes --- example.php | 18 ++------------ src/ApiRequest.php | 7 +++--- src/ApiRequestInterface.php | 2 +- src/Authorization.php | 9 +++---- src/AuthorizationInterface.php | 21 +++++++++------- src/Billing.php | 2 +- src/BillingInterface.php | 2 +- src/Capture.php | 19 +++++---------- src/CaptureApiRequest.php | 2 +- src/CaptureInterface.php | 4 ++-- src/CardDetails.php | 2 +- src/CardDetailsInterface.php | 2 +- src/Client.php | 2 +- src/ClientInterface.php | 2 +- src/Delivery.php | 2 +- src/DeliveryInterface.php | 2 +- src/DestinationInterface.php | 2 +- src/DetailsInterface.php | 2 +- src/Examples/getBindingFasterPayment.php | 2 +- src/Examples/getPaymentLink.php | 4 ++-- src/Examples/getPaymentLinkMarketplace.php | 2 +- src/Examples/paymentByFasterBinding.php | 2 +- src/Examples/simpleGetPaymentLink.php | 4 +--- src/IdentityDocument.php | 4 ++-- src/IdentityDocumentInterface.php | 4 ++-- src/MarketplaceSubmerchant.php | 2 +- src/MarketplaceSubmerchantInterface.php | 2 +- src/Merchant.php | 28 ++++++++-------------- src/MerchantInterface.php | 2 +- src/MerchantToken.php | 3 ++- src/MerchantTokenInterface.php | 2 +- src/OrderData.php | 2 +- src/OrderDataInterface.php | 2 +- src/Payment.php | 4 ++-- src/PaymentException.php | 2 +- src/PaymentInterface.php | 5 ++-- src/PaymentPageOptions.php | 4 +--- src/PaymentPageOptionsInterface.php | 4 +--- src/PaymentReference.php | 25 +++++++++++++------ src/PaymentResult.php | 2 +- src/PaymentResultInterface.php | 2 +- src/PayoutMobileDestination.php | 4 +--- src/PhoneDetails.php | 2 +- src/ProductInterface.php | 2 +- src/Qst.php | 4 +--- src/QstInterface.php | 4 +--- src/QstSchema.php | 4 +--- src/QstSchemaActualAddress.php | 4 +--- src/QstSchemaAddressAbstract.php | 4 +--- src/QstSchemaAddressInterface.php | 4 +--- src/QstSchemaBankAccount.php | 6 ++--- src/QstSchemaBankAccountInterface.php | 4 +--- src/QstSchemaCeo.php | 6 ++--- src/QstSchemaCeoInterface.php | 4 +--- src/QstSchemaCheckableTrait.php | 4 +--- src/QstSchemaIdentityDoc.php | 6 ++--- src/QstSchemaIdentityDocInterface.php | 6 ++--- src/QstSchemaInterface.php | 4 +--- src/QstSchemaLegalAddress.php | 4 +--- src/QstSchemaOwner.php | 6 ++--- src/QstSchemaOwnerInterface.php | 6 ++--- src/QstSchemaPostAddress.php | 4 +--- src/QstToArrayInterface.php | 4 +--- src/Refund.php | 2 +- src/RefundInterface.php | 4 ++-- src/Std.php | 2 +- src/StoredCredentials.php | 2 +- src/StoredCredentialsInterface.php | 2 +- src/TransactionInterface.php | 3 ++- src/Webhook.php | 8 +++---- src/WebhookInterface.php | 2 +- 71 files changed, 138 insertions(+), 198 deletions(-) diff --git a/example.php b/example.php index 0bb7cb0..47eb6b3 100644 --- a/example.php +++ b/example.php @@ -1,27 +1,13 @@ getAuthorization()->getMerchantToken()) // или содержится токен мерчанта || (!empty($payment->getAuthorization()->getOneTimeUseToken()) && !empty($payment->getAuthorization()->getOneTimeUseToken()->getToken()) - ) // или содержится одноразовый токен от "Secret Fields" + ) // или содержится одноразовый токен от "Secure Fields" ) { $payment->getAuthorization()->setUsePaymentPage(false); } elseif (empty($paymentMethod)) { - $payment->getAuthorization()->setUsePaymentPage(true); // если метод не выборан - + $payment->getAuthorization()->setUsePaymentPage(true); // если метод не выбран } return $this->sendPostRequest($payment, self::AUTHORIZE_API); diff --git a/src/ApiRequestInterface.php b/src/ApiRequestInterface.php index 7629126..fdd8cbd 100644 --- a/src/ApiRequestInterface.php +++ b/src/ApiRequestInterface.php @@ -1,4 +1,4 @@ -oneTimeUseToken; } - /** - * @inheritDoc - * @throws PaymentException - */ + /** @inheritDoc */ public function setMerchantToken(?MerchantTokenInterface $merchantToken): self { if (is_null($this->getCardDetails()) && $this->getUsePaymentPage() === false) { diff --git a/src/AuthorizationInterface.php b/src/AuthorizationInterface.php index c9572c0..f51e3ff 100644 --- a/src/AuthorizationInterface.php +++ b/src/AuthorizationInterface.php @@ -1,20 +1,20 @@ -setIdentityDocument( - new IdentityDocument('123456', 'PERSONALID') + new IdentityDocument(123456, 'PERSONALID') ); $delivery->setCountryCode('RU'); // Установим Код страны $delivery->setCity('Москва'); // Установим Город diff --git a/src/Examples/getPaymentLink.php b/src/Examples/getPaymentLink.php index 307008c..a9302c4 100644 --- a/src/Examples/getPaymentLink.php +++ b/src/Examples/getPaymentLink.php @@ -70,7 +70,7 @@ $delivery = new Delivery; // Установим документ, подтверждающий право приёма доставки $delivery->setIdentityDocument( - new IdentityDocument('123456', 'PERSONALID') + new IdentityDocument(123456, 'PERSONALID') ); // Установим Код страны $delivery->setCountryCode('RU'); @@ -108,7 +108,7 @@ // Создадим платёж $payment = new Payment; -// Установим позиции +// Присвоим товарные позиции $payment->addProduct($product1); $payment->addProduct($product2); // Установим валюту diff --git a/src/Examples/getPaymentLinkMarketplace.php b/src/Examples/getPaymentLinkMarketplace.php index 08d6e93..9e28c56 100644 --- a/src/Examples/getPaymentLinkMarketplace.php +++ b/src/Examples/getPaymentLinkMarketplace.php @@ -76,7 +76,7 @@ $delivery = new Delivery; // Установим документ, подтверждающий право приёма доставки $delivery->setIdentityDocument( - new IdentityDocument('123456', 'PERSONALID') + new IdentityDocument(123456, 'PERSONALID') ); // Установим Код страны $delivery->setCountryCode('RU'); diff --git a/src/Examples/paymentByFasterBinding.php b/src/Examples/paymentByFasterBinding.php index a73d86b..9632a43 100644 --- a/src/Examples/paymentByFasterBinding.php +++ b/src/Examples/paymentByFasterBinding.php @@ -73,7 +73,7 @@ $delivery = new Delivery; // Установим документ, подтверждающий право приёма доставки $delivery->setIdentityDocument( - new IdentityDocument('123456', 'PERSONALID') + new IdentityDocument(123456, 'PERSONALID') ); $delivery->setCountryCode('RU'); // Установим Код страны $delivery->setCity('Москва'); // Установим Город diff --git a/src/Examples/simpleGetPaymentLink.php b/src/Examples/simpleGetPaymentLink.php index d71d911..b5586a4 100644 --- a/src/Examples/simpleGetPaymentLink.php +++ b/src/Examples/simpleGetPaymentLink.php @@ -50,10 +50,8 @@ // Создадим платёж $payment = new Payment; -// Установим позиции +// Присвоим товарные позиции $payment->addProduct($orderAsProduct); -// Установим валюту -$payment->setCurrency('RUB'); // Создадим запрос на авторизацию платежа // здесь первым параметром можно передать конкретный способ оплаты из справочника // PaymentMethods.php diff --git a/src/IdentityDocument.php b/src/IdentityDocument.php index 2f482c8..ce0c0b3 100644 --- a/src/IdentityDocument.php +++ b/src/IdentityDocument.php @@ -1,4 +1,4 @@ -setNumber($number) ->setType($type); diff --git a/src/IdentityDocumentInterface.php b/src/IdentityDocumentInterface.php index 76efb8b..1822e69 100644 --- a/src/IdentityDocumentInterface.php +++ b/src/IdentityDocumentInterface.php @@ -1,4 +1,4 @@ -setSecret($merchantSecret); } - /** - * @inheritDoc - */ + /** @inheritDoc */ public function setCode(string $merchantCode): MerchantInterface { $this->merchantCode = $merchantCode; return $this; } - /** - * @inheritDoc - */ + /** @inheritDoc */ public function getCode(): string { return $this->merchantCode; } - /** - * @inheritDoc - */ + /** @inheritDoc */ public function setSecret(string $merchantSecret): MerchantInterface { $this->merchantSecret = $merchantSecret; return $this; } - /** - * @inheritDoc - */ + /** @inheritDoc */ public function getSecret(): string { return $this->merchantSecret; diff --git a/src/MerchantInterface.php b/src/MerchantInterface.php index fd3fad4..2096852 100644 --- a/src/MerchantInterface.php +++ b/src/MerchantInterface.php @@ -1,4 +1,4 @@ -setPaymentReference($paymentReference); + if (empty($paymentReference)) { + if($autoGenerate) { + $paymentReference = 'Заказ__' . uniqid() . '__' . time(); + } else { + throw new PaymentException('YPMN-003 Передайтие корректный уникальный номер заказа в вашей системе'); + } + } + + $this->setPaymentReference((string) $paymentReference); } - private function setPaymentReference(int $paymentReference) : self + private function setPaymentReference(string $paymentReference) : self { $this->paymentReference = $paymentReference; + return $this; } @@ -38,4 +49,4 @@ public function jsonSerialize(): string return json_encode($resultArray, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_LINE_TERMINATORS); } -} \ No newline at end of file +} diff --git a/src/PaymentResult.php b/src/PaymentResult.php index e235ccb..917c93b 100644 --- a/src/PaymentResult.php +++ b/src/PaymentResult.php @@ -1,4 +1,4 @@ - $this->getBankAccount() ]; } -} \ No newline at end of file +} diff --git a/src/QstSchemaBankAccountInterface.php b/src/QstSchemaBankAccountInterface.php index 7725f42..bf24b7e 100644 --- a/src/QstSchemaBankAccountInterface.php +++ b/src/QstSchemaBankAccountInterface.php @@ -1,6 +1,4 @@ - $value !== null); } -} \ No newline at end of file +} diff --git a/src/QstSchemaCeoInterface.php b/src/QstSchemaCeoInterface.php index 2f44d30..173a636 100644 --- a/src/QstSchemaCeoInterface.php +++ b/src/QstSchemaCeoInterface.php @@ -1,6 +1,4 @@ - $value !== null); } -} \ No newline at end of file +} diff --git a/src/QstSchemaIdentityDocInterface.php b/src/QstSchemaIdentityDocInterface.php index aa4da1d..620f8c0 100644 --- a/src/QstSchemaIdentityDocInterface.php +++ b/src/QstSchemaIdentityDocInterface.php @@ -1,6 +1,4 @@ - $this->getShare(), ]; } -} \ No newline at end of file +} diff --git a/src/QstSchemaOwnerInterface.php b/src/QstSchemaOwnerInterface.php index 7423f1a..d370b28 100644 --- a/src/QstSchemaOwnerInterface.php +++ b/src/QstSchemaOwnerInterface.php @@ -1,6 +1,4 @@ -orderData->setCurrency($request['orderData']['currency']); $this->orderData->setAmount($request['orderData']['amount']); $this->orderData->setCommission((float) $request['orderData']['commission']); - $this->orderData->setLoyaltyPointsAmount((int) $request['orderData']['loyaltyPointsAmount']); + $this->orderData->setLoyaltyPointsAmount((string) $request['orderData']['loyaltyPointsAmount']); $this->orderData->setLoyaltyPointsDetails((array) $request['orderData']['loyaltyPointsDetails']); $cardDetails = new CardDetails; @@ -46,7 +46,7 @@ public function catchJsonRequest(): self $this->paymentResult->setCardDetails($cardDetails); $this->paymentResult->setPaymentMethod($request['paymentResult']['paymentMethod']); $this->paymentResult->setPaymentDate($request['paymentResult']['paymentDate']); - $this->paymentResult->setAuthCode((int) $request['paymentResult']['authCode']); + $this->paymentResult->setAuthCode((string) $request['paymentResult']['authCode']); $this->paymentResult->setMerchantId($request['paymentResult']['merchantId']); if (isset($request['paymentResult']['captureDate'])) { diff --git a/src/WebhookInterface.php b/src/WebhookInterface.php index 0588196..8245f43 100644 --- a/src/WebhookInterface.php +++ b/src/WebhookInterface.php @@ -1,4 +1,4 @@ - Date: Fri, 13 Sep 2024 15:36:21 +0300 Subject: [PATCH 05/64] review fixes --- src/Merchant.php | 2 +- src/OrderData.php | 22 ++++++++++++---------- src/OrderDataInterface.php | 8 ++++---- src/PaymentReference.php | 22 +++++++++++++++------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/Merchant.php b/src/Merchant.php index 383475f..87e8c41 100644 --- a/src/Merchant.php +++ b/src/Merchant.php @@ -16,7 +16,7 @@ class Merchant implements MerchantInterface private string $merchantCode; /** - * Секретный Ключможно + * Секретный Ключ * !НЕ передавать в открытом виде * получить в https://ypmn.ru/cpanel/account_settings.php * Или в https://sandbox.ypmn.ru/cpanel/account_settings.php для тестов diff --git a/src/OrderData.php b/src/OrderData.php index cc9f22b..0a1182d 100644 --- a/src/OrderData.php +++ b/src/OrderData.php @@ -28,8 +28,8 @@ class OrderData implements OrderDataInterface /** @var string Идентификатор запроса на возмещение средств */ private string $refundRequestId; - /** @var string Количество баллов лояльности */ - private string $loyaltyPointsAmount; + /** @var int|null Количество баллов лояльности */ + private ?int $loyaltyPointsAmount = null; /** @var array Детализация баллов лояльности */ private array $loyaltyPointsDetails; @@ -44,19 +44,15 @@ public function getOrderDate(): string public function setOrderDate(string $orderDate): self { $this->orderDate = $orderDate; - return $this; - } - /** @inheritDoc */ - public function getUpmnPaymentReference(): string - { - return $this->ypmnPaymentReference; + return $this; } /** @inheritDoc */ public function setYpmnPaymentReference(string $ypmnPaymentReference): self { $this->ypmnPaymentReference = $ypmnPaymentReference; + return $this; } @@ -76,6 +72,7 @@ public function getMerchantPaymentReference(): string public function setMerchantPaymentReference(string $merchantPaymentReference): self { $this->merchantPaymentReference = $merchantPaymentReference; + return $this; } @@ -89,6 +86,7 @@ public function getStatus(): string public function setStatus(string $status): self { $this->status = $status; + return $this; } @@ -102,6 +100,7 @@ public function getCurrency(): string public function setCurrency(string $currency): self { $this->currency = $currency; + return $this; } @@ -115,6 +114,7 @@ public function getAmount(): ?float public function setAmount(float $amount): self { $this->amount = $amount; + return $this; } @@ -148,15 +148,16 @@ public function setRefundRequestId(string $refundRequestId): self } /** @inheritDoc */ - public function getLoyaltyPointsAmount(): ?string + public function getLoyaltyPointsAmount(): ?int { return $this->loyaltyPointsAmount; } /** @inheritDoc */ - public function setLoyaltyPointsAmount(string $loyaltyPointsAmount): self + public function setLoyaltyPointsAmount(int $loyaltyPointsAmount): self { $this->loyaltyPointsAmount = $loyaltyPointsAmount; + return $this; } @@ -172,6 +173,7 @@ public function setLoyaltyPointsDetails(array $loyaltyPointsDetails): self if(count($loyaltyPointsDetails) > 0) { $this->loyaltyPointsDetails = $loyaltyPointsDetails; } + return $this; } } diff --git a/src/OrderDataInterface.php b/src/OrderDataInterface.php index 3063121..f87ad4c 100644 --- a/src/OrderDataInterface.php +++ b/src/OrderDataInterface.php @@ -111,16 +111,16 @@ public function setRefundRequestId(string $refundRequestId): self; /** * Получить Количество Баллов Лояльности - * @return string Количество Баллов Лояльности + * @return int|null Количество Баллов Лояльности */ - public function getLoyaltyPointsAmount(): ?string; + public function getLoyaltyPointsAmount(): ?int; /** * Установить Количество Баллов Лояльности - * @param string $loyaltyPointsAmount + * @param int $loyaltyPointsAmount * @return $this Количество Баллов Лояльности */ - public function setLoyaltyPointsAmount(string $loyaltyPointsAmount): self; + public function setLoyaltyPointsAmount(int $loyaltyPointsAmount): self; /** * Получить Детализацию Баллов Лояльности diff --git a/src/PaymentReference.php b/src/PaymentReference.php index 72859c8..45dcca2 100644 --- a/src/PaymentReference.php +++ b/src/PaymentReference.php @@ -8,6 +8,7 @@ class PaymentReference implements \JsonSerializable { private ?string $paymentReference = null; + private bool $autoGenerate = true; /** * @param null $paymentReference номер транзакции @@ -15,21 +16,28 @@ class PaymentReference implements \JsonSerializable * @throws PaymentException */ public function __construct($paymentReference = null, bool $autoGenerate = true) + { + $this->autoGenerate = $autoGenerate; + $this->setPaymentReference($paymentReference); + } + + /** + * Установить уникальный номер заказа + * @param $paymentReference + * @return self + * @throws PaymentException + */ + private function setPaymentReference($paymentReference): self { if (empty($paymentReference)) { - if($autoGenerate) { + if($this->autoGenerate) { $paymentReference = 'Заказ__' . uniqid() . '__' . time(); } else { throw new PaymentException('YPMN-003 Передайтие корректный уникальный номер заказа в вашей системе'); } } - $this->setPaymentReference((string) $paymentReference); - } - - private function setPaymentReference(string $paymentReference) : self - { - $this->paymentReference = $paymentReference; + $this->paymentReference = (string) $paymentReference; return $this; } From b81325473aca31230cb7630283d9b3ff189620b3 Mon Sep 17 00:00:00 2001 From: Oleg Pavlov Date: Mon, 16 Sep 2024 10:05:25 +0300 Subject: [PATCH 06/64] Mirroring check --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e64d93f..86300e2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# «Твои Платежи»: Интеграция на PHP +## «Твои Платежи»: Интеграция на PHP Готовая библиотека + подробные примеры с комментариями. Требования: [PHP 7.4 и выше](https://github.com/yourpayments/php-api-client/blob/main/composer.json) ![](https://repository-images.githubusercontent.com/638835276/2067d028-b541-4355-b069-3c12c8a28042) From a8a0bf3210591a8ed34a5cc942e5fdd4230dfe32 Mon Sep 17 00:00:00 2001 From: Oleg Pavlov Date: Mon, 16 Sep 2024 10:06:30 +0300 Subject: [PATCH 07/64] Mirroring ckeck completed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86300e2..e64d93f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## «Твои Платежи»: Интеграция на PHP +# «Твои Платежи»: Интеграция на PHP Готовая библиотека + подробные примеры с комментариями. Требования: [PHP 7.4 и выше](https://github.com/yourpayments/php-api-client/blob/main/composer.json) ![](https://repository-images.githubusercontent.com/638835276/2067d028-b541-4355-b069-3c12c8a28042) From 311775dd0b1c4c303034ac8a84ece047854a4e0b Mon Sep 17 00:00:00 2001 From: Oleg Pavlov Date: Mon, 16 Sep 2024 11:27:58 +0300 Subject: [PATCH 08/64] Gitflic mirror test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e64d93f..86300e2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# «Твои Платежи»: Интеграция на PHP +## «Твои Платежи»: Интеграция на PHP Готовая библиотека + подробные примеры с комментариями. Требования: [PHP 7.4 и выше](https://github.com/yourpayments/php-api-client/blob/main/composer.json) ![](https://repository-images.githubusercontent.com/638835276/2067d028-b541-4355-b069-3c12c8a28042) From 5097f93de6cba0c7da174634a9d05dc066d7fb70 Mon Sep 17 00:00:00 2001 From: Oleg Pavlov Date: Mon, 16 Sep 2024 11:28:42 +0300 Subject: [PATCH 09/64] Gitflic mirroring test complete --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86300e2..e64d93f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## «Твои Платежи»: Интеграция на PHP +# «Твои Платежи»: Интеграция на PHP Готовая библиотека + подробные примеры с комментариями. Требования: [PHP 7.4 и выше](https://github.com/yourpayments/php-api-client/blob/main/composer.json) ![](https://repository-images.githubusercontent.com/638835276/2067d028-b541-4355-b069-3c12c8a28042) From c17a7ec60a719299faed2f46e47161e79f5be486 Mon Sep 17 00:00:00 2001 From: Alexey Babak Date: Tue, 24 Sep 2024 11:05:14 +0300 Subject: [PATCH 10/64] PaymentException update --- src/PaymentException.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/PaymentException.php b/src/PaymentException.php index 72b333b..e71a985 100644 --- a/src/PaymentException.php +++ b/src/PaymentException.php @@ -4,6 +4,9 @@ class PaymentException extends \Exception { + /** @var string Подробности для логирования */ + private string $logText; + /** * Ошибка в формате Bootstrap * @return string текст ошибки @@ -19,4 +22,22 @@ public function getHtmlMessage(): string '; } + + /** + * @return string + */ + public function getLogText(): string + { + return $this->logText; + } + + /** + * @param string $logText + * @return PaymentException + */ + public function setLogText(string $logText): self + { + $this->logText = $logText; + return $this; + } } From b31f67ca8a3fb687a67e7709634a2e715fc53837 Mon Sep 17 00:00:00 2001 From: Alexey Babak Date: Tue, 24 Sep 2024 11:23:23 +0300 Subject: [PATCH 11/64] readme update --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e64d93f..8537b5f 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,13 @@ [Пакет Composer](https://packagist.org/packages/yourpayments/php-api-client) может использоваться с любыми фреймворками, платформами и CMS, включая, но не ограничиваясь: Laravel, Bitrix, Wordpress, Yii, Symfony, и др. -## Установка за 1 минуту +## Установка и обновление за 1 минуту ```shell composer require yourpayments/php-api-client ``` +```shell +composer update yourpayments/php-api-client +``` (если на вашем проекте нет composer, слонируйте или скачайте, а затем подключите ([require](https://www.php.net/manual/ru/function.require.php)) файлы этого репозитория) ## Запуск в контейнере docker From 45b6ed15c9fff33be284a8bdeff11a18258106c0 Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Wed, 30 Oct 2024 13:37:19 +0500 Subject: [PATCH 12/64] YP-980_API functionality has been added to work with Users, Roles and Privileges. --- src/ApiCpanelArraySerializeInterface.php | 14 ++ src/ApiCpanelUserException.php | 11 + src/ApiCpanelUserRequest.php | 148 ++++++++++++ src/ApiRequest.php | 215 ++++++++++------- src/CpanelUser.php | 283 +++++++++++++++++++++++ src/Group.php | 95 ++++++++ src/Privilege.php | 96 ++++++++ src/Role.php | 189 +++++++++++++++ 8 files changed, 969 insertions(+), 82 deletions(-) create mode 100644 src/ApiCpanelArraySerializeInterface.php create mode 100644 src/ApiCpanelUserException.php create mode 100644 src/ApiCpanelUserRequest.php create mode 100644 src/CpanelUser.php create mode 100644 src/Group.php create mode 100644 src/Privilege.php create mode 100644 src/Role.php diff --git a/src/ApiCpanelArraySerializeInterface.php b/src/ApiCpanelArraySerializeInterface.php new file mode 100644 index 0000000..28b44f7 --- /dev/null +++ b/src/ApiCpanelArraySerializeInterface.php @@ -0,0 +1,14 @@ + null, 'error' => $pe->getMessage()]; + } + + return $result; + } + + /** + * @param array $merchants + * @return array + */ + public function getRolesList(array $merchants = []): array + { + $apiUrlWithQuery = self::CPANEL_ROLE_API; + if (!empty($merchants)) { + $apiUrlWithQuery .= '?merchants=' . implode(',', $merchants); + } + try { + $result = parent::sendGetRequest($apiUrlWithQuery); + } catch (PaymentException $pe) { + return ['response' => null, 'error' => $pe->getMessage()]; + } + + return $result; + } + + /** + * @param array $merchants + * @return array + */ + public function getUsersList(array $merchants = []): array + { + $apiUrlWithQuery = self::CPANEL_USER_API; + if (!empty($merchants)) { + $apiUrlWithQuery .= '?merchants=' . implode(',', $merchants); + } + try { + $result = parent::sendGetRequest($apiUrlWithQuery); + } catch (PaymentException $pe) { + return ['response' => null, 'error' => $pe->getMessage()]; + } + + return $result; + } + + /** + * @param CpanelUser $newUser + * @return array + */ + public function createUser(CpanelUser $newUser): array + { + $newUserSerialized = json_encode($newUser->arraySerialize()); + try { + $result = parent::sendPostRequest( + $newUserSerialized, + self::CPANEL_USER_API, + 'Ошибка создания пользователя' + ); + } catch (PaymentException $pe) { + return ['response' => null, 'error' => $pe->getMessage()]; + } + + return $result; + } + + /** + * @param CpanelUser $editUser + * @return array + */ + public function updateUser(CpanelUser $editUser): array + { + $editUserSerialized = json_encode($editUser->arraySerialize()); + try { + $result = parent::sendPutRequest( + $editUserSerialized, + self::CPANEL_USER_API, + 'Ошибка изменения пользователя' + ); + } catch (PaymentException $pe) { + return ['response' => null, 'error' => $pe->getMessage()]; + } + + return $result; + } + + /** + * @param Role $newRole + * @return array + */ + public function createRole(Role $newRole): array + { + $newRoleSerialized = json_encode($newRole->arraySerialize()); + try { + $result = parent::sendPostRequest( + $newRoleSerialized, + self::CPANEL_ROLE_API, + 'Ошибка создания роли' + ); + } catch (PaymentException $pe) { + return ['response' => null, 'error' => $pe->getMessage()]; + } + + return $result; + } + + /** + * @param Role $editRole + * @return array + */ + public function updateRole(Role $editRole): array + { + $editRoleSerialized = json_encode($editRole->arraySerialize()); + try { + $result = parent::sendPutRequest( + $editRoleSerialized, + self::CPANEL_ROLE_API, + 'Ошибка изменения роли' + ); + } catch (PaymentException $pe) { + return ['response' => null, 'error' => $pe->getMessage()]; + } + + return $result; + } +} diff --git a/src/ApiRequest.php b/src/ApiRequest.php index f6583d2..f736d8e 100644 --- a/src/ApiRequest.php +++ b/src/ApiRequest.php @@ -1,4 +1,6 @@ -host; } /** @inheritdoc */ - public function setHost(string $host) : self + public function setHost(string $host): self { if (filter_var($host, FILTER_VALIDATE_URL)) { $this->host = $host; @@ -185,7 +187,7 @@ private function buildReportsSourceString($parameters) * @param $parameters * @return string */ - private function reportsSign($parameters) + private function reportsSign($parameters): string { $sourceString = $this->buildReportsSourceString($parameters); @@ -198,7 +200,7 @@ private function reportsSign($parameters) * @return array ответ сервера Ypmn * @throws PaymentException */ - private function sendGetRequest(string $api): array + public function sendGetRequest(string $api): array { $curl = curl_init(); $date = (new DateTime())->format(DateTimeInterface::ATOM); @@ -244,7 +246,7 @@ private function sendGetRequest(string $api): array $this->echoDebugMessage($this->getHost() . $api); $this->echoDebugMessage('Ответ от сервера Ypmn:'); if ($this->getJsonDebugResponse()) { - $this->echoDebugMessage(json_encode(json_decode($response), JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); + $this->echoDebugMessage(json_encode(json_decode($response), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } else { $this->echoDebugMessage($response); } @@ -261,7 +263,7 @@ private function sendGetRequest(string $api): array echo '
Оставить заявку на улучшение'; echo '
Контакты'; } else { - $cpanel_url = 'https://' . ($this->getSandboxMode() ? 'sandbox' : 'secure' ). '.ypmn.ru/cpanel/'; + $cpanel_url = 'https://' . ($this->getSandboxMode() ? 'sandbox' : 'secure' ) . '.ypmn.ru/cpanel/'; if ($this->getSandboxMode()) { echo Std::alert([ @@ -287,14 +289,49 @@ private function sendGetRequest(string $api): array } /** - * Отправка POST-запроса + * Функция-декоратор для отправки POST-запроса + * @param string|JsonSerializable $data запрос + * @param string $api адрес API (URI) + * @param string|null $customErrorMessage Переопредеяемое пользователем сообщение + * при отсутствии ответа от сервера (опционально) + * @return array ответ сервера Ypmn + * @throws PaymentException + */ + public function sendPostRequest($data, string $api, ?string $customErrorMessage = null): array + { + return $this->sendPostPutRequest($data, $api, 'POST', $customErrorMessage); + } + + /** + * Функция-декоратор для отправки PUT-запроса * @param string|JsonSerializable $data запрос * @param string $api адрес API (URI) + * @param string|null $customErrorMessage Переопредеяемое пользователем сообщение + * при отсутствии ответа от сервера (опционально) * @return array ответ сервера Ypmn * @throws PaymentException */ - public function sendPostRequest($data, string $api): array + public function sendPutRequest($data, string $api, ?string $customErrorMessage = null): array { + return $this->sendPostPutRequest($data, $api, 'PUT', $customErrorMessage); + } + + /** + * Отправка POST и PUT запросов + * @param string|JsonSerializable $data запрос + * @param string $api адрес API (URI) + * @param string $method HTTP-метод (POST | PUT) + * @param string|null $customErrorMessage Переопредеяемое пользователем сообщение + * при отсутствии ответа от сервера (опционально) + * @return array ответ сервера Ypmn + * @throws PaymentException + */ + private function sendPostPutRequest( + $data, + string $api, + string $method, + ?string $customErrorMessage = null + ): array { if ($data instanceof JsonSerializable) { $encodedJsonData = $data->jsonSerialize(); } elseif (is_string($data)) { @@ -307,18 +344,19 @@ public function sendPostRequest($data, string $api): array throw new PaymentException('Incorrect request body JSON'); } + $encodedJsonDataHash = md5($encodedJsonData); $curl = curl_init(); $date = (new DateTime())->format(DateTimeInterface::ATOM); - $requestHttpVerb = 'POST'; + $requestHttpVerb = $method; $setOptArray = [ CURLOPT_URL => $this->getHost() . $api, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, - CURLOPT_TIMEOUT => 30, + CURLOPT_TIMEOUT => 60, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => $requestHttpVerb, CURLOPT_POSTFIELDS => $encodedJsonData, @@ -350,10 +388,10 @@ public function sendPostRequest($data, string $api): array curl_close($curl); if (true === $this->getDebugMode()) { - $this->echoDebugMessage('POST-Запрос к серверу Ypmn:'); + $this->echoDebugMessage("$method-Запрос к серверу Ypmn:"); $this->echoDebugMessage($encodedJsonData); $this->echoDebugMessage('Ответ от сервера Ypmn:'); - $this->echoDebugMessage(json_encode(json_decode($response), JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); + $this->echoDebugMessage(json_encode(json_decode($response), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); if ($this->getDebugShowResponseHeaders()) { $this->echoDebugMessage('Заголовки ответа от сервера Ypmn:'); @@ -369,7 +407,7 @@ public function sendPostRequest($data, string $api): array echo '
Оставить заявку на улучшение'; echo '
Контакты'; } else { - $cpanel_url = 'https://' . ($this->getSandboxMode() ? 'sandbox' : 'secure' ). '.ypmn.ru/cpanel/'; + $cpanel_url = 'https://' . ($this->getSandboxMode() ? 'sandbox' : 'secure' ) . '.ypmn.ru/cpanel/'; if ($this->getSandboxMode()) { echo Std::alert([ @@ -396,7 +434,9 @@ public function sendPostRequest($data, string $api): array } if ($response == null || strlen($response) === 0) { - throw new PaymentException('Вы можете попробовать другой способ оплаты, либо свяжитесь с продавцом.'); + throw new PaymentException( + $customErrorMessage ?? 'Вы можете попробовать другой способ оплаты, либо свяжитесь с продавцом.' + ); } return ['response' => $response, 'error' => $err]; @@ -410,46 +450,33 @@ public function sendSessionRequest(SessionRequest $sessionRequest): array return $this->sendPostRequest($sessionRequest, self::SESSION_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendAuthRequest(PaymentInterface $payment): array { - $paymentMethod = $payment->getAuthorization()->getPaymentMethod(); - $methodsWithPage = [ - PaymentMethods::CCVISAMC, - null, - ]; - - if ( - !in_array($paymentMethod, $methodsWithPage) // если метод не подразумевает страницу - || (!empty($payment->getAuthorization()->getCardDetails()) - && !empty($payment->getAuthorization()->getCardDetails()->getNumber()) - ) // или передаются данные PCI-DSS - || !empty($payment->getAuthorization()->getMerchantToken()) // или содержится токен мерчанта - || (!empty($payment->getAuthorization()->getOneTimeUseToken()) - && !empty($payment->getAuthorization()->getOneTimeUseToken()->getToken()) - ) // или содержится одноразовый токен от "Secure Fields" - ) { - $payment->getAuthorization()->setUsePaymentPage(false); - } elseif (empty($paymentMethod)) { - $payment->getAuthorization()->setUsePaymentPage(true); // если метод не выбран - } - return $this->sendPostRequest($payment, self::AUTHORIZE_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendCaptureRequest(CaptureInterface $capture): array { return $this->sendPostRequest($capture, self::CAPTURE_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendRefundRequest(RefundInterface $refund): array { return $this->sendPostRequest($refund, self::REFUND_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendStatusRequest(string $merchantPaymentReference): array { $responseData = $this->sendGetRequest(self::STATUS_API . '/' . $merchantPaymentReference); @@ -465,32 +492,42 @@ public function sendStatusRequest(string $merchantPaymentReference): array return $responseData; } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendTokenCreationRequest(PaymentReference $payuPaymentReference): array { return $this->sendPostRequest($payuPaymentReference, self::TOKEN_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendTokenPaymentRequest(MerchantToken $tokenHash): array { return $this->sendPostRequest($tokenHash, self::AUTHORIZE_API); } - /** @inheritDoc */ - public function sendPayoutCreateRequest(PayoutInterface $payout) + /** + * @throws PaymentException + */ + public function sendPayoutCreateRequest(PayoutInterface $payout): array { return $this->sendPostRequest($payout, self::PAYOUT_CREATE_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendReportChartRequest(array $params): array { $this->setJsonDebugResponse(false); return $this->sendGetRequest(self::REPORT_CHART_API . '/?' . http_build_query($params)); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendReportChartUpdateRequest(array $params): array { $getParams = [ @@ -507,19 +544,25 @@ public function sendReportChartUpdateRequest(array $params): array return $this->sendGetRequest(self::REPORT_CHART_API . '/?' . http_build_query($params)); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendReportGeneralRequest(array $params): array { return $this->sendGetRequest(self::REPORT_GENERAL_API . '/?' . http_build_query($params)); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendReportOrderRequest(array $params): array { return $this->sendGetRequest(self::REPORT_ORDERS_API_V4 . '/?' . http_build_query($params)); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendReportOrderDetailsRequest(array $params): array { return $this->sendGetRequest(self::REPORT_ORDER_DETAILS_API . '/?' . http_build_query($params)); @@ -533,11 +576,12 @@ public function sendReportOrderDetailsRequest(array $params): array * @param string $httpMethod HTTP * @param string $bodyHash md5-хэш запроса * @return string подпись + * @throws PaymentException */ private function getSignature(MerchantInterface $merchant, string $date, string $url, string $httpMethod, string $bodyHash): string { if (strlen($merchant->getCode()) < 2) { - throw new PaymentException('YPMN-001: не установлен код мерчанта, уточните его в личном кабинете или у Вашего менеджера'); + throw new PaymentException('YPMN-001: No Merchant Code'); } $urlParts = parse_url($url); @@ -570,13 +614,11 @@ public function setSandboxMode(bool $sandboxModeIsOn = true): self return $this; } - /** @inheritdoc */ public function getLocalMode(): bool { return $this->localModeIsOn; } - /** @inheritdoc */ public function setLocalMode(bool $localModeIsOn = true): self { if ($localModeIsOn) { @@ -602,14 +644,14 @@ public function setDebugMode(bool $debugModeIsOn = true): self } /** @inheritdoc */ - public function setJsonDebugResponse(bool $jsonDebugResponse): self + public function setJsonDebugResponse(bool $jsonDebugResponse): self { $this->jsonDebugResponse = $jsonDebugResponse; return $this; } /** @inheritdoc */ - public function getJsonDebugResponse(): bool + public function getJsonDebugResponse(): bool { return $this->jsonDebugResponse; } @@ -632,35 +674,45 @@ class="w-100 d-block" border: 1px solid green; white-space: pre-wrap; " - >'.print_r($mixedInput, true).''; + >' . print_r($mixedInput, true) . ''; } } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendPodeliRegistrationMerchantRequest(PodeliMerchant $merchant): array { return $this->sendPostRequest($merchant, self::PODELI_MERCHANT_REGISTRATION_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendQstCreateRequest(QstInterface $qst): array { return $this->sendPostRequest($qst, self::QST_CREATE_API); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendQstStatusRequest(int $qstId): array { return $this->sendGetRequest(self::QST_STATUS_API . '/' . $qstId); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendQstPrintRequest(int $qstId): array { return $this->sendGetRequest(self::QST_PRINT_API . '/' . $qstId); } - /** @inheritdoc */ + /** @inheritdoc + * @throws PaymentException + */ public function sendQstListRequest(): array { return $this->sendGetRequest(self::QST_LIST_API); @@ -687,8 +739,7 @@ public function setDebugShowResponseHeaders(bool $debugShowResponseHeaders = tru private function addCurlOptHeaderFunction(array &$curlOptArr, array &$headers): void { $curlOptArr += [ - CURLOPT_HEADERFUNCTION => static function($curl, $header) use (&$headers) - { + CURLOPT_HEADERFUNCTION => static function ($curl, $header) use (&$headers) { if (strlen(trim($header)) > 0) { $headers[] = trim($header); } diff --git a/src/CpanelUser.php b/src/CpanelUser.php new file mode 100644 index 0000000..a1de560 --- /dev/null +++ b/src/CpanelUser.php @@ -0,0 +1,283 @@ + + */ + private array $roles = []; + + /** + * Получить ID пользователя. + * + * @return int|null + */ + public function getId(): ?int + { + return $this->id; + } + + /** + * Установить ID пользователя + * + * @param int|null $id + * @return CpanelUser + */ + public function setId(?int $id): self + { + $this->id = $id; + + return $this; + } + + /** + * Получить имя пользователя. + * + * @return string|null + */ + public function getFirstName(): ?string + { + return $this->firstName; + } + + /** + * Установить имя пользователя. + * + * @param string|null $firstName + * @return CpanelUser + */ + public function setFirstName(?string $firstName): self + { + $this->firstName = $firstName; + + return $this; + } + + /** + * Получить фамилию пользователя. + * + * @return string|null + */ + public function getLastName(): ?string + { + return $this->lastName; + } + + /** + * Установить фамилию пользователя. + * + * @param string|null $lastName + * @return CpanelUser + */ + public function setLastName(?string $lastName): self + { + $this->lastName = $lastName; + + return $this; + } + + /** + * Получить email пользователя. + * + * @return string|null + */ + public function getEmail(): ?string + { + return $this->email; + } + + /** + * Установить email пользователя. + * + * @param string|null $email + * @return CpanelUser + */ + public function setEmail(?string $email): self + { + $this->email = $email; + + return $this; + } + + /** + * Получить пароль пользователя. + * Только для нового пользователя, которому был установлен пароль + * или при смене пароля. + * Поле актуально до сохранения пользователя в БД. + * Для пользователей созданных ранее и полученных из БД, всегда возвращается null. + * + * @return string|null + */ + public function getPassword(): ?string + { + return $this->password; + } + + /** + * Установить пароль пользователя. + * + * @param string|null $password + * @return CpanelUser + */ + public function setPassword(?string $password): self + { + $this->password = $password; + + return $this; + } + + /** + * Получить статус пользователя. + * + * @return string|null + */ + public function getStatus(): ?string + { + return $this->status; + } + + /** + * Включить пользователя. + * + * @return CpanelUser + */ + public function enable(): self + { + $this->status = self::USER_STATUS_ENABLED; + + return $this; + } + + /** + * Выключить пользователя. + * + * @return CpanelUser + */ + public function disable(): self + { + $this->status = self::USER_STATUS_DISABLED; + + return $this; + } + + /** + * Отметить пользователя удаленным. + * + * @return CpanelUser + */ + public function delete(): self + { + $this->status = self::USER_STATUS_DELETED; + + return $this; + } + + /** + * Получить роли пользователя. + * + * @return array + */ + public function getRoles(): array + { + return $this->roles; + } + + /** + * Установить роли пользователя. + * + * @param array $roles + * @return CpanelUser + */ + public function setRoles(array $roles): self + { + $arrayRoles = array_filter($roles, fn($role) => $role instanceof Role); + $this->roles = $arrayRoles; + + return $this; + } + + /** + * @inheritDoc + */ + public function arraySerialize(): array + { + $serializedUser = array_filter( + [ + 'firstName' => $this->firstName, + 'lastName' => $this->lastName, + 'emailUser' => $this->email, + 'userID' => (string) $this->id, + 'status' => $this->status, + 'password' => $this->password, + ] + ); + $serializedRoles = []; + foreach ($this->roles as $role) { + if (empty($roleId = $role->getId()) || empty($merchantCode = $role->getOwner())) { + continue; + } + $serializedRoles[] = ['merchantCode' => $merchantCode, 'roleID' => (string) $roleId]; + } + + $serializedUser['roles'] = $serializedRoles; + + return $serializedUser; + } +} diff --git a/src/Group.php b/src/Group.php new file mode 100644 index 0000000..71af6b0 --- /dev/null +++ b/src/Group.php @@ -0,0 +1,95 @@ + + */ + private array $privileges = []; + + /** + * Возвращает АПИ имя группы. + * + * @return string|null + */ + public function getApiName(): ?string + { + return $this->apiName; + } + + /** + * Устанавливает АПИ имя группы. + * + * @param string|null $groupApiName + * @return Group + */ + public function setApiName(?string $groupApiName): self + { + $this->apiName = $groupApiName; + + return $this; + } + + /** + * Возвращает набор привилегии в группе. + * + * @return array + */ + public function getPrivileges(): array + { + return $this->privileges; + } + + /** + * Устанавливает набор привилегий в группе. + * Имеющиеся привилегии группы перезаписываются. + * + * @param array $privileges + * @return Group + */ + public function setPrivileges(array $privileges): self + { + $arrayPrivileges = array_filter($privileges, fn($privilege) => $privilege instanceof Privilege); + $this->privileges = $arrayPrivileges; + + return $this; + } + + /** + * @inheritDoc + */ + public function arraySerialize(): array + { + + $serializedGroup = []; + + if (!empty($this->apiName)) { + $serializedGroup[$this->apiName] = []; + foreach ($this->privileges as $privilege) { + $serializedGroup[$this->apiName] = + array_merge($serializedGroup[$this->apiName], $privilege->arraySerialize()); + } + } + + return $serializedGroup; + } +} diff --git a/src/Privilege.php b/src/Privilege.php new file mode 100644 index 0000000..76e03b0 --- /dev/null +++ b/src/Privilege.php @@ -0,0 +1,96 @@ +apiName = $privilegeApiName; + $this->isOn = $isOn; + } + + /** + * Возвращает АПИ имя привилегии. + * + * @return string + */ + public function getApiName(): string + { + return $this->apiName; + } + + /** + * Устанавливает АПИ имя привилегии. + * + * @param string $privilegeApiName + * @return Privilege + */ + public function setApiName(string $privilegeApiName): self + { + $this->apiName = $privilegeApiName; + + return $this; + } + + /** + * Возвращает статус привилегии. + * + * @return bool + */ + public function isOn(): bool + { + return $this->isOn; + } + + /** + * Активировать привилегию. + * + * @return Privilege + */ + public function on(): self + { + $this->isOn = true; + + return $this; + } + + /** + * Деактивировать привилегию. + * + * @return Privilege + */ + public function off(): self + { + $this->isOn = false; + + return $this; + } + + /** + * @inheritDoc + */ + public function arraySerialize(): array + { + return [$this->apiName => $this->isOn]; + } +} diff --git a/src/Role.php b/src/Role.php new file mode 100644 index 0000000..e810fa0 --- /dev/null +++ b/src/Role.php @@ -0,0 +1,189 @@ + + */ + private array $groupOfPrivileges = []; + + /** + * Получить системный индентификатор роли. + * NULL для новой роли. + * + * @return int|null + */ + public function getId(): ?int + { + return $this->id; + } + + /** + * Установить системный идентификатор роли. + * + * @param int|null $id + * @return Role + */ + public function setId(?int $id): self + { + $this->id = $id; + + return $this; + } + + /** + * Получить системное имя роли. + * + * @return string|null + */ + public function getName(): ?string + { + return $this->name; + } + + /** + * Установить системное имя роли. + * + * @param string|null $name + * @return Role + */ + public function setName(?string $name): self + { + $this->name = $name; + + return $this; + } + + /** + * Получить описание роли. + * + * @return string|null + */ + public function getDescription(): ?string + { + return $this->description; + } + + /** + * Установить описание роли. + * + * @param string|null $description + * @return Role + */ + public function setDescription(?string $description): self + { + $this->description = $description; + + return $this; + } + + /** + * Получить системный код мерчанта - владельца роли. + * + * @return string|null + */ + public function getOwner(): ?string + { + return $this->owner; + } + + /** + * Установить системный код мерчанта - владельца роли. + * + * @param string|null $owner + * @return Role + */ + public function setOwner(?string $owner): self + { + $this->owner = $owner; + + return $this; + } + + /** + * Получить набор групп привилегий, определённых для роли. + * + * @return array + */ + public function getGroupOfPrivileges(): array + { + return $this->groupOfPrivileges; + } + + /** + * Установить набор групп привилегий, определённых для роли. + * + * @param array $groupOfPrivileges + * @return Role + */ + public function setGroupOfPrivileges(array $groupOfPrivileges): self + { + $arrayGroupsOfPrivileged = array_filter($groupOfPrivileges, fn($group) => $group instanceof Group); + $this->groupOfPrivileges = $arrayGroupsOfPrivileged; + + return $this; + } + + /** + * @inheritDoc + */ + public function arraySerialize(): array + { + $serializedRole = array_filter( + [ + 'roleName' => $this->name, + 'roleDescription' => $this->description, + 'merchant' => $this->owner, + 'roleID' => (string) $this->id, + ] + ); + + $serializedGroups = []; + foreach ($this->groupOfPrivileges as $groupOfPrivilege) { + $serializedGroups = + array_merge($serializedGroups, $groupOfPrivilege->arraySerialize()); + } + + $serializedRole['privilege'] = $serializedGroups; + + return $serializedRole; + } +} From 32c6a6cd407ad33167d5d42970398b8dbb683c6e Mon Sep 17 00:00:00 2001 From: Andrey Chugunov Date: Wed, 27 Nov 2024 10:55:59 +0300 Subject: [PATCH 13/64] YP-1173 Add: Widget. --- src/Examples/getWidget.php | 48 +++++++++++++ src/Widget.php | 135 +++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/Examples/getWidget.php create mode 100644 src/Widget.php diff --git a/src/Examples/getWidget.php b/src/Examples/getWidget.php new file mode 100644 index 0000000..a04415c --- /dev/null +++ b/src/Examples/getWidget.php @@ -0,0 +1,48 @@ +getCode(), "RU", "RUB"); +?> + + + + + + + Виджет YPMN + + +

Пример работы виджета

+ +

Полное описание товарной позиции номер один

+

Товар номер один - makeBuyButton(199.99, "RUB", LABEL, CLASSES); + ?>

+ +

Полное описание товарной позиции номер два

+

Товар номер два - makeBuyButton(299.99, "RUB", LABEL, CLASSES); + ?>

+ +

Полное описание товарной позиции номер три

+

Товар номер три - makeBuyButton(399.99, "RUB", LABEL, CLASSES); + ?>

+ + makeBuyForm(); ?> + + diff --git a/src/Widget.php b/src/Widget.php new file mode 100644 index 0000000..96fca40 --- /dev/null +++ b/src/Widget.php @@ -0,0 +1,135 @@ +merchantCode = $merchantCode; + $this->countryCode = $countryCode; + $this->firstName = $firstName; + $this->lastName = $lastName; + $this->email = $email; + $this->phone = $phone; + $this->returnUrl = $returnUrl; + } + + /** + * Метод возвращает кнопку покупки. + * + * @param float $amounts Сумма к оплате. + * @param string $currency Валюта. + * @param string $label Надпись на кнопке. + * @param string $classes Классы кнопки. + * + * @return string + */ + public function makeBuyButton( + float $amount, + string $currency = "RUB", + string $label = "Купить", + string $classes = "" + ): string { + $classes = trim("buyBtn " . $classes); + $params = "data-amount='{$amount}' data-currency='{$currency}'"; + + return "{$label}"; + } + + /** + * Метод возвращает скрипты для вставки в html. + * + * @return string + */ + public function makeBuyForm(): string + { + return " + + "; + } +} From a4bf55da50b26c4c5716512d0f48b1c8b71710f9 Mon Sep 17 00:00:00 2001 From: Andrey Chugunov Date: Wed, 27 Nov 2024 12:01:33 +0300 Subject: [PATCH 14/64] YP-1173 Fix: library --- src/Widget.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Widget.php b/src/Widget.php index 96fca40..002403e 100644 --- a/src/Widget.php +++ b/src/Widget.php @@ -80,14 +80,14 @@ public function makeBuyButton( */ public function makeBuyForm(): string { - return " - + return " +