Как перехватить момент подбора номенклатуры в 1С и вывести остаток в табличной части документа
Подбор номенклатуры открывается в отдельной форме, поэтому ПриИзменении в документе молчит. Разбираем три точки перехвата выбора, готовый запрос остатков по регистру ТоварыНаСкладах и заполнение табличной части ровно в момент подбора. Плюс чек-лист причин, по которым отладчик не останавливается на выборе.
Подбор номенклатуры в 1С работает в отдельной форме, поэтому ПриИзменении табличной части документа в момент выбора не вызывается. Строки попадают в документ программно, уже после возврата из подбора, а программное заполнение не порождает интерактивное событие. Отсюда два симптома: код в модуле документа молчит, точка останова в нём не срабатывает.
Перехватывать выбор нужно там, где он происходит: в форме подбора или в форме документа через ОбработкаВыбора, если подбор открыт в режиме выбора. Остаток по регистру накопления ТоварыНаСкладах считается запросом, значение записывается в поле табличной части сразу после того, как строки оказались в документе.
Ниже разобраны процедура КоманднаяПанельТоварыПодбор, жизненный цикл формы подбора, три точки перехвата, пример кода с запросом остатков и причины, по которым отладчик не останавливается на выборе номенклатуры.
Имена процедур, форм и команд отличаются в типовых конфигурациях: «Управление торговлей 11», «ERP», «Управление нашей фирмой», «Бухгалтерия 3.0». Перед доработкой откройте конфигуратор и сверьте названия в конкретной форме документа.
Почему стандартное событие ПриИзменении не срабатывает при подборе номенклатуры
Жизненный цикл выглядит так: документ, затем открытие отдельной формы подбора, затем выбор номенклатуры в её списке, затем возврат строк в документ. Событие ПриИзменении привязано к табличной части документа и относится к последнему шагу, да и то не всегда. Платформа вызывает его, когда пользователь интерактивно меняет значение в ячейке. Строки, вставленные кодом, такого события не порождают.
Второй слой проблемы: пока форма подбора открыта, у документа нет интерактивных действий. Кнопка «Подбор» обрабатывается в клиентском контексте формы документа, дальше управление уходит в другую форму с собственным модулем. Точки останова, выставленные в модуле документа, в этот момент не задействованы.
Как устроена процедура КоманднаяПанельТоварыПодбор
Процедура КоманднаяПанельТоварыПодбор - обработчик команды командной панели табличной части. Она получает один параметр (кнопку или команду), собирает параметры будущей формы и вызывает ОткрытьФорму. Типовая заготовка выглядит так:
&НаКлиенте
Процедура КоманднаяПанельТоварыПодбор(Команда)
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Склад", Объект.Склад);
ПараметрыФормы.Вставить("Дата", Объект.Дата);
ОткрытьФорму("Обработка.ПодборТоваров.Форма", ПараметрыФормы, ЭтотОбъект);
КонецПроцедуры
Разбор по элементам. &НаКлиенте означает, что процедура исполняется на стороне клиента. Параметр ЭтотОбъект в вызове ОткрытьФорму делает документ владельцем новой формы: подбор закрывается вместе с документом и может отправлять ему оповещения. Дальше работает код формы подбора, а модуль документа ждёт возврата.
Имя формы зависит от конфигурации. В одних решениях это форма обработки подбора, в других - форма списка справочника «Номенклатура», открытая в режиме выбора. Точное имя ищется так: откройте форму документа в конфигураторе, перейдите в свойства команды табличной части и посмотрите её процедуру-обработчик.
Что происходит после открытия формы подбора
Форма подбора живёт своей жизнью. Она получает параметры, строит отбор, показывает список номенклатуры с остатками и ценами, позволяет отметить несколько позиций и нажать «Перенести в документ» или «Выбрать». Результат возвращается одним из двух способов: через оповещение (ОписаниеОповещения) или через механизм выбора формы.
Таблица 1. Если таблица шире экрана, прокрутите её влево или вправо. С клавиатуры: перейдите к таблице клавишей Tab и используйте стрелки.
| Событие | Где живёт | Когда возникает |
|---|---|---|
| ПриИзменении | Модуль формы документа, табличная часть | Пользователь вручную меняет значение в ячейке документа |
| ОбработкаВыбора | Модуль формы документа | Подчинённая форма, открытая в режиме выбора, вернула значение |
| ОбработкаОповещения | Модуль формы документа | Форма подбора отправила оповещение по ОписаниеОповещения |
| ПриАктивизацииСтроки | Модуль формы подбора | Курсор перешёл на другую строку списка номенклатуры |
| ПриЗакрытии | Модуль формы подбора | Форма подбора закрывается |
Из таблицы видно, почему отладчик молчит: при выборе номенклатуры исполняется код формы подбора, а не документа. Строки в табличной части документа появляются позже, одним пакетом, и обработчик ПриИзменении по ним не вызывается.
Точки перехвата выбора номенклатуры в момент подбора
Три рабочих варианта: событие ОбработкаВыбора в форме документа, доработка формы подбора через расширение и перехват самой процедуры открытия подбора. Первый вариант подходит, когда подбор открыт как форма выбора. Второй и третий нужны, если подбор - самостоятельная обработка со своей кнопкой переноса.
Использование предопределённой процедуры ОбработкаВыбора
ОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка) - событие формы-владельца. Оно возникает, когда подчинённая форма закрылась с выбором. В обработчике доступны выбранное значение и флаг стандартной обработки. Если поставить СтандартнаяОбработка = Ложь, платформа не станет сама вставлять строки, и вы заполните табличную часть вручную, сразу с остатком.
&НаКлиенте
Процедура ОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
Если Элемент.Имя <> "Товары" Тогда
Возврат;
КонецЕсли;
СтандартнаяОбработка = Ложь;
МассивНоменклатуры = Новый Массив;
Для Каждого СтрокаПодбора Из ВыбранноеЗначение Цикл
МассивНоменклатуры.Добавить(СтрокаПодбора.Номенклатура);
КонецЦикла;
Остатки = ОстаткиПоСписку(МассивНоменклатуры, Объект.Склад, Объект.Дата);
Для Каждого СтрокаПодбора Из ВыбранноеЗначение Цикл
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрокаПодбора.Номенклатура;
НоваяСтрока.Количество = СтрокаПодбора.Количество;
НоваяСтрока.Остаток = Остатки[СтрокаПодбора.Номенклатура];
КонецЦикла;
КонецПроцедуры
Структура ВыбранноеЗначение зависит от того, что возвращает форма подбора: массив значений, таблицу значений или ссылку. Проверьте это в отладчике на первом же вызове, до того как писать цикл.
Важное условие: форма подбора должна открываться в режиме выбора. Если в вашей конфигурации она открывается обычным ОткрытьФорму без этого режима, событие ОбработкаВыбора в документе не возникнет, и понадобится второй вариант.
Точки расширения для перехвата подбора без изменения конфигурации
Расширение конфигурации позволяет добавить свой код в типовую форму и не снимать конфигурацию с поддержки. Работают аннотации &Перед, &После и &Вместо над процедурой расширения с тем же именем и той же сигнатурой, что у метода в конфигурации. Для &Вместо обязателен вызов ПродолжитьВызов(), иначе базовый код не выполнится.
&НаКлиенте
&После("ОбработкаВыбора")
Процедура Расш_ОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
Если Элемент.Имя = "Товары" Тогда
ЗаполнитьОстаткиВТоварах();
КонецЕсли;
КонецПроцедуры
Такой обработчик выполнится после типового, когда строки уже в табличной части. Остатки посчитает серверная процедура расширения ЗаполнитьОстаткиВТоварах. Плюс схемы: типовой код не тронут, при обновлении конфигурации расширение можно отключить.
Если подбор сделан отдельной обработкой, добавьте в расширение форму этой обработки и обработчик её команды переноса, либо перехватите КоманднаяПанельТоварыПодбор через &Вместо и передайте в форму подбора дополнительный параметр, например отбор по складу.
Пошаговый пример: получение остатков и заполнение табличного поля при подборе
- Добавьте в табличную часть документа поле для остатка. В типовых конфигурациях оно часто есть в форме подбора, но отсутствует в документе. Тип: число, точность как у количества.
- Определите точку перехвата:
ОбработкаВыборав форме документа или обработчик в расширении формы подбора. - Соберите список номенклатуры из результата подбора в массив, чтобы не делать запрос по одной позиции.
- Выполните один запрос к
РегистрНакопления.ТоварыНаСкладах.Остаткис отбором по списку и складу на дату документа. - Запишите остатки в поле табличной части и оставьте событие
ПриИзменениидля ручных правок номенклатуры.
Пример кода для получения остатков по выбранной номенклатуре
&НаСервереБезКонтекста
Функция ОстаткиПоСписку(МассивНоменклатуры, Склад, ДатаОстатков)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| СУММА(Остатки.КоличествоОстаток) КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(
| &ДатаОстатков,
| Номенклатура В (&СписокНоменклатуры)
| И Склад = &Склад) КАК Остатки
|СГРУППИРОВАТЬ ПО
| Остатки.Номенклатура";
Запрос.УстановитьПараметр("СписокНоменклатуры", МассивНоменклатуры);
Запрос.УстановитьПараметр("Склад", Склад);
Запрос.УстановитьПараметр("ДатаОстатков", КонецДня(ДатаОстатков));
Результат = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Результат.Вставить(Выборка.Номенклатура, Выборка.Остаток);
КонецЦикла;
Возврат Результат;
КонецФункции
Группировка и СУММА нужны, чтобы характеристики и серии не размножили строки: иначе на одну номенклатуру вернётся несколько записей, и Соответствие сохранит только последнюю. Если измерения «Склад» в вашем регистре нет, уберите это условие. Имя регистра тоже сверяйте с конфигурацией: в части решений остатки хранятся в других регистрах.
Заполнение табличного поля в документе после возврата из подбора
&НаСервере
Процедура ЗаполнитьОстаткиВТоварах()
МассивНоменклатуры = Объект.Товары.ВыгрузитьКолонку("Номенклатура");
Если МассивНоменклатуры.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Остатки = ОстаткиПоСписку(МассивНоменклатуры, Объект.Склад, Объект.Дата);
Для Каждого СтрокаТоваров Из Объект.Товары Цикл
СтрокаТоваров.Остаток = Остатки[СтрокаТоваров.Номенклатура];
КонецЦикла;
КонецПроцедуры
Один запрос на весь документ вместо запроса на каждую строку: на подборе из 50 позиций разница заметна. Если поле остатка не нужно хранить, используйте вычисляемое поле формы, но тогда запрос придётся обновлять при каждом изменении состава табличной части.
Событие ПриИзменении табличной части оставьте: оно сработает, когда менеджер вручную заменит номенклатуру в строке, и пересчитает остаток для новой позиции.
Типичные ошибки отладки при работе с формами подбора
Почему отладчик не останавливается на выборе номенклатуры
Первая причина встречается чаще всего: точка останова стоит в модуле документа, а исполняется код формы подбора. Отладчик останавливается только там, где реально выполняется строка. Поставьте точку в модуле формы подбора, в обработчике выбора списка или команды переноса.
Вторая причина - контекст выполнения. Код с &НаКлиенте исполняется на клиенте, с &НаСервере - на сервере. Точка останова в серверной процедуре не сработает, если в настройках отладки запрещена отладка сервера, и наоборот. В меню «Отладка» - «Параметры» должны быть разрешены отладка клиента и сервера, а опция «Не останавливаться на ошибках» выключена для нужных типов.
Третья причина - расширение не подключено или не обновлено. Изменения в расширении применяются после обновления конфигурации базы данных. Пока этого не сделано, старая версия кода остаётся в памяти сеанса.
Четвёртая - защита от зацикливания: если обработчик вызывает изменение того же поля, платформа блокирует повторный вызов. В отладчике это выглядит как перескок через строку.
Как проверить, что конфигурация и версия платформы не блокируют ваши обработчики
- Откройте список расширений: в конфигураторе «Конфигурация» - «Расширения конфигурации», в режиме предприятия через «Все функции». Убедитесь, что расширение активно и в колонке «Префикс» стоит ваш префикс.
- Посмотрите журнал регистрации: ошибки компиляции модуля и сообщения вида «Метод объекта не обнаружен» показывают, что платформа не видит ваш обработчик.
- Проверьте версию платформы. Аннотации
&Перед,&Послеи&Вместоподдерживаются не во всех релизах линейки 8.3: на старой сборке модуль просто не скомпилируется. Сверьте номер релиза с требованиями конфигурации. - Убедитесь, что обработчик не перекрыт другой доработкой: два расширения с одинаковым методом конфликтуют, и сработает одно.
- Проверьте, что в форме подбора есть событие, на которое вы подписались: набор событий зависит от типа формы (форма списка, форма обработки, форма документа).
Интерфейс 1С 8.5 меняет работу с формами и списками, поэтому проверяйте доработку на той версии платформы, где она будет работать. Этапы перевода конфигурации и факторы трудозатрат разобраны в статье «Переход на интерфейс «Версия 8.5» в 1С:Предприятие: что нужно знать разработчикам и руководителям». Как новые формы и списки выглядят в прикладном решении, показано в материале про интерфейс 8.5 на примере «1С:Управление нашей фирмой 8».
Заключение: как проверить доработку перед запуском
Схема, которая работает: перехват в момент выбора, один запрос остатков по списку номенклатуры, запись значений в табличную часть и сохранённый обработчик ПриИзменении для ручных правок. Точку перехвата выбирайте по типу подбора: ОбработкаВыбора для формы, открытой в режиме выбора, расширение формы для отдельной обработки подбора.
- Проверяйте на копии базы, не на рабочей.
- Сверяйте имена процедур, регистров и измерений в своей конфигурации:
ТоварыНаСкладахесть не везде. - Учитывайте характеристики и серии: без группировки запрос вернёт несколько строк на одну номенклатуру.
- Ставьте точки останова в том модуле, где исполняется код, и проверяйте настройки отладки клиента и сервера.
- Фиксируйте доработку в расширении, чтобы обновление конфигурации не потребовало повторной правки типовых модулей.
Задача решается на уровне формы, без правки типовых модулей в основной конфигурации. Начните с отладчика: определите, какая именно форма открывается по кнопке «Подбор» в вашем документе, и дальше работайте с её кодом.