From 883771a3a99828dda6a0a8f19af68aec79852870 Mon Sep 17 00:00:00 2001 From: Dmitriy Ignatenko Date: Mon, 29 Jun 2026 17:02:30 +0400 Subject: [PATCH 1/5] This is the first implementation for sign.b2e methods --- .php-cs-fixer.php | 1 + .tasks/504/plan.md | 94 ++++++++++++++++++ CHANGELOG.md | 11 +++ Makefile | 25 +++++ phpstan.neon.dist | 1 + phpunit.xml.dist | 19 ++++ rector.php | 2 + src/Services/RemoteEventsFactory.php | 15 +-- src/Services/ServiceBuilder.php | 21 ++-- .../Result/CompanyProviderItemResult.php | 29 ++++++ .../Result/CompanyProvidersResult.php | 35 +++++++ .../Service/CompanyProvider.php | 79 +++++++++++++++ .../Document/Result/DocumentItemResult.php | 26 +++++ .../B2e/Document/Result/DocumentResult.php | 29 ++++++ .../Sign/B2e/Document/Service/Document.php | 95 +++++++++++++++++++ .../Result/MySafeTailItemResult.php | 32 +++++++ .../MySafeTail/Result/MySafeTailResult.php | 35 +++++++ .../B2e/MySafeTail/Service/MySafeTail.php | 60 ++++++++++++ .../Result/PersonalTailItemResult.php | 28 ++++++ .../Result/PersonalTailResult.php | 35 +++++++ .../B2e/PersonalTail/Service/PersonalTail.php | 60 ++++++++++++ .../OnSignB2eDocumentStatusChanged.php | 32 +++++++ .../OnSignB2eDocumentStatusChangedPayload.php | 27 ++++++ .../OnSignB2eMemberStatusChanged.php | 32 +++++++ .../OnSignB2eMemberStatusChangedPayload.php | 28 ++++++ .../Sign/Events/SignB2eEventsFactory.php | 58 +++++++++++ src/Services/Sign/SignServiceBuilder.php | 75 +++++++++++++++ ...mpanyProviderItemResultAnnotationsTest.php | 58 +++++++++++ .../Service/CompanyProviderTest.php | 41 ++++++++ .../DocumentItemResultAnnotationsTest.php | 58 +++++++++++ .../B2e/Document/Service/DocumentTest.php | 50 ++++++++++ .../MySafeTailItemResultAnnotationsTest.php | 58 +++++++++++ .../B2e/MySafeTail/Service/MySafeTailTest.php | 41 ++++++++ .../PersonalTailItemResultAnnotationsTest.php | 58 +++++++++++ .../PersonalTail/Service/PersonalTailTest.php | 42 ++++++++ .../Services/Sign/SignServiceBuilderTest.php | 64 +++++++++++++ 36 files changed, 1442 insertions(+), 12 deletions(-) create mode 100644 .tasks/504/plan.md create mode 100644 src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php create mode 100644 src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php create mode 100644 src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php create mode 100644 src/Services/Sign/B2e/Document/Result/DocumentItemResult.php create mode 100644 src/Services/Sign/B2e/Document/Result/DocumentResult.php create mode 100644 src/Services/Sign/B2e/Document/Service/Document.php create mode 100644 src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php create mode 100644 src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php create mode 100644 src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php create mode 100644 src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php create mode 100644 src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php create mode 100644 src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php create mode 100644 src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php create mode 100644 src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php create mode 100644 src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php create mode 100644 src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php create mode 100644 src/Services/Sign/Events/SignB2eEventsFactory.php create mode 100644 src/Services/Sign/SignServiceBuilder.php create mode 100644 tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php create mode 100644 tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php create mode 100644 tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php create mode 100644 tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php create mode 100644 tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php create mode 100644 tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php create mode 100644 tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php create mode 100644 tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php create mode 100644 tests/Unit/Services/Sign/SignServiceBuilderTest.php diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 06f79bfe..c8f483b3 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -30,6 +30,7 @@ ->in(__DIR__ . '/src/Services/Booking/') ->in(__DIR__ . '/src/Services/Lists/') ->in(__DIR__ . '/src/Services/SonetGroup/') + ->in(__DIR__ . '/src/Services/Sign/') ->name('*.php') ->exclude(['vendor', 'storage', 'docker', 'docs']) // Exclude directories ->ignoreDotFiles(true) diff --git a/.tasks/504/plan.md b/.tasks/504/plan.md new file mode 100644 index 00000000..87138f28 --- /dev/null +++ b/.tasks/504/plan.md @@ -0,0 +1,94 @@ +# Plan: Add sign.b2e.* service support (issue #504) + +## Context + +Add support for Bitrix24 Electronic Document Management (КЭДО) REST API methods under the `sign.b2e.*` scope. + +**API methods:** +- `sign.b2e.document.send` — sends a document for signing (application context only) +- `sign.b2e.document.get` — returns information about a document and its signing members +- `sign.b2e.company.provider.list` — returns list of signature providers for a company +- `sign.b2e.personal.tail` — returns signed documents list for current user (application context only) +- `sign.b2e.mysafe.tail` — returns signed documents in company safe (application context only) + +**Events:** +- `OnSignB2eDocumentStatusChanged` (code `ONSIGNB2EDOCUMENTSTATUSCHANGED`) — fires when document status changes +- `OnSignB2eMemberStatusChanged` (code `ONSIGNB2EMEMBERSTATUSCHANGED`) — fires when member status changes + +**Response shapes:** +- `document.send` / `document.get` → `result` is object with `uid`, `state`, `members` +- `company.provider.list` → `result` is direct array of provider objects +- `personal.tail` → `result` is direct array of `{id, title, signed_date, file_url}` +- `mysafe.tail` → `result` is direct array of `{id, title, create_date, signed_date, creator_id, member_id, role, file_url}` + +**Scope:** `sign.b2e` (some methods also accept `crm` scope for company access) + +**Author:** © Dmitriy Ignatenko + +--- + +## Files to Create + +### Source + +1. `src/Services/Sign/SignServiceBuilder.php` — scope service builder with `#[ApiServiceBuilderMetadata(new Scope(['sign.b2e']))]` +2. `src/Services/Sign/B2e/Document/Result/DocumentItemResult.php` — `@property-read` for `uid`, `state`, `members` +3. `src/Services/Sign/B2e/Document/Result/DocumentResult.php` — wraps `DocumentItemResult` from `result` +4. `src/Services/Sign/B2e/Document/Service/Document.php` — `send()`, `get()` methods +5. `src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php` — `@property-read` for `code`, `uid`, `name`, `date`, `expires` +6. `src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php` — list result +7. `src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php` — `list()` method +8. `src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php` — `@property-read` for `id`, `title`, `signed_date`, `file_url` +9. `src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php` — list result +10. `src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php` — `tail()` method +11. `src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php` — `@property-read` for `id`, `title`, `create_date`, `signed_date`, `creator_id`, `member_id`, `role`, `file_url` +12. `src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php` — list result +13. `src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php` — `tail()` method +14. `src/Services/Sign/Events/SignB2eEventsFactory.php` +15. `src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php` +16. `src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php` +17. `src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php` +18. `src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php` + +### Tests + +19. `tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php` +20. `tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php` +21. `tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php` +22. `tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php` +23. `tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php` +24. `tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php` +25. `tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php` +26. `tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php` +27. `tests/Unit/Services/Sign/SignServiceBuilderTest.php` + +--- + +## Files to Modify + +1. `src/Services/ServiceBuilder.php` — add `getSignScope(): SignServiceBuilder` +2. `src/Services/RemoteEventsFactory.php` — register `SignB2eEventsFactory` in `init()` +3. `phpunit.xml.dist` — add test suites for sign.b2e +4. `Makefile` — add `test-integration-scope-sign` make target +5. `CHANGELOG.md` — add entry under `## 3.4.0 – UNRELEASED → ### Added` + +--- + +## Deptrac compliance + +New code lives in `src/Services/Sign/` (Services layer) and only depends on `Core` and `Application` +namespaces — no new violations introduced. + +--- + +## Verification + +```bash +make lint-cs-fixer +make lint-rector +make lint-phpstan +make lint-deptrac +make test-unit +make test-integration-scope-sign +``` + diff --git a/CHANGELOG.md b/CHANGELOG.md index 412f1737..2828e3f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ ### Added +- Added `Services\Sign\SignServiceBuilder` with support for `sign.b2e.*` methods and events, + see [sign.b2e.* methods](https://apidocs.bitrix24.com/api-reference/sign/index.html) ([#504](https://github.com/bitrix24/b24phpsdk/issues/504)): + - `document()->send()` — sends a document for company-side signing (КЭДО), application context only + - `document()->get()` — returns information about a document and its signing members + - `companyProvider()->list()` — returns the list of signature providers for a selected company + - `personalTail()->tail()` — returns the list of signed documents for the current user (КЭДО section), application context only + - `mySafeTail()->tail()` — returns the list of signed documents in the company safe, application context only +- Added events support for `sign.b2e` scope via `SignB2eEventsFactory` ([#504](https://github.com/bitrix24/b24phpsdk/issues/504)): + - `OnSignB2eDocumentStatusChanged` — fires when document status changes + - `OnSignB2eMemberStatusChanged` — fires when member status changes + ### Changed ### Fixed diff --git a/Makefile b/Makefile index 8846d0d5..3be34d36 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,11 @@ help: @echo "test-integration-lists-field - run Lists Field integration tests" @echo "test-integration-lists-section - run Lists Section integration tests" @echo "test-integration-lists-element - run Lists Element integration tests" + @echo "test-integration-scope-sign - run Sign B2e integration tests" + @echo "test-integration-sign-document - run Sign Document integration tests" + @echo "test-integration-sign-company-provider - run Sign CompanyProvider integration tests" + @echo "test-integration-sign-personal-tail - run Sign PersonalTail integration tests" + @echo "test-integration-sign-mysafe-tail - run Sign MySafeTail integration tests" t: docker compose run --rm php-cli sh @@ -664,6 +669,26 @@ test-integration-biconnector-source: test-integration-biconnector-dataset: docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_biconnector_dataset +.PHONY: test-integration-scope-sign +test-integration-scope-sign: + docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_sign + +.PHONY: test-integration-sign-document +test-integration-sign-document: + docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sign_document + +.PHONY: test-integration-sign-company-provider +test-integration-sign-company-provider: + docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sign_company_provider + +.PHONY: test-integration-sign-personal-tail +test-integration-sign-personal-tail: + docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sign_personal_tail + +.PHONY: test-integration-sign-mysafe-tail +test-integration-sign-mysafe-tail: + docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sign_mysafe_tail + # work dev environment .PHONY: php-dev-server-up php-dev-server-up: diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 84ba4b78..584ae289 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -40,6 +40,7 @@ parameters: - tests/Integration/Services/CRM/Documentgenerator/Document - tests/Integration/Services/CRM/Documentgenerator/Template - tests/Integration/Services/Timeman + - tests/Unit/Services/Sign excludePaths: # TODO: Fix type errors in RequisiteUserfieldUseCaseTest and remove this exclusion # Tracking: https://github.com/bitrix24/b24phpsdk/issues diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 322738da..40a503da 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -369,6 +369,25 @@ ./tests/Integration/Services/Biconnector/Dataset/Service/ ./tests/Integration/Services/Biconnector/Dataset/Result/ + + ./tests/Integration/Services/Sign/ + + + ./tests/Integration/Services/Sign/B2e/Document/Service/ + ./tests/Integration/Services/Sign/B2e/Document/Result/ + + + ./tests/Integration/Services/Sign/B2e/CompanyProvider/Service/ + ./tests/Integration/Services/Sign/B2e/CompanyProvider/Result/ + + + ./tests/Integration/Services/Sign/B2e/PersonalTail/Service/ + ./tests/Integration/Services/Sign/B2e/PersonalTail/Result/ + + + ./tests/Integration/Services/Sign/B2e/MySafeTail/Service/ + ./tests/Integration/Services/Sign/B2e/MySafeTail/Result/ + diff --git a/rector.php b/rector.php index b40555a6..e735cdf4 100644 --- a/rector.php +++ b/rector.php @@ -85,6 +85,8 @@ __DIR__ . '/tests/Unit/', __DIR__ . '/src/Services/Timeman', __DIR__ . '/tests/Integration/Services/Timeman', + __DIR__ . '/src/Services/Sign', + __DIR__ . '/tests/Integration/Services/Sign', ]) ->withCache(cacheDirectory: __DIR__ . '/var/.cache/rector') ->withSets( diff --git a/src/Services/RemoteEventsFactory.php b/src/Services/RemoteEventsFactory.php index 112159f4..c5da7302 100644 --- a/src/Services/RemoteEventsFactory.php +++ b/src/Services/RemoteEventsFactory.php @@ -29,6 +29,7 @@ use Bitrix24\SDK\Services\IMOpenLines\Events\IMOpenLinesEventsFactory; use Bitrix24\SDK\Services\SonetGroup\Events\SonetGroupEventsFactory; use Bitrix24\SDK\Services\Telephony\Events\TelephonyEventsFactory; +use Bitrix24\SDK\Services\Sign\Events\SignB2eEventsFactory; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; @@ -81,9 +82,9 @@ public function create(Request $request): EventInterface } $event = new UnsupportedRemoteEvent($request); - foreach ($this->eventsFabrics as $itemFabric) { - if ($itemFabric->isSupport($payload['event'])) { - $event = $itemFabric->create($request); + foreach ($this->eventsFabrics as $eventFabric) { + if ($eventFabric->isSupport($payload['event'])) { + $event = $eventFabric->create($request); break; } } @@ -155,6 +156,7 @@ public function createEvent(Request $request, ?string $applicationToken): EventI ]); throw new InvalidArgumentException('key «event» not found in request payload'); } + if ($applicationToken !== null && trim($applicationToken) === '') { throw new InvalidArgumentException('application token cannot be empty'); } @@ -166,9 +168,9 @@ public function createEvent(Request $request, ?string $applicationToken): EventI ]); $event = new UnsupportedRemoteEvent($request); - foreach ($this->eventsFabrics as $itemFabric) { - if ($itemFabric->isSupport($eventCode)) { - $event = $itemFabric->create($request); + foreach ($this->eventsFabrics as $eventFabric) { + if ($eventFabric->isSupport($eventCode)) { + $event = $eventFabric->create($request); break; } } @@ -225,6 +227,7 @@ public static function init(LoggerInterface $logger): self new IMOpenLinesEventsFactory(), new SonetGroupEventsFactory(), new Sale\Events\SaleEventsFactory(), + new SignB2eEventsFactory(), ], $logger ); diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 3d245be1..7325cec6 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -42,6 +42,7 @@ use Bitrix24\SDK\Legacy\LegacyServiceBuilder; use Bitrix24\SDK\Services\Lists\ListsServiceBuilder; use Bitrix24\SDK\Services\Rest\RestServiceBuilder; +use Bitrix24\SDK\Services\Sign\SignServiceBuilder; use Bitrix24\SDK\Services\Timeman\TimemanServiceBuilder; use Psr\Log\LoggerInterface; @@ -210,9 +211,6 @@ public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return MainServiceBuilder - */ public function getMainScope(): MainServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -255,9 +253,6 @@ public function getUserScope(): UserServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return PlacementServiceBuilder - */ public function getPlacementScope(): PlacementServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -440,4 +435,18 @@ public function getTimemanScope(): TimemanServiceBuilder return $this->serviceCache[__METHOD__]; } + public function getSignScope(): SignServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new SignServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + } diff --git a/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php new file mode 100644 index 00000000..806ded78 --- /dev/null +++ b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.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\Sign\B2e\CompanyProvider\Result; + +use Bitrix24\SDK\Core\Result\AbstractAnnotatedItem; +use Carbon\CarbonImmutable; + +/** + * @property-read string|null $code Signature provider code + * @property-read string|null $uid Unique identifier of the provider + * @property-read string|null $name Provider display name + * @property-read CarbonImmutable|null $date Provider activation date + * @property-read CarbonImmutable|null $expires Provider expiration date + */ +class CompanyProviderItemResult extends AbstractAnnotatedItem +{ +} + diff --git a/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php new file mode 100644 index 00000000..68b32786 --- /dev/null +++ b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.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\Sign\B2e\CompanyProvider\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class CompanyProvidersResult extends AbstractResult +{ + /** + * @return CompanyProviderItemResult[] + * @throws BaseException + */ + public function getProviders(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new CompanyProviderItemResult($item); + } + + return $items; + } +} + diff --git a/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php b/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php new file mode 100644 index 00000000..1c83094a --- /dev/null +++ b/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php @@ -0,0 +1,79 @@ + + * + * 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\Sign\B2e\CompanyProvider\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\Services\AbstractService; +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Result\CompanyProvidersResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['sign.b2e']))] +class CompanyProvider extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Returns the list of signature providers for a selected company. + * + * @link https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-company-provider-list.html + * + * @param string|null $companyUuid Company UUID in HCM Link (required if companyCrmId is not provided) + * @param int|null $companyCrmId Company CRM identifier (required if companyUuid is not provided) + * @param string|null $language Language for provider name localisation (default: en) + * @param int $limit Number of records per page (1–1000, default: 100) + * @param int $offset Pagination offset (default: 0) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sign.b2e.company.provider.list', + 'https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-company-provider-list.html', + 'Returns the list of signature providers for a selected company.' + )] + public function list( + ?string $companyUuid = null, + ?int $companyCrmId = null, + ?string $language = null, + int $limit = 100, + int $offset = 0 + ): CompanyProvidersResult { + $params = [ + 'limit' => $limit, + 'offset' => $offset, + ]; + if ($companyUuid !== null) { + $params['companyUuid'] = $companyUuid; + } + + if ($companyCrmId !== null) { + $params['companyCrmId'] = $companyCrmId; + } + + if ($language !== null) { + $params['language'] = $language; + } + + return new CompanyProvidersResult($this->core->call('sign.b2e.company.provider.list', $params)); + } +} + diff --git a/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php b/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php new file mode 100644 index 00000000..a12bfcbb --- /dev/null +++ b/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php @@ -0,0 +1,26 @@ + + * + * 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\Sign\B2e\Document\Result; + +use Bitrix24\SDK\Core\Result\AbstractAnnotatedItem; + +/** + * @property-read string|null $uid Unique identifier of the document + * @property-read array|null $state Document status with 'code' and 'name' keys + * @property-read array>|null $members List of signing members + */ +class DocumentItemResult extends AbstractAnnotatedItem +{ +} + diff --git a/src/Services/Sign/B2e/Document/Result/DocumentResult.php b/src/Services/Sign/B2e/Document/Result/DocumentResult.php new file mode 100644 index 00000000..6c6cd304 --- /dev/null +++ b/src/Services/Sign/B2e/Document/Result/DocumentResult.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\Sign\B2e\Document\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class DocumentResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getDocument(): DocumentItemResult + { + return new DocumentItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} + diff --git a/src/Services/Sign/B2e/Document/Service/Document.php b/src/Services/Sign/B2e/Document/Service/Document.php new file mode 100644 index 00000000..823e225b --- /dev/null +++ b/src/Services/Sign/B2e/Document/Service/Document.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\Sign\B2e\Document\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\Services\AbstractService; +use Bitrix24\SDK\Services\Sign\B2e\Document\Result\DocumentResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['sign.b2e']))] +class Document extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Sends a document for company-side signing (КЭДО). + * + * @link https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-document-send.html + * + * @param array{ + * company?: array, + * members?: array, + * responsible?: array{userId: int}, + * companyProviderUid?: string, + * files?: array, + * regionDocumentType?: string, + * externalSettings?: array, + * language?: string + * } $fields Document fields + * @param string|null $language Language for status localisation in response (default: en) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sign.b2e.document.send', + 'https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-document-send.html', + 'Sends a document for company-side signing (КЭДО). Requires application context.' + )] + public function send(array $fields, ?string $language = null): DocumentResult + { + $params = ['fields' => $fields]; + if ($language !== null) { + $params['language'] = $language; + } + + return new DocumentResult($this->core->call('sign.b2e.document.send', $params)); + } + + /** + * Returns information about a document and its signing members. + * + * @link https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-document-get.html + * + * @param string $uid Unique document identifier + * @param string|null $language Language for status localisation in response (default: en) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sign.b2e.document.get', + 'https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-document-get.html', + 'Returns information about a document and its signing members.' + )] + public function get(string $uid, ?string $language = null): DocumentResult + { + $params = ['uid' => $uid]; + if ($language !== null) { + $params['language'] = $language; + } + + return new DocumentResult($this->core->call('sign.b2e.document.get', $params)); + } +} + diff --git a/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php new file mode 100644 index 00000000..d1a831d6 --- /dev/null +++ b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php @@ -0,0 +1,32 @@ + + * + * 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\Sign\B2e\MySafeTail\Result; + +use Bitrix24\SDK\Core\Result\AbstractAnnotatedItem; +use Carbon\CarbonImmutable; + +/** + * @property-read int|null $id Signed document identifier + * @property-read string|null $title Document title + * @property-read CarbonImmutable|null $create_date Document creation date + * @property-read CarbonImmutable|null $signed_date Document signing date + * @property-read int|null $creator_id User ID who created the document + * @property-read int|null $member_id User ID of the signing party + * @property-read string|null $role Employee role in the document: editor, reviewer, assignee, signer + * @property-read string|null $file_url Download URL for the signed document + */ +class MySafeTailItemResult extends AbstractAnnotatedItem +{ +} + diff --git a/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php new file mode 100644 index 00000000..dd27803c --- /dev/null +++ b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.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\Sign\B2e\MySafeTail\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class MySafeTailResult extends AbstractResult +{ + /** + * @return MySafeTailItemResult[] + * @throws BaseException + */ + public function getItems(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new MySafeTailItemResult($item); + } + + return $items; + } +} + diff --git a/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php b/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php new file mode 100644 index 00000000..bffee563 --- /dev/null +++ b/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php @@ -0,0 +1,60 @@ + + * + * 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\Sign\B2e\MySafeTail\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\Services\AbstractService; +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Result\MySafeTailResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['sign.b2e']))] +class MySafeTail extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Returns the list of signed documents in the company safe. + * + * @link https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-mysafe-tail.html + * + * @param int $limit Number of records per page (1–50, default: 20) + * @param int $offset Pagination offset (default: 0) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sign.b2e.mysafe.tail', + 'https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-mysafe-tail.html', + 'Returns the list of signed documents in the company safe. Requires application context.' + )] + public function tail(int $limit = 20, int $offset = 0): MySafeTailResult + { + return new MySafeTailResult( + $this->core->call('sign.b2e.mysafe.tail', [ + 'limit' => $limit, + 'offset' => $offset, + ]) + ); + } +} + diff --git a/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php new file mode 100644 index 00000000..e8b7a2ef --- /dev/null +++ b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php @@ -0,0 +1,28 @@ + + * + * 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\Sign\B2e\PersonalTail\Result; + +use Bitrix24\SDK\Core\Result\AbstractAnnotatedItem; +use Carbon\CarbonImmutable; + +/** + * @property-read int|null $id Signed document identifier + * @property-read string|null $title Document title + * @property-read CarbonImmutable|null $signed_date Document signing date + * @property-read string|null $file_url Download URL for the signed document + */ +class PersonalTailItemResult extends AbstractAnnotatedItem +{ +} + diff --git a/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php new file mode 100644 index 00000000..5ee90aa4 --- /dev/null +++ b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.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\Sign\B2e\PersonalTail\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PersonalTailResult extends AbstractResult +{ + /** + * @return PersonalTailItemResult[] + * @throws BaseException + */ + public function getItems(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new PersonalTailItemResult($item); + } + + return $items; + } +} + diff --git a/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php b/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php new file mode 100644 index 00000000..8c0644f8 --- /dev/null +++ b/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php @@ -0,0 +1,60 @@ + + * + * 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\Sign\B2e\PersonalTail\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\Services\AbstractService; +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Result\PersonalTailResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['sign.b2e']))] +class PersonalTail extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Returns the list of signed documents for the current user from the КЭДО section. + * + * @link https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-personal-tail.html + * + * @param int $limit Number of records per page (1–50, default: 20) + * @param int $offset Pagination offset (default: 0) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'sign.b2e.personal.tail', + 'https://apidocs.bitrix24.com/api-reference/sign/sign-b2e-personal-tail.html', + 'Returns the list of signed documents for the current user from the КЭДО section. Requires application context.' + )] + public function tail(int $limit = 20, int $offset = 0): PersonalTailResult + { + return new PersonalTailResult( + $this->core->call('sign.b2e.personal.tail', [ + 'limit' => $limit, + 'offset' => $offset, + ]) + ); + } +} + diff --git a/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php new file mode 100644 index 00000000..499daedf --- /dev/null +++ b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php @@ -0,0 +1,32 @@ + + * + * 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\Sign\Events\OnSignB2eDocumentStatusChanged; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +/** + * Event fired when the status of a sign.b2e document changes. + * + * @link https://apidocs.bitrix24.com/api-reference/sign/events/on-sign-b2e-document-status-changed.html + */ +class OnSignB2eDocumentStatusChanged extends AbstractEventRequest +{ + public const CODE = 'ONSIGNB2EDOCUMENTSTATUSCHANGED'; + + public function getPayload(): OnSignB2eDocumentStatusChangedPayload + { + return new OnSignB2eDocumentStatusChangedPayload($this->eventPayload['data']); + } +} + diff --git a/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php new file mode 100644 index 00000000..04242472 --- /dev/null +++ b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php @@ -0,0 +1,27 @@ + + * + * 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\Sign\Events\OnSignB2eDocumentStatusChanged; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $documentUid Unique document identifier + * @property-read string|null $companyUid Unique company identifier (present when a company integration exists) + * @property-read string $statusCode Document status code + * @property-read string $statusName Document status name + */ +class OnSignB2eDocumentStatusChangedPayload extends AbstractItem +{ +} + diff --git a/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php new file mode 100644 index 00000000..99cd180f --- /dev/null +++ b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php @@ -0,0 +1,32 @@ + + * + * 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\Sign\Events\OnSignB2eMemberStatusChanged; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +/** + * Event fired when the status of a sign.b2e document member changes. + * + * @link https://apidocs.bitrix24.com/api-reference/sign/events/on-sign-b2e-member-status-changed.html + */ +class OnSignB2eMemberStatusChanged extends AbstractEventRequest +{ + public const CODE = 'ONSIGNB2EMEMBERSTATUSCHANGED'; + + public function getPayload(): OnSignB2eMemberStatusChangedPayload + { + return new OnSignB2eMemberStatusChangedPayload($this->eventPayload['data']); + } +} + diff --git a/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php new file mode 100644 index 00000000..2c1bb668 --- /dev/null +++ b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php @@ -0,0 +1,28 @@ + + * + * 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\Sign\Events\OnSignB2eMemberStatusChanged; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $memberUid Unique member identifier + * @property-read string $documentUid Unique document identifier + * @property-read string|null $companyUid Unique company identifier (present when a company integration exists) + * @property-read string $statusCode Member status code + * @property-read string $statusName Member status name + */ +class OnSignB2eMemberStatusChangedPayload extends AbstractItem +{ +} + diff --git a/src/Services/Sign/Events/SignB2eEventsFactory.php b/src/Services/Sign/Events/SignB2eEventsFactory.php new file mode 100644 index 00000000..0732827a --- /dev/null +++ b/src/Services/Sign/Events/SignB2eEventsFactory.php @@ -0,0 +1,58 @@ + + * + * 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\Sign\Events; + +use Bitrix24\SDK\Core\Contracts\Events\EventInterface; +use Bitrix24\SDK\Core\Contracts\Events\EventsFabricInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Services\Sign\Events\OnSignB2eDocumentStatusChanged\OnSignB2eDocumentStatusChanged; +use Bitrix24\SDK\Services\Sign\Events\OnSignB2eMemberStatusChanged\OnSignB2eMemberStatusChanged; +use Symfony\Component\HttpFoundation\Request; + +readonly class SignB2eEventsFactory implements EventsFabricInterface +{ + #[\Override] + public function isSupport(string $eventCode): bool + { + return in_array(strtoupper($eventCode), [ + OnSignB2eDocumentStatusChanged::CODE, + OnSignB2eMemberStatusChanged::CODE, + ], true); + } + + /** + * @throws InvalidArgumentException + */ + #[\Override] + public function create(Request $eventRequest): EventInterface + { + $eventPayload = $eventRequest->request->all(); + if (!array_key_exists('event', $eventPayload)) { + throw new InvalidArgumentException('«event» key not found in event payload'); + } + + $eventCode = strtoupper((string) $eventPayload['event']); + + return match ($eventCode) { + OnSignB2eDocumentStatusChanged::CODE => new OnSignB2eDocumentStatusChanged($eventRequest), + OnSignB2eMemberStatusChanged::CODE => new OnSignB2eMemberStatusChanged($eventRequest), + default => throw new InvalidArgumentException( + sprintf('Unexpected event code «%s»', $eventCode) + ), + }; + } +} + + + diff --git a/src/Services/Sign/SignServiceBuilder.php b/src/Services/Sign/SignServiceBuilder.php new file mode 100644 index 00000000..975166e4 --- /dev/null +++ b/src/Services/Sign/SignServiceBuilder.php @@ -0,0 +1,75 @@ + + * + * 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\Sign; + +use Bitrix24\SDK\Attributes\ApiServiceBuilderMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Service\CompanyProvider; +use Bitrix24\SDK\Services\Sign\B2e\Document\Service\Document; +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Service\MySafeTail; +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Service\PersonalTail; + +#[ApiServiceBuilderMetadata(new Scope(['sign.b2e']))] +class SignServiceBuilder extends AbstractServiceBuilder +{ + /** + * Document service for sign.b2e.document.* methods. + */ + public function document(): Document + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Document($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * Company provider service for sign.b2e.company.provider.* methods. + */ + public function companyProvider(): CompanyProvider + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new CompanyProvider($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * Personal tail service for sign.b2e.personal.tail method. + */ + public function personalTail(): PersonalTail + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new PersonalTail($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * My safe tail service for sign.b2e.mysafe.tail method. + */ + public function mySafeTail(): MySafeTail + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new MySafeTail($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} + diff --git a/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php new file mode 100644 index 00000000..d105f982 --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php @@ -0,0 +1,58 @@ + + * + * 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\Sign\B2e\CompanyProvider\Result; + +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Result\CompanyProviderItemResult; +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Service\CompanyProvider; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CompanyProviderItemResult::class)] +class CompanyProviderItemResultAnnotationsTest extends TestCase +{ + use CustomBitrix24Assertions; + + private CompanyProvider $companyProviderService; + + #[\Override] + protected function setUp(): void + { + $this->companyProviderService = Factory::getServiceBuilder()->getSignScope()->companyProvider(); + } + + #[Test] + #[TestDox('testAllSystemFieldsAnnotated: all fields in CompanyProviderItemResult are annotated in phpdoc')] + public function testAllSystemFieldsAnnotated(): void + { + $this->markTestSkipped( + 'sign.b2e.company.provider.list requires a valid company CRM ID with КЭДО integration. ' . + 'Run manually with a real companyCrmId to verify annotation completeness.' + ); + } + + #[Test] + #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in CompanyProviderItemResult have valid type annotations')] + public function testAllSystemFieldsHasValidTypeAnnotation(): void + { + $this->markTestSkipped( + 'sign.b2e.company.provider.list requires a valid company CRM ID with КЭДО integration. ' . + 'Run manually with a real companyCrmId to verify annotation types.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php b/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php new file mode 100644 index 00000000..0b63eefd --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php @@ -0,0 +1,41 @@ + + * + * 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\Sign\B2e\CompanyProvider\Service; + +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Service\CompanyProvider; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CompanyProvider::class)] +class CompanyProviderTest extends TestCase +{ + #[\Override] + protected function setUp() : void + { + } + + #[Test] + #[TestDox('sign.b2e.company.provider.list returns CompanyProvidersResult')] + public function testListReturnsCompanyProvidersResult(): void + { + $this->markTestSkipped( + 'sign.b2e.company.provider.list requires a valid company CRM ID with КЭДО integration. ' . + 'Run manually with a real companyCrmId to verify.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php new file mode 100644 index 00000000..78dda444 --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php @@ -0,0 +1,58 @@ + + * + * 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\Sign\B2e\Document\Result; + +use Bitrix24\SDK\Services\Sign\B2e\Document\Result\DocumentItemResult; +use Bitrix24\SDK\Services\Sign\B2e\Document\Service\Document; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(DocumentItemResult::class)] +class DocumentItemResultAnnotationsTest extends TestCase +{ + use CustomBitrix24Assertions; + + private Document $documentService; + + #[\Override] + protected function setUp(): void + { + $this->documentService = Factory::getServiceBuilder()->getSignScope()->document(); + } + + #[Test] + #[TestDox('testAllSystemFieldsAnnotated: all fields in DocumentItemResult are annotated in phpdoc')] + public function testAllSystemFieldsAnnotated(): void + { + $this->markTestSkipped( + 'sign.b2e.document.get requires application context and a valid КЭДО document UID. ' . + 'Run manually with a real document UID to verify annotation completeness.' + ); + } + + #[Test] + #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in DocumentItemResult have valid type annotations')] + public function testAllSystemFieldsHasValidTypeAnnotation(): void + { + $this->markTestSkipped( + 'sign.b2e.document.get requires application context and a valid КЭДО document UID. ' . + 'Run manually with a real document UID to verify annotation types.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php b/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php new file mode 100644 index 00000000..d68cbac8 --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php @@ -0,0 +1,50 @@ + + * + * 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\Sign\B2e\Document\Service; + +use Bitrix24\SDK\Services\Sign\B2e\Document\Result\DocumentResult; +use Bitrix24\SDK\Services\Sign\B2e\Document\Service\Document; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Document::class)] +class DocumentTest extends TestCase +{ + #[\Override] + protected function setUp() : void + { + } + + #[Test] + #[TestDox('sign.b2e.document.get returns DocumentResult for a known document UID')] + public function testGetReturnsDocumentResult(): void + { + $this->markTestSkipped( + 'sign.b2e.document.get requires application context and a valid document UID from a real КЭДО environment.' + ); + } + + #[Test] + #[TestDox('sign.b2e.document.send returns DocumentResult')] + public function testSendReturnsDocumentResult(): void + { + $this->markTestSkipped( + 'sign.b2e.document.send requires application context, sign.b2e scope and a real КЭДО environment.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php new file mode 100644 index 00000000..3093834d --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php @@ -0,0 +1,58 @@ + + * + * 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\Sign\B2e\MySafeTail\Result; + +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Result\MySafeTailItemResult; +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Service\MySafeTail; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(MySafeTailItemResult::class)] +class MySafeTailItemResultAnnotationsTest extends TestCase +{ + use CustomBitrix24Assertions; + + private MySafeTail $mySafeTailService; + + #[\Override] + protected function setUp(): void + { + $this->mySafeTailService = Factory::getServiceBuilder()->getSignScope()->mySafeTail(); + } + + #[Test] + #[TestDox('testAllSystemFieldsAnnotated: all fields in MySafeTailItemResult are annotated in phpdoc')] + public function testAllSystemFieldsAnnotated(): void + { + $this->markTestSkipped( + 'sign.b2e.mysafe.tail requires application context (not webhook). ' . + 'Run manually with OAuth application context to verify annotation completeness.' + ); + } + + #[Test] + #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in MySafeTailItemResult have valid type annotations')] + public function testAllSystemFieldsHasValidTypeAnnotation(): void + { + $this->markTestSkipped( + 'sign.b2e.mysafe.tail requires application context (not webhook). ' . + 'Run manually with OAuth application context to verify annotation types.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php b/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php new file mode 100644 index 00000000..166f494c --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php @@ -0,0 +1,41 @@ + + * + * 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\Sign\B2e\MySafeTail\Service; + +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Service\MySafeTail; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(MySafeTail::class)] +class MySafeTailTest extends TestCase +{ + #[\Override] + protected function setUp() : void + { + } + + #[Test] + #[TestDox('sign.b2e.mysafe.tail returns MySafeTailResult')] + public function testTailReturnsMySafeTailResult(): void + { + $this->markTestSkipped( + 'sign.b2e.mysafe.tail requires application context (not webhook). ' . + 'Run manually with OAuth application context to verify.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php new file mode 100644 index 00000000..644c58b6 --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php @@ -0,0 +1,58 @@ + + * + * 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\Sign\B2e\PersonalTail\Result; + +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Result\PersonalTailItemResult; +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Service\PersonalTail; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(PersonalTailItemResult::class)] +class PersonalTailItemResultAnnotationsTest extends TestCase +{ + use CustomBitrix24Assertions; + + private PersonalTail $personalTailService; + + #[\Override] + protected function setUp(): void + { + $this->personalTailService = Factory::getServiceBuilder()->getSignScope()->personalTail(); + } + + #[Test] + #[TestDox('testAllSystemFieldsAnnotated: all fields in PersonalTailItemResult are annotated in phpdoc')] + public function testAllSystemFieldsAnnotated(): void + { + $this->markTestSkipped( + 'sign.b2e.personal.tail requires application context (not webhook). ' . + 'Run manually with OAuth application context to verify annotation completeness.' + ); + } + + #[Test] + #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in PersonalTailItemResult have valid type annotations')] + public function testAllSystemFieldsHasValidTypeAnnotation(): void + { + $this->markTestSkipped( + 'sign.b2e.personal.tail requires application context (not webhook). ' . + 'Run manually with OAuth application context to verify annotation types.' + ); + } +} + diff --git a/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php b/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php new file mode 100644 index 00000000..8425ad32 --- /dev/null +++ b/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php @@ -0,0 +1,42 @@ + + * + * 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\Sign\B2e\PersonalTail\Service; + +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Result\PersonalTailResult; +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Service\PersonalTail; +use Bitrix24\SDK\Tests\Integration\Factory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(PersonalTail::class)] +class PersonalTailTest extends TestCase +{ + #[\Override] + protected function setUp() : void + { + } + + #[Test] + #[TestDox('sign.b2e.personal.tail returns PersonalTailResult')] + public function testTailReturnsPersonalTailResult(): void + { + $this->markTestSkipped( + 'sign.b2e.personal.tail requires application context (not webhook). ' . + 'Run manually with OAuth application context to verify.' + ); + } +} + diff --git a/tests/Unit/Services/Sign/SignServiceBuilderTest.php b/tests/Unit/Services/Sign/SignServiceBuilderTest.php new file mode 100644 index 00000000..2675f9c0 --- /dev/null +++ b/tests/Unit/Services/Sign/SignServiceBuilderTest.php @@ -0,0 +1,64 @@ + + * + * 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\Unit\Services\Sign; + +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Service\CompanyProvider; +use Bitrix24\SDK\Services\Sign\B2e\Document\Service\Document; +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Service\MySafeTail; +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Service\PersonalTail; +use Bitrix24\SDK\Services\Sign\SignServiceBuilder; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(SignServiceBuilder::class)] +class SignServiceBuilderTest extends TestCase +{ + #[Test] + #[TestDox('SignServiceBuilder class exists and can be instantiated')] + public function testSignServiceBuilderExists(): void + { + $this->assertTrue(class_exists(SignServiceBuilder::class)); + } + + #[Test] + #[TestDox('Document service class exists')] + public function testDocumentServiceClassExists(): void + { + $this->assertTrue(class_exists(Document::class)); + } + + #[Test] + #[TestDox('CompanyProvider service class exists')] + public function testCompanyProviderServiceClassExists(): void + { + $this->assertTrue(class_exists(CompanyProvider::class)); + } + + #[Test] + #[TestDox('PersonalTail service class exists')] + public function testPersonalTailServiceClassExists(): void + { + $this->assertTrue(class_exists(PersonalTail::class)); + } + + #[Test] + #[TestDox('MySafeTail service class exists')] + public function testMySafeTailServiceClassExists(): void + { + $this->assertTrue(class_exists(MySafeTail::class)); + } +} + From 95fc9361a7ebaa044df90af0640917cbfcf6a720 Mon Sep 17 00:00:00 2001 From: Dmitriy Ignatenko Date: Mon, 29 Jun 2026 18:07:54 +0400 Subject: [PATCH 2/5] Minor fix --- src/Services/ServiceBuilder.php | 1 - .../B2e/CompanyProvider/Result/CompanyProviderItemResult.php | 1 - .../Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php | 1 - .../Sign/B2e/CompanyProvider/Service/CompanyProvider.php | 1 - src/Services/Sign/B2e/Document/Result/DocumentItemResult.php | 1 - src/Services/Sign/B2e/Document/Result/DocumentResult.php | 1 - src/Services/Sign/B2e/Document/Service/Document.php | 1 - .../Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php | 1 - src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php | 1 - src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php | 1 - .../Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php | 1 - .../Sign/B2e/PersonalTail/Result/PersonalTailResult.php | 1 - src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php | 1 - .../OnSignB2eDocumentStatusChanged.php | 1 - .../OnSignB2eDocumentStatusChangedPayload.php | 1 - .../OnSignB2eMemberStatusChanged.php | 1 - .../OnSignB2eMemberStatusChangedPayload.php | 1 - src/Services/Sign/Events/SignB2eEventsFactory.php | 3 --- src/Services/Sign/SignServiceBuilder.php | 1 - .../Result/CompanyProviderItemResultAnnotationsTest.php | 1 - .../Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php | 1 - .../B2e/Document/Result/DocumentItemResultAnnotationsTest.php | 1 - .../Services/Sign/B2e/Document/Service/DocumentTest.php | 1 - .../MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php | 1 - .../Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php | 1 - .../Result/PersonalTailItemResultAnnotationsTest.php | 1 - .../Sign/B2e/PersonalTail/Service/PersonalTailTest.php | 1 - tests/Unit/Services/Sign/SignServiceBuilderTest.php | 1 - 28 files changed, 30 deletions(-) diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 7325cec6..16c9fb5d 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -448,5 +448,4 @@ public function getSignScope(): SignServiceBuilder return $this->serviceCache[__METHOD__]; } - } diff --git a/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php index 806ded78..b40e9045 100644 --- a/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php +++ b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResult.php @@ -26,4 +26,3 @@ class CompanyProviderItemResult extends AbstractAnnotatedItem { } - diff --git a/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php index 68b32786..d1ca4c6f 100644 --- a/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php +++ b/src/Services/Sign/B2e/CompanyProvider/Result/CompanyProvidersResult.php @@ -32,4 +32,3 @@ public function getProviders(): array return $items; } } - diff --git a/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php b/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php index 1c83094a..2f85cd53 100644 --- a/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php +++ b/src/Services/Sign/B2e/CompanyProvider/Service/CompanyProvider.php @@ -76,4 +76,3 @@ public function list( return new CompanyProvidersResult($this->core->call('sign.b2e.company.provider.list', $params)); } } - diff --git a/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php b/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php index a12bfcbb..aa3a300e 100644 --- a/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php +++ b/src/Services/Sign/B2e/Document/Result/DocumentItemResult.php @@ -23,4 +23,3 @@ class DocumentItemResult extends AbstractAnnotatedItem { } - diff --git a/src/Services/Sign/B2e/Document/Result/DocumentResult.php b/src/Services/Sign/B2e/Document/Result/DocumentResult.php index 6c6cd304..56ab2da7 100644 --- a/src/Services/Sign/B2e/Document/Result/DocumentResult.php +++ b/src/Services/Sign/B2e/Document/Result/DocumentResult.php @@ -26,4 +26,3 @@ public function getDocument(): DocumentItemResult return new DocumentItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } - diff --git a/src/Services/Sign/B2e/Document/Service/Document.php b/src/Services/Sign/B2e/Document/Service/Document.php index 823e225b..28bede8e 100644 --- a/src/Services/Sign/B2e/Document/Service/Document.php +++ b/src/Services/Sign/B2e/Document/Service/Document.php @@ -92,4 +92,3 @@ public function get(string $uid, ?string $language = null): DocumentResult return new DocumentResult($this->core->call('sign.b2e.document.get', $params)); } } - diff --git a/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php index d1a831d6..23de29b0 100644 --- a/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php +++ b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResult.php @@ -29,4 +29,3 @@ class MySafeTailItemResult extends AbstractAnnotatedItem { } - diff --git a/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php index dd27803c..696c0d90 100644 --- a/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php +++ b/src/Services/Sign/B2e/MySafeTail/Result/MySafeTailResult.php @@ -32,4 +32,3 @@ public function getItems(): array return $items; } } - diff --git a/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php b/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php index bffee563..ad623beb 100644 --- a/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php +++ b/src/Services/Sign/B2e/MySafeTail/Service/MySafeTail.php @@ -57,4 +57,3 @@ public function tail(int $limit = 20, int $offset = 0): MySafeTailResult ); } } - diff --git a/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php index e8b7a2ef..0735014a 100644 --- a/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php +++ b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResult.php @@ -25,4 +25,3 @@ class PersonalTailItemResult extends AbstractAnnotatedItem { } - diff --git a/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php index 5ee90aa4..1254b400 100644 --- a/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php +++ b/src/Services/Sign/B2e/PersonalTail/Result/PersonalTailResult.php @@ -32,4 +32,3 @@ public function getItems(): array return $items; } } - diff --git a/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php b/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php index 8c0644f8..092416af 100644 --- a/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php +++ b/src/Services/Sign/B2e/PersonalTail/Service/PersonalTail.php @@ -57,4 +57,3 @@ public function tail(int $limit = 20, int $offset = 0): PersonalTailResult ); } } - diff --git a/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php index 499daedf..25b6e451 100644 --- a/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php +++ b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChanged.php @@ -29,4 +29,3 @@ public function getPayload(): OnSignB2eDocumentStatusChangedPayload return new OnSignB2eDocumentStatusChangedPayload($this->eventPayload['data']); } } - diff --git a/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php index 04242472..9df3e38e 100644 --- a/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php +++ b/src/Services/Sign/Events/OnSignB2eDocumentStatusChanged/OnSignB2eDocumentStatusChangedPayload.php @@ -24,4 +24,3 @@ class OnSignB2eDocumentStatusChangedPayload extends AbstractItem { } - diff --git a/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php index 99cd180f..e54cabfc 100644 --- a/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php +++ b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChanged.php @@ -29,4 +29,3 @@ public function getPayload(): OnSignB2eMemberStatusChangedPayload return new OnSignB2eMemberStatusChangedPayload($this->eventPayload['data']); } } - diff --git a/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php index 2c1bb668..76ede3e0 100644 --- a/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php +++ b/src/Services/Sign/Events/OnSignB2eMemberStatusChanged/OnSignB2eMemberStatusChangedPayload.php @@ -25,4 +25,3 @@ class OnSignB2eMemberStatusChangedPayload extends AbstractItem { } - diff --git a/src/Services/Sign/Events/SignB2eEventsFactory.php b/src/Services/Sign/Events/SignB2eEventsFactory.php index 0732827a..d4eb11b0 100644 --- a/src/Services/Sign/Events/SignB2eEventsFactory.php +++ b/src/Services/Sign/Events/SignB2eEventsFactory.php @@ -53,6 +53,3 @@ public function create(Request $eventRequest): EventInterface }; } } - - - diff --git a/src/Services/Sign/SignServiceBuilder.php b/src/Services/Sign/SignServiceBuilder.php index 975166e4..556d73f1 100644 --- a/src/Services/Sign/SignServiceBuilder.php +++ b/src/Services/Sign/SignServiceBuilder.php @@ -72,4 +72,3 @@ public function mySafeTail(): MySafeTail return $this->serviceCache[__METHOD__]; } } - diff --git a/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php index d105f982..5c59fd0c 100644 --- a/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php @@ -55,4 +55,3 @@ public function testAllSystemFieldsHasValidTypeAnnotation(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php b/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php index 0b63eefd..cd085904 100644 --- a/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php +++ b/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php @@ -38,4 +38,3 @@ public function testListReturnsCompanyProvidersResult(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php index 78dda444..a3db46b0 100644 --- a/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php @@ -55,4 +55,3 @@ public function testAllSystemFieldsHasValidTypeAnnotation(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php b/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php index d68cbac8..be85c1a1 100644 --- a/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php +++ b/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php @@ -47,4 +47,3 @@ public function testSendReturnsDocumentResult(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php index 3093834d..48232db8 100644 --- a/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php @@ -55,4 +55,3 @@ public function testAllSystemFieldsHasValidTypeAnnotation(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php b/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php index 166f494c..7da482ba 100644 --- a/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php +++ b/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php @@ -38,4 +38,3 @@ public function testTailReturnsMySafeTailResult(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php index 644c58b6..05b197f7 100644 --- a/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php @@ -55,4 +55,3 @@ public function testAllSystemFieldsHasValidTypeAnnotation(): void ); } } - diff --git a/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php b/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php index 8425ad32..3aa53406 100644 --- a/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php +++ b/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php @@ -39,4 +39,3 @@ public function testTailReturnsPersonalTailResult(): void ); } } - diff --git a/tests/Unit/Services/Sign/SignServiceBuilderTest.php b/tests/Unit/Services/Sign/SignServiceBuilderTest.php index 2675f9c0..010828c6 100644 --- a/tests/Unit/Services/Sign/SignServiceBuilderTest.php +++ b/tests/Unit/Services/Sign/SignServiceBuilderTest.php @@ -61,4 +61,3 @@ public function testMySafeTailServiceClassExists(): void $this->assertTrue(class_exists(MySafeTail::class)); } } - From 993af4297199735125fbed2d49556d34f5e69ad3 Mon Sep 17 00:00:00 2001 From: Dmitriy Ignatenko Date: Mon, 29 Jun 2026 18:50:57 +0400 Subject: [PATCH 3/5] Implement integration tests --- phpstan.neon.dist | 2 +- tests/.env | 10 ++- ...mpanyProviderItemResultAnnotationsTest.php | 74 +++++++++++++++-- .../Service/CompanyProviderTest.php | 81 +++++++++++++++++-- .../DocumentItemResultAnnotationsTest.php | 62 ++++++++++++-- .../B2e/Document/Service/DocumentTest.php | 65 ++++++++++++--- .../MySafeTailItemResultAnnotationsTest.php | 56 +++++++++++-- .../B2e/MySafeTail/Service/MySafeTailTest.php | 56 +++++++++++-- .../PersonalTailItemResultAnnotationsTest.php | 56 +++++++++++-- .../PersonalTail/Service/PersonalTailTest.php | 54 +++++++++++-- 10 files changed, 455 insertions(+), 61 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 584ae289..80f52949 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -40,7 +40,7 @@ parameters: - tests/Integration/Services/CRM/Documentgenerator/Document - tests/Integration/Services/CRM/Documentgenerator/Template - tests/Integration/Services/Timeman - - tests/Unit/Services/Sign + - tests/Integration/Services/Sign excludePaths: # TODO: Fix type errors in RequisiteUserfieldUseCaseTest and remove this exclusion # Tracking: https://github.com/bitrix24/b24phpsdk/issues diff --git a/tests/.env b/tests/.env index 6335d1ec..cb7603bf 100644 --- a/tests/.env +++ b/tests/.env @@ -17,12 +17,20 @@ APP_ENV=dev BITRIX24_WEBHOOK= + # monolog log level INTEGRATION_TEST_LOG_LEVEL=100 LOGS_FILE=sdk.log + # integration tests assets INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 +# sign.b2e integration test settings — override in tests/.env.local +# Set companyCrmId of a company with КЭДО integration to enable CompanyProvider tests +SIGN_B2E_COMPANY_CRM_ID= +# Set a valid document UID from sign.b2e to enable Document.get annotation tests +SIGN_B2E_DOCUMENT_UID= + DOCUMENTATION_DEFAULT_TARGET_BRANCH= DOCUMENTATION_OPEN_AI_API_KEY= -DOCUMENTATION_REPOSITORY_FOLDER= \ No newline at end of file +DOCUMENTATION_REPOSITORY_FOLDER= diff --git a/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php index 5c59fd0c..bb8e4812 100644 --- a/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/CompanyProvider/Result/CompanyProviderItemResultAnnotationsTest.php @@ -13,6 +13,8 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\CompanyProvider\Result; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Result\CompanyProviderItemResult; use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Service\CompanyProvider; use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; @@ -29,29 +31,85 @@ class CompanyProviderItemResultAnnotationsTest extends TestCase private CompanyProvider $companyProviderService; + private ?int $companyCrmId = null; + #[\Override] protected function setUp(): void { - $this->companyProviderService = Factory::getServiceBuilder()->getSignScope()->companyProvider(); + $this->companyProviderService = Factory::getServiceBuilder(true)->getSignScope()->companyProvider(); + + $value = $_ENV['SIGN_B2E_COMPANY_CRM_ID'] ?? ''; + if ($value !== '') { + $this->companyCrmId = (int) $value; + } } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('testAllSystemFieldsAnnotated: all fields in CompanyProviderItemResult are annotated in phpdoc')] + #[TestDox('testAllSystemFieldsAnnotated: all fields in CompanyProviderItemResult are annotated in phpdoc and match raw API response')] public function testAllSystemFieldsAnnotated(): void { - $this->markTestSkipped( - 'sign.b2e.company.provider.list requires a valid company CRM ID with КЭДО integration. ' . - 'Run manually with a real companyCrmId to verify annotation completeness.' + if ($this->companyCrmId === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_COMPANY_CRM_ID in tests/.env.local to enable this test.' + ); + } + + $rawItems = $this->companyProviderService->list(null, $this->companyCrmId) + ->getCoreResponse()->getResponseData()->getResult(); + + if ($rawItems === []) { + $this->markTestSkipped( + 'No signature providers found for this company — cannot verify annotation completeness against live API data.' + ); + } + + $this->assertBitrix24AllResultItemFieldsAnnotated( + array_keys($rawItems[0]), + CompanyProviderItemResult::class ); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in CompanyProviderItemResult have valid type annotations')] public function testAllSystemFieldsHasValidTypeAnnotation(): void { - $this->markTestSkipped( - 'sign.b2e.company.provider.list requires a valid company CRM ID with КЭДО integration. ' . - 'Run manually with a real companyCrmId to verify annotation types.' + if ($this->companyCrmId === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_COMPANY_CRM_ID in tests/.env.local to enable this test.' + ); + } + + $rawItems = $this->companyProviderService->list(null, $this->companyCrmId) + ->getCoreResponse()->getResponseData()->getResult(); + + if ($rawItems === []) { + $this->markTestSkipped( + 'No signature providers found for this company — cannot verify type annotations against live API data.' + ); + } + + $fieldTypesMap = []; + foreach (array_keys($rawItems[0]) as $fieldCode) { + $fieldTypesMap[$fieldCode] = match ($fieldCode) { + 'code', 'uid', 'name' => ['type' => 'string'], + 'date', 'expires' => ['type' => 'datetime'], + default => throw new \RuntimeException( + sprintf('Unknown field «%s» in sign.b2e.company.provider.list response — update the type map.', $fieldCode) + ), + }; + } + + $this->assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( + $fieldTypesMap, + CompanyProviderItemResult::class ); } } diff --git a/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php b/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php index cd085904..b77988da 100644 --- a/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php +++ b/tests/Integration/Services/Sign/B2e/CompanyProvider/Service/CompanyProviderTest.php @@ -13,6 +13,10 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\CompanyProvider\Service; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Result\CompanyProviderItemResult; +use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Result\CompanyProvidersResult; use Bitrix24\SDK\Services\Sign\B2e\CompanyProvider\Service\CompanyProvider; use Bitrix24\SDK\Tests\Integration\Factory; use PHPUnit\Framework\Attributes\CoversClass; @@ -23,18 +27,83 @@ #[CoversClass(CompanyProvider::class)] class CompanyProviderTest extends TestCase { + private CompanyProvider $companyProviderService; + + private ?int $companyCrmId = null; + #[\Override] - protected function setUp() : void + protected function setUp(): void { + $this->companyProviderService = Factory::getServiceBuilder(true)->getSignScope()->companyProvider(); + + $value = $_ENV['SIGN_B2E_COMPANY_CRM_ID'] ?? ''; + if ($value !== '') { + $this->companyCrmId = (int) $value; + } } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('sign.b2e.company.provider.list returns CompanyProvidersResult')] + #[TestDox('sign.b2e.company.provider.list returns CompanyProvidersResult with items array')] public function testListReturnsCompanyProvidersResult(): void { - $this->markTestSkipped( - 'sign.b2e.company.provider.list requires a valid company CRM ID with КЭДО integration. ' . - 'Run manually with a real companyCrmId to verify.' - ); + if ($this->companyCrmId === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_COMPANY_CRM_ID in tests/.env.local to enable this test.' + ); + } + + $companyProvidersResult = $this->companyProviderService->list(null, $this->companyCrmId); + + self::assertInstanceOf(CompanyProvidersResult::class, $companyProvidersResult); + self::assertIsArray($companyProvidersResult->getProviders()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.company.provider.list items are CompanyProviderItemResult instances when not empty')] + public function testListItemsAreCompanyProviderItemResults(): void + { + if ($this->companyCrmId === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_COMPANY_CRM_ID in tests/.env.local to enable this test.' + ); + } + + $providers = $this->companyProviderService->list(null, $this->companyCrmId)->getProviders(); + + if ($providers === []) { + $this->markTestSkipped('No signature providers found for this company — cannot verify item type.'); + } + + self::assertInstanceOf(CompanyProviderItemResult::class, $providers[0]); + self::assertIsString($providers[0]->code); + self::assertIsString($providers[0]->uid); + self::assertIsString($providers[0]->name); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.company.provider.list respects limit parameter')] + public function testListRespectsLimitParameter(): void + { + if ($this->companyCrmId === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_COMPANY_CRM_ID in tests/.env.local to enable this test.' + ); + } + + $providers = $this->companyProviderService->list(null, $this->companyCrmId, null, 1, 0)->getProviders(); + + self::assertLessThanOrEqual(1, count($providers)); } } diff --git a/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php index a3db46b0..eadc9e84 100644 --- a/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/Document/Result/DocumentItemResultAnnotationsTest.php @@ -13,6 +13,8 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\Document\Result; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\Sign\B2e\Document\Result\DocumentItemResult; use Bitrix24\SDK\Services\Sign\B2e\Document\Service\Document; use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; @@ -29,29 +31,73 @@ class DocumentItemResultAnnotationsTest extends TestCase private Document $documentService; + private ?string $documentUid = null; + #[\Override] protected function setUp(): void { - $this->documentService = Factory::getServiceBuilder()->getSignScope()->document(); + $this->documentService = Factory::getServiceBuilder(true)->getSignScope()->document(); + + $value = $_ENV['SIGN_B2E_DOCUMENT_UID'] ?? ''; + if ($value !== '') { + $this->documentUid = $value; + } } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('testAllSystemFieldsAnnotated: all fields in DocumentItemResult are annotated in phpdoc')] + #[TestDox('testAllSystemFieldsAnnotated: all fields in DocumentItemResult are annotated in phpdoc and match raw API response')] public function testAllSystemFieldsAnnotated(): void { - $this->markTestSkipped( - 'sign.b2e.document.get requires application context and a valid КЭДО document UID. ' . - 'Run manually with a real document UID to verify annotation completeness.' + if ($this->documentUid === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_DOCUMENT_UID in tests/.env.local to enable this test.' + ); + } + + $rawResult = $this->documentService->get($this->documentUid) + ->getCoreResponse()->getResponseData()->getResult(); + + $this->assertBitrix24AllResultItemFieldsAnnotated( + array_keys($rawResult), + DocumentItemResult::class ); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in DocumentItemResult have valid type annotations')] public function testAllSystemFieldsHasValidTypeAnnotation(): void { - $this->markTestSkipped( - 'sign.b2e.document.get requires application context and a valid КЭДО document UID. ' . - 'Run manually with a real document UID to verify annotation types.' + if ($this->documentUid === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_DOCUMENT_UID in tests/.env.local to enable this test.' + ); + } + + $rawResult = $this->documentService->get($this->documentUid) + ->getCoreResponse()->getResponseData()->getResult(); + + $fieldTypesMap = []; + foreach (array_keys($rawResult) as $fieldCode) { + $fieldTypesMap[$fieldCode] = match ($fieldCode) { + 'uid' => ['type' => 'string'], + 'state', 'members' => ['type' => 'array'], + default => throw new \RuntimeException( + sprintf('Unknown field «%s» in sign.b2e.document.get response — update the type map.', $fieldCode) + ), + }; + } + + $this->assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( + $fieldTypesMap, + DocumentItemResult::class ); } } diff --git a/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php b/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php index be85c1a1..becf3b2d 100644 --- a/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php +++ b/tests/Integration/Services/Sign/B2e/Document/Service/DocumentTest.php @@ -13,6 +13,9 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\Document\Service; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Sign\B2e\Document\Result\DocumentItemResult; use Bitrix24\SDK\Services\Sign\B2e\Document\Result\DocumentResult; use Bitrix24\SDK\Services\Sign\B2e\Document\Service\Document; use Bitrix24\SDK\Tests\Integration\Factory; @@ -24,26 +27,70 @@ #[CoversClass(Document::class)] class DocumentTest extends TestCase { + private Document $documentService; + + private ?string $documentUid = null; + #[\Override] - protected function setUp() : void + protected function setUp(): void { + $this->documentService = Factory::getServiceBuilder(true)->getSignScope()->document(); + + $value = $_ENV['SIGN_B2E_DOCUMENT_UID'] ?? ''; + if ($value !== '') { + $this->documentUid = $value; + } } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] #[TestDox('sign.b2e.document.get returns DocumentResult for a known document UID')] public function testGetReturnsDocumentResult(): void { - $this->markTestSkipped( - 'sign.b2e.document.get requires application context and a valid document UID from a real КЭДО environment.' - ); + if ($this->documentUid === null) { + $this->markTestSkipped( + 'Set SIGN_B2E_DOCUMENT_UID in tests/.env.local to enable this test.' + ); + } + + $documentResult = $this->documentService->get($this->documentUid); + + self::assertInstanceOf(DocumentResult::class, $documentResult); + + $documentItemResult = $documentResult->getDocument(); + self::assertInstanceOf(DocumentItemResult::class, $documentItemResult); + self::assertIsString($documentItemResult->uid); + self::assertEquals($this->documentUid, $documentItemResult->uid); + self::assertIsArray($documentItemResult->state); + self::assertArrayHasKey('code', $documentItemResult->state); + self::assertArrayHasKey('name', $documentItemResult->state); + } + + /** + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.document.get throws BaseException for non-existent document UID')] + public function testGetThrowsExceptionForInvalidUid(): void + { + $this->expectException(BaseException::class); + + $this->documentService->get('non-existent-uid-00000000-0000-0000-0000-000000000000'); } + /** + * @throws TransportException + */ #[Test] - #[TestDox('sign.b2e.document.send returns DocumentResult')] - public function testSendReturnsDocumentResult(): void + #[TestDox('sign.b2e.document.send throws BaseException when required fields are missing')] + public function testSendThrowsExceptionWhenRequiredFieldsMissing(): void { - $this->markTestSkipped( - 'sign.b2e.document.send requires application context, sign.b2e scope and a real КЭДО environment.' - ); + $this->expectException(BaseException::class); + + // Sending with empty fields should return BAD_REQUEST from the API + $this->documentService->send([]); } } diff --git a/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php index 48232db8..6ca094ce 100644 --- a/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/MySafeTail/Result/MySafeTailItemResultAnnotationsTest.php @@ -13,6 +13,8 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\MySafeTail\Result; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Result\MySafeTailItemResult; use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Service\MySafeTail; use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; @@ -32,26 +34,64 @@ class MySafeTailItemResultAnnotationsTest extends TestCase #[\Override] protected function setUp(): void { - $this->mySafeTailService = Factory::getServiceBuilder()->getSignScope()->mySafeTail(); + $this->mySafeTailService = Factory::getServiceBuilder(true)->getSignScope()->mySafeTail(); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('testAllSystemFieldsAnnotated: all fields in MySafeTailItemResult are annotated in phpdoc')] + #[TestDox('testAllSystemFieldsAnnotated: all fields in MySafeTailItemResult are annotated in phpdoc and match raw API response')] public function testAllSystemFieldsAnnotated(): void { - $this->markTestSkipped( - 'sign.b2e.mysafe.tail requires application context (not webhook). ' . - 'Run manually with OAuth application context to verify annotation completeness.' + $rawItems = $this->mySafeTailService->tail(20, 0) + ->getCoreResponse()->getResponseData()->getResult(); + + if ($rawItems === []) { + $this->markTestSkipped( + 'No signed documents found in company safe — cannot verify annotation completeness against live API data.' + ); + } + + $this->assertBitrix24AllResultItemFieldsAnnotated( + array_keys($rawItems[0]), + MySafeTailItemResult::class ); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in MySafeTailItemResult have valid type annotations')] public function testAllSystemFieldsHasValidTypeAnnotation(): void { - $this->markTestSkipped( - 'sign.b2e.mysafe.tail requires application context (not webhook). ' . - 'Run manually with OAuth application context to verify annotation types.' + $rawItems = $this->mySafeTailService->tail(20, 0) + ->getCoreResponse()->getResponseData()->getResult(); + + if ($rawItems === []) { + $this->markTestSkipped( + 'No signed documents found in company safe — cannot verify type annotations against live API data.' + ); + } + + $fieldTypesMap = []; + foreach (array_keys($rawItems[0]) as $fieldCode) { + $fieldTypesMap[$fieldCode] = match ($fieldCode) { + 'id', 'creator_id', 'member_id' => ['type' => 'integer'], + 'title', 'file_url', 'role' => ['type' => 'string'], + 'create_date', 'signed_date' => ['type' => 'datetime'], + default => throw new \RuntimeException( + sprintf('Unknown field «%s» in sign.b2e.mysafe.tail response — update the type map.', $fieldCode) + ), + }; + } + + $this->assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( + $fieldTypesMap, + MySafeTailItemResult::class ); } } diff --git a/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php b/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php index 7da482ba..e6da1523 100644 --- a/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php +++ b/tests/Integration/Services/Sign/B2e/MySafeTail/Service/MySafeTailTest.php @@ -13,6 +13,10 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\MySafeTail\Service; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Result\MySafeTailItemResult; +use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Result\MySafeTailResult; use Bitrix24\SDK\Services\Sign\B2e\MySafeTail\Service\MySafeTail; use Bitrix24\SDK\Tests\Integration\Factory; use PHPUnit\Framework\Attributes\CoversClass; @@ -23,18 +27,58 @@ #[CoversClass(MySafeTail::class)] class MySafeTailTest extends TestCase { + private MySafeTail $mySafeTailService; + #[\Override] - protected function setUp() : void + protected function setUp(): void { + $this->mySafeTailService = Factory::getServiceBuilder(true)->getSignScope()->mySafeTail(); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('sign.b2e.mysafe.tail returns MySafeTailResult')] + #[TestDox('sign.b2e.mysafe.tail returns MySafeTailResult with items array')] public function testTailReturnsMySafeTailResult(): void { - $this->markTestSkipped( - 'sign.b2e.mysafe.tail requires application context (not webhook). ' . - 'Run manually with OAuth application context to verify.' - ); + $mySafeTailResult = $this->mySafeTailService->tail(20, 0); + + self::assertInstanceOf(MySafeTailResult::class, $mySafeTailResult); + self::assertIsArray($mySafeTailResult->getItems()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.mysafe.tail items are MySafeTailItemResult instances when not empty')] + public function testTailItemsAreMySafeTailItemResults(): void + { + $items = $this->mySafeTailService->tail(20, 0)->getItems(); + + if ($items === []) { + $this->markTestSkipped('No signed documents found in company safe — cannot verify item type.'); + } + + self::assertInstanceOf(MySafeTailItemResult::class, $items[0]); + self::assertIsInt($items[0]->id); + self::assertIsString($items[0]->title); + self::assertIsString($items[0]->role); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.mysafe.tail respects limit parameter')] + public function testTailRespectsLimitParameter(): void + { + $items = $this->mySafeTailService->tail(1, 0)->getItems(); + + self::assertLessThanOrEqual(1, count($items)); } } diff --git a/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php b/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php index 05b197f7..e41f7860 100644 --- a/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php +++ b/tests/Integration/Services/Sign/B2e/PersonalTail/Result/PersonalTailItemResultAnnotationsTest.php @@ -13,6 +13,8 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\PersonalTail\Result; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Result\PersonalTailItemResult; use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Service\PersonalTail; use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; @@ -32,26 +34,64 @@ class PersonalTailItemResultAnnotationsTest extends TestCase #[\Override] protected function setUp(): void { - $this->personalTailService = Factory::getServiceBuilder()->getSignScope()->personalTail(); + $this->personalTailService = Factory::getServiceBuilder(true)->getSignScope()->personalTail(); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('testAllSystemFieldsAnnotated: all fields in PersonalTailItemResult are annotated in phpdoc')] + #[TestDox('testAllSystemFieldsAnnotated: all fields in PersonalTailItemResult are annotated in phpdoc and match raw API response')] public function testAllSystemFieldsAnnotated(): void { - $this->markTestSkipped( - 'sign.b2e.personal.tail requires application context (not webhook). ' . - 'Run manually with OAuth application context to verify annotation completeness.' + $rawItems = $this->personalTailService->tail(20, 0) + ->getCoreResponse()->getResponseData()->getResult(); + + if ($rawItems === []) { + $this->markTestSkipped( + 'No signed documents found in personal tail — cannot verify annotation completeness against live API data.' + ); + } + + $this->assertBitrix24AllResultItemFieldsAnnotated( + array_keys($rawItems[0]), + PersonalTailItemResult::class ); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] #[TestDox('testAllSystemFieldsHasValidTypeAnnotation: all fields in PersonalTailItemResult have valid type annotations')] public function testAllSystemFieldsHasValidTypeAnnotation(): void { - $this->markTestSkipped( - 'sign.b2e.personal.tail requires application context (not webhook). ' . - 'Run manually with OAuth application context to verify annotation types.' + $rawItems = $this->personalTailService->tail(20, 0) + ->getCoreResponse()->getResponseData()->getResult(); + + if ($rawItems === []) { + $this->markTestSkipped( + 'No signed documents found in personal tail — cannot verify type annotations against live API data.' + ); + } + + $fieldTypesMap = []; + foreach (array_keys($rawItems[0]) as $fieldCode) { + $fieldTypesMap[$fieldCode] = match ($fieldCode) { + 'id' => ['type' => 'integer'], + 'title', 'file_url' => ['type' => 'string'], + 'signed_date' => ['type' => 'datetime'], + default => throw new \RuntimeException( + sprintf('Unknown field «%s» in sign.b2e.personal.tail response — update the type map.', $fieldCode) + ), + }; + } + + $this->assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( + $fieldTypesMap, + PersonalTailItemResult::class ); } } diff --git a/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php b/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php index 3aa53406..f9951ee5 100644 --- a/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php +++ b/tests/Integration/Services/Sign/B2e/PersonalTail/Service/PersonalTailTest.php @@ -13,6 +13,9 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Sign\B2e\PersonalTail\Service; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Result\PersonalTailItemResult; use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Result\PersonalTailResult; use Bitrix24\SDK\Services\Sign\B2e\PersonalTail\Service\PersonalTail; use Bitrix24\SDK\Tests\Integration\Factory; @@ -24,18 +27,57 @@ #[CoversClass(PersonalTail::class)] class PersonalTailTest extends TestCase { + private PersonalTail $personalTailService; + #[\Override] - protected function setUp() : void + protected function setUp(): void { + $this->personalTailService = Factory::getServiceBuilder(true)->getSignScope()->personalTail(); } + /** + * @throws BaseException + * @throws TransportException + */ #[Test] - #[TestDox('sign.b2e.personal.tail returns PersonalTailResult')] + #[TestDox('sign.b2e.personal.tail returns PersonalTailResult with items array')] public function testTailReturnsPersonalTailResult(): void { - $this->markTestSkipped( - 'sign.b2e.personal.tail requires application context (not webhook). ' . - 'Run manually with OAuth application context to verify.' - ); + $personalTailResult = $this->personalTailService->tail(20, 0); + + self::assertInstanceOf(PersonalTailResult::class, $personalTailResult); + self::assertIsArray($personalTailResult->getItems()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.personal.tail items are PersonalTailItemResult instances when not empty')] + public function testTailItemsArePersonalTailItemResults(): void + { + $items = $this->personalTailService->tail(20, 0)->getItems(); + + if ($items === []) { + $this->markTestSkipped('No signed documents found in personal tail — cannot verify item type.'); + } + + self::assertInstanceOf(PersonalTailItemResult::class, $items[0]); + self::assertIsInt($items[0]->id); + self::assertIsString($items[0]->title); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('sign.b2e.personal.tail respects limit parameter')] + public function testTailRespectsLimitParameter(): void + { + $items = $this->personalTailService->tail(1, 0)->getItems(); + + self::assertLessThanOrEqual(1, count($items)); } } From 83631e41e6ea9d9fedc591f5766079458da00405 Mon Sep 17 00:00:00 2001 From: Dmitriy Ignatenko Date: Tue, 30 Jun 2026 20:45:19 +0400 Subject: [PATCH 4/5] Add environment variables for the sign.b2e test --- tests/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/.env b/tests/.env index cb7603bf..6bfc6bf1 100644 --- a/tests/.env +++ b/tests/.env @@ -26,7 +26,7 @@ LOGS_FILE=sdk.log INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 # sign.b2e integration test settings — override in tests/.env.local -# Set companyCrmId of a company with КЭДО integration to enable CompanyProvider tests +# Set companyCrmId of a company with Electronic Personnel Document Management integration to enable CompanyProvider tests SIGN_B2E_COMPANY_CRM_ID= # Set a valid document UID from sign.b2e to enable Document.get annotation tests SIGN_B2E_DOCUMENT_UID= From 5fdab9dd651c039be94912b492e9c0ef28a66c6f Mon Sep 17 00:00:00 2001 From: Dmitriy Ignatenko Date: Wed, 1 Jul 2026 12:42:25 +0400 Subject: [PATCH 5/5] Minor fix --- rector.php | 2 +- src/Services/ServiceBuilder.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rector.php b/rector.php index e735cdf4..d59dac82 100644 --- a/rector.php +++ b/rector.php @@ -82,11 +82,11 @@ __DIR__ . '/tests/Integration/Services/CRM/Documentgenerator/Document', __DIR__ . '/src/Services/CRM/Documentgenerator/Template', __DIR__ . '/tests/Integration/Services/CRM/Documentgenerator/Template', - __DIR__ . '/tests/Unit/', __DIR__ . '/src/Services/Timeman', __DIR__ . '/tests/Integration/Services/Timeman', __DIR__ . '/src/Services/Sign', __DIR__ . '/tests/Integration/Services/Sign', + __DIR__ . '/tests/Unit/', ]) ->withCache(cacheDirectory: __DIR__ . '/var/.cache/rector') ->withSets( diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 16c9fb5d..c691bb08 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -211,6 +211,9 @@ public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder return $this->serviceCache[__METHOD__]; } + /** + * @return MainServiceBuilder + */ public function getMainScope(): MainServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -253,6 +256,9 @@ public function getUserScope(): UserServiceBuilder return $this->serviceCache[__METHOD__]; } + /** + * @return PlacementServiceBuilder + */ public function getPlacementScope(): PlacementServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) {