При ведении нормативно-справочной информации на производственных предприятиях часто возникает необходимость создать несколько аналогичных позиций номенклатуры на базе уже существующей. При этом стандартного копирования карточки недостаточно: вместе с номенклатурой требуется скопировать ее единицы измерения, привязать нужную спецификацию и сформировать сразу заданное количество дублей. Разберем, как правильно реализовать этот процесс, с какими ограничениями платформы можно столкнуться и как написать надежный программный код.
Когда разработчик впервые сталкивается с задачей кастомизации копирования, первыми кандидатами на реализацию кажутся стандартные обработчики платформы. Проанализируем, почему типовые события не всегда подходят для диалога с пользователем:
ПриКопировании в модуле объекта: процедура ПриКопировании(ОбъектКопирования) выполняется исключительно в контексте сервера. На сервере невозможно вызвать диалоговые окна с вопросами к пользователю (функция Вопрос()), открыть форму выбора спецификаций или запросить число копий. Любой интерактивный ввод должен происходить на стороне клиента до начала серверной записи.ПередНачаломДобавления в форме списка: перехват нажатия кнопки добавления или копирования срабатывает только при интерактивных действиях непосредственно в данной динамической таблице. Если пользователь открывает карточку или выполняет операцию из другого места системы, код не сработает. Кроме того, прерывание стандартного процесса для запуска серии копирований усложняет логику формы списка.Посмотрим на пример первой попытки перехвата события в динамическом списке, где при копировании открывается форма списка спецификаций:
Процедура СписокПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, ЭтоГруппа)
Если Копирование = Истина Тогда
Ответ = Вопрос("Необходимо ли скопировать спецификацию?", РежимДиалогаВопрос.ДаНет, 0, КодВозвратаДиалога.Нет);
Если Ответ = КодВозвратаДиалога.Да Тогда
ФормаОбъекта = Справочники.СпецификацииНоменклатуры.ПолучитьФорму("ФормаСписка");
ФормаОбъекта.Открыть();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Такой подход быстро показывает свои минусы: форма спецификаций открывается без отбора по исходной номенклатуре, а сам процесс создания копий не автоматизирован. Наиболее гибким решением в этой ситуации является создание отдельной формы-помощника (обработки или вспомогательной формы списка).
Для удобства пользователя в новой форме размещаются реквизиты: исходная Номенклатура (полученная в параметрах открытия), поле выбора Спецификация и числовое поле Количество (желаемое число создаваемых копий).
Выясним, как настроить выбор спецификации, чтобы пользователю не приходилось искать ее по всей базе данных. Необходимо переопределить обработчик НачалоВыбора и программно установить отбор по владельцу/выходному изделию. Разберем пример реализации для клиентской части формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Номенклатура = Параметры.СсылкаНом;
КонецПроцедуры
&НаКлиенте
Процедура СпецификацияНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ФормаВыбораСпецификации = Справочники.СпецификацииНоменклатуры.ПолучитьФормуВыбора(, Элемент);
// Устанавливаем отбор по исходной номенклатуре и признаку активности
ФормаВыбораСпецификации.Отбор.СпецификацииИзделийПоНоменклатуре.ВидСравнения = ВидСравнения.Равно;
ФормаВыбораСпецификации.Отбор.СпецификацииИзделийПоНоменклатуре.Значение = Номенклатура;
ФормаВыбораСпецификации.Отбор.СпецификацииИзделийПоНоменклатуре.Использование = Истина;
ФормаВыбораСпецификации.Отбор.Активная.Установить(Истина);
ФормаВыбораСпецификации.РежимВыбора = Истина;
ФормаВыбораСпецификации.Открыть();
КонецПроцедуры
Рассмотрим структуру тиражирования элементов. При создании дубликата номенклатуры нельзя просто вызвать метод Скопировать() для карточки товара. В типовых конфигурациях (таких как УПП) реквизиты ЕдиницаХраненияОстатков и ЕдиницаДляОтчетов ссылаются на подчиненный справочник ЕдиницыИзмерения, владельцем которых должна быть строго новая номенклатура.
Разберем по шагам логику, предложенную в решении:
Ссылка).Владелец на новую ссылку номенклатуры и записываем единицу.ВыходныеИзделия и заполняем строку данными только что созданной номенклатуры.Посмотрим на пример клиент-серверной реализации данной логики:
&НаКлиенте
Процедура СкопироватьНоменклатуру(Команда)
Если НЕ ЗначениеЗаполнено(Спецификация) Тогда
Предупреждение("Не выбрана спецификация. Копирование невозможно!");
Возврат;
КонецЕсли;
НоваяНом = Номенклатура.Ссылка;
Для ТекущийНомер = 1 По Количество Цикл
КопияНом = НоваяНом.Скопировать();
КопияНом.Записать();
КопияЕдХран = НоваяНом.ЕдиницаХраненияОстатков.Скопировать();
КопияЕдХран.Владелец = КопияНом.Ссылка;
КопияЕдХран.Записать();
Если НоваяНом.ЕдиницаХраненияОстатков <> НоваяНом.ЕдиницаДляОтчетов Тогда
КопияЕдОтч = НоваяНом.ЕдиницаДляОтчетов.Скопировать();
КопияЕдОтч.Владелец = КопияНом.Ссылка;
КопияЕдОтч.Записать();
КонецЕсли;
КопияНом.ЕдиницаХраненияОстатков = КопияЕдХран.Ссылка;
Если НоваяНом.ЕдиницаХраненияОстатков <> НоваяНом.ЕдиницаДляОтчетов Тогда
КопияНом.ЕдиницаДляОтчетов = КопияЕдОтч.Ссылка;
Иначе
КопияНом.ЕдиницаДляОтчетов = КопияЕдХран.Ссылка;
КонецЕсли;
КопияНом.Записать();
Если ЗначениеЗаполнено(Спецификация) Тогда
НоваяСпец = Спецификация.Ссылка;
КопияСпец = НоваяСпец.Скопировать();
КопияСпец.ВыходныеИзделия.Очистить();
Стр = КопияСпец.ВыходныеИзделия.Добавить();
Стр.Номенклатура = КопияНом.Ссылка;
Стр.ЕдиницаИзмерения = КопияНом.Ссылка.ЕдиницаХраненияОстатков;
Стр.Количество = 1;
Стр.Кратность = 1;
КопияСпец.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Приведенный алгоритм решает базовую задачу, однако для промышленной эксплуатации в рабочей базе необходимо учесть несколько важных технических факторов:
Скопировать(), Записать(), прямое обращение к менеджерам справочников) недоступны на тонком клиенте в управляемом приложении. Весь цикл создания и записи объектов следует выносить в процедуру с директивой &НаСервере или &НаСервереБезКонтекста, передавая туда параметры с клиента.НачатьТранзакцию() и ЗафиксироватьТранзакцию(). В случае непредвиденной ошибки в середине цикла конструкция ОтменитьТранзакцию() предотвратит появление «осиротевших» записей и некорректно заполненных карточек.ВидСпецификации). Табличная часть ВыходныеИзделия используется только для вида «Полная». Для сборочных спецификаций готовая продукция хранится в реквизитах шапки (Номенклатура, Количество). Очистка табличной части для таких спецификаций приведет к нарушению целостности структуры.ОсновныеСпецификацииНоменклатуры.Использование отдельной диалоговой формы с переносом тяжелой логики записи на сервер обеспечивает максимальную гибкость: пользователь контролирует выбор исходных данных, а система сохраняет стабильность при пакетном создании элементов.