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