@hubex/mcp 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.env.example +54 -0
  2. package/CONNECTING.md +260 -0
  3. package/README.md +266 -0
  4. package/dist/auth.js +226 -0
  5. package/dist/config.js +120 -0
  6. package/dist/generated/manifest.js +3643 -0
  7. package/dist/guides/field-notes.json +27 -0
  8. package/dist/guides/loader.js +32 -0
  9. package/dist/guides/service-map.js +6 -0
  10. package/dist/http.js +93 -0
  11. package/dist/index/store.js +134 -0
  12. package/dist/index/types.js +1 -0
  13. package/dist/index.js +20 -0
  14. package/dist/paths.js +20 -0
  15. package/dist/pii/fields.js +100 -0
  16. package/dist/pii/mask.js +50 -0
  17. package/dist/pii/strategies.js +88 -0
  18. package/dist/schema/build-index.js +67 -0
  19. package/dist/schema/deref.js +87 -0
  20. package/dist/schema/describe.js +65 -0
  21. package/dist/server.js +62 -0
  22. package/dist/token-prompt.js +41 -0
  23. package/dist/tools/curated.js +151 -0
  24. package/dist/tools/discovery.js +187 -0
  25. package/dist/tools/guides.js +126 -0
  26. package/dist/tools/registry.js +37 -0
  27. package/dist/tools/request.js +170 -0
  28. package/dist/tools/types.js +1 -0
  29. package/docs/guides/assets.md +334 -0
  30. package/docs/guides/attributes.md +125 -0
  31. package/docs/guides/checklisttemplates.md +154 -0
  32. package/docs/guides/companies.md +57 -0
  33. package/docs/guides/dictionaries.md +64 -0
  34. package/docs/guides/lifecycle.md +263 -0
  35. package/docs/guides/materials.md +135 -0
  36. package/docs/guides/notifications.md +184 -0
  37. package/docs/guides/roles.md +125 -0
  38. package/docs/guides/sla.md +130 -0
  39. package/docs/guides/start.md +67 -0
  40. package/docs/guides/taskchecklists.md +149 -0
  41. package/docs/guides/taskcreate.md +260 -0
  42. package/docs/guides/taskedit.md +277 -0
  43. package/docs/guides/tasktypes.md +156 -0
  44. package/docs/guides/users.md +71 -0
  45. package/generated/index.dev.json +18776 -0
  46. package/generated/index.prod.json +18858 -0
  47. package/package.json +48 -0
  48. package/swagger/dev/ADM.json +27777 -0
  49. package/swagger/dev/AUTH.json +1739 -0
  50. package/swagger/dev/AUTHN.json +1250 -0
  51. package/swagger/dev/AUTHZ.json +1404 -0
  52. package/swagger/dev/CM.json +309 -0
  53. package/swagger/dev/COMMON.json +6543 -0
  54. package/swagger/dev/ES.json +28029 -0
  55. package/swagger/dev/EXPORT.json +4575 -0
  56. package/swagger/dev/IMPORT.json +1479 -0
  57. package/swagger/dev/LIC.json +224 -0
  58. package/swagger/dev/MSG.json +7883 -0
  59. package/swagger/dev/NEWS.json +348 -0
  60. package/swagger/dev/PA.json +5981 -0
  61. package/swagger/dev/PMP.json +3196 -0
  62. package/swagger/dev/PROXY.json +416 -0
  63. package/swagger/dev/REPORT.json +3921 -0
  64. package/swagger/dev/SC.json +3771 -0
  65. package/swagger/dev/SLA.json +2837 -0
  66. package/swagger/dev/TSTG.json +4981 -0
  67. package/swagger/dev/UI.json +4720 -0
  68. package/swagger/dev/WH.json +16796 -0
  69. package/swagger/dev/WORK.json +36024 -0
  70. package/swagger/dev/WSP.json +1612 -0
  71. package/swagger/prod/ADM.json +27777 -0
  72. package/swagger/prod/AUTH.json +1308 -0
  73. package/swagger/prod/AUTHN.json +2710 -0
  74. package/swagger/prod/AUTHZ.json +896 -0
  75. package/swagger/prod/CM.json +162 -0
  76. package/swagger/prod/COMMON.json +4910 -0
  77. package/swagger/prod/ES.json +28029 -0
  78. package/swagger/prod/EXPORT.json +3091 -0
  79. package/swagger/prod/LIC.json +123 -0
  80. package/swagger/prod/MSG.json +6239 -0
  81. package/swagger/prod/NEWS.json +295 -0
  82. package/swagger/prod/PA.json +5123 -0
  83. package/swagger/prod/PMP.json +2978 -0
  84. package/swagger/prod/PROXY.json +250 -0
  85. package/swagger/prod/REPORT.json +3729 -0
  86. package/swagger/prod/SC.json +3771 -0
  87. package/swagger/prod/SLA.json +2201 -0
  88. package/swagger/prod/TSTG.json +4220 -0
  89. package/swagger/prod/UI.json +3879 -0
  90. package/swagger/prod/WH.json +16730 -0
  91. package/swagger/prod/WORK.json +35994 -0
  92. package/swagger/prod/WSP.json +1468 -0
@@ -0,0 +1,125 @@
1
+ ---
2
+ topic: roles
3
+ sources:
4
+ - page: adminapp/src/modules/RolesPage/saga.js
5
+ content_hash: dd2943597b30a21c
6
+ - page: adminapp/src/services/requests.js
7
+ content_hash: 54c3d95d85bb0ce0
8
+ - page: adminapp/src/locales/ru/app.json
9
+ content_hash: 22b22046c9336c1a
10
+ ---
11
+
12
+ # Роли и полномочия
13
+
14
+ Роль — набор прав, определяющий уровень доступа пользователя: какие разделы
15
+ видны, какие действия доступны, какие приложения (веб, приложение инженера,
16
+ приложение заказчика) можно открыть. Роль назначается пользователю отдельным
17
+ запросом (`hubex_get_guide topic="users"`).
18
+
19
+ Полномочия делятся на четыре независимых набора, и у каждого свой эндпоинт:
20
+
21
+ | Набор | Справочник | Привязка к роли |
22
+ | --- | --- | --- |
23
+ | API-полномочия (доступ к методам) | `ADM:GET:/PermissionsApi` | `ADM:POST:/RolePermissionsApi` |
24
+ | UI-полномочия (видимость элементов интерфейса) | `ADM:GET:/PermissionsUi` | `ADM:POST:/RolePermissionsUi` |
25
+ | Расширенные полномочия | `ADM:GET:/PermissionsExt` | `ADM:POST:/RolePermissionsExt` |
26
+ | Приложения | `COMMON:GET:/Applications` | `ADM:POST:/RoleApplications` |
27
+
28
+ Полномочия сгруппированы тематическими блоками — теги:
29
+ `ADM:GET:/PermissionApiTags`, `ADM:GET:/SystemPermissionUiTags`,
30
+ `ADM:GET:/PermissionExtTags`.
31
+
32
+ ## 1. Создание роли
33
+
34
+ Веб-клиент делает это в два шага: сначала роль, затем полномочия отдельными
35
+ запросами по каждому набору.
36
+
37
+ ```text
38
+ POST ADM:POST:/Roles → [roleID]
39
+ POST ADM:POST:/RolePermissionsApi → API-полномочия
40
+ POST ADM:POST:/RolePermissionsUi → UI-полномочия
41
+ POST ADM:POST:/RolePermissionsExt → расширенные полномочия
42
+ POST ADM:POST:/RoleApplications → доступные приложения
43
+ ```
44
+
45
+ Тело создания роли — массив: `[{ "name": "Диспетчер", "description": "..." }]`,
46
+ ответ `201` — массив идентификаторов. Изменение названия и описания —
47
+ `ADM:PUT:/Roles` (массив с `id`), удаление — `ADM:DELETE:/Roles/{id}`.
48
+
49
+ Тела привязок — массивы объектов вида `{ roleID, permission...ID }`; точную
50
+ схему бери через `hubex_describe_endpoint`, поля различаются между наборами.
51
+ Снятие полномочия — соответствующий `ADM:DELETE:/RolePermissionsApi`,
52
+ `ADM:DELETE:/RolePermissionsUi`, `ADM:DELETE:/RolePermissionsExt`,
53
+ `ADM:DELETE:/RoleApplications` с тем же телом.
54
+
55
+ ## 2. Роль по шаблону и копирование
56
+
57
+ - Копия роли целиком: `ADM:POST:/Roles/copy` с телом
58
+ `[{ "copiedRoleID": 4, "name": "Копия Диспетчер", "description": "..." }]` —
59
+ создаёт роль вместе со всеми полномочиями одним запросом.
60
+ - Роль «по шаблону» в интерфейсе — это обычное создание: полномочия шаблонной
61
+ роли читаются через `ADM:GET:/Roles/{roleID}/permissionsApi`,
62
+ `ADM:GET:/Roles/{roleID}/permissionsUi`, `ADM:GET:/Roles/{roleID}/permissionsExt`,
63
+ `ADM:GET:/Roles/{roleID}/applications` и затем прописываются новой роли.
64
+ Все четыре GET принимают `isCheckedPermission=false`, чтобы вернуть полный
65
+ список с отметкой, что выбрано.
66
+
67
+ ## 3. Плагины (пакеты) роли
68
+
69
+ - `ADM:GET:/Roles/{roleID}/packages` — список плагинов роли.
70
+ - `ADM:PUT:/Roles/{roleID}/packages/activate` / `.../deactivate` — включение и
71
+ выключение.
72
+ - Плагины тенанта в целом — `ADM:GET:/Tenants/this/packages`.
73
+
74
+ ## 4. Собственные UI-полномочия
75
+
76
+ Кроме системных, в тенанте можно завести свои UI-полномочия и привязывать их к
77
+ переходам жизненного цикла (`permissionUiID` у перехода) и к компонентам формы.
78
+
79
+ ```text
80
+ GET ADM:GET:/PermissionsUi
81
+ POST ADM:POST:/PermissionsUi
82
+ PUT ADM:PUT:/PermissionsUi
83
+ DELETE ADM:DELETE:/PermissionsUi
84
+ ```
85
+
86
+ ## 5. Доступ роли к полям заявки
87
+
88
+ Видимость полей формы заявки настраивается по паре «роль + стадия»:
89
+
90
+ - `TSTG:GET:/TaskStageComponents/availability` с query `roleID`, `taskStageID`,
91
+ `taskTypeID` — что доступно сейчас (компоненты и дополнительные поля).
92
+ - `TSTG:POST:/TaskStageComponents` — запись доступности:
93
+ `[{ "taskStageID": 12, "taskTypeID": 5, "components": [{ "id": 3, "roleID": 7, "capabilityID": 2 }], "attributes": [...] }]`.
94
+ - Справочник уровней доступа (только чтение / чтение и запись / скрыто) —
95
+ `ADM:GET:/Capabilities`.
96
+ - Доступ к дополнительным полям вне контекста стадии —
97
+ `ADM:GET:/RoleTaskPropertiesAccess/attributes`,
98
+ `ADM:POST:/RoleTaskPropertiesAccess/attributes`,
99
+ `ADM:PUT:/RoleTaskPropertiesAccess/attributes`.
100
+
101
+ ## Последовательность MCP-вызовов
102
+
103
+ ```text
104
+ hubex_request_read(endpointId: `ADM:GET:/Roles`)
105
+ hubex_request_write(endpointId: `ADM:POST:/Roles`, body: [{ name, description }])
106
+ → response[0] = roleID
107
+ hubex_request_read(endpointId: `ADM:GET:/PermissionsUi`)
108
+ hubex_request_write(endpointId: `ADM:POST:/RolePermissionsUi`, body: [{ roleID, ... }])
109
+ hubex_request_read(endpointId: `ADM:GET:/Roles/{roleID}/permissionsUi`, pathParams: { roleID }, query: { isCheckedPermission: false })
110
+ ```
111
+
112
+ ## Подводные камни
113
+
114
+ - Создание роли не даёт ей ни одного полномочия: без последующих
115
+ `RolePermissions*` пользователь с этой ролью не увидит ничего.
116
+ - Четыре набора полномочий независимы. Выдать API-полномочие и забыть про
117
+ UI-полномочие — типичная причина «метод работает, но кнопки нет».
118
+ - Для точной копии роли используй `ADM:POST:/Roles/copy`, а не ручной перенос:
119
+ ручной путь легко теряет расширенные полномочия и приложения.
120
+ - GET-эндпоинты полномочий роли возвращают **все** полномочия с отметкой
121
+ выбранных при `isCheckedPermission=false`; без этого параметра список
122
+ сокращённый — не принимай его за полный справочник.
123
+ - Роли и участки — разные измерения доступа: роль определяет, что можно
124
+ делать, участок (`ADM:POST:/UserDistricts`) — с какими объектами и типами
125
+ заявок.
@@ -0,0 +1,130 @@
1
+ ---
2
+ topic: sla
3
+ sources:
4
+ - page: adminapp/src/modules/slaPage/slaCreateForms.js
5
+ content_hash: d4a1651f41ee8605
6
+ - page: adminapp/src/services/requests.js
7
+ content_hash: 54c3d95d85bb0ce0
8
+ - page: adminapp/src/locales/ru/app.json
9
+ content_hash: 22b22046c9336c1a
10
+ ---
11
+
12
+ # SLA и графики работ
13
+
14
+ Правило SLA (`DeadlineRule`) рассчитывает крайний срок закрытия заявки, когда
15
+ он не задан явно в типе заявки (`closeMinutes`) или в виде работ. Правило
16
+ состоит из двух частей:
17
+
18
+ 1. **Само правило** — сколько времени даётся на выполнение и по какому графику
19
+ работ это время считать.
20
+ 2. **Атрибуты правила** — условия, при которых правило применяется
21
+ (критичность, вид работ, тип заявки, компания, объект).
22
+
23
+ ```text
24
+ POST SLA:POST:/DeadlineRules → { id }
25
+ POST SLA:POST:/DeadlineRules/attributes → условия применения
26
+ ```
27
+
28
+ ## 1. Правило
29
+
30
+ ```json
31
+ [
32
+ {
33
+ "name": "Срочные заявки — 4 часа",
34
+ "scheduleRuleID": 2,
35
+ "runtime": 4,
36
+ "isActive": true
37
+ }
38
+ ]
39
+ ```
40
+
41
+ - `runtime` — время выполнения в **часах**, дробное. Веб-клиент переводит
42
+ введённые минуты в часы: 90 минут → `1.5`.
43
+ - `scheduleRuleID` — график работ (`WSP:GET:/ScheduleRules`), по которому
44
+ «тикают» часы: в нерабочее время срок не расходуется.
45
+ - `isActive` — правило включено. Отдельные переключатели —
46
+ `SLA:PUT:/DeadlineRules/{DeadlineRuleID}/activate` и
47
+ `SLA:PUT:/DeadlineRules/{DeadlineRuleID}/deactivate`.
48
+
49
+ Ответ POST — объект с `id` (а не массив идентификаторов, как у большинства
50
+ других сущностей). Изменение — `SLA:PUT:/DeadlineRules` (массив с `id`),
51
+ удаление — `SLA:DELETE:/DeadlineRules/{DeadlineRuleID}`, чтение —
52
+ `SLA:GET:/DeadlineRules` и `SLA:GET:/DeadlineRules/{DeadlineRuleID}`.
53
+
54
+ ## 2. Условия применения
55
+
56
+ Условие — это пара «атрибут SLA + значение». Справочник атрибутов —
57
+ `SLA:GET:/Attributes`; ответ приходит словарём, ключ — идентификатор атрибута.
58
+ В AdminApp используются атрибуты с идентификаторами 1–6, по смыслу:
59
+ критичность, вид работ, тип заявки, компания, объект, объект-исключение.
60
+ Сверяйся с названиями из `SLA:GET:/Attributes`, а не с номерами вслепую.
61
+
62
+ ```json
63
+ [
64
+ {
65
+ "deadlineRuleID": 17,
66
+ "data": [
67
+ { "attributeID": 1, "attrNumbValue": 3 },
68
+ { "attributeID": 2, "attrNumbValue": 12 }
69
+ ]
70
+ }
71
+ ]
72
+ ```
73
+
74
+ `attrNumbValue` — идентификатор значения из соответствующего справочника
75
+ (`SLA:GET:/Criticalities`, `WORK:GET:/WorkTypes`, `WORK:GET:/TaskTypes`,
76
+ `ES:GET:/Companies`, `ES:GET:/Assets`). Несколько компаний или объектов
77
+ передаются несколькими элементами `data` с одним и тем же `attributeID`.
78
+
79
+ Чтение условий правила — `SLA:GET:/DeadlineRules/{deadlineRuleID}/attributes`,
80
+ удаление — `SLA:DELETE:/DeadlineRules/attributes` с телом того же вида.
81
+
82
+ ## 3. Графики работ
83
+
84
+ График (`ScheduleRule`, сервис WSP) описывает рабочие смены: период действия,
85
+ правила по cron, учёт праздников и переопределения отдельных дней.
86
+
87
+ ```text
88
+ GET WSP:GET:/ScheduleRules список
89
+ GET WSP:GET:/ScheduleRules/{id} один график
90
+ GET WSP:GET:/ScheduleRules/holiday производственный календарь
91
+ POST WSP:POST:/ScheduleRules создать
92
+ POST WSP:POST:/ScheduleRules/preview рассчитать смены, ничего не сохраняя
93
+ PUT WSP:PUT:/ScheduleRules/{id} изменить
94
+ PUT WSP:PUT:/ScheduleRules/extend/{id} продлить период действия
95
+ DELETE WSP:DELETE:/ScheduleRules/{id} удалить
96
+ ```
97
+
98
+ Тело создания — **объект**, а не массив: `from`, `till`, `name`,
99
+ `considerPublicHolidays`, `shortageHoursBeforeHoliday`, массив `rules`
100
+ (`cron` + `occurrenceDuration` + периодичность) и `overridings` для
101
+ исключений. Перед сохранением веб-клиент всегда прогоняет
102
+ `WSP:POST:/ScheduleRules/preview` с тем же телом и показывает получившийся
103
+ календарь — делай так же, прежде чем создавать график.
104
+
105
+ ## Последовательность MCP-вызовов
106
+
107
+ ```text
108
+ hubex_request_read(endpointId: `WSP:GET:/ScheduleRules`) → scheduleRuleID
109
+ hubex_request_read(endpointId: `SLA:GET:/Attributes`) → какие условия бывают
110
+ hubex_request_write(endpointId: `SLA:POST:/DeadlineRules`, body: [{ name, scheduleRuleID, runtime, isActive: true }])
111
+ → response.id = deadlineRuleID
112
+ hubex_request_write(endpointId: `SLA:POST:/DeadlineRules/attributes`, body: [{ deadlineRuleID, data: [{ attributeID, attrNumbValue }] }])
113
+ hubex_request_read(endpointId: `SLA:GET:/DeadlineRules/{deadlineRuleID}/attributes`, pathParams: { deadlineRuleID })
114
+ ```
115
+
116
+ ## Подводные камни
117
+
118
+ - `runtime` — часы (дробные), а не минуты: `closeMinutes` типа заявки задаётся
119
+ в минутах, легко перепутать.
120
+ - Правило без условий применяется как общее — проверь, что это действительно
121
+ нужно, прежде чем создавать его в живом тенанте.
122
+ - SLA считает срок только по своему графику работ: без корректного
123
+ `scheduleRuleID` дедлайны разъедутся с реальными сменами.
124
+ - Приоритет расчёта дедлайна: явный срок типа заявки и вида работ (берётся
125
+ **меньший**), и только если оба не заданы — правила SLA.
126
+ - Ответ `SLA:POST:/DeadlineRules` — объект `{ id }`; не пытайся читать его как
127
+ массив, в отличие от большинства POST-эндпоинтов HubEx.
128
+ - Обрати внимание на регистр параметров пути в этом сервисе: у части
129
+ эндпоинтов он `DeadlineRuleID`, у части — `deadlineRuleID`; сверяйся с
130
+ `hubex_describe_endpoint`.
@@ -0,0 +1,67 @@
1
+ ---
2
+ topic: start
3
+ sources:
4
+ - page: admin/StartIntegrationAPI.md
5
+ content_hash: 696caf08f152c57a
6
+ - page: admin/RESTAPI.md
7
+ content_hash: 39aca4ceab766e3e
8
+ ---
9
+
10
+ # Начало работы
11
+
12
+ HubEx REST API организован по сервисам: у каждого сервиса свой базовый URL
13
+ и своя OpenAPI-схема. Этот MCP-сервер работает поверх этих сервисов и
14
+ предоставляет собственный набор инструментов.
15
+
16
+ ## Базовые сведения о протоколе
17
+
18
+ - Базовый URL сервиса: `https://{env}-api.hubex.ru/fsm/{SERVICE}`, где
19
+ `env` — окружение (`dev`, `stg`); на проде префикса нет — `https://api.hubex.ru/fsm/{SERVICE}`. `SERVICE` — код сервиса
20
+ (`WORK`, `ES`, `ADM`, `AUTHZ`, `AUTHN`, `PA`, `SLA` и т.д.).
21
+ - Каждый запрос требует **два** заголовка: `Authorization: Bearer <access_token>`
22
+ и `X-Application-ID: <id приложения>`. Без второго заголовка сервер вернёт
23
+ ошибку 403 «Не найден обязательный заголовок [X-Application-ID]».
24
+ - Access-токен — JWT, действует ограниченное время (в вики указано 30 минут)
25
+ и получается отдельным запросом по сервисному токену; для этого сервера
26
+ обновление токена уже реализовано отдельным механизмом авторизации — вручную
27
+ вызывать `AUTHZ:POST:/AccessTokens` не нужно.
28
+ - HTTP-методы соответствуют обычной семантике REST: `GET` — чтение
29
+ (идемпотентно, не меняет данные), `POST` — создание/действие (не
30
+ идемпотентно), `PUT` — полная замена записи (идемпотентно, требует
31
+ **все** поля), `PATCH` — частичное обновление (идемпотентно, только
32
+ изменяемые поля), `DELETE` — удаление (идемпотентно, обычно помечает
33
+ запись удалённой, а не стирает физически).
34
+ - Ответы на GET-запросы коллекций приходят **словарём**, а не массивом:
35
+ `{ "5136": { ...поля }, "5135": { ...поля } }`, где ключ — id записи.
36
+ Ошибки возвращаются массивом объектов `{ traceIdentifier, code, message }`.
37
+ - Для каждого запроса списка всегда передавай оба query-параметра пагинации:
38
+ `fetch` (сколько записей) и `offset` (смещение). Один только `fetch`
39
+ недостаточен — без `offset` запрос может не отработать.
40
+
41
+ ## Порядок работы с этим сервером
42
+
43
+ 1. `hubex_list_scopes` — узнать, какие сервисы и предметные области доступны.
44
+ 2. `hubex_search_*_endpoints` (например поиск по сервису или ключевому
45
+ слову) — найти нужный эндпоинт, не читая весь swagger вручную.
46
+ 3. `hubex_describe_endpoint` — получить полную JSON Schema тела и параметров
47
+ найденного эндпоинта, уже с аннотациями бизнес-полей (описание,
48
+ обязательность, справочник-подсказка, если поле есть в оверлее).
49
+ 4. `hubex_request_*` — выполнить сам HTTP-запрос к HubEx с телом, собранным
50
+ по схеме из шага 3.
51
+
52
+ Перед первой работой с конкретной предметной областью (заявки, объекты,
53
+ компании, пользователи) стоит сначала прочитать соответствующий гайд
54
+ (`hubex_get_guide`) — там короткий порядок вызовов, обязательные поля и
55
+ типичные ошибки, собранные из бизнес-документации HubEx.
56
+
57
+ ## Подводные камни
58
+
59
+ - Забытый `X-Application-ID` — самая частая причина 403 при первом запросе:
60
+ одного `Authorization: Bearer` недостаточно.
61
+ - Коллекции — словари по id, а не массивы: код, который ожидает `Array`,
62
+ сломается на `Object.keys()`/итерации по ключам.
63
+ - В запросах списков указывай и `fetch`, и `offset`, даже если нужна первая
64
+ страница: например, `fetch=100&offset=0`.
65
+ - `PUT` требует полное тело записи (все поля, включая неизменяемые в этом
66
+ запросе), а не только то, что меняется — для частичного обновления
67
+ используй `PATCH`, если эндпоинт его поддерживает.
@@ -0,0 +1,149 @@
1
+ ---
2
+ topic: taskchecklists
3
+ sources:
4
+ - page: admin/ExampleRequestsAPI.md
5
+ content_hash: ad3e2bf92fe6a736
6
+ - page: admin/TicketLifeCycle.md
7
+ content_hash: 60be5a94c8573779
8
+ ---
9
+
10
+ # Редактирование чек-листов в заявке
11
+
12
+ Этот гайд описывает заполнение и изменение уже прикреплённых чек-листов на
13
+ вкладке «Чек-листы» в карточке созданной заявки. Он не изменяет шаблон
14
+ чек-листа, его пункты или привязки к объектам и видам работ.
15
+
16
+ Шаблон чек-листа и его экземпляр в заявке — разные сущности: не смешивай их
17
+ идентификаторы.
18
+
19
+ | Идентификатор | Что обозначает | Где используется |
20
+ | --- | --- | --- |
21
+ | `checkListID` | шаблон чек-листа | добавить шаблон в заявку |
22
+ | `taskCheckListID` | экземпляр шаблона в конкретной заявке | читать и записывать ответы, удалить из заявки |
23
+ | `id` результата | пункт (результат) внутри экземпляра | поле `id` в теле сохранения |
24
+
25
+ MainApp не сохраняет ответ при каждом нажатии. Оно держит все ответы в
26
+ `redux-form` формы заявки и отправляет на сервер только при сохранении заявки.
27
+ Порядок для агента безопаснее сделать явным: записать результаты, дождаться
28
+ успеха, затем отдельно перевести заявку на следующую стадию.
29
+
30
+ ## 1. Прочитай чек-листы и их пункты
31
+
32
+ 1. `WORK:GET:/Tasks/{taskID}/checkLists` — экземпляры чек-листов в заявке.
33
+ Ответ — словарь, где ключ — `taskCheckListID`. Значения содержат шаблон в
34
+ `checkList`, а также `totalItemsCount` и `completedItemsCount`.
35
+ 2. Для каждого ключа вызови
36
+ `WORK:GET:/Tasks/{taskID}/checkLists/{taskCheckListID}/results/v2`.
37
+ Это актуальная версия API; старый путь без `/v2` помечен в swagger как
38
+ устаревший. Ответ тоже словарь, а его ключ — `id` пункта, который нужен при
39
+ сохранении.
40
+
41
+ В MainApp загрузка устроена именно так: сначала список экземпляров, затем
42
+ результаты каждого экземпляра. Пункты сортируются по `sortOrder`, а прогресс
43
+ в шапке — `completedItemsCount / totalItemsCount` из первого ответа.
44
+
45
+ Для работы нужны права `TaskCheckListsList` и `TaskCheckListResultsList`.
46
+
47
+ ## 2. Измени пункт
48
+
49
+ Каждый пункт отображается как флажок выполнения `isChecked` и, если у него
50
+ есть атрибут кроме `Switch`, как поле значения. Поле выбирается из
51
+ `attributeType.code`:
52
+
53
+ | Тип | Представление в MainApp | Значение для API v2 |
54
+ | --- | --- | --- |
55
+ | `Switch` | только флажок | `values: []`, состояние в `isChecked` |
56
+ | `String`, `Int`, `Decimal`, `Text` | строка, число или многострочный текст | массив из одной строки |
57
+ | `Date`, `Datetime` | дата или дата-время | массив из одной ISO-строки |
58
+ | `Select` | один вариант | массив с одним id варианта |
59
+ | `MultiSelect` | несколько вариантов | массив id вариантов |
60
+ | `Attachment`, `Drawing` | список файлов | массив id вложений |
61
+ | атрибут с `domain` | справочник домена | один или несколько id из справочника |
62
+
63
+ Когда пользователь вводит непустое значение, интерфейс отмечает пункт как
64
+ выполненный; очистка значения снимает флажок. Флажок можно переключить и
65
+ отдельно. В API передавай оба поля явно:
66
+
67
+ ```json
68
+ // WORK:PUT:/Tasks/{taskID}/checkLists/{taskCheckListID}/results/v2
69
+ [
70
+ {
71
+ "id": 9151,
72
+ "isChecked": true,
73
+ "values": ["12.5"]
74
+ },
75
+ {
76
+ "id": 9152,
77
+ "isChecked": true,
78
+ "values": ["2026-08-13T12:00:00"]
79
+ },
80
+ {
81
+ "id": 9153,
82
+ "isChecked": true,
83
+ "values": []
84
+ }
85
+ ]
86
+ ```
87
+
88
+ Тело — массив изменённых пунктов. MainApp сравнивает форму с последним
89
+ ответом API и не отправляет неизменённые строки. `values`, а не `value`, —
90
+ контракт v2. Не используй устаревший `results`, где было строковое поле
91
+ `value`.
92
+
93
+ Перед записью проверь точную схему через
94
+ `hubex_describe_endpoint` для
95
+ `WORK:PUT:/Tasks/{taskID}/checkLists/{taskCheckListID}/results/v2`: swagger
96
+ требует только `id`, но для фактического изменения передавай и `isChecked`, и
97
+ `values`.
98
+
99
+ ## 3. Вложения и рисунки
100
+
101
+ Новый файл MainApp сначала загружает отдельно, а потом сохраняет возвращённые
102
+ идентификаторы вместе с результатом пункта.
103
+
104
+ 1. `WORK:POST:/Tasks/{taskID}/checkLists/{taskCheckListID}/upload/fromForm` —
105
+ `multipart/form-data`: `TaskCheckListResultID`, а каждый файл —
106
+ `Attachments.Index`, `Attachments[N].File`,
107
+ `Attachments[N].IsIgnorePossibleDuplication=true`.
108
+ 2. Возьми идентификаторы из `attachments` ответа и передай их строками в
109
+ `values` через `WORK:PUT:/Tasks/{taskID}/checkLists/{taskCheckListID}/results/v2`.
110
+
111
+ Для чтения метаданных вложений есть
112
+ `WORK:GET:/Tasks/{taskID}/checkLists/{taskCheckListID}/results/attachments`.
113
+ Для загрузки нужно полномочие `TaskCheckListResultAttachmentUpload`, для
114
+ сохранения — `TaskCheckListResultSet`.
115
+
116
+ ## 4. Сохранение и переход стадии
117
+
118
+ В MainApp цепочка редактирования такая:
119
+
120
+ ```text
121
+ редактирование полей заявки
122
+
123
+ PATCH заявки
124
+
125
+ PUT результатов чек-листов v2 (только изменённые пункты)
126
+
127
+ запись выполненных работ и дополнительных полей
128
+
129
+ переход на новую стадию
130
+ ```
131
+
132
+ Поэтому не меняй стадию параллельно с чек-листом. Если у целевой стадии
133
+ требование `CheckListsCompleted`, сервер не пропустит переход, пока не будут
134
+ заполнены все необходимые пункты. Требования стадии читай через
135
+ `TSTG:GET:/TaskStages/{id}/requirements`; затем выполняй переход способом из
136
+ гайда `hubex_get_guide topic="taskedit"`.
137
+
138
+ ## Подводные камни
139
+
140
+ - Списки и результаты приходят словарями по id, не массивами. Сохраняй ключи:
141
+ UI нормализует их только для отображения.
142
+ - `Switch` не хранит булево значение в `values`: единственный источник его
143
+ состояния — `isChecked`.
144
+ - Пустой `values` означает отсутствие значения. При очистке уже заполненного
145
+ пункта передай `isChecked: false` и `values: []`.
146
+ - Для `Attachment`/`Drawing` не посылай объекты файлов, URL или локальные
147
+ имена. Сервер ожидает только id уже загруженных вложений.
148
+ - MainApp перезагружает результаты после записи. Делай то же, если нужно
149
+ вернуть пользователю новый прогресс или удостовериться в сохранении.