Почему внешняя обработка не создает файл Excel после обновления 1С:Бухгалтерии и как это исправить?

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

После обновления конфигурации 1С:Бухгалтерия с версии 3.0.187.20 до 3.0.190.25 на платформе 8.3.27.1859 (клиент-сервер, SQL) внешние обработки могут перестать корректно работать, в частности, функция создания файлов Excel. В этой статье мы подробно разберем типичную проблему, когда файл не создается в заданном каталоге, и программа выдает сообщение "Не удалось записать файл № ...", а также предложим шаги по диагностике и устранению этой ошибки.

Анализируем исходный код обработки

Для начала, давайте внимательно рассмотрим предоставленный код, который отвечает за формирование и сохранение файлов Excel. Обычно этот процесс состоит из двух частей: серверного вызова для формирования табличного документа и клиентского вызова для его сохранения.

Серверный код формирования табличного документа

Обратимся к серверной части, где происходит формирование табличного документа и помещение его во временное хранилище:


&НаСервере
Процедура СФ_СформироватьНаСервере
    Для Каждого ТекСтрока Из Объект.СчетаФактуры Цикл
        Если ТекСтрока.Создавать Тогда
            Таб = Печать(ТекСтрока.Документ, ЛОЖЬ);
            Адрес = ПоместитьВоВременноеХранилище(Таб, Новый УникальныйИдентификатор);
            ТекСтрока.ПутьКФайлу = Адрес;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

В этом блоке кода:

  1. Мы перебираем строки счетов-фактур.
  2. Проверяем флаг ТекСтрока.Создавать.
  3. Вызываем функцию Печать() для получения табличного документа (переменная Таб).
  4. Помещаем полученный табличный документ Таб во временное хранилище, получая его адрес (переменная Адрес).
  5. Сохраняем этот адрес в поле ТекСтрока.ПутьКФайлу.

Клиентский код сохранения файла Excel

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


&НаКлиенте
Процедура ЗаписатьФайлыНаКлиенте
    Для каждого ТекСтрока Из объект.СчетаФактуры Цикл
        Если ЗначениеЗаполнено(ТекСтрока.ПутьКФайлу) Тогда
            Файл = ПолучитьИзВременногоХранилища(ТекСтрока.ПутьКФайлу);
            Если НЕ Файл = НЕОПРЕДЕЛЕНО Тогда
                ИмяФайла = СокрЛП(ЭтаФорма.Каталог) + "\Счет-Фактура" + СокрЛП(ТекСтрока.НомерДокумента) + ".xls";
                Файл.Записать(ИмяФайла,"XLS");
                ТекСтрока.ПутьКФайлу = ИмяФайла;
            Иначе
                Сообщить("Не удалось записать файл № " + СокрЛП(ТекСтрока.НомерДокумента));
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

В этом клиентском блоке:

  1. Мы снова перебираем строки счетов-фактур.
  2. Проверяем, заполнено ли поле ТекСтрока.ПутьКФайлу.
  3. Пытаемся получить объект из временного хранилища с помощью ПолучитьИзВременногоХранилища().
  4. Если объект успешно получен (то есть Файл не НЕОПРЕДЕЛЕНО), формируем имя файла и сохраняем его.
  5. Если объект не получен, выводим сообщение об ошибке.

Выявляем основную причину проблемы: Файл = НЕОПРЕДЕЛЕНО

По описанию проблемы, сообщение "Не удалось записать файл № ..." указывает на то, что мы попадаем в блок Иначе в клиентской процедуре. Это однозначно говорит нам о том, что переменная Файл после вызова ПолучитьИзВременногоХранилища(ТекСтрока.ПутьКФайлу) получает значение НЕОПРЕДЕЛЕНО. Теперь нам необходимо выяснить, почему это происходит.

Подробный разбор причин, по которым ПолучитьИзВременногоХранилища() может возвращать НЕОПРЕДЕЛЕНО

1. Некорректное или отсутствующее заполнение ТекСтрока.ПутьКФайлу

Прежде всего, нам необходимо убедиться, что поле ТекСтрока.ПутьКФайлу действительно содержит корректный адрес временного хранилища к моменту вызова клиентской процедуры. Рассмотрим потенциальные проблемы:

  1. Условие ТекСтрока.Создавать: Проверьте в отладчике на сервере, выполняется ли условие Если ТекСтрока.Создавать Тогда. Если этот флаг по какой-либо причине не установлен, то блок кода, помещающий табличный документ в хранилище, не будет выполнен, и ТекСтрока.ПутьКФайлу останется незаполненным.
  2. Результат функции Печать(): Убедитесь, что функция Печать(ТекСтрока.Документ, ЛОЖЬ) успешно возвращает табличный документ и переменная Таб заполнена. Возможно, в новой версии конфигурации произошли изменения во внутренней функции Печать или ее параметрах, что приводит к возврату пустого или некорректного значения.
  3. Присвоение адреса: Проверьте, что ТекСтрока.ПутьКФайлу = Адрес; действительно присваивает полученный адрес.

2. Жизненный цикл временного хранилища

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

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

Проверяем синтаксис сохранения файла

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

Файл.Записать(ИмяФайла,"XLS");

Хотя в старых версиях платформы это могло работать, рекомендуется использовать перечисление ТипФайлаТабличногоДокумента для явного указания формата сохранения. Правильный синтаксис должен быть таким:

Файл.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLS);

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

Проверяем имя файла и путь к каталогу

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


ИмяФайла = СокрЛП(ЭтаФорма.Каталог) + "\Счет-Фактура" + СокрЛП(ТекСтрока.НомерДокумента) + ".xls";
  1. Запрещенные символы в имени файла: Убедитесь, что ТекСтрока.НомерДокумента не содержит символов, запрещенных для использования в именах файлов операционной системой (например, \ / : * ? " < > |).
  2. Корректность каталога: Проверьте, что переменная ЭтаФорма.Каталог содержит существующий и доступный путь.
  3. Права доступа: Самое главное, убедитесь, что у пользователя, от имени которого запускается 1С-клиент, есть полные права на запись в указанный каталог. Если файл создается на сервере, то аналогичные права должны быть у учетной записи, под которой работает сервер 1С:Предприятия.

Шаги по пошаговой отладке для выявления причины

Самый эффективный способ найти причину проблемы — это использовать отладчик 1С. Мы предлагаем следующий план действий:

  1. Начнем с серверного кода (СФ_СформироватьНаСервере):
    1. Установите точку останова на строке Если ТекСтрока.Создавать Тогда.
    2. Проверьте значение ТекСтрока.Создавать. Должно быть Истина.
    3. Перейдите к строке Таб = Печать(ТекСтрока.Документ, ЛОЖЬ);. После выполнения этой строки проверьте, заполнена ли переменная Таб. В рабочем варианте вы утверждаете, что она заполнена, это важно подтвердить и для нерабочего. Если Таб НЕОПРЕДЕЛЕНО или пустой табличный документ, то это и есть корень проблемы.
    4. Перейдите к строке Адрес = ПоместитьВоВременноеХранилище(Таб, Новый УникальныйИдентификатор);. После выполнения проверьте, что переменная Адрес получила корректный путь к временному хранилищу (например, "e1cib/tempstorage/c33f2c5d-c6a6-44b2-a42e-ec5f8c32d9f3").
    5. Перейдите к строке ТекСтрока.ПутьКФайлу = Адрес;. Убедитесь, что адрес успешно присвоен объекту.
  2. Переходим к клиентскому коду (ЗаписатьФайлыНаКлиенте):
    1. Установите точку останова на строке Файл = ПолучитьИзВременногоХранилища(ТекСтрока.ПутьКФайлу);.
    2. Очень важно: Перед выполнением этой строки проверьте значение ТекСтрока.ПутьКФайлу. Оно должно быть тем же самым адресом, который мы получили на сервере. Если значение другое, или оно пустое, то причина уже здесь.
    3. Выполните строку Файл = ПолучитьИзВременногоХранилища(ТекСтрока.ПутьКФайлу);.
    4. После выполнения проверьте значение переменной Файл. Если она НЕОПРЕДЕЛЕНО, это подтверждает вашу проблему.
    5. Если Файл все еще НЕОПРЕДЕЛЕНО, это указывает на то, что объект из временного хранилища не был найден или был удален. Вероятные причины:
      • Изменение механизма работы временного хранилища в новой версии платформы или БСП.
      • Какие-то промежуточные серверные вызовы между ПоместитьВоВременноеХранилище и ПолучитьИзВременногоХранилища, которые могли привести к очистке хранилища.
      • Неправильное управление жизненным циклом идентификатора.
    6. Если Файл заполнен, тогда проверьте формирование ИмяФайла и синтаксис Файл.Записать().

Дополнительные рекомендации и способы решения

Если после тщательной отладки вы не смогли найти прямую причину, или она оказалась связана с глубинными изменениями в платформе или БСП, рассмотрите следующие подходы:

  1. Проверка прав доступа: Мы уже упоминали это, но это критически важный момент. Убедитесь, что у пользователя, от имени которого выполняется сохранение файла, есть необходимые права на запись в указанный каталог. Если используется сервер 1С, то у пользователя, под которым запущен серверный процесс.
  2. Использование асинхронных методов: В новых версиях конфигураций 1С:Предприятие для работы с файлами, особенно для операций, которые могут занимать время, рекомендуется использовать асинхронные методы. Это может быть связано с тем, что старые синхронные вызовы теперь обрабатываются иначе или вызывают проблемы с таймаутами.
  3. Использование ТипФайлаТабличногоДокумента: Как уже было указано, всегда явно указывайте тип файла при сохранении:
    
    Файл.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX); // Или ТипФайлаТабличногоДокумента.XLS
    

    Это не только правильный подход, но и может решить проблемы совместимости форматов в новых версиях.

  4. Проверка на изменения в БСП: Новые версии конфигураций часто обновляют Библиотеку стандартных подсистем (БСП). Если ваша функция Печать() использует БСП-функции, возможно, их сигнатуры или логика работы изменились. Попробуйте найти аналогичные функции в новой конфигурации и сравнить их с вашей реализацией.
  5. Обновления платформы: В платформе 1С:Предприятие 8.3.27 были внесены улучшения в работу с хранилищем двоичных данных. Хотя они направлены на оптимизацию, иногда изменения могут влиять на поведение старого кода.
  6. Альтернативные способы сохранения: Если возникают непреодолимые трудности с прямым сохранением табличного документа, можно рассмотреть вариант с записью двоичных данных файла в потоки данных (например, ПотокВПамяти) и последующим чтением из них, или даже через промежуточный файл на сервере, а затем передачу его на клиент.

Мы настоятельно рекомендуем начать с пошаговой отладки. Только так вы сможете точно определить, на каком именно этапе происходит сбой и почему переменная Файл становится НЕОПРЕДЕЛЕНО. После выявления корневой причины, применение вышеуказанных рекомендаций поможет эффективно устранить проблему.

← На главную