Почему отчет по состоянию заявки в 1С 7.7 не видит документы отгрузки?

Программист 1С v7.7 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Разберем подробно причины такого поведения, проанализируем структуру многорегистрового запроса, выясним, почему движения документов могут теряться, и рассмотрим надежные способы получения точных данных.

Анализ проблемы: многорегистровый запрос и его ограничения

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


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ДатаНачала по ДатаКонца;
|Заявка = Регистр.Заявки.ЗаявкаПокупателя,
|         Регистр.ЗаказыЗаявки.ЗаявкаПокупателя,
|         Регистр.РезервыТМЦ.ЗаявкаПокупателя;
|ТекДок = Регистр.Заявки.ТекущийДокумент;
|Договор = Регистр.РезервыТМЦ.ДоговорПокупателя;
|Фирма = Регистр.РезервыТМЦ.Фирма,
|        Регистр.ОстаткиТМЦ.Фирма,
|        Регистр.Заявки.Фирма,
|        Регистр.ЗаказыЗаявки.ЗаявкаПокупателя.Фирма;
|КолЗаявки = Регистр.Заявки.КоличествоРасход;
|КолЗаказа = Регистр.ЗаказыЗаявки.Количество;
|КолРезерва = Регистр.РезервыТМЦ.Количество;
|КолОстатка = Регистр.ОстаткиТМЦ.Количество;
|Номенклатура = Регистр.Заявки.Номенклатура,
|               Регистр.ЗаказыЗаявки.Номенклатура,
|               Регистр.РезервыТМЦ.Номенклатура,
|               Регистр.ОстаткиТМЦ.Номенклатура;
|Функция ВыписанаЗаявка = Приход(КолЗаявки) Когда (Заявка = ВыбДокумент);
|Функция ОстатокНаСкладах = КонОст(КолОстатка);
|Функция ОстатокЗаявки = КонОст(КолЗаявки) Когда (Заявка = ВыбДокумент);
|Функция Отпущено = Расход(КолЗаявки) Когда((Заявка = ВыбДокумент) и (ТекДок.Вид <> ""ЗаявкаПокупателя"") и (ТекДок.Вид <> ""ОтменаЗаявок""));
|Группировка Номенклатура Без Групп;
|Условие (Номенклатура в СписокНоменклатуры);
|Условие (Фирма = ФирмаЗаявки);
|";

Синтаксис платформы 1С 7.7 позволяет объединять измерения и ресурсы нескольких регистров в одну переменную через запятую. При этом платформа объединяет движения всех указанных регистров: запись попадает в выборку, если значение измерения присутствует хотя бы в одном из них. Однако совмещение четырех различных регистров (Заявки, ЗаказыЗаявки, РезервыТМЦ, ОстаткиТМЦ) в одном запросе порождает несколько узких мест:

  1. Использование реквизитов одиночного регистра в общих функциях. Переменная ТекДок объявлена только для регистра Заявки. При расчете агрегатов без группировки по самому документу (Группировка Документ;) обращение к свойствам через точку (например, ТекДок.Вид) внутри условий Когда (...) может возвращать пустое значение или отсекать строки других регистров и движений.
  2. Сложная логика условий в функциях. Наложение условий Когда (Заявка = ВыбДокумент) на сводную таблицу агрегирования снижает производительность и часто приводит к трудноуловимым ошибкам при перекрытии записей разных регистров.

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

Если запрос составлен синтаксически верно, но одна из реализаций упорно игнорируется при расчете функций Отпущено и ОстатокЗаявки, причину следует искать по цепочке от движений до параметров периода:

  1. Списание по другим заявкам в модуле проведения документа. В большинстве типовых и доработанных конфигураций (например, в «Торговля и Склад 7.7») модуль документа Реализация при проведении списывает остатки заявок не только жестко по ссылке, но и по методу ФИФО. Если на момент проведения реализации остаток по выбранной заявке уже исчерпан или отсутствует, алгоритм автоматически подбирает и закрывает другую более раннюю открытую заявку контрагента либо формирует расход без привязки к заказу. В результате вторая реализация списывает товар с нужной заявки, а первая — с чужой.
  2. Точка актуальности и хронология документов. Если документ отгрузки создан или проведен раньше времени исходной заявки, на момент проведения реализации остатка в регистре Заявки еще нет. Проведение пойдет некорректно, даже если внешне документы привязаны друг к другу.
  3. Ограничение границы периода в тексте запроса. Строка |Период с ДатаНачала по ДатаКонца; жестко ограничивает выборку конечной датой. Если документ проведен концом дня или позже указанной границы, его обороты и влияние на КонОст будут потеряны. Если необходимо получить актуальный остаток на текущий момент без отсечения более поздних документов, период следует задавать с открытой правой границей: |Период с ДатаНачала;.

Способ 1. Упрощение и разделение запроса

Если для конкретного отчета требуются только показатели выполнения заказа покупателя (выписано, отпущено и текущий остаток по заявке), не следует объединять в одном запросе остатки на складах и резервы. Ограничимся запросом исключительно к регистру Заявки:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ДатаНачала;
|Заявка = Регистр.Заявки.ЗаявкаПокупателя;
|Номенклатура = Регистр.Заявки.Номенклатура;
|Кол = Регистр.Заявки.КоличествоРасход;
|ТекДок = Регистр.Заявки.ТекущийДокумент;
|Функция Выписано = Приход(Кол);
|Функция Отгружено = Расход(Кол) Когда ((ТекДок.Вид <> ""ЗаявкаПокупателя"") и (ТекДок.Вид <> ""ОтменаЗаявок""));
|Функция Остаток = КонОст(Кол);
|Группировка Номенклатура Без Групп;
|Условие (Заявка = ВыбДокумент);
|";

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Пока Запрос.Группировка(1) = 1 Цикл
        // Обработка результатов по номенклатуре
    КонецЦикла;
КонецЕсли;

Условие Условие (Заявка = ВыбДокумент);, вынесенное на уровень всего запроса, работает значительно быстрее и надежнее, чем фильтрация внутри каждой расчетной функции Когда (...).

Способ 2. Прямая работа с объектом регистра (без использования запроса)

Для анализа состояния одной конкретной заявки покупателя наиболее производительным и точным решением в 1С 7.7 является использование встроенных методов объекта Регистр. Это исключает накладные расходы внутреннего движка запросов и гарантирует получение точных срезов:


РегЗаявки = СоздатьОбъект("Регистр.Заявки");

// Устанавливаем фильтр по конкретной заявке (1 - жесткий фильтр)
РегЗаявки.УстановитьЗначениеФильтра("ЗаявкаПокупателя", ВыбДокумент, 1);

// Выполняем временный расчет итогов
РегЗаявки.ВременныйРасчет(1);
РассчитатьРегистрыНа(ТекущаяДата());

ТабИтогов = СоздатьОбъект("ТаблицаЗначений");
РегЗаявки.ВыгрузитьИтоги(ТабИтогов, 1, 1);

// В ТабИтогов получаем точные остатки по номенклатуре для выбранного заказа

Если требуется проанализировать движения за период, используем перебор движений с помощью методов ВыбратьДвиженияДокумента() или ВыбратьДвижения(), что позволяет наглядно увидеть, какой именно документ и в каком объеме закрыл заявку.

Порядок диагностики ошибок при неверных показателях в отчетах

  1. Проверяем физические движения в регистре. Открываем движения каждой реализации по регистру Заявки и сверяем значение в колонке измерения ЗаявкаПокупателя. Если в первой реализации поле пустое или содержит другую заявку, проблема заключается в логике модуля документа реализации.
  2. Проверяем хронологическую последовательность. Убеждаемся, что время проведения заявки строго предшествует времени проведения всех связанных с ней реализаций.
  3. Проверяем открытую границу периода. При формировании отчетов по исполнению заказов используем синтаксис |Период с ДатаНачала;, чтобы расчет конечного остатка (КонОст) включал все последующие корректировки и отгрузки.
← На главную