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
16 changes: 16 additions & 0 deletions .claude/skills/b24phpsdk-maintainer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,22 @@ the Bitrix24 REST payload format at the service boundary, following existing ser
patterns. Do not expose raw date/time strings in service method arguments when the SDK can
accept a typed immutable date value instead.

### Field metadata methods

When a REST API entity exposes `*.field.get` and `*.field.list`, implement those methods in
a dedicated field metadata service instead of adding `fieldGet()` or `fieldList()` methods to
the primary entity service.

Use this shape:

- service class: `Services\<Scope>\<Entity>Field\Service\<Entity>Field`
- builder accessor: `<entity>Field()`
- public methods: `get(string $name, array $select = [])` and `list(array $select = [])`
- result wrappers: `<Entity>FieldResult`, `<Entity>FieldsResult`, and `<Entity>FieldItemResult`

If one issue covers several entities with field metadata endpoints, create one field service
per entity unless the scope already has an established shared field-service convention.

### ApiEndpointMetadata documentation links

When adding or changing `ApiEndpointMetadata` attributes, documentation links must point to
Expand Down
280 changes: 280 additions & 0 deletions .tasks/517/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
# Plan: Add humanresources.* v3 service - org structure (issue #517)

## Context

Issue #517 adds typed SDK support for the Bitrix24 REST API v3 `humanresources.*` scope.
The worktree is `/private/tmp/b24phpsdk-517-add-humanresources-scope` on branch
`feature/517-add-humanresources-scope`, based on `origin/v3-dev`.

The local OpenAPI snapshot was refreshed with:

```bash
make -s oa-schema-build BITRIX24_WEBHOOK="<local webhook from tests/.env.local>"
```

Baseline unit tests passed before implementation:

```bash
make test-unit
# OK (969 tests, 2723 assertions)
```

Official Bitrix24 documentation was checked for all 24 methods. The OpenAPI snapshot is not
complete enough to drive implementation blindly:

- several write/count methods have empty parameter schemas in `docs/open-api/openapi.json`
- `humanresources.employee.search`, `humanresources.node.list`, `humanresources.node.search`,
`humanresources.node.children`, and all field-list methods are documented as `result.items`
even when the snapshot exposes a flat array
- `humanresources.node.list` and `humanresources.node.search` require `type`
- field `get` methods return `result.item`
- count/multidepartment/subordinates/communication/member mutation methods return named payload
objects directly under `result`

Use official docs as the source of truth for method parameters and result envelopes.

Generator rule:

- Run `php bin/console b24-dev:result-item-generator <method.name> --stage=all` before manual
edits for generated `*ItemResult.php` classes.
- Use the generated result-item files as starting points, then correct names, namespaces,
nullability, and response-envelope wrappers against the official docs.

## API Surface

### Employee service

Methods:

- `count(): EmployeeCountResult` for `humanresources.employee.count`
- `multidepartment(): EmployeeMultidepartmentResult`
- `search(string $name, ?int $nodeId = null, array $select = []): EmployeesResult`
- `subordinates(int $id): EmployeeSubordinatesResult`

### Node service

Methods:

- `add(string $type, string $name, int $parentId, array $optional = []): NodeResult`
- `children(int $id, array $select = []): NodesResult`
- `count(): NodeCountResult`
- `edit(int $id, array $fields): NodeResult`
- `get(int $id, array $select = []): NodeResult`
- `list(string $type, array $select = [], array $pagination = []): NodesResult`
- `move(int $id, int $parentId): NodeResult`
- `search(string $type, string $name, ?int $parentId = null, array $pagination = []): NodesResult`

### Field metadata services

`*.field.get` and `*.field.list` methods live in dedicated field services, not in the
primary entity services:

- `EmployeeField::get(string $name, array $select = []): EmployeeFieldResult`
- `EmployeeField::list(array $select = []): EmployeeFieldsResult`
- `NodeField::get(string $name, array $select = []): NodeFieldResult`
- `NodeField::list(array $select = []): NodeFieldsResult`
- `NodeMemberField::get(string $name, array $select = []): NodeMemberFieldResult`
- `NodeMemberField::list(array $select = []): NodeMemberFieldsResult`

### NodeCommunication service

Methods:

- `edit(int $nodeId, string $communicationType, array $options = []): NodeCommunicationEditResult`
- `list(int $id): NodeCommunicationResult`

### NodeMember service

Methods:

- `add(int $nodeId, array $userIds, string $role): NodeMemberOperationResult`
- `move(int $nodeId, array $userIds, ?string $role = null): NodeMemberOperationResult`
- `remove(int $nodeId, array $userIds): NodeMemberRemoveResult`
- `set(int $nodeId, array $userIds): NodeMemberOperationResult`

Batch support:

- Add `Service/Batch.php` for list/add methods that are safe for batch in this issue:
`employee.search`, `node.children`, `node.list`, `node.search`, and `node.member.add`.
- Do not batch methods whose docs explicitly return `ERROR_BATCH_METHOD_NOT_ALLOWED` during
live verification; document any exclusions in this plan before implementation changes.

## Files to Create

### 1. `src/Services/HumanResources/HumanResourcesServiceBuilder.php`

Creates and caches:

- `employee(): Service\Employee`
- `employeeField(): EmployeeField\Service\EmployeeField`
- `node(): Service\Node`
- `nodeField(): NodeField\Service\NodeField`
- `nodeCommunication(): Service\NodeCommunication`
- `nodeMember(): Service\NodeMember`
- `nodeMemberField(): NodeMemberField\Service\NodeMemberField`

Add `#[ApiServiceBuilderMetadata(new Scope(['humanresources']))]`.

### 2. `src/Services/HumanResources/Service/*.php`

Create:

- `Service/Employee.php`
- `Service/Node.php`
- `Service/NodeCommunication.php`
- `Service/NodeMember.php`
- `Service/Batch.php`
- `EmployeeField/Service/EmployeeField.php`
- `NodeField/Service/NodeField.php`
- `NodeMemberField/Service/NodeMemberField.php`

Each service must use `ApiVersion::v3` in `core->call(...)`.
Every method must have `#[ApiEndpointMetadata(...)]` with the English docs URL.

### 3. `src/Services/HumanResources/Result/*.php`

Create result wrappers and item classes:

- `EmployeeItemResult.php`, `EmployeesResult.php`
- `EmployeeCountResult.php`
- `EmployeeMultidepartmentResult.php`
- `EmployeeSubordinatesResult.php`
- `NodeItemResult.php`, `NodeResult.php`, `NodesResult.php`, `NodeCountResult.php`
- `NodeMemberItemResult.php`
- `NodeCommunicationResult.php`, `NodeCommunicationEditResult.php`
- `NodeMemberOperationResult.php`, `NodeMemberRemoveResult.php`
- `EmployeeField/Result/EmployeeFieldItemResult.php`, `EmployeeField/Result/EmployeeFieldResult.php`,
`EmployeeField/Result/EmployeeFieldsResult.php`
- `NodeField/Result/NodeFieldItemResult.php`, `NodeField/Result/NodeFieldResult.php`,
`NodeField/Result/NodeFieldsResult.php`
- `NodeMemberField/Result/NodeMemberFieldItemResult.php`,
`NodeMemberField/Result/NodeMemberFieldResult.php`,
`NodeMemberField/Result/NodeMemberFieldsResult.php`

Generator commands to run before manual result-item edits:

```bash
php bin/console b24-dev:result-item-generator humanresources.employee.search --stage=all
php bin/console b24-dev:result-item-generator humanresources.node.get --stage=all
php bin/console b24-dev:result-item-generator humanresources.node.member.field.get --stage=all
php bin/console b24-dev:result-item-generator humanresources.employee.field.get --stage=all
```

Generator status:

- `docker compose run --rm -e BITRIX24_WEBHOOK="<local webhook>" php-cli php bin/console b24-dev:result-item-generator humanresources.employee.search --stage=all`
failed with `Unable to determine the current git branch`.
- The `php-cli` image does not contain `git`, and the generator fallback expects `.git/HEAD`
to exist as a directory path. This worktree uses the standard git-worktree `.git` file
pointing to the main repository metadata, so the fallback cannot resolve the branch.
- Result item classes are therefore created manually from the official API response
descriptions and will be verified by the mandatory annotation integration tests.
- Live portal verification note: the current test webhook portal has no `humanresources`
scope in `app.info` and returns `ERROR_METHOD_NOT_FOUND` for
`humanresources.employee.field.list`, `humanresources.node.field.list`, and
`humanresources.node.member.field.list`. Integration tests must therefore skip with an
explicit message on portals where this scope is not available.

### 4. Unit tests

Create:

- `tests/Unit/Services/HumanResources/HumanResourcesServiceBuilderTest.php`
- `tests/Unit/Services/HumanResources/Service/EmployeeTest.php`
- `tests/Unit/Services/HumanResources/Service/EmployeeFieldTest.php`
- `tests/Unit/Services/HumanResources/Service/NodeTest.php`
- `tests/Unit/Services/HumanResources/Service/NodeFieldTest.php`
- `tests/Unit/Services/HumanResources/Service/NodeCommunicationTest.php`
- `tests/Unit/Services/HumanResources/Service/NodeMemberTest.php`
- `tests/Unit/Services/HumanResources/Service/NodeMemberFieldTest.php`

Use TDD: write a failing test for each method before production code.
Each test must assert the exact REST method name, parameters, `ApiVersion::v3`, and result class.

### 5. Integration tests

Create:

- `tests/Integration/Services/HumanResources/Service/EmployeeTest.php`
- `tests/Integration/Services/HumanResources/Service/EmployeeFieldTest.php`
- `tests/Integration/Services/HumanResources/Service/NodeTest.php`
- `tests/Integration/Services/HumanResources/Service/NodeFieldTest.php`
- `tests/Integration/Services/HumanResources/Service/NodeCommunicationTest.php`
- `tests/Integration/Services/HumanResources/Service/NodeMemberTest.php`
- `tests/Integration/Services/HumanResources/Service/NodeMemberFieldTest.php`
- `tests/Integration/Services/HumanResources/Result/EmployeeItemResultAnnotationsTest.php`
- `tests/Integration/Services/HumanResources/Result/NodeItemResultAnnotationsTest.php`
- `tests/Integration/Services/HumanResources/Result/NodeMemberItemResultAnnotationsTest.php`
- `tests/Integration/Services/HumanResources/Result/EmployeeFieldItemResultAnnotationsTest.php`
- `tests/Integration/Services/HumanResources/Result/NodeFieldItemResultAnnotationsTest.php`
- `tests/Integration/Services/HumanResources/Result/NodeMemberFieldItemResultAnnotationsTest.php`

Integration tests must avoid destructive org-structure changes unless they create and clean up
their own test node. For mutation methods, prefer unit coverage first and keep live integration
coverage narrow enough to be repeatable on the shared test portal.

## Files to Modify

### 1. `src/Services/ServiceBuilder.php`

Add import for `Bitrix24\SDK\Services\HumanResources\HumanResourcesServiceBuilder`.
Add `getHumanResourcesScope(): HumanResourcesServiceBuilder`.

### 2. `phpunit.xml.dist`

Add a suite:

```xml
<testsuite name="integration_tests_scope_humanresources">
<directory>./tests/Integration/Services/HumanResources/</directory>
</testsuite>
```

### 3. `Makefile`

Add help line and target:

```make
test-integration-scope-humanresources:
docker compose run --rm php-cli $(PHPUNIT) --testsuite integration_tests_scope_humanresources
```

### 4. `CHANGELOG.md`

Add under `## X.Y.Z Unreleased` -> `### Added`:

```markdown
- Added v3 `humanresources.*` SDK services for company org structure, employees,
node communications, and node members ([#517](https://github.com/bitrix24/b24phpsdk/issues/517))
```

## Deptrac compliance

The new code stays inside the existing Services layer:

- services depend on Core contracts, credentials scope, exceptions, result wrappers, attributes, and logger
- result classes depend only on Core result abstractions and value classes such as `CarbonImmutable`
- tests use existing Unit stubs and Integration `Factory`

No dependency from Services to Tests, Infrastructure, or OpenApi runtime code is allowed.

## Verification

Run targeted RED/GREEN tests during implementation, then the full gate:

```bash
make test-file FILE=tests/Unit/Services/HumanResources/Service/EmployeeTest.php
make test-file FILE=tests/Unit/Services/HumanResources/Service/EmployeeFieldTest.php
make test-file FILE=tests/Unit/Services/HumanResources/Service/NodeTest.php
make test-file FILE=tests/Unit/Services/HumanResources/Service/NodeFieldTest.php
make test-file FILE=tests/Unit/Services/HumanResources/Service/NodeCommunicationTest.php
make test-file FILE=tests/Unit/Services/HumanResources/Service/NodeMemberTest.php
make test-file FILE=tests/Unit/Services/HumanResources/Service/NodeMemberFieldTest.php
make test-unit
make test-integration-scope-humanresources
make lint-cs-fixer
make lint-rector
make lint-phpstan
make lint-deptrac
make lint-all
```
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,14 @@
- `getList` gets the list of widgets for the current application
- `debug` enables or disables debug mode for all widgets of the current application
- Added `repoWidget()` accessor to `LandingServiceBuilder` ([#501](https://github.com/bitrix24/b24phpsdk/issues/501))
- Added `Services\HumanResources` v3 scope wrappers for company org structure,
employees, node communications, node members, and dedicated field metadata services
([#517](https://github.com/bitrix24/b24phpsdk/issues/517))

### Changed

- Updated `b24phpsdk-maintainer` skill: require dedicated field metadata services for
`*.field.get` and `*.field.list` endpoints ([#517](https://github.com/bitrix24/b24phpsdk/issues/517))
- Updated `b24phpsdk-maintainer` skill: `*ItemResult` classes must extend
`Core\Result\AbstractAnnotatedItem` (auto-casts from `@property-read` annotations) instead of the
legacy `AbstractItem` + manual `__get` pattern ([#518](https://github.com/bitrix24/b24phpsdk/issues/518))
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ help:
@echo "test-integration-im-chat - run IM Chat integration tests"
@echo "test-integration-im-chat-user - run IM Chat User integration tests"
@echo "test-integration-im-notify - run IM Notify integration tests"
@echo "test-integration-scope-humanresources - run HumanResources integration tests"
@echo "test-integration-scope-lists - run Lists integration tests"
@echo "test-integration-lists-service - run Lists Service integration tests"
@echo "test-integration-lists-field - run Lists Field integration tests"
Expand Down Expand Up @@ -621,6 +622,9 @@ test-integration-rest-scope:
test-integration-scope-timeman:
docker compose run --rm php-cli $(PHPUNIT) --testsuite integration_tests_scope_timeman

.PHONY: test-integration-scope-humanresources
test-integration-scope-humanresources:
@docker compose run --rm -e BITRIX24_WEBHOOK="$(BITRIX24_WEBHOOK)" php-cli $(PHPUNIT) --testsuite integration_tests_scope_humanresources
.PHONY: test-integration-timeman-record
test-integration-timeman-record:
docker compose run --rm php-cli $(PHPUNIT) --testsuite integration_tests_scope_timeman_record
Expand Down
2 changes: 2 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@
<testsuite name="integration_tests_scope_timeman">
<directory>./tests/Integration/Services/Timeman/</directory>
</testsuite>
<testsuite name="integration_tests_scope_humanresources">
<directory>./tests/Integration/Services/HumanResources/</directory>
<testsuite name="integration_tests_scope_timeman_record">
<file>./tests/Integration/Services/Timeman/Record/Service/RecordTest.php</file>
<file>./tests/Integration/Services/Timeman/Record/Result/RecordItemResultTest.php</file>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* This file is part of the bitrix24-php-sdk package.
*
* © Maksim Mesilov <mesilov.maxim@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\HumanResources\EmployeeField\Result;

use Bitrix24\SDK\Core\Result\AbstractAnnotatedItem;

/**
* @property-read string $name
* @property-read string $type
* @property-read string $title
* @property-read string|null $description
* @property-read array|null $validationRules
* @property-read array|null $requiredGroups
* @property-read bool $filterable
* @property-read bool $sortable
* @property-read bool $editable
* @property-read bool $multiple
* @property-read string|null $elementType
*/
class EmployeeFieldItemResult extends AbstractAnnotatedItem
{
}
Loading
Loading