Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
->in(__DIR__ . '/src/Services/SonetGroup/')
->in(__DIR__ . '/src/Services/MailService/')
->in(__DIR__ . '/src/Services/Messageservice/')
->in(__DIR__ . '/src/Services/Sign/')
->name('*.php')
->exclude(['vendor', 'storage', 'docker', 'docs']) // Exclude directories
->ignoreDotFiles(true)
Expand Down
94 changes: 94 additions & 0 deletions .tasks/504/plan.md
Original file line number Diff line number Diff line change
@@ -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 <algonexys@gmail.com>

---

## 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
```

10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@

### 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
- Added services `Services\Timeman\Record\Service\Record` and `Services\Timeman\RecordField\Service\RecordField`
with support for v3 `timeman.record.*` methods,
see [timeman REST v3](https://apidocs.bitrix24.com/api-reference/rest-v3/timeman/index.html) ([#518](https://github.com/bitrix24/b24phpsdk/issues/518)):
Expand Down
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ help:
@echo "test-integration-lists-section - run Lists Section integration tests"
@echo "test-integration-lists-element - run Lists Element integration tests"
@echo "test-integration-mailservice - run MailService 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
Expand Down Expand Up @@ -747,6 +752,26 @@ test-integration-messageservice-sender:
test-integration-messageservice-message-status:
docker compose run --rm php-cli $(PHPUNIT) --testsuite integration_tests_messageservice_message_status

.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:
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ parameters:
- tests/Integration/Services/Timeman
- tests/Integration/Services/MailService
- tests/Integration/Services/Messageservice
- tests/Integration/Services/Sign
excludePaths:
# TODO: Fix type errors in RequisiteUserfieldUseCaseTest and remove this exclusion
# Tracking: https://github.com/bitrix24/b24phpsdk/issues
Expand Down
19 changes: 19 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,25 @@
<testsuite name="integration_tests_messageservice_message_status">
<directory>./tests/Integration/Services/Messageservice/Message/Status/</directory>
</testsuite>
<testsuite name="integration_tests_scope_sign">
<directory>./tests/Integration/Services/Sign/</directory>
</testsuite>
<testsuite name="integration_tests_sign_document">
<directory>./tests/Integration/Services/Sign/B2e/Document/Service/</directory>
<directory>./tests/Integration/Services/Sign/B2e/Document/Result/</directory>
</testsuite>
<testsuite name="integration_tests_sign_company_provider">
<directory>./tests/Integration/Services/Sign/B2e/CompanyProvider/Service/</directory>
<directory>./tests/Integration/Services/Sign/B2e/CompanyProvider/Result/</directory>
</testsuite>
<testsuite name="integration_tests_sign_personal_tail">
<directory>./tests/Integration/Services/Sign/B2e/PersonalTail/Service/</directory>
<directory>./tests/Integration/Services/Sign/B2e/PersonalTail/Result/</directory>
</testsuite>
<testsuite name="integration_tests_sign_mysafe_tail">
<directory>./tests/Integration/Services/Sign/B2e/MySafeTail/Service/</directory>
<directory>./tests/Integration/Services/Sign/B2e/MySafeTail/Result/</directory>
</testsuite>
</testsuites>
<source>
<include>
Expand Down
2 changes: 2 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,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(
Expand Down
15 changes: 9 additions & 6 deletions src/Services/RemoteEventsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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');
}
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -225,6 +227,7 @@ public static function init(LoggerInterface $logger): self
new IMOpenLinesEventsFactory(),
new SonetGroupEventsFactory(),
new Sale\Events\SaleEventsFactory(),
new SignB2eEventsFactory(),
],
$logger
);
Expand Down
15 changes: 15 additions & 0 deletions src/Services/ServiceBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use Bitrix24\SDK\Services\MailService\MailServiceServiceBuilder;
use Bitrix24\SDK\Services\Messageservice\MessageserviceServiceBuilder;
use Bitrix24\SDK\Services\Rest\RestServiceBuilder;
use Bitrix24\SDK\Services\Sign\SignServiceBuilder;
use Bitrix24\SDK\Services\Timeman\TimemanServiceBuilder;
use Psr\Log\LoggerInterface;

Expand Down Expand Up @@ -485,4 +486,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__];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* This file is part of the bitrix24-php-sdk package.
*
* © Dmitriy Ignatenko <algonexys@gmail.com>
*
* 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
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* This file is part of the bitrix24-php-sdk package.
*
* © Dmitriy Ignatenko <algonexys@gmail.com>
*
* 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;
}
}
Loading
Loading