Почему Счет-фактура не проводится при проведении документа-основания через контекстное меню (ПКМ)?

Программист 1С v8.3 (Управляемые формы) Налоговый учет
← К списку

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

Причины возникновения проблемы и нежелательные практики

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

  1. Проблема прямого программного проведения из обработчика проведения:

    Попытки непосредственно провести подчиненный документ (например, СчетФактураВыданный) из обработчика проведения документа-основания (например, РеализацияТоваровУслуг) могут приводить к ошибкам. Платформа 1С выполняет множество внутренних проверок и транзакционных операций, которые могут конфликтовать при попытке провести другой документ в рамках той же или вложенной транзакции.

  2. Некорректное хранение данных:

    Например, хранение номера счета-фактуры непосредственно в реквизите расходной накладной является нетиповой и потенциально проблемной практикой. В стандартных конфигурациях 1С номер счета-фактуры — это реквизит самого документа СчетФактураВыданный, который связан с документом-основанием. При необходимости номер всегда можно получить через запрос к связанному документу.

  3. Попытки обхода стандартных проверок:

    Использование свойства ДополнительныеСвойства.Вставить("ПропуститьПроверкиПриПроведении", Истина); для объекта документа СчетФактура может привести к пропуску важных стандартных проверок при проведении. Это может временно "решить" проблему непроведения, но не устраняет ее корневую причину и может привести к некорректным данным, нарушению целостности базы данных и ошибкам в учете. Мы настоятельно не рекомендуем использовать этот подход.

  4. Изменение основного документа (ЭтотОбъект) в процессе проведения другого документа:

    Изменение и повторная запись основного документа (ЭтотОбъект) во время его собственного проведения, особенно для сохранения данных, полученных в ходе проведения подчиненного документа, является сложной и часто нежелательной практикой. Это может вызвать повторное проведение документа-основания, конфликты транзакций или непредсказуемое поведение системы.

  5. Общие причины непроведения документов:

    Помимо специфичных для связанных документов проблем, непроведение может быть вызвано и более общими причинами:

    • Ошибки в коде: Синтаксические или логические ошибки в обработчиках проведения.
    • Проблемы с данными: Некорректно заполненные обязательные реквизиты, отсутствие необходимых данных, нарушение ссылочной целостности.
    • Закрытый период: Попытка провести документ в уже закрытом для изменений периоде.
    • Ошибки при обмене данными: В распределенных информационных базах или при интеграции.

Решение 1: Использование стандартных механизмов БСП для проведения документов

Рассмотрим первый подход, который часто рекомендуется для программного проведения документов — использование функций из Библиотеки Стандартных Подсистем (БСП). БСП предлагает унифицированные и проверенные механизмы для выполнения многих типовых задач, что помогает избежать "велосипедов" и следовать лучшим практикам разработки в 1С.

Для попытки проведения документов в БСП существует метод ОбщегоНазначения.ПровестиДокументы() (или его серверный аналог ОбщегоНазначенияВызовСервера.ПровестиДокументы()). Этот метод принимает массив ссылок на документы, которые необходимо провести, и возвращает результат проведения с информацией об успехе или возможных ошибках.

Посмотрим на пример его использования:


МассивСсылок = Новый Массив;
МассивСсылок.Добавить(ТвояСФ.Ссылка); // Ссылка на документ Счет-фактура, который нужно провести
РезультатПроведения = ОбщегоНазначения.ПровестиДокументы(МассивСсылок);

Если РезультатПроведения[0].Проведен Тогда
    Сообщить("Счет-фактура успешно проведен: " + ТвояСФ.Ссылка);
Иначе
    Сообщить("Ошибка проведения Счет-фактуры: " + РезультатПроведения[0].ОписаниеОшибки);
КонецЕсли;

Почему этот метод может не сработать в контексте проведения основного документа?

Хотя ОбщегоНазначения.ПровестиДокументы() является правильным способом для программного проведения, его прямой вызов в обработчике проведения другого документа (особенно внутри одной транзакции) может столкнуться с проблемами. Это связано с тем, что платформа 1С может накладывать блокировки на данные, контролировать последовательность операций или ожидать завершения текущей транзакции до начала новой. В таких случаях вы можете получить ошибки, связанные с невозможностью проведения документа или конфликтами блокировок.

Решение 2: Отложенное проведение Счетов-фактур (Рекомендованное решение)

Если прямой вызов проведения связанного документа не работает, особенно при массовом вводе или сложных взаимосвязях, наиболее эффективным и типовым решением является использование механизма отложенного проведения. Этот подход, как подтвердил опыт пользователя на форуме, часто помогает решить проблему непроведения СФ при специфических сценариях, таких как проведение через ПКМ.

Что такое отложенное проведение?

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

Преимущества отложенного проведения:

  1. Снижение блокировок: Основной документ быстро проводится, освобождая ресурсы, а тяжелые операции по связанным документам выносятся во вне.
  2. Повышение производительности: Пользователи быстрее видят результат проведения основного документа.
  3. Устойчивость: Меньше вероятность возникновения ошибок, связанных с транзакциями и блокировками.

Механизм работы:

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

Как реализовать отложенное проведение для Счета-фактуры:

Мы не можем предоставить конкретный код для вашей конфигурации, так как механизм отложенного проведения требует глубокой интеграции с БСП и архитектурой вашей системы. Однако мы можем рассмотреть общие шаги:

  1. Идентификация необходимости отложенного проведения: В вашем коде, где вы пытаетесь провести СчетФактура, вместо прямого вызова проведения, вы должны пометить этот СчетФактура как требующий отложенного проведения. Это может быть сделано путем записи в специальный регистр или установки флага в самом документе, если такой механизм предусмотрен в вашей конфигурации или БСП.
  2. Настройка регламентного задания: Убедитесь, что у вас есть регламентное задание, которое периодически сканирует документы, помеченные для отложенного проведения, и выполняет их окончательное проведение. В типовых конфигурациях БСП есть стандартные регламентные задания для допроведения документов.
  3. Контроль и мониторинг: Предусмотрите механизмы для отслеживания статуса отложенно проводимых документов и обработки возможных ошибок, возникших при допроведении.

Связанные механизмы:

Также существует механизм "отложенного заполнения документов". Он используется, когда при проведении документа-источника он помещается в очередь отложенного заполнения, которая обрабатывается фоновым заданием для формирования документов-приемников. Это может быть полезно, если СчетФактура не только проводится, но и создается на основании другого документа.

Анализ и корректировка существующего кода

Давайте проанализируем код, который был предложен автором и не сработал, и выделим проблемные моменты, которые могли привести к непроведению счета-фактуры. Мы рассмотрим его в качестве примера для обучения.


Если НЕ Договор.Пустая() Тогда
    // Запрос для получения номера и ссылки СФ
    Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    СчетФактура.Ссылка КАК Ссылка,
        |    СчетФактура.Номер КАК Номер
        |ИЗ
        |    Документ.СчетФактура.Состав КАК СчетФактураСостав
        |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетФактура КАК СчетФактура
        |        ПО СчетФактураСостав.Ссылка = СчетФактура.Ссылка
        |ГДЕ
        |    СчетФактураСостав.Основание = &ДокументОснование
        |    И НЕ СчетФактура.ПометкаУдаления";
    Запрос.УстановитьПараметр("ДокументОснование", Ссылка);
    РезультатЗапроса = Запрос.Выполнить();

    СчетФактура = Неопределено;
    НомерСФ = "";
    Если НЕ РезультатЗапроса.Пустой() Тогда
        Выборка = РезультатЗапроса.Выбрать();
        Выборка.Следующий();
        СчетФактура = Выборка.Ссылка;
        НомерСФ = Выборка.Номер;
    КонецЕсли;

    Если ПустаяСтрока(НомерСФ)
        И струкУчетнаяПолитикаФирмы.АвтоматическоеФормированиеСчетаФактуры
        И ОмОбщиеПроцедурыИФункции.ПолучитьДоступностьВВодаСчетФактуры(Ссылка) Тогда
        Сообщить("Создаём СФ автоматически");
        Попытка
            ОмОбщиеПроцедурыИФункции.ВвестиСчетФактуруАвтоматически(ЭтотОбъект);
            // Повторный запрос для получения созданной СФ
            РезультатЗапроса = Запрос.Выполнить();
            Если НЕ РезультатЗапроса.Пустой() Тогда
                Выборка = РезультатЗапроса.Выбрать();
                Выборка.Следующий();
                СчетФактура = Выборка.Ссылка;
                НомерСФ = Выборка.Номер;
            КонецЕсли;
            Если ЗначениеЗаполнено(СчетФактура) Тогда
                // Проводим СФ
                СФОбъект = СчетФактура.ПолучитьОбъект();
                СФОбъект.ДополнительныеСвойства.Вставить("ПропуститьПроверкиПриПроведении", Истина);
                МассивСсылок = Новый Массив;
                МассивСсылок.Добавить(СчетФактура);
                РезультатПроведения = ОбщегоНазначения.ПровестиДокументы(МассивСсылок);
                Если РезультатПроведения[0].Проведен Тогда
                    Сообщить("СФ проведена: " + СчетФактура);
                Иначе
                    Сообщить("Ошибка проведения СФ: " + РезультатПроведения[0].ОписаниеОшибки);
                КонецЕсли;
            Иначе
                Сообщить("СФ не создана!");
            КонецЕсли;
        Исключение
            Сообщить("Ошибка создания СФ: " + ОписаниеОшибки());
        КонецПопытки;
    ИначеЕсли ЗначениеЗаполнено(СчетФактура)
        И ОмОбщиеПроцедурыИФункции.ПолучитьДоступностьВВодаСчетФактуры(Ссылка) Тогда
        Сообщить("Переоформляем СФ");
        Попытка
            ОмОбщиеПроцедурыИФункции.ПереоформлениеСчетФактуры(Ссылка);
            // Обновляем номер СФ
            РезультатЗапроса = Запрос.Выполнить();
            Если НЕ РезультатЗапроса.Пустой() Тогда
                Выборка = РезультатЗапроса.Выбрать();
                Выборка.Следующий();
                СчетФактура = Выборка.Ссылка;
                НомерСФ = Выборка.Номер;
            КонецЕсли;
            Сообщить("Переоформлен документ: Счет-фактура " + НомерСФ);
            // Проводим СФ
            СФОбъект = СчетФактура.ПолучитьОбъект();
            СФОбъект.ДополнительныеСвойства.Вставить("ПропуститьПроверкиПриПроведении", Истина);
            МассивСсылок = Новый Массив;
            МассивСсылок.Добавить(СчетФактура);
            РезультатПроведения = ОбщегоНазначения.ПровестиДокументы(МассивСсылок);
            Если РезультатПроведения[0].Проведен Тогда
                Сообщить("СФ проведена: " + СчетФактура);
            Иначе
                Сообщить("Ошибка проведения СФ: " + РезультатПроведения[0].ОписаниеОшибки);
            КонецЕсли;
        Исключение
            Сообщить("Ошибка переоформления СФ: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;

    // Заполняем НомерСф
    Если ЗначениеЗаполнено(НомерСФ) Тогда
        ЭтотОбъект.НомерСф = НомерСФ;
        ЭтотОбъект.ДополнительныеСвойства.Вставить("НеЗаполнятьНомерСФ", Истина);
        ЭтотОбъект.Записать(РежимЗаписиДокумента.Запись);
        Сообщить("Заполнен НомерСф в РН: " + ЭтотОбъект.НомерСф);
    КонецЕсли;
КонецЕсли;

Проанализируем этот код по шагам:

  1. Поиск и создание СФ:

    Код начинается с запроса для поиска существующего счета-фактуры. Если СФ не найден, он пытается создать его с помощью функции ОмОбщиеПроцедурыИФункции.ВвестиСчетФактуруАвтоматически(ЭтотОбъект);. Это хороший подход для автоматизации, но мы должны быть уверены в корректной работе этой функции.

  2. Критическая ошибка: Пропуск проверок при проведении:

    Строка СФОбъект.ДополнительныеСвойства.Вставить("ПропуститьПроверкиПриПроведении", Истина); является очень опасной практикой. Она отключает стандартные проверки платформы при проведении документа, что может привести к созданию некорректных движений, нарушению логики учета и ошибкам в данных. Мы настоятельно рекомендуем избегать использования этого свойства. Вместо этого необходимо выяснить причину, по которой документ не проводится, и устранить ее.

  3. Прямой вызов проведения в обработчике:

    Использование ОбщегоНазначения.ПровестиДокументы(МассивСсылок); непосредственно после создания/переоформления СФ и внутри обработчика проведения основного документа является причиной возникновения проблемы. Как мы уже обсуждали, это может приводить к конфликтам транзакций и блокировок, особенно при проведении документа-основания через ПКМ.

  4. Повторная запись основного документа:

    Строки ЭтотОбъект.НомерСф = НомерСФ; и ЭтотОбъект.Записать(РежимЗаписиДокумента.Запись); в конце кода пытаются обновить и записать основной документ (ЭтотОбъект) после получения номера счета-фактуры. Это также нежелательная практика, так как документ уже находится в процессе проведения. Повторная запись может вызвать непредсказуемое поведение, включая повторное проведение документа или ошибки, связанные с изменением объекта в неподходящий момент. Если номер СФ должен храниться, то лучше это делать не в реквизите документа-основания, а через механизмы дополнительных сведений или регистров.

Рекомендации по корректировке:

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

  1. Убрать ПропуститьПроверкиПриПроведении: Полностью исключите эту строку из кода.
  2. Использовать отложенное проведение: Вместо прямого вызова ОбщегоНазначения.ПровестиДокументы(), реализуйте механизм отложенного проведения для созданного или переоформленного счета-фактуры. Это означает, что после успешного создания или переоформления СФ, вы должны лишь пометить его для последующего проведения регламентным заданием.
  3. Избегать повторной записи ЭтотОбъект: Не записывайте основной документ повторно в его же обработчике проведения. Если вам необходимо сохранить номер СФ, рассмотрите альтернативные механизмы, например, дополнительные реквизиты или сведения, которые заполняются внешним по отношению к транзакции проведения образом, или вовсе отказаться от хранения этого номера в документе-основании, получая его по запросу при необходимости.

Таким образом, для надежного решения проблемы с непроведением счета-фактуры при проведении документа-основания, особенно через контекстное меню, мы настоятельно рекомендуем отказаться от прямого программного проведения связанных документов в обработчике проведения. Вместо этого следует использовать типовые механизмы БСП и, в частности, механизм отложенного проведения, который обеспечивает стабильность, производительность и корректность учета.

← К списку