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