---
name: onec-epf-skill
description: "Скилл 1c-epf — работа с внешними обработками/отчётами 1С (.epf/.erf), правка форм через v8unpack"
metadata: 
  node_type: memory
  type: reference
  originSessionId: ab4d9c44-f319-4b54-9c25-7bc595137110
  modified: 2026-08-03T13:50:20.958Z
---

Скилл **`1c-epf`** (`~/.claude/skills/1c-epf/`) — работа с внешними обработками/отчётами 1С (.epf/.erf) пользователя (Бурдуков С.Ю) и конфигурацией «НоваяКонфа».

- Файлы: обработки в `~/Downloads/ОбработкиЭкспорт/` (Finder «Загрузки»=Downloads; `~/Загрузки` НЕ существует), конфиг в `НоваяКонфа/`.
- `tools/epf.sh` (unpack/pack/**roundtrip** обязательный diff), `tools/form_inspect.py` (props/tree/data, --buttons, --readonly триангуляция), `tools/form_edit.py` (add-attribute из образца, set-table-readonly, set-flag). Формат формы = валидный JSON v8unpack, правим программно через Python (v8unpack принимает redump без потерь).
- **ОБЪЕКТНЫЕ метаданные** (ТЧ, типы, имя): `tools/obj_edit.py` — `attrs` (имя/binding-uuid/тип), `typeid НоваяКонфа Catalog.X` (TypeId), `retype --uuid --name --syn --type ref:<TypeId>|bool|string|number` (перетипизация колонки ТЧ ПО МЕСТУ, binding-uuid сохраняется → колонка формы следует сама; примитив→ссылку клонирует образец, ищет в соседних обработках), `rename` (имя во всём файле+header). **Команды/кнопки**: `tools/form_cmd.py` — `list`, `set-title`, `add-cmd` (+нужна одноимённая &НаКлиенте процедура), `rebind` (перевязать кнопку, напр. встроенную сортировку, на форменную команду). Формат и грабли — `reference/object_metadata.md`.
- **Грабли (важно):** имя+синоним обработки живут в бинарном `header`; поля `name`/`name2` в JSON ПРОИЗВОДНЫЕ — пакер игнорит, правка не переживёт pack→unpack (правь через obj_edit rename). Колонку формы НЕ добавляй вслепую (состав ТЧ размазан) — перетипизируй существующие. Известный безобидный шум round-trip: пере-вывод поля name реквизита формы из raw.
- Маркеры правок только в .bsl: `//+ Бурдуков С.Ю <дата> DEVACC-<n>` / `//-` (1 строка/процедура → только `//+`; блок → оба). В формах маркеров нет.
- macOS TCC: доступ к ~/Downloads даёт Full Disk Access вложенному `com.anthropic.claude-code` (`~/Library/Application Support/Claude/claude-code/<вер>/claude.app`), НЕ `/Applications/Claude.app`.
- Кейс DEVACC-723 (аСверкаРеестровыхКомпаний): кнопка общей команды «Связанные документы» не появлялась из-за привязки параметра к несуществующему реквизиту id 5 → добавил реквизит + снял «Только просмотр» таблицы (index 36). Инструменты воспроводят фикс байт-в-байт. Детали — `examples/` и `reference/elem_json_format.md`.
- **Сборка «с нуля» — предпочтительно XML-выгрузка + платформа** (не ручной v8unpack), особенно когда нужен свой набор колонок ТЧ: авторишь человекочитаемый XML (`Имя.xml` + `Имя/Forms/Форма/Ext/Form.xml` + `Module.bsl` + `Ext/ObjectModule.bsl`), zip питоном (**обязательно `unicodedata.normalize("NFC", arcname)` для кириллических имён + исключить `.bak`** — иначе macOS пишет NFD, корневой XML ссылается на NFC и 1С отвечает 422 «Файл объекта не существует»; CLI `zip` для этого НЕ годится), `POST /build?uid=1005954706` (база `ib_u<uid>/.ready` с конфой юзера; без uid ссылки CatalogRef.* не разрешатся). HTTP 200=готовый .epf (ground truth), 422=log Конфигуратора. Рецепт+формат — `reference/xml_build_from_scratch.md`, болванка-генератор — `examples/gen_xml_epf_from_scratch.py`, эталон структуры — `аСверкаРеестровыхКомпаний` (.xml+каталог). Цвет кнопки `<BackColor>#RRGGBB</BackColor>` round-trip'ит (в v8unpack хранится BGR-int: #70AD47→4697456). Выверено: `ИсправлениеСчетаРасчетовАгентскихУслуг` (11.06.2026, 7 колонок, зелёная кнопка, связь Пост↔Реал через ЗаказПокупателя).
- **Сверять имена полей с актуальной `НоваяКонфа/Documents/*.xml`** перед опорой на старый код: поля переименовываются (агентское `СчетУчетаРасчетовСАгентом` → ныне `СчетРасчетов`, тип `ChartOfAccountsRef.Хозрасчетный`; синоним «Счет расчетов»). Связь Поступление↔Реализация — через `ЗаказПокупателя` (Поступление.Сделка/Услуги.ДокументЗаказ ↔ СчётНаОплату.ЗаказПокупателя ↔ Реализация.Услуги.СчётНаОплатуПокупателю), НЕ через Основание.
- Проверка: headless batch-агентом (порт 8788, SKILL.md §6) — сборка + log Конфигуратора. **Визуальный GUI 1С на маке НЕ открывать** (см. [[onec-no-visual-1c]]); интерактивный UI смотрит пользователь. form_cmd.py button-printer чинен (не падает на платформенных формах, но для них источник истины — XML, не v8unpack).
- **Привязка события таблицы** (кнопка «Связанные документы» по активной ячейке): блок событий в raw '55' = ['1',event-guid,'"<Таблица>ПриАктивизацииЯчейки"','1','0',event-guid,'0','1'] (guid Ячейки=f228b12f, Строки=60edb81d). НЕЛЬЗЯ вставлять новым элементом (v8unpack выкинет) — ЗАМЕНИТЬ пустой слот ['0'] перед командной панелью; искать слот перебором замен + semantic roundtrip. Обработчик берёт док активной ячейки. Кейс аСверка слот ot[58].
- **«Только просмотр» бывает ПОЛЕ-уровневым**: флаг [14] колонки '37' (1=просмотр,0=редакт.), найден сравнением редактируемого поля-фильтра с колонкой сетки. `form_edit.py set-fields-readonly --table T --value 0` (ищет колонки по сегменту /<table>/, поддерживает вложенные таблицы). Табличный [36] — отдельный аспект. Кейс аСверка: сетка аДокументы 7 колонок [14]=1→0.
- **`obj_edit.py rename --syn` баг (03.08.2026, кейс РеализацияУслугиПоступлениеБайко):** команда пишет новый синоним ТОЛЬКО в производное поле `name2` — реальную строку синонима внутри `header` НЕ трогает. После pack→unpack синоним откатывается на старый (round-trip ловит как `VALUE DIFF at /name2/ru`). Лечение: найти путь до строки-литерала синонима в `header` вручную (`walk()` по распарсенному JSON, искать `"<старый синоним>"` — именно в кавычках-как-часть-строки, это токен вида `"\"Текст\""`) и заменить точечно тем же способом, что делает `rename` для Имени (там замена по всем вхождениям токена работает верно, только для Имени, не для Синонима). Плюс не забыть: строковые self-reference на СТАРОЕ техническое Имя в .bsl-модулях (`ПолучитьСсылкуНаОбработку("Имя")`, `"ВнешняяОбработка.Имя"` в параметрах выполнения, `ДобавитьКоманду(..., "Имя", ...)`) — `obj_edit rename` их не видит вообще, это отдельный `grep -rn "СтароеИмя"` по `*.obj.bsl`/`Form/*/*.bsl` после rename, руками через маркеры.
- **Поле «Версия» в `СведенияОВнешнейОбработке()`** (правило юзера, на будущее, во ВСЕХ внешних обработках): держать равным ТЕКУЩЕЙ дате правки, формат `ДД.ММ.ГГГГ.NN` (NN — номер ревизии за день, начиная с 01), как уже принято в остальных обработках юзера. При любой правке обработки — обновлять эту строку на сегодня, не только при явном запросе.
