В практике разработки на платформе 1С:Предприятие 8 часто возникает задача — обеспечить определенную последовательность документов в рамках одного дня. Типичный пример: документы «Выпуск продукции» должны располагаться раньше, чем «Реализация» или «Требование-накладная», чтобы обеспечить корректные остатки на складах в момент проведения. Однако, когда мы пытаемся программно установить время документа в 00:00:00 (начало дня), мы сталкиваемся с тем, что новые документы упорно встают в конец списка уже существующих документов этой же секунды. Разберем подробно, почему это происходит и как решить эту задачу.
Для начала проанализируем стандартный подход, который часто используют разработчики. Платформа предоставляет метод УстановитьВремя(), который позволяет задать позицию документа относительно других документов дня. Рассмотрим код:
ДокОбъект = Документы.ВыпускПродукции.СоздатьДокумент();
ДокОбъект.Дата = НачалоДня(ТекущаяДата());
ДокОбъект.УстановитьВремя(РежимАвтоВремя.Первым, Истина);
ДокОбъект.Записать();
Как работает этот код: Система ищет самый ранний документ в указанном дне. Если самый ранний документ имеет время, например, 00:00:05, то наш новый документ получит время 00:00:04. Проблема возникает тогда, когда в базе уже есть документы с временем 00:00:00. Платформа не может установить отрицательное время или время, относящееся к предыдущему дню. В итоге новый документ также получает время 00:00:00 и «проигрывает» конкуренцию за первенство.
В отличие от версии 7.7, где количество документов в одной секунде было ограничено, в 1С 8.x таких ограничений нет. Порядок документов внутри одной секунды определяется понятием Момент времени. Момент времени — это комбинация даты/времени и уникального идентификатора ссылки (GUID).
Проанализируем ситуацию: если у десяти документов время совпадает до секунды, система выстраивает их по возрастанию бинарного представления их GUID. При создании нового документа система генерирует новый УникальныйИдентификатор. В большинстве случаев (хотя и не всегда, из-за специфики генерации последовательных GUID в SQL) новый идентификатор будет «больше» предыдущих, и документ визуально окажется в конце списка документов данной секунды.
Самый чистый и надежный способ — это изменение административной политики записи документов. Мы можем договориться (и реализовать программно), что все «обычные» документы в системе записываются, начиная с 00:00:01. Тогда секунда 00:00:00 резервируется исключительно для тех документов, которые обязаны быть первыми (ввод остатков, выпуски продукции и т.д.).
Разберем, как это реализовать при записи «обычного» документа:
Если ДокОбъект.Дата = НачалоДня(ДокОбъект.Дата) Тогда
// Сдвигаем время на 1 секунду вперед, чтобы освободить 00:00:00
ДокОбъект.Дата = ДокОбъект.Дата + 1;
КонецЕсли;
ДокОбъект.Записать();
Если ситуация критическая и документ обязательно должен стоять перед уже существующими документами с временем 00:00:00, нам придется «подвинуть» конкурентов. Это ресурсоемкая операция, так как она требует перепроведения документов, но иногда это единственный выход. Рассмотрим алгоритм:
00:00:00.00:00:00.Пример кода для сдвига:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг
|ГДЕ
| Дата = &НачалоДня";
Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ТекДата));
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
ОбъектДок = Результат.Ссылка.ПолучитьОбъект();
ОбъектДок.Дата = ОбъектДок.Дата + 1; // Сдвиг на 1 секунду
ОбъектДок.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
Как упоминалось в обсуждении, порядок внутри секунды зависит от ссылки. Теоретически можно попытаться создать документ с заранее определенным УникальнымИдентификатором, который будет «меньше» существующих. Однако на практике это крайне сложно реализовать, так как 1С и СУБД (особенно SQL Server) используют сложные алгоритмы сортировки уникальных идентификаторов, и простое «уменьшение» строки GUID не гарантирует его позицию в начале индекса таблицы. Кроме того, создание документов с кастомными GUID может привести к фрагментации индексов базы данных.
Иногда разработчики путают физический порядок документов в базе (влияющий на итоги в регистрах) и визуальный порядок в списке. Если ваша задача — просто показать пользователю последний созданный документ вверху списка, не стоит мучить время документа. Для этого достаточно настроить сортировку в динамическом списке.
Разберем настройку формы списка:
Дата (Убывание) и Ссылка (Убывание).В этом случае, даже если у документов время совпадает до секунды, самый «свежий» документ (с большим GUID) будет отображаться выше остальных при сортировке по убыванию.
Проанализировав проблему, можно сделать следующие выводы:
УстановитьВремя(РежимАвтоВремя.Первым) бессилен, если в базе уже есть документы на начало дня.00:00:00. Оставляйте эту секунду пустой для исключительных случаев или ручного ввода остатков.НачалоДня(ТекДата) + 10 для обычных операций).Помните, что корректная последовательность документов важна прежде всего для механизмов последовательностей и границ оперативных итогов. Если вы обеспечите документам выпуска продукции время 00:00:00, а документам продажи — 00:00:01, вы навсегда избавитесь от проблем с нехваткой остатков при проведении документов «одним числом».