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