В процессе работы со старыми типовыми конфигурациями «1С:Предприятие 8» (такими как «Комплексная автоматизация 1.1», «Управление производственным предприятием 1.3» или «Управление торговлей 10.3») пользователи и разработчики часто сталкиваются с крайне странным поведением системы. При создании документа сегодняшним числом в табличную часть при подборе подтягиваются цены из будущих документов установки цен (например, запланированных на начало следующего года или месяца). При этом, если изменить дату документа всего на один день назад или вперед, автоподбор начинает работать абсолютно корректно.
В данной статье мы подробно разберем, почему возникает этот классический «глюк», проанализируем логику работы платформы с виртуальными таблицами регистров сведений и найдем способ навсегда устранить эту ошибку в коде конфигурации.
Давайте воссоздадим ситуацию, описанную пользователями на форуме, чтобы понять логику проявления ошибки:
На первый взгляд такое поведение кажется мистическим. Почему равенство даты документа текущей дате ломает логику среза цен? Для ответа на этот вопрос нам придется заглянуть в конфигуратор.
Разберем детально, как инициализируется форма подбора в типовых конфигурациях. При нажатии кнопки «Подбор» программа подготавливает структуру параметров, которая будет передана в открывающуюся обработку подбора. В модуле формы документа или в специализированном общем модуле (например, при формировании параметров подбора) мы можем встретить следующий тернарный оператор:
ДатаРасчетов = ?(НачалоДня(ДатаДокумента) = НачалоДня(ТекущаяДата()), Неопределено, ДатаДокумента);
Рассмотрим подробнее логику, которой руководствовались разработчики 1С при написании этого условия:
ДатаРасчетов передается точное значение времени и даты документа.ДатаРасчетов передается системное значение Неопределено.Замысел разработчиков состоял в том, чтобы при работе «сегодняшним» числом база данных не тратила ресурсы на избыточную фильтрацию по дате, предполагая, что текущие актуальные цены — это просто самые последние записи в базе данных.
Однако здесь кроется ключевая архитектурная ловушка платформы «1С:Предприятие». Запрос, который отвечает за получение цен для формы подбора, обращается к виртуальной таблице среза последних:
ВЫБРАТЬ
ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаРасчетов, Номенклатура = &Номенклатура) КАК ЦеныНоменклатурыСрезПоследних
Согласно спецификации платформы 1С, поведение виртуальной таблицы СрезПоследних напрямую зависит от значения первого параметра (Период):
Дата, система выбирает самые последние записи, актуальные на указанный момент времени включительно. Все записи, сделанные позже этой даты, игнорируются.Неопределено (или пустая дата), то система считает, что ограничение по времени отсутствует вовсе. Срез берется на «бесконечность». Соответственно, запрос вернет абсолютно последние записи из регистра, даже если их дата лежит далеко в будущем относительно текущего момента времени.Именно поэтому при оформлении документа от 14.12.2018 (сегодняшнее число) параметр периода заменяется на Неопределено, запрос «пробивает» временную границу текущего дня и извлекает из базы данных будущие цены от 01.01.2019.
Подтверждение этой логики легко найти в коде управления элементами интерфейса формы подбора. Обратим внимание на следующее выражение, управляющее видимостью информационной надписи:
ЭлементыФормы.НадписьДатаРасчетов.Видимость = Не (ПодборПоСправочнику или НЕ ЗначениеЗаполнено(ДатаРасчетов));
Проанализируем работу этого выражения по шагам для случая, когда документ открыт сегодняшней датой:
ДатаРасчетов при открытии передано значение Неопределено.ЗначениеЗаполнено(Неопределено) возвращает результат Ложь.НЕ Ложь преобразует выражение в Истина.(ПодборПоСправочнику или Истина) в любом случае дает результат Истина.Не (Истина) превращается в Ложь.В результате свойство Видимость для надписи «Дата расчетов» принимает значение Ложь, и поле скрывается с формы. Программа считает, что дата расчетов «не задана» (так как передано пустое значение), хотя фактически пользователь ожидает расчеты именно на текущую дату компьютера.
Для того чтобы исправить это некорректное поведение и заставить систему всегда ориентироваться на фактическую дату документа (даже если она совпадает с сегодняшней), нам необходимо скорректировать логику заполнения параметров подбора в конфигураторе.
Откроем конфигурацию в режиме «Конфигуратор». Ошибка чаще всего кроется в общем модуле, отвечающем за работу с торговыми диалогами (например, РаботаСДиалогами, ОбработкаТабличныхЧастей) или непосредственно в модуле формы документа (например, ФормаДокумента реализации или заказа покупателя) в процедуре вызова подбора.
Воспользуемся глобальным поиском по конфигурации (сочетание клавиш Ctrl + Shift + F) и найдем строку инициализации переменной даты расчетов. Искать следует текст:
НачалоДня(ТекущаяДата())
Проанализируем найденный код. Нам необходимо заменить тернарное условие, убирающее дату, на прямую передачу даты документа.
Рассмотрим, как выглядел код ДО изменения:
// Старый некорректный вариант:
ВременнаяДатаРасчетов = ?(НачалоДня(Дата) = НачалоДня(ТекущаяДата()), Неопределено, Дата);
СтруктураПараметровПодбора.Вставить("ДатаРасчетов", ВременнаяДатаРасчетов);
Перепишем этот участок кода так, чтобы дата документа передавалась в подбор всегда, без каких-либо исключений:
// Новый исправленный вариант:
ВременнаяДатаРасчетов = Дата;
СтруктураПараметровПодбора.Вставить("ДатаРасчетов", ВременнаяДатаРасчетов);
Если вы работаете в конфигурации на управляемых формах (например, в более новых редакциях), передача параметров может происходить через структуру параметров формы при вызове метода ОткрытьФорму. В этом случае убедитесь, что свойство ДатаРасчетов заполняется значением Объект.Дата напрямую, без предварительных проверок на текущую дату компьютера.
После внесения изменений выполним следующие действия:
Таким простым изменением кода мы избавили пользователей от необходимости искусственно менять дату документа «на вчера», чтобы получить корректный расчет цен в подборе номенклатуры.