Как реализовать автоинкремент порядкового номера в имени TXT-файла выгрузки для банка в 1С?

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

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

Если отправить файл с именем, которое уже загружалось ранее, банковская система автоматически отклонит его как дубликат. Даже если по регламенту выгрузка происходит один раз в сутки, всегда существует вероятность повторной отправки реестра из-за ошибок в данных или технических сбоев. В этой статье мы подробно рассмотрим, как реализовать надежный автоинкремент номера в имени TXT-файла средствами платформы 1С:Предприятие 8.

Почему статический номер — это плохая идея?

Самый простой и очевидный совет, который часто можно встретить на форумах, — жестко прописать в коде номер "001", если выгрузка осуществляется строго один раз в день. Однако на практике этот подход крайне ненадежен по следующим причинам:

  1. Человеческий фактор: Бухгалтер может выгрузить реестр, обнаружить ошибку в сумме или реквизитах сотрудника, исправить ее в базе и попытаться выгрузить файл заново. Банк отклонит новый файл, так как его имя полностью совпадет с предыдущим.
  2. Технические сбои: При проблемах с интернет-соединением во время отправки статус реестра в банке может остаться неопределенным, и потребуется повторная отправка обновленного файла.
  3. Масштабирование процессов: Со временем бизнес-процессы компании могут измениться, и выгрузка реестров начнет выполняться несколько раз в день (например, по разным подразделениям или типам выплат).

Поэтому правильным решением является динамическое определение и увеличение номера файла на +1 при каждой выгрузке.

Вариант 1. Сканирование каталога выгрузки с помощью функции НайтиФайлы()

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

Рассмотрим подробнее алгоритм реализации этого метода:

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

Посмотрим на пример программной реализации этого метода:


// Определяем каталог и маску поиска
КаталогВыгрузки = "C:\SberbankExport\";
ТекущаяДатаСтр = Формат(ТекущаяДата(), "ДФ=ddMMyyyy"); // Например, 25102023
МаскаПоиска = "*_" + ТекущаяДатаСтр + "_*.txt";

НайденныеФайлы = НайтиФайлы(КаталогВыгрузки, МаскаПоиска);

МаксимальныйНомер = 0;

Для Каждого Файл Из НайденныеФайлы Цикл
    ИмяБезРасширения = Файл.ИмяБезРасширения;
    
    // Разбиваем имя файла по разделителю "_"
    ЧастиИмени = СтрРазделить(ИмяБезРасширения, "_");
    
    // Предположим, структура имени: ИНН_РС_НОМЕР_ДАТА
    // Номер находится на 3-й позиции (индекс 2 в массиве)
    Если ЧастиИмени.Количество() >= 3 Тогда
        СтрокаНомера = ЧастиИмени[2];
        Попытка
            ЧислоНомера = Число(СтрокаНомера);
            Если ЧислоНомера > МаксимальныйНомер Тогда
                МаксимальныйНомер = ЧислоНомера;
            КонецЕсли;
        Исключение
            // Игнорируем файлы, где на месте номера не число
        КонецПопытки;
    КонецЕсли;
КонецЦикла;

// Вычисляем новый номер реестра
НовыйНомер = МаксимальныйНомер + 1;

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

Вариант 2. Хранение нумерации в Регистре сведений (Наиболее надежный метод)

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

Создадим регистр сведений со следующей структурой:

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


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

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


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

Вариант 3. Использование стандартного нумератора документов 1С

Если ваша внешняя обработка запускается на основании какого-либо документа системы (например, типового документа ВедомостьНаВыплатуЗарплатыВБанк или вашего специализированного кастомного документа), то изобретать велосипед не нужно. В платформу 1С уже заложен мощный механизм автонумерации документов, гарантирующий уникальность в пределах периода (года или месяца).

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

Технические тонкости: форматирование лидирующих нулей

Поскольку банк ожидает строго фиксированную длину номера (обычно это 3 символа, то есть 001, 015, 120), простое преобразование числа в строку функцией Строка(НовыйНомер) вернет нам значения "1" или "15", что вызовет ошибку формата при импорте в банк.

Для правильного приведения чисел к строковому формату с лидирующими нулями в 1С используется функция Формат() со спецификатором ЧВН (Численное Выводить Нули) и указанием длины ЧЦ (Число Цифр):


// Форматируем числовой номер в трехзначную строку с лидирующими нулями
НомерДляБанка = Формат(НовыйНомер, "ЧЦ=3; ЧРД=; ЧГ=0; ЧВН=");
// Результат для числа 5 -> "005"
// Результат для числа 42 -> "042"

Разберем параметры этого формата:

Проблема превышения лимита 999

В случае, если нумерация сквозная и не сбрасывается ежедневно, количество выгружаемых реестров рано или поздно превысит отметку 999. При попытке преобразовать число 1000 через формат "ЧЦ=3" произойдет сбой формата, либо банк отклонит некорректно сформированное имя файла.

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

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

← На главную