Клиент несколько лет пользовался УТ 11.5, при этом никто ему не объяснил, как ей пользоваться - не делалось никогда закрытие месяца. А главное, у клиента вообще нет производства и УТ ему, в общем-то, не была и нужна, изначально - просто небольшая торговля на маркетплейсах и мечты об интернет-магазине.
Поэтому, когда он изрядно намучился (в течение нескольких лет делая "корректировки" неправильных остатков с помощью накладных, например!) и обратился к профессионалам, он уже успел накопить "хвостов" в товароучете - причем, одна и та же позиция "гуляла" по одному регистру на одно количество, по другому на другое, по третьему на третье и т.д. Бюджет на исправление всех бед был невелик, так что было принято волевое решение, с помощью документа КорректировкаРегистров, просто закрыть остатки, по всем(!) регистрам товароучета, в ноль, потом сделать приход и продолжать торговлю на радость покупателям (подчеркну - у клиента нет потребности во всяких там расчетах с/с, распределения доходов/расходов и прочих плюшках - "надо просто продать товар").
Список проблемных позиций был у заказчика "на карандаше" - поэтому, запрос к ИИ-агентам (на сайте ресурса есть лаконичные инструкции, здесь не буду на этом останавливаться) был простой:
Сделай новую внешнюю обработку.
На ее форме должна быть таблица "Товары", с колонками "Номенклатура" и "Характеристика".
Результатом обработки должен быть документ "КорректировкаРегистров".
На форме должна быть кнопка команды "Закрыть остатки". По нажатию этой кнопки, по каждому регистру накопления, у которого есть измерение "Номенклатура", для всех товаров строк таблицы "Товары", должен сформироваться запрос по остаткам, и с помощью этого запроса заполниться строки документа "КорректировкаРегистров".
В итоге, этот документ должен закрыть все остатки в базе, по всем регистрам накопления, для всех строк таблицы "Товары".

После небольшого раздумья, помощник задал пару уточняющих вопросов, и, получив на них ответы приступил к работе. Прошло минут 10 и... Облом.

Баг-репорт в техподдержку отправится в ближайшее свободное время; а пока, делаем финт ушами - прошу ВСЁ делать программно; и, еще несколько минут, - и вуаля:

Скачиваю обработку, открываю сразу в УТ 11.5, сразу же ловлю сообщение про отсутствующую функцию Абс(), немного препираюсь с ИИ-помощником (еще он оказался немного забывчив - кнопку сделал, а команду забыл; кроме того, он не связал событие формы ПриСозданииНаСервере с процедурой - сделал это вручную) - и, наконец, получаю результат, который тут же, на тестовой базе, дает мне то что я хотел:



Созвон с клиентом, запуск на рабочей базе, обсуждение планов про интернет-магазин (пока обработка делает свое дело), совместная проверка результата. Все ок.
..........................................
Если кто захочет оценить качество кода (руками я только связал событие формы ПриСозданииНаСервере с процедурой, а также закомментировал ТолькоПросмотр = Истина, для реквизита СозданныйДокумент), или воспользоваться разработкой (просто создаем пустую обработку с формой, кидаем в модуль формы код, не забываем про связь события формы с процедурой - и вперед) - пожалуйста:
// Консоль AL 02.09.2026 — программное создание реквизитов и элементов формы
#Область ОбработчикиСобытийФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ДобавляемыеРеквизиты = Новый Массив;
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ДатаОстатков", Новый ОписаниеТипов("Дата", Новый КвалификаторыДаты(ЧастиДаты.Дата))));
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("Товары", Новый ОписаниеТипов("ТаблицаЗначений")));
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Товары"));
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("Характеристика", Новый ОписаниеТипов("СправочникСсылка.ХарактеристикиНоменклатуры"), "Товары"));
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("СозданныйДокумент", Новый ОписаниеТипов("ДокументСсылка.КорректировкаРегистров")));
ИзменитьРеквизиты(ДобавляемыеРеквизиты);
ЭтаФорма.ДатаОстатков = ТекущаяДата();
ЭтаФорма.Товары.Загрузить(Новый ТаблицаЗначений);
ПолеДата = Элементы.Добавить("ДатаОстатков", Тип("ПолеФормы"));
ПолеДата.Вид = ВидПоляФормы.ПолеВвода;
ПолеДата.ПутьКДанным = "ДатаОстатков";
Заголовок = "Дата остатков";
ТаблицаТоваров = Элементы.Добавить("Товары", Тип("ТаблицаФормы"));
ТаблицаТоваров.ПутьКДанным = "Товары";
ПолеНоменклатура = Элементы.Добавить("ТоварыНоменклатура", Тип("ПолеФормы"), ТаблицаТоваров);
ПолеНоменклатура.Вид = ВидПоляФормы.ПолеВвода;
ПолеНоменклатура.ПутьКДанным = "Товары.Номенклатура";
ПолеХарактеристика = Элементы.Добавить("ТоварыХарактеристика", Тип("ПолеФормы"), ТаблицаТоваров);
ПолеХарактеристика.Вид = ВидПоляФормы.ПолеВвода;
ПолеХарактеристика.ПутьКДанным = "Товары.Характеристика";
НоваяКоманда = Команды.Добавить("ЗакрытьОстатки");
НоваяКоманда.Заголовок = "Закрыть остатки";
НоваяКоманда.Действие = "ЗакрытьОстатки";
КнопкаЗакрытия = Элементы.Добавить("ЗакрытьОстатки", Тип("КнопкаФормы"));
КнопкаЗакрытия.Вид = ВидКнопкиФормы.ОбычнаяКнопка;
КнопкаЗакрытия.Заголовок = "Закрыть остатки";
КнопкаЗакрытия.ИмяКоманды = "ЗакрытьОстатки";
ПолеДокумента = Элементы.Добавить("СозданныйДокумент", Тип("ПолеФормы"));
ПолеДокумента.Вид = ВидПоляФормы.ПолеВвода;
ПолеДокумента.ПутьКДанным = "СозданныйДокумент";
ПолеДокумента.КнопкаВыбора = Истина;
//ПолеДокумента.ТолькоПросмотр = Истина;
КонецПроцедуры
#КонецОбласти
#Область Команды
&НаКлиенте
Процедура ЗакрытьОстатки(Команда)
Если ЭтаФорма.Товары.Количество() = 0 Тогда
Сообщить("Добавьте хотя бы один товар.");
Возврат;
КонецЕсли;
СозданныйДокумент = ЗакрытьОстаткиНаСервере();
Если ЗначениеЗаполнено(СозданныйДокумент) Тогда
ЭтаФорма.СозданныйДокумент = СозданныйДокумент;
ОткрытьЗначение(СозданныйДокумент);
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ЗакрытьОстаткиНаСервере()
МассивТоваров = Новый Массив;
Для Каждого СтрокаТовара Из ЭтаФорма.Товары Цикл
Если ЗначениеЗаполнено(СтрокаТовара.Номенклатура) И МассивТоваров.Найти(СтрокаТовара.Номенклатура) = Неопределено Тогда
МассивТоваров.Добавить(СтрокаТовара.Номенклатура);
КонецЕсли;
КонецЦикла;
Если МассивТоваров.Количество() = 0 Тогда
Сообщить("В таблице нет заполненной номенклатуры.");
Возврат Неопределено;
КонецЕсли;
ДокументКорректировки = Документы.КорректировкаРегистров.СоздатьДокумент();
ДокументКорректировки.Дата = КонецДня(ЭтаФорма.ДатаОстатков);
ДокументКорректировки.Операция = Перечисления.ОперацииКорректировкиРегистров.РучнаяКорректировка;
ДокументКорректировки.Комментарий = "Закрытие остатков по товарам на " + Формат(ЭтаФорма.ДатаОстатков, "ДФ=dd.MM.yyyy");
КоличествоДвижений = 0;
Для Каждого МетаданноеРегистра Из Метаданные.РегистрыНакопления Цикл
Если МетаданноеРегистра.ВидРегистра = Метаданные.СвойстваОбъектов.ВидРегистраНакопления.Обороты Тогда
Продолжить;
КонецЕсли;
Если МетаданноеРегистра.Измерения.Найти("Номенклатура") = Неопределено Тогда
Продолжить;
КонецЕсли;
Если ДокументКорректировки.Движения.Найти(МетаданноеРегистра.Имя) = Неопределено Тогда
Продолжить;
КонецЕсли;
КоличествоДвижений = КоличествоДвижений + ЗаполнитьДвиженияРегистра(ДокументКорректировки, МетаданноеРегистра, МассивТоваров);
КонецЦикла;
Если КоличествоДвижений = 0 Тогда
Сообщить("Ненулевые остатки по указанным товарам не найдены.");
Возврат Неопределено;
КонецЕсли;
ДокументКорректировки.Записать(РежимЗаписиДокумента.Запись);
Возврат ДокументКорректировки.Ссылка;
КонецФункции
&НаСервере
Функция ЗаполнитьДвиженияРегистра(ДокументКорректировки, МетаданноеРегистра, МассивТоваров)
Поля = Новый Массив;
Для Каждого Измерение Из МетаданноеРегистра.Измерения Цикл
Поля.Добавить("Остатки." + Измерение.Имя + " КАК " + Измерение.Имя);
КонецЦикла;
Для Каждого Ресурс Из МетаданноеРегистра.Ресурсы Цикл
Поля.Добавить("Остатки." + Ресурс.Имя + "Остаток КАК " + Ресурс.Имя);
КонецЦикла;
ТекстЗапроса = "ВЫБРАТЬ
| " + СтрСоединить(Поля, "," + Символы.ПС + " ") + "
|ИЗ
| РегистрНакопления." + МетаданноеРегистра.Имя + ".Остатки(&МоментОстатков, Номенклатура В (&Товары)) КАК Остатки";
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("МоментОстатков", НачалоДня(ЭтаФорма.ДатаОстатков + 24 * 60 * 60));
Запрос.УстановитьПараметр("Товары", МассивТоваров);
Остатки = Запрос.Выполнить().Выгрузить();
НаборДвижений = ДокументКорректировки.Движения[МетаданноеРегистра.Имя];
НаборДвижений.Записывать = Истина;
КоличествоДвижений = 0;
Для Каждого СтрокаОстатков Из Остатки Цикл
Для Каждого Ресурс Из МетаданноеРегистра.Ресурсы Цикл
ЗначениеРесурса = СтрокаОстатков[Ресурс.Имя];
Если ЗначениеРесурса = 0 Тогда
Продолжить;
КонецЕсли;
Движение = НаборДвижений.Добавить();
Движение.Период = КонецДня(ЭтаФорма.ДатаОстатков);
Движение.ВидДвижения = ?(ЗначениеРесурса > 0, ВидДвиженияНакопления.Расход, ВидДвиженияНакопления.Приход);
Для Каждого Измерение Из МетаданноеРегистра.Измерения Цикл
Движение[Измерение.Имя] = СтрокаОстатков[Измерение.Имя];
КонецЦикла;
Движение[Ресурс.Имя] = АбсолютноеЗначение(ЗначениеРесурса); // Консоль AL 02.09.2026 — замена отсутствующей функции Абс
КоличествоДвижений = КоличествоДвижений + 1;
КонецЦикла;
КонецЦикла;
Если КоличествоДвижений > 0 Тогда
СтрокаРегистра = ДокументКорректировки.ТаблицаРегистров.Добавить();
СтрокаРегистра.Имя = МетаданноеРегистра.Имя;
КонецЕсли;
Возврат КоличествоДвижений;
КонецФункции
// Консоль AL 02.09.2026 — абсолютное значение числа
&НаСервере
Функция АбсолютноеЗначение(Значение)
Если Значение < 0 Тогда
Возврат -Значение;
КонецЕсли;
Возврат Значение;
КонецФункции
// Конец Консоль AL
#КонецОбласти
// Конец Консоль AL
Ах, да, чуть не забыл - мне не пригодилось, но раз уж ИИ любезно предоставил, то и я делюсь - в модуле формы он сделал заготовку для БСП-механизма доп. обработок (кому надо, дописать нужное):
////////////////////////////////////////////////////////////////////////////////
// БСП: «Дополнительные отчёты и обработки».
// Каркас обработки, готовый к регистрации в одноимённом справочнике конфигурации
// на базе Библиотеки стандартных подсистем (БСП 3.x).
#Область ПрограммныйИнтерфейс
// Возвращает сведения о внешней обработке для регистрации в подсистеме БСП
// «Дополнительные отчёты и обработки».
//
// Возвращаемое значение:
// Структура - параметры регистрации обработки:
// * Вид - Строка - вид обработки, см. ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработки*().
// * Назначение - Массив - полные имена объектов метаданных, к которым относится обработка
// (например, "Документ.ЗаказКлиента"). Пусто - обработка для всей конфигурации.
// * Команды - ТаблицаЗначений - команды обработки (Представление, Идентификатор, Использование).
// * Версия - Строка
// * Наименование - Строка
// * Информация - Строка
// * БезопасныйРежим - Булево
//
Функция СведенияОВнешнейОбработке() Экспорт
МетаданныеОбъекта = Метаданные();
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке(
СтандартныеПодсистемыСервер.ВерсияБиблиотеки());
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Наименование = МетаданныеОбъекта.Синоним;
ПараметрыРегистрации.Версия = "1.0.0";
ПараметрыРегистрации.Информация = НСтр("ru = 'Заготовка дополнительной обработки.'");
ПараметрыРегистрации.БезопасныйРежим = Истина;
// Назначение - к каким объектам конфигурации применима обработка. Пусто = вся конфигурация.
// ПараметрыРегистрации.Назначение.Добавить("Документ.<ИмяДокумента>");
// Команды.
Команда = ПараметрыРегистрации.Команды.Добавить();
Команда.Представление = МетаданныеОбъекта.Синоним;
Команда.Идентификатор = "ОсновнаяКоманда";
Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
Команда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
// Точка входа БСП для команд с типом «ВызовСерверногоМетода» / «ВызовКлиентскогоМетода».
//
// Параметры:
// ИдентификаторКоманды - Строка - значение Команда.Идентификатор из СведенияОВнешнейОбработке().
// ПараметрыВыполнения - Структура - параметры выполнения, передаваемые подсистемой БСП.
//
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = "ОсновнаяКоманда" Тогда
// TODO: реализовать команду.
КонецЕсли;
КонецПроцедуры
#КонецОбласти
В общем-то, все.
Поддерживаем автора плюсиком, а если кто-то захочет поддержать и посущественнее - то и скачиванием обработки (да, взять вести 15 уроков информатики/математики в неделю в школе - это минус 30 рабочих часов в неделю из разработки, так что буду реально благодарен за скачивание).
П.С. Цель этой статьи двоякая: с одной стороны, предложить действительно кому-то полезный инструмент; а с другой, продемонстрировать, что для участия в тренде вайбкодинга не обязательно иметь топовое железо и несколько месяцев осваивать установку-настройку оркестров ИИ-агентов: уже есть весьма годные инструменты он-лайн (еще раз повторюсь, не реклама, просто собственный опыт).
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 11, релизы 11.5.27.81
Вступайте в нашу телеграмм-группу Инфостарт