В практике разработки на платформе 1С:Предприятие 8 часто возникает задача трансформации данных в табличных частях документов. Одной из таких задач является «разбиение» или «развертка» строки: когда одна позиция с большим количеством (например, 5 единиц) должна превратиться в пять отдельных строк с количеством 1. Это может потребоваться для указания индивидуальных серий, штрихкодов, ячеек хранения или для подготовки данных к маркировке «Честный Знак».
В рамках этой статьи мы подробно разберем, как реализовать этот механизм программно, проанализируем типичные ошибки начинающих разработчиков и выясним, где искать стандартную кнопку в типовых конфигурациях.
Прежде чем приступать к написанию собственного кода, проанализируем возможности современных типовых конфигураций (таких как 1С:ERP, Управление торговлей 11 или Комплексная автоматизация). Разработчики фирмы «1С» уже предусмотрели механизмы разделения строк в большинстве складских и торговых документов.
Как правило, кнопка «Разбить строку» находится в командной панели табличной части (иногда она скрыта в подменю «Еще»). В документах «Отбор (размещение) товаров» или «Приходный ордер на товары» этот функционал работает автоматически при включенном адресном хранении или учете по сериям. Если вам нужно разделить строку вручную, поищите иконку с изображением двух стрелок, направленных в разные стороны.
Рассмотрим ситуацию, когда нам необходимо программно обойти табличную часть и разделить строки. Основная ошибка, которую совершают многие программисты (и что мы видим в сообщениях форума), — это попытка изменять коллекцию прямо в процессе её обхода циклом Для Каждого.
Проанализируем проблему: когда вы используете цикл Для Каждого СтрокаТЧ Из Объект.Товары и внутри добавляете новую строку методом Добавить(), индекс коллекции смещается, и цикл может либо уйти в бесконечность, либо пропустить необработанные строки. Чтобы этого избежать, мы рекомендуем два подхода:
Рассмотрим пример правильного обхода с конца:
// Определяем количество строк до начала обработки
ВсегоСтрок = Объект.Товары.Количество();
// Обходим таблицу с последней строки к первой
Для Индекс = -(ВсегоСтрок - 1) По 0 Цикл
ТекущийИндекс = -Индекс;
СтрокаТЧ = Объект.Товары[ТекущийИндекс];
Если СтрокаТЧ.Количество > 1 Тогда
ИсходноеКоличество = СтрокаТЧ.Количество;
// Устанавливаем количество в текущей строке равным 1
СтрокаТЧ.Количество = 1;
// Добавляем недостающие строки (Количество - 1)
Для Счетчик = 1 По (ИсходноеКоличество - 1) Цикл
НоваяСтрока = Объект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЧ);
НоваяСтрока.Количество = 1;
КонецЦикла;
КонецЕсли;
КонецЦикла;
При создании новых строк крайне важно перенести все реквизиты исходной строки: номенклатуру, упаковку, характеристики, ставку НДС и прочее. Чтобы не прописывать каждую колонку вручную, мы используем встроенную функцию ЗаполнитьЗначенияСвойств. Она автоматически сопоставляет имена колонок и копирует значения из строки-источника в новую строку.
Обратите внимание, что после копирования свойств в новой строке нужно обязательно скорректировать реквизит Количество (и, возможно, Сумма), иначе данные будут задвоены.
Часто задача разбиения строк возникает в момент создания одного документа на основании другого. В этом случае логику удобнее встроить в процедуру ОбработкаЗаполнения в модуле объекта. Выясним, как это выглядит на практике:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
Для Каждого ТекСтрока Из ДанныеЗаполнения.Товары Цикл
// Если в заказе 5 штук, создаем 5 строк в текущем документе
Для Счетчик = 1 По ТекСтрока.Количество Цикл
НоваяСтрока = Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекСтрока);
НоваяСтрока.Количество = 1;
// Не забываем про пересчет сумм, если это необходимо
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Проанализируем ситуацию с дробным количеством и денежными суммами. Если вы разбиваете строку, где количество было равно 3, а общая сумма составляла 100 рублей, то при простом делении у вас получится три строки по 33.33 рубля. В сумме это даст 99.99 рублей.
Важные рекомендации:
ОбработкаТабличнойЧастиКлиент.РассчитатьСуммуНДС.Для Счетчик = 1 По Количество не сработает. В таком случае необходимо использовать Цел(Количество) и отдельно обрабатывать остаток.Как упоминалось в сообщении 7 обсуждаемой темы, разбиение часто требуется для распределения товара по ячейкам. Если запрос к остаткам показывает, что товар лежит в трех разных ячейках, нам нужно создать три строки, даже если в исходном распоряжении была одна. В этом случае мы сначала получаем таблицу остатков по ячейкам, а затем в цикле заполняем табличную часть документа, уменьшая «требуемое» количество на то, что фактически нашли в каждой конкретной ячейке.
Таким образом, задача разбиения строки — это не просто создание дублей, а инструмент для детализации учета. Правильное использование индексов при обходе и методов копирования свойств позволит вам избежать ошибок «Метод объекта не обнаружен» и некорректного заполнения данных.