Возможно ли автоматически заполнить количество в документе «Реализация товаров и услуг» остатками со склада?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При автоматизации работы менеджеров по продажам часто возникает задача максимально сократить ручной ввод данных. Одна из типичных идей — автоматически подставлять текущий складской остаток товара в поле Количество при выборе номенклатуры в документе РеализацияТоваровУслуг. На первый взгляд задача кажется тривиальной, однако при её реализации "в лоб" разработчики сталкиваются с серьезными проблемами производительности базы данных и ошибками в учете резервов.

В этой статье мы подробно разберем, как правильно реализовать заполнение документа остатками со склада, какие архитектурные подходы использовать и как избежать типичных ошибок программирования в среде «1С:Предприятие».

Способ 1. Использование стандартного механизма подбора (без программирования)

Прежде чем приступать к написанию собственного кода, давайте проанализируем штатные возможности типовых конфигураций 1С (таких как «Управление торговлей», «ERP Управление предприятием» или «Комплексная автоматизация»). Разработчики фирмы 1С уже предусмотрели удобный инструмент решения этой задачи.

Над табличной частью товаров в документе реализации расположена кнопка Подобрать (или «Подбор товаров»). При ее нажатии открывается специализированное диалоговое окно, в котором:

  1. Отображается весь список номенклатуры с актуальными остатками в разрезе выбранного склада.
  2. Доступна кнопка Выбрать остаток. При её нажатии система автоматически переносит всю номенклатуру с ее полным текущим количеством со склада в документ.
  3. Пользователь может оперативно видеть свободные остатки с учетом резервов, характеристик и серий.

Использование типового подбора — это наиболее безопасный и правильный путь, который не требует изменения конфигурации и полностью сохраняет базу данных на стандартной поддержке.

Способ 2. Заполнение по кнопке вместо обработки события выбора номенклатуры

Если заказчик настаивает на автоматическом заполнении, крайне важно выбрать правильное событие. Автор темы на форуме изначально планировал привязать алгоритм к событию выбора номенклатуры (обработчик ПриИзменении для поля Номенклатура в строке табличной части).

Давайте выясним, почему этот подход опасен. При изменении номенклатуры в каждой отдельной строке система будет вынуждена делать вызов сервера и выполнять запрос к базе данных для получения остатка. Если менеджер заполняет документ на 50–100 строк, система сделает 50–100 отдельных запросов к СУБД. При активной работе десятков пользователей это неминуемо приведет к сильным зависаниям интерфейса и блокировкам базы данных.

Гораздо более производительным и правильным решением является создание команды Заполнить по остаткам для всей табличной части. В этом случае мы пишем один оптимизированный запрос, который за один серверный вызов получает остатки сразу по всей номенклатуре из документа и распределяет их по строкам.

Рассмотрим пример запроса для получения остатков по массиву номенклатуры и складу:


&НаСервере
Процедура ЗаполнитьКоличествоОстаткамиНаСервере(СсылкаНаДокумент)
    
    // Получаем объект документа для изменения
    ДокументОбъект = РеквизитФормыВЗначение("Объект");
    ТабличнаяЧасть = ДокументОбъект.Товары;
    
    // Формируем массив номенклатуры для минимизации выборки
    МассивНоменклатуры = ТабличнаяЧасть.ВыгрузитьКолонку("Номенклатура");
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	СвободныеОстаткиОстатки.Номенклатура КАК Номенклатура,
    |	ЕСТЬNULL(СвободныеОстаткиОстатки.ВНаличииОстаток, 0) - ЕСТЬNULL(СвободныеОстаткиОстатки.ЗарезервированоОстаток, 0) КАК ДоступныйОстаток
    |ИЗ
    |	РегистрНакопления.СвободныеОстатки.Остатки(
    |		&Период,
    |		Номенклатура В (&МассивНоменклатуры)
    |			И Склад = &Склад
    |	) КАК СвободныеОстаткиОстатки";
    
    Запрос.УстановитьПараметр("Период", Новый Граница(ДокументОбъект.Дата, ВидГраницы.Исключая));
    Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
    Запрос.УстановитьПараметр("Склад", ДокументОбъект.Склад);
    
    РезультатЗапроса = Запрос.Выполнить();
    Если Не РезультатЗапроса.Пустой() Тогда
        Выборка = РезультатЗапроса.Выбрать();
        Пока Выборка.Следующий() Цикл
            // Находим строки в ТЧ и заполняем количество
            ПараметрыОтбора = Новый Структура("Номенклатура", Выборка.Номенклатура);
            НайденныеСтроки = ТабличнаяЧасть.НайтиСтроки(ПараметрыОтбора);
            Для Каждого СтрокаТЧ Из НайденныеСтроки Цикл
                СтрокаТЧ.Количество = Выборка.ДоступныйОстаток;
                // Принудительно вызываем пересчет сумм и НДС
                ОбработкаТабличнойЧастиКлиентСервер.РассчитатьСуммуТабличнойЧасти(СтрокаТЧ);
            EndЦикла;
        КонецЦикла;
    КонецЕсли;
    
    ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
    
КонецПроцедуры

Способ 3. Реализация внешней обработки по стандартам БСП

Для того чтобы не изменять типовую конфигурацию и сохранить возможность беспрепятственного обновления, рекомендуется оформить данный алгоритм в виде внешней обработки заполнения табличной части, работающей через Библиотеку стандартных подсистем (БСП).

Разберем структуру модуля такой внешней обработки. В модуле объекта обязательно должна быть экспортная функция СведенияОВнешнейОбработке, которая регистрирует обработку в справочнике «Дополнительные отчеты и обработки» с типом ЗаполнениеОбъекта:


Функция СведенияОВнешнейОбработке() Экспорт
    
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработкеРегистрации("2.2.2.1");
    ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта();
    ПараметрыРегистрации.Наименование = "Заполнить количество остатками склада";
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.БезопасныйРежим = Ложь;
    
    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = "Заполнить количество по остаткам";
    НоваяКоманда.Идентификатор = "ЗаполнитьКоличествоПоОстаткам";
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
    НоваяКоманда.ПоказыватьОповещение = Истина;
    
    Возврат ПараметрыРегистрации;
    
КонецФункции

После регистрации этой обработки в интерфейсе документа «Реализация товаров и услуг» в меню кнопки Заполнить автоматически появится созданная нами команда. Это стандартное и наиболее поддерживаемое решение.

Важные технические нюансы и правила хорошего тона

При написании собственных запросов получения остатков обязательно учитывайте следующие архитектурные особенности:

Соблюдение этих правил позволит вам создать надежное и быстродействующее решение, которое упростит работу пользователей и сохранит стабильность информационной системы.

← На главную