Как правильно реализовать пересчет количества с учетом коэффициента в табличной части документа 1С

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Управленческий учет Торговля и дистрибуция
← На главную

При разработке в среде 1С:Предприятие часто возникает задача автоматического пересчета данных в табличной части документа. Типичный пример — документ ПеремещениеТоваров, где при заполнении на основании ПоступленияТоваровИУслуг необходимо умножить базовое количество на коэффициент упаковки. Однако за этой простой арифметической операцией скрываются серьезные риски для целостности данных и корректности складского учета.

В этой статье мы подробно разберем, как реализовать подобную логику, избежав "подводных камней", таких как бесконечное умножение при перезаписи документа, и выберем оптимальный технический метод решения задачи.

Анализ проблемы: почему нельзя просто перемножить данные при открытии

Разберем ситуацию, которая часто встречается у начинающих разработчиков. Если мы решим программно изменять Количество непосредственно в обработчике ПриОткрытии или в момент загрузки данных без дополнительных проверок, мы можем столкнуться с проблемой рекурсивного пересчета.

Представим сценарий: в базе хранится Количество = 10 и Коэффициент = 2. При открытии документа программа видит эти данные и умножает их: 10 * 2 = 20. Пользователь сохраняет документ. При следующем открытии программа снова видит Количество (уже 20) и снова умножает на Коэффициент 2. В итоге количество становится 40, затем 80 и так далее. Это приведет к полному краху партионного учета и остатков на складах. Выясним, как сделать пересчет безопасным.

Решение 1. Использование запроса для вычисления значений

Если данные в документ ПеремещениеТоваров попадают из другого документа (например, ПоступлениеТоваровИУслуг) с помощью запроса, наиболее логично произвести вычисления на уровне СУБД. Проанализируем, как будет выглядеть такой запрос.

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


ТекстЗапроса = 
"ВЫБРАТЬ
|	ПоступлениеТовары.Номенклатура КАК Номенклатура,
|	ПоступлениеТовары.Количество КАК ИсходноеКоличество,
|	ПоступлениеТовары.Коэффициент КАК Коэффициент,
|	ВЫБОР
|		КОГДА ПоступлениеТовары.Коэффициент > 1
|			ТОГДА ПоступлениеТовары.Количество * ПоступлениеТовары.Коэффициент
|		ИНАЧЕ ПоступлениеТовары.Количество
|	КОНЕЦ КАК КоличествоДляПеремещения
|ИЗ
|	Документ.ПоступлениеТоваровИУслуг.Товары КАК ПоступлениеТовары
|ГДЕ
|	ПоступлениеТовары.Ссылка = &СсылкаНаПоступление";

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

Решение 2. Программный обход строк в объекте

Если нам нужно выполнить пересчет уже после того, как данные попали в документ, но перед его записью, мы используем программный перебор строк табличной части. Чтобы избежать вышеописанной проблемы рекурсии, мы должны четко понимать логику: перемножаем ли мы "Количество мест" на "Коэффициент" или "Базовое количество" на "Коэффициент".

Проанализируем пример кода, который выполняет расчет для каждой строки:


Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    // Проверяем наличие коэффициента и заполненность данных
    Если СтрокаТЧ.Коэффициент > 1 Тогда
        // Безопасный расчет: за основу берем количество мест, 
        // чтобы не умножать уже пересчитанное базовое количество
        СтрокаТЧ.Количество = СтрокаТЧ.КоличествоМест * СтрокаТЧ.Коэффициент;
    КонецЕсли;
КонецЦикла;

Важный момент: в типовых конфигурациях 1С (таких как БП 3.0 или УТ 11) логика обычно строится на том, что Количество — это всегда количество в базовых единицах измерения (штуках), а КоличествоМест — это количество в упаковках. Если вы меняете Количество, вы напрямую влияете на движения по регистрам накопления.

Решение 3. Визуальное отображение без изменения данных (Условное оформление)

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

  1. Добавим на форму документа в таблицу Товары новый элемент — Поле (без привязки к реквизиту объекта).
  2. Назовем его КоличествоСУчетомКоэффициента.
  3. В обработчике события ПриУсловномОформлении или через установку пути к данным (если это позволяет конфигурация) настроим отображение.

Однако чаще всего расчетные поля на форме реализуются через событие ПриВыводеСтроки (в обычных формах) или через вычисляемые реквизиты в расширениях. Посмотрим на наиболее современный метод — использование обработчика ПриИзменении на форме:


&НаКлиенте
Процедура ТоварыКоличествоМестПриИзменении(Элемент)
    СтрокаТЧ = Элементы.Товары.ТекущиеДанные;
    Если СтрокаТЧ <> Неопределено Тогда
        // Выполняем расчет в реальном времени при вводе данных пользователем
        СтрокаТЧ.Количество = СтрокаТЧ.КоличествоМест * СтрокаТЧ.Коэффициент;
    КонецЕсли;
КонецПроцедуры

Контроль точности и округления

При умножении Количества на дробный Коэффициент (например, при переводе из литров в килограммы или при использовании специфических коэффициентов упаковок) неизбежно возникают проблемы с округлением. В 1С стандартная точность для количества — 3 знака после запятой.

Разберем, как правильно применять функцию Окр(), чтобы избежать ошибок при проведении документа. Если результат умножения будет иметь 5 знаков после запятой, а реквизит базы данных настроен на 3, система может выдать ошибку или неверно распределить себестоимость.

Используем следующий подход при расчетах:

СтрокаТЧ.Количество = Окр(ИсходноеЗначение * Коэффициент, 3, РежимОкругления.Через0_5);

Профессиональные рекомендации

Для создания качественного и отказоустойчивого решения придерживайтесь следующих правил:

Подводя итог, отметим: технически реализовать умножение несложно, но важно выбрать момент (заполнение или изменение на форме), чтобы не нарушить бизнес-логику документа. Самым надежным способом является расчет в момент подбора товара или заполнения по основанию, с последующей возможностью ручной корректировки пользователем через обработчик ПриИзменении.

← На главную