Создать и провести документ
Самый частый сценарий — создать документ, заполнить шапку, добавить строки в табличную часть и провести. Раньше это 40 строк, теперь 8.
// 40 строк, куча служебного кода НовыйДок = Документы.ВыпускПродукцииУслуг .СоздатьДокумент(); НовыйДок.Дата = ТекущаяДата(); НовыйДок.Организация = Орг; НовыйДок.Склад = Склад; НовыйДок.Комментарий = "Загружено из Excel"; НоваяСтрока = НовыйДок.Продукция.Добавить(); НоваяСтрока.Номенклатура = НомСсылка; НоваяСтрока.Количество = 1; НоваяСтрока.Сумма = 3500000; // ... повторить для каждой строки ... НовыйДок.Записать( РежимЗаписиДокумента.Проведение); СсылкаНаДок = НовыйДок.Ссылка;
// Шапка одной строкой Дата = '20260201'; Dok = A1sDocs.Of("ВыпускПродукцииУслуг", A1sDS.Of( "Дата", Дата, "Организация", Орг, "Склад", Склад, "Комментарий", "Загружено из Excel")); // Строка ТЧ одной строкой A1sDocs.AddRow(Dok, "Продукция", A1sDS.Of( "Номенклатура", НомСсылка, "Количество", 1, "Сумма", 3500000)); Ссылка = A1sDocs.Post(Dok);
// ───────────────────────────────────────────────── // Шаг 1: Список квартир — просто строки // ───────────────────────────────────────────────── Квартиры = A1sAR.Of( A1sDS.Of("Название", "Квартира 101", "Площадь", 42.5, "Цена", 3500000), A1sDS.Of("Название", "Квартира 102", "Площадь", 38.0, "Цена", 3100000), A1sDS.Of("Название", "Квартира 103", "Площадь", 55.2, "Цена", 4400000)); // ───────────────────────────────────────────────── // Шаг 2: Создаём документ — шапка одной структурой // ───────────────────────────────────────────────── Dok = A1sDocs.Of("ВыпускПродукцииУслуг", A1sDS.Of( "Дата", '20260201', "Организация", МояОрганизация, // ссылка из переменной "Склад", СкладГотовойПрод, "Комментарий", "Корпус А — февраль 2026")); // ───────────────────────────────────────────────── // Шаг 3: Добавляем строки в ТЧ // AddRowAuto — сам разрешает "Квартира 101" в ссылку // по типу реквизита Номенклатура из метаданных ТЧ // ───────────────────────────────────────────────── Для Каждого Квартира Из Квартиры Цикл A1sDocs.AddRowAuto(Dok, "Продукция", A1sDS.Of( "Номенклатура", Квартира.Название, // строка → ссылка автоматом "Количество", 1, "Сумма", Квартира.Цена)); КонецЦикла; // ───────────────────────────────────────────────── // Шаг 4: Провести — одна строка // ───────────────────────────────────────────────── СсылкаНаВыпуск = A1sDocs.Post(Dok); Сообщить("✓ Выпуск создан: " + СсылкаНаВыпуск);
AddRowAuto: он посмотрит на тип реквизита в метаданных ТЧ и сам вызовет EnsureByType. Если у вас уже есть ссылки — используйте обычный AddRow, это быстрее.Загрузка и синхронизация справочника
Получили Excel с квартирами. Нужно найти существующие и создать те, которых нет. Классика — 60+ строк с обработкой ошибок. Теперь 10.
// ───────────────────────────────────────────────── // Шаг 1: Убедимся, что группа существует // EnsureGroup — найдёт или создаст группу // ───────────────────────────────────────────────── ГрКвартиры = A1sCatalogs.EnsureGroup( "Номенклатура", "Квартиры — корпус А"); // ───────────────────────────────────────────────── // Шаг 2: Для каждой квартиры из Excel: // Ensure = найти по наименованию ИЛИ создать // ───────────────────────────────────────────────── Данные = A1sAR.Of( A1sDS.Of("Наименование", "Квартира 101", "Площадь", 42.5, "Этаж", 3), A1sDS.Of("Наименование", "Квартира 102", "Площадь", 38.0, "Этаж", 3), A1sDS.Of("Наименование", "Квартира 201", "Площадь", 42.5, "Этаж", 4)); Для Каждого Строка Из Данные Цикл Ссылка = A1sCatalogs.Ensure( "Номенклатура", Строка.Наименование, A1sDS.Of( // реквизиты — только при создании "Родитель", ГрКвартиры, "Площадь", Строка.Площадь, "Этаж", Строка.Этаж)); Сообщить(Строка.Наименование + " → " + Ссылка); КонецЦикла;
// Нужны ссылки на номенклатурные группы — просто передаём имена Имена = A1sAR.Of( "ПРОЖИВАНИЕ", "ПИТАНИЕ", "КОММУНАЛЬНЫЕ УСЛУГИ", "ПРОЧИЕ УСЛУГИ"); // EnsureBatch: для каждого имени — найти или создать // Возвращает массив ссылок в том же порядке Ссылки = A1sCatalogs.EnsureBatch( "НоменклатурныеГруппы", Имена); // Результат: массив [Ссылка, Ссылка, Ссылка, Ссылка] // Ссылки[0] = группа "ПРОЖИВАНИЕ" // Ссылки[1] = группа "ПИТАНИЕ" и т.д. ГрПроживание = Ссылки[0]; ГрПитание = Ссылки[1];
// Прайс-лист из внешней системы (например, из JSON) // Задача: обновить цены у существующих, создать новые ПрайсЛист = A1sAR.Of( A1sDS.Of("Наименование", "Квартира 101", "Цена", 3750000, "Площадь", 42.5), A1sDS.Of("Наименование", "Квартира 102", "Цена", 3250000, "Площадь", 38.0), A1sDS.Of("Наименование", "Квартира 305", "Цена", 5100000, "Площадь", 67.0)); // новая! Для Каждого Позиция Из ПрайсЛист Цикл // EnsureUpdate: нашёл → обновит Цену и Площадь; не нашёл → создаст A1sCatalogs.EnsureUpdate( "Номенклатура", Позиция.Наименование, A1sDS.Of( "Цена", Позиция.Цена, "Площадь", Позиция.Площадь, "Родитель", ГрКвартиры)); КонецЦикла; Сообщить("✓ Синхронизировано: " + ПрайсЛист.Количество() + " позиций");
Массовые операции над документами
PostAll, UnpostAll, UpdateAll — провести пачку документов за раз, обновить поле у всех, получить статистику ошибок.
// Шаг 1: Получаем все НЕПРОВЕДЁННЫЕ выпуски за февраль НепроведённыеВыпуски = A1sDocs.AllUnposted( "ВыпускПродукцииУслуг", '20260201', // начало периода '20260228'); // конец периода Сообщить("Найдено непроведённых: " + НепроведённыеВыпуски.Количество()); // Шаг 2: Провести все одной командой // StopOnError = Ложь — продолжать даже если один упадёт Итог = A1sDocs.PostAll(НепроведённыеВыпуски, Ложь); // Шаг 3: Статистика Сообщить("✓ Проведено: " + Итог.Success.Количество()); Сообщить("✗ С ошибками: " + Итог.Failed.Количество()); // Вывести что именно упало Для Каждого ДокСсылка Из Итог.Failed Цикл Сообщить(" Ошибка: " + ДокСсылка); КонецЦикла;
// Все выпуски за 1-й квартал 2026 ВыпускиQ1 = A1sDocs.AllInPeriod( "ВыпускПродукцииУслуг", '20260101', '20260331'); // Переназначить ответственного всем документам разом A1sDocs.UpdateAll( ВыпускиQ1, A1sDS.Of("Ответственный", НовыйОтветственный)); // Можно обновить несколько реквизитов сразу A1sDocs.UpdateAll( ВыпускиQ1, A1sDS.Of( "Комментарий", "Q1 2026 — скорректировано", "Ответственный", НовыйОтветственный));
Fluent-цепочки — код как предложение
Fluent API — это когда каждый метод возвращает обёртку и позволяет вызывать следующий. Читается как инструкция на русском языке.
// Таблица значений уже готова (например, выгрузили из Excel) // ТЗКвартиры содержит колонки: Номенклатура, Количество, Сумма СсылкаНаДок = A1sDocs.On( // создаём обёртку "ВыпускПродукцииУслуг", A1sDS.Of( "Дата", '20260201', "Организация", МояОрг)) .Set("Комментарий", "Квартиры — корпус А") // добавляем реквизит .Set("Склад", СкладГотовой) // ещё один .AddRows("Продукция", ТЗКвартиры) // загружаем ТЧ .Post(); // провести и вернуть ссылку Сообщить("Документ создан: " + СсылкаНаДок);
// Создать элемент справочника шаг за шагом КварталСсылка = A1sCatalogs.On("Номенклатура") .Set("Наименование", "Квартира 401") .Set("Родитель", ГрКвартиры) .Set("Площадь", 48.5) .Set("Этаж", 5) .Write(); Сообщить("Создана: " + КварталСсылка); // Или Fluent для структур — A1sDS.On() // Удобно строить структуру условно Параметры = A1sDS.On() .Set("Организация", МояОрг) .Set("Дата", ТекущаяДата()) .Set("Режим", "Авто") .Done(); // → обычная Структура
Загрузка из JSON — MapRow + EnsureMapByNameQ
Получили JSON из API с наименованиями вместо ссылок. Правильный паттерн: сначала один запрос кэшируем все справочники через EnsureMapByNameQ, затем MapRow декларативно собирает строки — без N+1 запросов.
// JSON из API выглядит так: // [ { "Номенклатура": "Квартира 101", "Единица": "шт", "Количество": 1, "Сумма": 3500000 }, // { "Номенклатура": "Квартира 102", "Единица": "шт", "Количество": 1, "Сумма": 3100000 } ] // ───────────────────────────────────────────────── // ШАГ 1: Pre-fetch кэша (ДО цикла, 1 запрос на каждый справочник) // Собираем уникальные имена из всего пакета сразу // ───────────────────────────────────────────────── ИменаНом = A1sAR.Distinct(A1sAR.Pick(ДанныеJSON, "Номенклатура")); ИменаЕдиниц = A1sAR.Distinct(A1sAR.Pick(ДанныеJSON, "Единица")); // EnsureMapByNameQ: один SQL-запрос → Соответствие {Имя → Ссылка} // Отсутствующие элементы создаются автоматически КэшНом = A1sCatalogs.EnsureMapByNameQ("Номенклатура", ИменаНом); КэшЕдиниц = A1sCatalogs.EnsureMapByNameQ("КлассификаторЕдиницИзмерения", ИменаЕдиниц); // ───────────────────────────────────────────────── // ШАГ 2: Схема маппинга — декларативно, меняем только здесь // Ключ = поле в JSON, Значение = Соответствие-кэш (Map) // ───────────────────────────────────────────────── СхемаМаппинга = A1sDS.Of( "Номенклатура", КэшНом, // строка → ссылка из кэша (O(1)) "Единица", КэшЕдиниц); // строка → ссылка из кэша (O(1)) // ───────────────────────────────────────────────── // ШАГ 3: Создаём документ и загружаем строки // MapRow в цикле только читает из кэша — запросов к БД нет! // ───────────────────────────────────────────────── Dok = A1sDocs.Of("РеализацияТоваровУслуг", A1sDS.Of("Дата", ТекущаяДата(), "Контрагент", КонтрагентСсылка)); Для Каждого СтрокаJSON Из ДанныеJSON Цикл // MapRow: строки → ссылки из кэша, числа/даты — как есть СтрокаДляДока = A1sCatalogs.MapRow(СтрокаJSON, СхемаМаппинга); A1sDocs.AddRow(Dok, "Товары", СтрокаДляДока); КонецЦикла; Ссылка = A1sDocs.Post(Dok);
Ensure на каждую строку — 1000 строк × 2 справочника = 2000 запросов.
С EnsureMapByNameQ до цикла — ровно 2 запроса на весь пакет, независимо от его размера.
// После загрузки 20 документов нужно поставить статус "Сдан" // всем квартирам, которые упоминаются в документах Для Каждого ДокСсылка Из ЗагруженныеДокументы Цикл // Собираем уникальные ссылки на номенклатуру из ТЧ "Продукция" НоменклатураВДоке = A1sCatalogs.PickFromDocument( ДокСсылка, "Продукция", "Номенклатура"); // Всем найденным — поставить статус и этап строительства A1sCatalogs.UpdateAll( НоменклатураВДоке, A1sDS.Of( "Статус", ПредопрСтатус.Сдан, "ЭтапСтроительства", ЭтапСдан)); КонецЦикла;
Поиск и анализ
Найти документ по номеру, проверить существование, получить реквизиты одним запросом без открытия объекта.
// Найти выпуск по номеру ВыпускСсылка = A1sDocs.ByNumber( "ВыпускПродукцииУслуг", "ВП-000042"); Если НЕ ЗначениеЗаполнено(ВыпускСсылка) Тогда Сообщить("Документ не найден"); Возврат; КонецЕсли; // Получить нужные реквизиты ОДНИМ ЗАПРОСОМ — без открытия объекта Реквизиты = A1sDocs.Details( ВыпускСсылка, "Организация, Склад, Комментарий, Ответственный"); Сообщить("Организация: " + Реквизиты.Организация); Сообщить("Комментарий: " + Реквизиты.Комментарий); Сообщить("Проведён: " + A1sDocs.IsPosted(ВыпускСсылка)); // Поиск по реквизиту — найти первый выпуск с нужной организацией ПервыйВыпуск = A1sDocs.ByAttr( "ВыпускПродукцииУслуг", "Организация", МояОрганизация); // Запрос с произвольным WHERE — без написания запроса вручную ВыпускиСклада = A1sDocs.Refs( "ВыпускПродукцииУслуг", "Склад = &Склад И Дата >= &НачалоМесяца", A1sDS.Of( "Склад", МойСклад, "НачалоМесяца", '20260201'));
// ───────────────────────────────────────────────── // Задача: подготовить кэш перед загрузкой пакета данных. // EnsureMapByNameQ = найти ИЛИ создать + вернуть Map // Результат: Соответствие {Имя → Ссылка} // ───────────────────────────────────────────────── СписокГрупп = A1sAR.Of( "ПРОЖИВАНИЕ", "ПИТАНИЕ", "ПРОЧИЕ УСЛУГИ"); // Один запрос к БД на весь пакет. // Группы, которых нет — будут созданы автоматически. МапГрупп = A1sCatalogs.EnsureMapByNameQ( "НоменклатурныеГруппы", СписокГрупп); // Доступ по имени — O(1), без дополнительных запросов ГрПроживание = МапГрупп["ПРОЖИВАНИЕ"]; ГрПитание = МапГрупп["ПИТАНИЕ"]; // ───────────────────────────────────────────────── // Типичный паттерн: собрать уникальные имена из пакета, // передать в EnsureMapByNameQ — классика любых загрузок // ───────────────────────────────────────────────── ВсеИменаЕдиниц = A1sAR.Distinct( A1sAR.Pick(ДанныеИмпорта, "unit_name")); // ["шт", "кг", "м²"] КэшЕдиниц = A1sCatalogs.EnsureMapByNameQ( "КлассификаторЕдиницИзмерения", ВсеИменаЕдиниц); Для Каждого Строка Из ДанныеИмпорта Цикл // В цикле — только обращение к кэшу, запросов к БД нет Единица = КэшЕдиниц[Строка.unit_name]; // мгновенно КонецЦикла;
PickByName — стало EnsureMapByNameQ.
Старый PickByName только искал и возвращал Неопределено для отсутствующих.
EnsureMapByNameQ гарантирует: каждый ключ в Map будет заполнен ссылкой — отсутствующие элементы создаются.
Если нужен режим «только чтение» без создания — используйте FindMapByNameQ (пример ниже).
// Задача: проверить, есть ли уже эти контрагенты в базе. // НЕ создаём — только читаем. Нет в базе → не будет в Map. ИменаКА = A1sAR.Of( "ООО Ромашка", "ИП Иванов", "АО Незнакомец"); // этого нет в базе // FindMapByNameQ: 1 запрос, только найденные попадут в Map МапКА = A1sCatalogs.FindMapByNameQ( "Контрагенты", ИменаКА); // Разбить на найденные и не найденные Для Каждого Имя Из ИменаКА Цикл Если МапКА.Получить(Имя) <> Неопределено Тогда Сообщить("✓ Найден: " + Имя); Иначе Сообщить("✗ Не найден: " + Имя); КонецЕсли; КонецЦикла; // Итог: "✓ Найден: ООО Ромашка", "✓ Найден: ИП Иванов" // "✗ Не найден: АО Незнакомец" ← не создан, просто отсутствует
EnsureMapByNameQ — при загрузке данных (справочники должны существовать, создаём недостающие).
FindMapByNameQ — при валидации и проверке (нужно знать, что уже есть, ничего не создаём).
Структуры и массивы как инструмент
A1sDS и A1sAR — фундамент всей библиотеки. Несколько мощных паттернов для работы с данными.
// Список из формы может содержать пустые значения и дубликаты СырыеДанные = A1sAR.Of( Ном1, Неопределено, Ном2, Ном1, Неопределено, Ном3); // Очистить: убрать пустые и дубликаты ЧистыйМассив = A1sAR.PickFilled( // → убрать пустые A1sAR.RemoveDuplicates(СырыеДанные)); // → убрать дубликаты // Результат: [Ном1, Ном2, Ном3] // Объединить несколько массивов в один уникальный ВсяНоменклатура = A1sAR.Concatenate( НомДокумент1, НомДокумент2, НомДокумент3, /*ТолькоУникальные =*/ Истина); // Разбить массив на порции по 100 — для пакетной загрузки Порции = A1sAR.Chunk(ВсяНоменклатура, 100); Для Каждого Порция Из Порции Цикл // ... обработать порцию ... КонецЦикла; // Получить только первый и последний — без доступа по индексу Первый = A1sAR.First(ВсяНоменклатура); Последний = A1sAR.Last(ВсяНоменклатура); // Склеить имена в строку через запятую (для сообщений) ИменаВСтрочку = A1sAR.Join( A1sAR.Of("Квартира 101", "Квартира 102", "Квартира 103"), ", "); // Результат: "Квартира 101, Квартира 102, Квартира 103"
// Значения по умолчанию + пользовательские данные // Defaults заполняет только ОТСУТСТВУЮЩИЕ ключи Умолчания = A1sDS.Of( "Валюта", "RUB", "НДС", Истина, "Проводить", Истина); ДанныеПользователя = A1sDS.Of( "Валюта", "USD", // переопределяем "Режим", "Авто"); // новый ключ Итоговые = A1sDS.Defaults(ДанныеПользователя, Умолчания); // Итог: {Валюта:"USD", Режим:"Авто", НДС:Истина, Проводить:Истина} // Переименовать поля (например, API возвращает другие имена) ДанныеAPI = A1sDS.Of("name", "Квартира 101", "price", 3500000); Переименовано = A1sDS.Rename( ДанныеAPI, A1sDS.Of("name", "Наименование", "price", "ЦенаПродажи")); // Итог: {Наименование:"Квартира 101", ЦенаПродажи:3500000} // Выбрать только нужные поля из большой структуры ТолькоНужные = A1sDS.Pick(БольшаяСтруктура, "Дата, Организация, Сумма"); // Проверить что все обязательные поля заполнены Если НЕ A1sDS.HasKeys(Данные, "Организация, Склад, Дата") Тогда ВызватьИсключение "Не заполнены обязательные поля"; КонецЕсли;
Fluent Logging — логирование внутри цепочки
Новый Boilerplate в A1sDP_Catalogs и A1sDP_Docs: методы .Comment(), .LogInfo(), .LogError() встраиваются прямо в Fluent-цепочку. Код не просто пишет данные — он описывает историю того, что делает.
ShowComment() — выводятся пользователю, при LogComment() — пишутся в Журнал Регистрации.// Было: логирование отдельными строками вне цепочки // Стало: комментарий встроен туда, где происходит действие A1sCatalogs.OnRef(СсылкаНоменклатуры) .Comment("Начало обновления штрихкодов") // накапливается в буфере .ClearRows("Штрихкоды") .Comment("Очищены старые коды") // добавляется через "; " .LoadTabRows("Штрихкоды", ТоварИзJSON.barcodes) .Comment("Загружено " + ТоварИзJSON.barcodes.Количество() + " кодов") .ShowComment() // → сообщение пользователю .Write(); // Вывод: "[Номенклатура] Ноутбук Pro: Начало обновления штрихкодов; // Очищены старые коды; Загружено 2 кодов" // Если нужен тихий режим — только в Журнал Регистрации A1sCatalogs.OnRef(СсылкаНоменклатуры) .Comment("Синхронизация цены: " + НоваяЦена) .Set("Цена", НоваяЦена) .LogComment() // → A1sLog.Info (ЖР, без окна) .Write();
Comment, эти методы пишут в Журнал Регистрации сразу — не накапливая. Идеально для диагностики и аудита операций.// Пример 1: Тихое логирование — только ЖР, без окна пользователя A1sCatalogs.On("Номенклатура") .Set("Наименование", "Товар из API") .Set("Артикул", "API-001") .LogInfo("Создание нового товара из внешнего API") // → ЖР, уровень Info .Write(); // Пример 2: Предупреждение — цена подозрительно низкая Если НоваяЦена < 1000 Тогда A1sCatalogs.OnRef(СсылкаТовар) .Set("Цена", НоваяЦена) .LogWarning("Аномально низкая цена: " + НоваяЦена) // → ЖР, уровень Warn .Write(); КонецЕсли; // Пример 3: Обработка ошибки в Попытка/Исключение Попытка A1sDocs.On("РеализацияТоваровУслуг", A1sDS.Of("Контрагент", КА, "Дата", ТекущаяДата())) .AddRows("Товары", Строки) .LogInfo("Создание реализации для: " + КА) .Post(); Исключение // Логируем ошибку прямо там — не теряем контекст A1sDocs.On("РеализацияТоваровУслуг") .LogError("Ошибка создания реализации: " + ОписаниеОшибки()); // → ЖР, уровень Error КонецПопытки;
.Comment() накапливает текст в буфере — выводится только при явном ShowComment() или LogComment().
.LogInfo() / .LogWarning() / .LogError() пишут в A1sLog немедленно, без буферизации.
Используйте Comment для составных операций, Log — для событий с однозначным моментом возникновения.
A1sCatalogs.OnRef(Ссылка) .ClearRows("Штрихкоды") .LoadTabRows("Штрихкоды", Данные) .Write(); // Отдельно, после цепочки :( Сообщить("Обновлено: " + Ссылка); A1sLog.Info("Номенклатура", "Штрихкоды обновлены");
A1sCatalogs.OnRef(Ссылка) .ClearRows("Штрихкоды") .Comment("Старые коды очищены") .LoadTabRows("Штрихкоды", Данные) .Comment("Загружено: " + N) .LogComment() // → ЖР .ShowComment() // → пользователю .Write();
Сквозная синхронизация — эталонный пример
Полный production-ready пример: загрузка каталога из JSON, кэширование справочников через EnsureMapByNameQ, Upsert через EnsureUpdate с AutoResolve, загрузка штрихкодов через Fluent-цепочку с логированием. Объединяет все техники на одном сценарии.
// ========================================================================= // Функция: ВыполнитьСинхронизациюНоменклатуры // Паттерн: Batch-Cache → Upsert(AutoResolve) → Fluent TabRows → Log // ========================================================================= &AtServer Функция ВыполнитьСинхронизацию(ДанныеИмпорта) Экспорт // ───────────────────────────────────────────────── // 1. PRE-FETCH КЭША (1 запрос на справочник, ДО цикла) // Горячие ссылки (группы, единицы) — через Map: максимальная скорость // Динамические поля (виды, НДС) — через AutoResolve: максимальное удобство // ───────────────────────────────────────────────── ИменаГрупп = A1sAR.Distinct(A1sAR.Pick(ДанныеИмпорта, "group_name")); ИменаЕдиниц = A1sAR.Distinct(A1sAR.Pick(ДанныеИмпорта, "unit_name")); // EnsureMapByNameQ: создаёт отсутствующие + возвращает Map за 1 запрос КэшГрупп = A1sCatalogs.EnsureMapByNameQ("НоменклатурныеГруппы", ИменаГрупп); КэшЕдиниц = A1sCatalogs.EnsureMapByNameQ("КлассификаторЕдиницИзмерения", ИменаЕдиниц); // ───────────────────────────────────────────────── // 2. ОСНОВНОЙ ЦИКЛ — Upsert с гибридным подходом // ───────────────────────────────────────────────── Статистика = A1sDS.Of("Обновлено", 0, "Ошибок", 0); Для Каждого Товар Из ДанныеИмпорта Цикл Попытка // Горячие поля — из кэша (O(1), без запросов) // Строковые поля — оставляем строками (AutoResolve разберёт) ДанныеТовара = A1sDS.Of( "Родитель", КэшГрупп[Товар.group_name], // ссылка из кэша "ЕдиницаИзмерения", КэшЕдиниц[Товар.unit_name], // ссылка из кэша "ВидНоменклатуры", Товар.type_name, // строка → AutoResolve "СтавкаНДС", Товар.vat_rate, // строка → AutoResolve "Цена", Товар.price, "Артикул", Товар.articul); // EnsureUpdate: нашёл → обновит; не нашёл → создаст // Параметр Истина, Истина = точное совпадение + AutoResolve строк Ссылка = A1sCatalogs.EnsureUpdate( "Номенклатура", Товар.name, ДанныеТовара, Истина, // точное совпадение имени Истина); // AutoResolve строковых полей // Fluent-обновление штрихкодов с Logging // ClearRows → LoadTabRows → Comment → Write Если Товар.Свойство("barcodes") И Товар.barcodes.Количество() > 0 Тогда A1sCatalogs.OnRef(Ссылка) .ClearRows("Штрихкоды") .LoadTabRows("Штрихкоды", Товар.barcodes) .Comment("Штрихкодов: " + Товар.barcodes.Количество()) .LogComment() // в ЖР — тихо, без окна пользователя .Write(); КонецЕсли; Статистика.Обновлено = Статистика.Обновлено + 1; Исключение // Fail-Safe: один кривой товар не ломает весь импорт A1sLog.Error("Синхронизация", "Ошибка: " + Товар.name + " | " + ОписаниеОшибки()); Статистика.Ошибок = Статистика.Ошибок + 1; КонецПопытки; КонецЦикла; Сообщить("✓ Обновлено: " + Статистика.Обновлено + ", ошибок: " + Статистика.Ошибок); Возврат Статистика; КонецФункции