mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-11 00:14:56 +03:00
Merge branch 'dev'
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: role-compile
|
||||
description: Создание роли 1С — метаданные и Rights.xml из описания прав
|
||||
argument-hint: <RoleName> <RolesDir>
|
||||
argument-hint: <JsonPath> <RolesDir>
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
@@ -9,199 +9,101 @@ allowed-tools:
|
||||
- Glob
|
||||
---
|
||||
|
||||
# /role-compile — создание роли 1С
|
||||
# /role-compile — генерация роли 1С из JSON DSL
|
||||
|
||||
Создаёт файлы роли (метаданные + Rights.xml) по описанию прав. Скрипта нет — агент генерирует XML по шаблонам ниже.
|
||||
Принимает JSON-определение роли → генерирует `Roles/Имя.xml` (метаданные) и `Roles/Имя/Ext/Rights.xml` (права). UUID автоматически.
|
||||
|
||||
## Использование
|
||||
## Параметры и команда
|
||||
|
||||
```
|
||||
/role-compile <RoleName> <RolesDir>
|
||||
| Параметр | Описание |
|
||||
|----------|----------|
|
||||
| `JsonPath` | Путь к JSON-определению роли |
|
||||
| `RolesDir` | Каталог `Roles/` в исходниках конфигурации |
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -File .claude\skills\role-compile\scripts\role-compile.ps1 -JsonPath "<json>" -OutputDir "<RolesDir>"
|
||||
```
|
||||
|
||||
- **RoleName** — программное имя роли
|
||||
- **RolesDir** — каталог `Roles/` в исходниках конфигурации
|
||||
`<Role>ИмяРоли</Role>` автоматически добавляется в `<ChildObjects>` файла `Configuration.xml` (ожидается в parent от `RolesDir`).
|
||||
|
||||
## Файловая структура и регистрация
|
||||
## JSON DSL
|
||||
|
||||
```
|
||||
Roles/
|
||||
ИмяРоли.xml ← метаданные (uuid, имя, синоним)
|
||||
ИмяРоли/
|
||||
Ext/
|
||||
Rights.xml ← определение прав
|
||||
### Структура
|
||||
|
||||
```json
|
||||
{ "name": "ИмяРоли", "synonym": "Отображаемое имя", "objects": [...], "templates": [...] }
|
||||
```
|
||||
|
||||
В `Configuration.xml` добавить `<Role>ИмяРоли</Role>` в секцию `<ChildObjects>`.
|
||||
Необязательные: `comment` (""), `setForNewObjects` (false), `setForAttributesByDefault` (true), `independentRightsOfChildObjects` (false).
|
||||
|
||||
## Шаблон метаданных: Roles/ИмяРоли.xml
|
||||
### Shorthand-строки и объектная форма
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses"
|
||||
xmlns:v8="http://v8.1c.ru/8.1/data/core"
|
||||
xmlns:xr="http://v8.1c.ru/8.3/xcf/readable"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
version="2.17">
|
||||
<Role uuid="GENERATE-UUID-HERE">
|
||||
<Properties>
|
||||
<Name>ИмяРоли</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Отображаемое имя роли</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
</Properties>
|
||||
</Role>
|
||||
</MetaDataObject>
|
||||
```json
|
||||
"objects": [
|
||||
"Catalog.Номенклатура: @view",
|
||||
"Document.Реализация: @edit",
|
||||
"DataProcessor.Загрузка: @view",
|
||||
"InformationRegister.Цены: Read, Update",
|
||||
{ "name": "Document.Продажа", "preset": "view", "rights": {"Delete": false}, "rls": {"Read": "#Шаблон(\"\")"} }
|
||||
]
|
||||
```
|
||||
|
||||
**UUID:** `powershell.exe -Command "[guid]::NewGuid().ToString()"`
|
||||
- Shorthand: `"Тип.Имя: @пресет"` или `"Тип.Имя: Право1, Право2"`
|
||||
- Объектная форма: `preset` + `rights` (переопределения) + `rls` (ограничения)
|
||||
|
||||
## Шаблон прав: Roles/ИмяРоли/Ext/Rights.xml
|
||||
### Пресеты
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Rights xmlns="http://v8.1c.ru/8.2/roles"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:type="Rights" version="2.17">
|
||||
<setForNewObjects>false</setForNewObjects>
|
||||
<setForAttributesByDefault>true</setForAttributesByDefault>
|
||||
<independentRightsOfChildObjects>false</independentRightsOfChildObjects>
|
||||
<!-- блоки <object> -->
|
||||
</Rights>
|
||||
| Пресет | Действие |
|
||||
|--------|----------|
|
||||
| `@view` | Просмотр — Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
|
||||
| `@edit` | Полное редактирование — CRUD + Interactive* + Posting (документы) |
|
||||
|
||||
`@` обязателен в shorthand. В объектной форме — `"preset": "view"` без `@`.
|
||||
|
||||
Для сервисов (WebService, HTTPService, IntegrationService) пресеты не определены — используй явные права: `"WebService.Имя: Use"`.
|
||||
|
||||
### Русские синонимы
|
||||
|
||||
Поддерживаются русские типы (`Справочник`→Catalog, `Документ`→Document) и права (`Чтение`→Read, `Просмотр`→View). Смешивание допустимо: `"Справочник.Контрагенты: Чтение, View"`.
|
||||
|
||||
### Шаблоны RLS
|
||||
|
||||
```json
|
||||
"templates": [{"name": "ДляОбъекта(Мод)", "condition": "ГДЕ Организация = &ТекОрг"}]
|
||||
```
|
||||
|
||||
NB: namespace `http://v8.1c.ru/8.2/roles` (исторически 8.2, не 8.3).
|
||||
Ссылка в `rls`: `"#ДляОбъекта(\"\")"`. Символ `&` автоматически экранируется в XML.
|
||||
|
||||
## Формат блока прав
|
||||
## Примеры
|
||||
|
||||
```xml
|
||||
<object>
|
||||
<name>Catalog.Номенклатура</name>
|
||||
<right><name>Read</name><value>true</value></right>
|
||||
<right><name>View</name><value>true</value></right>
|
||||
</object>
|
||||
### Простая роль
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ЧтениеНоменклатуры", "synonym": "Чтение номенклатуры",
|
||||
"objects": ["Catalog.Номенклатура: @view", "Catalog.Контрагенты: @view", "DataProcessor.Загрузка: @view"]
|
||||
}
|
||||
```
|
||||
|
||||
Имя объекта — dot-нотация: `ТипОбъекта.Имя[.ТипВложенного.ИмяВложенного]`.
|
||||
### Роль с RLS
|
||||
|
||||
## Практические наборы прав
|
||||
|
||||
### Catalog / ExchangePlan
|
||||
|
||||
| Набор | Права |
|
||||
|-------|-------|
|
||||
| Чтение | Read, View, InputByString |
|
||||
| Полные | Read, Insert, Update, Delete, View, Edit, InputByString, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark |
|
||||
|
||||
### Document
|
||||
|
||||
| Набор | Права |
|
||||
|-------|-------|
|
||||
| Чтение | Read, View, InputByString |
|
||||
| Полные | Read, Insert, Update, Delete, View, Edit, InputByString, Posting, UndoPosting, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractivePosting, InteractivePostingRegular, InteractiveUndoPosting, InteractiveChangeOfPosted |
|
||||
|
||||
### InformationRegister / AccumulationRegister / AccountingRegister
|
||||
|
||||
| Набор | Права |
|
||||
|-------|-------|
|
||||
| Чтение | Read, View |
|
||||
| Полные | Read, Update, View, Edit |
|
||||
|
||||
TotalsControl — только для управления итогами, обычно не нужно.
|
||||
|
||||
### Простые типы
|
||||
|
||||
| Тип | Права |
|
||||
|-----|-------|
|
||||
| `DataProcessor` / `Report` | Use, View |
|
||||
| `Constant` | Read, Update, View, Edit (чтение: Read, View) |
|
||||
| `CommonForm` / `CommonCommand` / `Subsystem` / `FilterCriterion` | View |
|
||||
| `DocumentJournal` | Read, View |
|
||||
| `Sequence` | Read, Update |
|
||||
| `SessionParameter` | Get (+ Set если пишет) |
|
||||
| `CommonAttribute` | View (+ Edit если редактирует) |
|
||||
| `WebService` / `HTTPService` / `IntegrationService` | Use |
|
||||
| `CalculationRegister` | Read, View |
|
||||
|
||||
### Редкие ссылочные типы
|
||||
|
||||
| Тип | Особенности (относительно Catalog) |
|
||||
|-----|-------|
|
||||
| `ChartOfAccounts`, `ChartOfCharacteristicTypes`, `ChartOfCalculationTypes` | + Predefined-права (InteractiveDeletePredefinedData и др.) |
|
||||
| `BusinessProcess` | + Start, InteractiveStart, InteractiveActivate |
|
||||
| `Task` | + Execute, InteractiveExecute, InteractiveActivate |
|
||||
|
||||
### Типы БЕЗ прав в ролях
|
||||
|
||||
Enum, FunctionalOption, DefinedType, CommonModule, CommonPicture, CommonTemplate — не фигурируют в Rights.xml.
|
||||
|
||||
### Вложенные объекты (права: View, Edit)
|
||||
|
||||
```
|
||||
Catalog.Контрагенты.Attribute.ИНН
|
||||
Document.Реализация.StandardAttribute.Posted
|
||||
Document.Реализация.TabularSection.Товары
|
||||
InformationRegister.Цены.Dimension.Номенклатура
|
||||
InformationRegister.Цены.Resource.Цена
|
||||
Catalog.Контрагенты.Command.ОткрытьКарточку ← только View
|
||||
Task.Задача.AddressingAttribute.Исполнитель
|
||||
```json
|
||||
{
|
||||
"name": "ЧтениеДокументовПоОрганизации",
|
||||
"synonym": "Чтение документов (ограничение по организации)",
|
||||
"objects": [
|
||||
"Catalog.Организации: @view",
|
||||
{"name": "Document.РеализацияТоваровУслуг", "preset": "view", "rls": {"Read": "#ДляОбъекта(\"\")"}}
|
||||
],
|
||||
"templates": [{"name": "ДляОбъекта(Модификатор)", "condition": "ГДЕ Организация = &ТекущаяОрганизация"}]
|
||||
}
|
||||
```
|
||||
|
||||
Используются для точечного запрета: `<value>false</value>` на конкретный реквизит.
|
||||
Подробные таблицы пресетов, русских синонимов и дополнительные примеры — в `dsl-reference.md`.
|
||||
|
||||
### Configuration
|
||||
## Верификация
|
||||
|
||||
Объект: `Configuration.ИмяКонфигурации`. Ключевые права: Administration, DataAdministration, ThinClient, WebClient, ThickClient, MobileClient, ExternalConnection, Output, SaveUserData, InteractiveOpenExtDataProcessors, InteractiveOpenExtReports, MainWindowModeNormal, MainWindowModeWorkplace, MainWindowModeEmbeddedWorkplace, MainWindowModeFullscreenWorkplace, MainWindowModeKiosk, AnalyticsSystemClient.
|
||||
|
||||
> DataHistory-права (ReadDataHistory, UpdateDataHistory и др.) существуют у Catalog, Document, Register, Constant — но используются крайне редко, в типовых ролях практически не встречаются.
|
||||
|
||||
## RLS (ограничения на уровне записей)
|
||||
|
||||
Внутрь `<right>`, после `<value>`. Применяется к Read, Update, Insert, Delete.
|
||||
|
||||
```xml
|
||||
<right>
|
||||
<name>Read</name>
|
||||
<value>true</value>
|
||||
<restrictionByCondition>
|
||||
<condition>#ИмяШаблона("Параметр1", "Параметр2")</condition>
|
||||
</restrictionByCondition>
|
||||
</right>
|
||||
```
|
||||
|
||||
Шаблоны — в конце Rights.xml, после всех `<object>`:
|
||||
|
||||
```xml
|
||||
<restrictionTemplate>
|
||||
<name>ИмяШаблона(Параметр1, Параметр2)</name>
|
||||
<condition>Текст шаблона</condition>
|
||||
</restrictionTemplate>
|
||||
/role-validate <RightsPath> [MetadataPath] — проверка корректности XML, прав, RLS
|
||||
/role-info <RightsPath> — визуальная сводка структуры
|
||||
```
|
||||
|
||||
`&` в условии → `&`. Типичные шаблоны: ДляОбъекта, ПоЗначениям, ДляРегистра.
|
||||
|
||||
## Пример: роль для регламентного задания
|
||||
|
||||
```xml
|
||||
<object>
|
||||
<name>Catalog.Валюты</name>
|
||||
<right><name>Read</name><value>true</value></right>
|
||||
</object>
|
||||
<object>
|
||||
<name>InformationRegister.КурсыВалют</name>
|
||||
<right><name>Read</name><value>true</value></right>
|
||||
<right><name>Update</name><value>true</value></right>
|
||||
</object>
|
||||
<object>
|
||||
<name>Constant.ОсновнаяВалюта</name>
|
||||
<right><name>Read</name><value>true</value></right>
|
||||
</object>
|
||||
```
|
||||
|
||||
Фоновые задания не требуют Interactive/View/Edit-прав и прав конфигурации (ThinClient, WebClient и др.) — только программные (Read, Insert, Update, Delete, Posting).
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
# Role DSL — полная справка
|
||||
|
||||
Подробная справка по JSON DSL для `/role-compile`. Компактное описание — в [SKILL.md](SKILL.md).
|
||||
|
||||
## Структура верхнего уровня
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ИмяРоли",
|
||||
"synonym": "Отображаемое имя роли",
|
||||
"comment": "",
|
||||
"setForNewObjects": false,
|
||||
"setForAttributesByDefault": true,
|
||||
"independentRightsOfChildObjects": false,
|
||||
"objects": [ ... ],
|
||||
"templates": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
- `name` — программное имя роли (обязательно)
|
||||
- `synonym` — отображаемое имя (по умолчанию = name)
|
||||
- `comment` — комментарий (по умолчанию пусто)
|
||||
- Глобальные флаги — по умолчанию `false`, `true`, `false`
|
||||
|
||||
## Объекты: два формата
|
||||
|
||||
Массив `objects` принимает строки (shorthand) и объекты (полная форма).
|
||||
|
||||
### Строковый shorthand
|
||||
|
||||
```
|
||||
"ОбъектМетаданных: @пресет"
|
||||
"ОбъектМетаданных: Право1, Право2"
|
||||
```
|
||||
|
||||
Примеры:
|
||||
```json
|
||||
"objects": [
|
||||
"Catalog.Номенклатура: @view",
|
||||
"Document.Реализация: @edit",
|
||||
"InformationRegister.Цены: Read, Update",
|
||||
"DataProcessor.Загрузка: @view"
|
||||
]
|
||||
```
|
||||
|
||||
### Объектная форма (для RLS и переопределений)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Document.Реализация",
|
||||
"preset": "view",
|
||||
"rights": { "Delete": false },
|
||||
"rls": { "Read": "#ДляОбъекта(\"\")" }
|
||||
}
|
||||
```
|
||||
|
||||
- `preset` — базовый набор прав (`"view"`, `"edit"`)
|
||||
- `rights` — переопределения: dict `{"Right": true/false}` или массив `["Right1", "Right2"]`
|
||||
- `rls` — RLS-ограничения: `{"ИмяПрава": "текст условия"}`
|
||||
|
||||
## Пресеты — подробные таблицы
|
||||
|
||||
Пресеты обозначаются `@` в строковом формате. В объектной форме ключ `preset` без `@`.
|
||||
|
||||
### `@view` — просмотр
|
||||
|
||||
| Тип объекта | Права |
|
||||
|-------------|-------|
|
||||
| Catalog, ExchangePlan, Document, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task | Read, View, InputByString |
|
||||
| InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, Constant, DocumentJournal | Read, View |
|
||||
| Sequence | Read |
|
||||
| CommonForm, CommonCommand, Subsystem, FilterCriterion, CommonAttribute | View |
|
||||
| DataProcessor, Report | Use, View |
|
||||
| SessionParameter | Get |
|
||||
| Configuration | ThinClient, WebClient, Output, SaveUserData, MainWindowModeNormal |
|
||||
|
||||
### `@edit` — полное редактирование
|
||||
|
||||
| Тип объекта | Права |
|
||||
|-------------|-------|
|
||||
| Catalog, ExchangePlan, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes | Read, Insert, Update, Delete, View, Edit, InputByString, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark |
|
||||
| Document | Read, Insert, Update, Delete, View, Edit, InputByString, Posting, UndoPosting, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractivePosting, InteractivePostingRegular, InteractiveUndoPosting, InteractiveChangeOfPosted |
|
||||
| BusinessProcess | Read, Insert, Update, Delete, View, Edit, InputByString, Start, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractiveActivate, InteractiveStart |
|
||||
| Task | Read, Insert, Update, Delete, View, Edit, InputByString, Execute, InteractiveInsert, InteractiveSetDeletionMark, InteractiveClearDeletionMark, InteractiveActivate, InteractiveExecute |
|
||||
| InformationRegister, AccumulationRegister, AccountingRegister, Constant | Read, Update, View, Edit |
|
||||
| DocumentJournal | Read, View |
|
||||
| Sequence | Read, Update |
|
||||
| SessionParameter | Get, Set |
|
||||
| CommonAttribute | View, Edit |
|
||||
|
||||
Для сервисов (WebService, HTTPService, IntegrationService) пресеты не определены — используй явные права: `"WebService.Имя: Use"`.
|
||||
|
||||
Если пресет не определён для типа объекта — предупреждение с подсказкой доступных.
|
||||
|
||||
## Русские синонимы
|
||||
|
||||
Скрипт автоматически транслирует русские имена в английские. Можно смешивать: `"Справочник.Контрагенты: Чтение, View"` — работает.
|
||||
|
||||
### Типы объектов
|
||||
|
||||
| Русский | English |
|
||||
|---------|---------|
|
||||
| `Справочник` | Catalog |
|
||||
| `Документ` | Document |
|
||||
| `РегистрСведений` | InformationRegister |
|
||||
| `РегистрНакопления` | AccumulationRegister |
|
||||
| `РегистрБухгалтерии` | AccountingRegister |
|
||||
| `РегистрРасчета` | CalculationRegister |
|
||||
| `Константа` | Constant |
|
||||
| `ПланСчетов` | ChartOfAccounts |
|
||||
| `ПланВидовХарактеристик` | ChartOfCharacteristicTypes |
|
||||
| `ПланВидовРасчета` | ChartOfCalculationTypes |
|
||||
| `ПланОбмена` | ExchangePlan |
|
||||
| `БизнесПроцесс` | BusinessProcess |
|
||||
| `Задача` | Task |
|
||||
| `Обработка` | DataProcessor |
|
||||
| `Отчет` | Report |
|
||||
| `ОбщаяФорма` | CommonForm |
|
||||
| `ОбщаяКоманда` | CommonCommand |
|
||||
| `Подсистема` | Subsystem |
|
||||
| `КритерийОтбора` | FilterCriterion |
|
||||
| `ЖурналДокументов` | DocumentJournal |
|
||||
| `Последовательность` | Sequence |
|
||||
| `ВебСервис` | WebService |
|
||||
| `HTTPСервис` | HTTPService |
|
||||
| `СервисИнтеграции` | IntegrationService |
|
||||
| `ПараметрСеанса` | SessionParameter |
|
||||
| `ОбщийРеквизит` | CommonAttribute |
|
||||
| `Конфигурация` | Configuration |
|
||||
| `Перечисление` | Enum |
|
||||
|
||||
### Вложенные типы
|
||||
|
||||
| Русский | English |
|
||||
|---------|---------|
|
||||
| `Реквизит` | Attribute |
|
||||
| `СтандартныйРеквизит` | StandardAttribute |
|
||||
| `ТабличнаяЧасть` | TabularSection |
|
||||
| `Измерение` | Dimension |
|
||||
| `Ресурс` | Resource |
|
||||
| `Команда` | Command |
|
||||
| `РеквизитАдресации` | AddressingAttribute |
|
||||
|
||||
### Права (основные)
|
||||
|
||||
| Русский | English |
|
||||
|---------|---------|
|
||||
| `Чтение` | Read |
|
||||
| `Добавление` | Insert |
|
||||
| `Изменение` | Update |
|
||||
| `Удаление` | Delete |
|
||||
| `Просмотр` | View |
|
||||
| `Редактирование` | Edit |
|
||||
| `ВводПоСтроке` | InputByString |
|
||||
| `Проведение` | Posting |
|
||||
| `ОтменаПроведения` | UndoPosting |
|
||||
| `Использование` | Use |
|
||||
| `Получение` | Get |
|
||||
| `Установка` | Set |
|
||||
| `Старт` | Start |
|
||||
| `Выполнение` | Execute |
|
||||
| `УправлениеИтогами` | TotalsControl |
|
||||
|
||||
### Права (интерактивные)
|
||||
|
||||
| Русский | English |
|
||||
|---------|---------|
|
||||
| `ИнтерактивноеДобавление` | InteractiveInsert |
|
||||
| `ИнтерактивнаяПометкаУдаления` | InteractiveSetDeletionMark |
|
||||
| `ИнтерактивноеСнятиеПометкиУдаления` | InteractiveClearDeletionMark |
|
||||
| `ИнтерактивноеУдаление` | InteractiveDelete |
|
||||
| `ИнтерактивноеУдалениеПомеченных` | InteractiveDeleteMarked |
|
||||
| `ИнтерактивноеПроведение` | InteractivePosting |
|
||||
| `ИнтерактивноеПроведениеНеоперативное` | InteractivePostingRegular |
|
||||
| `ИнтерактивнаяОтменаПроведения` | InteractiveUndoPosting |
|
||||
| `ИнтерактивноеИзменениеПроведенных` | InteractiveChangeOfPosted |
|
||||
| `ИнтерактивныйСтарт` | InteractiveStart |
|
||||
| `ИнтерактивнаяАктивация` | InteractiveActivate |
|
||||
| `ИнтерактивноеВыполнение` | InteractiveExecute |
|
||||
|
||||
### Права (конфигурация)
|
||||
|
||||
| Русский | English |
|
||||
|---------|---------|
|
||||
| `Администрирование` | Administration |
|
||||
| `АдминистрированиеДанных` | DataAdministration |
|
||||
| `ТонкийКлиент` | ThinClient |
|
||||
| `ТолстыйКлиент` | ThickClient |
|
||||
| `ВебКлиент` | WebClient |
|
||||
| `МобильныйКлиент` | MobileClient |
|
||||
| `ВнешнееСоединение` | ExternalConnection |
|
||||
| `Вывод` | Output |
|
||||
| `СохранениеДанныхПользователя` | SaveUserData |
|
||||
|
||||
## Типы объектов без прав в ролях
|
||||
|
||||
Следующие типы 1С **не могут** иметь права в ролях (не добавляются в `objects`):
|
||||
|
||||
| Тип | Причина |
|
||||
|-----|---------|
|
||||
| Enum (Перечисление) | Права наследуются от конфигурации, явное назначение невозможно |
|
||||
| CommonModule (ОбщийМодуль) | Не имеет собственных прав в роли |
|
||||
| DefinedType (ОпределяемыйТип) | Тип данных, не объект прав |
|
||||
| CommonPicture (ОбщаяКартинка) | Ресурс, не объект прав |
|
||||
| CommonTemplate (ОбщийМакет) | Ресурс, не объект прав |
|
||||
| Language (Язык) | Конфигурационный элемент |
|
||||
| FunctionalOption (ФункциональнаяОпция) | Не объект прав |
|
||||
| FunctionalOptionsParameter | Не объект прав |
|
||||
| EventSubscription (ПодпискаНаСобытие) | Не объект прав |
|
||||
| ScheduledJob (РегламентноеЗадание) | Не объект прав |
|
||||
| StyleItem (ЭлементСтиля) | Ресурс оформления |
|
||||
|
||||
## Шаблоны ограничений (RLS templates)
|
||||
|
||||
```json
|
||||
"templates": [
|
||||
{
|
||||
"name": "ДляОбъекта(Модификатор)",
|
||||
"condition": "// текст шаблона\nГДЕ 1=1\n&Модификатор"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- `&` в условии автоматически экранируется в `&` в XML
|
||||
- Ссылка на шаблон в `rls`: `"#ИмяШаблона(\"параметры\")"` — начинается с `#`
|
||||
- Параметры шаблона можно передавать пустыми: `#ДляОбъекта("")`
|
||||
|
||||
## Примеры
|
||||
|
||||
### 1. Простая роль (только пресеты)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ЧтениеНоменклатуры",
|
||||
"synonym": "Чтение номенклатуры",
|
||||
"objects": [
|
||||
"Catalog.Номенклатура: @view",
|
||||
"Catalog.Контрагенты: @view",
|
||||
"DataProcessor.Загрузка: @view"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Роль для регламентного задания
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ОбновлениеЦен",
|
||||
"synonym": "Обновление цен номенклатуры",
|
||||
"objects": [
|
||||
"Catalog.Номенклатура: Read",
|
||||
"Catalog.Валюты: Read",
|
||||
"InformationRegister.ЦеныНоменклатуры: Read, Update",
|
||||
"Constant.ОсновнаяВалюта: Read"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Роль с RLS
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ЧтениеДокументовПоОрганизации",
|
||||
"synonym": "Чтение документов (ограничение по организации)",
|
||||
"objects": [
|
||||
"Catalog.Организации: @view",
|
||||
{
|
||||
"name": "Document.РеализацияТоваровУслуг",
|
||||
"preset": "view",
|
||||
"rls": {
|
||||
"Read": "#ДляОбъекта(\"\")"
|
||||
}
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"name": "ДляОбъекта(Модификатор)",
|
||||
"condition": "ГДЕ Организация = &ТекущаяОрганизация"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Роль с русскими синонимами
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ПросмотрДанных",
|
||||
"synonym": "Просмотр данных",
|
||||
"objects": [
|
||||
"Справочник.Контрагенты: @view",
|
||||
"Документ.Реализация: Чтение, Просмотр",
|
||||
"РегистрСведений.Цены: @edit",
|
||||
"Обработка.ЗагрузкаДанных: @view"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Роль с переопределением прав из пресета
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ОграниченноеРедактирование",
|
||||
"synonym": "Редактирование без удаления",
|
||||
"objects": [
|
||||
{
|
||||
"name": "Catalog.Контрагенты",
|
||||
"preset": "edit",
|
||||
"rights": { "Delete": false }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,713 @@
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$JsonPath,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]$OutputDir
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- 1. Load and validate JSON ---
|
||||
|
||||
if (-not (Test-Path $JsonPath)) {
|
||||
Write-Error "File not found: $JsonPath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
||||
$def = $json | ConvertFrom-Json
|
||||
|
||||
if (-not $def.name) {
|
||||
Write-Error "JSON must have 'name' field (role programmatic name)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$roleName = "$($def.name)"
|
||||
$synonym = if ($def.synonym) { "$($def.synonym)" } else { $roleName }
|
||||
$comment = if ($def.comment) { "$($def.comment)" } else { "" }
|
||||
|
||||
# --- 2. XML helpers ---
|
||||
|
||||
$script:xmlBuf = $null
|
||||
|
||||
function X {
|
||||
param([string]$text)
|
||||
$script:xmlBuf.AppendLine($text) | Out-Null
|
||||
}
|
||||
|
||||
function Esc-Xml {
|
||||
param([string]$s)
|
||||
return $s.Replace('&','&').Replace('<','<').Replace('>','>').Replace('"','"')
|
||||
}
|
||||
|
||||
# --- 3. Russian synonyms → canonical English names ---
|
||||
|
||||
$script:typeAliases = @{
|
||||
"Справочник" = "Catalog"
|
||||
"Документ" = "Document"
|
||||
"РегистрСведений" = "InformationRegister"
|
||||
"РегистрНакопления" = "AccumulationRegister"
|
||||
"РегистрБухгалтерии" = "AccountingRegister"
|
||||
"РегистрРасчета" = "CalculationRegister"
|
||||
"Константа" = "Constant"
|
||||
"ПланСчетов" = "ChartOfAccounts"
|
||||
"ПланВидовХарактеристик" = "ChartOfCharacteristicTypes"
|
||||
"ПланВидовРасчета" = "ChartOfCalculationTypes"
|
||||
"ПланОбмена" = "ExchangePlan"
|
||||
"БизнесПроцесс" = "BusinessProcess"
|
||||
"Задача" = "Task"
|
||||
"Обработка" = "DataProcessor"
|
||||
"Отчет" = "Report"
|
||||
"ОбщаяФорма" = "CommonForm"
|
||||
"ОбщаяКоманда" = "CommonCommand"
|
||||
"Подсистема" = "Subsystem"
|
||||
"КритерийОтбора" = "FilterCriterion"
|
||||
"ЖурналДокументов" = "DocumentJournal"
|
||||
"Последовательность" = "Sequence"
|
||||
"ВебСервис" = "WebService"
|
||||
"HTTPСервис" = "HTTPService"
|
||||
"СервисИнтеграции" = "IntegrationService"
|
||||
"ПараметрСеанса" = "SessionParameter"
|
||||
"ОбщийРеквизит" = "CommonAttribute"
|
||||
"Конфигурация" = "Configuration"
|
||||
"Перечисление" = "Enum"
|
||||
# Nested
|
||||
"Реквизит" = "Attribute"
|
||||
"СтандартныйРеквизит" = "StandardAttribute"
|
||||
"ТабличнаяЧасть" = "TabularSection"
|
||||
"Измерение" = "Dimension"
|
||||
"Ресурс" = "Resource"
|
||||
"Команда" = "Command"
|
||||
"РеквизитАдресации" = "AddressingAttribute"
|
||||
}
|
||||
|
||||
$script:rightAliases = @{
|
||||
"Чтение" = "Read"
|
||||
"Добавление" = "Insert"
|
||||
"Изменение" = "Update"
|
||||
"Удаление" = "Delete"
|
||||
"Просмотр" = "View"
|
||||
"Редактирование" = "Edit"
|
||||
"ВводПоСтроке" = "InputByString"
|
||||
"Проведение" = "Posting"
|
||||
"ОтменаПроведения" = "UndoPosting"
|
||||
"ИнтерактивноеДобавление" = "InteractiveInsert"
|
||||
"ИнтерактивнаяПометкаУдаления" = "InteractiveSetDeletionMark"
|
||||
"ИнтерактивноеСнятиеПометкиУдаления" = "InteractiveClearDeletionMark"
|
||||
"ИнтерактивноеУдаление" = "InteractiveDelete"
|
||||
"ИнтерактивноеУдалениеПомеченных" = "InteractiveDeleteMarked"
|
||||
"ИнтерактивноеПроведение" = "InteractivePosting"
|
||||
"ИнтерактивноеПроведениеНеоперативное" = "InteractivePostingRegular"
|
||||
"ИнтерактивнаяОтменаПроведения" = "InteractiveUndoPosting"
|
||||
"ИнтерактивноеИзменениеПроведенных" = "InteractiveChangeOfPosted"
|
||||
"Использование" = "Use"
|
||||
"Получение" = "Get"
|
||||
"Установка" = "Set"
|
||||
"Старт" = "Start"
|
||||
"ИнтерактивныйСтарт" = "InteractiveStart"
|
||||
"ИнтерактивнаяАктивация" = "InteractiveActivate"
|
||||
"Выполнение" = "Execute"
|
||||
"ИнтерактивноеВыполнение" = "InteractiveExecute"
|
||||
"УправлениеИтогами" = "TotalsControl"
|
||||
"Администрирование" = "Administration"
|
||||
"АдминистрированиеДанных" = "DataAdministration"
|
||||
"ТонкийКлиент" = "ThinClient"
|
||||
"ВебКлиент" = "WebClient"
|
||||
"ТолстыйКлиент" = "ThickClient"
|
||||
"ВнешнееСоединение" = "ExternalConnection"
|
||||
"Вывод" = "Output"
|
||||
"СохранениеДанныхПользователя" = "SaveUserData"
|
||||
"МобильныйКлиент" = "MobileClient"
|
||||
}
|
||||
|
||||
# Translate Russian object name to English (e.g. "Справочник.Контрагенты" → "Catalog.Контрагенты")
|
||||
function Translate-ObjectName {
|
||||
param([string]$name)
|
||||
$parts = $name.Split(".")
|
||||
$result = @()
|
||||
foreach ($p in $parts) {
|
||||
if ($script:typeAliases.ContainsKey($p)) {
|
||||
$result += $script:typeAliases[$p]
|
||||
} else {
|
||||
$result += $p
|
||||
}
|
||||
}
|
||||
return $result -join "."
|
||||
}
|
||||
|
||||
# Translate Russian right name to English (e.g. "Чтение" → "Read")
|
||||
function Translate-RightName {
|
||||
param([string]$name)
|
||||
if ($script:rightAliases.ContainsKey($name)) {
|
||||
return $script:rightAliases[$name]
|
||||
}
|
||||
return $name
|
||||
}
|
||||
|
||||
# --- 4. Known rights per object type (source: docs/1c-role-spec.md) ---
|
||||
|
||||
$script:knownRights = @{
|
||||
"Configuration" = @(
|
||||
"Administration","DataAdministration","UpdateDataBaseConfiguration",
|
||||
"ConfigurationExtensionsAdministration","ActiveUsers","EventLog","ExclusiveMode",
|
||||
"ThinClient","ThickClient","WebClient","MobileClient","ExternalConnection",
|
||||
"Automation","Output","SaveUserData","TechnicalSpecialistMode",
|
||||
"InteractiveOpenExtDataProcessors","InteractiveOpenExtReports",
|
||||
"AnalyticsSystemClient","CollaborationSystemInfoBaseRegistration",
|
||||
"MainWindowModeNormal","MainWindowModeWorkplace",
|
||||
"MainWindowModeEmbeddedWorkplace","MainWindowModeFullscreenWorkplace","MainWindowModeKiosk"
|
||||
)
|
||||
"Catalog" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"Document" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"Posting","UndoPosting",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"InteractivePosting","InteractivePostingRegular","InteractiveUndoPosting",
|
||||
"InteractiveChangeOfPosted",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"InformationRegister" = @(
|
||||
"Read","Update","View","Edit","TotalsControl",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"AccumulationRegister" = @("Read","Update","View","Edit","TotalsControl")
|
||||
"AccountingRegister" = @("Read","Update","View","Edit","TotalsControl")
|
||||
"CalculationRegister" = @("Read","View")
|
||||
"Constant" = @(
|
||||
"Read","Update","View","Edit",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"ChartOfAccounts" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
|
||||
"ReadDataHistory","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistory","UpdateDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment"
|
||||
)
|
||||
"ChartOfCharacteristicTypes" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"ChartOfCalculationTypes" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData"
|
||||
)
|
||||
"ExchangePlan" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"BusinessProcess" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"Start","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveActivate","InteractiveStart"
|
||||
)
|
||||
"Task" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"Execute","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveActivate","InteractiveExecute"
|
||||
)
|
||||
"DataProcessor" = @("Use","View")
|
||||
"Report" = @("Use","View")
|
||||
"CommonForm" = @("View")
|
||||
"CommonCommand" = @("View")
|
||||
"Subsystem" = @("View")
|
||||
"FilterCriterion" = @("View")
|
||||
"DocumentJournal" = @("Read","View")
|
||||
"Sequence" = @("Read","Update")
|
||||
"WebService" = @("Use")
|
||||
"HTTPService" = @("Use")
|
||||
"IntegrationService" = @("Use")
|
||||
"SessionParameter" = @("Get","Set")
|
||||
"CommonAttribute" = @("View","Edit")
|
||||
}
|
||||
|
||||
# Nested objects: Attribute, StandardAttribute, TabularSection, Dimension, Resource, AddressingAttribute
|
||||
$script:nestedRights = @("View","Edit")
|
||||
$script:commandRights = @("View")
|
||||
|
||||
# --- 4. Presets (@view, @edit) ---
|
||||
|
||||
$script:presets = @{
|
||||
"view" = @{
|
||||
"Catalog" = @("Read","View","InputByString")
|
||||
"ExchangePlan" = @("Read","View","InputByString")
|
||||
"Document" = @("Read","View","InputByString")
|
||||
"ChartOfAccounts" = @("Read","View","InputByString")
|
||||
"ChartOfCharacteristicTypes" = @("Read","View","InputByString")
|
||||
"ChartOfCalculationTypes" = @("Read","View","InputByString")
|
||||
"BusinessProcess" = @("Read","View","InputByString")
|
||||
"Task" = @("Read","View","InputByString")
|
||||
"InformationRegister" = @("Read","View")
|
||||
"AccumulationRegister" = @("Read","View")
|
||||
"AccountingRegister" = @("Read","View")
|
||||
"CalculationRegister" = @("Read","View")
|
||||
"Constant" = @("Read","View")
|
||||
"DocumentJournal" = @("Read","View")
|
||||
"Sequence" = @("Read")
|
||||
"CommonForm" = @("View")
|
||||
"CommonCommand" = @("View")
|
||||
"Subsystem" = @("View")
|
||||
"FilterCriterion" = @("View")
|
||||
"SessionParameter" = @("Get")
|
||||
"CommonAttribute" = @("View")
|
||||
"DataProcessor" = @("Use","View")
|
||||
"Report" = @("Use","View")
|
||||
"Configuration" = @("ThinClient","WebClient","Output","SaveUserData","MainWindowModeNormal")
|
||||
}
|
||||
"edit" = @{
|
||||
"Catalog" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
|
||||
"ExchangePlan" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
|
||||
"Document" = @("Read","Insert","Update","Delete","View","Edit","InputByString","Posting","UndoPosting","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark","InteractivePosting","InteractivePostingRegular","InteractiveUndoPosting","InteractiveChangeOfPosted")
|
||||
"ChartOfAccounts" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
|
||||
"ChartOfCharacteristicTypes" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
|
||||
"ChartOfCalculationTypes" = @("Read","Insert","Update","Delete","View","Edit","InputByString","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark")
|
||||
"BusinessProcess" = @("Read","Insert","Update","Delete","View","Edit","InputByString","Start","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark","InteractiveActivate","InteractiveStart")
|
||||
"Task" = @("Read","Insert","Update","Delete","View","Edit","InputByString","Execute","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark","InteractiveActivate","InteractiveExecute")
|
||||
"InformationRegister" = @("Read","Update","View","Edit")
|
||||
"AccumulationRegister" = @("Read","Update","View","Edit")
|
||||
"AccountingRegister" = @("Read","Update","View","Edit")
|
||||
"Constant" = @("Read","Update","View","Edit")
|
||||
"DocumentJournal" = @("Read","View")
|
||||
"Sequence" = @("Read","Update")
|
||||
"SessionParameter" = @("Get","Set")
|
||||
"CommonAttribute" = @("View","Edit")
|
||||
}
|
||||
}
|
||||
|
||||
# --- 5. Helpers ---
|
||||
|
||||
function Get-ObjectType {
|
||||
param([string]$objectName)
|
||||
$dotIdx = $objectName.IndexOf(".")
|
||||
if ($dotIdx -lt 0) { return $objectName }
|
||||
return $objectName.Substring(0, $dotIdx)
|
||||
}
|
||||
|
||||
function Is-NestedObject {
|
||||
param([string]$objectName)
|
||||
return ($objectName.Split(".").Count -ge 3)
|
||||
}
|
||||
|
||||
function Resolve-Preset {
|
||||
param([string]$objectType, [string]$presetName)
|
||||
|
||||
$preset = $presetName.TrimStart('@')
|
||||
|
||||
if (-not $script:presets.ContainsKey($preset)) {
|
||||
Write-Warning "Unknown preset '@$preset'. Known: @view, @edit"
|
||||
return @()
|
||||
}
|
||||
|
||||
$typeMap = $script:presets[$preset]
|
||||
if (-not $typeMap.ContainsKey($objectType)) {
|
||||
$available = @()
|
||||
foreach ($k in $script:presets.Keys) {
|
||||
if ($script:presets[$k].ContainsKey($objectType)) {
|
||||
$available += "@$k"
|
||||
}
|
||||
}
|
||||
$availStr = if ($available.Count -gt 0) { $available -join ", " } else { "none" }
|
||||
Write-Warning "Preset '@$preset' not defined for type '$objectType'. Available: $availStr"
|
||||
return @()
|
||||
}
|
||||
|
||||
return @($typeMap[$objectType])
|
||||
}
|
||||
|
||||
function Validate-RightName {
|
||||
param([string]$objectName, [string]$rightName)
|
||||
|
||||
$objectType = Get-ObjectType $objectName
|
||||
|
||||
if (Is-NestedObject $objectName) {
|
||||
if ($objectName -match '\.Command\.') {
|
||||
if ($rightName -notin $script:commandRights) {
|
||||
Write-Warning "${objectName}: '$rightName' not valid for commands (only: View)"
|
||||
return $false
|
||||
}
|
||||
} else {
|
||||
if ($rightName -notin $script:nestedRights) {
|
||||
Write-Warning "${objectName}: '$rightName' not valid for nested objects (only: View, Edit)"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
if (-not $script:knownRights.ContainsKey($objectType)) {
|
||||
Write-Warning "${objectName}: unknown object type '$objectType'"
|
||||
return $true
|
||||
}
|
||||
|
||||
$validRights = $script:knownRights[$objectType]
|
||||
if ($rightName -notin $validRights) {
|
||||
$suggestions = @($validRights | Where-Object {
|
||||
$_ -like "*$rightName*" -or $rightName -like "*$_*"
|
||||
})
|
||||
$sugStr = if ($suggestions.Count -gt 0) { " Did you mean: $($suggestions -join ', ')?" } else { "" }
|
||||
Write-Warning "${objectName}: unknown right '$rightName'.$sugStr"
|
||||
return $false
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
# --- 6. Parse object entries ---
|
||||
|
||||
function Parse-ObjectEntry {
|
||||
param($entry)
|
||||
|
||||
# --- String shorthand ---
|
||||
if ($entry -is [string]) {
|
||||
$colonIdx = $entry.IndexOf(':')
|
||||
if ($colonIdx -lt 0) {
|
||||
Write-Warning "Invalid string '$entry' -- expected 'Object.Name: @preset' or 'Object.Name: Right1, Right2'"
|
||||
return $null
|
||||
}
|
||||
$objName = Translate-ObjectName ($entry.Substring(0, $colonIdx).Trim())
|
||||
$rightsStr = $entry.Substring($colonIdx + 1).Trim()
|
||||
$objectType = Get-ObjectType $objName
|
||||
|
||||
if ($rightsStr.StartsWith('@')) {
|
||||
$rightNames = @(Resolve-Preset -objectType $objectType -presetName $rightsStr)
|
||||
} else {
|
||||
$rightNames = @($rightsStr -split ',\s*' | ForEach-Object { Translate-RightName $_.Trim() } | Where-Object { $_ })
|
||||
foreach ($r in $rightNames) {
|
||||
Validate-RightName -objectName $objName -rightName $r | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
$rights = @()
|
||||
foreach ($r in $rightNames) {
|
||||
$rights += ,@{Name=$r; Value="true"; Condition=$null}
|
||||
}
|
||||
return @{ Name = $objName; Rights = $rights }
|
||||
}
|
||||
|
||||
# --- Object form ---
|
||||
$objName = Translate-ObjectName "$($entry.name)"
|
||||
if (-not $objName) {
|
||||
Write-Warning "Object entry missing 'name' field"
|
||||
return $null
|
||||
}
|
||||
|
||||
$objectType = Get-ObjectType $objName
|
||||
$rightsMap = [ordered]@{}
|
||||
|
||||
# 1) Start with preset
|
||||
if ($entry.preset) {
|
||||
$presetRights = @(Resolve-Preset -objectType $objectType -presetName "$($entry.preset)")
|
||||
foreach ($r in $presetRights) {
|
||||
$rightsMap[$r] = @{Value="true"; Condition=$null}
|
||||
}
|
||||
}
|
||||
|
||||
# 2) Apply explicit rights
|
||||
if ($entry.rights) {
|
||||
if ($entry.rights -is [array]) {
|
||||
foreach ($r in $entry.rights) {
|
||||
$rName = Translate-RightName "$r"
|
||||
Validate-RightName -objectName $objName -rightName $rName | Out-Null
|
||||
$rightsMap[$rName] = @{Value="true"; Condition=$null}
|
||||
}
|
||||
} else {
|
||||
foreach ($p in $entry.rights.PSObject.Properties) {
|
||||
$rName = Translate-RightName $p.Name
|
||||
Validate-RightName -objectName $objName -rightName $rName | Out-Null
|
||||
$boolVal = $p.Value
|
||||
if ($boolVal -eq $true -or "$boolVal" -eq "True") {
|
||||
$rightsMap[$rName] = @{Value="true"; Condition=$null}
|
||||
} else {
|
||||
$rightsMap[$rName] = @{Value="false"; Condition=$null}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 3) Apply RLS conditions
|
||||
if ($entry.rls) {
|
||||
foreach ($p in $entry.rls.PSObject.Properties) {
|
||||
$rlsRight = Translate-RightName $p.Name
|
||||
if ($rightsMap.Contains($rlsRight)) {
|
||||
$rightsMap[$rlsRight].Condition = "$($p.Value)"
|
||||
} else {
|
||||
Write-Warning "${objName}: RLS for '$rlsRight' but this right is not in the rights list"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Convert to array
|
||||
$rights = @()
|
||||
foreach ($k in $rightsMap.Keys) {
|
||||
$rights += ,@{
|
||||
Name = $k
|
||||
Value = $rightsMap[$k].Value
|
||||
Condition = $rightsMap[$k].Condition
|
||||
}
|
||||
}
|
||||
|
||||
return @{ Name = $objName; Rights = $rights }
|
||||
}
|
||||
|
||||
# --- 7. Parse all object entries ---
|
||||
|
||||
$parsedObjects = @()
|
||||
if ($def.objects) {
|
||||
foreach ($entry in $def.objects) {
|
||||
$parsed = Parse-ObjectEntry -entry $entry
|
||||
if ($parsed) {
|
||||
$parsedObjects += ,$parsed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- 8. Generate UUID ---
|
||||
|
||||
$uuid = [guid]::NewGuid().ToString()
|
||||
|
||||
# --- 9. Emit metadata XML (Roles/Name.xml) ---
|
||||
|
||||
$script:xmlBuf = New-Object System.Text.StringBuilder 4096
|
||||
|
||||
X '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
X '<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses"'
|
||||
X ' xmlns:app="http://v8.1c.ru/8.2/managed-application/core"'
|
||||
X ' xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config"'
|
||||
X ' xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi"'
|
||||
X ' xmlns:ent="http://v8.1c.ru/8.1/data/enterprise"'
|
||||
X ' xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform"'
|
||||
X ' xmlns:style="http://v8.1c.ru/8.1/data/ui/style"'
|
||||
X ' xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system"'
|
||||
X ' xmlns:v8="http://v8.1c.ru/8.1/data/core"'
|
||||
X ' xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"'
|
||||
X ' xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web"'
|
||||
X ' xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows"'
|
||||
X ' xmlns:xen="http://v8.1c.ru/8.3/xcf/enums"'
|
||||
X ' xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef"'
|
||||
X ' xmlns:xr="http://v8.1c.ru/8.3/xcf/readable"'
|
||||
X ' xmlns:xs="http://www.w3.org/2001/XMLSchema"'
|
||||
X ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
|
||||
X ' version="2.17">'
|
||||
X " <Role uuid=`"$uuid`">"
|
||||
X ' <Properties>'
|
||||
X " <Name>$roleName</Name>"
|
||||
X ' <Synonym>'
|
||||
X ' <v8:item>'
|
||||
X ' <v8:lang>ru</v8:lang>'
|
||||
X " <v8:content>$(Esc-Xml $synonym)</v8:content>"
|
||||
X ' </v8:item>'
|
||||
X ' </Synonym>'
|
||||
if ($comment) {
|
||||
X " <Comment>$(Esc-Xml $comment)</Comment>"
|
||||
} else {
|
||||
X ' <Comment/>'
|
||||
}
|
||||
X ' </Properties>'
|
||||
X ' </Role>'
|
||||
X '</MetaDataObject>'
|
||||
|
||||
$metadataXml = $script:xmlBuf.ToString()
|
||||
|
||||
# --- 10. Emit Rights XML (Roles/Name/Ext/Rights.xml) ---
|
||||
|
||||
$script:xmlBuf = New-Object System.Text.StringBuilder 8192
|
||||
|
||||
X '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
X '<Rights xmlns="http://v8.1c.ru/8.2/roles"'
|
||||
X ' xmlns:xs="http://www.w3.org/2001/XMLSchema"'
|
||||
X ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
|
||||
X ' xsi:type="Rights" version="2.17">'
|
||||
|
||||
# Global flags (defaults match typical 1C roles)
|
||||
$sfno = if ($null -ne $def.setForNewObjects) { "$($def.setForNewObjects)".ToLower() } else { "false" }
|
||||
$sfab = if ($null -ne $def.setForAttributesByDefault) { "$($def.setForAttributesByDefault)".ToLower() } else { "true" }
|
||||
$irco = if ($null -ne $def.independentRightsOfChildObjects) { "$($def.independentRightsOfChildObjects)".ToLower() } else { "false" }
|
||||
|
||||
X " <setForNewObjects>$sfno</setForNewObjects>"
|
||||
X " <setForAttributesByDefault>$sfab</setForAttributesByDefault>"
|
||||
X " <independentRightsOfChildObjects>$irco</independentRightsOfChildObjects>"
|
||||
|
||||
# Object blocks
|
||||
$totalRights = 0
|
||||
foreach ($obj in $parsedObjects) {
|
||||
X ' <object>'
|
||||
X " <name>$($obj.Name)</name>"
|
||||
foreach ($right in $obj.Rights) {
|
||||
X ' <right>'
|
||||
X " <name>$($right.Name)</name>"
|
||||
X " <value>$($right.Value)</value>"
|
||||
if ($right.Condition) {
|
||||
X ' <restrictionByCondition>'
|
||||
X " <condition>$(Esc-Xml $right.Condition)</condition>"
|
||||
X ' </restrictionByCondition>'
|
||||
}
|
||||
X ' </right>'
|
||||
$totalRights++
|
||||
}
|
||||
X ' </object>'
|
||||
}
|
||||
|
||||
# RLS restriction templates
|
||||
$templateCount = 0
|
||||
if ($def.templates) {
|
||||
foreach ($tpl in $def.templates) {
|
||||
X ' <restrictionTemplate>'
|
||||
X " <name>$(Esc-Xml "$($tpl.name)")</name>"
|
||||
X " <condition>$(Esc-Xml "$($tpl.condition)")</condition>"
|
||||
X ' </restrictionTemplate>'
|
||||
$templateCount++
|
||||
}
|
||||
}
|
||||
|
||||
X '</Rights>'
|
||||
|
||||
$rightsXml = $script:xmlBuf.ToString()
|
||||
|
||||
# --- 11. Write output files ---
|
||||
|
||||
$outDir = if ([System.IO.Path]::IsPathRooted($OutputDir)) {
|
||||
$OutputDir
|
||||
} else {
|
||||
Join-Path (Get-Location) $OutputDir
|
||||
}
|
||||
|
||||
# Metadata: OutputDir/RoleName.xml
|
||||
$metadataPath = Join-Path $outDir "$roleName.xml"
|
||||
if (-not (Test-Path $outDir)) {
|
||||
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# Rights: OutputDir/RoleName/Ext/Rights.xml
|
||||
$roleSubDir = Join-Path $outDir $roleName
|
||||
$extDir = Join-Path $roleSubDir "Ext"
|
||||
$rightsPath = Join-Path $extDir "Rights.xml"
|
||||
if (-not (Test-Path $extDir)) {
|
||||
New-Item -ItemType Directory -Path $extDir -Force | Out-Null
|
||||
}
|
||||
|
||||
$enc = New-Object System.Text.UTF8Encoding($true)
|
||||
[System.IO.File]::WriteAllText($metadataPath, $metadataXml, $enc)
|
||||
[System.IO.File]::WriteAllText($rightsPath, $rightsXml, $enc)
|
||||
|
||||
# --- 12. Register in Configuration.xml ---
|
||||
|
||||
$configDir = Split-Path $outDir -Parent
|
||||
$configXmlPath = Join-Path $configDir "Configuration.xml"
|
||||
$regResult = $null
|
||||
|
||||
if (Test-Path $configXmlPath) {
|
||||
$configDoc = New-Object System.Xml.XmlDocument
|
||||
$configDoc.PreserveWhitespace = $true
|
||||
$configDoc.Load($configXmlPath)
|
||||
|
||||
$nsMgr = New-Object System.Xml.XmlNamespaceManager($configDoc.NameTable)
|
||||
$nsMgr.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
|
||||
|
||||
$childObjects = $configDoc.SelectSingleNode("//md:Configuration/md:ChildObjects", $nsMgr)
|
||||
if ($childObjects) {
|
||||
$existing = $childObjects.SelectNodes("md:Role", $nsMgr)
|
||||
$alreadyExists = $false
|
||||
foreach ($r in $existing) {
|
||||
if ($r.InnerText -eq $roleName) {
|
||||
$alreadyExists = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ($alreadyExists) {
|
||||
$regResult = "already"
|
||||
} else {
|
||||
$roleElem = $configDoc.CreateElement("Role", "http://v8.1c.ru/8.3/MDClasses")
|
||||
$roleElem.InnerText = $roleName
|
||||
|
||||
if ($existing.Count -gt 0) {
|
||||
# Insert after last existing <Role>
|
||||
$lastRole = $existing[$existing.Count - 1]
|
||||
$newWs = $configDoc.CreateWhitespace("`n`t`t`t")
|
||||
$childObjects.InsertAfter($newWs, $lastRole) | Out-Null
|
||||
$childObjects.InsertAfter($roleElem, $newWs) | Out-Null
|
||||
} else {
|
||||
# No existing roles — insert before closing whitespace
|
||||
$lastChild = $childObjects.LastChild
|
||||
if ($lastChild.NodeType -eq [System.Xml.XmlNodeType]::Whitespace) {
|
||||
$newWs = $configDoc.CreateWhitespace("`n`t`t`t")
|
||||
$childObjects.InsertBefore($newWs, $lastChild) | Out-Null
|
||||
$childObjects.InsertBefore($roleElem, $lastChild) | Out-Null
|
||||
} else {
|
||||
$childObjects.AppendChild($configDoc.CreateWhitespace("`n`t`t`t")) | Out-Null
|
||||
$childObjects.AppendChild($roleElem) | Out-Null
|
||||
$childObjects.AppendChild($configDoc.CreateWhitespace("`n`t`t")) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Save
|
||||
$cfgSettings = New-Object System.Xml.XmlWriterSettings
|
||||
$cfgSettings.Encoding = New-Object System.Text.UTF8Encoding($true)
|
||||
$cfgSettings.Indent = $false
|
||||
$stream = New-Object System.IO.FileStream($configXmlPath, [System.IO.FileMode]::Create)
|
||||
$writer = [System.Xml.XmlWriter]::Create($stream, $cfgSettings)
|
||||
$configDoc.Save($writer)
|
||||
$writer.Close()
|
||||
$stream.Close()
|
||||
|
||||
$regResult = "added"
|
||||
}
|
||||
} else {
|
||||
$regResult = "no-childobj"
|
||||
}
|
||||
} else {
|
||||
$regResult = "no-config"
|
||||
}
|
||||
|
||||
# --- 13. Summary ---
|
||||
|
||||
Write-Host "[OK] Role '$roleName' compiled"
|
||||
Write-Host " UUID: $uuid"
|
||||
Write-Host " Metadata: $metadataPath"
|
||||
Write-Host " Rights: $rightsPath"
|
||||
Write-Host " Objects: $($parsedObjects.Count), Rights: $totalRights, Templates: $templateCount"
|
||||
switch ($regResult) {
|
||||
"added" { Write-Host " Configuration.xml: <Role>$roleName</Role> added to ChildObjects" }
|
||||
"already" { Write-Host " Configuration.xml: <Role>$roleName</Role> already registered" }
|
||||
"no-childobj" { Write-Warning "Configuration.xml found but <ChildObjects> not found" }
|
||||
"no-config" { Write-Warning "Configuration.xml not found at $configXmlPath — register manually" }
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- Output helper (always collect, paginate at the end) ---
|
||||
$script:lines = @()
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
name: role-validate
|
||||
description: Валидация структурной корректности роли 1С (Rights.xml) — формат, права, RLS, шаблоны
|
||||
argument-hint: <RightsPath>
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
---
|
||||
|
||||
# /role-validate — валидация роли 1С
|
||||
|
||||
Проверяет корректность `Rights.xml` роли: формат XML, namespace, глобальные флаги, типы объектов, имена прав, RLS-ограничения, шаблоны. Опционально проверяет метаданные роли (UUID, имя, синоним).
|
||||
|
||||
## Использование
|
||||
|
||||
```
|
||||
/role-validate <RightsPath> [MetadataPath]
|
||||
```
|
||||
|
||||
## Запуск скрипта
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -File .claude\skills\role-validate\scripts\role-validate.ps1 -RightsPath <path> [-MetadataPath <path>] [-OutFile <output.txt>]
|
||||
```
|
||||
|
||||
### Параметры
|
||||
|
||||
| Параметр | Обязательный | Описание |
|
||||
|----------|:------------:|----------|
|
||||
| `-RightsPath` | да | Путь к `Rights.xml` роли |
|
||||
| `-MetadataPath` | нет | Путь к метаданным роли (`Roles/ИмяРоли.xml`) |
|
||||
| `-OutFile` | нет | Записать результат в файл (UTF-8 BOM). Без этого — вывод в консоль |
|
||||
|
||||
**Важно:** Для кириллических путей используй `-OutFile` и читай результат через Read tool.
|
||||
|
||||
## Проверки
|
||||
|
||||
### Rights.xml
|
||||
1. XML well-formed — парсинг без ошибок
|
||||
2. Корневой элемент `<Rights>` с namespace `http://v8.1c.ru/8.2/roles`
|
||||
3. Три глобальных флага: `setForNewObjects`, `setForAttributesByDefault`, `independentRightsOfChildObjects`
|
||||
4. Для каждого `<object>`:
|
||||
- `<name>` не пуст
|
||||
- Тип объекта распознан (Catalog, Document, InformationRegister и т.д.)
|
||||
- Каждое `<right>` имеет `<name>` и `<value>` (`true`/`false`)
|
||||
- Имя права валидно для данного типа объекта (с подсказкой при опечатке)
|
||||
5. Вложенные объекты (3+ сегмента через `.`): допустимы только View, Edit (или Use для IntegrationServiceChannel)
|
||||
6. RLS `<restrictionByCondition>`: `<condition>` не пуст
|
||||
7. Шаблоны `<restrictionTemplate>`: `<name>` и `<condition>` не пусты
|
||||
|
||||
### Метаданные (опционально)
|
||||
- Элемент `<Role>` найден
|
||||
- UUID в корректном формате
|
||||
- `<Name>` не пуст
|
||||
- `<Synonym>` присутствует
|
||||
|
||||
## Формат вывода
|
||||
|
||||
```
|
||||
Validating: Roles/МояРоль/Ext/Rights.xml
|
||||
OK XML well-formed
|
||||
OK Root element: <Rights> with correct namespace
|
||||
OK 3 global flags present
|
||||
WARN Document.Реализация: unknown right 'Rea'. Did you mean: Read?
|
||||
OK 12 objects, 45 rights
|
||||
OK 2 RLS restrictions
|
||||
OK 1 templates: ДляОбъекта
|
||||
|
||||
OK Metadata: UUID valid (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
|
||||
OK Metadata: Name = МояРоль
|
||||
OK Metadata: Synonym present
|
||||
---
|
||||
Result: 0 error(s), 1 warning(s)
|
||||
```
|
||||
|
||||
### Уровни сообщений
|
||||
|
||||
| Маркер | Значение |
|
||||
|--------|----------|
|
||||
| `OK` | Проверка пройдена |
|
||||
| `WARN` | Предупреждение (неизвестный тип объекта, подозрительное имя права) |
|
||||
| `ERR` | Ошибка (невалидный XML, отсутствие обязательных элементов) |
|
||||
|
||||
Код возврата: `0` — без ошибок, `1` — есть ошибки.
|
||||
|
||||
## Примеры
|
||||
|
||||
### Только Rights.xml
|
||||
|
||||
```
|
||||
/role-validate upload/acc_8.3.20/Roles/БазовыеПраваБП/Ext/Rights.xml
|
||||
```
|
||||
|
||||
### С проверкой метаданных
|
||||
|
||||
```
|
||||
/role-validate Roles/МояРоль/Ext/Rights.xml Roles/МояРоль.xml
|
||||
```
|
||||
|
||||
### Верификация после /role-compile
|
||||
|
||||
```
|
||||
/role-compile role.json Roles/
|
||||
/role-validate Roles/МояРоль/Ext/Rights.xml Roles/МояРоль.xml
|
||||
```
|
||||
@@ -0,0 +1,472 @@
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$RightsPath,
|
||||
|
||||
[string]$MetadataPath,
|
||||
|
||||
[string]$OutFile
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- 1. Known rights per object type ---
|
||||
|
||||
$script:knownRights = @{
|
||||
"Configuration" = @(
|
||||
"Administration","DataAdministration","UpdateDataBaseConfiguration",
|
||||
"ConfigurationExtensionsAdministration","ActiveUsers","EventLog","ExclusiveMode",
|
||||
"ThinClient","ThickClient","WebClient","MobileClient","ExternalConnection",
|
||||
"Automation","Output","SaveUserData","TechnicalSpecialistMode",
|
||||
"InteractiveOpenExtDataProcessors","InteractiveOpenExtReports",
|
||||
"AnalyticsSystemClient","CollaborationSystemInfoBaseRegistration",
|
||||
"MainWindowModeNormal","MainWindowModeWorkplace",
|
||||
"MainWindowModeEmbeddedWorkplace","MainWindowModeFullscreenWorkplace","MainWindowModeKiosk"
|
||||
)
|
||||
"Catalog" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"Document" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"Posting","UndoPosting",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"InteractivePosting","InteractivePostingRegular","InteractiveUndoPosting",
|
||||
"InteractiveChangeOfPosted",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"InformationRegister" = @(
|
||||
"Read","Update","View","Edit","TotalsControl",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistoryOfMissingData","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"AccumulationRegister" = @("Read","Update","View","Edit","TotalsControl")
|
||||
"AccountingRegister" = @("Read","Update","View","Edit","TotalsControl")
|
||||
"CalculationRegister" = @("Read","View")
|
||||
"Constant" = @(
|
||||
"Read","Update","View","Edit",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"ChartOfAccounts" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
|
||||
"ReadDataHistory","ReadDataHistoryOfMissingData",
|
||||
"UpdateDataHistory","UpdateDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment"
|
||||
)
|
||||
"ChartOfCharacteristicTypes" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"ChartOfCalculationTypes" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete",
|
||||
"InteractiveDeletePredefinedData","InteractiveSetDeletionMarkPredefinedData",
|
||||
"InteractiveClearDeletionMarkPredefinedData","InteractiveDeleteMarkedPredefinedData"
|
||||
)
|
||||
"ExchangePlan" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveDeleteMarked",
|
||||
"ReadDataHistory","ViewDataHistory","UpdateDataHistory",
|
||||
"ReadDataHistoryOfMissingData","UpdateDataHistoryOfMissingData",
|
||||
"UpdateDataHistorySettings","UpdateDataHistoryVersionComment",
|
||||
"EditDataHistoryVersionComment","SwitchToDataHistoryVersion"
|
||||
)
|
||||
"BusinessProcess" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"Start","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveActivate","InteractiveStart"
|
||||
)
|
||||
"Task" = @(
|
||||
"Read","Insert","Update","Delete","View","Edit","InputByString",
|
||||
"Execute","InteractiveInsert","InteractiveSetDeletionMark","InteractiveClearDeletionMark",
|
||||
"InteractiveDelete","InteractiveActivate","InteractiveExecute"
|
||||
)
|
||||
"DataProcessor" = @("Use","View")
|
||||
"Report" = @("Use","View")
|
||||
"CommonForm" = @("View")
|
||||
"CommonCommand" = @("View")
|
||||
"Subsystem" = @("View")
|
||||
"FilterCriterion" = @("View")
|
||||
"DocumentJournal" = @("Read","View")
|
||||
"Sequence" = @("Read","Update")
|
||||
"WebService" = @("Use")
|
||||
"HTTPService" = @("Use")
|
||||
"IntegrationService" = @("Use")
|
||||
"SessionParameter" = @("Get","Set")
|
||||
"CommonAttribute" = @("View","Edit")
|
||||
}
|
||||
|
||||
$script:nestedRights = @("View","Edit")
|
||||
$script:channelRights = @("Use")
|
||||
$script:commandRights = @("View")
|
||||
|
||||
# --- 2. Output helpers ---
|
||||
|
||||
$script:lines = @()
|
||||
$script:errors = 0
|
||||
$script:warnings = 0
|
||||
|
||||
function Out-OK {
|
||||
param([string]$msg)
|
||||
$script:lines += " OK $msg"
|
||||
}
|
||||
|
||||
function Out-WARN {
|
||||
param([string]$msg)
|
||||
$script:warnings++
|
||||
$script:lines += " WARN $msg"
|
||||
}
|
||||
|
||||
function Out-ERR {
|
||||
param([string]$msg)
|
||||
$script:errors++
|
||||
$script:lines += " ERR $msg"
|
||||
}
|
||||
|
||||
function Get-ObjectType {
|
||||
param([string]$name)
|
||||
$dotIdx = $name.IndexOf(".")
|
||||
if ($dotIdx -lt 0) { return $name }
|
||||
return $name.Substring(0, $dotIdx)
|
||||
}
|
||||
|
||||
function Is-NestedObject {
|
||||
param([string]$name)
|
||||
return ($name.Split(".").Count -ge 3)
|
||||
}
|
||||
|
||||
function Find-Similar {
|
||||
param([string]$needle, [string[]]$haystack)
|
||||
$result = @($haystack | Where-Object {
|
||||
$_ -like "*$needle*" -or $needle -like "*$_*"
|
||||
})
|
||||
if ($result.Count -gt 3) { $result = $result[0..2] }
|
||||
return $result
|
||||
}
|
||||
|
||||
# --- 3. Validate Rights.xml ---
|
||||
|
||||
$script:lines += "Validating: $RightsPath"
|
||||
|
||||
if (-not (Test-Path $RightsPath)) {
|
||||
Out-ERR "File not found: $RightsPath"
|
||||
$script:lines += "---"
|
||||
$script:lines += "Result: $($script:errors) error(s), $($script:warnings) warning(s)"
|
||||
$output = $script:lines -join "`n"
|
||||
if ($OutFile) {
|
||||
$enc = New-Object System.Text.UTF8Encoding($true)
|
||||
[System.IO.File]::WriteAllText($OutFile, $output, $enc)
|
||||
} else {
|
||||
Write-Host $output
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 3a. Parse XML
|
||||
try {
|
||||
[xml]$xml = Get-Content -Path $RightsPath -Encoding UTF8
|
||||
Out-OK "XML well-formed"
|
||||
} catch {
|
||||
Out-ERR "XML parse error: $($_.Exception.Message)"
|
||||
$script:lines += "---"
|
||||
$script:lines += "Result: $($script:errors) error(s), $($script:warnings) warning(s)"
|
||||
$output = $script:lines -join "`n"
|
||||
if ($OutFile) {
|
||||
$enc = New-Object System.Text.UTF8Encoding($true)
|
||||
[System.IO.File]::WriteAllText($OutFile, $output, $enc)
|
||||
} else {
|
||||
Write-Host $output
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
|
||||
$root = $xml.DocumentElement
|
||||
$rightsNs = "http://v8.1c.ru/8.2/roles"
|
||||
|
||||
# 3b. Check root element
|
||||
if ($root.LocalName -ne "Rights") {
|
||||
Out-ERR "Root element is '$($root.LocalName)', expected 'Rights'"
|
||||
} elseif ($root.NamespaceURI -ne $rightsNs) {
|
||||
Out-WARN "Namespace is '$($root.NamespaceURI)', expected '$rightsNs'"
|
||||
} else {
|
||||
Out-OK "Root element: <Rights> with correct namespace"
|
||||
}
|
||||
|
||||
# 3c. Global flags
|
||||
$flagNames = @("setForNewObjects","setForAttributesByDefault","independentRightsOfChildObjects")
|
||||
$flagsFound = 0
|
||||
foreach ($fn in $flagNames) {
|
||||
$node = $root.GetElementsByTagName($fn, $rightsNs)
|
||||
if ($node.Count -gt 0) {
|
||||
$val = $node[0].InnerText
|
||||
if ($val -ne "true" -and $val -ne "false") {
|
||||
Out-WARN "$fn = '$val' (expected 'true' or 'false')"
|
||||
}
|
||||
$flagsFound++
|
||||
} else {
|
||||
Out-WARN "Missing global flag: $fn"
|
||||
}
|
||||
}
|
||||
if ($flagsFound -eq 3) {
|
||||
Out-OK "3 global flags present"
|
||||
}
|
||||
|
||||
# 3d. Objects
|
||||
$objects = $root.GetElementsByTagName("object", $rightsNs)
|
||||
$objCount = $objects.Count
|
||||
$rightCount = 0
|
||||
$rlsCount = 0
|
||||
|
||||
foreach ($obj in $objects) {
|
||||
$objName = ""
|
||||
foreach ($child in $obj.ChildNodes) {
|
||||
if ($child.LocalName -eq "name") {
|
||||
$objName = $child.InnerText
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $objName) {
|
||||
Out-ERR "Object without <name>"
|
||||
continue
|
||||
}
|
||||
|
||||
$objectType = Get-ObjectType $objName
|
||||
$isNested = Is-NestedObject $objName
|
||||
|
||||
# Check object type is known
|
||||
if (-not $isNested -and -not $script:knownRights.ContainsKey($objectType)) {
|
||||
Out-WARN "${objName}: unknown object type '$objectType'"
|
||||
}
|
||||
|
||||
# Check rights
|
||||
foreach ($child in $obj.ChildNodes) {
|
||||
if ($child.LocalName -ne "right") { continue }
|
||||
|
||||
$rName = ""
|
||||
$rValue = ""
|
||||
$hasRLS = $false
|
||||
|
||||
foreach ($rc in $child.ChildNodes) {
|
||||
if ($rc.LocalName -eq "name") { $rName = $rc.InnerText }
|
||||
if ($rc.LocalName -eq "value") { $rValue = $rc.InnerText }
|
||||
if ($rc.LocalName -eq "restrictionByCondition") {
|
||||
$hasRLS = $true
|
||||
$rlsCount++
|
||||
# Check condition not empty
|
||||
$condNode = $null
|
||||
foreach ($rcc in $rc.ChildNodes) {
|
||||
if ($rcc.LocalName -eq "condition") { $condNode = $rcc }
|
||||
}
|
||||
if (-not $condNode -or -not $condNode.InnerText) {
|
||||
Out-WARN "${objName}: RLS condition for '$rName' is empty"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $rName) {
|
||||
Out-ERR "${objName}: <right> without <name>"
|
||||
continue
|
||||
}
|
||||
|
||||
if ($rValue -ne "true" -and $rValue -ne "false") {
|
||||
Out-ERR "${objName}: right '$rName' has invalid value '$rValue'"
|
||||
continue
|
||||
}
|
||||
|
||||
$rightCount++
|
||||
|
||||
# Validate right name
|
||||
if ($isNested) {
|
||||
if ($objName -match '\.Command\.') {
|
||||
if ($rName -notin $script:commandRights) {
|
||||
Out-WARN "${objName}: '$rName' not valid for commands (only: View)"
|
||||
}
|
||||
} elseif ($objName -match '\.IntegrationServiceChannel\.') {
|
||||
if ($rName -notin $script:channelRights) {
|
||||
Out-WARN "${objName}: '$rName' not valid for channels (only: Use)"
|
||||
}
|
||||
} else {
|
||||
if ($rName -notin $script:nestedRights) {
|
||||
Out-WARN "${objName}: '$rName' not valid for nested objects (only: View, Edit)"
|
||||
}
|
||||
}
|
||||
} elseif ($script:knownRights.ContainsKey($objectType)) {
|
||||
$validRights = $script:knownRights[$objectType]
|
||||
if ($rName -notin $validRights) {
|
||||
$similar = Find-Similar -needle $rName -haystack $validRights
|
||||
$sugStr = if ($similar.Count -gt 0) { " Did you mean: $($similar -join ', ')?" } else { "" }
|
||||
Out-WARN "${objName}: unknown right '$rName'.$sugStr"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Out-OK "$objCount objects, $rightCount rights"
|
||||
if ($rlsCount -gt 0) {
|
||||
Out-OK "$rlsCount RLS restrictions"
|
||||
}
|
||||
|
||||
# 3e. Templates
|
||||
$templates = $root.GetElementsByTagName("restrictionTemplate", $rightsNs)
|
||||
if ($templates.Count -gt 0) {
|
||||
$tplNames = @()
|
||||
foreach ($tpl in $templates) {
|
||||
$tName = ""
|
||||
$tCond = ""
|
||||
foreach ($child in $tpl.ChildNodes) {
|
||||
if ($child.LocalName -eq "name") { $tName = $child.InnerText }
|
||||
if ($child.LocalName -eq "condition") { $tCond = $child.InnerText }
|
||||
}
|
||||
if (-not $tName) {
|
||||
Out-WARN "Restriction template without <name>"
|
||||
} else {
|
||||
$parenIdx = $tName.IndexOf("(")
|
||||
$shortName = if ($parenIdx -gt 0) { $tName.Substring(0, $parenIdx) } else { $tName }
|
||||
$tplNames += $shortName
|
||||
}
|
||||
if (-not $tCond) {
|
||||
Out-WARN "Template '$tName': empty <condition>"
|
||||
}
|
||||
}
|
||||
Out-OK "$($templates.Count) templates: $($tplNames -join ', ')"
|
||||
}
|
||||
|
||||
# --- 4. Validate metadata (optional) ---
|
||||
|
||||
if ($MetadataPath) {
|
||||
$script:lines += ""
|
||||
|
||||
if (-not (Test-Path $MetadataPath)) {
|
||||
Out-ERR "Metadata file not found: $MetadataPath"
|
||||
} else {
|
||||
try {
|
||||
[xml]$metaXml = Get-Content -Path $MetadataPath -Encoding UTF8
|
||||
$roleNode = $metaXml.DocumentElement.SelectSingleNode("//*[local-name()='Role']")
|
||||
if (-not $roleNode) {
|
||||
Out-ERR "Metadata: <Role> element not found"
|
||||
} else {
|
||||
$uuid = $roleNode.GetAttribute("uuid")
|
||||
if ($uuid -match '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') {
|
||||
Out-OK "Metadata: UUID valid ($uuid)"
|
||||
} else {
|
||||
Out-ERR "Metadata: invalid UUID format '$uuid'"
|
||||
}
|
||||
|
||||
$nameNode = $roleNode.SelectSingleNode(".//*[local-name()='Name']")
|
||||
if ($nameNode -and $nameNode.InnerText) {
|
||||
Out-OK "Metadata: Name = $($nameNode.InnerText)"
|
||||
} else {
|
||||
Out-ERR "Metadata: <Name> is empty or missing"
|
||||
}
|
||||
|
||||
$synNode = $roleNode.SelectSingleNode(".//*[local-name()='Synonym']")
|
||||
if ($synNode -and $synNode.InnerXml) {
|
||||
Out-OK "Metadata: Synonym present"
|
||||
} else {
|
||||
Out-WARN "Metadata: <Synonym> is empty"
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Out-ERR "Metadata XML parse error: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- 5. Check registration in Configuration.xml ---
|
||||
|
||||
# Infer paths: RightsPath = .../Roles/Name/Ext/Rights.xml
|
||||
$extDir2 = Split-Path (Resolve-Path $RightsPath).Path -Parent
|
||||
$roleDir2 = Split-Path $extDir2 -Parent
|
||||
$rolesDir2 = Split-Path $roleDir2 -Parent
|
||||
$configDir2 = Split-Path $rolesDir2 -Parent
|
||||
$configXmlPath2 = Join-Path $configDir2 "Configuration.xml"
|
||||
$inferredRoleName = Split-Path $roleDir2 -Leaf
|
||||
|
||||
# Use metadata name if available
|
||||
if ($MetadataPath -and (Test-Path $MetadataPath)) {
|
||||
try {
|
||||
[xml]$metaXml2 = Get-Content -Path $MetadataPath -Encoding UTF8
|
||||
$nameNode2 = $metaXml2.DocumentElement.SelectSingleNode("//*[local-name()='Role']//*[local-name()='Name']")
|
||||
if ($nameNode2 -and $nameNode2.InnerText) {
|
||||
$inferredRoleName = $nameNode2.InnerText
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
if (Test-Path $configXmlPath2) {
|
||||
$script:lines += ""
|
||||
try {
|
||||
[xml]$cfgXml = Get-Content -Path $configXmlPath2 -Encoding UTF8
|
||||
$cfgNs = New-Object System.Xml.XmlNamespaceManager($cfgXml.NameTable)
|
||||
$cfgNs.AddNamespace("md", "http://v8.1c.ru/8.3/MDClasses")
|
||||
$childObj = $cfgXml.SelectSingleNode("//md:Configuration/md:ChildObjects", $cfgNs)
|
||||
if ($childObj) {
|
||||
$roleNodes = $childObj.SelectNodes("md:Role", $cfgNs)
|
||||
$found = $false
|
||||
foreach ($rn in $roleNodes) {
|
||||
if ($rn.InnerText -eq $inferredRoleName) {
|
||||
$found = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($found) {
|
||||
Out-OK "Configuration.xml: <Role>$inferredRoleName</Role> registered"
|
||||
} else {
|
||||
Out-WARN "Configuration.xml: <Role>$inferredRoleName</Role> NOT found in ChildObjects"
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Out-WARN "Configuration.xml: parse error — $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# --- 6. Summary ---
|
||||
|
||||
$script:lines += "---"
|
||||
$script:lines += "Result: $($script:errors) error(s), $($script:warnings) warning(s)"
|
||||
|
||||
$output = $script:lines -join "`n"
|
||||
|
||||
if ($OutFile) {
|
||||
$outPath = if ([System.IO.Path]::IsPathRooted($OutFile)) { $OutFile } else { Join-Path (Get-Location) $OutFile }
|
||||
$outDir = [System.IO.Path]::GetDirectoryName($outPath)
|
||||
if (-not (Test-Path $outDir)) {
|
||||
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
|
||||
}
|
||||
$enc = New-Object System.Text.UTF8Encoding($true)
|
||||
[System.IO.File]::WriteAllText($outPath, $output, $enc)
|
||||
Write-Host "[OK] Validation result written to: $outPath"
|
||||
} else {
|
||||
Write-Host $output
|
||||
}
|
||||
|
||||
if ($script:errors -gt 0) { exit 1 } else { exit 0 }
|
||||
@@ -22,7 +22,7 @@
|
||||
| Внешние обработки (EPF) | 10 навыков `/epf-*` | Создание, модификация, сборка обработок из XML-исходников | [Подробнее](docs/epf-guide.md) |
|
||||
| Табличный документ (MXL) | 4 навыка `/mxl-*` | Анализ, создание, компиляция макетов печатных форм | [Подробнее](docs/mxl-guide.md) |
|
||||
| Управляемые формы (Form) | 6 навыков `/form-*` | Создание, анализ, генерация, модификация, валидация управляемых форм | [Подробнее](docs/form-guide.md) |
|
||||
| Роли (Role) | 2 навыка `/role-*` | Анализ прав роли, создание роли из описания | [Подробнее](docs/role-guide.md) |
|
||||
| Роли (Role) | 3 навыка `/role-*` | Анализ прав роли, создание из JSON DSL, валидация | [Подробнее](docs/role-guide.md) |
|
||||
| Утилиты | `/img-grid` | Наложение сетки на изображение для определения пропорций колонок | — |
|
||||
|
||||
## Требования
|
||||
@@ -40,6 +40,7 @@
|
||||
- [MXL DSL](docs/mxl-dsl-spec.md) — JSON-формат описания макета для `/mxl-compile` и `/mxl-decompile`
|
||||
- [Form DSL](docs/form-dsl-spec.md) — JSON-формат описания формы для `/form-compile`
|
||||
- [Роли (Rights.xml)](docs/1c-role-spec.md) — XML-формат прав роли, типы объектов, RLS
|
||||
- [Role DSL](docs/role-dsl-spec.md) — JSON-формат описания ролей для `/role-compile`
|
||||
|
||||
## Структура репозитория
|
||||
|
||||
@@ -66,7 +67,8 @@
|
||||
├── form-edit/ # Добавление элементов в форму
|
||||
├── form-patterns/ # Справочник паттернов компоновки форм
|
||||
├── role-info/ # Анализ прав роли
|
||||
├── role-compile/ # Создание роли из описания
|
||||
├── role-compile/ # Создание роли из JSON DSL
|
||||
├── role-validate/ # Валидация роли
|
||||
└── img-grid/ # Сетка для анализа изображений
|
||||
docs/
|
||||
├── epf-guide.md # Гайд: внешние обработки
|
||||
|
||||
@@ -0,0 +1,957 @@
|
||||
# Спецификация XML-формата схемы компоновки данных 1С (DCS)
|
||||
|
||||
Спецификация формата `DataCompositionSchema` — макетов типа «Схема компоновки данных» в конфигурации 1С:Предприятие 8.3.
|
||||
Составлена на основе анализа 930 схем конфигурации «Бухгалтерия предприятия 3.0.180» (платформа 8.3.24).
|
||||
|
||||
---
|
||||
|
||||
## 0. Файловая структура
|
||||
|
||||
### Два файла на каждую схему
|
||||
|
||||
```
|
||||
<Объект>/Templates/
|
||||
ИмяМакета.xml ← метаданные (UUID, имя, TemplateType)
|
||||
ИмяМакета/
|
||||
Ext/
|
||||
Template.xml ← тело схемы (DataCompositionSchema)
|
||||
```
|
||||
|
||||
Типичные имена макетов: `ОсновнаяСхемаКомпоновкиДанных`, `СхемаКомпоновкиДанных`, произвольные.
|
||||
|
||||
### Метаданные макета — шаблон
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses"
|
||||
xmlns:v8="http://v8.1c.ru/8.1/data/core"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
version="2.17">
|
||||
<Template uuid="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX">
|
||||
<Properties>
|
||||
<Name>ОсновнаяСхемаКомпоновкиДанных</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Основная схема компоновки данных</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
<TemplateType>DataCompositionSchema</TemplateType>
|
||||
</Properties>
|
||||
</Template>
|
||||
</MetaDataObject>
|
||||
```
|
||||
|
||||
Значение `TemplateType` для DCS всегда: **`DataCompositionSchema`**.
|
||||
|
||||
### Где встречаются DCS-макеты
|
||||
|
||||
| Тип объекта метаданных | Частота | Примечание |
|
||||
|---|---|---|
|
||||
| Reports (Отчёты) | ~420 | Основное место — каждый отчёт СКД |
|
||||
| DataProcessors (Обработки) | ~11 | Обработки с отчётными функциями |
|
||||
| Enums (Перечисления) | ~20 | Дополнительные ссылки |
|
||||
| Catalogs (Справочники) | ~5 | Запросы к справочным данным |
|
||||
| DocumentJournals | ~4 | Журналы документов |
|
||||
| CommonTemplates | ~3 | Общие макеты |
|
||||
| InformationRegisters | ~2 | Регистры сведений |
|
||||
| Documents (Документы) | ~1 | Редко |
|
||||
|
||||
---
|
||||
|
||||
## 1. Пространства имён
|
||||
|
||||
Корневой элемент — `<DataCompositionSchema>`.
|
||||
|
||||
```xml
|
||||
<DataCompositionSchema
|
||||
xmlns="http://v8.1c.ru/8.1/data-composition-system/schema"
|
||||
xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common"
|
||||
xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core"
|
||||
xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings"
|
||||
xmlns:v8="http://v8.1c.ru/8.1/data/core"
|
||||
xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
```
|
||||
|
||||
| Префикс | URI | Назначение |
|
||||
|---|---|---|
|
||||
| *(default)* | `.../data-composition-system/schema` | Элементы схемы (dataSource, dataSet, field, parameter, ...) |
|
||||
| `dcscom` | `.../data-composition-system/common` | Общие типы СКД (dimension, account, role, ...) |
|
||||
| `dcscor` | `.../data-composition-system/core` | Ядро СКД (Field, SettingsParameterValue, ChoiceParameterLinks, ...) |
|
||||
| `dcsset` | `.../data-composition-system/settings` | Настройки варианта (selection, filter, order, group, ...) |
|
||||
| `v8` | `.../data/core` | Типы данных ядра (LocalStringType, Type, StandardPeriod, ...) |
|
||||
| `v8ui` | `.../data/ui` | UI-типы (HorizontalAlign, ...) |
|
||||
| `xs` | `.../XMLSchema` | Стандартные XSD-типы (string, dateTime, boolean, decimal, ...) |
|
||||
| `xsi` | `.../XMLSchema-instance` | Атрибуты экземпляра (xsi:type, xsi:nil) |
|
||||
|
||||
Дополнительные пространства имён (появляются в `settingsVariant`):
|
||||
|
||||
| Префикс | URI | Где |
|
||||
|---|---|---|
|
||||
| `style` | `http://v8.1c.ru/8.1/data/ui/style` | В settings — стили оформления |
|
||||
| `sys` | `http://v8.1c.ru/8.1/data/ui/fonts/system` | В settings — системные шрифты |
|
||||
| `web` | `http://v8.1c.ru/8.1/data/ui/colors/web` | В settings — веб-цвета |
|
||||
| `win` | `http://v8.1c.ru/8.1/data/ui/colors/windows` | В settings — цвета Windows |
|
||||
|
||||
---
|
||||
|
||||
## 2. Общая структура DataCompositionSchema
|
||||
|
||||
Элементы верхнего уровня (порядок фиксирован):
|
||||
|
||||
```
|
||||
DataCompositionSchema
|
||||
├── dataSource* — источники данных (раздел 3)
|
||||
├── dataSet* — наборы данных (раздел 4)
|
||||
├── dataSetLink* — связи между наборами (раздел 5)
|
||||
├── calculatedField* — вычисляемые поля (раздел 6)
|
||||
├── totalField* — итоговые поля (раздел 7)
|
||||
├── parameter* — параметры схемы (раздел 8)
|
||||
├── template* — макеты областей (раздел 9)
|
||||
├── groupTemplate* — привязки макетов группировок (раздел 10)
|
||||
├── settingsVariant* — варианты настроек (раздел 11)
|
||||
```
|
||||
|
||||
`*` — 0..N элементов.
|
||||
|
||||
Минимальная DCS содержит: 1 dataSource + 1 dataSet + 1 settingsVariant.
|
||||
|
||||
---
|
||||
|
||||
## 3. Источники данных (dataSource)
|
||||
|
||||
```xml
|
||||
<dataSource>
|
||||
<name>ИсточникДанных1</name>
|
||||
<dataSourceType>Local</dataSourceType>
|
||||
</dataSource>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `name` | да | Уникальное имя, на которое ссылаются наборы данных |
|
||||
| `dataSourceType` | да | Тип: `Local` (текущая информационная база) или `External` (внешний) |
|
||||
|
||||
В подавляющем большинстве случаев — один источник `Local`. Имя произвольное: `ИсточникДанных1`, `ИнформационнаяБаза` и т.п.
|
||||
|
||||
---
|
||||
|
||||
## 4. Наборы данных (dataSet)
|
||||
|
||||
Тип набора определяется атрибутом `xsi:type`. Три типа:
|
||||
|
||||
### 4.1. DataSetQuery — запрос
|
||||
|
||||
Самый распространённый тип. Содержит SQL-подобный запрос на языке 1С.
|
||||
|
||||
```xml
|
||||
<dataSet xsi:type="DataSetQuery">
|
||||
<name>НаборДанных1</name>
|
||||
<field xsi:type="DataSetFieldField">...</field> <!-- 0..N полей -->
|
||||
<dataSource>ИсточникДанных1</dataSource>
|
||||
<query>ВЫБРАТЬ ... ИЗ ...</query>
|
||||
<autoFillFields>false</autoFillFields> <!-- опционально -->
|
||||
</dataSet>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `name` | да | Уникальное имя набора |
|
||||
| `field` | нет | Описания полей (раздел 4.4) |
|
||||
| `dataSource` | да | Ссылка на имя dataSource |
|
||||
| `query` | да | Текст запроса на языке 1С (XML-экранирование: `&` для `&`, `>` для `>`) |
|
||||
| `autoFillFields` | нет | `false` — отключить автозаполнение полей из запроса (по умолчанию `true`) |
|
||||
|
||||
#### Особенности запросов в DCS
|
||||
|
||||
- Параметры: `&ИмяПараметра` (в XML: `&ИмяПараметра`)
|
||||
- Авторазметка полей в фигурных скобках: `{ВЫБРАТЬ ...}`, `{ГДЕ ...}`, `{ЛЕВОЕ СОЕДИНЕНИЕ ...}` — позволяют СКД автоматически модифицировать запрос
|
||||
- Пакетные запросы: несколько запросов через `; ////////////////`
|
||||
- Временные таблицы: `ПОМЕСТИТЬ ИмяВТ`, `ИНДЕКСИРОВАТЬ ПО`
|
||||
|
||||
### 4.2. DataSetObject — объект
|
||||
|
||||
Данные берутся из программно заполненной таблицы значений.
|
||||
|
||||
```xml
|
||||
<dataSet xsi:type="DataSetObject">
|
||||
<name>НаборДанных1</name>
|
||||
<field xsi:type="DataSetFieldField">...</field>
|
||||
<dataSource>ИсточникДанных1</dataSource>
|
||||
<objectName>ТаблицаПроверки</objectName>
|
||||
</dataSet>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `objectName` | да | Имя объекта (таблицы значений), передаваемого программно |
|
||||
|
||||
### 4.3. DataSetUnion — объединение
|
||||
|
||||
Объединяет поля из нескольких наборов. Сам не содержит запросов — объединяет подчинённые наборы.
|
||||
|
||||
```xml
|
||||
<dataSet xsi:type="DataSetUnion">
|
||||
<name>РасчетНалога</name>
|
||||
<field xsi:type="DataSetFieldField">...</field> <!-- агрегированные поля -->
|
||||
<item xsi:type="DataSetQuery"> <!-- вложенные наборы -->
|
||||
<name>ДанныеПоСтоимости</name>
|
||||
...
|
||||
</item>
|
||||
<item xsi:type="DataSetQuery">
|
||||
<name>ДанныеПоКадастру</name>
|
||||
...
|
||||
</item>
|
||||
</dataSet>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `field` | нет | Поля объединения (описывают результирующие колонки) |
|
||||
| `item` | да | Вложенные наборы (DataSetQuery или другие) |
|
||||
|
||||
### 4.4. Поля набора данных (field)
|
||||
|
||||
Каждое поле — элемент `<field xsi:type="DataSetFieldField">`:
|
||||
|
||||
```xml
|
||||
<field xsi:type="DataSetFieldField">
|
||||
<dataPath>ОстаточнаяСтоимость</dataPath>
|
||||
<field>ОстаточнаяСтоимость</field>
|
||||
<title xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Остаточная стоимость</v8:content>
|
||||
</v8:item>
|
||||
</title>
|
||||
<useRestriction>
|
||||
<condition>true</condition>
|
||||
</useRestriction>
|
||||
<role>
|
||||
<dcscom:dimension>true</dcscom:dimension>
|
||||
</role>
|
||||
<valueType>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>11</v8:Length>
|
||||
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</valueType>
|
||||
<appearance>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Формат</dcscor:parameter>
|
||||
<dcscor:value xsi:type="xs:string">ЧДЦ=2</dcscor:value>
|
||||
</dcscor:item>
|
||||
</appearance>
|
||||
<inputParameters>...</inputParameters>
|
||||
<presentationExpression>...</presentationExpression>
|
||||
</field>
|
||||
```
|
||||
|
||||
#### Элементы поля
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `dataPath` | да | Путь к данным (имя поля в результате СКД). Через точку — реквизиты: `Номенклатура.Артикул` |
|
||||
| `field` | да | Имя поля в запросе (может отличаться от dataPath) |
|
||||
| `title` | нет | Локализованный заголовок (`v8:LocalStringType`) |
|
||||
| `useRestriction` | нет | Ограничения использования поля (раздел 4.5) |
|
||||
| `attributeUseRestriction` | нет | Ограничения использования реквизитов поля (раздел 4.5) |
|
||||
| `role` | нет | Роль поля в СКД (раздел 4.6) |
|
||||
| `valueType` | нет | Тип значения поля (раздел 4.7) |
|
||||
| `appearance` | нет | Оформление — список параметров `dcscor:item` (раздел 4.8) |
|
||||
| `inputParameters` | нет | Параметры ввода / связи параметров выбора (раздел 4.9) |
|
||||
| `presentationExpression` | нет | Выражение для формирования представления (на языке 1С) |
|
||||
|
||||
### 4.5. Ограничения использования поля (useRestriction / attributeUseRestriction)
|
||||
|
||||
```xml
|
||||
<useRestriction>
|
||||
<field>true</field> <!-- запрет использования как поле в выборке -->
|
||||
<condition>true</condition> <!-- запрет в условиях отбора -->
|
||||
<group>true</group> <!-- запрет в группировках -->
|
||||
<order>true</order> <!-- запрет в сортировке -->
|
||||
</useRestriction>
|
||||
```
|
||||
|
||||
Каждый подэлемент — `true`/`false` (по умолчанию `false` = разрешено). Можно указывать подмножество.
|
||||
|
||||
`attributeUseRestriction` — аналогичная структура, применяется к реквизитам (дочерним полям) поля.
|
||||
|
||||
### 4.6. Роли полей (role)
|
||||
|
||||
```xml
|
||||
<role>
|
||||
<dcscom:dimension>true</dcscom:dimension> <!-- поле — измерение -->
|
||||
<dcscom:account>true</dcscom:account> <!-- поле — счёт -->
|
||||
<dcscom:accountTypeExpression>Счет.Вид</dcscom:accountTypeExpression> <!-- выражение типа счёта -->
|
||||
</role>
|
||||
```
|
||||
|
||||
| Подэлемент | Описание |
|
||||
|---|---|
|
||||
| `dcscom:dimension` | Поле является измерением (`true`/`false`) |
|
||||
| `dcscom:account` | Поле является счётом |
|
||||
| `dcscom:accountTypeExpression` | Выражение для определения типа счёта |
|
||||
| `dcscom:balance` | Поле является остатком |
|
||||
| `dcscom:balanceGroup` | Группа остатка |
|
||||
| `dcscom:period` | Поле — период |
|
||||
|
||||
### 4.7. Тип значения (valueType)
|
||||
|
||||
```xml
|
||||
<valueType>
|
||||
<v8:Type>xs:string</v8:Type>
|
||||
<v8:StringQualifiers>
|
||||
<v8:Length>11</v8:Length>
|
||||
<v8:AllowedLength>Variable</v8:AllowedLength>
|
||||
</v8:StringQualifiers>
|
||||
</valueType>
|
||||
```
|
||||
|
||||
Типы: `xs:string`, `xs:dateTime`, `xs:decimal`, `xs:boolean`, ссылочные (`d4p1:CatalogRef.Номенклатура`).
|
||||
|
||||
Квалификаторы:
|
||||
- `v8:StringQualifiers` → `v8:Length`, `v8:AllowedLength` (Fixed/Variable)
|
||||
- `v8:DateQualifiers` → `v8:DateFractions` (Date/Time/DateTime)
|
||||
- `v8:NumberQualifiers` → `v8:Digits`, `v8:FractionDigits`, `v8:AllowedSign` (Any/Nonnegative)
|
||||
|
||||
### 4.8. Оформление полей (appearance)
|
||||
|
||||
Список параметров оформления:
|
||||
|
||||
```xml
|
||||
<appearance>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Формат</dcscor:parameter>
|
||||
<dcscor:value xsi:type="xs:string">ЧДЦ=2</dcscor:value>
|
||||
</dcscor:item>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>ГоризонтальноеПоложение</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8ui:HorizontalAlign">Center</dcscor:value>
|
||||
</dcscor:item>
|
||||
</appearance>
|
||||
```
|
||||
|
||||
Типичные параметры оформления:
|
||||
|
||||
| Параметр | Тип значения | Пример |
|
||||
|---|---|---|
|
||||
| `Формат` | `xs:string` | `ЧДЦ=2`, `ЧГ=0`, `ЧН=0`, `ДФ=dd.MM.yyyy`, `Л=ru; ДФ=ММММ` |
|
||||
| `ГоризонтальноеПоложение` | `v8ui:HorizontalAlign` | `Left`, `Center`, `Right` |
|
||||
|
||||
### 4.9. Параметры ввода (inputParameters)
|
||||
|
||||
Связи параметров выбора для интерактивных полей:
|
||||
|
||||
```xml
|
||||
<inputParameters>
|
||||
<dcscor:item>
|
||||
<dcscor:parameter>СвязиПараметровВыбора</dcscor:parameter>
|
||||
<dcscor:value xsi:type="dcscor:ChoiceParameterLinks">
|
||||
<dcscor:item>
|
||||
<dcscor:choiceParameter>Отбор.Владелец</dcscor:choiceParameter>
|
||||
<dcscor:value>Организация</dcscor:value>
|
||||
<dcscor:mode xmlns:d8p1="http://v8.1c.ru/8.1/data/enterprise"
|
||||
xsi:type="d8p1:LinkedValueChangeMode">Clear</dcscor:mode>
|
||||
</dcscor:item>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
</inputParameters>
|
||||
```
|
||||
|
||||
Используется для каскадных зависимостей в пользовательских настройках (например, подразделение зависит от организации).
|
||||
|
||||
---
|
||||
|
||||
## 5. Связи между наборами данных (dataSetLink)
|
||||
|
||||
Позволяют передавать параметры из одного набора в другой:
|
||||
|
||||
```xml
|
||||
<dataSetLink>
|
||||
<sourceDataSet>Периоды</sourceDataSet>
|
||||
<destinationDataSet>ДанныеТ13</destinationDataSet>
|
||||
<sourceExpression>НачалоМесяца</sourceExpression>
|
||||
<destinationExpression>Месяц</destinationExpression>
|
||||
<parameter>НачалоМесяца</parameter>
|
||||
<parameterListAllowed>false</parameterListAllowed>
|
||||
</dataSetLink>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `sourceDataSet` | да | Имя набора-источника |
|
||||
| `destinationDataSet` | да | Имя целевого набора |
|
||||
| `sourceExpression` | да | Выражение из источника (поле или формула) |
|
||||
| `destinationExpression` | да | Выражение для сопоставления в целевом наборе |
|
||||
| `parameter` | нет | Имя параметра для передачи значения |
|
||||
| `parameterListAllowed` | нет | Допустим ли список значений (`true`/`false`) |
|
||||
|
||||
---
|
||||
|
||||
## 6. Вычисляемые поля (calculatedField)
|
||||
|
||||
Поля, вычисляемые выражением на языке 1С (не из запроса):
|
||||
|
||||
```xml
|
||||
<calculatedField>
|
||||
<dataPath>УИД</dataPath>
|
||||
<expression>БухгалтерскиеОтчеты.ПолучитьУИДСсылкиСтрокой(Номенклатура)</expression>
|
||||
<title xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Уникальный идентификатор</v8:content>
|
||||
</v8:item>
|
||||
</title>
|
||||
<useRestriction>
|
||||
<condition>true</condition>
|
||||
<group>true</group>
|
||||
<order>true</order>
|
||||
</useRestriction>
|
||||
</calculatedField>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `dataPath` | да | Путь к полю в результате |
|
||||
| `expression` | да | Выражение на языке 1С (может вызывать методы общих модулей) |
|
||||
| `title` | нет | Локализованный заголовок |
|
||||
| `useRestriction` | нет | Ограничения использования (аналогично полям) |
|
||||
| `valueType` | нет | Тип значения |
|
||||
| `appearance` | нет | Оформление |
|
||||
|
||||
---
|
||||
|
||||
## 7. Итоговые поля (totalField)
|
||||
|
||||
Агрегатные функции для подведения итогов:
|
||||
|
||||
```xml
|
||||
<totalField>
|
||||
<dataPath>Количество</dataPath>
|
||||
<expression>Сумма(Количество)</expression>
|
||||
</totalField>
|
||||
<totalField>
|
||||
<dataPath>Цена</dataPath>
|
||||
<expression>Максимум(Цена)</expression>
|
||||
</totalField>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `dataPath` | да | Путь к полю |
|
||||
| `expression` | да | Агрегатная функция: `Сумма(...)`, `Количество(...)`, `Максимум(...)`, `Минимум(...)`, `Среднее(...)` |
|
||||
| `group` | нет | Для какой группировки считать итоги |
|
||||
|
||||
---
|
||||
|
||||
## 8. Параметры схемы (parameter)
|
||||
|
||||
Параметры, доступные для задания пользователем или программно:
|
||||
|
||||
```xml
|
||||
<parameter>
|
||||
<name>Период</name>
|
||||
<title xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Период</v8:content>
|
||||
</v8:item>
|
||||
</title>
|
||||
<valueType>
|
||||
<v8:Type>v8:StandardPeriod</v8:Type>
|
||||
</valueType>
|
||||
<value xsi:type="v8:StandardPeriod">
|
||||
<v8:variant xsi:type="v8:StandardPeriodVariant">LastMonth</v8:variant>
|
||||
</value>
|
||||
<useRestriction>false</useRestriction>
|
||||
<expression>&Период.ДатаНачала</expression>
|
||||
<availableAsField>false</availableAsField>
|
||||
<use>Always</use>
|
||||
</parameter>
|
||||
```
|
||||
|
||||
| Элемент | Обязат. | Описание |
|
||||
|---|---|---|
|
||||
| `name` | да | Имя параметра (используется в запросах как `&ИмяПараметра`) |
|
||||
| `title` | нет | Локализованный заголовок |
|
||||
| `valueType` | нет | Тип значения (раздел 4.7) |
|
||||
| `value` | нет | Значение по умолчанию |
|
||||
| `useRestriction` | нет | `true` — параметр скрыт от пользователя, `false` — доступен |
|
||||
| `expression` | нет | Выражение для автоматического вычисления (например, `&Период.ДатаНачала`) |
|
||||
| `availableAsField` | нет | `false` — параметр недоступен как поле в отчёте |
|
||||
| `use` | нет | Режим: `Always` (всегда), `Auto` (автоматически) |
|
||||
|
||||
### Типы значений параметров
|
||||
|
||||
| Тип | XML-тип | Пример value |
|
||||
|---|---|---|
|
||||
| Дата | `xs:dateTime` | `0001-01-01T00:00:00` |
|
||||
| Строка | `xs:string` | `Т13` |
|
||||
| Стандартный период | `v8:StandardPeriod` | `<v8:variant>LastMonth</v8:variant>` |
|
||||
| Ссылка | `d4p1:CatalogRef.ИмяСправочника` | `xsi:nil="true"` |
|
||||
| null | — | `xsi:nil="true"` |
|
||||
|
||||
Стандартные варианты периодов (`v8:StandardPeriodVariant`): `Custom`, `Today`, `ThisWeek`, `ThisMonth`, `ThisQuarter`, `ThisYear`, `LastMonth`, `LastQuarter`, `LastYear` и др.
|
||||
|
||||
---
|
||||
|
||||
## 9. Макеты областей (template)
|
||||
|
||||
Пользовательские шаблоны вывода (макеты ячеек):
|
||||
|
||||
```xml
|
||||
<template>
|
||||
<name>Макет1</name>
|
||||
<template xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template"
|
||||
xsi:type="dcsat:AreaTemplate">
|
||||
<dcsat:item xsi:type="dcsat:TableRow">
|
||||
<dcsat:tableCell>
|
||||
<dcsat:item xsi:type="dcsat:Field">
|
||||
<dcsat:value xsi:type="dcscor:Parameter">ТипЦены</dcsat:value>
|
||||
</dcsat:item>
|
||||
</dcsat:tableCell>
|
||||
</dcsat:item>
|
||||
</template>
|
||||
<parameter xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template"
|
||||
xsi:type="dcsat:ExpressionAreaTemplateParameter">
|
||||
<dcsat:name>ТипЦены</dcsat:name>
|
||||
<dcsat:expression>Представление(ТипЦен)</dcsat:expression>
|
||||
</parameter>
|
||||
</template>
|
||||
```
|
||||
|
||||
Пространство имён `dcsat`: `http://v8.1c.ru/8.1/data-composition-system/area-template`.
|
||||
|
||||
| Элемент | Описание |
|
||||
|---|---|
|
||||
| `name` | Имя макета (ссылаются groupTemplate) |
|
||||
| `template` (вложенный) | Описание строк/ячеек (`dcsat:AreaTemplate`) |
|
||||
| `parameter` | Параметры макета (`dcsat:ExpressionAreaTemplateParameter`) — выражения для подстановки |
|
||||
|
||||
---
|
||||
|
||||
## 10. Привязки макетов группировок (groupTemplate)
|
||||
|
||||
Связывают группировку с пользовательским макетом:
|
||||
|
||||
```xml
|
||||
<groupTemplate>
|
||||
<groupField>ТипЦен</groupField>
|
||||
<templateType>Header</templateType>
|
||||
<template>Макет1</template>
|
||||
</groupTemplate>
|
||||
```
|
||||
|
||||
| Элемент | Описание |
|
||||
|---|---|
|
||||
| `groupField` | Имя поля группировки |
|
||||
| `templateType` | Тип: `Header` (заголовок), `Footer` (подвал), `Overall` (общий) |
|
||||
| `template` | Ссылка на имя template из раздела 9 |
|
||||
|
||||
---
|
||||
|
||||
## 11. Варианты настроек (settingsVariant)
|
||||
|
||||
Каждый вариант — именованная конфигурация отчёта. Отчёт может иметь несколько вариантов.
|
||||
|
||||
```xml
|
||||
<settingsVariant>
|
||||
<dcsset:name>Основной</dcsset:name>
|
||||
<dcsset:presentation xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Основной вариант отчёта</v8:content>
|
||||
</v8:item>
|
||||
</dcsset:presentation>
|
||||
<dcsset:settings xmlns:style="..." xmlns:sys="..." xmlns:web="..." xmlns:win="...">
|
||||
<!-- содержимое настроек -->
|
||||
</dcsset:settings>
|
||||
</settingsVariant>
|
||||
```
|
||||
|
||||
### 11.1. Структура settings
|
||||
|
||||
```
|
||||
dcsset:settings
|
||||
├── dcsset:selection — выбранные поля (раздел 11.2)
|
||||
├── dcsset:filter — отборы (раздел 11.3)
|
||||
├── dcsset:order — сортировка (раздел 11.4)
|
||||
├── dcsset:conditionalAppearance — условное оформление (раздел 11.5)
|
||||
├── dcsset:outputParameters — параметры вывода (раздел 11.6)
|
||||
├── dcsset:dataParameters — значения параметров данных (раздел 11.7)
|
||||
├── dcsset:item* — элементы структуры (раздел 11.8)
|
||||
```
|
||||
|
||||
### 11.2. Выборка полей (selection)
|
||||
|
||||
```xml
|
||||
<dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemField">
|
||||
<dcsset:field>ТипОбъекта</dcsset:field>
|
||||
<dcsset:lwsTitle> <!-- опциональный заголовок -->
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Наименование</v8:content>
|
||||
</v8:item>
|
||||
</dcsset:lwsTitle>
|
||||
</dcsset:item>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/> <!-- авто-выбор -->
|
||||
</dcsset:selection>
|
||||
```
|
||||
|
||||
Типы элементов выборки:
|
||||
- `dcsset:SelectedItemField` — конкретное поле (элемент `dcsset:field`)
|
||||
- `dcsset:SelectedItemAuto` — автоматический подбор полей
|
||||
|
||||
### 11.3. Отборы (filter)
|
||||
|
||||
```xml
|
||||
<dcsset:filter>
|
||||
<dcsset:item xsi:type="dcsset:FilterItemComparison">
|
||||
<dcsset:use>false</dcsset:use> <!-- включён/выключен -->
|
||||
<dcsset:left xsi:type="dcscor:Field">Организация</dcsset:left>
|
||||
<dcsset:comparisonType>Equal</dcsset:comparisonType>
|
||||
<dcsset:right xsi:type="xs:boolean">false</dcsset:right>
|
||||
<dcsset:presentation xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Описание фильтра</v8:content>
|
||||
</v8:item>
|
||||
</dcsset:presentation>
|
||||
<dcsset:viewMode>Normal</dcsset:viewMode>
|
||||
<dcsset:userSettingID>GUID</dcsset:userSettingID>
|
||||
</dcsset:item>
|
||||
</dcsset:filter>
|
||||
```
|
||||
|
||||
Типы элементов фильтра:
|
||||
- `dcsset:FilterItemComparison` — сравнение поля с значением
|
||||
- `dcsset:FilterItemGroup` — группа условий (И/ИЛИ)
|
||||
|
||||
Типы сравнения (`comparisonType`):
|
||||
|
||||
| Значение | Описание |
|
||||
|---|---|
|
||||
| `Equal` | Равно |
|
||||
| `NotEqual` | Не равно |
|
||||
| `Greater` | Больше |
|
||||
| `GreaterOrEqual` | Больше или равно |
|
||||
| `Less` | Меньше |
|
||||
| `LessOrEqual` | Меньше или равно |
|
||||
| `InList` | В списке |
|
||||
| `NotInList` | Не в списке |
|
||||
| `InHierarchy` | В иерархии |
|
||||
| `InListByHierarchy` | В списке по иерархии |
|
||||
| `Contains` | Содержит |
|
||||
| `NotContains` | Не содержит |
|
||||
| `BeginsWith` | Начинается с |
|
||||
| `NotBeginsWith` | Не начинается с |
|
||||
| `Filled` | Заполнено |
|
||||
| `NotFilled` | Не заполнено |
|
||||
|
||||
Значение правой части (`right`) — может содержать списки:
|
||||
```xml
|
||||
<dcsset:right xsi:type="v8:ValueListType">
|
||||
<v8:valueType/>
|
||||
<v8:lastId xsi:type="xs:decimal">-1</v8:lastId>
|
||||
</dcsset:right>
|
||||
```
|
||||
|
||||
### 11.4. Сортировка (order)
|
||||
|
||||
```xml
|
||||
<dcsset:order>
|
||||
<dcsset:item xsi:type="dcsset:OrderItemField">
|
||||
<dcsset:field>РазмерДанных</dcsset:field>
|
||||
<dcsset:orderType>Desc</dcsset:orderType>
|
||||
</dcsset:item>
|
||||
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
|
||||
</dcsset:order>
|
||||
```
|
||||
|
||||
Типы элементов сортировки:
|
||||
- `dcsset:OrderItemField` — по полю (`dcsset:field` + `dcsset:orderType`: `Asc`/`Desc`)
|
||||
- `dcsset:OrderItemAuto` — автоматическая сортировка
|
||||
|
||||
### 11.5. Условное оформление (conditionalAppearance)
|
||||
|
||||
```xml
|
||||
<dcsset:conditionalAppearance>
|
||||
<dcsset:item>
|
||||
<dcsset:selection>
|
||||
<dcsset:item>
|
||||
<dcsset:field>ИмяПоля</dcsset:field>
|
||||
</dcsset:item>
|
||||
</dcsset:selection>
|
||||
<dcsset:filter>
|
||||
<dcsset:item xsi:type="dcsset:FilterItemComparison">
|
||||
<dcsset:left xsi:type="dcscor:Field">ИмяПоля</dcsset:left>
|
||||
<dcsset:comparisonType>Equal</dcsset:comparisonType>
|
||||
<dcsset:right xsi:type="xs:decimal">0</dcsset:right>
|
||||
</dcsset:item>
|
||||
</dcsset:filter>
|
||||
<dcsset:appearance>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:parameter>Текст</dcscor:parameter>
|
||||
<dcscor:value xsi:type="xs:string"/>
|
||||
</dcscor:item>
|
||||
</dcsset:appearance>
|
||||
</dcsset:item>
|
||||
</dcsset:conditionalAppearance>
|
||||
```
|
||||
|
||||
### 11.6. Параметры вывода (outputParameters)
|
||||
|
||||
```xml
|
||||
<dcsset:outputParameters>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:use>false</dcscor:use> <!-- опционально -->
|
||||
<dcscor:parameter>Заголовок</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Текст заголовка</v8:content>
|
||||
</v8:item>
|
||||
</dcscor:value>
|
||||
</dcscor:item>
|
||||
</dcsset:outputParameters>
|
||||
```
|
||||
|
||||
Типичные параметры вывода:
|
||||
|
||||
| Параметр | Тип значения | Описание |
|
||||
|---|---|---|
|
||||
| `Заголовок` | `v8:LocalStringType` | Заголовок отчёта |
|
||||
| `МакетОформления` | `xs:string` | Имя макета оформления: `ОформлениеОтчетовЧерноБелый`, `Зеленый` и др. |
|
||||
| `РасположениеПолейГруппировки` | `dcsset:DataCompositionGroupFieldsPlacement` | `Together`, `Separately`, `SeparatelyAndInGroups` |
|
||||
| `РасположениеРеквизитов` | `dcsset:DataCompositionAttributesPlacement` | `Together`, `Separately`, `SeparatelyAndInGroups` |
|
||||
| `ГоризонтальноеРасположениеОбщихИтогов` | `dcscor:DataCompositionTotalPlacement` | `None`, `Begin`, `End`, `Auto` |
|
||||
| `ВертикальноеРасположениеОбщихИтогов` | `dcscor:DataCompositionTotalPlacement` | `None`, `Begin`, `End`, `Auto` |
|
||||
| `ВыводитьЗаголовок` | `dcsset:DataCompositionTextOutputType` | `Auto`, `DontOutput`, `Output` |
|
||||
| `ВыводитьПараметрыДанных` | `dcsset:DataCompositionTextOutputType` | То же |
|
||||
| `ВыводитьОтбор` | `dcsset:DataCompositionTextOutputType` | То же |
|
||||
|
||||
### 11.7. Параметры данных (dataParameters)
|
||||
|
||||
Значения параметров схемы в конкретном варианте:
|
||||
|
||||
```xml
|
||||
<dcsset:dataParameters>
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:use>false</dcscor:use>
|
||||
<dcscor:parameter>Период</dcscor:parameter>
|
||||
<dcscor:value xsi:type="v8:StandardPeriod">
|
||||
<v8:variant xsi:type="v8:StandardPeriodVariant">LastMonth</v8:variant>
|
||||
</dcscor:value>
|
||||
<dcsset:viewMode>Normal</dcsset:viewMode>
|
||||
<dcsset:userSettingID>GUID</dcsset:userSettingID>
|
||||
</dcscor:item>
|
||||
</dcsset:dataParameters>
|
||||
```
|
||||
|
||||
| Элемент | Описание |
|
||||
|---|---|
|
||||
| `dcscor:use` | `true`/`false` — использовать значение или нет |
|
||||
| `dcscor:parameter` | Имя параметра из раздела 8 |
|
||||
| `dcscor:value` | Значение параметра |
|
||||
| `dcsset:viewMode` | Режим отображения: `Normal`, `QuickAccess`, `Inaccessible` |
|
||||
| `dcsset:userSettingID` | GUID пользовательской настройки |
|
||||
|
||||
### 11.8. Элементы структуры (structure items)
|
||||
|
||||
Структура отчёта — иерархия группировок, таблиц, диаграмм.
|
||||
|
||||
#### StructureItemGroup — группировка
|
||||
|
||||
```xml
|
||||
<dcsset:item xsi:type="dcsset:StructureItemGroup">
|
||||
<dcsset:name>Группировка</dcsset:name>
|
||||
<dcsset:groupItems>
|
||||
<dcsset:item xsi:type="dcsset:GroupItemField">
|
||||
<dcsset:field>Организация</dcsset:field>
|
||||
<dcsset:groupType>Items</dcsset:groupType>
|
||||
<dcsset:periodAdditionType>None</dcsset:periodAdditionType>
|
||||
<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
|
||||
<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
|
||||
</dcsset:item>
|
||||
</dcsset:groupItems>
|
||||
<dcsset:order>
|
||||
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
|
||||
</dcsset:order>
|
||||
<dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>
|
||||
</dcsset:selection>
|
||||
<dcsset:outputParameters>...</dcsset:outputParameters>
|
||||
<dcsset:item xsi:type="dcsset:StructureItemGroup"> <!-- вложенная группировка -->
|
||||
...
|
||||
</dcsset:item>
|
||||
</dcsset:item>
|
||||
```
|
||||
|
||||
Типы группировки (`groupType`): `Items`, `Hierarchy`, `HierarchyOnly`.
|
||||
|
||||
Типы дополнения периодом (`periodAdditionType`): `None`, `Year`, `HalfYear`, `Quarter`, `Month`, `TenDays`, `Week`, `Day`.
|
||||
|
||||
Пустая группировка (без `groupItems`) = детальные записи.
|
||||
|
||||
#### StructureItemTable — таблица (кросс-таблица)
|
||||
|
||||
```xml
|
||||
<dcsset:item xsi:type="dcsset:StructureItemTable">
|
||||
<dcsset:name>Таблица</dcsset:name>
|
||||
<dcsset:column> <!-- группировки колонок -->
|
||||
<dcsset:groupItems>...</dcsset:groupItems>
|
||||
<dcsset:order>...</dcsset:order>
|
||||
<dcsset:selection>...</dcsset:selection>
|
||||
</dcsset:column>
|
||||
<dcsset:row> <!-- группировки строк -->
|
||||
<dcsset:name>Группировка</dcsset:name>
|
||||
<dcsset:groupItems>...</dcsset:groupItems>
|
||||
<dcsset:order>...</dcsset:order>
|
||||
<dcsset:selection>...</dcsset:selection>
|
||||
</dcsset:row>
|
||||
</dcsset:item>
|
||||
```
|
||||
|
||||
#### StructureItemChart — диаграмма
|
||||
|
||||
```xml
|
||||
<dcsset:item xsi:type="dcsset:StructureItemChart">
|
||||
<dcsset:point> <!-- точки (ось X) -->
|
||||
<dcsset:groupItems>...</dcsset:groupItems>
|
||||
<dcsset:order>...</dcsset:order>
|
||||
<dcsset:selection>...</dcsset:selection>
|
||||
</dcsset:point>
|
||||
<dcsset:series> <!-- серии (необязательно) -->
|
||||
<dcsset:groupItems>...</dcsset:groupItems>
|
||||
...
|
||||
</dcsset:series>
|
||||
<dcsset:selection> <!-- значения для отображения -->
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemField">
|
||||
<dcsset:field>РазмерДанных</dcsset:field>
|
||||
</dcsset:item>
|
||||
</dcsset:selection>
|
||||
<dcsset:outputParameters>...</dcsset:outputParameters>
|
||||
</dcsset:item>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Типы данных — сводка
|
||||
|
||||
### v8:LocalStringType — локализованная строка
|
||||
|
||||
```xml
|
||||
<title xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Текст на русском</v8:content>
|
||||
</v8:item>
|
||||
</title>
|
||||
```
|
||||
|
||||
Также можно задать как простую строку: `xsi:type="xs:string"`.
|
||||
|
||||
### dcscor:SettingsParameterValue — параметр настройки
|
||||
|
||||
```xml
|
||||
<dcscor:item xsi:type="dcsset:SettingsParameterValue">
|
||||
<dcscor:use>true</dcscor:use> <!-- опционально -->
|
||||
<dcscor:parameter>ИмяПараметра</dcscor:parameter>
|
||||
<dcscor:value xsi:type="ТипЗначения">Значение</dcscor:value>
|
||||
</dcscor:item>
|
||||
```
|
||||
|
||||
### dcscor:Field — ссылка на поле
|
||||
|
||||
```xml
|
||||
<dcsset:left xsi:type="dcscor:Field">ИмяПоля</dcsset:left>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Полный минимальный пример
|
||||
|
||||
Простая DCS: один запрос, два поля, один итог, один вариант:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<DataCompositionSchema xmlns="http://v8.1c.ru/8.1/data-composition-system/schema"
|
||||
xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common"
|
||||
xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core"
|
||||
xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings"
|
||||
xmlns:v8="http://v8.1c.ru/8.1/data/core"
|
||||
xmlns:v8ui="http://v8.1c.ru/8.1/data/ui"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<dataSource>
|
||||
<name>ИсточникДанных1</name>
|
||||
<dataSourceType>Local</dataSourceType>
|
||||
</dataSource>
|
||||
<dataSet xsi:type="DataSetQuery">
|
||||
<name>НаборДанных1</name>
|
||||
<field xsi:type="DataSetFieldField">
|
||||
<dataPath>Наименование</dataPath>
|
||||
<field>Наименование</field>
|
||||
<title xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Наименование</v8:content>
|
||||
</v8:item>
|
||||
</title>
|
||||
</field>
|
||||
<field xsi:type="DataSetFieldField">
|
||||
<dataPath>Количество</dataPath>
|
||||
<field>Количество</field>
|
||||
</field>
|
||||
<dataSource>ИсточникДанных1</dataSource>
|
||||
<query>ВЫБРАТЬ
|
||||
Номенклатура.Наименование КАК Наименование,
|
||||
КОЛИЧЕСТВО(1) КАК Количество
|
||||
ИЗ
|
||||
Справочник.Номенклатура КАК Номенклатура
|
||||
СГРУППИРОВАТЬ ПО
|
||||
Номенклатура.Наименование</query>
|
||||
</dataSet>
|
||||
<totalField>
|
||||
<dataPath>Количество</dataPath>
|
||||
<expression>Сумма(Количество)</expression>
|
||||
</totalField>
|
||||
<settingsVariant>
|
||||
<dcsset:name>Основной</dcsset:name>
|
||||
<dcsset:presentation xsi:type="v8:LocalStringType">
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Основной</v8:content>
|
||||
</v8:item>
|
||||
</dcsset:presentation>
|
||||
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style"
|
||||
xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system"
|
||||
xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web"
|
||||
xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows">
|
||||
<dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemField">
|
||||
<dcsset:field>Наименование</dcsset:field>
|
||||
</dcsset:item>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemField">
|
||||
<dcsset:field>Количество</dcsset:field>
|
||||
</dcsset:item>
|
||||
</dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:StructureItemGroup">
|
||||
<dcsset:order>
|
||||
<dcsset:item xsi:type="dcsset:OrderItemAuto"/>
|
||||
</dcsset:order>
|
||||
<dcsset:selection>
|
||||
<dcsset:item xsi:type="dcsset:SelectedItemAuto"/>
|
||||
</dcsset:selection>
|
||||
</dcsset:item>
|
||||
</dcsset:settings>
|
||||
</settingsVariant>
|
||||
</DataCompositionSchema>
|
||||
```
|
||||
@@ -0,0 +1,112 @@
|
||||
# Спецификация Role JSON DSL
|
||||
|
||||
Формат JSON для описания ролей 1С, используемый навыком `/role-compile`.
|
||||
|
||||
## Обзор
|
||||
|
||||
Role JSON DSL — компактный JSON-формат, транслируемый скриптом в XML-файлы роли 1С:Предприятия (метаданные + Rights.xml). Поддерживает пресеты прав, русские синонимы типов и прав, шаблоны ограничений (RLS).
|
||||
|
||||
## Корневой объект
|
||||
|
||||
| Поле | Тип | Обяз. | По умолчанию | Описание |
|
||||
|------|-----|:-----:|:------------:|----------|
|
||||
| `name` | string | да | — | Программное имя роли |
|
||||
| `synonym` | string | нет | = name | Отображаемое имя |
|
||||
| `comment` | string | нет | `""` | Комментарий |
|
||||
| `setForNewObjects` | bool | нет | `false` | Устанавливать для новых объектов |
|
||||
| `setForAttributesByDefault` | bool | нет | `true` | Устанавливать для реквизитов по умолчанию |
|
||||
| `independentRightsOfChildObjects` | bool | нет | `false` | Независимые права подчинённых объектов |
|
||||
| `objects` | array | нет | `[]` | Массив объектов метаданных с правами |
|
||||
| `templates` | array | нет | `[]` | Шаблоны ограничений (RLS) |
|
||||
|
||||
## Элементы `objects`
|
||||
|
||||
Массив принимает два формата, которые можно смешивать.
|
||||
|
||||
### Строковый shorthand
|
||||
|
||||
```
|
||||
"Тип.Имя: @пресет"
|
||||
"Тип.Имя: Право1, Право2"
|
||||
```
|
||||
|
||||
Тип — английский (Catalog) или русский (Справочник). Права — английские (Read) или русские (Чтение).
|
||||
|
||||
### Объектная форма
|
||||
|
||||
| Поле | Тип | Обяз. | Описание |
|
||||
|------|-----|:-----:|----------|
|
||||
| `name` | string | да | Полное имя объекта: `Тип.Имя` |
|
||||
| `preset` | string | нет | Пресет: `"view"`, `"edit"` (без `@`) |
|
||||
| `rights` | object\|array | нет | Переопределения: `{"Right": bool}` или `["Right1", "Right2"]` |
|
||||
| `rls` | object | нет | RLS: `{"ИмяПрава": "текст условия или #шаблон"}` |
|
||||
|
||||
При наличии `preset` + `rights` — сначала применяется пресет, затем `rights` переопределяют отдельные права.
|
||||
|
||||
## Пресеты
|
||||
|
||||
Три встроенных пресета определяют набор прав в зависимости от типа объекта:
|
||||
|
||||
| Пресет | Назначение |
|
||||
|--------|------------|
|
||||
| `view` | Просмотр: Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
|
||||
| `edit` | Полное редактирование: CRUD + Interactive* + Posting (документы) |
|
||||
|
||||
Подробные таблицы прав для каждого типа объекта — в `.claude/skills/role-compile/dsl-reference.md`.
|
||||
|
||||
## Шаблоны ограничений (RLS)
|
||||
|
||||
Элементы массива `templates`:
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| `name` | string | Имя шаблона с параметрами: `"ДляОбъекта(Модификатор)"` |
|
||||
| `condition` | string | Текст условия. `&` экранируется в `&` автоматически |
|
||||
|
||||
Ссылка на шаблон в `rls`: `"#ИмяШаблона(\"параметры\")"` — начинается с `#`.
|
||||
|
||||
## Русские синонимы
|
||||
|
||||
DSL принимает русские имена типов и прав, транслируя их в английские. Полные таблицы соответствий — в `.claude/skills/role-compile/dsl-reference.md`.
|
||||
|
||||
Примеры: `Справочник` → Catalog, `Документ` → Document, `Чтение` → Read, `Просмотр` → View.
|
||||
|
||||
## Пример
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "МенеджерПродаж",
|
||||
"synonym": "Менеджер продаж",
|
||||
"objects": [
|
||||
"Document.РеализацияТоваровУслуг: @edit",
|
||||
"Catalog.Контрагенты: @view",
|
||||
"Catalog.Номенклатура: @view",
|
||||
{
|
||||
"name": "Document.ЗаказКлиента",
|
||||
"preset": "view",
|
||||
"rls": { "Read": "#ДляОбъекта(\"\")" }
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"name": "ДляОбъекта(Модификатор)",
|
||||
"condition": "ГДЕ Организация = &ТекущаяОрганизация"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Генерируемые файлы
|
||||
|
||||
```
|
||||
Roles/
|
||||
ИмяРоли.xml # Метаданные (UUID, синоним, флаги)
|
||||
ИмяРоли/
|
||||
└── Ext/
|
||||
└── Rights.xml # Права доступа (объекты, права, RLS)
|
||||
```
|
||||
|
||||
## См. также
|
||||
|
||||
- [Роли (Rights.xml)](1c-role-spec.md) — XML-формат прав роли, типы объектов, RLS
|
||||
- [Гайд по ролям](role-guide.md) — сценарии использования, рабочий цикл
|
||||
+103
-17
@@ -1,13 +1,72 @@
|
||||
# Роли (Role)
|
||||
|
||||
Навыки группы `/role-*` позволяют анализировать и создавать роли 1С — XML-файлы прав доступа (Rights.xml) и метаданных.
|
||||
Навыки группы `/role-*` позволяют анализировать, создавать и проверять роли 1С — XML-файлы прав доступа (Rights.xml) и метаданных.
|
||||
|
||||
## Навыки
|
||||
|
||||
| Навык | Параметры | Описание |
|
||||
|-------|-----------|----------|
|
||||
| `/role-info` | `<RightsPath>` | Компактная сводка прав: объекты по типам, только разрешённые, RLS, шаблоны |
|
||||
| `/role-compile` | `<RoleName> <RolesDir>` | Создание роли: метаданные + Rights.xml по описанию прав |
|
||||
| `/role-compile` | `<JsonPath> <RolesDir>` | Генерация роли из JSON DSL: метаданные + Rights.xml, UUID автоматически |
|
||||
| `/role-validate` | `<RightsPath> [MetadataPath]` | Валидация структурной корректности: XML, namespace, права, RLS, шаблоны |
|
||||
|
||||
## Рабочий цикл
|
||||
|
||||
```
|
||||
Описание прав (текст) → JSON DSL → /role-compile → XML-исходники → /role-validate
|
||||
→ /role-info
|
||||
```
|
||||
|
||||
1. Claude формирует JSON-определение роли (с пресетами или явными правами)
|
||||
2. `/role-compile` генерирует `Roles/ИмяРоли.xml` + `Roles/ИмяРоли/Ext/Rights.xml`
|
||||
3. `/role-validate` проверяет корректность сгенерированного XML
|
||||
4. `/role-info` выводит компактную сводку для визуальной проверки
|
||||
|
||||
## JSON DSL — компактный формат
|
||||
|
||||
Роли описываются в JSON с двумя уровнями детализации:
|
||||
|
||||
### Строковый shorthand (простые роли)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "ЧтениеНоменклатуры",
|
||||
"synonym": "Чтение номенклатуры",
|
||||
"objects": [
|
||||
"Catalog.Номенклатура: @view",
|
||||
"Catalog.Контрагенты: @view",
|
||||
"DataProcessor.Загрузка: @view"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Формат строки: `Тип.Имя: @пресет` или `Тип.Имя: Право1, Право2`.
|
||||
|
||||
### Объектная форма (RLS, переопределения)
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Document.Реализация",
|
||||
"preset": "view",
|
||||
"rights": { "Delete": false },
|
||||
"rls": { "Read": "#ДляОбъекта(\"\")" }
|
||||
}
|
||||
```
|
||||
|
||||
Форматы можно смешивать в одном массиве `objects`.
|
||||
|
||||
### Пресеты
|
||||
|
||||
| Пресет | Действие |
|
||||
|--------|----------|
|
||||
| `@view` | Просмотр: Read, View (+InputByString для справочников/документов; Use+View для обработок/отчётов) |
|
||||
| `@edit` | Полное редактирование: CRUD + Interactive* + Posting (для документов) |
|
||||
|
||||
`@` обязателен в строковом shorthand. В объектной форме — ключ `preset` без `@`.
|
||||
|
||||
### Русские синонимы
|
||||
|
||||
Скрипт принимает русские имена типов и прав: `Справочник` → Catalog, `Чтение` → Read, `Проведение` → Posting и т.д. Полный список — в [спецификации Role DSL](role-dsl-spec.md).
|
||||
|
||||
## Сценарии использования
|
||||
|
||||
@@ -22,15 +81,6 @@ Claude вызовет `/role-info`, получит компактную свод
|
||||
- где есть ограничения RLS
|
||||
- какие шаблоны ограничений используются
|
||||
|
||||
### Создание роли для регламентного задания
|
||||
|
||||
```
|
||||
> Проанализируй модуль регламентного задания ОбновлениеКурсовВалют
|
||||
> и создай роль с минимальными правами для его выполнения
|
||||
```
|
||||
|
||||
Claude проанализирует код, определит используемые объекты метаданных, и вызовет `/role-compile` для создания роли с нужными правами (Read, Update, Posting и т.д.).
|
||||
|
||||
### Создание роли по описанию
|
||||
|
||||
```
|
||||
@@ -41,11 +91,46 @@ Claude проанализирует код, определит использу
|
||||
> - Регистр ЦеныНоменклатуры: чтение
|
||||
```
|
||||
|
||||
Рабочий цикл:
|
||||
1. Claude генерирует `Roles/МенеджерПродаж.xml` (метаданные с UUID)
|
||||
2. Claude генерирует `Roles/МенеджерПродаж/Ext/Rights.xml` (права)
|
||||
3. Регистрирует роль в `Configuration.xml` (`<ChildObjects>`)
|
||||
4. Проверяет результат через `/role-info`
|
||||
Claude сформирует JSON с пресетами:
|
||||
```json
|
||||
{
|
||||
"name": "МенеджерПродаж",
|
||||
"synonym": "Менеджер продаж",
|
||||
"objects": [
|
||||
"Document.РеализацияТоваровУслуг: @edit",
|
||||
"Catalog.Контрагенты: @view",
|
||||
"Catalog.Номенклатура: @view",
|
||||
"InformationRegister.ЦеныНоменклатуры: @view"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
И вызовет `/role-compile` → `/role-validate` → `/role-info`.
|
||||
|
||||
### Создание роли для регламентного задания
|
||||
|
||||
```
|
||||
> Проанализируй модуль регламентного задания ОбновлениеКурсовВалют
|
||||
> и создай роль с минимальными правами для его выполнения
|
||||
```
|
||||
|
||||
Claude проанализирует код, определит используемые объекты, создаст JSON с точечными правами (без пресетов — только нужные права), и скомпилирует роль.
|
||||
|
||||
### Создание роли с RLS
|
||||
|
||||
```
|
||||
> Создай роль для чтения документов с ограничением по организации
|
||||
```
|
||||
|
||||
Claude использует объектную форму JSON с шаблонами ограничений.
|
||||
|
||||
### Проверка существующей роли
|
||||
|
||||
```
|
||||
> Проверь корректность роли Roles/МояРоль/Ext/Rights.xml
|
||||
```
|
||||
|
||||
Claude вызовет `/role-validate` и покажет результат: ошибки (невалидный XML, отсутствующие элементы) и предупреждения (неизвестные типы объектов, подозрительные имена прав с подсказками).
|
||||
|
||||
## Структура файлов роли
|
||||
|
||||
@@ -66,4 +151,5 @@ Roles/
|
||||
|
||||
## Спецификация
|
||||
|
||||
Полная спецификация формата: [1c-role-spec.md](1c-role-spec.md) — типы объектов, права, RLS, шаблоны ограничений, версии формата.
|
||||
- [1c-role-spec.md](1c-role-spec.md) — XML-формат прав роли, типы объектов, RLS, шаблоны ограничений
|
||||
- [role-dsl-spec.md](role-dsl-spec.md) — JSON DSL для описания ролей (формат входных данных `/role-compile`)
|
||||
|
||||
Reference in New Issue
Block a user