1c-meta-compile
Создать объект метаданных 1С. Используй когда пользователь просит создать или добавить справочник, документ, регистр, перечисление, константу, общий модуль, обработку, отчёт и др.
Install
npx skills add https://github.com/Desko77/claude-code-skills-1c/tree/main/skills/1c-meta-compile
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install desko77-claude-code-skills-1c@llmmart
git clone https://github.com/Desko77/claude-code-skills-1c.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole desko77/claude-code-skills-1c collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
/meta-compile - генерация объектов метаданных из JSON DSL
Принимает JSON-определение объекта метаданных → генерирует XML + модули в структуре выгрузки конфигурации + регистрирует в Configuration.xml.
Порядок работы
- Составь JSON по синтаксису и примерам ниже → запиши во временный файл
- Запусти скрипт meta-compile
- Если нужно изменить созданный объект -
/meta-edit - Если нужно проверить -
/meta-validate
Команда
powershell.exe -NoProfile -File skills/1c-meta-compile/scripts/meta-compile.ps1 -JsonPath "<json>" -OutputDir "<ConfigDir>"
| Параметр | Описание |
|---|---|
JsonPath |
Путь к JSON-файлу (один объект {...} или массив [{...}, ...]) |
OutputDir |
Корень выгрузки конфигурации (где Configuration.xml, Catalogs/, Documents/ и т.д.) |
JSON DSL
Общая структура
{ "type": "Catalog", "name": "Номенклатура", ...свойства типа... }
type и name - обязательные. synonym генерируется из name автоматически (CamelCase → слова через пробел). Можно задать явно: "synonym": "Мой синоним".
Shorthand реквизитов
Используется в attributes, dimensions, resources, tabularSections:
"ИмяРеквизита" → String(10) по умолчанию
"ИмяРеквизита: Тип" → с типом
"ИмяРеквизита: Тип | req, index" → с флагами
Типы: String(100), Number(15,2), Boolean, Date, DateTime, CatalogRef.Xxx, DocumentRef.Xxx, EnumRef.Xxx, DefinedType.Xxx и др. ссылочные.
Составной тип: "Значение: String + Number(15,2) + CatalogRef.Контрагенты".
Флаги: req, index, indexAdditional, nonneg, master, mainFilter, denyIncomplete, useInTotals.
Свойства по типам
Примеров и shorthand-синтаксиса выше достаточно для типовых задач. Если нужны свойства типа, не показанные в примерах, и их допустимые значения - см. reference-файл:
reference/types-basic.md- Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessorreference/types-registers.md- InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypesreference/types-process.md- BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournalreference/types-web.md- HTTPService, WebServicereference/types-config.md- CommonAttribute, CommonCommand, CommandGroup, CommonForm, CommonTemplate, CommonPicture, FilterCriterion, Sequence, DocumentNumerator, SessionParameter, SettingsStorage, FunctionalOption, FunctionalOptionsParameter, WSReference
Эта инструкция и reference-файлы - полная документация для генерации. Не ищи примеры XML в выгрузках конфигураций.
Примеры паттернов DSL
Минимальный объект
{ "type": "Catalog", "name": "Валюты" }
С реквизитами
{
"type": "Catalog", "name": "Организации",
"descriptionLength": 100,
"attributes": ["ИНН: String(12)", "КПП: String(9)", "Директор: CatalogRef.ФизическиеЛица"]
}
С табличной частью
{
"type": "Document", "name": "ПриходнаяНакладная",
"registerRecords": ["AccumulationRegister.ОстаткиТоваров"],
"attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"],
"tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)", "Цена: Number(15,2)"] }
}
Табличная часть задается списком колонок либо объектом, если нужен свой синоним:
"tabularSections": {
"Товары": { "synonym": "Строки заказа", "attributes": ["Номенклатура: CatalogRef.Номенклатура"] }
}
Поддержаны ключи attributes, synonym и comment. Любой другой ключ навык не применит и скажет об
этом предупреждением - молча он их больше не проглатывает.
Регистровый паттерн (измерения + ресурсы)
{
"type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day",
"dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"],
"resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"]
}
Batch - несколько объектов в одном файле
[
{ "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] },
{ "type": "Catalog", "name": "Валюты" },
{ "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" }
]
Files (claude-code-skills-1c)
-
docs
-
meta-dsl-spec.md 39.1 KB
# Meta DSL - спецификация JSON-формата для объектов метаданных 1С Версия: 2.1 ## Обзор JSON DSL для описания объектов метаданных конфигурации 1С. Компактный формат компилируется в полноценный XML, совместимый с выгрузкой конфигурации 1С:Предприятие 8.3. Поддерживаемые типы (23): **Catalog**, **Document**, **Enum**, **Constant**, **InformationRegister**, **AccumulationRegister**, **AccountingRegister**, **CalculationRegister**, **ChartOfAccounts**, **ChartOfCharacteristicTypes**, **ChartOfCalculationTypes**, **BusinessProcess**, **Task**, **ExchangePlan**, **DocumentJournal**, **Report**, **DataProcessor**, **CommonModule**, **ScheduledJob**, **EventSubscription**, **HTTPService**, **WebService**, **DefinedType**. --- ## 1. Корневая структура ```json { "type": "Catalog", "name": "Номенклатура", "synonym": "авто из name", "comment": "", ...type-specific properties..., "attributes": [...], "tabularSections": {...} } ``` | Поле | Тип | Обязательное | Описание | |------|-----|-------------|----------| | `type` | string | да | Тип объекта (см. §8) | | `name` | string | да | Имя объекта (идентификатор 1С) | | `synonym` | string | нет | Синоним; если не указан - авто из CamelCase (§2) | | `comment` | string | нет | Комментарий | Дополнительные поля зависят от типа (§7). --- ## 2. Автогенерация синонима (CamelCase → слова) Если `synonym` не указан, имя автоматически разбивается на слова: | Вход | Результат | |------|-----------| | `АвансовыйОтчет` | `Авансовый отчет` | | `ОсновнаяВалюта` | `Основная валюта` | | `НДС20` | `НДС20` | | `IncomingDocument` | `Incoming document` | Правила: - Граница на переходе `[а-яе][А-ЯЕ]` и `[a-z][A-Z]` - Первое слово сохраняет заглавную, остальные - строчные - Явный `synonym` перекрывает автогенерацию --- ## 3. Система типов Совместима с skd-compile. ### 3.1 Примитивные типы | DSL | XML | |-----|-----| | `String` или `String(100)` | `xs:string` + StringQualifiers | | `Number(15,2)` | `xs:decimal` + NumberQualifiers | | `Number(10,0,nonneg)` | `xs:decimal` + AllowedSign=Nonnegative | | `Boolean` | `xs:boolean` | | `Date` | `xs:dateTime` + DateFractions=Date | | `DateTime` | `xs:dateTime` + DateFractions=DateTime | ### 3.2 Ссылочные типы | DSL | XML | |-----|-----| | `CatalogRef.Xxx` | `cfg:CatalogRef.Xxx` | | `DocumentRef.Xxx` | `cfg:DocumentRef.Xxx` | | `EnumRef.Xxx` | `cfg:EnumRef.Xxx` | | `ChartOfAccountsRef.Xxx` | `cfg:ChartOfAccountsRef.Xxx` | | `ChartOfCharacteristicTypesRef.Xxx` | `cfg:ChartOfCharacteristicTypesRef.Xxx` | | `ChartOfCalculationTypesRef.Xxx` | `cfg:ChartOfCalculationTypesRef.Xxx` | | `ExchangePlanRef.Xxx` | `cfg:ExchangePlanRef.Xxx` | | `BusinessProcessRef.Xxx` | `cfg:BusinessProcessRef.Xxx` | | `TaskRef.Xxx` | `cfg:TaskRef.Xxx` | | `DefinedType.Xxx` | `cfg:DefinedType.Xxx` (через `v8:TypeSet`) | ### 3.3 Русские синонимы типов | Русский | Канонический | |---------|-------------| | `Строка(100)` | `String(100)` | | `Число(15,2)` | `Number(15,2)` | | `Булево` | `Boolean` | | `Дата` | `Date` | | `ДатаВремя` | `DateTime` | | `СправочникСсылка.Xxx` | `CatalogRef.Xxx` | | `ДокументСсылка.Xxx` | `DocumentRef.Xxx` | | `ПеречислениеСсылка.Xxx` | `EnumRef.Xxx` | | `ПланСчетовСсылка.Xxx` | `ChartOfAccountsRef.Xxx` | | `ПланВидовХарактеристикСсылка.Xxx` | `ChartOfCharacteristicTypesRef.Xxx` | | `ПланВидовРасчетаСсылка.Xxx` | `ChartOfCalculationTypesRef.Xxx` | | `ПланОбменаСсылка.Xxx` | `ExchangePlanRef.Xxx` | | `БизнесПроцессСсылка.Xxx` | `BusinessProcessRef.Xxx` | | `ЗадачаСсылка.Xxx` | `TaskRef.Xxx` | | `ОпределяемыйТип.Xxx` | `DefinedType.Xxx` | Регистронезависимые. --- ## 4. Сокращенная запись реквизитов ### 4.1 Строковая форма ``` "ИмяРеквизита" → String(10) по умолчанию "ИмяРеквизита: Тип" → с типом "ИмяРеквизита: Тип | req, index" → с флагами ``` ### 4.2 Объектная форма ```json { "name": "Имя", "type": "String(100)", "synonym": "Мой синоним", "comment": "Комментарий", "fillChecking": "ShowError", "indexing": "Index" } ``` Тип можно задать единой строкой (`"type": "String(100)"`) или раздельными полями: ```json { "name": "Имя", "type": "String", "length": 100 } { "name": "Сумма", "type": "Number", "length": 15, "precision": 2 } { "name": "Остаток", "type": "Number", "length": 15, "precision": 2, "nonneg": true } ``` Раздельная форма эквивалентна `String(100)`, `Number(15,2)`, `Number(15,2,nonneg)`. Если `type` уже содержит скобки - `length`/`precision` игнорируются. ### 4.3 Флаги | Флаг | Действие | Применимость | |------|---------|-------------| | `req` | FillChecking = ShowError | attributes, dimensions, resources | | `index` | Indexing = Index | attributes, dimensions | | `indexAdditional` | Indexing = IndexWithAdditionalOrder | attributes | | `multiline` | MultiLine = true | attributes | | `nonneg` | MinValue = 0 (+ nonneg для Number) | attributes, resources | | `master` | Master = true | dimensions (РС) | | `mainFilter` | MainFilter = true | dimensions (РС) | | `denyIncomplete` | DenyIncompleteValues = true | dimensions | | `useInTotals` | UseInTotals = true | dimensions (РН) | Флаги разделяются запятой после `|`. --- ## 5. Табличные части Для типов с ChildObjects → TabularSection: Catalog, Document, ExchangePlan, ChartOfCharacteristicTypes, ChartOfCalculationTypes, BusinessProcess, Task, Report, DataProcessor, ChartOfAccounts. ```json "tabularSections": { "Товары": [ "Номенклатура: CatalogRef.Номенклатура | req", "Количество: Number(10,3)", "Цена: Number(15,2)", "Сумма: Number(15,2)" ], "Услуги": [ "Описание: String(200)" ] } ``` Ключ - имя табличной части, значение - массив реквизитов (в строковой или объектной форме). Для Catalog добавляется `<Use>ForItem</Use>` в Properties табличной части. Для Document Use не применяется. --- ## 6. Значения перечислений Только для Enum. ```json "values": [ "Приход", "Расход", { "name": "НДС20", "synonym": "НДС 20%" } ] ``` Строка - имя (синоним авто из CamelCase). Объект - полная форма. --- ## 7. Свойства по типам ### 7.1 Catalog | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `hierarchical` | `false` | Hierarchical | | `hierarchyType` | `HierarchyFoldersAndItems` | HierarchyType | | `limitLevelCount` | `false` | LimitLevelCount | | `levelCount` | `2` | LevelCount | | `foldersOnTop` | `true` | FoldersOnTop | | `codeLength` | `9` | CodeLength | | `codeType` | `String` | CodeType | | `codeAllowedLength` | `Variable` | CodeAllowedLength | | `codeSeries` | `WholeCatalog` | CodeSeries | | `descriptionLength` | `25` | DescriptionLength | | `autonumbering` | `true` | Autonumbering | | `checkUnique` | `false` | CheckUnique | | `defaultPresentation` | `AsDescription` | DefaultPresentation | | `subordinationUse` | `ToItems` | SubordinationUse | | `quickChoice` | `true` | QuickChoice | | `choiceMode` | `BothWays` | ChoiceMode | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `owners` | `[]` | Owners | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | ### 7.2 Document | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `numberType` | `String` | NumberType | | `numberLength` | `11` | NumberLength | | `numberAllowedLength` | `Variable` | NumberAllowedLength | | `numberPeriodicity` | `Year` | NumberPeriodicity | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `posting` | `Allow` | Posting | | `realTimePosting` | `Deny` | RealTimePosting | | `registerRecordsDeletion` | `AutoDelete` | RegisterRecordsDeletion | | `registerRecordsWritingOnPost` | `WriteModified` | RegisterRecordsWritingOnPost | | `postInPrivilegedMode` | `true` | PostInPrivilegedMode | | `unpostInPrivilegedMode` | `true` | UnpostInPrivilegedMode | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `registerRecords` | `[]` | RegisterRecords | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | ### 7.3 Enum | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `values` | `[]` | → EnumValue в ChildObjects | Других настраиваемых свойств нет - все дефолтные. ### 7.4 Constant | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueType` | `String` | Type | | `length` | - | Длина строки (если valueType=String) | | `precision` | - | Точность числа (если valueType=Number) | | `dataLockControlMode` | `Automatic` | DataLockControlMode | `valueType` + `length`/`precision` работают аналогично раздельной форме типа (§4.2): `"valueType": "String", "length": 100` → `String(100)`. ### 7.5 InformationRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `writeMode` | `Independent` | WriteMode | | `periodicity` | `Nonperiodical` | InformationRegisterPeriodicity | | `mainFilterOnPeriod` | авто* | MainFilterOnPeriod | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `dimensions` | `[]` | → Dimension в ChildObjects | | `resources` | `[]` | → Resource в ChildObjects | | `attributes` | `[]` | → Attribute в ChildObjects | \* `mainFilterOnPeriod` = `true` если `periodicity` != `Nonperiodical`, иначе `false`. ### 7.6 AccumulationRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `registerType` | `Balance` | RegisterType | | `enableTotalsSplitting` | `true` | EnableTotalsSplitting | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `dimensions` | `[]` | → Dimension в ChildObjects | | `resources` | `[]` | → Resource в ChildObjects | | `attributes` | `[]` | → Attribute в ChildObjects | ### 7.7 DefinedType | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueTypes` | `[]` | Type (составной - массив `v8:Type`) | | `valueType` | - | Алиас для `valueTypes` (принимает строку или массив) | Без ChildObjects и модулей. Принимается как `valueTypes` (мн.ч.), так и `valueType` (ед.ч.). ```json { "type": "DefinedType", "name": "ДенежныеСредства", "valueTypes": ["CatalogRef.БанковскиеСчета", "CatalogRef.Кассы"] } { "type": "DefinedType", "name": "ФлагАктивности", "valueType": "Boolean" } ``` ### 7.8 CommonModule | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `context` | - | Шорткат (см. ниже) | | `global` | `false` | Global | | `server` | `false` | Server | | `serverCall` | `false` | ServerCall | | `clientManagedApplication` | `false` | ClientManagedApplication | | `clientOrdinaryApplication` | `false` | ClientOrdinaryApplication | | `externalConnection` | `false` | ExternalConnection | | `privileged` | `false` | Privileged | | `returnValuesReuse` | `DontUse` | ReturnValuesReuse | Шорткаты `context`: - `"server"` → Server=true, ServerCall=true - `"client"` → ClientManagedApplication=true - `"serverClient"` → Server=true, ClientManagedApplication=true Модуль: `Ext/Module.bsl` (пустой). ```json { "type": "CommonModule", "name": "ОбменДаннымиСервер", "context": "server", "returnValuesReuse": "DuringRequest" } ``` ### 7.9 ScheduledJob | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `methodName` | `""` | MethodName (авто-префикс `CommonModule.`) | | `description` | = synonym | Description | | `key` | `""` | Key | | `use` | `false` | Use | | `predefined` | `false` | Predefined | | `restartCountOnFailure` | `3` | RestartCountOnFailure | | `restartIntervalOnFailure` | `10` | RestartIntervalOnFailure | Без ChildObjects и модулей. Формат `methodName`: `"МодульСервер.Процедура"` - при компиляции авто-дополняется до `CommonModule.МодульСервер.Процедура`. Если уже содержит `CommonModule.` - оставляется как есть. ```json { "type": "ScheduledJob", "name": "ОбменДанными", "methodName": "ОбменДаннымиСервер.Выполнить", "use": true } ``` ### 7.10 EventSubscription | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `source` | `[]` | Source (массив `v8:Type`, формат `cfg:XxxObject.Name`) | | `event` | `BeforeWrite` | Event | | `handler` | `""` | Handler (авто-префикс `CommonModule.`) | Без ChildObjects и модулей. Значения `event`: `BeforeWrite`, `OnWrite`, `BeforeDelete`, `OnReadAtServer`, `FillCheckProcessing` и др. Формат `handler`: `"МодульСервер.Процедура"` - при компиляции авто-дополняется до `CommonModule.МодульСервер.Процедура`. Если уже содержит `CommonModule.` - оставляется как есть. ```json { "type": "EventSubscription", "name": "ПередЗаписьюКонтрагента", "source": ["CatalogObject.Контрагенты"], "event": "BeforeWrite", "handler": "ОбщегоНазначенияСервер.ПередЗаписьюКонтрагента" } ``` ### 7.11 Report | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `defaultForm` | `""` | DefaultForm | | `auxiliaryForm` | `""` | AuxiliaryForm | | `mainDataCompositionSchema` | `""` | MainDataCompositionSchema | | `defaultSettingsForm` | `""` | DefaultSettingsForm | | `auxiliarySettingsForm` | `""` | AuxiliarySettingsForm | | `defaultVariantForm` | `""` | DefaultVariantForm | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | Модули: `Ext/ObjectModule.bsl` (пустой). ```json { "type": "Report", "name": "ОстаткиТоваров", "attributes": ["НачалоПериода: Date", "КонецПериода: Date"] } ``` ### 7.12 DataProcessor | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `defaultForm` | `""` | DefaultForm | | `auxiliaryForm` | `""` | AuxiliaryForm | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | Модули: `Ext/ObjectModule.bsl` (пустой). ```json { "type": "DataProcessor", "name": "ЗагрузкаДанных", "attributes": ["ПутьКФайлу: String(500)"] } ``` ### 7.13 ExchangePlan | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `codeLength` | `9` | CodeLength | | `codeAllowedLength` | `Variable` | CodeAllowedLength | | `descriptionLength` | `100` | DescriptionLength | | `distributedInfoBase` | `false` | DistributedInfoBase | | `includeConfigurationExtensions` | `false` | IncludeConfigurationExtensions | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | Модули: `Ext/ObjectModule.bsl` (пустой). Дополнительно: `Ext/Content.xml` (пустой шаблон). ```json { "type": "ExchangePlan", "name": "ОбменССайтом", "attributes": ["АдресСервера: String(200)"] } ``` ### 7.14 ChartOfCharacteristicTypes | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `codeLength` | `9` | CodeLength | | `codeType` | `String` | CodeType | | `codeAllowedLength` | `Variable` | CodeAllowedLength | | `descriptionLength` | `25` | DescriptionLength | | `autonumbering` | `true` | Autonumbering | | `checkUnique` | `false` | CheckUnique | | `characteristicExtValues` | `""` | CharacteristicExtValues | | `valueTypes` | авто* | Type (составной тип значений характеристик) | | `hierarchical` | `false` | Hierarchical | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | \* Если `valueTypes` не указан, по умолчанию: Boolean, String(100), Number(15,2), DateTime. Модули: `Ext/ObjectModule.bsl` (пустой). ```json { "type": "ChartOfCharacteristicTypes", "name": "ВидыСубконто", "valueTypes": ["CatalogRef.Номенклатура", "CatalogRef.Контрагенты", "Boolean", "String", "Number(15,2)"] } ``` ### 7.15 DocumentJournal | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `defaultForm` | `""` | DefaultForm | | `auxiliaryForm` | `""` | AuxiliaryForm | | `registeredDocuments` | `[]` | RegisteredDocuments | | `columns` | `[]` | → Column в ChildObjects | Без модулей. DSL для `registeredDocuments` - массив строк `"Document.ИмяДокумента"` (или русский `"Документ.ИмяДокумента"`). DSL для `columns` (§12). ```json { "type": "DocumentJournal", "name": "Взаимодействия", "registeredDocuments": ["Document.Встреча", "Document.ТелефонныйЗвонок"], "columns": [{ "name": "Организация", "indexing": "Index", "references": ["Document.Встреча.Attribute.Организация"] }] } ``` ### 7.16 ChartOfAccounts | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `extDimensionTypes` | `""` | ExtDimensionTypes (ссылка на ПВХ) | | `maxExtDimensionCount` | `3` | MaxExtDimensionCount | | `codeMask` | `""` | CodeMask | | `codeLength` | `8` | CodeLength | | `descriptionLength` | `120` | DescriptionLength | | `codeSeries` | `WholeChartOfAccounts` | CodeSeries | | `autoOrderByCode` | `true` | AutoOrderByCode | | `orderLength` | `5` | OrderLength | | `hierarchical` | `false` | Hierarchical | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `accountingFlags` | `[]` | → AccountingFlag в ChildObjects (§13) | | `extDimensionAccountingFlags` | `[]` | → ExtDimensionAccountingFlag в ChildObjects (§14) | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | Модули: `Ext/ObjectModule.bsl` (пустой). ```json { "type": "ChartOfAccounts", "name": "Хозрасчетный", "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3, "codeMask": "@@@.@@.@", "codeLength": 8, "accountingFlags": ["Валютный", "Количественный"], "extDimensionAccountingFlags": ["Суммовой", "Валютный"] } ``` ### 7.17 AccountingRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `chartOfAccounts` | `""` | ChartOfAccounts (ссылка на план счетов) | | `correspondence` | `false` | Correspondence | | `periodAdjustmentLength` | `0` | PeriodAdjustmentLength | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `dimensions` | `[]` | → Dimension в ChildObjects | | `resources` | `[]` | → Resource в ChildObjects | | `attributes` | `[]` | → Attribute в ChildObjects | Модули: `Ext/RecordSetModule.bsl` (пустой). ```json { "type": "AccountingRegister", "name": "Хозрасчетный", "chartOfAccounts": "ChartOfAccounts.Хозрасчетный", "correspondence": true, "dimensions": ["Организация: CatalogRef.Организации"], "resources": ["Сумма: Number(15,2)"] } ``` ### 7.18 ChartOfCalculationTypes | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `codeLength` | `9` | CodeLength | | `codeType` | `String` | CodeType | | `codeAllowedLength` | `Variable` | CodeAllowedLength | | `descriptionLength` | `25` | DescriptionLength | | `autonumbering` | `true` | Autonumbering | | `checkUnique` | `false` | CheckUnique | | `dependenceOnCalculationTypes` | `NotUsed` | DependenceOnCalculationTypes | | `baseCalculationTypes` | `[]` | BaseCalculationTypes | | `actionPeriodUse` | `false` | ActionPeriodUse | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | Значения `dependenceOnCalculationTypes`: `NotUsed`, `ExclusionAndDependence`, `ExclusionOnly`. Модули: `Ext/ObjectModule.bsl` (пустой). ```json { "type": "ChartOfCalculationTypes", "name": "Начисления", "dependenceOnCalculationTypes": "ExclusionAndDependence", "actionPeriodUse": true } ``` ### 7.19 CalculationRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `chartOfCalculationTypes` | `""` | ChartOfCalculationTypes (ссылка на ПВР) | | `periodicity` | `Month` | Periodicity | | `actionPeriod` | `false` | ActionPeriod | | `basePeriod` | `false` | BasePeriod | | `schedule` | `""` | Schedule (ссылка на РС графиков) | | `scheduleValue` | `""` | ScheduleValue | | `scheduleDate` | `""` | ScheduleDate | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `dimensions` | `[]` | → Dimension в ChildObjects | | `resources` | `[]` | → Resource в ChildObjects | | `attributes` | `[]` | → Attribute в ChildObjects | Модули: `Ext/RecordSetModule.bsl` (пустой). ```json { "type": "CalculationRegister", "name": "Начисления", "chartOfCalculationTypes": "ChartOfCalculationTypes.Начисления", "periodicity": "Month", "actionPeriod": true, "basePeriod": true, "dimensions": ["Сотрудник: CatalogRef.Сотрудники"], "resources": ["Сумма: Number(15,2)", "Дни: Number(3,0)"] } ``` ### 7.20 BusinessProcess | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `editType` | `InDialog` | EditType | | `numberType` | `String` | NumberType | | `numberLength` | `11` | NumberLength | | `numberAllowedLength` | `Variable` | NumberAllowedLength | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `task` | `""` | Task (ссылка на Task.XXX) | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | Модули: `Ext/ObjectModule.bsl` (пустой). Дополнительно: `Ext/Flowchart.xml` (заглушка карты маршрута). ```json { "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] } ``` ### 7.21 Task | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `numberType` | `String` | NumberType | | `numberLength` | `14` | NumberLength | | `numberAllowedLength` | `Variable` | NumberAllowedLength | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `taskNumberAutoPrefix` | `BusinessProcessNumber` | TaskNumberAutoPrefix | | `descriptionLength` | `150` | DescriptionLength | | `addressing` | `""` | Addressing (ссылка на РС адресации) | | `mainAddressingAttribute` | `""` | MainAddressingAttribute | | `currentPerformer` | `""` | CurrentPerformer | | `dataLockControlMode` | `Automatic` | DataLockControlMode | | `fullTextSearch` | `Use` | FullTextSearch | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | | `addressingAttributes` | `[]` | → AddressingAttribute в ChildObjects (§15) | Модули: `Ext/ObjectModule.bsl` (пустой). ```json { "type": "Task", "name": "ЗадачаИсполнителя", "descriptionLength": 200, "addressing": "InformationRegister.АдресацияЗадач", "addressingAttributes": [{ "name": "Исполнитель", "type": "CatalogRef.Пользователи", "addressingDimension": "InformationRegister.АдресацияЗадач.Dimension.Исполнитель" }] } ``` ### 7.22 HTTPService | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `rootURL` | = имя (lowercase) | RootURL | | `reuseSessions` | `DontUse` | ReuseSessions | | `sessionMaxAge` | `20` | SessionMaxAge | | `urlTemplates` | `{}` | → URLTemplate в ChildObjects (§16) | Модули: `Ext/Module.bsl` (пустой). ```json { "type": "HTTPService", "name": "API", "rootURL": "api", "urlTemplates": { "Users": { "template": "/v1/users", "methods": { "Get": "GET", "Create": "POST" } } } } ``` ### 7.23 WebService | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `namespace` | `""` | Namespace | | `xdtoPackages` | `""` | XDTOPackages | | `reuseSessions` | `DontUse` | ReuseSessions | | `sessionMaxAge` | `20` | SessionMaxAge | | `operations` | `{}` | → Operation в ChildObjects (§17) | Модули: `Ext/Module.bsl` (пустой). ```json { "type": "WebService", "name": "DataExchange", "namespace": "http://www.1c.ru/DataExchange", "operations": { "TestConnection": { "returnType": "xs:boolean", "handler": "ПроверкаПодключения", "parameters": { "ErrorMessage": { "type": "xs:string", "direction": "Out" } } } } } ``` --- ## 8. Русские синонимы типов объектов | Русский | Канонический | |---------|-------------| | `Справочник` | `Catalog` | | `Документ` | `Document` | | `Перечисление` | `Enum` | | `Константа` | `Constant` | | `РегистрСведений` | `InformationRegister` | | `РегистрНакопления` | `AccumulationRegister` | | `РегистрБухгалтерии` | `AccountingRegister` | | `РегистрРасчета` | `CalculationRegister` | | `ПланСчетов` | `ChartOfAccounts` | | `ПланВидовХарактеристик` | `ChartOfCharacteristicTypes` | | `ПланВидовРасчета` | `ChartOfCalculationTypes` | | `БизнесПроцесс` | `BusinessProcess` | | `Задача` | `Task` | | `ПланОбмена` | `ExchangePlan` | | `ЖурналДокументов` | `DocumentJournal` | | `Отчет` | `Report` | | `Обработка` | `DataProcessor` | | `ОбщийМодуль` | `CommonModule` | | `РегламентноеЗадание` | `ScheduledJob` | | `ПодпискаНаСобытие` | `EventSubscription` | | `HTTPСервис` | `HTTPService` | | `ВебСервис` | `WebService` | | `ОпределяемыйТип` | `DefinedType` | --- ## 9. RegisterRecords для документов ```json "registerRecords": [ "AccumulationRegister.Продажи", "InformationRegister.Цены" ] ``` Или с русскими синонимами: `"РегистрНакопления.Продажи"`. --- ## 10. Измерения и ресурсы регистров Синтаксис аналогичен реквизитам (§4), но с дополнительными флагами: ### Измерения (dimensions) ```json "dimensions": [ "Организация: CatalogRef.Организации | master, mainFilter, denyIncomplete", "Номенклатура: CatalogRef.Номенклатура" ] ``` ### Ресурсы (resources) ```json "resources": [ "Количество: Number(15,3)", "Сумма: Number(15,2)" ] ``` Флаг `useInTotals` - только для измерений AccumulationRegister (по умолчанию `true`). Применимо к: InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister. --- ## 11. Примеры ### Минимальные ```json { "type": "Catalog", "name": "Валюты" } ``` ```json { "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] } ``` ```json { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" } ``` ### Справочник с реквизитами и табличной частью ```json { "type": "Catalog", "name": "Номенклатура", "codeLength": 11, "descriptionLength": 100, "hierarchical": true, "attributes": [ "Артикул: String(25)", "ЕдиницаИзмерения: CatalogRef.ЕдиницыИзмерения | req", "ВидНоменклатуры: EnumRef.ВидыНоменклатуры", "Цена: Number(15,2)" ], "tabularSections": { "Штрихкоды": [ "Штрихкод: String(200) | req, index" ] } } ``` ### Документ с движениями ```json { "type": "Document", "name": "РеализацияТоваров", "posting": "Allow", "registerRecords": ["AccumulationRegister.Продажи"], "attributes": [ "Организация: CatalogRef.Организации | req", "Контрагент: CatalogRef.Контрагенты | req", "Склад: CatalogRef.Склады" ], "tabularSections": { "Товары": [ "Номенклатура: CatalogRef.Номенклатура | req", "Количество: Number(15,3)", "Цена: Number(15,2)", "Сумма: Number(15,2)" ] } } ``` ### Регистр сведений с периодичностью ```json { "type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day", "dimensions": [ "Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete" ], "resources": [ "Курс: Number(15,4)", "Кратность: Number(10,0)" ] } ``` ### Регистр накопления ```json { "type": "AccumulationRegister", "name": "ОстаткиТоваров", "registerType": "Balance", "dimensions": [ "Номенклатура: CatalogRef.Номенклатура", "Склад: CatalogRef.Склады" ], "resources": [ "Количество: Number(15,3)" ] } ``` ### Определяемый тип ```json { "type": "DefinedType", "name": "ДенежныеСредства", "valueTypes": ["CatalogRef.БанковскиеСчета", "CatalogRef.Кассы"] } ``` ### Общий модуль ```json { "type": "CommonModule", "name": "ОбменДаннымиСервер", "context": "server", "returnValuesReuse": "DuringRequest" } ``` ### План обмена ```json { "type": "ExchangePlan", "name": "ОбменССайтом", "attributes": ["АдресСервера: String(200)"] } ``` ### Журнал документов ```json { "type": "DocumentJournal", "name": "Взаимодействия", "registeredDocuments": ["Document.Встреча", "Document.ТелефонныйЗвонок"], "columns": [{ "name": "Организация", "indexing": "Index", "references": ["Document.Встреча.Attribute.Организация"] }] } ``` ### План счетов ```json { "type": "ChartOfAccounts", "name": "Хозрасчетный", "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3, "codeMask": "@@@.@@.@", "codeLength": 8, "accountingFlags": ["Валютный", "Количественный"], "extDimensionAccountingFlags": ["Суммовой", "Валютный"] } ``` ### HTTP-сервис ```json { "type": "HTTPService", "name": "API", "rootURL": "api", "urlTemplates": { "Users": { "template": "/v1/users", "methods": { "Get": "GET", "Create": "POST" } } } } ``` ### Веб-сервис ```json { "type": "WebService", "name": "DataExchange", "namespace": "http://www.1c.ru/DataExchange", "operations": { "TestConnection": { "returnType": "xs:boolean", "handler": "ПроверкаПодключения", "parameters": { "ErrorMessage": { "type": "xs:string", "direction": "Out" } } } } } ``` ### Бизнес-процесс ```json { "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] } ``` ### Задача ```json { "type": "Task", "name": "ЗадачаИсполнителя", "descriptionLength": 200, "addressing": "InformationRegister.АдресацияЗадач", "addressingAttributes": [{ "name": "Исполнитель", "type": "CatalogRef.Пользователи" }] } ``` --- ## 12. Графы журнала документов (columns) Только для DocumentJournal. ### Строковая форма ```json "columns": ["Организация", "Контрагент"] ``` Создает графу без ссылок, без индексации. ### Объектная форма ```json "columns": [ { "name": "Организация", "synonym": "Организация", "indexing": "Index", "references": [ "Document.Встреча.Attribute.Организация", "Document.ТелефонныйЗвонок.Attribute.Организация" ] } ] ``` | Поле | Умолчание | Описание | |------|----------|----------| | `name` | - | Имя графы (обязательное) | | `synonym` | авто | Синоним | | `indexing` | `DontIndex` | `DontIndex` / `Index` | | `references` | `[]` | Ссылки на реквизиты регистрируемых документов | --- ## 13. Признаки учета (accountingFlags) Только для ChartOfAccounts. ```json "accountingFlags": ["Валютный", "Количественный"] ``` Массив имен. Каждый признак - Boolean-тип. Синоним авто из CamelCase. --- ## 14. Признаки учета субконто (extDimensionAccountingFlags) Только для ChartOfAccounts. ```json "extDimensionAccountingFlags": ["Суммовой", "Валютный"] ``` Аналогично accountingFlags, но применяется к субконто (ExtDimensionTypes). --- ## 15. Реквизиты адресации (addressingAttributes) Только для Task. ### Строковая форма ```json "addressingAttributes": ["Исполнитель"] ``` ### Объектная форма ```json "addressingAttributes": [ { "name": "Исполнитель", "type": "CatalogRef.Пользователи", "addressingDimension": "InformationRegister.АдресацияЗадач.Dimension.Исполнитель" } ] ``` | Поле | Умолчание | Описание | |------|----------|----------| | `name` | - | Имя реквизита (обязательное) | | `type` | `String` | Тип значения | | `synonym` | авто | Синоним | | `addressingDimension` | `""` | Ссылка на измерение регистра адресации | --- ## 16. URL-шаблоны HTTP-сервиса (urlTemplates) Только для HTTPService. ```json "urlTemplates": { "Users": { "template": "/v1/users", "methods": { "Get": "GET", "Create": "POST" } } } ``` Ключ - имя шаблона. Значение - объект: | Поле | Умолчание | Описание | |------|----------|----------| | `template` | `/{name}` | URL-шаблон (строка) | | `methods` | `{}` | Имя метода → HTTP-метод (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) | Обработчик метода авто: `{TemplateName}{MethodName}` (напр. `UsersGet`). Если значение - строка, интерпретируется как `template` без методов. --- ## 17. Операции веб-сервиса (operations) Только для WebService. ```json "operations": { "TestConnection": { "returnType": "xs:boolean", "handler": "ПроверкаПодключения", "nillable": false, "transactioned": false, "parameters": { "ErrorMessage": { "type": "xs:string", "nillable": true, "direction": "Out" } } } } ``` Ключ - имя операции. Значение - объект: | Поле | Умолчание | Описание | |------|----------|----------| | `returnType` | `xs:string` | XDTO-тип возвращаемого значения | | `handler` | = имя операции | Имя процедуры-обработчика | | `nillable` | `false` | Может ли возвращать null | | `transactioned` | `false` | Выполняется в транзакции | | `parameters` | `{}` | Параметры операции | Если значение - строка, интерпретируется как `returnType`. ### Параметры операции | Поле | Умолчание | Описание | |------|----------|----------| | `type` | `xs:string` | XDTO-тип параметра | | `nillable` | `true` | Может ли быть null | | `direction` | `In` | Направление: `In` / `Out` / `InOut` | Если значение - строка, интерпретируется как `type`.
-
-
evals
-
evals.json 3.4 KB
{ "skill_name": "1c-meta-compile", "evals": [ { "id": 1, "prompt": "Создай справочник Контрагенты с реквизитами ИНН (строка 12), КПП (строка 9), ЮридическийАдрес (строка 255). Выгрузка конфигурации в папке src/.", "expected_output": "В папке src/Catalogs/Контрагенты/ созданы XML-файлы (Catalog.xml, Ext/ObjectModule.bsl и др.), справочник зарегистрирован в src/Configuration.xml.", "expectations": [ "Скрипт meta-compile.ps1 вызван с параметрами -JsonPath и -OutputDir", "Создана папка Catalogs/Контрагенты/ (или аналогичное имя)", "Файл Catalog.xml содержит элемент с именем Контрагенты", "Реквизит ИНН присутствует в XML-определении объекта", "Справочник добавлен в Configuration.xml" ] }, { "id": 2, "prompt": "Добавь документ ПоступлениеТоваров с шапочными реквизитами Склад (ссылка на справочник Склады) и Контрагент (ссылка на справочник Контрагенты), и табличной частью Товары с реквизитами Номенклатура, Количество (число 15,3), Цена (число 15,2), Сумма (число 15,2). Выгрузка в D:/Config/src/.", "expected_output": "В D:/Config/src/Documents/ПоступлениеТоваров/ созданы файлы документа, включая XML с описанием табличной части Товары и реквизитами.", "expectations": [ "Скрипт meta-compile.ps1 вызван с корректным путём к OutputDir", "Создана папка Documents/ПоступлениеТоваров/", "Document.xml содержит определение табличной части Товары", "Реквизиты Количество и Цена определены с числовым типом", "Документ зарегистрирован в Configuration.xml" ] }, { "id": 3, "prompt": "Создай регистр сведений КурсыВалют с измерением Валюта (ссылка на справочник Валюты), измерением Период (дата) и ресурсом Курс (число 15,4). Без регистратора, периодичность — по позиции регистратора. Конфигурация в C:/Projects/Erp/src/.", "expected_output": "В C:/Projects/Erp/src/InformationRegisters/КурсыВалют/ созданы файлы регистра сведений.", "expectations": [ "Скрипт meta-compile.ps1 вызван с типом объекта InformationRegister или регистр сведений", "Создана папка InformationRegisters/КурсыВалют/", "Измерение Валюта определено в XML-файле", "Ресурс Курс определён с числовым типом", "Регистр добавлен в Configuration.xml" ] } ] }
-
-
reference
-
types-basic.md 4.5 KB
# Базовые типы: Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor ## Catalog | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `hierarchical` | `false` | Hierarchical | | `hierarchyType` | `HierarchyFoldersAndItems` | HierarchyType | | `limitLevelCount` | `false` | LimitLevelCount | | `levelCount` | `2` | LevelCount | | `foldersOnTop` | `true` | FoldersOnTop | | `codeLength` | `9` | CodeLength | | `codeType` | `String` | CodeType | | `codeAllowedLength` | `Variable` | CodeAllowedLength | | `codeSeries` | `WholeCatalog` | CodeSeries | | `descriptionLength` | `25` | DescriptionLength | | `autonumbering` | `true` | Autonumbering | | `checkUnique` | `false` | CheckUnique | | `defaultPresentation` | `AsDescription` | DefaultPresentation | | `subordinationUse` | `ToItems` | SubordinationUse | | `quickChoice` | `true` | QuickChoice | | `choiceMode` | `BothWays` | ChoiceMode | | `owners` | `[]` | Owners | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | ```json { "type": "Catalog", "name": "Организации", "attributes": ["ИНН: String(12)", "КПП: String(9)"] } ``` ## Document | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `numberType` | `String` | NumberType | | `numberLength` | `11` | NumberLength | | `numberAllowedLength` | `Variable` | NumberAllowedLength | | `numberPeriodicity` | `Year` | NumberPeriodicity | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `posting` | `Allow` | Posting | | `realTimePosting` | `Deny` | RealTimePosting | | `registerRecordsDeletion` | `AutoDelete` | RegisterRecordsDeletion | | `registerRecordsWritingOnPost` | `WriteModified` | RegisterRecordsWritingOnPost | | `postInPrivilegedMode` | `true` | PostInPrivilegedMode | | `unpostInPrivilegedMode` | `true` | UnpostInPrivilegedMode | | `registerRecords` | `[]` | RegisterRecords | | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | RegisterRecords - массив строк: `"AccumulationRegister.Продажи"`, `"InformationRegister.Цены"`. ```json { "type": "Document", "name": "ПриходнаяНакладная", "registerRecords": ["AccumulationRegister.ОстаткиТоваров"], "attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"], "tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)"] } } ``` ## Enum | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `values` | `[]` | → EnumValue в ChildObjects | ```json { "type": "Enum", "name": "Статусы", "values": ["Новый", "ВРаботе", "Закрыт"] } ``` ## Constant | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueType` | `String` | Type | `valueType` принимает shorthand типа: `"String(100)"`, `"Number(15,2)"`, `"Boolean"`, `"CatalogRef.Валюты"`. ```json { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" } ``` ## DefinedType | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueTypes` | `[]` | Type (составной тип) | | `valueType` | - | Алиас для `valueTypes` (строка или массив) | ```json { "type": "DefinedType", "name": "ДенежныеСредства", "valueTypes": ["CatalogRef.БанковскиеСчета", "CatalogRef.Кассы"] } { "type": "DefinedType", "name": "ФлагАктивности", "valueType": "Boolean" } ``` ## Report | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | ```json { "type": "Report", "name": "ОстаткиТоваров" } ``` ## DataProcessor | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `attributes` | `[]` | → Attribute в ChildObjects | | `tabularSections` | `{}` | → TabularSection в ChildObjects | ```json { "type": "DataProcessor", "name": "ЗагрузкаДанных", "attributes": ["ПутьКФайлу: String(500)"] } ``` -
types-config.md 8.5 KB
# Конфигурационные объекты без собственных данных Объекты, которые не хранят свои таблицы, а настраивают поведение конфигурации: общие реквизиты, команды, формы, макеты, картинки, критерии отбора, последовательности, нумераторы, параметры сеанса, хранилища настроек, функциональные опции и WS-ссылки. Общее для всех: `name` обязателен, `synonym` по умолчанию выводится из имени, `comment` пишется как задан. ## Ссылки на метаданные Поля состава (`content`, `documents`, `use`, `documentMap`, `location` и подобные) принимают путь к метаданным на русском или английском вперемешку - вид объекта переводится, имя остается как написано: ``` "Документ.РеализацияТоваров.Реквизит.Склад" -> Document.РеализацияТоваров.Attribute.Склад "РегистрСведений.Настройки.Измерение.Организация" -> InformationRegister.Настройки.Dimension.Организация ``` Переводятся виды объектов (`Документ`, `Справочник`, `РегистрНакопления`, ...) и виды подчиненных элементов: `Реквизит` -> Attribute, `ТабличнаяЧасть` -> TabularSection, `Измерение` -> Dimension, `Ресурс` -> Resource, `Графа` -> Column, `ЗначениеПеречисления` -> EnumValue, `Форма` -> Form, `Макет` -> Template, `Команда` -> Command, `ПризнакУчета` -> AccountingFlag, `ПризнакУчетаСубконто` -> ExtDimensionAccountingFlag, `РеквизитАдресации` -> AddressingAttribute. ## CommonAttribute (Общий реквизит) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueType` | - | Type | | `content` | `[]` | Content | | `autoUse` | `DontUse` | AutoUse | | `indexing` | `DontIndex` | Indexing | | `fullTextSearch` | `Use` | FullTextSearch | | `dataHistory` | `Use` | DataHistory | `content` - массив, элемент строкой (`"Документ.РеализацияТоваров"`) или объектом `{ "metadata": "...", "use": "Use" }`. Без `use` подставляется `Use`. ```json { "type": "CommonAttribute", "name": "Организация", "valueType": "CatalogRef.Организации", "autoUse": "Use", "content": [ { "metadata": "Документ.РеализацияТоваров", "use": "Use" }, "Документ.ПоступлениеТоваров" ] } ``` ## CommonCommand (Общая команда) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `group` | пусто | Group | | `commandParameterType` | пусто | CommandParameterType | | `parameterUseMode` | `Single` | ParameterUseMode | | `modifiesData` | `false` | ModifiesData | | `representation` | `Auto` | Representation | | `picture` | пусто | Picture | Модули: `Ext/CommandModule.bsl` (создается пустым, обработчик пишется отдельно). ## CommandGroup (Группа команд) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `representation` | `Auto` | Representation | | `category` | `FormCommandBar` | Category | | `picture` | пусто | Picture | `picture` - строка `"CommonPicture.Логотип"` либо объект `{ "src": "CommonPicture.Логотип", "loadTransparent": false }`. ## CommonForm (Общая форма) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `formType` | `Managed` | FormType | | `usePurposes` | `["PlatformApplication"]` | UsePurposes | | `useStandardCommands` | `false` | UseStandardCommands | Создает заготовку формы `Ext/Form.xml` (пустая командная панель и пустые элементы) и модуль `Ext/Form/Module.bsl`. Наполнение формы - навык `1c-form-compile`. ## CommonTemplate (Общий макет) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `templateType` | `SpreadsheetDocument` | TemplateType | Пишутся только метаданные макета. Содержимое макета - навыки `1c-mxl-compile` (табличный документ) и `1c-skd-compile` (схема компоновки). ## CommonPicture (Общая картинка) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `availabilityForChoice` | `false` | AvailabilityForChoice | | `availabilityForAppearance` | `false` | AvailabilityForAppearance | Файл самой картинки не создается - его кладут в `Ext/Picture` отдельно. ## FilterCriterion (Критерий отбора) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueType` | - | Type | | `useStandardCommands` | `true` | UseStandardCommands | | `content` | `[]` | Content | ## Sequence (Последовательность) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `documents` | `[]` | Documents | | `registerRecords` | `[]` | RegisterRecords | | `moveBoundaryOnPosting` | `DontMove` | MoveBoundaryOnPosting | | `dataLockControlMode` | `Managed` | DataLockControlMode | | `dimensions` | `[]` | → Dimension | Измерение: `{ "name": "...", "type": "CatalogRef.X", "documentMap": [...], "registerRecordsMap": [...] }`. `documentMap` перечисляет реквизиты документов, откуда берется значение измерения. ```json { "type": "Sequence", "name": "ВзаиморасчетыСКонтрагентами", "documents": ["Документ.ПоступлениеТоваров", "Document.РеализацияТоваров"], "dimensions": [{ "name": "Организация", "type": "CatalogRef.Организации", "documentMap": ["Документ.ПоступлениеТоваров.Реквизит.Организация"] }] } ``` ## DocumentNumerator (Нумератор документов) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `numberType` | `String` | NumberType | | `numberLength` | `9` | NumberLength | | `numberAllowedLength` | `Variable` | NumberAllowedLength | | `numberPeriodicity` | `Year` | NumberPeriodicity | | `checkUnique` | `true` | CheckUnique | ## SessionParameter (Параметр сеанса) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `valueType` | - | Type | Составной тип - через `+`: `"CatalogRef.Пользователи + CatalogRef.ВнешниеПользователи"`. ## SettingsStorage (Хранилище настроек) Своих полей нет: только имя, синоним и комментарий. Формы сохранения и загрузки остаются пустыми. ## FunctionalOption (Функциональная опция) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `location` | пусто | Location | | `privilegedGetMode` | `true` | PrivilegedGetMode | | `content` | `[]` | Content | `location` - где хранится значение опции: константа или реквизит (`"Constant.ВестиУчетПоСкладам"`). ## FunctionalOptionsParameter (Параметр функциональных опций) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `use` | `[]` | Use | `use` - измерения регистров, по которым параметризуется опция. ## WSReference (WS-ссылка) | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `locationURL` | пусто | LocationURL | Адрес WSDL. Сам WSDL не скачивается и не разбирается. -
types-process.md 5.5 KB
# Процессы и сервисные: BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal ## BusinessProcess | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `task` | `""` | Task (ссылка `Task.XXX`) | | `numberType` | `String` | NumberType | | `numberLength` | `11` | NumberLength | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `attributes` | `[]` | → Attribute | | `tabularSections` | `{}` | → TabularSection | Модули: `Ext/ObjectModule.bsl`, `Ext/Flowchart.xml`. ```json { "type": "BusinessProcess", "name": "Задание", "task": "Task.ЗадачаИсполнителя", "attributes": ["Описание: String(200)"] } ``` ## Task | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `numberType` | `String` | NumberType | | `numberLength` | `14` | NumberLength | | `checkUnique` | `true` | CheckUnique | | `autonumbering` | `true` | Autonumbering | | `descriptionLength` | `150` | DescriptionLength | | `addressing` | `""` | Addressing (ссылка на РС адресации) | | `mainAddressingAttribute` | `""` | MainAddressingAttribute | | `currentPerformer` | `""` | CurrentPerformer | | `attributes` | `[]` | → Attribute | | `tabularSections` | `{}` | → TabularSection | | `addressingAttributes` | `[]` | → AddressingAttribute (shorthand или объект) | AddressingAttribute - shorthand `"Имя: Тип"` или объект `{ "name", "type", "addressingDimension" }`. ```json { "type": "Task", "name": "ЗадачаИсполнителя", "addressingAttributes": ["Исполнитель: CatalogRef.Пользователи"] } ``` ## ExchangePlan | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `codeLength` | `9` | CodeLength | | `descriptionLength` | `100` | DescriptionLength | | `distributedInfoBase` | `false` | DistributedInfoBase | | `attributes` | `[]` | → Attribute | | `tabularSections` | `{}` | → TabularSection | Модули: `Ext/ObjectModule.bsl`, `Ext/Content.xml`. ```json { "type": "ExchangePlan", "name": "ОбменССайтом", "attributes": ["АдресСервера: String(200)"] } ``` ## CommonModule | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `context` | - | Шорткат (см. ниже) | | `global` | `false` | Global | | `server` | `false` | Server | | `serverCall` | `false` | ServerCall | | `clientManagedApplication` | `false` | ClientManagedApplication | | `externalConnection` | `false` | ExternalConnection | | `privileged` | `false` | Privileged | | `returnValuesReuse` | `DontUse` | ReturnValuesReuse | Шорткаты `context`: `"server"` → Server+ServerCall, `"client"` → ClientManagedApplication, `"serverClient"` → Server+ClientManagedApplication. ```json { "type": "CommonModule", "name": "ОбщиеФункции", "context": "serverClient" } ``` ## ScheduledJob | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `methodName` | `""` | MethodName | | `description` | = synonym | Description | | `use` | `false` | Use | | `predefined` | `false` | Predefined | | `restartCountOnFailure` | `3` | RestartCountOnFailure | | `restartIntervalOnFailure` | `10` | RestartIntervalOnFailure | Формат `methodName`: `"МодульСервер.Процедура"` - авто-дополняется до `CommonModule.МодульСервер.Процедура`. ```json { "type": "ScheduledJob", "name": "ОбменДанными", "methodName": "ОбменДаннымиСервер.Выполнить" } ``` ## EventSubscription | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `source` | `[]` | Source (массив, формат `XxxObject.Name`) | | `event` | `BeforeWrite` | Event | | `handler` | `""` | Handler | Формат `handler`: `"МодульСервер.Процедура"` - авто-дополняется до `CommonModule.МодульСервер.Процедура`. Значения `event`: `BeforeWrite`, `OnWrite`, `BeforeDelete`, `OnReadAtServer`, `FillCheckProcessing`. Формат `source`: `"CatalogObject.Xxx"`, `"DocumentObject.Xxx"`. ```json { "type": "EventSubscription", "name": "ПередЗаписью", "source": ["CatalogObject.Контрагенты"], "event": "BeforeWrite", "handler": "ОбщиеФункции.ПередЗаписью" } ``` ## DocumentJournal | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `registeredDocuments` | `[]` | RegisteredDocuments (массив `"Document.Xxx"`) | | `columns` | `[]` | → Column | Колонки - строка `"Имя"` или объект `{ "name", "synonym", "indexing": "Index"/"DontIndex", "references": ["Document.Xxx.Attribute.Yyy"] }`. ```json { "type": "DocumentJournal", "name": "Взаимодействия", "registeredDocuments": ["Document.Встреча", "Document.Звонок"], "columns": [{ "name": "Организация", "indexing": "Index", "references": ["Document.Встреча.Attribute.Организация"] }] } ``` ## Зависимости - **ScheduledJob/EventSubscription** - процедура-обработчик должна существовать в модуле (экспортная) - **BusinessProcess** → `Task` (задача должна существовать) -
types-registers.md 7.4 KB
# Регистры и планы: InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes ## Измерения и ресурсы (общее) Синтаксис аналогичен реквизитам (shorthand `"Имя: Тип | флаги"`). Флаги измерений: `master`, `mainFilter`, `denyIncomplete`, `useInTotals` (AccumulationRegister only, default `true`). ```json "dimensions": ["Организация: CatalogRef.Организации | master, mainFilter, denyIncomplete"], "resources": ["Сумма: Number(15,2)"] ``` --- ## InformationRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `writeMode` | `Independent` | WriteMode | | `periodicity` | `Nonperiodical` | InformationRegisterPeriodicity | | `mainFilterOnPeriod` | авто* | MainFilterOnPeriod | | `dimensions` | `[]` | → Dimension | | `resources` | `[]` | → Resource | | `attributes` | `[]` | → Attribute | \* `mainFilterOnPeriod` = `true` если `periodicity` != `Nonperiodical`. ```json { "type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day", "dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"], "resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"] } ``` ## AccumulationRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `registerType` | `Balance` | RegisterType (`Balance` / `Turnovers`) | | `enableTotalsSplitting` | `true` | EnableTotalsSplitting | | `dimensions` | `[]` | → Dimension | | `resources` | `[]` | → Resource | | `attributes` | `[]` | → Attribute | ```json { "type": "AccumulationRegister", "name": "ОстаткиТоваров", "registerType": "Balance", "dimensions": ["Номенклатура: CatalogRef.Номенклатура"], "resources": ["Количество: Number(15,3)"] } ``` ## AccountingRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `chartOfAccounts` | `""` | ChartOfAccounts (**обязательная** ссылка на план счетов) | | `correspondence` | `false` | Correspondence | | `periodAdjustmentLength` | `0` | PeriodAdjustmentLength | | `dimensions` | `[]` | → Dimension | | `resources` | `[]` | → Resource | | `attributes` | `[]` | → Attribute | ```json { "type": "AccountingRegister", "name": "Хозрасчетный", "chartOfAccounts": "ChartOfAccounts.Хозрасчетный", "dimensions": ["Организация: CatalogRef.Организации"], "resources": ["Сумма: Number(15,2)"] } ``` ## CalculationRegister | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `chartOfCalculationTypes` | `""` | ChartOfCalculationTypes (**обязательная** ссылка на ПВР) | | `periodicity` | `Month` | Periodicity | | `actionPeriod` | `false` | ActionPeriod | | `basePeriod` | `false` | BasePeriod | | `schedule` | `""` | Schedule (ссылка на РС графиков) | | `dimensions` | `[]` | → Dimension | | `resources` | `[]` | → Resource | | `attributes` | `[]` | → Attribute | ```json { "type": "CalculationRegister", "name": "Начисления", "chartOfCalculationTypes": "ChartOfCalculationTypes.Начисления", "periodicity": "Month", "dimensions": ["Сотрудник: CatalogRef.Сотрудники"], "resources": ["Сумма: Number(15,2)"] } ``` --- ## ChartOfCharacteristicTypes | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `codeLength` | `9` | CodeLength | | `descriptionLength` | `25` | DescriptionLength | | `autonumbering` | `true` | Autonumbering | | `checkUnique` | `false` | CheckUnique | | `characteristicExtValues` | `""` | CharacteristicExtValues | | `valueTypes` | авто* | Type (составной тип значений характеристик) | | `hierarchical` | `false` | Hierarchical | | `attributes` | `[]` | → Attribute | | `tabularSections` | `{}` | → TabularSection | \* По умолчанию: Boolean, String(100), Number(15,2), DateTime. ```json { "type": "ChartOfCharacteristicTypes", "name": "ВидыСубконто", "valueTypes": ["CatalogRef.Номенклатура", "CatalogRef.Контрагенты", "Boolean", "String", "Number(15,2)"] } ``` ## ChartOfAccounts | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `extDimensionTypes` | `""` | ExtDimensionTypes (ссылка на ПВХ) | | `maxExtDimensionCount` | `3` с ПВХ, иначе `0` | MaxExtDimensionCount | | `codeMask` | `""` | CodeMask | | `codeLength` | `8` | CodeLength | | `descriptionLength` | `120` | DescriptionLength | | `codeSeries` | `WholeChartOfAccounts` | CodeSeries | | `autoOrderByCode` | `true` | AutoOrderByCode | | `orderLength` | `5` | OrderLength | | `hierarchical` | `false` | Hierarchical | | `accountingFlags` | `[]` | → AccountingFlag (Boolean-тип, массив имен) | | `extDimensionAccountingFlags` | `[]` | → ExtDimensionAccountingFlag (Boolean-тип, массив имен) | | `attributes` | `[]` | → Attribute | | `tabularSections` | `{}` | → TabularSection | **Субконто идут парой.** Ненулевой `maxExtDimensionCount` без `extDimensionTypes` дает объект, который платформа отказывается грузить: "У плана счетов с количеством субконто не равным 0 должен быть установлен план видов характеристик". Поэтому без ссылки на ПВХ счетчик по умолчанию 0, а если выставить его руками - навык предупредит. План счетов без субконто законен, это просто другой план. ```json { "type": "ChartOfAccounts", "name": "Хозрасчетный", "extDimensionTypes": "ChartOfCharacteristicTypes.ВидыСубконто", "maxExtDimensionCount": 3, "codeLength": 8, "codeMask": "@@@.@@.@", "accountingFlags": ["Валютный", "Количественный"], "extDimensionAccountingFlags": ["Суммовой", "Валютный"] } ``` ## ChartOfCalculationTypes | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `codeLength` | `9` | CodeLength | | `descriptionLength` | `25` | DescriptionLength | | `autonumbering` | `true` | Autonumbering | | `checkUnique` | `false` | CheckUnique | | `dependenceOnCalculationTypes` | `DontUse` | DependenceOnCalculationTypes | | `actionPeriodUse` | `false` | ActionPeriodUse | | `attributes` | `[]` | → Attribute | | `tabularSections` | `{}` | → TabularSection | `dependenceOnCalculationTypes`: `DontUse`, `OnActionPeriod`. ```json { "type": "ChartOfCalculationTypes", "name": "Начисления", "dependenceOnCalculationTypes": "OnActionPeriod" } ``` ## Зависимости - **AccountingRegister** требует `ChartOfAccounts` (и документ-регистратор) - **CalculationRegister** требует `ChartOfCalculationTypes` (и документ-регистратор) - **ChartOfAccounts** ссылается на `ChartOfCharacteristicTypes` через `extDimensionTypes` -
types-web.md 3.5 KB
# Веб-сервисы: HTTPService, WebService ## HTTPService | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `rootURL` | `= name.toLower()` | RootURL | | `reuseSessions` | `DontUse` | ReuseSessions | | `sessionMaxAge` | `20` | SessionMaxAge | | `urlTemplates` | `{}` | → URLTemplate | Модули: `Ext/Module.bsl`. ### urlTemplates - вложенная структура `urlTemplates` - объект `{ "TemplateName": templateDef, ... }`. Каждый `templateDef`: - Строка - URL-шаблон: `"/v1/users"` (без методов) - Объект: | Поле | Умолчание | Описание | |------|----------|----------| | `template` | `"/templatename"` | URL-путь (с параметрами `{id}`) | | `methods` | `{}` | Методы: `{ "MethodName": "HTTPMethod" }` | Допустимые HTTPMethod: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`, `CONNECT`, `TRACE`, `MERGE`. Обработчик метода генерируется автоматически: `{TemplateName}{MethodName}` - должен быть реализован в `Ext/Module.bsl`. ```json { "type": "HTTPService", "name": "API", "rootURL": "api", "urlTemplates": { "Users": { "template": "/v1/users/{id}", "methods": { "Get": "GET", "Create": "POST", "Update": "PUT", "Delete": "DELETE" } }, "Health": "/health" } } ``` ## WebService | Поле JSON | Умолчание | XML элемент | |-----------|----------|-------------| | `namespace` | `""` | Namespace (URI пространства имен WSDL) | | `xdtoPackages` | `""` | XDTOPackages | | `reuseSessions` | `DontUse` | ReuseSessions | | `sessionMaxAge` | `20` | SessionMaxAge | | `operations` | `{}` | → Operation | Модули: `Ext/Module.bsl`. ### operations - вложенная структура `operations` - объект `{ "OperationName": operationDef, ... }`. Каждый `operationDef`: - Строка - тип возврата: `"xs:boolean"` (параметров нет, обработчик = имя операции) - Объект: | Поле | Умолчание | Описание | |------|----------|----------| | `returnType` | `xs:string` | XDTO-тип возврата | | `nillable` | `false` | Может ли вернуть null | | `transactioned` | `false` | Выполнять в транзакции | | `handler` | `= operationName` | Имя процедуры в модуле | | `parameters` | `{}` | Параметры операции | ### parameters - параметры операции `parameters` - объект `{ "ParamName": paramDef, ... }`. Каждый `paramDef`: - Строка - XDTO-тип: `"xs:string"` (direction = In, nillable = true) - Объект: | Поле | Умолчание | Описание | |------|----------|----------| | `type` | `xs:string` | XDTO-тип параметра | | `nillable` | `true` | Может ли быть null | | `direction` | `In` | Направление: `In`, `Out`, `InOut` | Стандартные XDTO-типы: `xs:string`, `xs:boolean`, `xs:int`, `xs:long`, `xs:decimal`, `xs:dateTime`, `xs:base64Binary`. ```json { "type": "WebService", "name": "DataExchange", "namespace": "http://www.1c.ru/DataExchange", "operations": { "TestConnection": { "returnType": "xs:boolean", "handler": "ПроверкаПодключения", "parameters": { "ErrorMessage": { "type": "xs:string", "direction": "Out" } } }, "GetVersion": "xs:string" } } ```
-
-
scripts
-
meta-compile.ps1 186.9 KB · in bundle
-
meta-compile.py 195.2 KB
#!/usr/bin/env python3 # meta-compile v1.10 - Compile 1C metadata object from JSON # Source: https://github.com/Desko77/claude-code-skills-1c import argparse import json import os import re import subprocess import sys import tempfile import uuid import xml.etree.ElementTree as ET # ============================================================ # Support guard (Ext/ParentConfigurations.bin) - see docs/1c-support-state-spec.md # Blocks edits of vendor objects "на замке" / read-only configs. Trigger = bin # present; reaction from .v8-project.json editingAllowedCheck (deny|warn|off, # default deny). Never throws (except sys.exit on deny) - errors degrade to allow. # ============================================================ def _sg_parse(xml_path): """Разбор XML средствами стандартной библиотеки. Свой, а не разбор скила: одни порты работают через lxml, другие XML не разбирают вовсе, и обращение к чужому имени попадало в общий except ниже - гард молча разрешал правку. """ from xml.etree import ElementTree as _sg_et return _sg_et.parse(xml_path).getroot() def _sg_root_uuid(xml_path): if not os.path.isfile(xml_path): return None try: mx = _sg_parse(xml_path) for child in mx: if isinstance(child.tag, str) and child.get("uuid"): return child.get("uuid") except Exception: return None return None def _sg_is_external_root(xml_path): if not os.path.isfile(xml_path): return False try: mx = _sg_parse(xml_path) for child in mx: if isinstance(child.tag, str): return child.tag.split("}")[-1] in ("ExternalDataProcessor", "ExternalReport") except Exception: return False return False def _sg_find_v8project(start_dir): d = start_dir for _ in range(20): if not d: break pj = os.path.join(d, ".v8-project.json") if os.path.isfile(pj): return pj parent = os.path.dirname(d) if parent == d: break d = parent return None def _sg_get_edit_mode(cfg_dir): try: pj = _sg_find_v8project(os.getcwd()) or _sg_find_v8project(cfg_dir) if not pj: return "deny" proj = json.loads(open(pj, encoding="utf-8-sig").read()) cfg_full = os.path.normcase(os.path.abspath(cfg_dir)).rstrip("\\/") for db in proj.get("databases", []): src = db.get("configSrc") if src: src_full = os.path.normcase(os.path.abspath(src)).rstrip("\\/") if cfg_full == src_full or cfg_full.startswith(src_full + os.sep): if db.get("editingAllowedCheck"): return db["editingAllowedCheck"] if proj.get("editingAllowedCheck"): return proj["editingAllowedCheck"] return "deny" except Exception: return "deny" def assert_edit_allowed(target_path, require): try: rp = os.path.abspath(target_path) # Autonomous external object (EPF/ERF): never part of a config on support (issue #39). if _sg_is_external_root(rp): return elem_uuid = _sg_root_uuid(rp) cfg_dir = None bin_path = None d = rp if os.path.isdir(rp) else os.path.dirname(rp) for _ in range(12): if not d: break if _sg_is_external_root(d + ".xml"): return if not elem_uuid: elem_uuid = _sg_root_uuid(d + ".xml") if not cfg_dir: cand = os.path.join(d, "Ext", "ParentConfigurations.bin") if os.path.exists(cand) or os.path.exists(os.path.join(d, "Configuration.xml")): cfg_dir = d bin_path = cand if elem_uuid and cfg_dir: break parent = os.path.dirname(d) if parent == d: break d = parent if not elem_uuid and cfg_dir: elem_uuid = _sg_root_uuid(os.path.join(cfg_dir, "Configuration.xml")) if not bin_path or not os.path.exists(bin_path): return data = open(bin_path, "rb").read() if len(data) <= 32: return if data[:3] == b"\xef\xbb\xbf": data = data[3:] text = data.decode("utf-8", "replace") h = re.match(r"\{6,(\d+),(\d+),", text) if not h: return g = int(h.group(1)) k = int(h.group(2)) if k == 0: return best = None if elem_uuid: for m in re.finditer(r"([0-2]),0," + re.escape(elem_uuid.lower()), text): f1 = int(m.group(1)) if best is None or f1 < best: best = f1 blocked = False code = "" reason = "" if g == 1: blocked = True code = "capability-off" reason = "возможность изменения конфигурации выключена (вся конфигурация read-only)" elif require == "removed": if best is not None and best != 2: blocked = True code = "not-removed" reason = "объект не снят с поддержки - удаление сломает обновления" else: if best is not None and best == 0: blocked = True code = "locked" reason = "объект на замке - редактирование сломает обновления" if not blocked: return mode = _sg_get_edit_mode(cfg_dir) if mode == "off": return if mode == "warn": sys.stderr.write(f"[support-guard] ПРЕДУПРЕЖДЕНИЕ: {reason}. Цель: {rp}\n") return head = "[support-guard] Редактирование отклонено: это объект типовой конфигурации на поддержке поставщика, прямое редактирование молча сломает будущие обновления." cfe = "Рекомендуемый путь: внести доработку в расширение (навыки cfe-borrow / cfe-patch-method) - состояние поддержки менять не нужно, обновления вендора сохраняются." off_note = "Снять проверку для этой базы: editingAllowedCheck = warn|off в .v8-project.json." if code == "capability-off": state = f"Состояние: у всей конфигурации выключена возможность изменения (режим read-only 'из коробки') - поэтому объект '{rp}' редактировать нельзя." fix = ( "Либо снять защиту явно (навык support-edit, два шага):\n" f' 1. support-edit -Path "{cfg_dir}" -Capability on - включить возможность изменения (объекты пока остаются на замке);\n' f' 2. support-edit -Path "{rp}" -Set editable - открыть этот объект для редактирования.\n' " Изменение применяется в базу полной загрузкой выгрузки и обходит механизм обновлений вендора." ) elif code == "not-removed": state = f"Состояние: объект '{rp}' на поддержке (не снят с поддержки) - его удаление разорвет обновления вендора." fix = ( "Либо сначала снять объект с поддержки, затем удалять:\n" f' support-edit -Path "{rp}" -Set off-support - объект уходит из-под обновлений, после этого удаление безопасно.' ) else: state = f"Состояние: объект '{rp}' на замке (возможность изменения конфигурации включена, но сам объект не редактируется)." fix = ( "Либо разрешить редактирование этого объекта (навык support-edit, выбрать одно):\n" f' support-edit -Path "{rp}" -Set editable - редактировать и дальше получать обновления вендора (возможны конфликты слияния);\n' f' support-edit -Path "{rp}" -Set off-support - снять с поддержки: обновления по объекту больше не приходят.' ) sys.stderr.write(head + "\n" + state + "\n" + cfe + "\n" + fix + "\n" + off_note + "\n") sys.exit(1) except SystemExit: raise except Exception: return # --- Конец общего блока гарда поддержки --- sys.stdout.reconfigure(encoding="utf-8") sys.stderr.reconfigure(encoding="utf-8") # --------------------------------------------------------------------------- # Inline utilities # --------------------------------------------------------------------------- def esc_xml(s): return s.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') def new_uuid(): return str(uuid.uuid4()) def detect_file_eol(path): """Конец строки существующего файла; у нового - канонический CRLF.""" try: with open(path, "rb") as fh: data = fh.read() except OSError: return '\r\n' return '\r\n' if b'\r\n' in data or b'\n' not in data else '\n' def write_utf8_bom(path, content, eol='\r\n'): # Исходники 1С хранятся в CRLF: этого ждет Конфигуратор, и это закреплено в .gitattributes. # Сборка идет через '\n'.join, поэтому концы строк разворачиваются здесь, на записи. # Нормализация идемпотентна - смешанный текст тоже приходит к одному виду. # Правка существующего файла передает сюда его собственный eol: форсировать CRLF там # нельзя, иначе навык переписывает весь чужой файл ради одной добавленной строки. content = content.replace('\r\n', '\n').replace('\n', eol) with open(path, 'w', encoding='utf-8-sig', newline='') as f: f.write(content) # --------------------------------------------------------------------------- # XML builder (lines list) # --------------------------------------------------------------------------- lines = [] def X(text): lines.append(text) def emit_mltext(indent, tag, text): if not text: X(f'{indent}<{tag}/>') return # Значение бывает строкой (тогда это русский вариант) и словарем { 'ru': ..., 'en': ... }. # Раньше словарь приводился к строке и уезжал в XML как есть, вместо перевода. if isinstance(text, dict): ml_items = [(str(lang), str(content)) for lang, content in text.items()] else: ml_items = [('ru', str(text))] X(f'{indent}<{tag}>') for lang, content in ml_items: X(f'{indent}\t<v8:item>') # Пустой язык платформа пишет одиночным тегом: пара с пустым содержимым не совпадает # с выгрузкой. if lang: X(f'{indent}\t\t<v8:lang>{lang}</v8:lang>') else: X(f'{indent}\t\t<v8:lang/>') X(f'{indent}\t\t<v8:content>{esc_xml(content)}</v8:content>') X(f'{indent}\t</v8:item>') X(f'{indent}</{tag}>') # --------------------------------------------------------------------------- # CamelCase splitter # --------------------------------------------------------------------------- def split_camel_case(name): if not name: return name result = re.sub(r'([а-яё])([А-ЯЁ])', r'\1 \2', name) result = re.sub(r'([a-z])([A-Z])', r'\1 \2', result) if len(result) > 1: tail = re.sub(r'(?<![А-ЯЁA-Z])([А-ЯЁA-Z])(?![А-ЯЁA-Z])', lambda m: m.group(1).lower(), result[1:]) result = result[0] + tail return result # --------------------------------------------------------------------------- # 1. Load and validate JSON # --------------------------------------------------------------------------- parser = argparse.ArgumentParser(allow_abbrev=False) parser.add_argument('-JsonPath', required=True) parser.add_argument('-OutputDir', required=True) args = parser.parse_args() json_path = args.JsonPath output_dir = args.OutputDir assert_edit_allowed(output_dir, "editable") if not os.path.isfile(json_path): print(f'File not found: {json_path}', file=sys.stderr) sys.exit(1) with open(json_path, 'r', encoding='utf-8-sig') as f: json_text = f.read() class LenientDict(dict): """Словарь, нечувствительный к регистру ключей - как PSObject в PowerShell. Нужен для прощающего ввода: DSL принимает и `codeLength`, и `CodeLength`. Вложенные словари оборачиваются тоже, иначе леность теряется на первом же уровне вложенности. """ def __init__(self, data=None): super().__init__() for k, v in (data or {}).items(): self[k] = v @staticmethod def _wrap(v): if isinstance(v, dict): return LenientDict(v) if isinstance(v, list): return [LenientDict(x) if isinstance(x, dict) else x for x in v] return v def __setitem__(self, key, value): super().__setitem__(key, self._wrap(value)) def _actual_key(self, key): if super().__contains__(key): return key if isinstance(key, str): low = key.lower() for k in super().keys(): if isinstance(k, str) and k.lower() == low: return k return None def __getitem__(self, key): k = self._actual_key(key) if k is None: raise KeyError(key) return super().__getitem__(k) def __contains__(self, key): return self._actual_key(key) is not None def get(self, key, default=None): k = self._actual_key(key) return super().__getitem__(k) if k is not None else default def lenient(data): """JSON бывает объектом и массивом объектов - оборачиваем и то, и другое.""" if isinstance(data, list): return [LenientDict(x) if isinstance(x, dict) else x for x in data] return LenientDict(data) if isinstance(data, dict) else data defn = lenient(json.loads(json_text)) # --- Batch mode: JSON array of objects --- if isinstance(defn, list): batch_ok = 0 batch_fail = 0 for idx, item in enumerate(defn, 1): tmp_fd, tmp_path = tempfile.mkstemp(suffix='.json', prefix=f'meta-compile-batch-{idx}-') try: with os.fdopen(tmp_fd, 'w', encoding='utf-8') as f: json.dump(item, f, ensure_ascii=False, indent=2) rc = subprocess.call([sys.executable, __file__, '-JsonPath', tmp_path, '-OutputDir', output_dir]) if rc == 0: batch_ok += 1 else: batch_fail += 1 finally: if os.path.exists(tmp_path): os.unlink(tmp_path) print() print(f"=== Batch: {len(defn)} objects, {batch_ok} compiled, {batch_fail} failed ===") sys.exit(1 if batch_fail > 0 else 0) # Normalize field synonyms: accept "objectType" as alias for "type" if not defn.get('type') and defn.get('objectType'): defn['type'] = defn['objectType'] # Object type synonyms (Russian -> English) object_type_synonyms = { 'Справочник': 'Catalog', 'Каталог': 'Catalog', 'Документ': 'Document', 'Перечисление': 'Enum', 'Константа': 'Constant', 'РегистрСведений': 'InformationRegister', 'РегистрНакопления': 'AccumulationRegister', 'РегистрБухгалтерии': 'AccountingRegister', 'РегистрРасчёта': 'CalculationRegister', 'РегистрРасчета': 'CalculationRegister', 'ПланСчетов': 'ChartOfAccounts', 'ПланВидовХарактеристик': 'ChartOfCharacteristicTypes', 'ПланВидовРасчёта': 'ChartOfCalculationTypes', 'ПланВидовРасчета': 'ChartOfCalculationTypes', 'БизнесПроцесс': 'BusinessProcess', 'Задача': 'Task', 'ПланОбмена': 'ExchangePlan', 'ЖурналДокументов': 'DocumentJournal', 'Отчёт': 'Report', 'Отчет': 'Report', 'Обработка': 'DataProcessor', 'ОбщийМодуль': 'CommonModule', 'РегламентноеЗадание': 'ScheduledJob', 'ПодпискаНаСобытие': 'EventSubscription', 'HTTPСервис': 'HTTPService', 'ВебСервис': 'WebService', 'ОпределяемыйТип': 'DefinedType', 'ОбщийРеквизит': 'CommonAttribute', 'ОбщаяФорма': 'CommonForm', 'ОбщаяКоманда': 'CommonCommand', 'ГруппаКоманд': 'CommandGroup', 'ОбщийМакет': 'CommonTemplate', 'ОбщаяКартинка': 'CommonPicture', 'КритерийОтбора': 'FilterCriterion', 'Последовательность': 'Sequence', 'НумераторДокументов': 'DocumentNumerator', 'ПараметрСеанса': 'SessionParameter', 'ХранилищеНастроек': 'SettingsStorage', 'ФункциональнаяОпция': 'FunctionalOption', 'ПараметрФункциональныхОпций': 'FunctionalOptionsParameter', 'WSСсылка': 'WSReference', } # Enum property value synonyms - model often gets these slightly wrong enum_value_aliases = { # RegisterType (AccumulationRegister) 'Balances': 'Balance', 'Остатки': 'Balance', 'Обороты': 'Turnovers', # WriteMode (InformationRegister) 'RecordSubordinate': 'RecorderSubordinate', 'Subordinate': 'RecorderSubordinate', 'ПодчинениеРегистратору': 'RecorderSubordinate', 'Независимый': 'Independent', # DependenceOnCalculationTypes (ChartOfCalculationTypes) 'NotDependOnCalculationTypes': 'DontUse', 'NoDependence': 'DontUse', 'NotUsed': 'DontUse', 'Depend': 'OnActionPeriod', 'ПоПериодуДействия': 'OnActionPeriod', # InformationRegisterPeriodicity 'None': 'Nonperiodical', 'Daily': 'Day', 'Monthly': 'Month', 'Quarterly': 'Quarter', 'Yearly': 'Year', 'Непериодический': 'Nonperiodical', 'Секунда': 'Second', 'День': 'Day', 'Месяц': 'Month', 'Квартал': 'Quarter', 'Год': 'Year', 'ПозицияРегистратора': 'RecorderPosition', # DataLockControlMode 'Автоматический': 'Automatic', 'Управляемый': 'Managed', # FullTextSearch 'Использовать': 'Use', 'НеИспользовать': 'DontUse', # Posting 'Разрешить': 'Allow', 'Запретить': 'Deny', # EditType 'ВДиалоге': 'InDialog', 'ВСписке': 'InList', 'ОбаСпособа': 'BothWays', # DefaultPresentation 'ВВидеНаименования': 'AsDescription', 'ВВидеКода': 'AsCode', # FillChecking 'НеПроверять': 'DontCheck', 'Ошибка': 'ShowError', 'Предупреждение': 'ShowWarning', # Indexing 'НеИндексировать': 'DontIndex', 'Индексировать': 'Index', 'ИндексироватьСДопУпорядочиванием': 'IndexWithAdditionalOrder', } # Valid enum values per property (from meta-validate) valid_enum_values = { 'RegisterType': ['Balance', 'Turnovers'], 'WriteMode': ['Independent', 'RecorderSubordinate'], 'InformationRegisterPeriodicity': ['Nonperiodical', 'Second', 'Day', 'Month', 'Quarter', 'Year', 'RecorderPosition'], 'DependenceOnCalculationTypes': ['DontUse', 'OnActionPeriod'], 'DataLockControlMode': ['Automatic', 'Managed'], 'FullTextSearch': ['Use', 'DontUse'], 'DataHistory': ['Use', 'DontUse'], 'DefaultPresentation': ['AsDescription', 'AsCode'], 'Posting': ['Allow', 'Deny'], 'RealTimePosting': ['Allow', 'Deny'], 'EditType': ['InDialog', 'InList', 'BothWays'], 'HierarchyType': ['HierarchyFoldersAndItems', 'HierarchyItemsOnly'], 'CodeType': ['String', 'Number'], 'CodeAllowedLength': ['Variable', 'Fixed'], 'NumberType': ['String', 'Number'], 'NumberAllowedLength': ['Variable', 'Fixed'], 'RegisterRecordsDeletion': ['AutoDelete', 'AutoDeleteOnUnpost', 'AutoDeleteOff'], 'RegisterRecordsWritingOnPost': ['WriteModified', 'WriteSelected', 'WriteAll'], 'ReturnValuesReuse': ['DontUse', 'DuringRequest', 'DuringSession'], 'ReuseSessions': ['DontUse', 'Use', 'AutoUse'], 'FillChecking': ['DontCheck', 'ShowError', 'ShowWarning'], 'Indexing': ['DontIndex', 'Index', 'IndexWithAdditionalOrder'], 'SubordinationUse': ['ToItems', 'ToFolders', 'ToFoldersAndItems'], 'CodeSeries': ['WholeCatalog', 'WithinSubordination'], 'ChoiceMode': ['BothWays', 'QuickChoice', 'FromForm'], } def normalize_enum_value(prop_name, value): # 1. Check alias dictionary - silent auto-correct. Поиск без учета регистра: хеш-таблица # PowerShell находит "обороты" по ключу "Обороты", словарь python - нет. alias = lookup_ci(enum_value_aliases, value) if alias is not None: return alias # 2. Case-insensitive match against valid values - silent valid = valid_enum_values.get(prop_name) if valid: for v in valid: if v.lower() == value.lower(): return v # 3. Known property, unknown value - error with hint print(f"Invalid value '{value}' for property '{prop_name}'. Valid values: {', '.join(valid)}", file=sys.stderr) sys.exit(1) # 4. Unknown property - pass-through (no validation data) return value def get_enum_prop(prop_name, field_name, default): val = defn.get(field_name) raw = str(val) if val else default return normalize_enum_value(prop_name, raw) # Виды вложенных сущностей: русское имя -> английское. Дополняется синонимами типов объектов, # чтобы путь вида "Документ.Заказ.Реквизит.Сумма" приводился к английскому целиком. md_kind_synonyms = { 'Реквизит': 'Attribute', 'ТабличнаяЧасть': 'TabularSection', 'Измерение': 'Dimension', 'Ресурс': 'Resource', 'Графа': 'Column', 'ЗначениеПеречисления': 'EnumValue', 'Форма': 'Form', 'Макет': 'Template', 'Команда': 'Command', 'ПризнакУчета': 'AccountingFlag', 'ПризнакУчетаСубконто': 'ExtDimensionAccountingFlag', 'РеквизитАдресации': 'AddressingAttribute', } md_kind_synonyms.update(object_type_synonyms) def as_array(value): """Аналог @(...) в PowerShell: строка становится ОДНИМ элементом, а не списком символов. Через list() строковое значение рассыпалось посимвольно - например источник подписки "CatalogObject.Товары" выпускался как двадцать типов d5p1:C, d5p1:a, d5p1:t... """ if value is None: return [] if isinstance(value, (list, tuple)): return [v for v in value if v is not None] return [value] def resolve_md_path(path): """Приводит путь к метаданным к английским именам: русские идут на нечетных позициях.""" if not path: return path parts = str(path).split('.') for idx in range(0, len(parts), 2): # Поиск без учета регистра: хеш-таблица PowerShell находит "документ" по ключу "Документ", # словарь python - нет, и русский вид сущности оставался непереведенным. syn = lookup_ci(md_kind_synonyms, parts[idx]) if syn: parts[idx] = syn return '.'.join(parts) def emit_comment(indent): if comment: X(f'{indent}<Comment>{esc_xml(comment)}</Comment>') else: X(f'{indent}<Comment/>') def emit_common_head(indent): """Голова свойств, одинаковая у всех типов: имя, синоним, комментарий.""" X(f'{indent}<Name>{esc_xml(obj_name)}</Name>') emit_mltext(indent, 'Synonym', synonym) emit_comment(indent) def emit_md_ref_list(indent, tag, items): """Список ссылок: <xr:Item xsi:type="xr:MDObjectRef">Document.X</xr:Item>""" refs = [r for r in (items if isinstance(items, list) else ([items] if items else [])) if r] if not refs: X(f'{indent}<{tag}/>') return X(f'{indent}<{tag}>') for ref in refs: X(f'{indent}\t<xr:Item xsi:type="xr:MDObjectRef">{resolve_md_path(str(ref))}</xr:Item>') X(f'{indent}</{tag}>') def emit_picture_ref(indent, picture): """Картинка команды или группы: либо ссылка на общую картинку, либо пустой тег.""" if not picture: X(f'{indent}<Picture/>') return src = picture if isinstance(picture, str) else picture.get('src') if not src: X(f'{indent}<Picture/>') return transparent = 'true' if (not isinstance(picture, str) and picture.get('loadTransparent') is True) else 'false' X(f'{indent}<Picture>') X(f'{indent}\t<xr:Ref>{resolve_md_path(str(src))}</xr:Ref>') X(f'{indent}\t<xr:LoadTransparent>{transparent}</xr:LoadTransparent>') X(f'{indent}</Picture>') if not defn.get('type'): print("JSON must have 'type' field", file=sys.stderr) sys.exit(1) def lookup_ci(table, key): """Поиск по словарю без учета регистра - хеш-таблица PowerShell ведет себя так же.""" if key in table: return table[key] low = str(key).lower() for k, v in table.items(): if str(k).lower() == low: return v return None obj_type = str(defn['type']) _syn = lookup_ci(object_type_synonyms, obj_type) if _syn: obj_type = _syn valid_types = [ 'Catalog', 'Document', 'Enum', 'Constant', 'InformationRegister', 'AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'ChartOfAccounts', 'ChartOfCharacteristicTypes', 'ChartOfCalculationTypes', 'BusinessProcess', 'Task', 'ExchangePlan', 'DocumentJournal', 'Report', 'DataProcessor', 'CommonModule', 'ScheduledJob', 'EventSubscription', 'HTTPService', 'WebService', 'DefinedType', 'CommonAttribute', 'CommonCommand', 'CommandGroup', 'CommonForm', 'CommonTemplate', 'CommonPicture', 'FilterCriterion', 'Sequence', 'DocumentNumerator', 'SessionParameter', 'SettingsStorage', 'FunctionalOption', 'FunctionalOptionsParameter', 'WSReference', ] # Сравнение регистронезависимое, как оператор -in в PowerShell, но имя типа затем приводится # к каноническому виду. Иначе "catalog" уходит в XML тегом <catalog>, а платформа на таком теге # не ругается - она МОЛЧА выбрасывает объект: "не является подчиненным для объекта # Configuration", код возврата 0, объекта в базе нет. Замерено на 8.3.27. _canonical = next((v for v in valid_types if v.lower() == obj_type.lower()), None) if _canonical is None: print(f"Unsupported type: {obj_type}. Valid: {', '.join(valid_types)}", file=sys.stderr) sys.exit(1) obj_type = _canonical if not defn.get('name'): print("JSON must have 'name' field", file=sys.stderr) sys.exit(1) obj_name = str(defn['name']) # Auto-synonym synonym = defn['synonym'] if defn.get('synonym') else split_camel_case(obj_name) comment = str(defn['comment']) if defn.get('comment') else '' # --------------------------------------------------------------------------- # 4. Type system # --------------------------------------------------------------------------- type_synonyms = { 'число': 'Number', 'строка': 'String', 'булево': 'Boolean', 'дата': 'Date', 'датавремя': 'DateTime', 'number': 'Number', 'string': 'String', 'boolean': 'Boolean', 'date': 'Date', 'datetime': 'DateTime', 'bool': 'Boolean', # Reference synonyms (Russian, lowercase) 'справочникссылка': 'CatalogRef', 'документссылка': 'DocumentRef', 'перечислениессылка': 'EnumRef', 'плансчетовссылка': 'ChartOfAccountsRef', 'планвидовхарактеристикссылка': 'ChartOfCharacteristicTypesRef', 'планвидоврасчётассылка': 'ChartOfCalculationTypesRef', 'планвидоврасчетассылка': 'ChartOfCalculationTypesRef', 'планобменассылка': 'ExchangePlanRef', 'бизнеспроцессссылка': 'BusinessProcessRef', 'задачассылка': 'TaskRef', 'определяемыйтип': 'DefinedType', 'definedtype': 'DefinedType', # English lowercase ref synonyms 'catalogref': 'CatalogRef', 'documentref': 'DocumentRef', 'enumref': 'EnumRef', } def resolve_type_str(type_str): if not type_str: return type_str # Тип, скопированный из выгрузки, несет префикс пространства имен: cfg:, d5p1:, d4p1:. # Срезается только префикс выгрузки конфигурации: схемные префиксы (v8:, xs:, v8ui:) # часть имени типа, и без них тип не разрешается. m_prefix = re.match(r'^(?:cfg|d\d+p\d+):(.+)$', type_str) if m_prefix: type_str = m_prefix.group(1) # Parameterized types: Number(15,2), Строка(100), etc. m = re.match(r'^([^(]+)\((.+)\)$', type_str) if m: base_name = m.group(1).strip() params = m.group(2) resolved = type_synonyms.get(base_name.lower()) if resolved: return f'{resolved}({params})' return type_str # Reference types: СправочникСсылка.Организации -> CatalogRef.Организации if '.' in type_str: dot_idx = type_str.index('.') prefix = type_str[:dot_idx] suffix = type_str[dot_idx:] # includes the dot resolved = type_synonyms.get(prefix.lower()) if resolved: return f'{resolved}{suffix}' return type_str # Simple name lookup resolved = type_synonyms.get(type_str.lower()) if resolved: return resolved return type_str def emit_type_content(indent, type_str, cfg_prefix=False): if not type_str: return # Составной тип платформа пишет блоками: сперва все типы, затем наборы типов, затем # квалификаторы по одному на вид - числовой, строковый, дата. Наш вывод шел парами # тип-квалификатор, и файл расходился с выгрузкой на каждом составном типе. if ' + ' in type_str: parts = [p.strip() for p in type_str.split('+')] type_lines, set_lines, quals = [], [], {} for part in parts: start = len(lines) emit_type_content(indent, part, cfg_prefix) chunk = lines[start:] del lines[start:] open_kind = None for line in chunk: stripped = line.strip() if open_kind: quals[open_kind].append(line) if stripped == f'</v8:{open_kind}>': open_kind = None continue m_qual = re.match(r'<v8:(\w+Qualifiers)>', stripped) if m_qual: open_kind = m_qual.group(1) quals.setdefault(open_kind, []).append(line) elif stripped.startswith('<v8:TypeSet'): set_lines.append(line) elif stripped.startswith('<v8:Type'): type_lines.append(line) else: type_lines.append(line) for line in type_lines + set_lines: X(line) ordered = ['NumberQualifiers', 'StringQualifiers', 'DateQualifiers'] for kind in ordered + [k for k in quals if k not in ordered]: for line in quals.get(kind, []): X(line) return type_str = resolve_type_str(type_str) # Boolean if type_str == 'Boolean': X(f'{indent}<v8:Type>xs:boolean</v8:Type>') return # String or String(N) m = re.match(r'^String(\((\d+)\))?$', type_str) if m: length = m.group(2) if m.group(2) else '10' X(f'{indent}<v8:Type>xs:string</v8:Type>') X(f'{indent}<v8:StringQualifiers>') X(f'{indent}\t<v8:Length>{length}</v8:Length>') X(f'{indent}\t<v8:AllowedLength>Variable</v8:AllowedLength>') X(f'{indent}</v8:StringQualifiers>') return # Number without params -> Number(10,0) if type_str == 'Number': X(f'{indent}<v8:Type>xs:decimal</v8:Type>') X(f'{indent}<v8:NumberQualifiers>') X(f'{indent}\t<v8:Digits>10</v8:Digits>') X(f'{indent}\t<v8:FractionDigits>0</v8:FractionDigits>') X(f'{indent}\t<v8:AllowedSign>Any</v8:AllowedSign>') X(f'{indent}</v8:NumberQualifiers>') return # Number(D,F) or Number(D,F,nonneg) m = re.match(r'^Number\((\d+),(\d+)(,nonneg)?\)$', type_str) if m: digits = m.group(1) fraction = m.group(2) sign = 'Nonnegative' if m.group(3) else 'Any' X(f'{indent}<v8:Type>xs:decimal</v8:Type>') X(f'{indent}<v8:NumberQualifiers>') X(f'{indent}\t<v8:Digits>{digits}</v8:Digits>') X(f'{indent}\t<v8:FractionDigits>{fraction}</v8:FractionDigits>') X(f'{indent}\t<v8:AllowedSign>{sign}</v8:AllowedSign>') X(f'{indent}</v8:NumberQualifiers>') return # Date / DateTime if type_str == 'Date': X(f'{indent}<v8:Type>xs:dateTime</v8:Type>') X(f'{indent}<v8:DateQualifiers>') X(f'{indent}\t<v8:DateFractions>Date</v8:DateFractions>') X(f'{indent}</v8:DateQualifiers>') return if type_str == 'DateTime': X(f'{indent}<v8:Type>xs:dateTime</v8:Type>') X(f'{indent}<v8:DateQualifiers>') X(f'{indent}\t<v8:DateFractions>DateTime</v8:DateFractions>') X(f'{indent}</v8:DateQualifiers>') return # DefinedType m = re.match(r'^DefinedType\.(.+)$', type_str) if m: dt_name = m.group(1) X(f'{indent}<v8:TypeSet>cfg:DefinedType.{dt_name}</v8:TypeSet>') return # ValueStorage if type_str == 'ValueStorage': X(f'{indent}<v8:Type>xs:base64Binary</v8:Type>') return # Reference types - use local xmlns declaration for 1C compatibility m = re.match(r'^(CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef)\.(.+)$', type_str) if m: if cfg_prefix: X(f'{indent}<v8:Type>cfg:{type_str}</v8:Type>') else: X(f'{indent}<v8:Type xmlns:d5p1="http://v8.1c.ru/8.1/data/enterprise/current-config">d5p1:{type_str}</v8:Type>') return # Ссылочный тип без имени объекта - это НАБОР типов, а не тип: любой справочник, # любой документ. Платформа пишет его элементом TypeSet. if re.fullmatch(r'CatalogRef|DocumentRef|EnumRef|ChartOfAccountsRef|ChartOfCharacteristicTypesRef|ChartOfCalculationTypesRef|ExchangePlanRef|BusinessProcessRef|TaskRef', type_str): X(f'{indent}<v8:TypeSet>cfg:{type_str}</v8:TypeSet>') return # Fallback X(f'{indent}<v8:Type>{type_str}</v8:Type>') def emit_value_type(indent, type_str): # Измерения и ресурсы регистров платформа выгружает через объявленный в шапке префикс # cfg, а не локальным объявлением - замерено на эталоне регистра сведений. X(f'{indent}<Type>') emit_type_content(f'{indent}\t', type_str, cfg_prefix=True) X(f'{indent}</Type>') def emit_fill_value(indent, type_str): if not type_str: X(f'{indent}<FillValue xsi:nil="true"/>') return type_str = resolve_type_str(type_str) if type_str == 'Boolean': X(f'{indent}<FillValue xsi:type="xs:boolean">false</FillValue>') return if re.match(r'^String', type_str): X(f'{indent}<FillValue xsi:type="xs:string"/>') return if re.match(r'^Number', type_str): X(f'{indent}<FillValue xsi:type="xs:decimal">0</FillValue>') return if re.match(r'^(Date|DateTime)$', type_str): X(f'{indent}<FillValue xsi:nil="true"/>') return X(f'{indent}<FillValue xsi:nil="true"/>') # --------------------------------------------------------------------------- # 5. Attribute shorthand parser # --------------------------------------------------------------------------- def build_type_str(obj): t = str(obj.get('valueType') or obj.get('type') or '') if t and '(' not in t: if t == 'String' and obj.get('length'): t = f"String({obj['length']})" elif t == 'Number' and obj.get('length'): prec = obj.get('precision', 0) nn = ',nonneg' if obj.get('nonneg') or obj.get('nonnegative') else '' t = f"Number({obj['length']},{prec}{nn})" return t def parse_attribute_shorthand(val): if isinstance(val, str): parsed = { 'name': '', 'type': '', 'synonym': '', 'comment': '', 'flags': [], 'fillChecking': '', 'indexing': '', } parts = val.split('|', 1) main_part = parts[0].strip() if len(parts) > 1: flag_str = parts[1].strip() parsed['flags'] = [f.strip().lower() for f in flag_str.split(',') if f.strip()] colon_parts = main_part.split(':', 1) parsed['name'] = colon_parts[0].strip() if len(colon_parts) > 1: parsed['type'] = colon_parts[1].strip() parsed['synonym'] = split_camel_case(parsed['name']) return parsed # Object form name = str(val.get('name', '')) return { 'name': name, 'type': build_type_str(val), 'synonym': val['synonym'] if val.get('synonym') else split_camel_case(name), 'comment': str(val['comment']) if val.get('comment') else '', 'flags': list(val.get('flags', [])), 'fillChecking': str(val['fillChecking']) if val.get('fillChecking') else '', 'indexing': str(val['indexing']) if val.get('indexing') else '', 'multiLine': True if val.get('multiLine') is True else False, } def parse_enum_value_shorthand(val): if isinstance(val, str): return { 'name': val, 'synonym': split_camel_case(val), 'comment': '', } name = str(val.get('name', '')) return { 'name': name, 'synonym': val['synonym'] if val.get('synonym') else split_camel_case(name), 'comment': str(val['comment']) if val.get('comment') else '', } # --------------------------------------------------------------------------- # 6. GeneratedType categories # --------------------------------------------------------------------------- generated_types = { 'Catalog': [ {'prefix': 'CatalogObject', 'category': 'Object'}, {'prefix': 'CatalogRef', 'category': 'Ref'}, {'prefix': 'CatalogSelection', 'category': 'Selection'}, {'prefix': 'CatalogList', 'category': 'List'}, {'prefix': 'CatalogManager', 'category': 'Manager'}, ], 'Document': [ {'prefix': 'DocumentObject', 'category': 'Object'}, {'prefix': 'DocumentRef', 'category': 'Ref'}, {'prefix': 'DocumentSelection', 'category': 'Selection'}, {'prefix': 'DocumentList', 'category': 'List'}, {'prefix': 'DocumentManager', 'category': 'Manager'}, ], 'Enum': [ {'prefix': 'EnumRef', 'category': 'Ref'}, {'prefix': 'EnumManager', 'category': 'Manager'}, {'prefix': 'EnumList', 'category': 'List'}, ], 'Constant': [ {'prefix': 'ConstantManager', 'category': 'Manager'}, {'prefix': 'ConstantValueManager', 'category': 'ValueManager'}, {'prefix': 'ConstantValueKey', 'category': 'ValueKey'}, ], 'InformationRegister': [ {'prefix': 'InformationRegisterRecord', 'category': 'Record'}, {'prefix': 'InformationRegisterManager', 'category': 'Manager'}, {'prefix': 'InformationRegisterSelection', 'category': 'Selection'}, {'prefix': 'InformationRegisterList', 'category': 'List'}, {'prefix': 'InformationRegisterRecordSet', 'category': 'RecordSet'}, {'prefix': 'InformationRegisterRecordKey', 'category': 'RecordKey'}, {'prefix': 'InformationRegisterRecordManager', 'category': 'RecordManager'}, ], 'AccumulationRegister': [ {'prefix': 'AccumulationRegisterRecord', 'category': 'Record'}, {'prefix': 'AccumulationRegisterManager', 'category': 'Manager'}, {'prefix': 'AccumulationRegisterSelection', 'category': 'Selection'}, {'prefix': 'AccumulationRegisterList', 'category': 'List'}, {'prefix': 'AccumulationRegisterRecordSet', 'category': 'RecordSet'}, {'prefix': 'AccumulationRegisterRecordKey', 'category': 'RecordKey'}, ], 'AccountingRegister': [ {'prefix': 'AccountingRegisterRecord', 'category': 'Record'}, {'prefix': 'AccountingRegisterExtDimensions', 'category': 'ExtDimensions'}, {'prefix': 'AccountingRegisterRecordSet', 'category': 'RecordSet'}, {'prefix': 'AccountingRegisterRecordKey', 'category': 'RecordKey'}, {'prefix': 'AccountingRegisterSelection', 'category': 'Selection'}, {'prefix': 'AccountingRegisterList', 'category': 'List'}, {'prefix': 'AccountingRegisterManager', 'category': 'Manager'}, ], 'CalculationRegister': [ {'prefix': 'CalculationRegisterRecord', 'category': 'Record'}, {'prefix': 'CalculationRegisterManager', 'category': 'Manager'}, {'prefix': 'CalculationRegisterSelection', 'category': 'Selection'}, {'prefix': 'CalculationRegisterList', 'category': 'List'}, {'prefix': 'CalculationRegisterRecordSet', 'category': 'RecordSet'}, {'prefix': 'CalculationRegisterRecordKey', 'category': 'RecordKey'}, {'prefix': 'RecalculationsManager', 'category': 'Recalcs'}, ], 'ChartOfAccounts': [ {'prefix': 'ChartOfAccountsObject', 'category': 'Object'}, {'prefix': 'ChartOfAccountsRef', 'category': 'Ref'}, {'prefix': 'ChartOfAccountsSelection', 'category': 'Selection'}, {'prefix': 'ChartOfAccountsList', 'category': 'List'}, {'prefix': 'ChartOfAccountsManager', 'category': 'Manager'}, {'prefix': 'ChartOfAccountsExtDimensionTypes', 'category': 'ExtDimensionTypes'}, {'prefix': 'ChartOfAccountsExtDimensionTypesRow', 'category': 'ExtDimensionTypesRow'}, ], 'ChartOfCharacteristicTypes': [ {'prefix': 'ChartOfCharacteristicTypesObject', 'category': 'Object'}, {'prefix': 'ChartOfCharacteristicTypesRef', 'category': 'Ref'}, {'prefix': 'ChartOfCharacteristicTypesSelection', 'category': 'Selection'}, {'prefix': 'ChartOfCharacteristicTypesList', 'category': 'List'}, # Префикс именно "Characteristic", без имени типа: так пишет платформа. Замерено круговым # прогоном через 8.3.27 и подтверждено выгрузкой типовой конфигурации. {'prefix': 'Characteristic', 'category': 'Characteristic'}, {'prefix': 'ChartOfCharacteristicTypesManager', 'category': 'Manager'}, ], 'ChartOfCalculationTypes': [ {'prefix': 'ChartOfCalculationTypesObject', 'category': 'Object'}, {'prefix': 'ChartOfCalculationTypesRef', 'category': 'Ref'}, {'prefix': 'ChartOfCalculationTypesSelection', 'category': 'Selection'}, {'prefix': 'ChartOfCalculationTypesList', 'category': 'List'}, {'prefix': 'ChartOfCalculationTypesManager', 'category': 'Manager'}, {'prefix': 'DisplacingCalculationTypes', 'category': 'DisplacingCalculationTypes'}, {'prefix': 'DisplacingCalculationTypesRow', 'category': 'DisplacingCalculationTypesRow'}, {'prefix': 'BaseCalculationTypes', 'category': 'BaseCalculationTypes'}, {'prefix': 'BaseCalculationTypesRow', 'category': 'BaseCalculationTypesRow'}, {'prefix': 'LeadingCalculationTypes', 'category': 'LeadingCalculationTypes'}, {'prefix': 'LeadingCalculationTypesRow', 'category': 'LeadingCalculationTypesRow'}, ], 'BusinessProcess': [ {'prefix': 'BusinessProcessObject', 'category': 'Object'}, {'prefix': 'BusinessProcessRef', 'category': 'Ref'}, {'prefix': 'BusinessProcessSelection', 'category': 'Selection'}, {'prefix': 'BusinessProcessList', 'category': 'List'}, {'prefix': 'BusinessProcessManager', 'category': 'Manager'}, {'prefix': 'BusinessProcessRoutePointRef', 'category': 'RoutePointRef'}, ], 'Task': [ {'prefix': 'TaskObject', 'category': 'Object'}, {'prefix': 'TaskRef', 'category': 'Ref'}, {'prefix': 'TaskSelection', 'category': 'Selection'}, {'prefix': 'TaskList', 'category': 'List'}, {'prefix': 'TaskManager', 'category': 'Manager'}, ], 'ExchangePlan': [ {'prefix': 'ExchangePlanObject', 'category': 'Object'}, {'prefix': 'ExchangePlanRef', 'category': 'Ref'}, {'prefix': 'ExchangePlanSelection', 'category': 'Selection'}, {'prefix': 'ExchangePlanList', 'category': 'List'}, {'prefix': 'ExchangePlanManager', 'category': 'Manager'}, ], 'DefinedType': [ {'prefix': 'DefinedType', 'category': 'DefinedType'}, ], 'FilterCriterion': [ {'prefix': 'FilterCriterionManager', 'category': 'Manager'}, {'prefix': 'FilterCriterionList', 'category': 'List'}, ], 'Sequence': [ {'prefix': 'SequenceRecord', 'category': 'Record'}, {'prefix': 'SequenceManager', 'category': 'Manager'}, {'prefix': 'SequenceRecordSet', 'category': 'RecordSet'}, ], 'SettingsStorage': [ {'prefix': 'SettingsStorageManager', 'category': 'Manager'}, ], 'WSReference': [ {'prefix': 'WSReferenceManager', 'category': 'Manager'}, ], 'DocumentJournal': [ {'prefix': 'DocumentJournalSelection', 'category': 'Selection'}, {'prefix': 'DocumentJournalList', 'category': 'List'}, {'prefix': 'DocumentJournalManager', 'category': 'Manager'}, ], 'Report': [ {'prefix': 'ReportObject', 'category': 'Object'}, {'prefix': 'ReportManager', 'category': 'Manager'}, ], 'DataProcessor': [ {'prefix': 'DataProcessorObject', 'category': 'Object'}, {'prefix': 'DataProcessorManager', 'category': 'Manager'}, ], } def emit_internal_info(indent, object_type, object_name): types = generated_types.get(object_type) if not types: return X(f'{indent}<InternalInfo>') if object_type == 'ExchangePlan': X(f'{indent}\t<xr:ThisNode>{new_uuid()}</xr:ThisNode>') for gt in types: full_name = f"{gt['prefix']}.{object_name}" X(f'{indent}\t<xr:GeneratedType name="{full_name}" category="{gt["category"]}">') X(f'{indent}\t\t<xr:TypeId>{new_uuid()}</xr:TypeId>') X(f'{indent}\t\t<xr:ValueId>{new_uuid()}</xr:ValueId>') X(f'{indent}\t</xr:GeneratedType>') X(f'{indent}</InternalInfo>') # --------------------------------------------------------------------------- # 7. StandardAttributes # --------------------------------------------------------------------------- standard_attributes_by_type = { 'Catalog': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'IsFolder', 'Owner', 'Parent', 'Description', 'Code'], 'Document': ['Posted', 'Ref', 'DeletionMark', 'Date', 'Number'], 'Enum': ['Order', 'Ref'], 'InformationRegister': ['Active', 'LineNumber', 'Recorder', 'Period'], 'AccumulationRegister': ['Active', 'LineNumber', 'Recorder', 'Period'], 'AccountingRegister': ['Active', 'Period', 'Recorder', 'LineNumber', 'Account'], 'CalculationRegister': ['RegistrationPeriod', 'ReversingEntry', 'Active', 'EndOfBasePeriod', 'BegOfBasePeriod', 'EndOfActionPeriod', 'BegOfActionPeriod', 'ActionPeriod', 'CalculationType', 'LineNumber', 'Recorder'], 'ChartOfAccounts': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'Parent', 'Order', 'Type', 'OffBalance'], 'ChartOfCharacteristicTypes': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'Parent', 'ValueType'], 'ChartOfCalculationTypes': ['PredefinedDataName', 'Predefined', 'Ref', 'DeletionMark', 'Description', 'Code', 'ActionPeriodIsBasic'], 'BusinessProcess': ['Ref', 'DeletionMark', 'Date', 'Number', 'Started', 'Completed', 'HeadTask'], 'Task': ['Ref', 'DeletionMark', 'Date', 'Number', 'Executed', 'Description', 'RoutePoint', 'BusinessProcess'], 'ExchangePlan': ['Ref', 'DeletionMark', 'Code', 'Description', 'ThisNode', 'SentNo', 'ReceivedNo'], 'DocumentJournal': ['Type', 'Ref', 'Date', 'Posted', 'DeletionMark', 'Number'], } # --- Команды объекта --- # Группа обязательна: без нее платформа не знает, где показывать команду. Секционные группы # командного интерфейса параметра команды не принимают. COMMAND_SECTION_GROUPS = ( 'NavigationPanelImportant', 'NavigationPanelOrdinary', 'NavigationPanelSeeAlso', 'ActionsPanelImportant', 'ActionsPanelOrdinary', 'ActionsPanelSeeAlso', 'ActionsPanelCreate', 'CommandBar', 'CommandStatusBar', ) COMMAND_GROUP_SYNONYMS = { 'панельнавигации.важное': 'NavigationPanelImportant', 'панельнавигации.обычное': 'NavigationPanelOrdinary', 'панельнавигации.смтакже': 'NavigationPanelSeeAlso', 'панельдействий.важное': 'ActionsPanelImportant', 'панельдействий.обычное': 'ActionsPanelOrdinary', 'панельдействий.смтакже': 'ActionsPanelSeeAlso', 'панельдействий.создать': 'ActionsPanelCreate', 'панельдействий.сервис': 'ActionsPanelTools', 'команднаяпанельформы.важное': 'FormCommandBarImportant', 'команднаяпанельформы.обычное': 'FormCommandBarOrdinary', 'команднаяпанельформы.смтакже': 'FormCommandBarSeeAlso', 'команднаяпанельформы.создать': 'FormCommandBarCreate', 'панельнавигацииформы.важное': 'FormNavigationPanelImportant', 'панельнавигацииформы.обычное': 'FormNavigationPanelOrdinary', 'панельнавигацииформы.перейти': 'FormNavigationPanelGoTo', 'панельнавигацииформы.смтакже': 'FormNavigationPanelSeeAlso', } def resolve_command_group(group): """Группа задается предопределенным именем или ссылкой на собственную группу команд.""" if not group: return '' key = re.sub(r'\s', '', group).lower() if key in COMMAND_GROUP_SYNONYMS: return COMMAND_GROUP_SYNONYMS[key] m = re.match(r'^(?:ГруппаКоманд|CommandGroup)\.(.+)$', group) if m: return 'CommandGroup.' + m.group(1) return group def emit_object_command(indent, cmd_name, cmd_def): group = resolve_command_group(str(cmd_def.get('group', ''))) if not group: print("Ошибка: команде '" + cmd_name + "' не задана группа. " "Укажите group, например FormCommandBarImportant", file=sys.stderr) sys.exit(1) param_type = str(cmd_def.get('commandParameterType', '')) if param_type and group in COMMAND_SECTION_GROUPS: print("Ошибка: у команды '" + cmd_name + "' параметр команды недоступен для группы " + group + " - секционные группы командного интерфейса принимают команды без параметра", file=sys.stderr) sys.exit(1) X(indent + '<Command uuid="' + new_uuid() + '">') i = indent + '\t\t' X(indent + '\t<Properties>') X(i + '<Name>' + esc_xml(cmd_name) + '</Name>') emit_mltext(i, 'Synonym', cmd_def.get('synonym') or split_camel_case(cmd_name)) comment = str(cmd_def.get('comment', '')) X(i + '<Comment>' + esc_xml(comment) + '</Comment>' if comment else i + '<Comment/>') X(i + '<Group>' + group + '</Group>') if param_type: X(i + '<CommandParameterType>') emit_type_content(i + '\t', param_type, cfg_prefix=True) X(i + '</CommandParameterType>') else: X(i + '<CommandParameterType/>') X(i + '<ParameterUseMode>' + str(cmd_def.get('parameterUseMode', 'Single')) + '</ParameterUseMode>') X(i + '<ModifiesData>' + ('true' if cmd_def.get('modifiesData') is True else 'false') + '</ModifiesData>') X(i + '<Representation>' + str(cmd_def.get('representation', 'Auto')) + '</Representation>') if cmd_def.get('tooltip'): emit_mltext(i, 'ToolTip', cmd_def['tooltip']) else: X(i + '<ToolTip/>') # Картинка задается именем или объектом с прозрачным пикселем. picture = cmd_def.get('picture') if picture: pic_ref = picture if isinstance(picture, str) else str(picture.get('src', '')) X(i + '<Picture>') X(i + '\t<xr:Ref>' + esc_xml(pic_ref) + '</xr:Ref>') load_transparent = 'false' if cmd_def.get('loadTransparent') is False else 'true' X(i + '\t<xr:LoadTransparent>' + load_transparent + '</xr:LoadTransparent>') if not isinstance(picture, str) and picture.get('transparentPixel'): pixel = picture['transparentPixel'] X(i + '\t<xr:TransparentPixel x="' + str(pixel.get('x', 0)) + '" y="' + str(pixel.get('y', 0)) + '"/>') X(i + '</Picture>') else: X(i + '<Picture/>') shortcut = str(cmd_def.get('shortcut', '')) X(i + '<Shortcut>' + esc_xml(shortcut) + '</Shortcut>' if shortcut else i + '<Shortcut/>') X(i + '<OnMainServerUnavalableBehavior>' + str(cmd_def.get('onMainServerUnavalableBehavior', 'Auto')) + '</OnMainServerUnavalableBehavior>') X(indent + '\t</Properties>') X(indent + '</Command>') def emit_standard_attribute(indent, attr_name, required=False): # Настройки приходят ключом standardAttributes: заданное свойство заменяет умолчание, # остальные печатаются как есть. cfg = (defn.get('standardAttributes') or {}).get(attr_name) or {} X(f'{indent}<xr:StandardAttribute name="{attr_name}">') X(f'{indent}\t<xr:LinkByType/>') # Владелец подчиненного справочника обязателен к заполнению - платформа выставляет это # сама. Владелец и родитель заполняются из значения заполнения. default_checking = 'ShowError' if attr_name == 'Owner' or required else 'DontCheck' fill_checking = (normalize_enum_value('FillChecking', str(cfg['fillChecking'])) if cfg.get('fillChecking') else default_checking) X(f'{indent}\t<xr:FillChecking>{fill_checking}</xr:FillChecking>') X(f'{indent}\t<xr:MultiLine>false</xr:MultiLine>') from_filling = 'true' if attr_name in ('Owner', 'Parent') else 'false' X(f'{indent}\t<xr:FillFromFillingValue>{from_filling}</xr:FillFromFillingValue>') X(f'{indent}\t<xr:CreateOnInput>Auto</xr:CreateOnInput>') # Свойство появилось в формате 2.18. У владельца справочника тип задан списком владельцев, # и приведение значений платформа запрещает. if float(format_version) >= 2.18: reduction = 'Deny' if attr_name == 'Owner' else 'TransformValues' X(f'{indent}\t<xr:TypeReductionMode>{reduction}</xr:TypeReductionMode>') X(f'{indent}\t<xr:MaxValue xsi:nil="true"/>') if cfg.get('tooltip'): emit_mltext(f'{indent} ', 'xr:ToolTip', cfg['tooltip']) else: X(f'{indent} <xr:ToolTip/>') X(f'{indent}\t<xr:ExtendedEdit>false</xr:ExtendedEdit>') X(f'{indent}\t<xr:Format/>') X(f'{indent}\t<xr:ChoiceForm/>') X(f'{indent}\t<xr:QuickChoice>Auto</xr:QuickChoice>') X(f'{indent}\t<xr:ChoiceHistoryOnInput>Auto</xr:ChoiceHistoryOnInput>') X(f'{indent}\t<xr:EditFormat/>') X(f'{indent}\t<xr:PasswordMode>false</xr:PasswordMode>') X(f'{indent}\t<xr:DataHistory>Use</xr:DataHistory>') X(f'{indent}\t<xr:MarkNegatives>false</xr:MarkNegatives>') X(f'{indent}\t<xr:MinValue xsi:nil="true"/>') if cfg.get('synonym'): emit_mltext(f'{indent} ', 'xr:Synonym', cfg['synonym']) else: X(f'{indent} <xr:Synonym/>') if cfg.get('comment'): X(f'{indent} <
-
-
SKILL.md 6.1 KB
--- name: 1c-meta-compile description: Создать объект метаданных 1С. Используй когда пользователь просит создать или добавить справочник, документ, регистр, перечисление, константу, общий модуль, обработку, отчет и др. argument-hint: <JsonPath> <OutputDir> allowed-tools: - Bash - Read - Write - Glob --- # /meta-compile - генерация объектов метаданных из JSON DSL Принимает JSON-определение объекта метаданных → генерирует XML + модули в структуре выгрузки конфигурации + регистрирует в Configuration.xml. ## Порядок работы 1. Составь JSON по синтаксису и примерам ниже → запиши во временный файл 2. Запусти скрипт meta-compile 3. Если нужно изменить созданный объект - `/meta-edit` 4. Если нужно проверить - `/meta-validate` ## Команда ```powershell powershell.exe -NoProfile -File skills/1c-meta-compile/scripts/meta-compile.ps1 -JsonPath "<json>" -OutputDir "<ConfigDir>" ``` | Параметр | Описание | |----------|----------| | `JsonPath` | Путь к JSON-файлу (один объект `{...}` или массив `[{...}, ...]`) | | `OutputDir` | Корень выгрузки конфигурации (где `Configuration.xml`, `Catalogs/`, `Documents/` и т.д.) | ## JSON DSL ### Общая структура ```json { "type": "Catalog", "name": "Номенклатура", ...свойства типа... } ``` `type` и `name` - обязательные. `synonym` генерируется из `name` автоматически (CamelCase → слова через пробел). Можно задать явно: `"synonym": "Мой синоним"`. ### Shorthand реквизитов Используется в `attributes`, `dimensions`, `resources`, `tabularSections`: ``` "ИмяРеквизита" → String(10) по умолчанию "ИмяРеквизита: Тип" → с типом "ИмяРеквизита: Тип | req, index" → с флагами ``` Типы: `String(100)`, `Number(15,2)`, `Boolean`, `Date`, `DateTime`, `CatalogRef.Xxx`, `DocumentRef.Xxx`, `EnumRef.Xxx`, `DefinedType.Xxx` и др. ссылочные. Составной тип: `"Значение: String + Number(15,2) + CatalogRef.Контрагенты"`. Флаги: `req`, `index`, `indexAdditional`, `nonneg`, `master`, `mainFilter`, `denyIncomplete`, `useInTotals`. ### Свойства по типам Примеров и shorthand-синтаксиса выше достаточно для типовых задач. Если нужны свойства типа, не показанные в примерах, и их допустимые значения - см. reference-файл: - `reference/types-basic.md` - Catalog, Document, Enum, Constant, DefinedType, Report, DataProcessor - `reference/types-registers.md` - InformationRegister, AccumulationRegister, AccountingRegister, CalculationRegister, ChartOfAccounts, ChartOfCharacteristicTypes, ChartOfCalculationTypes - `reference/types-process.md` - BusinessProcess, Task, ExchangePlan, CommonModule, ScheduledJob, EventSubscription, DocumentJournal - `reference/types-web.md` - HTTPService, WebService - `reference/types-config.md` - CommonAttribute, CommonCommand, CommandGroup, CommonForm, CommonTemplate, CommonPicture, FilterCriterion, Sequence, DocumentNumerator, SessionParameter, SettingsStorage, FunctionalOption, FunctionalOptionsParameter, WSReference Эта инструкция и reference-файлы - полная документация для генерации. Не ищи примеры XML в выгрузках конфигураций. ## Примеры паттернов DSL ### Минимальный объект ```json { "type": "Catalog", "name": "Валюты" } ``` ### С реквизитами ```json { "type": "Catalog", "name": "Организации", "descriptionLength": 100, "attributes": ["ИНН: String(12)", "КПП: String(9)", "Директор: CatalogRef.ФизическиеЛица"] } ``` ### С табличной частью ```json { "type": "Document", "name": "ПриходнаяНакладная", "registerRecords": ["AccumulationRegister.ОстаткиТоваров"], "attributes": ["Организация: CatalogRef.Организации", "Контрагент: CatalogRef.Контрагенты"], "tabularSections": { "Товары": ["Номенклатура: CatalogRef.Номенклатура", "Количество: Number(15,3)", "Цена: Number(15,2)"] } } ``` Табличная часть задается списком колонок либо объектом, если нужен свой синоним: ```json "tabularSections": { "Товары": { "synonym": "Строки заказа", "attributes": ["Номенклатура: CatalogRef.Номенклатура"] } } ``` Поддержаны ключи `attributes`, `synonym` и `comment`. Любой другой ключ навык не применит и скажет об этом предупреждением - молча он их больше не проглатывает. ### Регистровый паттерн (измерения + ресурсы) ```json { "type": "InformationRegister", "name": "КурсыВалют", "periodicity": "Day", "dimensions": ["Валюта: CatalogRef.Валюты | master, mainFilter, denyIncomplete"], "resources": ["Курс: Number(15,4)", "Кратность: Number(10,0)"] } ``` ### Batch - несколько объектов в одном файле ```json [ { "type": "Enum", "name": "Статусы", "values": ["Новый", "Закрыт"] }, { "type": "Catalog", "name": "Валюты" }, { "type": "Constant", "name": "ОсновнаяВалюта", "valueType": "CatalogRef.Валюты" } ] ```
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.