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