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