Как в 1С определить, что документ проводится из обработки «Закрытие месяца»?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке и кастомизации конфигураций на платформе 1С:Предприятие 8.3 часто возникает классическая задача: разделить логику проведения документа в зависимости от того, кто или что инициировало этот процесс. Особенно актуально это для документов, которые массово перепроводятся в конце периода, таких как ОтражениеЗарплатыВБухучете, АмортизацияОС или РаспределениеРасходов.

Если документ проводится вручную (интерактивно бухгалтером), нам может потребоваться выполнить дополнительные проверки, заполнить аналитику или выдать предупреждение. Если же документ перепроводится регламентной обработкой Закрытие месяца, любые интерактивные диалоги должны быть исключены, а ресурсоемкие проверки — оптимизированы или отключены для ускорения группового закрытия периода.

В этой статье мы подробно разберем, как решить эту задачу изящно, надежно и, самое главное, без изменения типовой конфигурации, используя современные возможности платформы.

---

Метод 1. Использование механизма расширений и параметров сеанса (Рекомендуемый способ)

Наиболее архитектурно правильным и безопасным способом является использование механизма расширений конфигурации в связке с параметром сеанса. Мы временно взведем "флаг" в начале выполнения закрытия месяца и снимем его при завершении. В самом документе мы просто считаем этот флаг.

Давайте разберем этот метод по шагам:

  1. Создадим новое расширение конфигурации (или используем существующее).
  2. Добавим в расширение собственный параметр сеанса, например Расш_ВыполняетсяЗакрытиеМесяца с типом значения Булево.
  3. В модуле сеанса расширения установим его значение по умолчанию в Ложь при старте системы.
  4. Перехватим процедуру запуска регламентных операций в закрытии месяца. В конфигурации "Бухгалтерия предприятия 3.0" за это обычно отвечает общий модуль ЗакрытиеМесяцаБПСервер или модуль менеджера обработки ЗакрытиеМесяца. Мы применим аннотации &Перед и &После к ключевому методу проведения.

Рассмотрим пример кода в расширении для общего модуля, управляющего закрытием месяца:


&Перед("ВыполнитьРегламентныеОперации")
Процедура Расш1_ВыполнитьРегламентныеОперацииПеред(ПараметрыВыполнения)
    // Устанавливаем флаг перед началом выполнения регламентных операций
    ПараметрыСеанса.Расш_ВыполняетсяЗакрытиеМесяца = Истина;
КонецПроцедуры

&После("ВыполнитьРегламентныеОперации")
Процедура Расш1_ВыполнитьРегламентныеОперацииПосле(ПараметрыВыполнения)
    // Сбрасываем флаг после завершения процесса
    ПараметрыСеанса.Расш_ВыполняетсяЗакрытиеМесяца = Ложь;
КонецПроцедуры

Теперь проанализируем, как использовать этот флаг непосредственно в модуле документа (например, в обработчике события ОбработкаПроведения):


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Проверяем флаг из параметров сеанса
    ПроведениеИзЗакрытия = Ложь;
    Попытка
        Если ПараметрыСеанса.Расш_ВыполняетсяЗакрытиеМесяца = Истина Тогда
            ПроведениеИзЗакрытия = Истина;
        КонецЕсли;
    Исключение
        // На случай, если параметр сеанса не инициализирован
        ПроведениеИзЗакрытия = Ложь;
    КонецПопытки;

    Если ПроведениеИзЗакрытия Тогда
        // Здесь пишем оптимизированную логику для закрытия месяца
        // Например, отключаем сложные проверки заполнения реквизитов
    Иначе
        // Стандартные интерактивные проверки для обычного пользователя
        ВыполнитьПолнуюПроверкуДанных();
    EndIf;
    
КонецПроцедуры

Преимущества: Высочайшее быстродействие, надежность, полное соответствие стандартам разработки фирмы "1С". Код легко читать и поддерживать.

---

Метод 2. Программный анализ стека вызовов (Call Stack)

Что делать, если вам нужно решить задачу быстро, "здесь и сейчас", не создавая новые параметры сеанса в расширении, а логику нужно внедрить исключительно внутрь модуля самого документа? В этом случае на помощь приходит проверенный разработчиками лайфхак с программным анализом стека вызовов.

Идея заключается в том, чтобы вызвать контролируемое исключение (ошибку), перехватить его в блоке Попытка...Исключение и проанализировать текстовое представление стека функций, приведших к этой точке выполнения.

Давайте посмотрим, как выглядит реализация этого алгоритма:


Функция ЭтоПроведениеИзЗакрытияМесяца() Экспорт
    
    Результат = Ложь;
    
    Попытка
        // Искусственно вызываем исключение (деление на ноль)
        ВызватьОшибку = 1 / 0;
    Исключение
        ИнформацияОбОшибке = ИнформацияОбОшибке();
        // Получаем детальное описание стека вызовов в виде строки
        ТекстСтека = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
        
        // Ищем ключевые слова, характерные для процедур закрытия месяца
        Если СтрНайти(ТекстСтека, "ЗакрытиеМесяца") > 0 
           Или СтрНайти(ТекстСтека, "РегламентныеОперации") > 0 Тогда
            Результат = Истина;
        КонецЕсли;
    КонецПопытки;
    
    Возвратить Результат;
    
КонецФункции

Теперь в процедуре ОбработкаПроведения нашего документа достаточно вызвать эту функцию:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Если ЭтоПроведениеИзЗакрытияМесяца() Тогда
        // Логика при проведении регламентной операцией
    Иначе
        // Обычное интерактивное проведение
    КонецЕсли;
    
КонецПроцедуры

Преимущества: Код полностью локализован в одном месте (в модуле документа или его подписке). Никаких изменений в других объектах системы не требуется.

Минусы: Генерация исключений платформой — операция относительно "тяжелая" для процессора. Если документ проводится тысячами в цикле, этот метод может незначительно замедлить процесс выполнения.

---

Метод 3. Анализ текущего фонового задания

В современных типовых решениях (БП 3.0, ERP, КА) закрытие месяца практически всегда выполняется в фоновом режиме на сервере, чтобы не блокировать интерфейс пользователя. Платформа 1С позволяет получить параметры текущего выполняющегося потока (фонового задания).

Мы можем проанализировать имя метода или наименование фонового задания, которое запустило текущий процесс проведения. Выясним, как это реализовать на практике:


Функция ВыполняетсяВФоновомЗакрытииМесяца() Экспорт
    
    ТекущееЗадание = ФоновыеЗадания.ПолучитьТекущееФоновоеЗадание();
    
    Если ТекущееЗадание <> Неопределено Тогда
        
        ИмяМетода = ТекущееЗадание.ИмяМетода;
        Наименование = ТекущееЗадание.Наименование;
        
        // Выполняем поиск ключевых фраз в системных метаданных задания
        Если СтрНайти(ИмяМетода, "ЗакрытиеМесяца") > 0 
           Или СтрНайти(Наименование, "Закрытие месяца") > 0 Тогда
            Возврат Истина;
        КонецЕсли;
        
    КонецЕсли;
    
    Возврат Ложь;
    
КонецФункции

Преимущества: Высокая скорость работы (нет вызовов исключений), чистота кода, использование стандартного программного интерфейса платформы (API).

Минусы: Способ может не сработать, если в базе включена отладка в режиме "в один поток" или закрытие месяца принудительно запущено в монопольном режиме без фонового задания (хотя на рабочих базах такое встречается крайне редко).

---

Метод 4. Использование Дополнительных Свойств объекта

На форумах часто советуют использовать коллекцию ДополнительныеСвойства. Это действительно стандарт разработки фирмы "1С" для передачи параметров "сквозь" транзакцию. Но у него есть нюанс: чтобы свойство попало в документ, его нужно туда записать в коде обработки, которая документ проводит.

Если мы не хотим менять типовую обработку "Закрытие месяца", мы можем использовать расширение для перехвата момента записи документа внутри алгоритмов закрытия месяца.

Разберем по шагам, как настроить такую подмену через расширение:

  1. В расширении перехватываем процедуру проведения конкретного документа в модуле обработки закрытия месяца.
  2. Перед вызовом метода Записать() или Записать(РежимЗаписиДокумента.Проведение) внедряем свой флаг в структуру ДополнительныеСвойства.

Пример кода расширения для обработки закрытия месяца:


&Перед("ПровестиРегламентныйДокумент") // Имя процедуры зависит от конфигурации
Процедура Расш1_ПровестиРегламентныйДокумент(ДокументСсылка)
    
    // Получаем объект документа непосредственно перед записью алгоритмом закрытия
    ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
    Если ДокументОбъект <> Неопределено Тогда
        ДокументОбъект.ДополнительныеСвойства.Вставить("ПроведениеИзЗакрытияМесяца", Истина);
        // Записываем обратно, чтобы свойство передалось в ОбработкуПроведения
        // В зависимости от логики типового кода, возможно, документ проведется сам далее
    КонецЕсли;
    
КонецПроцедуры

В модуле проведения самого документа (например, ОтражениеЗарплатыВБухучете) проверяем это свойство:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Если ДополнительныеСвойства.Свойство("ПроведениеИзЗакрытияМесяца") 
       И ДополнительныеСвойства.ПроведениеИзЗакрытияМесяца = Истина Тогда
        // Документ пришел из регламентной операции
    КонецЕсли;
    
КонецПроцедуры

Преимущества: Строгое следование канонам объектно-ориентированного программирования в 1С. Свойства живут только в рамках одной транзакции.

---

Резюме и рекомендации

Мы проанализировали четыре различных подхода к решению задачи. Какой же из них выбрать?

Любой из этих методов позволит вам сохранить типовую конфигурацию на поддержке и гибко управлять бизнес-логикой проведения документов в вашей системе 1С!

← На главную