Разработчики систем на платформе 1С часто сталкиваются с ситуацией, когда доработанная печатная форма отлично выводит новые данные при печати непосредственно из интерфейса программы, но при автоматической отправке через API или обмене с CRM-системой клиенту уходит старый вариант документа. Кажется, что платформа игнорирует внесенные изменения, берет макет «из воздуха» или обращается к какому-то скрытому кэшу.
В этой статье мы подробно разберем, почему возникает такое поведение, проанализируем архитектуру вызова внешних обработок печати, выясним, почему советы «почистить кэш» в данном случае абсолютно бесполезны, и рассмотрим правильный алгоритм поиска и устранения подобных ошибок.
Для начала детально рассмотрим программный код, который отвечает за формирование печатной формы в формате PDF для последующей передачи в CRM-систему. Проанализируем ключевую функцию обмена:
Функция СформироватьИСохранитьПечатнуюФорму(ДокументСсылка, СтруктураДанных, НастройкиОбмена)
ПечатнаяФорма = Неопределено;
ПутьКФайлу = "";
Если ТипЗнч(ДокументСсылка) = Тип("ДокументСсылка.СчетНаОплатуПокупателю") Тогда
НайденаяОбработка = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("Счет на бланке");
Если Не НайденаяОбработка.Пустая() Тогда
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(ДокументСсылка);
ОбъектыПечати = Новый СписокЗначений;
ИмяФайла = ПолучитьИмяВременногоФайла();
ДвоичныеДанные = НайденаяОбработка.ХранилищеОбработки.Получить();
ДвоичныеДанные.Записать(ИмяФайла);
ОбработкаОбъект = ВнешниеОбработки.Создать(ИмяФайла, Истина);
ПечатнаяФорма = ОбработкаОбъект.PechatDokumenta(МассивОбъектов, ОбъектыПечати, (Число(СтруктураДанных.sign) = 1));
ОбработкаОбъект = Неопределено;
УдалитьФайлы(ИмяФайла);
КонецЕсли;
// ... (код для обработки других типов документов)
Если ПечатнаяФорма <> Неопределено Тогда
Если Число(СтруктураДанных.format) = 0 Тогда
ПутьКФайлу = СтруктураДанных.ПутьКаталога + "\" + СтруктураДанных.Представление + ".xlsx";
ПечатнаяФорма.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
ИначеЕсли Число(СтруктураДанных.format) = 1 Тогда
ПутьКФайлу = СтруктураДанных.ПутьКаталога + "\" + СтруктураДанных.Представление + ".pdf";
ПечатнаяФорма.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
КонецЕсли;
Иначе
ПутьКФайлу = "";
КонецЕсли;
Возврат ПутьКФайлу;
КонецФункции
Разберем этот алгоритм по шагам, чтобы понять логику его работы:
ДокументСсылка.СчетНаОплатуПокупателю, управление передается ветке обработки счета.ДополнительныеОтчетыИОбработки по наименованию «Счет на бланке».ХранилищеОбработки, который имеет тип ХранилищеЗначения.ПолучитьИмяВременногоФайла() генерирует уникальный путь во временной папке операционной системы (например, C:\Users\Username\AppData\Local\Temp\v8_A1B2_34.tmp).ВнешниеОбработки.Создать(ИмяФайла, Истина) инициализирует объект внешней обработки в безопасном режиме.PechatDokumenta() модуля внешней обработки, которая возвращает сформированный объект ТабличныйДокумент.УдалитьФайлы().Когда разработчик сталкивается с ситуацией, при которой изменения в печатной форме не «применяются» при программном вызове, первая реакция большинства коллег на форумах — посоветовать очистить локальный кэш конфигурации 1С. Однако, если мы внимательно проанализируем приведенный выше код, станет очевидно, что кэш здесь абсолютно ни при чем.
Кэширование платформы 1С работает для метаданных конфигурации, а также для некоторых повторно используемых модулей. В данном коде внешняя обработка извлекается непосредственно из базы данных (из таблицы справочника ДополнительныеОтчетыИОбработки) в виде потока байт при каждом (!) запуске обмена. Платформа каждый раз записывает этот поток в файл с новым уникальным именем во временном каталоге ОС, открывает его как абсолютно новую внешнюю обработку и сразу после генерации макета физически удаляет файл с диска.
В такой схеме старой версии обработки физически неоткуда взяться в локальном кэше платформы. Проблема кроется глубже — во внутренней логике самого макета и в параметрах, которые передаются при вызове функции печати.
Обратим внимание на строку вызова функции печати из модуля обмена:
ПечатнаяФорма = ОбработкаОбъект.PechatDokumenta(МассивОбъектов, ОбъектыПечати, (Число(СтруктураДанных.sign) = 1));
Третьим параметром в функцию PechatDokumenta() передается логическое выражение (Число(СтруктураДанных.sign) = 1). Этот параметр определяет, нужно ли выводить в печатную форму факсимильные подписи и печать организации:
ПодвалСчета. Именно эту область отредактировал разработчик, поэтому при локальной печати все изменения отображаются корректно.sign = 1, что вычисляет третий параметр вызова как Истина. Внутри модуля внешней обработки срабатывает ветвление алгоритма: вместо стандартного подвала программа выводит совершенно другую область макета — например, ПодвалСчетаСПодписьюИПечатью.Внешние печатные формы часто проектируются таким образом, что области макета для вывода с факсимиле и без него расположены в разных частях одной таблицы MXL. Разработчик, открыв макет в конфигураторе, визуально видит только первую область (подвал без подписи), вносит туда правки и сохраняет обработку. Область для факсимильной печати может находиться ниже, отделенная пустыми строками, или вообще располагаться на отдельном листе макета.
Поскольку в области ПодвалСчетаСПодписьюИПечатью текст не менялся, CRM-система продолжала получать PDF-файлы, сформированные по старому шаблону. В этом и заключалась «мистика» поведения платформы.
Представленный фрагмент программного кода обмена содержит несколько критических уязвимостей и нарушений стандартов разработки 1С, которые усложняют поддержку и приводят к подобным скрытым ошибкам.
1. Использование метода НайтиПоНаименованию() без точного соответствия
Поиск элемента справочника по строковому представлению НайтиПоНаименованию("Счет на бланке") крайне опасен. Во-первых, если в справочнике появится элемент с похожим именем (например, «Счет на бланке (старый)» или «Счет на бланке (копия)»), метод может вернуть ссылку на неактуальный объект. Во-вторых, любое случайное изменение названия элемента пользователем в режиме «1С:Предприятие» (например, добавление лишней точки или пробела) полностью заблокирует работу обмена с CRM, так как обработка не будет найдена.
2. Игнорирование механизмов БСП (Библиотеки стандартных подсистем)
В современных конфигурациях 1С ручное извлечение обработок из хранилища и запись их во временные файлы на диске считается устаревшим подходом. Для работы с дополнительными отчетами и обработками в БСП предусмотрен специальный программный интерфейс (API), который автоматизирует безопасное извлечение, инициализацию и выполнение кода во внешних объектах. Ручной обход этих механизмов лишает систему контроля прав доступа и централизованного логирования ошибок.
3. Жесткое кодирование (Hardcode) типов документов
Конструкция Если ТипЗнч(ДокументСсылка) = Тип("ДокументСсылка.СчетНаОплатуПокупателю") делает модуль интеграции статичным. При добавлении новых типов документов для отправки в CRM разработчику придется каждый раз вручную дописывать новые ветки ИначеЕсли в общий модуль обмена.
Чтобы быстро локализовать подобные проблемы в будущем и не тратить время на догадки, рекомендуем использовать следующий универсальный алгоритм отладки внешних обработок печати, работающих в составе интеграционных механизмов:
УдалитьФайлы(ИмяФайла); и закомментируйте её на время проведения расследования.PechatDokumenta().ИмяФайла (это будет реальный путь к временному файлу .tmp или .epf на вашем компьютере).ПолучитьОбласть() в зависимости от переданных из CRM параметров и флага подписи.Этот простой метод гарантирует 100% результат при поиске несоответствий в макетах и избавляет от необходимости тратить часы на безрезультатную очистку кэша или гадание на форумах.