diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index ee2ef05e..26d3a1eb 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -17,6 +17,7 @@ ->in(__DIR__ . '/src/Services/CRM/Timeline/') ->in(__DIR__ . '/src/Services/Entity/Section/') ->in(__DIR__ . '/src/Services/Department/') + ->in(__DIR__ . '/src/Services/Paysystem/') ->in(__DIR__ . '/src/Services/Sale/') ->in(__DIR__ . '/src/Services/Task/') ->in(__DIR__ . '/src/Services/Sale/') diff --git a/CHANGELOG.md b/CHANGELOG.md index 7af2a5bb..79e23652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ ### Added +- Added service `Services\Paysystem\Handler\Service\Handler` with support methods, + see [pay_system.handler.* methods](https://github.com/bitrix24/b24phpsdk/issues/260): + - `add` adds a payment system handler + - `update` updates a payment system handler + - `list` returns a list of payment system handlers + - `delete` deletes a payment system handler +- Added service `Services\Paysystem\Service\Paysystem` with support methods, + see [sale.paysystem.* methods](https://github.com/bitrix24/b24phpsdk/issues/260): + - `add` adds a payment system + - `update` updates a payment system + - `get` returns a payment system by its identifier + - `list` returns a list of payment systems + - `delete` deletes a payment system + - `payPayment` pays a payment + - `payInvoice` pays an invoice (legacy version) +- Added service `Services\Paysystem\Settings\Service\Settings` with support methods, + see [sale.paysystem.settings.* methods](https://github.com/bitrix24/b24phpsdk/issues/260): + - `get` returns the settings of the payment system + - `update` updates the payment system settings + - `getForPayment` returns the payment system settings for a specific payment + - `getForInvoice` returns the payment system settings for a specific invoice (legacy version) - Added service `Services\Sale\Shipment\Service\Shipment` with support methods, see [sale.shipment.* methods](https://github.com/bitrix24/b24phpsdk/issues/250): - `add` adds a shipment diff --git a/Makefile b/Makefile index 7e2eb9b6..6a5e3a2d 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ help: @echo "" @echo "test-unit - run unit tests" @echo "test-integration-sale-basket-property - run BasketProperty integration tests" + @echo "test-integration-scope-paysystem - run Payment System integration tests" @echo "test-integration-sale-payment-item-basket - run PaymentItemBasket integration tests" @echo "test-integration-sale-payment-item-shipment - run PaymentItemShipment integration tests" @echo "test-integration-sale-property-relation - run PropertyRelation integration tests" @@ -163,6 +164,18 @@ test-integration-scope-im: test-integration-scope-placement: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_placement +.PHONY: test-integration-scope-paysystem +test-integration-scope-paysystem: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_paysystem + +.PHONY: test-integration-paysystem-service +test-integration-paysystem-service: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_paysystem_service + +.PHONY: test-integration-paysystem-settings +test-integration-paysystem-settings: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_paysystem_settings + .PHONY: test-integration-scope-im-open-lines test-integration-scope-im-open-lines: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_im_open_lines diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 3bead767..c4d6b7ba 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,6 +10,7 @@ parameters: - tests/Integration/Services/Catalog - tests/Integration/Services/IMOpenLines - tests/Integration/Services/Main + - tests/Integration/Services/Paysystem - tests/Integration/Services/Placement - tests/Integration/Services/CRM/Address - tests/Integration/Services/CRM/Deal/Service/DealRecurringTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 812551f3..c6db4cb1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -28,6 +28,15 @@ ./tests/Integration/Services/Placement/ + + ./tests/Integration/Services/Paysystem/ + + + ./tests/Integration/Services/Paysystem/Service/ + + + ./tests/Integration/Services/Paysystem/Settings/ + ./tests/Integration/Services/User/ diff --git a/rector.php b/rector.php index 4b458e5f..892855ab 100644 --- a/rector.php +++ b/rector.php @@ -34,6 +34,8 @@ __DIR__ . '/tests/Integration/Services/CRM/Address', __DIR__ . '/src/Services/Main', __DIR__ . '/tests/Integration/Services/Main', + __DIR__ . '/src/Services/Paysystem', + __DIR__ . '/tests/Integration/Services/Paysystem', __DIR__ . '/src/Services/Placement', __DIR__ . '/tests/Integration/Services/Placement', __DIR__ . '/src/Services/CRM/Deal', diff --git a/src/Services/Paysystem/Handler/Result/HandlerItemResult.php b/src/Services/Paysystem/Handler/Result/HandlerItemResult.php new file mode 100644 index 00000000..b6b770c0 --- /dev/null +++ b/src/Services/Paysystem/Handler/Result/HandlerItemResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Handler\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class HandlerItemResult + * + * @property-read int $ID Payment system handler identifier + * @property-read string $NAME Name of the REST handler + * @property-read string $CODE Code of the REST handler + * @property-read int $SORT Sorting order + * @property-read array $SETTINGS Handler settings containing currency, client type, form/checkout/iframe data, and codes + */ +class HandlerItemResult extends AbstractItem +{ +} diff --git a/src/Services/Paysystem/Handler/Result/HandlersResult.php b/src/Services/Paysystem/Handler/Result/HandlersResult.php new file mode 100644 index 00000000..77edb07f --- /dev/null +++ b/src/Services/Paysystem/Handler/Result/HandlersResult.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Handler\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * List of payment system handlers result for sale.paysystem.handler.list + */ +class HandlersResult extends AbstractResult +{ + /** + * @return HandlerItemResult[] + * @throws BaseException + */ + public function getHandlers(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new HandlerItemResult($item); + } + + return $items; + } +} diff --git a/src/Services/Paysystem/Handler/Service/Handler.php b/src/Services/Paysystem/Handler/Service/Handler.php new file mode 100644 index 00000000..6e1025b4 --- /dev/null +++ b/src/Services/Paysystem/Handler/Service/Handler.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Handler\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Paysystem\Handler\Result\HandlersResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['pay_system']))] +class Handler extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Adds a REST handler for the payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-add.html + * + * @param string $name Name of the REST handler + * @param string $code Code of the REST handler. Must be unique among all handlers + * @param array $settings Handler settings + * @param int $sort Sorting. Default is 100 + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.handler.add', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-add.html', + 'Adds a REST handler for the payment system.' + )] + public function add(string $name, string $code, array $settings, int $sort = 100): AddedItemResult + { + return new AddedItemResult( + $this->core->call('sale.paysystem.handler.add', [ + 'NAME' => $name, + 'CODE' => $code, + 'SETTINGS' => $settings, + 'SORT' => $sort, + ]) + ); + } + + /** + * Updates a REST handler for the payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-update.html + * + * @param int $id Identifier of the REST handler + * @param array $fields Set of values for updating + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.handler.update', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-update.html', + 'Updates a REST handler for the payment system.' + )] + public function update(int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call('sale.paysystem.handler.update', [ + 'ID' => $id, + 'FIELDS' => $fields, + ]) + ); + } + + /** + * Returns a list of REST handlers for the payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-list.html + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.handler.list', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-list.html', + 'Returns a list of REST handlers for the payment system.' + )] + public function list(): HandlersResult + { + return new HandlersResult( + $this->core->call('sale.paysystem.handler.list') + ); + } + + /** + * Deletes a REST handler for the payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-delete.html + * + * @param int $id Identifier of the REST handler + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.handler.delete', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-handler-delete.html', + 'Deletes a REST handler for the payment system.' + )] + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call('sale.paysystem.handler.delete', [ + 'ID' => $id, + ]) + ); + } +} diff --git a/src/Services/Paysystem/PaysystemServiceBuilder.php b/src/Services/Paysystem/PaysystemServiceBuilder.php new file mode 100644 index 00000000..442f1ec1 --- /dev/null +++ b/src/Services/Paysystem/PaysystemServiceBuilder.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem; + +use Bitrix24\SDK\Attributes\ApiServiceBuilderMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Paysystem\Handler\Service\Handler; + +/** + * Class PaysystemServiceBuilder + * + * @package Bitrix24\SDK\Services\Paysystem + */ +#[ApiServiceBuilderMetadata(new Scope(['pay_system']))] +class PaysystemServiceBuilder extends AbstractServiceBuilder +{ + /** + * Payment system handlers service (sale.paysystem.handler.*) + */ + public function handler(): Handler + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Handler($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * Payment systems service (sale.paysystem.*) + */ + public function paysystem(): Service\Paysystem + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Service\Paysystem( + new Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * Payment system settings service (sale.paysystem.settings.*) + */ + public function settings(): Settings\Service\Settings + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Settings\Service\Settings($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + +} diff --git a/src/Services/Paysystem/Result/PaymentResult.php b/src/Services/Paysystem/Result/PaymentResult.php new file mode 100644 index 00000000..2d55fb90 --- /dev/null +++ b/src/Services/Paysystem/Result/PaymentResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class PaymentResult + * + * @package Bitrix24\SDK\Services\Paysystem\Result + */ +class PaymentResult extends AbstractResult +{ + /** + * Returns the payment operation result + * + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Paysystem/Result/PaysystemItemResult.php b/src/Services/Paysystem/Result/PaysystemItemResult.php new file mode 100644 index 00000000..bbef6f4a --- /dev/null +++ b/src/Services/Paysystem/Result/PaysystemItemResult.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class PaysystemItemResult + * + * @property-read int|null $ID Payment system identifier + * @property-read string|null $NAME Payment system name + * @property-read string|null $CODE Payment system code + * @property-read string|null $DESCRIPTION Payment system description + * @property-read string|null $ACTIVE Payment system activity status (Y/N) + * @property-read int|null $SORT Sorting order + * @property-read string|null $PS_MODE Payment system mode + * @property-read string|null $ACTION_FILE Action file path + * @property-read string|null $RESULT_FILE Result file path + * @property-read string|null $NEW_WINDOW Open in new window flag (Y/N) + * @property-read string|null $HAVE_PAYMENT Has payment flag (Y/N) + * @property-read string|null $HAVE_ACTION Has action flag (Y/N) + * @property-read string|null $HAVE_RESULT Has result flag (Y/N) + * @property-read string|null $HAVE_PREPAY Has prepayment flag (Y/N) + * @property-read string|null $HAVE_PRICE Has price flag (Y/N) + * @property-read string|null $CURRENCY Currency code + * @property-read array|null $LOGOTIP Payment system logo + * @property-read string|null $XML_ID External identifier + * @property-read array|null $SETTINGS Payment system settings + */ +class PaysystemItemResult extends AbstractItem +{ +} diff --git a/src/Services/Paysystem/Result/PaysystemsResult.php b/src/Services/Paysystem/Result/PaysystemsResult.php new file mode 100644 index 00000000..4ec7a612 --- /dev/null +++ b/src/Services/Paysystem/Result/PaysystemsResult.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class PaysystemsResult + * + * @package Bitrix24\SDK\Services\Paysystem\Result + */ +class PaysystemsResult extends AbstractResult +{ + /** + * @return PaysystemItemResult[] + * @throws BaseException + */ + public function getPaysystems(): array + { + $paysystems = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $paysystems[] = new PaysystemItemResult($item); + } + + return $paysystems; + } +} diff --git a/src/Services/Paysystem/Service/Batch.php b/src/Services/Paysystem/Service/Batch.php new file mode 100644 index 00000000..3c709237 --- /dev/null +++ b/src/Services/Paysystem/Service/Batch.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; +use Bitrix24\SDK\Services\AbstractBatchService; +use Bitrix24\SDK\Services\Paysystem\Result\PaysystemItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['pay_system']))] +class Batch extends AbstractBatchService +{ + /** + * Batch add method for payment systems + * + * @param array $paysystems Array of payment system data + * + * @return Generator + * + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'sale.paysystem.add', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-add.html', + 'Adds payment systems.' + )] + public function add(array $paysystems): Generator + { + foreach ($this->batch->addEntityItems('sale.paysystem.add', $paysystems) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch update method for payment systems + * + * Update elements in array with structure + * element_id => [ // PS item id + * 'fields' => [] // PS item fields to update + * ] + * + * @return Generator + * + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'sale.paysystem.update', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-update.html', + 'Updates payment systems.' + )] + public function update(array $paysystems): Generator + { + foreach ($this->batch->updateEntityItems('sale.paysystem.update', $paysystems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } + + /** + * Batch delete method for payment systems + * + * @param array $paysystemIds Array of payment system identifiers + * + * @return Generator + * + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'sale.paysystem.delete', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-delete.html', + 'Deletes payment systems.' + )] + public function delete(array $paysystemIds): Generator + { + foreach ($this->batch->deleteEntityItems('sale.paysystem.delete', $paysystemIds) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} diff --git a/src/Services/Paysystem/Service/Paysystem.php b/src/Services/Paysystem/Service/Paysystem.php new file mode 100644 index 00000000..90621d55 --- /dev/null +++ b/src/Services/Paysystem/Service/Paysystem.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Paysystem\Result\PaymentResult; +use Bitrix24\SDK\Services\Paysystem\Result\PaysystemsResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['pay_system']))] +class Paysystem extends AbstractService +{ + /** + * Paysystem constructor. + */ + public function __construct(public Batch $batch, CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Adds a payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-add.html + * + * @param array $fields Field values for creating a payment system + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.add', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-add.html', + 'Adds a payment system.' + )] + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call('sale.paysystem.add', $fields) + ); + } + + /** + * Modifies a payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-update.html + * + * @param int $id Payment system identifier + * @param array $fields Field values for update + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.update', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-update.html', + 'Modifies a payment system.' + )] + public function update(int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call('sale.paysystem.update', [ + 'ID' => $id, + 'FIELDS' => $fields, + ]) + ); + } /** + * Returns a list of payment systems. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-list.html + * + * @param array $select Fields to select + * @param array $filter Filter criteria + * @param array $order Sort order + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.list', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-list.html', + 'Returns a list of payment systems.' + )] + public function list(array $select = [], array $filter = [], array $order = []): PaysystemsResult + { + return new PaysystemsResult( + $this->core->call('sale.paysystem.list', [ + 'SELECT' => $select, + 'FILTER' => $filter, + 'ORDER' => $order, + ]) + ); + } + + /** + * Deletes a payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-delete.html + * + * @param int $id Payment system identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.delete', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-delete.html', + 'Deletes a payment system.' + )] + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call('sale.paysystem.delete', [ + 'ID' => $id, + ]) + ); + } + + /** + * Pay for an order through a specific payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-pay-payment.html + * + * @param int $paymentId Payment identifier + * @param int $paySystemId Payment system identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.pay.payment', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-pay-payment.html', + 'Pay for an order through a specific payment system.' + )] + public function payPayment(int $paymentId, int $paySystemId): PaymentResult + { + return new PaymentResult( + $this->core->call('sale.paysystem.pay.payment', [ + 'PAYMENT_ID' => $paymentId, + 'PAY_SYSTEM_ID' => $paySystemId, + ]) + ); + } + + /** + * Pay an invoice through a specific payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-pay-invoice.html + * + * @param int $invoiceId Identifier of the old version invoice + * @param int|null $paySystemId Identifier of the payment system + * @param string|null $bxRestHandler Symbolic identifier of the payment system's REST handler + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.pay.invoice', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-pay-invoice.html', + 'Pay an invoice through a specific payment system.' + )] + public function payInvoice(int $invoiceId, ?int $paySystemId = null, ?string $bxRestHandler = null): PaymentResult + { + $params = ['INVOICE_ID' => $invoiceId]; + + if ($paySystemId !== null) { + $params['PAY_SYSTEM_ID'] = $paySystemId; + } + + if ($bxRestHandler !== null) { + $params['BX_REST_HANDLER'] = $bxRestHandler; + } + + return new PaymentResult( + $this->core->call('sale.paysystem.pay.invoice', $params) + ); + } +} diff --git a/src/Services/Paysystem/Settings/Result/SettingsItemResult.php b/src/Services/Paysystem/Settings/Result/SettingsItemResult.php new file mode 100644 index 00000000..49231dd7 --- /dev/null +++ b/src/Services/Paysystem/Settings/Result/SettingsItemResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Settings\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class SettingsItemResult + * + * Represents payment system settings data. The structure of the settings is defined + * when adding the payment system handler in the method sale.paysystem.handler.add + * under the CODES key of the SETTINGS parameter. + * + * The keys of the result object are the parameter codes specified when adding the handler, + * and the values are the parameter values: either filled in manually by the user when + * creating the payment system or specified when adding the payment system via + * sale.paysystem.add or specified when executing the method sale.paysystem.settings.update. + * + * Common setting properties (examples from documentation): + * @property-read string|null $REST_SERVICE_ID_IFRAME Service ID for iframe integration + * @property-read string|null $REST_SERVICE_KEY_IFRAME Service key for iframe integration + * @property-read string|null $PS_WORK_MODE_IFRAME Payment system work mode (e.g., "REGULAR") + * + * Note: The actual properties depend on the specific payment system handler configuration + * and may vary for different payment systems. + */ +class SettingsItemResult extends AbstractItem +{ +} diff --git a/src/Services/Paysystem/Settings/Service/Settings.php b/src/Services/Paysystem/Settings/Service/Settings.php new file mode 100644 index 00000000..a1ed7666 --- /dev/null +++ b/src/Services/Paysystem/Settings/Service/Settings.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Paysystem\Settings\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Paysystem\Settings\Result\SettingsItemResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['pay_system']))] +class Settings extends AbstractService +{ + /** + * Returns the settings of the payment system. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-get.html + * + * @param int $paySystemId Payment system identifier + * @param int $personTypeId Payer type identifier (pass 0 to get default settings) + * + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.settings.get', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-get.html', + 'Returns the settings of the payment system' + )] + public function get(int $paySystemId, int $personTypeId): SettingsItemResult + { + return new SettingsItemResult( + $this->core->call( + 'sale.paysystem.settings.get', + [ + 'ID' => $paySystemId, + 'PERSON_TYPE_ID' => $personTypeId, + ] + )->getResponseData()->getResult() + ); + } + + /** + * Updates the payment system settings. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-update.html + * + * @param int $paySystemId Payment system identifier + * @param array $settings Settings to be updated. Each setting should have structure: + * ['PARAMETER_NAME' => ['TYPE' => 'VALUE', 'VALUE' => 'parameter_value']] + * @param int|null $personTypeId Payer type identifier (optional) + * + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.settings.update', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-update.html', + 'Updates the payment system settings' + )] + public function update(int $paySystemId, array $settings, ?int $personTypeId = null): UpdatedItemResult + { + $params = [ + 'ID' => $paySystemId, + 'SETTINGS' => $settings, + ]; + + if ($personTypeId !== null) { + $params['PERSON_TYPE_ID'] = $personTypeId; + } + + return new UpdatedItemResult( + $this->core->call('sale.paysystem.settings.update', $params) + ); + } + + /** + * Returns the payment system settings for a specific payment. + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-payment-get.html + * + * @param int $paymentId Payment identifier + * @param int $paySystemId Payment system identifier + * + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.settings.payment.get', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-payment-get.html', + 'Returns the payment system settings for a specific payment' + )] + public function getForPayment(int $paymentId, int $paySystemId): SettingsItemResult + { + return new SettingsItemResult( + $this->core->call( + 'sale.paysystem.settings.payment.get', + [ + 'PAYMENT_ID' => $paymentId, + 'PAY_SYSTEM_ID' => $paySystemId, + ] + )->getResponseData()->getResult() + ); + } + + /** + * Returns the payment system settings for a specific invoice (legacy version). + * + * @link https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-invoice-get.html + * + * @param int $invoiceId Legacy invoice identifier + * @param int|null $paySystemId Payment system identifier (optional if bxRestHandler is provided) + * @param string|null $bxRestHandler Symbolic identifier of the payment system REST handler (optional if paySystemId is provided) + * + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sale.paysystem.settings.invoice.get', + 'https://apidocs.bitrix24.com/api-reference/pay-system/sale-pay-system-settings-invoice-get.html', + 'Returns the payment system settings for a specific invoice (legacy version)' + )] + public function getForInvoice(int $invoiceId, ?int $paySystemId = null, ?string $bxRestHandler = null): SettingsItemResult + { + if ($paySystemId === null && $bxRestHandler === null) { + throw new \InvalidArgumentException('Either paySystemId or bxRestHandler parameter must be provided'); + } + + $params = ['INVOICE_ID' => $invoiceId]; + + if ($paySystemId !== null) { + $params['PAY_SYSTEM_ID'] = $paySystemId; + } + + if ($bxRestHandler !== null) { + $params['BX_REST_HANDLER'] = $bxRestHandler; + } + + return new SettingsItemResult( + $this->core->call( + 'sale.paysystem.settings.invoice.get', + $params + )->getResponseData()->getResult() + ); + } +} diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index c03dcd9d..064ca371 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -32,6 +32,7 @@ use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; use Bitrix24\SDK\Services\Workflows\WorkflowsServiceBuilder; use Bitrix24\SDK\Services\Sale\SaleServiceBuilder; +use Bitrix24\SDK\Services\Paysystem\PaysystemServiceBuilder; use Psr\Log\LoggerInterface; class ServiceBuilder extends AbstractServiceBuilder @@ -205,6 +206,20 @@ public function getPlacementScope(): PlacementServiceBuilder return $this->serviceCache[__METHOD__]; } + public function getPaysystemScope(): PaysystemServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new PaysystemServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + public function getCatalogScope(): CatalogServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { diff --git a/tests/Integration/Services/Paysystem/Handler/Service/HandlerTest.php b/tests/Integration/Services/Paysystem/Handler/Service/HandlerTest.php new file mode 100644 index 00000000..cafcb781 --- /dev/null +++ b/tests/Integration/Services/Paysystem/Handler/Service/HandlerTest.php @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Paysystem\Handler\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Paysystem\Handler\Service\Handler; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class HandlerTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\Paysystem\Handler\Service + */ +#[CoversMethod(Handler::class, 'add')] +#[CoversMethod(Handler::class, 'update')] +#[CoversMethod(Handler::class, 'list')] +#[CoversMethod(Handler::class, 'delete')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Paysystem\Handler\Service\Handler::class)] +class HandlerTest extends TestCase +{ + protected Handler $handlerService; + + protected function setUp(): void + { + $this->handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + } + + /** + * Get default handler settings for tests + */ + private function getDefaultHandlerSettings(): array + { + return [ + 'CURRENCY' => ['USD'], + 'CLIENT_TYPE' => 'b2c', + 'FORM_DATA' => [ + 'ACTION_URI' => 'https://example.com/payment_form.php', + 'METHOD' => 'POST', + 'FIELDS' => [ + 'paymentId' => [ + 'CODE' => 'PAYMENT_ID', + 'VISIBLE' => 'Y' + ] + ] + ], + 'CODES' => [ + 'PAYMENT_ID' => [ + 'NAME' => 'Payment ID', + 'DESCRIPTION' => 'Payment identifier', + 'SORT' => '100', + 'GROUP' => 'PAYMENT', + 'DEFAULT' => [ + 'PROVIDER_KEY' => 'PAYMENT', + 'PROVIDER_VALUE' => 'ACCOUNT_NUMBER' + ] + ] + ] + ]; + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + // Create a payment system handler + $handlerName = 'Test Handler ' . time(); + $handlerCode = 'test_handler_' . time(); + $handlerSettings = $this->getDefaultHandlerSettings(); + + $addedItemResult = $this->handlerService->add($handlerName, $handlerCode, $handlerSettings); + $handlerId = $addedItemResult->getId(); + + self::assertGreaterThan(0, $handlerId); + + // Clean up + $this->handlerService->delete($handlerId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + // Create a handler first + $handlerName = 'Test Handler ' . time(); + $handlerCode = 'test_handler_' . time(); + $handlerSettings = $this->getDefaultHandlerSettings(); + + $addedItemResult = $this->handlerService->add($handlerName, $handlerCode, $handlerSettings); + $handlerId = $addedItemResult->getId(); + + // Update the handler + $updateFields = [ + 'NAME' => 'Updated Test Handler ' . time(), + 'SORT' => 200 + ]; + + $updatedItemResult = $this->handlerService->update($handlerId, $updateFields); + self::assertTrue($updatedItemResult->isSuccess()); + + // Clean up + $this->handlerService->delete($handlerId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + // Create a handler first + $handlerName = 'Test Handler ' . time(); + $handlerCode = 'test_handler_' . time(); + $handlerSettings = $this->getDefaultHandlerSettings(); + + $addedItemResult = $this->handlerService->add($handlerName, $handlerCode, $handlerSettings); + $handlerId = $addedItemResult->getId(); + + // Test list functionality + $handlersResult = $this->handlerService->list(); + $handlers = $handlersResult->getHandlers(); + + self::assertIsArray($handlers); + + // Find our created handler + $foundHandler = null; + foreach ($handlers as $handler) { + if ($handler->ID === (string)$handlerId) { + $foundHandler = $handler; + break; + } + } + + self::assertNotNull($foundHandler); + self::assertEquals($handlerName, $foundHandler->NAME); + self::assertEquals($handlerCode, $foundHandler->CODE); + + // Clean up + $this->handlerService->delete($handlerId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + // Create a handler first + $handlerName = 'Test Handler ' . time(); + $handlerCode = 'test_handler_' . time(); + $handlerSettings = $this->getDefaultHandlerSettings(); + + $addedItemResult = $this->handlerService->add($handlerName, $handlerCode, $handlerSettings); + $handlerId = $addedItemResult->getId(); + + // Delete the handler + $deletedItemResult = $this->handlerService->delete($handlerId); + self::assertTrue($deletedItemResult->isSuccess()); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Paysystem/Service/PaysystemBatchTest.php b/tests/Integration/Services/Paysystem/Service/PaysystemBatchTest.php new file mode 100644 index 00000000..d8a07ca6 --- /dev/null +++ b/tests/Integration/Services/Paysystem/Service/PaysystemBatchTest.php @@ -0,0 +1,315 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Paysystem\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Paysystem\Service\Paysystem; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +/** + * Class PaysystemBatchTest + * + * Integration tests for Payment System batch operations + * + * @package Bitrix24\SDK\Tests\Integration\Services\Paysystem\Service + */ +#[CoversClass(\Bitrix24\SDK\Services\Paysystem\Service\Batch::class)] +class PaysystemBatchTest extends TestCase +{ + private const TEST_SEGMENT_ELEMENTS_COUNT = 50; + + protected Paysystem $paysystemService; + + /** + * Get or create a person type ID for tests + */ + private function getPersonTypeId(): int + { + $personTypeService = Fabric::getServiceBuilder()->getSaleScope()->personType(); + $personTypesResult = $personTypeService->list(); + + if ($personTypesResult->getPersonTypes() !== []) { + return $personTypesResult->getPersonTypes()[0]->id; + } + + $addedPersonTypeResult = $personTypeService->add(['name' => 'Test Person Type ' . time()]); + return $addedPersonTypeResult->getId(); + } + + /** + * Create a test handler for payment system + */ + private function createTestHandler(): string + { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + $handlerName = 'Test Handler ' . time(); + $handlerCode = 'test_handler_' . time(); + $handlerSettings = [ + 'CURRENCY' => ['USD'], + 'CLIENT_TYPE' => 'b2c', + 'FORM_DATA' => [ + 'ACTION_URI' => 'https://example.com/payment_form.php', + 'METHOD' => 'POST', + 'FIELDS' => [ + 'paymentId' => [ + 'CODE' => 'PAYMENT_ID', + 'VISIBLE' => 'Y' + ] + ] + ], + 'CODES' => [ + 'PAYMENT_ID' => [ + 'NAME' => 'Payment ID', + 'DESCRIPTION' => 'Payment identifier', + 'SORT' => '100', + 'GROUP' => 'PAYMENT', + 'DEFAULT' => [ + 'PROVIDER_KEY' => 'PAYMENT', + 'PROVIDER_VALUE' => 'ACCOUNT_NUMBER' + ] + ] + ] + ]; + + $handlerService->add($handlerName, $handlerCode, $handlerSettings); + return $handlerCode; + } + + /** + * Delete test handler + */ + private function deleteTestHandlerByCode(string $handlerCode): void + { + try { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + $handlers = $handlerService->list(); + foreach ($handlers->getHandlers() as $handlerItemResult) { + if ($handlerItemResult->CODE === $handlerCode) { + $handlerService->delete(intval($handlerItemResult->ID)); + break; + } + } + } catch (BaseException $baseException) { + // Log the error but don't fail the test if handler deletion fails + // This is cleanup code, so failures should not break tests + error_log(sprintf('Warning: Failed to delete test handler %s: ', $handlerCode) . $baseException->getMessage()); + } + } + + /** + * Test batch add payment systems + * + * @throws BaseException + * @throws TransportException + */ + public function testBatchAdd(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + $paysystems = []; + $timestamp = time(); + + for ($i = 1; $i <= 10; $i++) { + $paysystems[] = [ + 'NAME' => 'Batch Test Payment System ' . $i . ' ' . $timestamp, + 'DESCRIPTION' => 'Batch test payment system ' . $i, + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER', + 'NEW_WINDOW' => 'N', + 'XML_ID' => 'test_batch_ps_' . $i . '_' . $timestamp + ]; + } + + $cnt = 0; + $createdIds = []; + foreach ($this->paysystemService->batch->add($paysystems) as $item) { + $cnt++; + $paysystemId = $item->getId(); + self::assertGreaterThanOrEqual(1, $paysystemId); + $createdIds[] = $paysystemId; + } + + self::assertEquals(count($paysystems), $cnt); + + // Clean up created payment systems + foreach ($createdIds as $createdId) { + $this->paysystemService->delete($createdId); + } + + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test batch update and delete payment systems + * + * @throws BaseException + * @throws TransportException + */ + public function testBatchUpdate(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + + // Add payment systems first + $paysystems = []; + $timestamp = time(); + + for ($i = 1; $i <= self::TEST_SEGMENT_ELEMENTS_COUNT; $i++) { + $paysystems[] = [ + 'NAME' => 'Batch Update Test PS ' . $i . ' ' . $timestamp, + 'DESCRIPTION' => 'Original description ' . $i, + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER', + 'NEW_WINDOW' => 'N', + 'XML_ID' => 'batch_update_test_' . $i . '_' . $timestamp + ]; + } + + $cnt = 0; + $paysystemIds = []; + foreach ($this->paysystemService->batch->add($paysystems) as $item) { + $cnt++; + $paysystemIds[] = $item->getId(); + } + + self::assertEquals(count($paysystems), $cnt); + + // Generate update data + $updatePaysystemData = []; + foreach ($paysystemIds as $index => $id) { + $updatePaysystemData[$id] = [ + 'fields' => [ + 'NAME' => 'Updated Payment System ' . ($index + 1) . ' ' . $timestamp, + 'DESCRIPTION' => 'Updated description ' . ($index + 1), + 'SORT' => 200 + $index + ], + ]; + } + + // Update payment systems in batch mode + $cnt = 0; + foreach ($this->paysystemService->batch->update($updatePaysystemData) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + + self::assertEquals(count($paysystems), $cnt); + + // Delete payment systems in batch mode + $cnt = 0; + foreach ($this->paysystemService->batch->delete($paysystemIds) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + + self::assertEquals(count($paysystems), $cnt); + + // Clean up handler + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test batch delete payment systems + * + * @throws BaseException + * @throws TransportException + */ + public function testBatchDelete(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + + // Add some payment systems first + $paysystems = []; + $timestamp = time(); + + for ($i = 1; $i <= 5; $i++) { + $paysystems[] = [ + 'NAME' => 'Batch Delete Test PS ' . $i . ' ' . $timestamp, + 'DESCRIPTION' => 'Test payment system for batch deletion ' . $i, + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER', + 'NEW_WINDOW' => 'N', + 'XML_ID' => 'batch_delete_test_' . $i . '_' . $timestamp + ]; + } + + $paysystemIds = []; + foreach ($this->paysystemService->batch->add($paysystems) as $item) { + $paysystemIds[] = $item->getId(); + } + + //echo "\nPaysystem Ids:\n"; + //print_r($paysystemIds); + + // Delete payment systems in batch + $cnt = 0; + foreach ($this->paysystemService->batch->delete($paysystemIds) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + + echo "\nCount Ids:\n"; + print_r($cnt); + + self::assertEquals(count($paysystems), $cnt); + + // Clean up handler + $this->deleteTestHandlerByCode($handlerCode); + } + + protected function setUp(): void + { + $this->paysystemService = Fabric::getServiceBuilder()->getPaysystemScope()->paysystem(); + } + + protected function tearDown(): void + { + // Additional cleanup: remove any remaining test handlers that might have been left + $this->cleanupTestHandlers(); + } + + /** + * Clean up any test handlers that might be left over + */ + private function cleanupTestHandlers(): void + { + try { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + $handlers = $handlerService->list(); + foreach ($handlers->getHandlers() as $handlerItemResult) { + if (str_contains($handlerItemResult->CODE, 'test_handler_')) { + try { + $handlerService->delete(intval($handlerItemResult->ID)); + } catch (BaseException $e) { + // Ignore individual deletion errors + error_log(sprintf('Warning: Failed to cleanup test handler %s: ', $handlerItemResult->CODE) . $e->getMessage()); + } + } + } + } catch (BaseException $baseException) { + // Ignore general cleanup errors + error_log("Warning: Failed to list handlers during cleanup: " . $baseException->getMessage()); + } + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Paysystem/Service/PaysystemTest.php b/tests/Integration/Services/Paysystem/Service/PaysystemTest.php new file mode 100644 index 00000000..5bdf555a --- /dev/null +++ b/tests/Integration/Services/Paysystem/Service/PaysystemTest.php @@ -0,0 +1,477 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Paysystem\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Paysystem\Result\PaysystemItemResult; +use Bitrix24\SDK\Services\Paysystem\Service\Paysystem; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; +use Bitrix24\SDK\Core; + +/** + * Class PaysystemTest + * + * Integration tests for Payment System service + * + * @package Bitrix24\SDK\Tests\Integration\Services\Paysystem\Service + */ +#[CoversClass(Paysystem::class)] +#[CoversMethod(Paysystem::class, 'add')] +#[CoversMethod(Paysystem::class, 'delete')] +#[CoversMethod(Paysystem::class, 'list')] +#[CoversMethod(Paysystem::class, 'update')] +#[CoversMethod(Paysystem::class, 'payPayment')] +class PaysystemTest extends TestCase +{ + use CustomBitrix24Assertions; + + private Paysystem $paysystemService; + + /** + * Get or create a person type ID for tests + * + * @throws BaseException + * @throws TransportException + */ + private function getPersonTypeId(): int + { + $personTypeService = Fabric::getServiceBuilder()->getSaleScope()->personType(); + $personTypesResult = $personTypeService->list(); + + return $personTypesResult->getPersonTypes()[0]->id; + } + + /** + * Helper method to create a test order + * + * @return int Order ID + * @throws BaseException + * @throws TransportException + */ + private function createTestOrder(int $personTypeId): int + { + $orderService = Fabric::getServiceBuilder()->getSaleScope()->order(); + $orderFields = [ + 'lid' => 's1', + 'personTypeId' => $personTypeId, + 'currency' => 'USD', + 'price' => 100.00 + ]; + + return $orderService->add($orderFields)->getId(); + } + + /** + * Helper method to create a test payment + * + * @return int Payment ID + * @throws BaseException + * @throws TransportException + */ + private function createTestPayment(int $orderId, int $paySystemId): int + { + $paymentService = Fabric::getServiceBuilder()->getSaleScope()->payment(); + $paymentFields = [ + 'orderId' => $orderId, + 'paySystemId' => $paySystemId, + 'sum' => 100.00, + 'currency' => 'USD' + ]; + + return $paymentService->add($paymentFields)->getId(); + } + + /** + * Helper method to delete a test order + */ + private function deleteTestOrder(int $id): void + { + try { + $orderService = Fabric::getServiceBuilder()->getSaleScope()->order(); + $orderService->delete($id); + } catch (\Exception) { + // Ignore if order doesn't exist + } + } + + /** + * Helper method to delete a test payment + */ + private function deleteTestPayment(int $id): void + { + try { + $paymentService = Fabric::getServiceBuilder()->getSaleScope()->payment(); + $paymentService->delete($id); + } catch (\Exception) { + // Ignore if payment doesn't exist + } + } + + /** + * Create a test handler for payment system + * + * @return string Handler CODE + * @throws BaseException + * @throws TransportException + */ + private function createTestHandler(): string + { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + + $handlerName = 'Test Handler ' . time(); + $handlerCode = 'test_handler_' . time(); + $handlerSettings = [ + 'CURRENCY' => ['USD'], + 'CLIENT_TYPE' => 'b2b', + 'FORM_DATA' => [ + 'ACTION_URI' => 'https://example.com/payment_form.php', + 'METHOD' => 'POST', + 'FIELDS' => [ + 'paymentId' => [ + 'CODE' => 'PAYMENT_ID', + 'VISIBLE' => 'Y' + ] + ] + ], + 'CODES' => [ + 'PAYMENT_ID' => [ + 'NAME' => 'Payment ID', + 'DESCRIPTION' => 'Payment identifier', + 'SORT' => '100', + 'GROUP' => 'PAYMENT', + 'DEFAULT' => [ + 'PROVIDER_KEY' => 'PAYMENT', + 'PROVIDER_VALUE' => 'ACCOUNT_NUMBER' + ] + ] + ] + ]; + + $handlerService->add($handlerName, $handlerCode, $handlerSettings); + // Return the CODE, not the ID + return $handlerCode; + } + + /** + * Delete test handler by code + * + * @throws BaseException + * @throws TransportException + */ + private function deleteTestHandlerByCode(string $handlerCode): void + { + try { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + // We need to get the handler ID first to delete it + $handlers = $handlerService->list(); + foreach ($handlers->getHandlers() as $handlerItemResult) { + if ($handlerItemResult->CODE === $handlerCode) { + $handlerService->delete(intval($handlerItemResult->ID)); + break; + } + } + } catch (BaseException $baseException) { + // Log the error but don't fail the test if handler deletion fails + // This is cleanup code, so failures should not break tests + error_log(sprintf('Warning: Failed to delete test handler %s: ', $handlerCode) . $baseException->getMessage()); + } + } + + /** + * Test add payment system + * + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $personTypeId = $this->getPersonTypeId(); + $handlerCode = $this->createTestHandler(); + + $name = 'Test Payment System ' . time(); + + $addedItemResult = $this->paysystemService->add([ + 'NAME' => $name, + 'DESCRIPTION' => 'Test payment system description', + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER', + 'NEW_WINDOW' => 'N', + 'XML_ID' => 'test_ps_' . time() + ]); + + self::assertGreaterThanOrEqual(1, $addedItemResult->getId()); + + // Clean up: first delete payment system, then handler + $this->paysystemService->delete($addedItemResult->getId()); + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test delete payment system + * + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + $personTypeId = $this->getPersonTypeId(); + $handlerCode = $this->createTestHandler(); + + $name = 'Test Payment System to Delete ' . time(); + + $addedItemResult = $this->paysystemService->add([ + 'NAME' => $name, + 'DESCRIPTION' => 'Test payment system for deletion', + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER' + ]); + + $deletedItemResult = $this->paysystemService->delete($addedItemResult->getId()); + self::assertTrue($deletedItemResult->isSuccess()); + + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test list payment systems + * + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + $personTypeId = $this->getPersonTypeId(); + $handlerCode = $this->createTestHandler(); + + // Create a test payment system first + $name = 'Test Payment System for List ' . time(); + + $addedItemResult = $this->paysystemService->add([ + 'NAME' => $name, + 'DESCRIPTION' => 'Test payment system for listing', + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER' + ]); + + $paysystemsResult = $this->paysystemService->list( + ['ID', 'NAME', 'ACTIVE'], + [], + ['ID' => 'ASC'] + ); + + self::assertGreaterThanOrEqual(1, count($paysystemsResult->getPaysystems())); + + foreach ($paysystemsResult->getPaysystems() as $paysystemItemResult) { + self::assertInstanceOf(PaysystemItemResult::class, $paysystemItemResult); + self::assertNotNull($paysystemItemResult->ID); + self::assertNotNull($paysystemItemResult->NAME); + } + + // Clean up + $this->paysystemService->delete($addedItemResult->getId()); + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test update payment system + * + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + + // Create a payment system first + $addedItemResult = $this->paysystemService->add([ + 'NAME' => 'Payment System for Update Test ' . time(), + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ENTITY_REGISTRY_TYPE' => 'ORDER' + ]); + + $paysystemId = $addedItemResult->getId(); + $newName = 'Updated Payment System ' . time(); + + // Update the payment system + $updatedItemResult = $this->paysystemService->update($paysystemId, [ + 'NAME' => $newName + ]); + + self::assertTrue($updatedItemResult->isSuccess()); + + // Verify the update by listing and finding our payment system + $paysystemsResult = $this->paysystemService->list(['ID', 'NAME'], ['ID' => $paysystemId]); + $paysystems = $paysystemsResult->getPaysystems(); + self::assertCount(1, $paysystems); + self::assertEquals($newName, $paysystems[0]->NAME); + + // Clean up + $this->paysystemService->delete($paysystemId); + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test list with filter + * + * @throws BaseException + * @throws TransportException + */ + public function testListWithFilter(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + $testName = 'Test Payment System for List Filter ' . time(); + + // Add a test payment system + $addedItemResult = $this->paysystemService->add([ + 'NAME' => $testName, + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ENTITY_REGISTRY_TYPE' => 'ORDER' + ]); + + $paysystemId = $addedItemResult->getId(); + + // Test list with filter + $paysystemsResult = $this->paysystemService->list(['ID', 'NAME'], ['NAME' => $testName]); + $paysystems = $paysystemsResult->getPaysystems(); + + self::assertGreaterThanOrEqual(1, count($paysystems)); + self::assertEquals($testName, $paysystems[0]->NAME); + + // Clean up + $this->paysystemService->delete($paysystemId); + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test list returns payment systems correctly + * + * @throws BaseException + * @throws TransportException + */ + public function testListCount(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + + // Add a test payment system + $addedItemResult = $this->paysystemService->add([ + 'NAME' => 'Test Payment System for Count ' . time(), + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ENTITY_REGISTRY_TYPE' => 'ORDER' + ]); + + $paysystemId = $addedItemResult->getId(); + + // Test list returns at least one result + $paysystemsResult = $this->paysystemService->list(); + self::assertGreaterThanOrEqual(1, count($paysystemsResult->getPaysystems())); + + // Clean up + $this->paysystemService->delete($paysystemId); + $this->deleteTestHandlerByCode($handlerCode); + } + + /** + * Test pay payment through specific payment system + * + * @throws BaseException + * @throws TransportException + */ + public function testPayPayment(): void + { + $handlerCode = $this->createTestHandler(); + $personTypeId = $this->getPersonTypeId(); + + // Create a test payment system + $addedItemResult = $this->paysystemService->add([ + 'NAME' => 'Test Payment System for Payment ' . time(), + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ENTITY_REGISTRY_TYPE' => 'ORDER', + 'ACTIVE' => 'Y' + ]); + + $paysystemId = $addedItemResult->getId(); + + // Create a test order + $orderId = $this->createTestOrder($personTypeId); + + // Create a test payment + $paymentId = $this->createTestPayment($orderId, $paysystemId); + + // Test the payPayment method + $paymentResult = $this->paysystemService->payPayment($paymentId, $paysystemId); + + // Verify that payment result is returned (can be true or false depending on payment system configuration) + self::assertIsBool($paymentResult->isSuccess()); + + // Clean up in reverse order + $this->deleteTestPayment($paymentId); + $this->deleteTestOrder($orderId); + $this->paysystemService->delete($paysystemId); + $this->deleteTestHandlerByCode($handlerCode); + } + + + protected function setUp(): void + { + $this->paysystemService = Fabric::getServiceBuilder()->getPaysystemScope()->paysystem(); + } + + protected function tearDown(): void + { + // Additional cleanup: remove any remaining test handlers that might have been left + $this->cleanupTestHandlers(); + } + + /** + * Clean up any test handlers that might be left over + */ + private function cleanupTestHandlers(): void + { + try { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + $handlers = $handlerService->list(); + foreach ($handlers->getHandlers() as $handlerItemResult) { + if (str_contains($handlerItemResult->CODE, 'test_handler_')) { + try { + $handlerService->delete(intval($handlerItemResult->ID)); + } catch (BaseException $e) { + // Ignore individual deletion errors + error_log(sprintf('Warning: Failed to cleanup test handler %s: ', $handlerItemResult->CODE) . $e->getMessage()); + } + } + } + } catch (BaseException $baseException) { + // Ignore general cleanup errors + error_log("Warning: Failed to list handlers during cleanup: " . $baseException->getMessage()); + } + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Paysystem/Settings/Service/SettingsTest.php b/tests/Integration/Services/Paysystem/Settings/Service/SettingsTest.php new file mode 100644 index 00000000..ef87a07d --- /dev/null +++ b/tests/Integration/Services/Paysystem/Settings/Service/SettingsTest.php @@ -0,0 +1,384 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Paysystem\Settings\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Paysystem\Settings\Result\SettingsItemResult; +use Bitrix24\SDK\Services\Paysystem\Settings\Service\Settings; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class SettingsTest + * + * Integration tests for Payment System Settings service + * + * @package Bitrix24\SDK\Tests\Integration\Services\Paysystem\Settings\Service + */ +#[CoversClass(Settings::class)] +#[CoversMethod(Settings::class, 'get')] +#[CoversMethod(Settings::class, 'update')] +#[CoversMethod(Settings::class, 'getForPayment')] +class SettingsTest extends TestCase +{ + use CustomBitrix24Assertions; + + private Settings $settingsService; + + private array $testDataCleanup = []; + + /** + * Get or create a person type ID for tests + * + * @throws BaseException + * @throws TransportException + */ + private function getPersonTypeId(): int + { + $personTypeService = Fabric::getServiceBuilder()->getSaleScope()->personType(); + $personTypesResult = $personTypeService->list(); + + return $personTypesResult->getPersonTypes()[0]->id; + } + + /** + * Create a test handler for payment system + * + * @return string Handler CODE + * @throws BaseException + * @throws TransportException + */ + private function createTestHandler(): string + { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + + $handlerName = 'Test Settings Handler ' . time(); + $handlerCode = 'test_settings_handler_' . time(); + $handlerSettings = [ + 'CURRENCY' => ['USD'], + 'CLIENT_TYPE' => 'b2b', + 'FORM_DATA' => [ + 'ACTION_URI' => 'https://example.com/payment_form.php', + 'METHOD' => 'POST', + 'FIELDS' => [ + 'paymentId' => [ + 'CODE' => 'PAYMENT_ID', + 'VISIBLE' => 'Y' + ] + ] + ], + 'CODES' => [ + 'TEST_API_KEY' => [ + 'NAME' => 'Test API Key', + 'DESCRIPTION' => 'API key for testing', + 'SORT' => '100', + 'GROUP' => 'CONNECT', + 'DEFAULT' => [ + 'PROVIDER_KEY' => 'VALUE', + 'PROVIDER_VALUE' => '' + ] + ], + 'TEST_MERCHANT_ID' => [ + 'NAME' => 'Test Merchant ID', + 'DESCRIPTION' => 'Merchant identifier for testing', + 'SORT' => '200', + 'GROUP' => 'CONNECT', + 'DEFAULT' => [ + 'PROVIDER_KEY' => 'VALUE', + 'PROVIDER_VALUE' => '' + ] + ], + 'TEST_MODE' => [ + 'NAME' => 'Test Mode', + 'DESCRIPTION' => 'Test or production mode', + 'SORT' => '300', + 'GROUP' => 'GENERAL', + 'DEFAULT' => [ + 'PROVIDER_KEY' => 'VALUE', + 'PROVIDER_VALUE' => 'TEST' + ] + ] + ] + ]; + + $handlerService->add($handlerName, $handlerCode, $handlerSettings); + $this->testDataCleanup['handler_code'] = $handlerCode; + + return $handlerCode; + } + + /** + * Create a test payment system + * + * @return int Payment system ID + * @throws BaseException + * @throws TransportException + */ + private function createTestPaymentSystem(string $handlerCode): int + { + $paysystemService = Fabric::getServiceBuilder()->getPaysystemScope()->paysystem(); + $personTypeId = $this->getPersonTypeId(); + + $name = 'Test Payment System for Settings ' . time(); + + $addedItemResult = $paysystemService->add([ + 'NAME' => $name, + 'DESCRIPTION' => 'Test payment system for settings testing', + 'PERSON_TYPE_ID' => $personTypeId, + 'BX_REST_HANDLER' => $handlerCode, + 'ACTIVE' => 'Y', + 'ENTITY_REGISTRY_TYPE' => 'ORDER', + 'NEW_WINDOW' => 'N', + 'XML_ID' => 'test_settings_ps_' . time() + ]); + + $paySystemId = $addedItemResult->getId(); + $this->testDataCleanup['paysystem_id'] = $paySystemId; + + return $paySystemId; + } + + /** + * Helper method to create a test order + * + * @return int Order ID + * @throws BaseException + * @throws TransportException + */ + private function createTestOrder(int $personTypeId): int + { + $orderService = Fabric::getServiceBuilder()->getSaleScope()->order(); + $orderFields = [ + 'lid' => 's1', + 'personTypeId' => $personTypeId, + 'currency' => 'USD', + 'price' => 100.00 + ]; + + $orderId = $orderService->add($orderFields)->getId(); + $this->testDataCleanup['order_id'] = $orderId; + + return $orderId; + } + + /** + * Helper method to create a test payment + * + * @return int Payment ID + * @throws BaseException + * @throws TransportException + */ + private function createTestPayment(int $orderId, int $paySystemId): int + { + $paymentService = Fabric::getServiceBuilder()->getSaleScope()->payment(); + $paymentFields = [ + 'orderId' => $orderId, + 'paySystemId' => $paySystemId, + 'sum' => 100.00, + 'currency' => 'USD' + ]; + + $paymentId = $paymentService->add($paymentFields)->getId(); + $this->testDataCleanup['payment_id'] = $paymentId; + + return $paymentId; + } + + /** + * Test get payment system settings + * + * @throws BaseException + * @throws TransportException + */ + public function testGet(): void + { + $handlerCode = $this->createTestHandler(); + $paySystemId = $this->createTestPaymentSystem($handlerCode); + $personTypeId = $this->getPersonTypeId(); + + $settingsItemResult = $this->settingsService->get($paySystemId, $personTypeId); + + self::assertInstanceOf(SettingsItemResult::class, $settingsItemResult); + // The settings should contain the default values from the handler + $settings = iterator_to_array($settingsItemResult->getIterator()); + self::assertIsArray($settings); + + // Check that we can access settings as properties + self::assertNotNull($settingsItemResult->TEST_MODE ?? null); + } + + /** + * Test update payment system settings + * + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + $handlerCode = $this->createTestHandler(); + $paySystemId = $this->createTestPaymentSystem($handlerCode); + $personTypeId = $this->getPersonTypeId(); + + // First, get current settings to ensure we have a baseline + $this->settingsService->get($paySystemId, $personTypeId); + + // Update settings + $newSettings = [ + 'TEST_API_KEY' => [ + 'TYPE' => 'VALUE', + 'VALUE' => 'test_api_key_' . time() + ], + 'TEST_MERCHANT_ID' => [ + 'TYPE' => 'VALUE', + 'VALUE' => 'test_merchant_' . time() + ] + ]; + + $updatedItemResult = $this->settingsService->update($paySystemId, $newSettings, $personTypeId); + self::assertTrue($updatedItemResult->isSuccess()); + + // Verify settings were updated + $settingsItemResult = $this->settingsService->get($paySystemId, $personTypeId); + + // Debug: check what we actually got + $settingsArray = iterator_to_array($settingsItemResult->getIterator()); + + // Check that settings exist and have correct values + self::assertArrayHasKey('TEST_API_KEY', $settingsArray); + self::assertArrayHasKey('TEST_MERCHANT_ID', $settingsArray); + + // Compare values directly from array + self::assertEquals($newSettings['TEST_API_KEY']['VALUE'], $settingsArray['TEST_API_KEY']['VALUE']); + self::assertEquals($newSettings['TEST_MERCHANT_ID']['VALUE'], $settingsArray['TEST_MERCHANT_ID']['VALUE']); + } + + /** + * Test get payment system settings for specific payment + * + * @throws BaseException + * @throws TransportException + */ + public function testGetForPayment(): void + { + $handlerCode = $this->createTestHandler(); + $paySystemId = $this->createTestPaymentSystem($handlerCode); + $personTypeId = $this->getPersonTypeId(); + + // Create test order and payment + $orderId = $this->createTestOrder($personTypeId); + $paymentId = $this->createTestPayment($orderId, $paySystemId); + + $settingsItemResult = $this->settingsService->getForPayment($paymentId, $paySystemId); + + self::assertInstanceOf(SettingsItemResult::class, $settingsItemResult); + + // The settings should contain the values from the payment system + $settings = iterator_to_array($settingsItemResult->getIterator()); + self::assertIsArray($settings); + + // Check that we can access settings as properties + self::assertNotNull($settingsItemResult->TEST_MODE ?? null); + } + + /** + * Test get with default person type (ID = 0) + * + * @throws BaseException + * @throws TransportException + */ + public function testGetWithDefaultPersonType(): void + { + $handlerCode = $this->createTestHandler(); + $paySystemId = $this->createTestPaymentSystem($handlerCode); + + $settingsItemResult = $this->settingsService->get($paySystemId, 0); + + self::assertInstanceOf(SettingsItemResult::class, $settingsItemResult); + $settings = iterator_to_array($settingsItemResult->getIterator()); + self::assertIsArray($settings); + } + + protected function setUp(): void + { + $this->settingsService = Fabric::getServiceBuilder()->getPaysystemScope()->settings(); + $this->testDataCleanup = []; + } + + protected function tearDown(): void + { + // Clean up test data in reverse order of creation + $this->cleanupTestData(); + } + + /** + * Clean up test data created during tests + */ + private function cleanupTestData(): void + { + try { + // Delete payment first (if exists) + if (isset($this->testDataCleanup['payment_id'])) { + $paymentService = Fabric::getServiceBuilder()->getSaleScope()->payment(); + try { + $paymentService->delete($this->testDataCleanup['payment_id']); + } catch (\Exception $e) { + error_log("Warning: Failed to delete test payment: " . $e->getMessage()); + } + } + + // Delete order (if exists) + if (isset($this->testDataCleanup['order_id'])) { + $orderService = Fabric::getServiceBuilder()->getSaleScope()->order(); + try { + $orderService->delete($this->testDataCleanup['order_id']); + } catch (\Exception $e) { + error_log("Warning: Failed to delete test order: " . $e->getMessage()); + } + } + + // Delete payment system (if exists) + if (isset($this->testDataCleanup['paysystem_id'])) { + $paysystemService = Fabric::getServiceBuilder()->getPaysystemScope()->paysystem(); + try { + $paysystemService->delete($this->testDataCleanup['paysystem_id']); + } catch (\Exception $e) { + error_log("Warning: Failed to delete test payment system: " . $e->getMessage()); + } + } + + // Delete handler last (if exists) + if (isset($this->testDataCleanup['handler_code'])) { + $handlerService = Fabric::getServiceBuilder()->getPaysystemScope()->handler(); + try { + // We need to get the handler ID first to delete it + $handlers = $handlerService->list(); + foreach ($handlers->getHandlers() as $handlerItemResult) { + if ($handlerItemResult->CODE === $this->testDataCleanup['handler_code']) { + $handlerService->delete(intval($handlerItemResult->ID)); + break; + } + } + } catch (\Exception $e) { + error_log("Warning: Failed to delete test handler: " . $e->getMessage()); + } + } + } catch (\Exception $exception) { + error_log("Warning: General cleanup error: " . $exception->getMessage()); + } + } +} \ No newline at end of file