При разработке обработок заполнения или загрузки данных в конфигурацию 1С:Бухгалтерия Предприятия 3.0 программисты часто сталкиваются со специфическим поведением системы: даже если в коде явно указано время документа 23:59:59 (конец дня), после вызова метода Записать() время принудительно меняется на 12:00:00. Это создает серьезные проблемы для документов списания (например, Расход материалов или Требование-накладная), так как если поступление товаров было зафиксировано позже 12:00, программа выдаст ошибку об отсутствии остатков на складе.
В этой статье мы подробно разберем, почему это происходит, проанализируем внутренние механизмы конфигурации и рассмотрим несколько способов решения этой задачи.
Для начала проанализируем ситуацию. В типовых решениях на базе 1С:Предприятие 8.3, и в частности в БП 3.0, реализована логика строгого упорядочивания документов внутри дня. Это сделано для того, чтобы пользователю не приходилось вручную выстраивать последовательность «Приход -> Расход».
Основные причины сброса времени:
ПриУстановкеНовогоНомераДокумента), которые обращаются к общим модулям (например, ОбщегоНазначенияБПСобытия). Эти модули переопределяют время в зависимости от типа документа: приходные документы записываются на начало дня, складские и расходные — на полдень (12:00), а регламентные — на конец дня.Записать() без параметров платформа может применять внутренние правила автоустановки времени, если они заданы на уровне метаданных или настроек.Рассмотрим подробнее программные способы обхода этого поведения.
Это один из самых эффективных, но требующих осторожности методов. Установка свойства ОбменДанными.Загрузка = Истина сообщает системе, что объект загружается из внешнего источника, и большинство проверок, а также подписок на события, должны быть проигнорированы.
Посмотрим на пример кода, который решает проблему:
// Создаем новый документ
ДокОбъект = Документы.ТребованиеНакладная.СоздатьДокумент();
ДокОбъект.Дата = КонецДня(Объект.ДатаДокумента);
// Заполняем необходимые реквизиты
ДокОбъект.Организация = Объект.Организация;
// ... заполнение табличных частей ...
// Устанавливаем режим загрузки, чтобы обойти подписки на события БП
ДокОбъект.ОбменДанными.Загрузка = Истина;
// ВАЖНО: При установленном флаге Загрузка номер автоматически не присвоится.
// Поэтому вызываем установку номера вручную.
ДокОбъект.УстановитьНовыйНомер();
// Записываем документ
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Преимущества этого метода: время гарантированно останется таким, каким вы его задали (23:59:59). Риски: при использовании Загрузка = Истина не сработают типовые проверки заполнения и бизнес-логика, заложенная в модуле объекта.
Если вы не хотите отключать механизмы платформы и подписки, можно воспользоваться методом «двойной записи». Суть заключается в том, что при первой записи система устанавливает время согласно своим правилам, а при второй записи (уже существующего в базе документа) логика «автоматического времени» обычно не срабатывает так агрессивно.
Разберем по шагам этот алгоритм:
// 1. Создаем и записываем документ с системным временем
ДокОбъект = Документы.ТребованиеНакладная.СоздатьДокумент();
ДокОбъект.Дата = Объект.ДатаДокумента;
// ... заполнение ...
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
// 2. Теперь, когда документ уже в базе и имеет номер, меняем дату на конец дня
ДокОбъект.Дата = КонецДня(Объект.ДатаДокумента);
// 3. Записываем повторно
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Этот метод более безопасен с точки зрения целостности данных, так как все подписки на события сработают штатно. Однако он менее производителен, так как выполняется две транзакции записи в базу данных вместо одной.
Проанализируем возможности встроенного языка платформы. У объекта документа есть метод УстановитьВремя(), который позволяет явно указать позицию документа на временной шкале. Рассмотрим пример:
ДокОбъект = Документы.ТребованиеНакладная.СоздатьДокумент();
ДокОбъект.Дата = Объект.ДатаДокумента;
// ... заполнение ...
// Используем системное перечисление РежимАвтоВремя
ДокОбъект.УстановитьВремя(РежимАвтоВремя.Последним);
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
К сожалению, в конфигурации Бухгалтерия Предприятия 3.0 этот метод часто перекрывается логикой в подписках «При записи» или «Перед записью». Если после выполнения этого кода время все равно становится 12:00, значит, в вашей версии конфигурации типовые механизмы имеют высший приоритет. В таком случае вернитесь к Способу 1.
Нужно понимать, зачем вообще требуется запись в конец дня. Как правило, это связано с ошибками проведения. Если документ создается программно без проведения (только запись), то время 12:00 не является критичным до момента попытки проведения.
Если ваша задача — обеспечить проведение документов вне зависимости от времени поступления товаров в рамках одного дня, можно рассмотреть альтернативный вариант: временное отключение контроля остатков для конкретного сеанса или пользователя, хотя это является крайней мерой и не рекомендуется для оперативного учета.
Проанализировав все варианты, мы рекомендуем придерживаться следующей стратегии при разработке в БП 3.0:
ОбменДанными.Загрузка = Истина совместно с явным вызовом УстановитьНовыйНомер(). Это самый быстрый и надежный способ сохранить нужное время.Важный момент: при использовании ручной установки времени всегда убеждайтесь, что вы используете функцию КонецДня() от нужной даты, чтобы избежать случайного переноса документа на следующий календарный день (например, если текущее время было близко к полуночи).