Files
yookassa-sdk-php/tests/Client/ClientTest.php
Антон Н. Николаев 2db9951ff6 Валидация payment_order.recipient.bank.name и payment_order.payment_period.year. Выплаты самозанятым теперь deprecated
Информация про чеки самозанятых в платежах и возвратах удалена - больше не поддерживаем сервисы для самозанятых
Добавлена возможность выставления счета по смс и email
Добавлена поддержка работы со списками выплат
Обновлен Copyright
2026-02-05 15:36:37 +03:00

3232 lines
107 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/*
* The MIT License
*
* Copyright (c) 2026 "YooMoney", NBСO LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace Tests\YooKassa\Client;
use DateTime;
use Exception;
use Faker\Provider\Internet;
use InvalidArgumentException;
use JsonException;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use ReflectionException;
use ReflectionMethod;
use stdClass;
use TypeError;
use YooKassa\Client;
use YooKassa\Client\ApiClientInterface;
use YooKassa\Client\CurlClient;
use YooKassa\Common\Exceptions\ApiConnectionException;
use YooKassa\Common\Exceptions\ApiException;
use YooKassa\Common\Exceptions\AuthorizeException;
use YooKassa\Common\Exceptions\BadApiRequestException;
use YooKassa\Common\Exceptions\ExtensionNotFoundException;
use YooKassa\Common\Exceptions\ForbiddenException;
use YooKassa\Common\Exceptions\GoneException;
use YooKassa\Common\Exceptions\InternalServerError;
use YooKassa\Common\Exceptions\NotFoundException;
use YooKassa\Common\Exceptions\ResponseProcessingException;
use YooKassa\Common\Exceptions\TooManyRequestsException;
use YooKassa\Common\Exceptions\UnauthorizedException;
use YooKassa\Common\LoggerWrapper;
use YooKassa\Helpers\Random;
use YooKassa\Helpers\StringObject;
use YooKassa\Model\Deal\DealType;
use YooKassa\Model\Deal\FeeMoment;
use YooKassa\Model\Invoice\LineItem;
use YooKassa\Model\MonetaryAmount;
use YooKassa\Model\Payment\PaymentMethodType;
use YooKassa\Model\PersonalData\PersonalDataType;
use YooKassa\Model\Receipt\ReceiptCustomer;
use YooKassa\Model\Receipt\ReceiptItem;
use YooKassa\Model\Receipt\ReceiptType;
use YooKassa\Model\Receipt\Settlement;
use YooKassa\Model\SavePaymentMethod\Confirmation\ConfirmationType;
use YooKassa\Model\SavePaymentMethod\SavePaymentMethodType;
use YooKassa\Request\Deals\CreateDealRequest;
use YooKassa\Request\Deals\CreateDealResponse;
use YooKassa\Request\Deals\DealResponse;
use YooKassa\Request\Deals\DealsRequest;
use YooKassa\Request\Deals\DealsResponse;
use YooKassa\Request\Invoices\CreateInvoiceRequest;
use YooKassa\Request\Invoices\InvoiceResponse;
use YooKassa\Request\Invoices\PaymentData;
use YooKassa\Request\PaymentMethods\ConfirmationData\ConfirmationRedirect;
use YooKassa\Request\PaymentMethods\CreatePaymentMethodRequest;
use YooKassa\Request\PaymentMethods\PaymentMethodCard;
use YooKassa\Request\PaymentMethods\PaymentMethodHolder;
use YooKassa\Request\PaymentMethods\PaymentMethodResponse;
use YooKassa\Request\Payments\CancelResponse;
use YooKassa\Request\Payments\CreateCaptureRequest;
use YooKassa\Request\Payments\CreateCaptureResponse;
use YooKassa\Request\Payments\CreatePaymentRequest;
use YooKassa\Request\Payments\CreatePaymentResponse;
use YooKassa\Request\Payments\PaymentResponse;
use YooKassa\Request\Payments\PaymentsRequest;
use YooKassa\Request\Payments\PaymentsResponse;
use YooKassa\Request\Payouts\CreatePayoutRequest;
use YooKassa\Request\Payouts\CreatePayoutResponse;
use YooKassa\Request\Payouts\PayoutResponse;
use YooKassa\Request\Payouts\PayoutsRequest;
use YooKassa\Request\Payouts\PayoutsResponse;
use YooKassa\Request\Payouts\SbpBanksResponse;
use YooKassa\Request\PersonalData\PersonalDataResponse;
use YooKassa\Request\PersonalData\PersonalDataType\PayoutStatementRecipientPersonalDataRequest;
use YooKassa\Request\PersonalData\PersonalDataType\SbpPayoutRecipientPersonalDataRequest;
use YooKassa\Request\Receipts\AbstractReceiptResponse;
use YooKassa\Request\Receipts\CreatePostReceiptRequest;
use YooKassa\Request\Refunds\CreateRefundRequest;
use YooKassa\Request\Refunds\CreateRefundResponse;
use YooKassa\Request\Refunds\RefundResponse;
use YooKassa\Request\Refunds\RefundsRequest;
use YooKassa\Request\Refunds\RefundsResponse;
use YooKassa\Request\SelfEmployed\SelfEmployedRequest;
use YooKassa\Request\SelfEmployed\SelfEmployedResponse;
/**
* @internal
*/
class ClientTest extends TestCase
{
public function testCreatePayment(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setRecipient(['gateway_id' => 123, 'account_id' => 321])
->setAirline([])
->setDeal(null)
->setFraudData(null)
->setReceipt([])
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPaymentFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreatePaymentResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPaymentFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment([
'amount' => [
'value' => 123,
'currency' => 'USD',
],
'payment_token' => Random::str(36),
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreatePaymentResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws Exception
*/
public function testInvalidCreatePayment($httpCode, $errorResponse, $requiredException): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setRecipient(['gateway_id' => 123, 'account_id' => 321])
->setAirline([])
->setDeal(null)
->setFraudData(null)
->setReceipt([])
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Authorization' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->createPayment($payment, 123);
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider paymentsListDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testPaymentsList(mixed $request): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Authorization' => 'HeaderValue'],
$this->getFixtures('getPaymentsFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPayments($request)
;
$this->assertInstanceOf(PaymentsResponse::class, $response);
}
public static function paymentsListDataProvider(): array
{
return [
[null],
[PaymentsRequest::builder()->build()],
[[
'account_id' => 12,
]],
];
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*/
public function testInvalidPaymentsList($httpCode, $errorResponse, $requiredException): void
{
$payments = PaymentsRequest::builder()->build();
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->getPayments($payments);
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider paymentInfoDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testGetPaymentInfo(mixed $paymentId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('paymentInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo($paymentId)
;
self::assertInstanceOf(PaymentResponse::class, $response);
}
public static function paymentInfoDataProvider(): array
{
return [
[Random::str(36)],
[new StringObject(Random::str(36))],
[true, InvalidArgumentException::class],
[false, InvalidArgumentException::class],
[0, InvalidArgumentException::class],
[1, InvalidArgumentException::class],
[0.1, InvalidArgumentException::class],
[Random::str(35), InvalidArgumentException::class],
[Random::str(37), InvalidArgumentException::class],
];
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws Exception
*/
public function testInvalidGetPaymentInfo($httpCode, $errorResponse, $requiredException): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->getPaymentInfo(Random::str(36));
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
public function testCapturePayment(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('capturePaymentFixtures.json'),
['http_code' => 200],
])
;
$capturePaymentRequest = [
'amount' => [
'value' => 123,
'currency' => 'EUR',
],
];
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->capturePayment($capturePaymentRequest, '1ddd77af-0bd7-500d-895b-c475c55fdefc', 123)
;
$this->assertInstanceOf(CreateCaptureResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('capturePaymentFixtures.json'),
['http_code' => 200],
])
;
$capturePaymentRequest = CreateCaptureRequest::builder()->setAmount(10)->build();
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->capturePayment($capturePaymentRequest, '1ddd77af-0bd7-500d-895b-c475c55fdefc')
;
$this->assertInstanceOf(CreateCaptureResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":123}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->capturePayment($capturePaymentRequest, '1ddd77af-0bd7-500d-895b-c475c55fdefc', 123)
;
self::fail('Exception not thrown');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
}
try {
$apiClient->capturePayment($capturePaymentRequest, Random::str(37, 50), 123);
} catch (InvalidArgumentException $e) {
// it's ok
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws Exception
*/
public function testInvalidCapturePayment($httpCode, $errorResponse, $requiredException): void
{
$capturePaymentRequest = CreateCaptureRequest::builder()
->setAmount(10)
->setDeal(null)
->build();
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->capturePayment($capturePaymentRequest, '1ddd77af-0bd7-500d-895b-c475c55fdefc', 123);
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider paymentInfoDataProvider
*
* @throws ApiException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testPaymentIdCapturePayment(mixed $paymentId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null === $exceptionClassName ? self::once() : self::never())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('capturePaymentFixtures.json'),
['http_code' => 200],
])
;
$capturePaymentRequest = [
'amount' => [
'value' => 123,
'currency' => 'EUR',
],
];
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->capturePayment($capturePaymentRequest, $paymentId, 123)
;
self::assertInstanceOf(CreateCaptureResponse::class, $response);
}
/**
* @dataProvider paymentInfoDataProvider
*
* @throws ApiException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testCancelPayment(mixed $paymentId, ?string $exceptionClassName = null): void
{
$invalid = null !== $exceptionClassName;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($invalid ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('cancelPaymentFixtures.json'),
['http_code' => 200],
])
;
if ($invalid) {
$this->expectException($exceptionClassName);
}
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->cancelPayment($paymentId, 123)
;
$this->assertInstanceOf(CancelResponse::class, $response);
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws ExtensionNotFoundException
*/
public function testInvalidCancelPayment($httpCode, $errorResponse, $requiredException): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->cancelPayment(Random::str(36));
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider refundsDataProvider
*
* @param mixed $refundsRequest
*
* @throws ApiException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testGetRefunds($refundsRequest): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('refundsInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getRefunds($refundsRequest)
;
$this->assertInstanceOf(RefundsResponse::class, $response);
}
public static function refundsDataProvider(): array
{
return [
[null],
[RefundsRequest::builder()->build()],
[[
'account_id' => 123,
]],
];
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws ExtensionNotFoundException
*/
public function testInvalidGetRefunds($httpCode, $errorResponse, $requiredException): void
{
$refundsRequest = RefundsRequest::builder()->build();
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->getRefunds($refundsRequest);
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
public function testCreateRefund(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createRefundFixtures.json'),
['http_code' => 200],
])
;
$refundRequest = CreateRefundRequest::builder()->setPaymentId('1ddd77af-0bd7-500d-895b-c475c55fdefc')->setAmount(123)->build();
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createRefund($refundRequest, 123)
;
$this->assertInstanceOf(CreateRefundResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createRefundFixtures.json'),
['http_code' => 200],
])
;
$refundRequest = [
'payment_id' => '1ddd77af-0bd7-500d-895b-c475c55fdefc',
'amount' => [
'value' => 321,
'currency' => 'RUB',
],
];
$apiClient = new Client();
$response = $apiClient
->setMaxRequestAttempts(2)
->setRetryTimeout(1000)
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createRefund($refundRequest)
;
$this->assertInstanceOf(CreateRefundResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createRefund($refundRequest, 123)
;
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws Exception
*/
public function testInvalidCreateRefund($httpCode, $errorResponse, $requiredException): void
{
$refundRequest = CreateRefundRequest::builder()->setPaymentId('1ddd77af-0bd7-500d-895b-c475c55fdefc')->setAmount(123)->build();
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->createRefund($refundRequest, 123);
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider paymentInfoDataProvider
*
* @throws ApiException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ExtensionNotFoundException
*/
public function testRefundInfo(mixed $refundId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null === $exceptionClassName ? self::once() : self::never())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('refundInfoFixtures.json'),
['http_code' => 200],
])
;
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getRefundInfo($refundId)
;
$this->assertInstanceOf(RefundResponse::class, $response);
try {
$apiClient->getRefundInfo(Random::str(50, 100));
} catch (InvalidArgumentException $e) {
// it's ok
return;
}
self::fail('Exception not thrown');
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
*
* @throws Exception
*/
public function testInvalidRefundInfo($httpCode, $errorResponse, $requiredException): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->getRefundInfo(Random::str(36));
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
public function testApiException(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'unknown response here',
['http_code' => 444],
])
;
$this->expectException(ApiException::class);
$apiClient = new Client();
$apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
}
public function testBadRequestException(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"description": "error_msg", "code": "invalid_request", "parameter": "parameter_name"}',
['http_code' => 400],
])
;
$this->expectException(BadApiRequestException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
}
public function testTechnicalErrorException(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"description": "error_msg", "code": "internal_server_error"}',
['http_code' => 500],
])
;
$this->expectException(InternalServerError::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
}
public function testUnauthorizedException(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"description": "error_msg"}',
['http_code' => 401],
])
;
$this->expectException(UnauthorizedException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
}
public function testForbiddenException(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type": "error", "description": "error_msg", "code": "forbidden", "parameter": "parameter_name", "operation_name": "operation_name"}',
['http_code' => 403],
])
;
$this->expectException(ForbiddenException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment, 123)
;
}
public function testNotFoundException(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type": "error", "description": "error_msg", "code": "not_found", "parameter": "parameter_name", "operation": "operation_name"}',
['http_code' => 404],
])
;
$this->expectException(NotFoundException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo(Random::str(36))
;
}
public function testGoneException(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type": "error", "description": "error_msg", "code": "gone", "parameter": "parameter_name", "operation": "operation_name"}',
['http_code' => 410],
])
;
$this->expectException(GoneException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo(Random::str(36))
;
}
public function testToManyRequestsException(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type": "error", "description": "error_msg", "code": "too_many_requests", "parameter": "parameter_name", "operation": "operation_name"}',
['http_code' => 429],
])
;
$this->expectException(TooManyRequestsException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo(Random::str(36))
;
}
public function testAnotherExceptions(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{}',
['http_code' => 322],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo(Random::str(36))
;
self::assertNull($response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{}',
['http_code' => 402],
])
;
$apiClient = new Client();
$this->expectException(ApiException::class);
$apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo(Random::str(36))
;
}
public function testConfig(): void
{
$apiClient = new Client();
$apiClient->setConfig([
'url' => 'test',
]);
$this->assertEquals(['url' => 'test'], $apiClient->getConfig());
}
public function testSetLogger(): void
{
$wrapped = new ArrayLogger();
$logger = new LoggerWrapper($wrapped);
$apiClient = new Client();
$apiClient->setLogger($logger);
$clientMock = $this->getMockBuilder(ApiClientInterface::class)
->onlyMethods(['setLogger', 'setConfig', 'call', 'setShopId', 'getUserAgent', 'setBearerToken', 'setShopPassword', 'setAdvancedCurlOptions'])
->disableOriginalConstructor()
->getMock()
;
$expectedLoggers = [];
$clientMock->expects(self::exactly(3))->method('setLogger')->willReturnCallback(function ($logger) use (&$expectedLoggers): void {
$expectedLoggers[] = $logger;
});
$clientMock->expects(self::once())->method('setConfig')->willReturn($clientMock);
$apiClient->setApiClient($clientMock);
self::assertSame($expectedLoggers[0], $logger);
$apiClient->setLogger($wrapped);
$apiClient->setLogger(function ($level, $log, $context = []) use ($wrapped): void {
$wrapped->log($level, $log, $context);
});
}
public function testDecodeInvalidData(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(self::any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"invalid":"json"',
['http_code' => 200],
])
;
$this->expectException(JsonException::class);
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentInfo(Random::str(36))
;
}
public function testEncodeMultibyteData(): void
{
$instance = new TestClient();
$value = ['hello' => 'Привет', 'olleh' => 'سلام'];
$result = $instance->encode($value);
self::assertTrue(str_contains($result, 'Привет'));
self::assertTrue(str_contains($result, 'سلام'));
}
/**
* @dataProvider invalidJsonDataProvider
* @param mixed $value
* @return void
* @throws ReflectionException
*/
public function testEncodeInvalidData(mixed $value): void
{
$instance = new TestClient();
$this->expectException(JsonException::class);
$instance->encode($value);
}
public function invalidJsonDataProvider(): array
{
$recursion = ['test' => 'test', 'val' => null];
$recursion['val'] = &$recursion;
return [
[
$recursion
],
[
['test' => iconv('utf-8', 'windows-1251', 'абвгдеёжз')]
],
];
}
public function testCreatePaymentErrors(): void
{
$payment = CreatePaymentRequest::builder()
->setAmount(123)
->setPaymentToken(Random::str(36))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPaymentErrorsGeneralFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayment($payment)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreatePaymentResponse::class, $response);
self::assertEquals('canceled', $response->getStatus());
self::assertEquals('general_decline', $response->getCancellationDetails()->getReason());
}
/**
* @throws ApiException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ApiConnectionException
* @throws AuthorizeException
* @throws ExtensionNotFoundException
*/
public function testCreateReceipt(): void
{
// Create Receipt via object
$receipt = $this->createReceiptViaObject();
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createReceiptFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createReceipt($receipt)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(AbstractReceiptResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createReceiptFixtures.json'),
['http_code' => 200],
])
;
// Create Receipt via array
$receipt = $this->createReceiptViaArray();
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createReceipt($receipt, 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(AbstractReceiptResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createReceipt($receipt, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createReceipt($receipt, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
public function testCreateDeal(): void
{
$deal = CreateDealRequest::builder()
->setType(DealType::SAFE_DEAL)
->setFeeMoment(FeeMoment::PAYMENT_SUCCEEDED)
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createDealFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createDeal($deal)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreateDealResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createDealFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createDeal([
'type' => 'safe_deal',
'fee_moment' => 'payment_succeeded',
'description' => Random::str(36),
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreateDealResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createDeal($deal, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createDeal($deal, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
/**
* @dataProvider dealInfoDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ExtensionNotFoundException
*/
public function testGetDealInfo(mixed $dealId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('dealInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getDealInfo($dealId)
;
self::assertInstanceOf(DealResponse::class, $response);
}
public static function dealInfoDataProvider(): array
{
return [
[Random::str(36)],
[new StringObject(Random::str(36))],
[true, InvalidArgumentException::class],
[false, InvalidArgumentException::class],
[0, InvalidArgumentException::class],
[1, InvalidArgumentException::class],
[0.1, InvalidArgumentException::class],
[Random::str(35), InvalidArgumentException::class],
[Random::str(51), InvalidArgumentException::class],
];
}
/**
* @dataProvider dealsDataProvider
*
* @param mixed $dealsRequest
*
* @throws ApiException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testGetDeals($dealsRequest): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('dealsInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getDeals($dealsRequest)
;
$this->assertInstanceOf(DealsResponse::class, $response);
}
public static function dealsDataProvider(): array
{
return [
[null],
[DealsRequest::builder()->build()],
[[
'status' => 'closed',
]],
];
}
public function testCreatePayout(): void
{
$payout = CreatePayoutRequest::builder()
->setAmount(['value' => '320', 'currency' => 'RUB'])
->setPayoutDestinationData([
'type' => PaymentMethodType::YOO_MONEY,
'account_number' => '41001614575714',
])
->setDescription('Выплата по заказу №37')
->setMetadata(['order_id' => '37'])
->setDeal(['id' => 'dl-285e5ee7-0022-5000-8000-01516a44b147'])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPayoutFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayout($payout)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreatePayoutResponse::class, $response);
$payout = CreatePayoutRequest::builder()
->setAmount(['value' => '320', 'currency' => 'RUB'])
->setPayoutToken('<Синоним банковской карты>')
->setDescription('Выплата по заказу №37')
->setMetadata(['order_id' => '37'])
->setDeal(['id' => 'dl-285e5ee7-0022-5000-8000-01516a44b147'])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPayoutFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayout($payout)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreatePayoutResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPayoutFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayout([
'amount' => ['value' => '320', 'currency' => 'RUB'],
'description' => 'Выплата по заказу №37',
'payout_token' => '<Синоним банковской карты>',
'deal' => ['id' => 'dl-285e5ee7-0022-5000-8000-01516a44b147'],
'metadata' => ['order_id' => '37'],
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(CreatePayoutResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayout($payout, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayout($payout, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPayout([
'amount' => ['value' => '320', 'currency' => 'RUB'],
'description' => 'Выплата по заказу №37',
'payout_token' => '<Синоним банковской карты>',
'payout_destination_data' => ['type' => 'bank_card', 'card' => ['number' => '1234567890123456']],
'deal' => ['id' => 'dl-285e5ee7-0022-5000-8000-01516a44b147'],
'metadata' => ['order_id' => '37'],
], 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
/**
* @dataProvider payoutInfoDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ExtensionNotFoundException
*/
public function testGetPayoutInfo(mixed $payoutId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('payoutInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPayoutInfo($payoutId)
;
self::assertInstanceOf(PayoutResponse::class, $response);
}
public static function payoutInfoDataProvider(): array
{
return [
[Random::str(36)],
[new StringObject(Random::str(36))],
[true, InvalidArgumentException::class],
[false, InvalidArgumentException::class],
[0, InvalidArgumentException::class],
[1, InvalidArgumentException::class],
[0.1, InvalidArgumentException::class],
[Random::str(35), InvalidArgumentException::class],
[Random::str(51), InvalidArgumentException::class],
];
}
/**
* @dataProvider payoutsListDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ExtensionNotFoundException
*/
public function testPayoutsList(mixed $request): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Authorization' => 'HeaderValue'],
$this->getFixtures('getPayoutsFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPayouts($request)
;
$this->assertInstanceOf(PayoutsResponse::class, $response);
}
public static function payoutsListDataProvider(): array
{
return [
[null],
[PayoutsRequest::builder()->build()],
[[
'status' => 'canceled',
]],
];
}
/**
* @dataProvider errorResponseDataProvider
*
* @param mixed $httpCode
* @param mixed $errorResponse
* @param mixed $requiredException
* @throws ExtensionNotFoundException
*/
public function testInvalidPayoutsList(mixed $httpCode, mixed $errorResponse, mixed $requiredException): void
{
$payouts = PayoutsRequest::builder()->build();
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$errorResponse,
['http_code' => $httpCode],
])
;
$apiClient = new Client();
$apiClient->setApiClient($curlClientStub)->setAuth('123456', 'shopPassword');
try {
$apiClient->getPayouts($payouts);
} catch (ApiException $e) {
self::assertInstanceOf($requiredException, $e);
return;
}
self::fail('Exception not thrown');
}
public function testCreatePersonalData(): void
{
$personalData = SbpPayoutRecipientPersonalDataRequest::builder()
->setLastName('Иванов')
->setFirstName('Иван')
->setMiddleName('Иванович')
->setMetadata(['recipient_id' => '37'])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPersonalDataFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPersonalData($personalData)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(PersonalDataResponse::class, $response);
$personalData = PayoutStatementRecipientPersonalDataRequest::builder()
->setLastName('Иванов')
->setFirstName('Иван')
->setMiddleName('Иванович')
->setBirthdate('2000-01-02')
->setMetadata(['recipient_id' => '37'])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPersonalDataFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPersonalData($personalData)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(PersonalDataResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPersonalDataFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPersonalData([
'type' => PersonalDataType::PAYOUT_STATEMENT_RECIPIENT,
'last_name' => 'Иванов',
'first_name' => 'Иван',
'middle_name' => 'Иванович',
'birthdate' => '2000-01-02',
'metadata' => ['recipient_id' => '37'],
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(PersonalDataResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPersonalData($personalData, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPersonalData($personalData, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPersonalData([
'type' => 'sbp_payout_recipient',
'last_name' => 'Иванов',
'first_name' => 'Иван',
'middle_name' => 'Иванович',
'metadata' => ['recipient_id' => '37'],
], 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
/**
* @dataProvider personalDataInfoDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ExtensionNotFoundException
*/
public function testGetPersonalDataInfo(mixed $personalDataId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('personalDataInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPersonalDataInfo($personalDataId)
;
self::assertInstanceOf(PersonalDataResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPersonalDataInfo($personalDataId)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
public static function personalDataInfoDataProvider(): array
{
return [
[Random::str(36)],
[new StringObject(Random::str(36))],
[true, InvalidArgumentException::class],
[false, InvalidArgumentException::class],
[0, InvalidArgumentException::class],
[1, InvalidArgumentException::class],
[0.1, InvalidArgumentException::class],
[Random::str(35), InvalidArgumentException::class],
[Random::str(51), InvalidArgumentException::class],
];
}
/**
* @dataProvider paymentsListDataProvider
*
* @throws ApiException
* @throws ResponseProcessingException
* @throws BadApiRequestException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws TooManyRequestsException
* @throws UnauthorizedException
* @throws ExtensionNotFoundException
*/
public function testSbpBanksList(): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('getSbpBanksFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getSbpBanks()
;
$this->assertInstanceOf(SbpBanksResponse::class, $response);
}
public function testCreateSelfEmployed(): void
{
$selfEmployed = SelfEmployedRequest::builder()
->setItn('123456789012')
->setPhone('79001002030')
->setConfirmation(['type' => 'redirect'])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createSelfEmployedFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createSelfEmployed($selfEmployed)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(SelfEmployedResponse::class, $response);
$selfEmployed = SelfEmployedRequest::builder()
->setItn('123456789012')
->setPhone('79001002030')
->setConfirmation(['type' => 'redirect'])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createSelfEmployedFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createSelfEmployed($selfEmployed)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(SelfEmployedResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createSelfEmployedFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createSelfEmployed([
'itn' => '123456789012',
'phone' => '79001002030',
'confirmation' => ['type' => 'redirect'],
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(SelfEmployedResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createSelfEmployed($selfEmployed, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createSelfEmployed($selfEmployed, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createSelfEmployed([
'itn' => '123456789012',
'phone' => '79001002030',
'confirmation' => ['type' => 'redirect'],
], 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
/**
* @dataProvider selfEmployedInfoDataProvider
*
* @param mixed $selfEmployedId
*
* @throws ApiException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testGetSelfEmployedInfo($selfEmployedId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('selfEmployedInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getSelfEmployedInfo($selfEmployedId)
;
self::assertInstanceOf(SelfEmployedResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getSelfEmployedInfo($selfEmployedId)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
public static function selfEmployedInfoDataProvider(): array
{
return [
[Random::str(36)],
[new StringObject(Random::str(36))],
[true, InvalidArgumentException::class],
[false, InvalidArgumentException::class],
[0, InvalidArgumentException::class],
[1, InvalidArgumentException::class],
[0.1, InvalidArgumentException::class],
[Random::str(35), InvalidArgumentException::class],
[Random::str(51), InvalidArgumentException::class],
];
}
public function testCreateInvoice(): void
{
$invoice = CreateInvoiceRequest::builder()
->setPaymentData([
'amount' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'save_payment_method' => true,
'description' => Random::str(5, 128),
'client_ip' => Internet::localIpv4(),
])
->setCart([
[
'description' => Random::str(5, 128),
'price' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'discount_price' => null,
'quantity' => Random::int(1, 10),
]
])
->setExpiresAt(new DateTime('+ 1 month'))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createInvoiceFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createInvoice($invoice)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(InvoiceResponse::class, $response);
$invoice = CreateInvoiceRequest::builder()
->setPaymentData([
'amount' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'save_payment_method' => true,
'description' => Random::str(5, 128),
'client_ip' => Internet::localIpv4(),
])
->setCart([
[
'description' => Random::str(5, 128),
'price' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'discount_price' => null,
'quantity' => Random::int(1, 10),
]
])
->setExpiresAt(new DateTime('+ 1 month'))
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createInvoiceFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createInvoice($invoice)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(InvoiceResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createInvoiceFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createInvoice([
'payment_data' => new PaymentData([
'amount' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'save_payment_method' => true,
'description' => Random::str(5, 128),
'client_ip' => Internet::localIpv4(),
]),
'cart' => [
new LineItem([
'description' => Random::str(5, 128),
'price' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'discount_price' => null,
'quantity' => Random::int(1, 10),
]),
],
'delivery_method_data' => ['type' => 'self'],
'expires_at' => new DateTime('+ 1 month'),
'locale' => Random::value(['ru_RU', 'en_US', null]),
'description' => Random::str(5, 128),
'metadata' => ['test' => 'test'],
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(InvoiceResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createInvoice($invoice, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createInvoice($invoice, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted"}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createInvoice([
'payment_data' => new PaymentData([
'amount' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'save_payment_method' => true,
'description' => Random::str(5, 128),
'client_ip' => Internet::localIpv4(),
]),
'cart' => [
new LineItem([
'description' => Random::str(5, 128),
'price' => new MonetaryAmount(Random::int(1, 1000000), 'RUB'),
'discount_price' => null,
'quantity' => Random::int(1, 10),
]),
],
'delivery_method_data' => ['type' => 'self'],
'expires_at' => new DateTime('+ 1 month'),
'locale' => Random::value(['ru_RU', 'en_US', null]),
'description' => Random::str(5, 128),
'metadata' => ['test' => 'test'],
], 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
/**
* @dataProvider invoiceInfoDataProvider
*
* @param mixed $invoiceId
* @param string|null $exceptionClassName
*
* @throws ApiConnectionException
* @throws ApiException
* @throws AuthorizeException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws JsonException
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testGetInvoiceInfo(mixed $invoiceId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('invoiceInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getInvoiceInfo($invoiceId)
;
self::assertInstanceOf(InvoiceResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getInvoiceInfo($invoiceId)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
return;
}
}
public static function invoiceInfoDataProvider(): array
{
return [
[Random::str(39)],
[new StringObject(Random::str(39))],
[true, InvalidArgumentException::class],
[false, InvalidArgumentException::class],
[0, InvalidArgumentException::class],
[1, InvalidArgumentException::class],
[0.1, InvalidArgumentException::class],
[Random::str(38), InvalidArgumentException::class],
[Random::str(41), InvalidArgumentException::class],
];
}
public function testCreatePaymentMethod()
{
$paymentMethod = CreatePaymentMethodRequest::builder()
->setType(SavePaymentMethodType::BANK_CARD)
->setCard([
'number' => Random::str(16, 19, '0123456789'),
'expiry_year' => (string) Random::int(2023, 2045),
'expiry_month' => str_pad((string) Random::int(1, 12), 2, '0', STR_PAD_LEFT),
'cardholder' => Random::str(1, 26, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ \'-'),
'csc' => Random::str(3, 4, '0123456789'),
])
->setHolder(['gateway_id' => Random::str(1, 256),])
->setClientIp(Internet::localIpv4())
->setConfirmation([
'type' => ConfirmationType::REDIRECT,
'enforce' => Random::bool(),
'return_url' => Random::str(1,2048),
'locale' => Random::value(['ru_RU', 'en_US']),
])
->build()
;
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createPaymentMethodFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPaymentMethod($paymentMethod)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(PaymentMethodResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('createInvoiceFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPaymentMethod([
'type' => SavePaymentMethodType::BANK_CARD,
'card' => new PaymentMethodCard([
'number' => Random::str(16, 19, '0123456789'),
'expiry_year' => (string) Random::int(2023, 2045),
'expiry_month' => str_pad((string) Random::int(1, 12), 2, '0', STR_PAD_LEFT),
'cardholder' => Random::str(1, 26, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ \'-'),
'csc' => Random::str(3, 4, '0123456789'),
]),
'holder' => new PaymentMethodHolder([
'gateway_id' => Random::str(1, 256),
]),
'client_ip' => Internet::localIpv4(),
'confirmation' => new ConfirmationRedirect([
'type' => ConfirmationType::REDIRECT,
'enforce' => Random::bool(),
'return_url' => Random::str(1,2048),
'locale' => Random::value(['ru_RU', 'en_US']),
]),
], 123)
;
self::assertSame($curlClientStub, $apiClient->getApiClient());
self::assertInstanceOf(PaymentMethodResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPaymentMethod($paymentMethod, 123)
;
self::fail('Исключение не было выброшено');
} catch (ApiException $e) {
self::assertInstanceOf(ResponseProcessingException::class, $e);
}
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->createPaymentMethod($paymentMethod, 123)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
}
}
/**
* @dataProvider paymentMethodInfoDataProvider
*
* @param mixed $paymentMethodId
* @param string|null $exceptionClassName
*
* @throws ApiConnectionException
* @throws ApiException
* @throws AuthorizeException
* @throws BadApiRequestException
* @throws ExtensionNotFoundException
* @throws ForbiddenException
* @throws InternalServerError
* @throws JsonException
* @throws NotFoundException
* @throws ResponseProcessingException
* @throws TooManyRequestsException
* @throws UnauthorizedException
*/
public function testGetPaymentMethodInfo(mixed $paymentMethodId, ?string $exceptionClassName = null): void
{
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects(null !== $exceptionClassName ? self::never() : self::once())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
$this->getFixtures('paymentMethodInfoFixtures.json'),
['http_code' => 200],
])
;
$apiClient = new Client();
if (null !== $exceptionClassName) {
$this->expectException($exceptionClassName);
}
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentMethodInfo($paymentMethodId)
;
self::assertInstanceOf(PaymentMethodResponse::class, $response);
$curlClientStub = $this->getCurlClientStub();
$curlClientStub
->expects($this->any())
->method('sendRequest')
->willReturn([
['Header-Name' => 'HeaderValue'],
'{"type":"error","code":"request_accepted","retry_after":1800}',
['http_code' => 202],
])
;
try {
$apiClient->setRetryTimeout(0);
$response = $apiClient
->setApiClient($curlClientStub)
->setAuth('123456', 'shopPassword')
->getPaymentMethodInfo($paymentMethodId)
;
self::fail('Исключение не было выброшено');
} catch (ResponseProcessingException $e) {
self::assertEquals(Client::DEFAULT_DELAY, $e->retryAfter);
self::assertEquals(Client::DEFAULT_DELAY, $e->getError()->getRetryAfter());
}
}
public static function paymentMethodInfoDataProvider(): array
{
return [
[Random::str(39)],
[new StringObject(Random::str(39))],
[[], TypeError::class],
[new stdClass(), TypeError::class],
];
}
public function getCurlClientStub(): MockObject
{
return $this->getMockBuilder(CurlClient::class)
->onlyMethods(['sendRequest'])
->getMock()
;
}
public static function errorResponseDataProvider(): array
{
return [
[NotFoundException::HTTP_CODE, '{}', NotFoundException::class],
[GoneException::HTTP_CODE, '{}', GoneException::class],
[BadApiRequestException::HTTP_CODE, '{}', BadApiRequestException::class],
[ForbiddenException::HTTP_CODE, '{}', ForbiddenException::class],
[UnauthorizedException::HTTP_CODE, '{}', UnauthorizedException::class],
[TooManyRequestsException::HTTP_CODE, '{}', TooManyRequestsException::class],
];
}
private function createReceiptViaArray(): array
{
return [
'customer' => [
'full_name' => 'Иванов Иван Иванович',
'inn' => '6321341814',
'email' => 'johndoe@yoomoney.ru',
'phone' => '79000000000',
],
'items' => [
[
'description' => 'string',
'quantity' => 1,
'amount' => [
'value' => '10.00',
'currency' => 'RUB',
],
'vat_code' => 1,
'payment_subject' => 'commodity',
'payment_mode' => 'full_prepayment',
'product_code' => '00 00 00 01 00 21 FA 41 00 23 05 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 00 AB 00',
'country_of_origin_code' => 'RU',
'customs_declaration_number' => '10714040/140917/0090376',
'excise' => '20.00',
'planned_status'=> 6
],
],
'tax_system_code' => 1,
'type' => 'payment',
'send' => true,
'settlements' => [
[
'type' => 'cashless',
'amount' => [
'value' => '10.00',
'currency' => 'RUB',
],
],
],
'payment_id' => '1da5c87d-0984-50e8-a7f3-8de646dd9ec9',
];
}
private function createReceiptViaObject(): CreatePostReceiptRequest
{
$customer = new ReceiptCustomer([
'full_name' => 'Иванов Иван Иванович',
'inn' => '6321341814',
'email' => 'johndoe@yoomoney.ru',
'phone' => '79000000000',
]);
$settlement = new Settlement([
'type' => 'cashless',
'amount' => [
'value' => '10.00',
'currency' => 'RUB',
],
]);
$receiptItem = new ReceiptItem([
'description' => 'string',
'quantity' => 1,
'amount' => [
'value' => '10.00',
'currency' => 'RUB',
],
'vat_code' => 1,
'payment_subject' => 'commodity',
'planned_status' => 6,
'payment_mode' => 'full_prepayment',
'product_code' => '00 00 00 01 00 21 FA 41 00 23 05 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 00 AB 00',
'country_of_origin_code' => 'RU',
'customs_declaration_number' => '10714040/140917/0090376',
'excise' => '20.00',
]);
return CreatePostReceiptRequest::builder()
->setCustomer($customer)
->setType(ReceiptType::PAYMENT)
->setObjectId('1da5c87d-0984-50e8-a7f3-8de646dd9ec9', ReceiptType::PAYMENT)
->setSend(true)
->setSettlements([$settlement])
->setOnBehalfOf('545665')
->setItems([$receiptItem])
->build()
;
}
private function getFixtures($fileName): bool|string
{
return file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . $fileName);
}
}
class ArrayLogger implements LoggerInterface
{
private array $lastLog;
public function log($level, $message, array $context = []): void
{
$this->lastLog = [$level, $message, $context];
}
public function getLastLog(): array
{
return $this->lastLog;
}
public function emergency($message, array $context = []): void
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}
public function alert($message, array $context = []): void
{
$this->log(LogLevel::ALERT, $message, $context);
}
public function critical($message, array $context = []): void
{
$this->log(LogLevel::CRITICAL, $message, $context);
}
public function error($message, array $context = []): void
{
$this->log(LogLevel::ERROR, $message, $context);
}
public function warning($message, array $context = []): void
{
$this->log(LogLevel::WARNING, $message, $context);
}
public function notice($message, array $context = []): void
{
$this->log(LogLevel::NOTICE, $message, $context);
}
public function info($message, array $context = []): void
{
$this->log(LogLevel::INFO, $message, $context);
}
public function debug($message, array $context = []): void
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}
class TestClient extends Client
{
/**
* @param mixed $data
*
* @return mixed
* @throws ReflectionException
*/
public function encode(mixed $data): mixed
{
$reflection = new ReflectionMethod($this, 'encodeData');
if (PHP_VERSION_ID < 80100) {
$reflection->setAccessible(true);
}
return $reflection->invoke($this, $data);
}
}