Информация для пользователей:
Сразу объясню, зачем это нужно, ведь при использовании стандартной обработки подбора товара (через меню Заполнить -> Подобрать товары) остаток товара на складе и так отображается. Но если, скажем, вы заполняете документ путем загрузки данных из внешнего файла (например, из Excel-заявки покупателя), то в этом случае складские остатки уже не отображаются, и при попытке записать документ могут вылезать сообщения о том, что какой-то товар недоступен. Приходится выискивать эти позиции товара и удалять из документа, поэтому было бы неплохо видеть сразу, что именно и где удалять. Еще, например, если товара осталось мало, и менеджеру нужно уменьшить запрашиваемое покупателем количество (чтобы и других покупателей не обделить), то было бы неплохо сразу в документе видеть, сколько в данный момент всего есть товара на складе. В общем, наши девчонки меня очень просили - я сделал. Может, кому-нибудь ещё пригодится.
Как это работает:
Если вам нужно быстро отобразить остатки, вы нажимаете на кнопку Заполнение -> Показать остаток товара на складе, и в уже открытую таблицу с товарами добавляется колонка, куда будет выведен доступный остаток товара на складе по каждой позиции номенклатуры из таблицы. Через меню Все действия -> Изменить форму вы можете найти группу элементов Заполнение, выбрать для неё Вид -> Группа кнопок, перетащить кнопку в удобное для вас место на форме документа. Там же можно переименовать заголовок новой колонки, передвинуть её в нужное вам место таблицы. Эти настройки сохранятся для всех последующих документов.
Подключение внешней обработки:
В меню НСИ и администрирование -> Настройка параметров системы -> Печатные формы, отчеты и обработки -> Отчеты и обработки -> Дополнительные отчеты и обработки нажимаете кнопку Создать, после чего автоматически откроется окно, где нужно будет указать путь к файлу обработки. Затем нужно снять галочку Показывать в списках и нажать на кнопку Записать и закрыть (то есть обработка вывода остатков будет вызываться только из самого документа "Реализация товаров и услуг", в списках документов - она не нужна).
Информация для разработчиков:
Я решил выложить код обработки, потому что при написании его столкнулся с трудностями, и надеюсь новичкам (таким же как и я) этот материал поможет разобраться с тем, как работает обработка заполнения объекта с типом команды ЗаполнениеФормы. В сети есть куча материала на тему, как заполнять объекты через ВызовКлиентскогоМетода. Лично для меня эталонной стал вот эта публикация: //infostart.ru/public/84119/. Но там есть масса ограничений при работе с формой владельца. Так, в форме владельца не получится динамически создать новые реквизиты и элементы формы, применить условное оформление и т.п. (не говоря уже о том, что нужно создавать "невидимую" форму обработки и уже из модуля этой формы обращаться к форме владельца).
Частично можно было решить вопрос (в моем случае вопрос с динамическим добавлением на форму документа "Реализация товаров и услуг" новых реквизитов и элементов) через переопределение стандартных процедур создания форм в общем модуле МодификацияКонфигурацииПереопределяемый. Ваш код в этом модуле, по-идее, не должен затираться при обновлении конфигурации, но всё равно нужно было править типовую конфигурацию. Многие стараются этого избегать. Если интересно, можете почитать здесь: //infostart.ru/public/424358/.
А вот тип команды обработки ЗаполнениеФормы является большим шагом вперед и позволяет работать непосредственно с контекстом формы самого документа на сервере прямо из модуля объекта внешней обработки. Никаких дополнительных форм при этом создавать не нужно. Обращение к форме происходит через параметр ПараметрыВыполнения.ЭтаФорма. Это позволяет на лету менять форму владельца, добавлять новые реквизиты, элементы и заполнять уже существующие (при использовании ВызовКлиентскогоМетода нельзя было на сервере обратиться к форме владельца - свойство ЭтоФорма.ВладелецФормы было на сервере недоступно, и передавать на сервер можно было только объект формы).
Единственный минус в том, что тип команды ЗаполениеФормы реализован в новых БСП и доступен только в свежих релизах типовых конфигураций. Хотя "новый" - это понятие, вообще говоря, условное. Я так думаю, что этот материал сам по себе уже далеко не новый. Все спецы давно в курсе, конечно. Но я адресую эту публикацию в первую очередь новичкам, потому что повторюсь: на форумах куча древних веток на тему заполнения объектов, а из свеженького - совсем мало. Секрет что ли какой-то?
Вообще, очень рекомендую отыскать в сети последнюю версию БСП. Там в архиве идет демонстрационная база, где можно наглядно посмотреть как реализованы обработки заполнения объектов, и не только. А при желании можно их выгрузить во внешний файл, и слегка подправив код, использовать как свои собственные. Правда, приходится следить за тем, чтобы версия БСП не отставала от той, которая внедрена в типовой конфигурации, и если после очередного обновления обработка слетит, быстро подправить её, указав более свежую версию БСП. Надеюсь, я ничего не напутал. В этом, конечно, есть недостаток в плане универсальности.
Кстати, узнать какую версию БСП использует ваша типовая конфигурация можно в режиме Конфигуратора: Общие -> Общие модули -> ОбновлениеИнформационнойБазыБСП.
Теперь перехожу от слов к делу. Ниже представлен код модуля объекта внешней обработки создания и заполнения колонки складских остатков в табличной части Товары документа "Реализация товаров и услуг":
// возвращает сведения о внешней обработке
Функция СведенияОВнешнейОбработке() Экспорт
// здесь я указываю актуальную версию БСП, которую ипользует типовая конфигурация
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта();
ПараметрыРегистрации.Версия = "1.0";
ПараметрыРегистрации.Назначение.Добавить("Документ.РеализацияТоваровУслуг");
ПараметрыРегистрации.БезопасныйРежим = Ложь;
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = НСтр("ru = 'Показать остатки'");
НоваяКоманда.Идентификатор = "ПоказатьОстатки";
// указываю тип команды "ЗаполнениеФормы" вместо "ВызовКлиентскогоМетода"
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыЗаполнениеФормы();
НоваяКоманда.ПоказыватьОповещение = Ложь;
// в конфигурации "Управление торговлей "версии 11.4 следующую строку нужно убрать, иначе команда отображаться не будет
// в предыдущих версиях я так и не разобрался, где и что она скрывает
НоваяКоманда.Скрыть = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
// непосредственно код выполнения команды обработки
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = "ПоказатьОстатки" Тогда
// собственно, это и есть форма владельца (то есть форма документа назначения, в котором выполняется обработка)
// её можно изменять на лету (динамически добавлять новые реквизиты и заполнять уже существующие,
// программно применять условное оформление и т.п.)
// причем без необходимости назойливой проверки записанности данных перед вызовом обработки
Форма = ПараметрыВыполнения.ЭтаФорма;
// дальше рассматривается пример динамического создания и заполнения новой информационной колонки в табличной части Товары
// для отображения текущих остатков товара на складе
// создаем новый реквизит отбъекта и соответствующий ему элемент формы
Если Форма.Элементы.Найти("ТоварыОстатки") = Неопределено Тогда
Реквизиты = Новый Массив;
Реквизиты.Добавить(Новый РеквизитФормы("Остатки", Новый ОписаниеТипов("Число"), "Объект.Товары" , "Доступно на складе", Ложь));
Форма.ИзменитьРеквизиты(Реквизиты);
НовыйЭлементФормы = Форма.Элементы.Добавить("ТоварыОстатки", Тип("ПолеФормы"), Форма.Элементы.Товары);
НовыйЭлементФормы.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлементФормы.ТолькоПросмотр = Истина;
НовыйЭлементФормы.ПутьКДанным = "Объект.Товары.Остатки";
КонецЕсли;
// переходим к заполнению табличной части объекта формы
ТЧ = Форма.Объект.Товары;
Для Каждого Строка Из ТЧ Цикл
Строка.Остатки = ПолучитьОстатокТовараИзРегистра(Строка.Номенклатура);
КонецЦикла;
// код, конечно, требует оптимизации, потому что каждый раз в цикле обращаться с запросом к регистру неправильно
// лучше, наверное, сначала сформировать массив всех строк номенклатуры, выполнить один запрос и потом уже его в цикле обрабатывать
// но для наглядности пусть остается пока так
КонецЕсли;
КонецПроцедуры
// вспомогательная функция запроса к регистру накопления ТоварыНаСкладах
Функция ПолучитьОстатокТовараИзРегистра(Номенклатура)
Запрос = Новый Запрос;
Запрос.Текст ="
| ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура,
| ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииОстаток, 0) - ЕСТЬNULL(ТоварыНаСкладахОстатки.КОтгрузкеОстаток, 0) КАК Остаток
| ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки( , Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Остаток;
Иначе
Возврат 0;
КонецЕсли;
КонецФункции
Примечание:
Код самих обработок (тех, что выложены для скачивания) немного отличается от представленного выше: во-первых, выводятся свободные остатки (с учетом резерва); во-вторых, в запрос включено условие отбора по складу. Также добавлено немного форматирования и всякой мелочи. Например, если товара нет на складе, то отображается текстовое поле "<нет на складе>", и позиция товара подсвечивается красным цветом, колонка с остатками добавляется не в конец таблицы, а вставляется сразу за колонкой Количество и т.п.