Найти в Дзене
1с разное

Программная работа с упаковками и единицами измерения в КА 2.5

Демонстрирую несколько методов для быстрой адаптации типовых механизмов упаковок и единиц измерения в 1С:Комплексная автоматизация, вер. 2.5. * * * Всем привет! Все описанные методы были разработаны и протестированы на платформе 1С: Предприятие 8.3.18.1334, на конфигурации 1С: Комплексная автоматизация 2.4.14.164 с использованием расширений. Также проверено на КА 2.5. Исходная задача была следующей: Как только возникает задача адаптации, доработки, расширения функционала, связанного с единицами измерения товара, сразу возникает необходимость разобраться с типовыми механизмами и взаимосвязями между товарами и единицами измерения. В КА 2.5 появилось новое понятие "упаковка" - как отдельный вид справочника - очень важное понятие с точки зрения понимания всего механизма единиц измерений. Скажем так, для тех, кто ранее работал с конфигурациями на обычных формах таких, как Управление торговлей 10.3 или Управление производственным предпри
Оглавление

Демонстрирую несколько методов для быстрой адаптации типовых механизмов упаковок и единиц измерения в 1С:Комплексная автоматизация, вер. 2.5.

* * *

Всем привет!

Все описанные методы были разработаны и протестированы на платформе 1С: Предприятие 8.3.18.1334, на конфигурации 1С: Комплексная автоматизация 2.4.14.164 с использованием расширений. Также проверено на КА 2.5.

Исходная задача была следующей:

  1. необходимо было создать новую печатную форму "Расходного ордера на товары" с отображением веса-брутто товара (это вес упаковки, рис.1).
  2. необходимо было доработать форму размещения товара по ячейкам - с указанием веса-брутто товара (это вес упаковки, рис. 2).
Рис. 1. Расходный ордер на товары с выводом общего веса упаковки товара
Рис. 1. Расходный ордер на товары с выводом общего веса упаковки товара
Рис. 2. Размещение товаров по ячейкам с указанием веса упаковки товара
Рис. 2. Размещение товаров по ячейкам с указанием веса упаковки товара

Как только возникает задача адаптации, доработки, расширения функционала, связанного с единицами измерения товара, сразу возникает необходимость разобраться с типовыми механизмами и взаимосвязями между товарами и единицами измерения. В КА 2.5 появилось новое понятие "упаковка" - как отдельный вид справочника - очень важное понятие с точки зрения понимания всего механизма единиц измерений.

Скажем так, для тех, кто ранее работал с конфигурациями на обычных формах таких, как Управление торговлей 10.3 или Управление производственным предприятием 1.2 - для них переход на КА 2.5 будет более сложным. Поскольку ранее был один справочник ЕдиницыИзмерения, и для каждого товара можно было создавать и привязывать несколько единиц измерения (далее ЕИ): Штука, Пачка ( состоит из 10 штук), Блок (состоит из 10 блоков) и т.д. Как получить одну ЕИ из другой - за это отвечал коэффициент пересчета - обычный реквизит справочника ЕдиницыИзмерения, также у каждой единицы был реквизит Вес - через который можно было задать вес ЕИ.

Собственно, вот такая простая конструкция позволяла оперировать и упаковками и единицами измерения одновременно.

В КА 2.5:

  • вес-брутто товара (вес упаковки) задается в карточке Упаковки - это справочник "УпаковкиЕдиницыИзмерения",
  • вес-нетто (вес товара без упаковки) - задается в карточке Товара - через реквизит справочника "Номенклатура" - запомните, что это типовой механизм (!).

Любая программная работа с объектами заключается в умении Прочитать (Получить) значение объекта и в умении Записать (Сохранить) значение объекта.

Поэтому программное чтение веса упаковки организуем "из" упаковки, а программную запись веса упаковки - соответственно "в" упаковку. То же самое с весом товара: чтение организуем "из" номенклатуры, а запись - "в" номенклатуру.

С точки зрения решаемой исходной задачи, надо реализовать чтение веса упаковки для печатной формы и запись веса упаковки при размещении товара по ячейкам.

Скажу наперед, что механизм размещения товаров по ячейкам является наполовину типовым: для приходных ордеров на товары имеется типовой вызов формы размещения товаров по ячейкам.

Для расходных одеров на товары такого типового механизма нет. Но я его легко адаптировал для расходных ордеров - через расширение конфигурации. Но это другая история, и к единицам измерения отношения не имеет.

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

Номенклатура в КА 2.5 делится на три категории:

  1. номенклатура, у которой признак ИспользоватьУпаковки (тип Булево) не возведен (то есть = Ложь) - откройте карточку номенклатуры и сразу все увидите;
  2. номенклатура, у которой признак ИспользоватьУпаковки = Истина, и с ней связан общий "набор упаковок";
  3. номенклатура, у которой признак ИспользоватьУпаковки = Истина, и с ней связана индивидуальная упаковка (правильнее говорить "индивидуальный набор упаковок").

Алгоритмы, представленные в статье, не обладают универсальностью, поскольку при разработке были приняты определенные допущения и ограничения: к примеру, что индивидуальных упаковок или общих наборов упаковок для каждой номенклатуры будет только по одному экземпляру - то есть:

  1. для категории 1 - нет упаковок (к примеру, все мерные товары - то есть не штучные, а метровые, килограммовые и др.);
  2. для категории 2 - один общий набор упаковок;
  3. для категории 3 - одна индивидуальная упаковка.

Технически можно задавать несколько наборов и несколько инд. упаковок - КА 2.5 не проверяет и не блокирует.

Но в базе есть определенные договоренности по ведению учета - вторых наборов и инд. упаковок не должно быть и нельзя создавать. За создание наборов и инд. упаковок отвечает один человек - он же системный администратор базы.

Для понимания, исторически изначально упаковки не использовались в базе - использовались только единицы измерения - после перехода с КА 1.1. Со временем началось внедрение адресного хранения, при котором "Использование упаковок" обязательно - это функциональная опция конфигурации КА 2.5, которую необходимо включить (!).

Для большинства номенклатур были созданы общие "наборы упаковок". Когда пришло время прописывать вес и габариты, мы поняли что "общего" в наборах упаковок нет ничего, кроме наименования - вес и размеры упаковок отличались у каждого поставщика - поэтому стали создавать индивидуальные упаковки (то есть инд. наборы упаковок).

Поскольку использование упаковок в организации происходило постепенно и последовательно, представленные алгоритмы обрастали проверками, условиями и доп. механизмами - о чем по мере необходимости будет дополнительно написано.

Чтение упаковки и получение веса упаковки

Процедура ЗаполнитьПоДокументуПриемкиСервер()

//...

//так не пойдет:
//ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоНаименованию("кг", Истина, , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);

//вот так пойдет:
ЕИ_Кг = ПолучитьБазовуюЕдиницуИзмерения("166", "KGM", "кг");
Если Выборка.Номенклатура.НаборУпаковок = Справочники.НаборыУпаковок.ИндивидуальныйДляНоменклатуры Тогда

//получаем вес-брутто из упаковки
Упак = ПолучитьУпаковку(Выборка.Номенклатура);
Если ЗначениеЗаполнено(Упак) Тогда
НоваяСтрока.Вес = Упак.Вес;
КонецЕсли;
НоваяСтрока.ВесЕдиницаИзмерения = ЕИ_Кг;

ИначеЕсли ЗначениеЗаполнено(Выборка.Номенклатура.НаборУпаковок) Тогда

//то есть это общий набор упаковок
//значит вес пока не задан
//НоваяСтрока.Вес = Выборка.Номенклатура.ВесЧислитель;
НоваяСтрока.ВесЕдиницаИзмерения = ЕИ_Кг;

ИначеЕсли НЕ Выборка.Номенклатура.ИспользоватьУпаковки
И Выборка.Номенклатура.ЕдиницаИзмерения.ТипИзмеряемойВеличины <> Перечисления.ТипыИзмеряемыхВеличин.Вес Тогда

//то есть упаковки не используются, но вес указывать нужно
//вес берем из карточки номенклатуры
НоваяСтрока.Вес = Выборка.Номенклатура.ВесЧислитель;
НоваяСтрока.ВесЕдиницаИзмерения = ЕИ_Кг;

Иначе
//остальные случаи: товар продается в "кг" или еще не изученные - не рассматриваем
КонецЕсли;

//...

КонецПроцедуры

Функция ПолучитьУпаковку(Номенклатура)

Упаковка = Неопределено;

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.ПометкаУдаления = Ложь
| И УпаковкиЕдиницыИзмерения.Владелец = &Владелец
| И УпаковкиЕдиницыИзмерения.ТипУпаковки = Значение(Перечисление.ТипыУпаковокНоменклатуры.Конечная)
| И УпаковкиЕдиницыИзмерения.ВесоГабаритнаяУпаковка = Истина";

Запрос.УстановитьПараметр("Владелец", Номенклатура);

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Если Выборка.Количество()>1 ИЛИ Выборка.Количество()=0 Тогда
Возврат Неопределено;
КонецЕсли;

Если Выборка.Следующий() Тогда
Упаковка = Выборка.Ссылка;
КонецЕсли;

Возврат Упаковка;

КонецФункции

Функция ПолучитьБазовуюЕдиницуИзмерения(КодЕИ, МеждСокр, НаименованиеЕИ)

//примеры:
//166, KGM, кг
//778, NMP, упак
//796, PCE, шт

Рез = Неопределено;

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.ПометкаУдаления = ЛОЖЬ
| И УпаковкиЕдиницыИзмерения.Владелец = ЗНАЧЕНИЕ(Справочник.НаборыУпаковок.БазовыеЕдиницыИзмерения)
| И УпаковкиЕдиницыИзмерения.Код = &КодЕИ
| И УпаковкиЕдиницыИзмерения.МеждународноеСокращение = &МеждСокр
| И УпаковкиЕдиницыИзмерения.Наименование = &НаименованиеЕИ";

Запрос.УстановитьПараметр("КодЕИ", КодЕИ);
Запрос.УстановитьПараметр("МеждСокр", МеждСокр);
Запрос.УстановитьПараметр("НаименованиеЕИ", НаименованиеЕИ);

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Если Выборка.Следующий() Тогда
Рез = Выборка.Ссылка;
КонецЕсли;

Возврат Рез;

КонецФункции

Поясню ряд моментов:

  1. Все процедуры и функции нужно прописывать с директивой НаСервере
  2. Получение базовой ед. изм. лучше вынести в отдельную процедуру - и получать по трем параметрам, поскольку технически в базе можно создать несколько базовых ед. изм. с одинаковым наименованием, одинаковым сокращенным названием или одинаковыми кодами. Поэтому для минимизации ошибок следует искать базовую ед. изм по трем параметрам.
  3. Если по номенклатуре не используется упаковка, то вес упаковки (вес-брутто) будем записывать и читать в/из поля Вес карточки номенклатуры, которое предназначено для хранения веса товара без упаковки (веса-нетто) согласно типовым механизмам.
  4. Со временем в компании понадобилось создавать дополнительные инд. упаковки по номенклатуре для сайта и маркетплейсов. Чтобы разделить инд. упаковки, созданные для хранения веса упаковки (веса-брутто) в рамках исходной задачи и представленного проекта, был добавлен признак в карточку упаковки "ВесоГабаритнаяУпаковка" = Истина (см. рис.) Отбор по этому полю вы будете встречать в запросах.

Рис. 3. Добавили признак Весо-габаритная упаковка для разделения упаковок на используемые в расходных ордерах (и других документах) и на используемые только для хранения новых весо-габаритных размеров для сайта и маркетплейсов
Рис. 3. Добавили признак Весо-габаритная упаковка для разделения упаковок на используемые в расходных ордерах (и других документах) и на используемые только для хранения новых весо-габаритных размеров для сайта и маркетплейсов

Запись упаковки и запись веса


Функция ЗаписатьВРегистрСервер()

//...

//доработка+ запишем вес-брутто
Если Не ЕстьОшибки Тогда

МасНоменклатур = Новый Массив;
Для Каждого Стр Из Объект.ОсновныеЯчейки Цикл

Если Стр.Вес = 0 Тогда
Продолжить;
КонецЕсли;

Если МасНоменклатур.Найти(Стр.Номенклатура) <> Неопределено Тогда
//уже обработали
Продолжить;
КонецЕсли;

Если ЕстьОшибки Тогда
Возврат ЕстьОшибки;
КонецЕсли;

МасНоменклатур.Добавить(Стр.Номенклатура);

Если Стр.Номенклатура.НаборУпаковок = Справочники.НаборыУпаковок.ИндивидуальныйДляНоменклатуры Тогда

//по-умолчанию предполагаем, что вес указывается в "кг"
ЕстьОшибки = НайтиУпаковкуЗаписатьВес(Стр.Номенклатура, Стр.Вес);

ИначеЕсли ЗначениеЗаполнено(Стр.Номенклатура.НаборУпаковок) Тогда

//то есть имеется общий набор упаковок
ЕстьОшибки = СоздатьУпаковкуЗаписатьВес(Стр.Номенклатура, Стр.Вес);

ИначеЕсли НЕ Стр.Номенклатура.ИспользоватьУпаковки И Стр.Номенклатура.ЕдиницаИзмерения.ТипИзмеряемойВеличины <> Перечисления.ТипыИзмеряемыхВеличин.Вес Тогда

ЕстьОшибки = ЗаписатьВесВКарточкуНоменклатуры(Стр.Номенклатура, Стр.Вес);

Иначе

//ничего не записываем,
//поскольку или товар и так продается в "кг", или какая-то ошибка

КонецЕсли;

КонецЦикла;

КонецЕсли;

Возврат ЕстьОшибки;

КонецФункции
Функция ПолучитьУпаковку(Номенклатура)

Упаковка = Неопределено;

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.ПометкаУдаления = Ложь
| И УпаковкиЕдиницыИзмерения.Владелец = &Владелец
| И УпаковкиЕдиницыИзмерения.ТипУпаковки = Значение(Перечисление.ТипыУпаковокНоменклатуры.Конечная)
| И УпаковкиЕдиницыИзмерения.ВесоГабаритнаяУпаковка = Истина";

Запрос.УстановитьПараметр("Владелец", Номенклатура);

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Если Выборка.Количество()>1 ИЛИ Выборка.Количество()=0 Тогда
Возврат Неопределено;
КонецЕсли;

Если Выборка.Следующий() Тогда
Упаковка = Выборка.Ссылка;
КонецЕсли;

Возврат Упаковка;

КонецФункции

Функция НайтиУпаковкуЗаписатьВес(Номенклатура, Вес)

ЕстьОшибки = Ложь; //возвращаемый параметр

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.ПометкаУдаления = Ложь
| И УпаковкиЕдиницыИзмерения.Владелец = &Владелец
| И УпаковкиЕдиницыИзмерения.ТипУпаковки = Значение(Перечисление.ТипыУпаковокНоменклатуры.Конечная)
| И УпаковкиЕдиницыИзмерения.ВесоГабаритнаяУпаковка = Истина";

Запрос.УстановитьПараметр("Владелец", Номенклатура);

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Если Выборка.Количество()>1 Тогда
//ничего не записываем
ЕстьОшибки = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ном-ра " + Номенклатура + " содержит несколько упаковок - непонятно для какой упаковки записывать вес-брутто");
КонецЕсли;

Если Выборка.Количество()=0 Тогда
//ничего не записываем
ЕстьОшибки = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ном-ра " + Номенклатура + " не содержит предустановленных упаковок");
КонецЕсли;

Если ЕстьОшибки Тогда
Возврат Истина;
КонецЕсли;

Если Выборка.Следующий() Тогда

Упаковка = Выборка.Ссылка.ПолучитьОбъект();
Упаковка.Вес = Вес;

//вес-брутто измеряем в "кг" - на всякий случай запишем
//ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("166");
ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоНаименованию("кг", Истина, , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);
Упаковка.ВесЕдиницаИзмерения = ЕИ_Кг;
Упаковка.ВесоГабаритнаяУпаковка = Истина;

//не изменяем, не проверяем
//Упаковка.Наименование = Стр.Номенклатура.НаборУпаковок.Наименование;
//Упаковка.Числитель = 1;
//Упаковка.Знаменатель = 1;
//Упаковка.ТипИзмеряемойВеличины = Перечисления.ТипыИзмеряемыхВеличин.Упаковка;
//Упаковка.ТипУпаковки = Перечисления.ТипыУпаковокНоменклатуры.Конечная;

Попытка
//конструкцию ОбменДанными.Загрузка = Истина - не используем,
//поскольку ПередЗаписью происходит проверка реквизитов объекта
Упаковка.Записать();
Исключение
ЕстьОшибки = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("По ном-ре " + Номенклатура + " не удалось записать вес упаковки"
+ Символы.ПС + ИнформацияОбОшибке().Описание);
КонецПопытки;

КонецЕсли;

Возврат ЕстьОшибки;

КонецФункции
Функция СоздатьУпаковкуЗаписатьВес(Номенклатура, Вес)

//создадим программно инд. упаковку только для той номенклатуры, у которой были заданы общие наборы упаковок

ЕстьОшибки = Ложь; //возвращаемый параметр

//Базовые единицы измерения
//ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("166");
//ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоНаименованию("кг", Истина, , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);
//ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоРеквизиту("МеждународноеСокращение", "KGM", , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);
//ЕИ_Упак = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоРеквизиту("МеждународноеСокращение", "NMP", , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);
//ЕИ_Упак = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("778", Истина, , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);

ЕИ_Кг = ПолучитьБазовуюЕдиницуИзмерения("166", "KGM", "кг");
ЕИ_Упак = ПолучитьБазовуюЕдиницуИзмерения("778", "NMP", "упак");
ЕИ_Шт = ПолучитьБазовуюЕдиницуИзмерения("796", "PCE", "шт");

//нужно получить коэффициент пересчета
УпаковкаОбщегоНабора = ПолучитьУпаковкуИзОбщегоНабора(Номенклатура.НаборУпаковок);
Если УпаковкаОбщегоНабора = Неопределено Тогда
ЕстьОшибки = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("По ном-ре " + Номенклатура + " не удалось создать индивидуальную упаковку из общего набора и записать вес-брутто");
Возврат ЕстьОшибки;
Иначе
Наименование = УпаковкаОбщегоНабора.Наименование;
Числитель = УпаковкаОбщегоНабора.Числитель;
КонецЕсли;

//общий набор упаковок не подходит для указания весо-габаритных характеристик,
// когда Владелец = Стр.Номенклатура.НаборУпаковок;
//создаем только индивидуальный набор упаковок

//вес-брутто измеряем в "кг" - на всякий случай запишем

//сначала воспользуемся наименованием общего набора упаковок (!) для создания упаковки
НоваяУпаковка = Справочники.УпаковкиЕдиницыИзмерения.СоздатьЭлемент();
НоваяУпаковка.Наименование = Наименование;
НоваяУпаковка.Владелец = Номенклатура;
НоваяУпаковка.ТипИзмеряемойВеличины = Перечисления.ТипыИзмеряемыхВеличин.Упаковка;
НоваяУпаковка.ТипУпаковки = Перечисления.ТипыУпаковокНоменклатуры.Конечная;
НоваяУпаковка.Вес = Вес;
НоваяУпаковка.ВесЕдиницаИзмерения = ЕИ_Кг;
НоваяУпаковка.ЕдиницаИзмерения = ?(Наименование = "шт", ЕИ_Шт, ЕИ_Упак);
НоваяУпаковка.Числитель = Числитель; //берем из упаковки общего набора
НоваяУпаковка.Знаменатель = 1;
НоваяУпаковка.ВесоГабаритнаяУпаковка = Истина;

НоменклатураОбъект = Номенклатура.ПолучитьОбъект();
НоменклатураОбъект.ИспользоватьУпаковки = Истина; //это нельзя изменять, иначе сломаем логику
НоменклатураОбъект.НаборУпаковок = Справочники.НаборыУпаковок.ИндивидуальныйДляНоменклатуры;

Попытка
НоменклатураОбъект.Записать();
НоваяУпаковка.Записать();
Исключение
ЕстьОшибки = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("По ном-ре " + Номенклатура + " не удалось записать вес-брутто и/или создать индивидуальную упаковку"
+ Символы.ПС + ИнформацияОбОшибке().Описание);
КонецПопытки;

Возврат ЕстьОшибки;

КонецФункции

Функция ПолучитьБазовуюЕдиницуИзмерения(КодЕИ, МеждСокр, НаименованиеЕИ)

//примеры:
//166, KGM, кг
//778, NMP, упак

Рез = Неопределено;

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.ПометкаУдаления = ЛОЖЬ
| И УпаковкиЕдиницыИзмерения.Владелец = ЗНАЧЕНИЕ(Справочник.НаборыУпаковок.БазовыеЕдиницыИзмерения)
| И УпаковкиЕдиницыИзмерения.Код = &КодЕИ
| И УпаковкиЕдиницыИзмерения.МеждународноеСокращение = &МеждСокр
| И УпаковкиЕдиницыИзмерения.Наименование = &НаименованиеЕИ";

Запрос.УстановитьПараметр("КодЕИ", КодЕИ);
Запрос.УстановитьПараметр("МеждСокр", МеждСокр);
Запрос.УстановитьПараметр("НаименованиеЕИ", НаименованиеЕИ);

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Если Выборка.Следующий() Тогда
Рез = Выборка.Ссылка;
КонецЕсли;

Возврат Рез;

КонецФункции
Функция ПолучитьУпаковкуИзОбщегоНабора(ОбщийНабор)

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка,
| УпаковкиЕдиницыИзмерения.Наименование КАК Наименование,
| УпаковкиЕдиницыИзмерения.Числитель КАК Числитель
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.Владелец = &ОбщийНабор
| И УпаковкиЕдиницыИзмерения.ПометкаУдаления = ЛОЖЬ";

Запрос.УстановитьПараметр("ОбщийНабор", ОбщийНабор);

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Рез = Неопределено;
Если Выборка.Следующий() Тогда
Рез = Новый Структура("Наименование, Числитель");
Рез.Вставить("Наименование", Выборка.Наименование);
Рез.Вставить("Числитель", Выборка.Числитель);
КонецЕсли;

Возврат Рез;

КонецФункции

Функция ЗаписатьВесВКарточкуНоменклатуры(Номенклатура, Вес)

ЕстьОшибки = Ложь; //возвращаемый параметр

//вес-брутто измеряем в "кг" - на всякий случай запишем
//ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоКоду("166");
ЕИ_Кг = Справочники.УпаковкиЕдиницыИзмерения.НайтиПоНаименованию("кг", Истина, , Справочники.НаборыУпаковок.БазовыеЕдиницыИзмерения);

//вес-нетто - используем не для всей номенклатуры, а только для той, по которым упаковки не используются
//(ни общие наборы, ни индивидуальные)
НоменклатураОбъект = Номенклатура.ПолучитьОбъект();
НоменклатураОбъект.ВесИспользовать = Истина;
НоменклатураОбъект.ВесЧислитель = Вес;
НоменклатураОбъект.ВесЗнаменатель = 1;
НоменклатураОбъект.ВесЕдиницаИзмерения = ЕИ_Кг; //Кг

Попытка
НоменклатураОбъект.Записать();
Исключение
ЕстьОшибки = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("По ном-ре " + Номенклатура + " не удалось записать вес в карточку товара"
+ Символы.ПС + ИнформацияОбОшибке().Описание);
КонецПопытки;

Возврат ЕстьОшибки;

КонецФункции

Опять-таки все процедуры и функции можете вынести в один серверный модуль, и перед каждым пропишите директиву НаСервере.

Разделение по упаковкам

При создании расходного ордера на товар вызывается типовой метод разделения количества товаров по упаковкам. Метод интересный и удобный в том плане, что, если у вас отгружается 300 шт, и задана упаковка "упак (10 шт)", то программа пересчитает количество упаковок = 30 упак (10 шт).

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

К примеру менеджер оформил 310 штук товара (см. верхний абзац), тогда программа в расходнике соберет товар в двух строках - в первой будет = 30 упак (10 шт), во второй строке =10 шт остаток. С таким алгоритмом всегда будет "хвостик", и с таким алгоритмом все ошибки и эксперименты учета всегда будут видны в расходном ордере.

Для нашей задачи я сначала отключил автораспределение через процедуру ОбработкаЗаполнения() модуля документа Расходного ордера - просто закомментировал этот участок кода.

Если Не СкладыСервер.ИспользоватьАдресноеХранение(Склад, Помещение, ДатаОтгрузки) И ПолучитьФункциональнуюОпцию( "ИспользоватьУпаковкиНоменклатуры") Тогда
Документы.РасходныйОрдерНаТовары.РазбитьПоУпаковкамСправочно( ЭтотОбъект);
КонецЕсли;

Автораспределение срабатывает, если у вас ведется учет упаковок и не используется АдресноеХранение (см. код). Замечу, что сначала мы внедряли именно адресное хранение и с этим поведением расходного ордера не сталкивались. Когда изменили план внедрения и перешли на внедрение справочного указания ячеек, данный механизм неожиданно для нас сработал автоматически.

Распределение по упаковкам можно также вызвать интерактивно в форме расходника в разделе команд "Заполнить" - по упаковкам (справочно) или по распоряжениям.

Когда мы стали добавлять новые упаковки для маркетплейсов, пришлось вернуть данный участок кода. Но тогда пришлось добавить отбор в процедуру РазбитьПоУпаковкамСправочно(Объект) модуля менеджера Расходного ордера - отбор по "нашему" признаку ВесоГабаритнаяУпаковка (см. рис.)

Рис. 4. Доработка типового механизма распределения количества товара по упаковкам
Рис. 4. Доработка типового механизма распределения количества товара по упаковкам

Просмотр журнала регистрации

Объект метаданных справочника упаковок имеет несколько форм выбора: для единицы измерения, для упаковок, для выбора из документа и т.д. (см. рис.). Поэтому нельзя в журнале регистрации и в других нетиповых формах выбрать именно упаковку - всегда будет открываться по умолчанию форма выбора единиц измерения (!)

Рис. 5. Разные формы выбора - и при установке фильтра в журнале регистрации - для установки отбора одинаковых по названию упаковок - выбор упаковок никогда не откроется
Рис. 5. Разные формы выбора - и при установке фильтра в журнале регистрации - для установки отбора одинаковых по названию упаковок - выбор упаковок никогда не откроется

Для просмотра журнала регистрации по конкретной упаковке можно использовать программное открытие журнала регистрации. Реализуется через внешнюю обработку. Перед использованием обработки в наименование упаковки внесите звездочку в начало названия. Поиск упаковки я произвел по наличию "звездочки" в названии - см. код ниже.

//НаКлиенте
Процедура ОткрытьЖР(Команда)

Упаковка = ПолучитьУпаковкуИзОбщегоНабора();

// Отбор - Структура:
// Пользователь - Строка
// - СписокЗначений - имя или список пользователей информационной базы.
// СобытиеЖурналаРегистрации - Строка, Массив - идентификатор события.
// ДатаНачала - Дата - начало интервала отображаемых событий.
// ДатаОкончания - Дата - конец интервала отображаемых событий.
// Данные - Произвольный - данные любого типа.
// Сеанс - СписокЗначений - список выбираемых сеансов.
// Уровень - Строка, Массив - представление уровня важности события журнала регистрации.
// ИмяПриложения - Массив - массив идентификаторов приложения.

Отбор = Новый Структура("Данные");
Отбор.Вставить("Данные", Упаковка);

//Отбор.Пользователь = "Администратор";
//Отбор.ДатаНачала = НачалоДня(ТекущаяДата());
//Отбор.ДатаОкончания = КонецДня(ТекущаяДата());
//Отбор.Уровень = "Ошибка";
//Отбор.СобытиеЖурналаРегистрации = "Событие тестовое строкой1";

ЖурналРегистрацииКлиент.ОткрытьЖурналРегистрации(Отбор, ЭтаФорма);

КонецПроцедуры

//НаСервере
Функция ПолучитьУпаковкуИзОбщегоНабора()

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка,
| УпаковкиЕдиницыИзмерения.Наименование КАК Наименование,
| УпаковкиЕдиницыИзмерения.Числитель КАК Числитель
|ИЗ
| Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
|ГДЕ
| УпаковкиЕдиницыИзмерения.ПометкаУдаления = ИСТИНА
| И УпаковкиЕдиницыИзмерения.Наименование ПОДОБНО ""*%""";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Рез = Неопределено;
Если Выборка.Следующий() Тогда
Рез = Выборка.Ссылка;
КонецЕсли;

Возврат Рез;

КонецФункции

Вызов и открытие журнала регистрации надо производить с директивой НаКлиенте, а поиск и получение упаковки - с директивой НаСервере.

Запросы в консоли

1) первый запрос я использовал для вывода общей информации по номенклатуре, единицам измерения, упаковкам - общий запрос по номенклатуре.

ВЫБРАТЬ
Номенклатура.ИспользоватьУпаковки КАК Упак,
Номенклатура.ЕдиницаИзмерения.ТипИзмеряемойВеличины КАК ТипВеличины,
Номенклатура.ЕдиницаИзмерения.ТипУпаковки КАК ТипУпаковки,
Номенклатура.ЕдиницаИзмерения КАК ЕИ,
Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.ЕдиницаИзмерения.Вес КАК Вес,
Номенклатура.ЕдиницаИзмерения.ВесЕдиницаИзмерения КАК ЕИвес,
Номенклатура.НаборУпаковок КАК НаборУпаковок
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ПометкаУдаления = ЛОЖЬ
И Номенклатура.ЭтоГруппа = ЛОЖЬ
И Номенклатура.Ссылка = &Ссылка

УПОРЯДОЧИТЬ ПО
Упак,
ТипВеличины,
ТипУпаковки,
ЕИ,
ВидНоменклатуры
ИТОГИ ПО
Упак,
ТипВеличины,
ТипУпаковки,
ЕИ

2) второй запрос - общий запрос по справочнику единиц измерения - в одном списке намешано все: единицы измерения, упаковки, базовые единицы измерения.

ВЫБРАТЬ
УпаковкиЕдиницыИзмерения.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка,
УпаковкиЕдиницыИзмерения.Наименование КАК Наименование,
УпаковкиЕдиницыИзмерения.НаименованиеПолное КАК НаименованиеПолное,
УпаковкиЕдиницыИзмерения.МеждународноеСокращение КАК МеждународноеСокращение,
УпаковкиЕдиницыИзмерения.ТипИзмеряемойВеличины КАК ТипИзмеряемойВеличины,
УпаковкиЕдиницыИзмерения.ТипУпаковки КАК ТипУпаковки,
УпаковкиЕдиницыИзмерения.Числитель КАК Числитель,
УпаковкиЕдиницыИзмерения.Знаменатель КАК Знаменатель
ИЗ
Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
ГДЕ
УпаковкиЕдиницыИзмерения.ПометкаУдаления = ЛОЖЬ

УПОРЯДОЧИТЬ ПО
ЕдиницаИзмерения
ИТОГИ ПО
ЕдиницаИзмерения

3) третий запрос - общий запрос по упаковкам общих наборов.

ВЫБРАТЬ
УпаковкиЕдиницыИзмерения.Владелец КАК Владелец,
УпаковкиЕдиницыИзмерения.Ссылка КАК Ссылка,
УпаковкиЕдиницыИзмерения.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
УпаковкиЕдиницыИзмерения.Числитель КАК Числитель,
ВЫРАЗИТЬ(УпаковкиЕдиницыИзмерения.Владелец КАК Справочник.НаборыУпаковок).ЕдиницаИзмерения КАК ЕИНабора
ИЗ
Справочник.УпаковкиЕдиницыИзмерения КАК УпаковкиЕдиницыИзмерения
ГДЕ
УпаковкиЕдиницыИзмерения.Владелец ССЫЛКА Справочник.НаборыУпаковок
И УпаковкиЕдиницыИзмерения.ПометкаУдаления = ЛОЖЬ
И УпаковкиЕдиницыИзмерения.Владелец <> ЗНАЧЕНИЕ(Справочник.НаборыУпаковок.БазовыеЕдиницыИзмерения)
ИТОГИ ПО
ЕИНабора

4) четвертый запрос - запрос по остаткам на складе по номенклатуре, связанной с наборами упаковок.

ВЫБРАТЬ
ТоварыНаСкладахОстатки.Номенклатура.Ссылка КАК НоменклатураСсылка,
ТоварыНаСкладахОстатки.Номенклатура.НаборУпаковок КАК НоменклатураНаборУпаковок,
ТоварыНаСкладахОстатки.ВНаличииОстаток КАК ВНаличииОстаток,
ТоварыНаСкладахОстатки.Номенклатура.Код КАК НоменклатураКод,
ТоварыНаСкладахОстатки.Склад КАК Склад
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
ГДЕ
НЕ ТоварыНаСкладахОстатки.Номенклатура.НаборУпаковок.Предопределенный
И ТоварыНаСкладахОстатки.ВНаличииОстаток > 0
И ТоварыНаСкладахОстатки.Склад = &Склад

На этом все. Всем добра!

С пользой для клиентов, RustIG