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