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