Работа с объектом ТаблицаЗначений — это базовая задача для любого разработчика 1С. Однако при реализации сложных алгоритмов, таких как интеграция с API логистических операторов (например, Новая Почта), возникают нюансы, связанные с типами данных и точностью вычислений. В этой статье мы разберем, как правильно обрабатывать данные из табличной части документа, разделять их по условиям и вычислять суммарные показатели, избегая типичных ошибок новичков.
Рассмотрим ситуацию, когда необходимо получить данные только по определенным единицам измерения (например, только "метры" или только "километры"). Типичная ошибка заключается в попытке передать в структуру поиска строковое значение вместо ссылки. Проанализируем пример кода:
Отбор = Новый Структура("ЕдиницаИзмерения", "м"); // Ошибка!
ТоварыМ = Товары.Скопировать(Отбор);
В системе 1С реквизит ЕдиницаИзмерения в табличных частях документов, как правило, имеет тип СправочникСсылка. Когда мы передаем строку "м", платформа пытается найти соответствие объекта строке, что всегда возвращает ложь. В результате мы получаем пустую таблицу или таблицу со всеми строками, если логика метода была нарушена.
Если нам нужно не просто получить копию таблицы, а быстро перебрать определенные строки для расчета, лучше всего использовать метод НайтиСтроки(). Рассмотрим по шагам, как это реализовать правильно.
Сначала нам необходимо получить правильную ссылку на элемент справочника. Для этого воспользуемся методом НайтиПоНаименованию. Проанализируем следующий алгоритм:
// Получаем ссылки на нужные единицы измерения
СсылкаМетр = Справочники.ЕдиницыИзмерения.НайтиПоНаименованию("м");
СсылкаКМетр = Справочники.ЕдиницыИзмерения.НайтиПоНаименованию("км");
// Формируем структуру отбора с использованием ссылок
Отбор = Новый Структура("ЕдиницаИзмерения", СсылкаМетр);
// Находим массив строк, соответствующих условию
НайденныеСтроки = Товары.НайтиСтроки(Отбор);
ОбщийВесМ = 0;
Для Каждого ТекущаяСтрока Из НайденныеСтроки Цикл
// Выполняем расчет с учетом специфики метров
// Например, если вес указан за 1000 метров
ОбщийВесМ = ОбщийВесМ + (ТекущаяСтрока.Количество * ТекущаяСтрока.Номенклатура.ВесЗаТысячу / 1000);
КонецЦикла;
Важный момент: метод НайтиСтроки возвращает Массив, содержащий ссылки на строки исходной таблицы. Это значит, что если вы измените значение в ТекущаяСтрока, оно изменится и в основной таблице Товары. Это очень удобно для массового обновления данных.
Если задача требует создания отдельной независимой таблицы (например, для вывода в отчет или передачи в другую функцию), используем метод Скопировать(). Выясним причину, по которой у автора вопроса "получалась фигня" при копировании. Когда мы вызываем Товары.Скопировать(Отбор), система создает новую таблицу значений, структура колонок которой полностью идентична исходной.
Давайте разберем правильный подход к копированию:
// 1. Сначала находим ссылку
СсылкаМ = Справочники.ЕдиницыИзмерения.НайтиПоНаименованию("м");
// 2. Создаем структуру отбора
ПараметрыОтбора = Новый Структура("ЕдиницаИзмерения", СсылкаМ);
// 3. Копируем строки в новую ТЗ
ТоварыМетры = Товары.Скопировать(ПараметрыОтбора);
// Теперь у нас есть отдельная таблица ТоварыМетры,
// где присутствуют только товары в метрах
Обратите внимание: если в исходной таблице Товары не было колонки ОбщВес, то и в новой таблице её не будет. Если вы добавили колонку программно в одну таблицу, а потом выполнили копирование из другой — старая переменная будет перезаписана новой таблицей.
В процессе работы с логистическими данными критически важна точность. В типовых конфигурациях 1С точность веса в справочниках часто ограничена 3 знаками после запятой. Если 1 метр весит очень мало, то при умножении на 5000 метров погрешность может составить несколько килограммов.
Чтобы решить эту проблему, проанализируем подход с хранением веса за более крупную единицу (например, за 1000 метров или за 1 километр) и последующим делением. Посмотрим на пример кода расчета:
Для Каждого СтрокаТЗ Из Товары Цикл
Если СтрокаТЗ.ЕдиницаИзмерения = СсылкаМетр Тогда
// Расчет для метров с повышенной точностью
ВесСтроки = (СтрокаТЗ.Количество * СтрокаТЗ.Номенклатура.ВесЗа1000м) / 1000;
СтрокаТЗ.ОбщВес = Окр(ВесСтроки, 3);
Иначе
// Обычный расчет для КМ
СтрокаТЗ.ОбщВес = СтрокаТЗ.Количество * СтрокаТЗ.ЕдиницаИзмерения.Вес;
КонецЕсли;
КонецЦикла;
ИтоговыйВес = Товары.Итог("ОбщВес");
Использование функции Окр() (Округление) позволяет избежать накопления "мусора" в дробной части числа, который возникает из-за особенностей представления чисел с плавающей точкой в памяти компьютера.
Рассмотрим ситуацию, когда в таблице товаров тысячи строк. Постоянный поиск методом НайтиСтроки может замедлить работу обработки. Для ускорения процесса рекомендуется использовать индексы. Проанализируем, как это сделать:
Перед началом всех поисков добавьте строку кода: Товары.Индексы.Добавить("ЕдиницаИзмерения");. Это создаст в оперативной памяти хэш-таблицу, которая позволит 1С мгновенно находить нужные строки без полного перебора таблицы. Это особенно полезно при работе с внешними API, где время отклика системы имеет значение.
Подведем итоги нашего анализа работы с таблицами значений:
НайтиПоНаименованию или НайтиПоКоду, а не сравнивайте со строкой.Скопировать(СтруктураОтбора) создает новую таблицу, уничтожая старое содержимое переменной.НайтиСтроки().Окр().Строка.ЕдиницаИзмерения.Вес) помните, что это вызывает обращение к базе данных. Если строк много, лучше заранее выгрузить нужные веса в структуру или соответствие.Соблюдение этих правил позволит вам писать надежный и быстрый код для обработки любых табличных данных в системе 1С:Предприятие.