В типовой практике ведения учета в конфигурации «1С:Управление нашей фирмой» (УНФ) часто возникает задача автоматизации рутинных операций. Одной из таких задач является автоматическое создание и проведение документа Счет-фактура (СФ) сразу после того, как пользователь провел документ Расходная накладная (РТУ). Это позволяет избежать забывчивости сотрудников и гарантирует наличие всех необходимых документов для налогового учета.
Рассмотрим, как реализовать этот механизм с помощью расширения, разберем типичные ошибки в коде запросов и выясним, почему расширение может «не подхватываться» системой.
Для реализации автоматического создания документа нам необходимо привязаться к моменту, когда основной документ (Расходная накладная) уже записан в базу данных и имеет ссылку. Наиболее подходящим местом в форме документа является событие ПослеЗаписиНаСервере. Мы будем использовать аннотацию &После, чтобы наш код выполнялся сразу после стандартных процедур записи конфигурации.
Проанализируем структуру процедуры. Нам важно убедиться, что:
Одной из главных проблем, с которой сталкиваются разработчики при написании кода для расширений, является синтаксис запроса и передача параметров. Рассмотрим пример некорректного кода, часто встречающегося на форумах:
ГДЕ
РасходнаяНакладная.Проведен = &Проведен
И СчетФактура.Ссылка ЕСТЬ NULL
И РасходнаяНакладная.Ссылка = &Ссылка
Проанализируем ситуацию: в языке запросов 1С поле Проведен является булевым. Передача параметра &Проведен излишня и часто ведет к ошибке, если разработчик забыл установить этот параметр в коде 1С. Правильнее использовать прямое обращение к полю.
Исправленный вариант условия запроса должен выглядеть так:
ГДЕ
РасходнаяНакладная.Проведен
И СчетФактура.Ссылка ЕСТЬ NULL
И РасходнаяНакладная.Ссылка = &Ссылка
Здесь условие РасходнаяНакладная.Проведен само по себе возвращает Истина или Ложь, что является корректным для секции ГДЕ.
В 1С:УНФ и других современных конфигурациях связь между Счетом-фактурой и основанием часто реализуется через табличную часть ДокументыОснования. При написании запроса с ЛЕВОЕ СОЕДИНЕНИЕ важно правильно указать условие связи. Если мы просто соединяем документы, мы можем получить пустой результат или, наоборот, дубли. Рассмотрим правильный способ проверки существования подчиненного документа:
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| СчетФактура.Ссылка КАК Ссылка
|ИЗ
| Документ.СчетФактура КАК СчетФактура
|ГДЕ
| СчетФактура.ДокументыОснования.ДокументОснование = &Ссылка
| И НЕ СчетФактура.ПометкаУдаления";
Такой запрос гораздо эффективнее: он ищет хотя бы один существующий и не помеченный на удаление документ СчетФактура, в табличной части которого указана наша накладная.
Когда мы убедились, что Счет-фактура отсутствует, перейдем к ее созданию. Разберем по шагам процесс заполнения данных. Важно помнить, что в УНФ для корректного заполнения СФ недостаточно просто создать объект, нужно вызвать процедуру Заполнить(), которая инициализирует параметры на основании переданной структуры или объекта-основания.
Посмотрим на пример правильной реализации процедуры в расширении:
&НаСервере
Процедура СА_АФСФ_ПослеЗаписиНаСервереПосле(ТекущийОбъект, ПараметрыЗаписи)
// Проверяем, что документ проведен.
// Используем ТекущийОбъект, так как это расширение формы, и объект уже записан.
Если Не ТекущийОбъект.Проведен Тогда
Возврат;
КонецЕсли;
// Проверяем наличие существующего СФ
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СчетФактура.Ссылка КАК Ссылка
|ИЗ
| Документ.СчетФактура КАК СчетФактура
|ГДЕ
| СчетФактура.ДокументыОснования.ДокументОснование = &Основание
| И НЕ СчетФактура.ПометкаУдаления";
Запрос.УстановитьПараметр("Основание", ТекущийОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
// СФ уже существует, выходим
Возврат;
КонецЕсли;
// Создаем новый документ
НовыйСФ = Документы.СчетФактура.СоздатьДокумент();
// Заполняем структуру для инициализации
ДанныеДляЗаполнения = Новый Структура;
ДанныеДляЗаполнения.Вставить("ДокументОснование", ТекущийОбъект.Ссылка);
ДанныеДляЗаполнения.Вставить("Организация", ТекущийОбъект.Организация);
ДанныеДляЗаполнения.Вставить("Дата", ТекущийОбъект.Дата);
// Вызываем типовой механизм заполнения
НовыйСФ.Заполнить(ДанныеДляЗаполнения);
Попытка
НовыйСФ.Записать(РежимЗаписиДокумента.Проведение);
Исключение
ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации("АвтоматическоеСозданиеСФ", УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
КонецПопытки;
КонецПроцедуры
Если код написан верно, но результат (созданный СФ) отсутствует, выясним причину с помощью последовательной диагностики.
1. Проверка активности расширения. Убедитесь, что в списке расширений у вашего расширения снята галочка Безопасный режим. В безопасном режиме работа с запросами к некоторым объектам метаданных и запись новых объектов могут быть ограничены программно.
2. Метод «Сообщить». Если отладчик не останавливается на точках останова в расширении (что часто бывает в клиент-серверных вариантах или при отсутствии ключа -debug на сервере), воспользуйтесь старым проверенным способом. Добавьте в начало процедуры строку Сообщить("Код расширения запущен!");. Если при нажатии кнопки «Провести и закрыть» сообщение не появляется — значит, событие расширения вообще не вызывается.
3. Проверка параметров отладки. В файловых базах отладка обычно работает сразу. В серверных базах убедитесь, что:
-debug.Вместо прямого запроса к табличным частям документа СчетФактура, профессиональным подходом считается использование Критериев отбора. В типовых конфигурациях существует критерий СвязанныеДокументы. Проверка через него работает быстрее, так как индексы платформы оптимизированы под эти задачи.
Проанализируем, как это упрощает код. Вместо написания текста SQL-запроса вы можете вызвать метод критерия отбора, передав туда ссылку на вашу Расходную накладную. Если в возвращаемом массиве (или таблице) есть документы типа СчетФактура, значит, создание нового документа не требуется.
Мы рассмотрели процесс автоматизации создания Счета-фактуры в УНФ 1.6 через механизмы расширения. Основное внимание стоит уделять корректности запросов (особенно работе с булевыми полями и проверке на NULL) и настройкам безопасности самого расширения. Помните, что использование блока Попытка...Исключение при записи документа является обязательным стандартом разработки, так как проведение подчиненного документа может сорваться из-за нехватки прав доступа или незаполненных обязательных реквизитов.