Добавление колонок остатков товаров в табличную часть документа
По идее, если брать обычный документ в 1С Предприятие, то можно добавить реквизит «Остаток» и туда заполнять каждый раз значение остатка номенклатуры на складе, но так делать неправильно: при каждом открытии документа будет осуществляться заполнение реквизита текущими значениями остатка на складе. Это приведет к тому, что документ каждый раз при закрытии придется перезаписывать, что по сути неправильно. Для этого необходимо в табличную часть добавить колонку, которая не будет связана с данными документа.
В моем примере я добавляю сразу несколько колонок про остатки для каждого склада по отдельности, включая резерв на выбранных складах в табличную часть списка подбора номенклатуры. Менеджеру удобнее видеть сразу все остатки по товарам, не прибегая к отчету «Ведомость остатков по складах» для того ,что узнать каково наличие на складе. Все сразу видно.
Перед каждым добавлением колонок мы будем удалять «старые» колонки. Например, если пользователь удалил один склад из своего списка желаний.
1 2 3 4 5 6 7 8 9 10 11 12 |
//Удалим старые колонки Попытка Для ПорядокВывода = 1 По 1000 Цикл НазваниеКолонки = "Склад" + Строка(ПорядокВывода); ЭлементыФормы.Список.Колонки.Удалить(ЭлементыФормы.Список.Колонки.Индекс(ЭлементыФормы.Список.Колонки[НазваниеКолонки])); НазваниеКолонки = "Остаток" + Строка(ПорядокВывода); ЭлементыФормы.Список.Колонки.Удалить(ЭлементыФормы.Список.Колонки.Индекс(ЭлементыФормы.Список.Колонки[НазваниеКолонки])); НазваниеКолонки = "Резерв" + Строка(ПорядокВывода); ЭлементыФормы.Список.Колонки.Удалить(ЭлементыФормы.Список.Колонки.Индекс(ЭлементыФормы.Список.Колонки[НазваниеКолонки])); КонецЦикла; Исключение КонецПопытки; |
Добавим колонки программно в табличную часть списка номенклатуры на форме подбора (далее ТЧ). «Список» — это динамический список справочника «Номенклатура». Для элемента управления установим доступность в «Ложь», что бы ненароком не изменить значение поля. 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//Добавим новые колонки ПорядокВывода = 1; Для Каждого ТекСклад Из СписокСкладовДляРаботыССделками Цикл СкладКолонки = "Склад" + Строка(ПорядокВывода); ЭлементыФормы.Список.Колонки.Добавить(СкладКолонки, ТекСклад.Склад.Наименование); ЭлементыФормы.Список.Колонки[СкладКолонки].Положение = ПоложениеКолонки.НоваяКолонка; ЭлементыФормы.Список.Колонки[СкладКолонки].Доступность = Истина; ЭлементыФормы.Список.Колонки[СкладКолонки].УстановитьЭлементУправления(Тип("ПолеВвода")); ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.Склады"); ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.Значение = ТекСклад.Склад;// Присвоим значение ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.Доступность = Ложь; СкладКолонки = "Остаток" + Строка(ПорядокВывода); ЭлементыФормы.Список.Колонки.Добавить(СкладКолонки, "Остаток"); ЭлементыФормы.Список.Колонки[СкладКолонки].Положение = ПоложениеКолонки.НаСледующейСтроке; ЭлементыФормы.Список.Колонки[СкладКолонки].Доступность = Истина; ЭлементыФормы.Список.Колонки[СкладКолонки].УстановитьЭлементУправления(Тип("ПолеВвода")); ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.ТипЗначения = Новый ОписаниеТипов("Число"); ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.Доступность = Ложь; СкладКолонки = "Резерв" + Строка(ПорядокВывода); ЭлементыФормы.Список.Колонки.Добавить(СкладКолонки, "Резерв"); ЭлементыФормы.Список.Колонки[СкладКолонки].Положение = ПоложениеКолонки.ВТойЖеКолонке; ЭлементыФормы.Список.Колонки[СкладКолонки].Доступность = Истина; ЭлементыФормы.Список.Колонки[СкладКолонки].УстановитьЭлементУправления(Тип("ПолеВвода")); ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.ТипЗначения = Новый ОписаниеТипов("Число"); ЭлементыФормы.Список.Колонки[СкладКолонки].ЭлементУправления.Доступность = Ложь; ПорядокВывода = ПорядокВывода + 1; КонецЦикла; |
Далее в предопределенной процедуре «При получении данных» мы удалим из видимости поле «Склад1», «Склад2» и т.д. по итерации в зависимости от того, сколько пользователь выбрал складов для отображения.
1 2 3 4 5 6 7 8 9 10 11 |
// Удалим колонку "Склад" из зоны видимости для красивого отображения шапки с остатками и резервом Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл Попытка КоличествоСкладов = СписокСкладовДляРаботыССделками.Количество(); Для Ном = 1 По КоличествоСкладов Цикл ПорядокСтрокиСклада = "Склад"+Строка(Ном); ОформлениеСтроки.Ячейки[ПорядокСтрокиСклада].Видимость = Ложь; КонецЦикла; Исключение КонецПопытки; КонецЦикла; |
Если бы мы не скрыли поле склада, то образовалась бы вторая строчка для каждой позиции, а это не красиво. Поэтому я добавил колонку с наименованием склада, заполнил поле значением ссылки склада, а само поле скрыл.
Далее мы в той же процедуре «При получении данных» заполним значения остатков. Собираем все номенклатуры в порции данных, далее узнаем остатки, в разрезе выбранных товаров и складов. «СписокСкладовДляРаботыССделками» — это табличное поле, в котором пользователь добавляет виды складов для отображения в ТЧ. В примере на фото можно видеть, что там есть колонка «Тип цены» — Оптовая. Эта колонка тоже динамическая.
Узнаем список номенклатуры в порции данных:
1 2 3 4 5 6 7 8 |
// Заполним список номенклатуры СписокНоменклатуры = Новый СписокЗначений; // Удалим колонку "Склад" из зоны видимости для красивого отображения шапки с остатками и резервом Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл // Добавим в список для формирования остатков по колонках складов СписокНоменклатуры.Добавить(ОформлениеСтроки.ДанныеСтроки.Ссылка); КонецЦикла; |
Проверки на тип номенклатуры в примере я удалил, также как и на родителя.
Узнаем остатки номенклатуры:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
Если СписокСкладовДляРаботыССделками.Количество() <> 0 Тогда СписокСкладов = Новый СписокЗначений; СписокСкладов.ЗагрузитьЗначения(СписокСкладовДляРаботыССделками.ВыгрузитьКолонку("Склад")); //*************************************** //Выберем остатки номенклатуры //*************************************** Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | ВложенныйЗапрос.Склад, | ВложенныйЗапрос.Номенклатура, | СУММА(ВложенныйЗапрос.Остаток) КАК Остаток, | СУММА(ВложенныйЗапрос.Резерв) КАК Резерв |ИЗ | (ВЫБРАТЬ | ТоварыНаСкладахОстатки.Склад КАК Склад, | ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура, | ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток, | 0 КАК Резерв | ИЗ | РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки | | ОБЪЕДИНИТЬ ВСЕ | | ВЫБРАТЬ | ВРезерве.Склад, | ВРезерве.Номенклатура, | 0, | ВРезерве.КоличествоОстаток | ИЗ | РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки КАК ВРезерве) КАК ВложенныйЗапрос |ГДЕ | ВложенныйЗапрос.Номенклатура В(&СписокНоменклатуры) | И ВложенныйЗапрос.Склад В(&СписокСкладов) | |СГРУППИРОВАТЬ ПО | ВложенныйЗапрос.Склад, | ВложенныйЗапрос.Номенклатура"; Запрос.УстановитьПараметр("СписокНоменклатуры", СписокНоменклатуры); Запрос.УстановитьПараметр("СписокСкладов", СписокСкладов); РезультатЗапроса = Запрос.Выполнить(); ЗаписиОстатков = РезультатЗапроса.Выгрузить(); КонецЕсли; |
Заполняем ячейки строк.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// Делаем через попытку, так как иногда бывает срабатывает процедура раньше // чем окно появляется и нет ещё элементов управления // Когда надо, то она сработает как надо :) Попытка Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл НоменклатураСтроки = ОформлениеСтроки.ДанныеСтроки.Ссылка; // Если не родитель Если НЕ НоменклатураСтроки.ЭтоГруппа Тогда // Выведем остатки //********************************** Для ПорядокСкладов = 1 По СписокСкладовДляРаботыССделками.Количество() Цикл ПорядокСтрокиСклада = "Склад"+Строка(ПорядокСкладов); СкладКолонки = СписокСкладовДляРаботыССделками[ПорядокСкладов-1].Склад; СтруктураОтбора = Новый Структура("Склад,Номенклатура",СкладКолонки, НоменклатураСтроки); СтрокиСОстатками = ЗаписиОстатков.НайтиСтроки(СтруктураОтбора); Для Каждого ТекСтрокаСОстатками Из СтрокиСОстатками Цикл Если ТекСтрокаСОстатками.Остаток - ТекСтрокаСОстатками.Резерв > 0 Тогда ПорядокСтрокиСклада = "Остаток"+Строка(ПорядокСкладов); ОформлениеСтроки.Ячейки[ПорядокСтрокиСклада].Значение = ТекСтрокаСОстатками.Остаток - ТекСтрокаСОстатками.Резерв; КонецЕсли; ПорядокСтрокиСклада = "Резерв"+Строка(ПорядокСкладов); ОформлениеСтроки.Ячейки[ПорядокСтрокиСклада].Значение = ТекСтрокаСОстатками.Резерв; КонецЦикла; КонецЦикла; КонецЕсли; КонецЦикла; Исключение //Сообщить(ОписаниеОшибки()); КонецПопытки; |
В итоге мы получаем динамическое отображение остатков. Пользователь захотел показывать один склад — без проблем, а может три склада, тоже все нормально. В общем это действительно удобно.