Как правильно сформировать XML по формату ФНС для ЭДО в 1С: разбор структуры адреса, получение кодов регионов и шаблонизация выгрузки

Программист 1С v7.7 Налоговый учет Торговля и дистрибуция
← На главную

Разработка интеграции с системами электронного документооборота (ЭДО) для выгрузки первичных документов и счетов-фактур в формате XML — задача, с которой сталкивается каждый разработчик 1С. В процессе реализации часто возникают технические трудности, связанные со строгим форматно-логическим контролем (ФЛК) со стороны ФНС и жесткими требованиями крупных торговых сетей (ритейлеров). В рамках данной статьи мы подробно разберем, как правильно спроектировать выгрузку сведений об адресах, как автоматически определять коды регионов для индивидуальных предпринимателей и как собрать XML-документ наиболее простым и производительным способом без использования тяжелых механизмов DOM или XDTO.

Несмотря на то, что исторически обсуждение опиралось на формат 820@ версии 5.01, описанные архитектурные подходы и алгоритмы разбора данных остаются фундаментальными и полностью применимыми для актуальных форматов электронного документооборота (включая современный формат УПД версии 5.03). Мы рассмотрим практические аспекты реализации этих механизмов как на платформе 1С:Предприятие 8, так и на классической платформе 1С:Предприятие 7.7.

Разбор структуры адреса и логика выбора тегов в XSD-схеме

При анализе XSD-схемы формата обмена элемента АдресТип мы сталкиваемся с конструкцией xs:choice, которая объединяет три элемента:

  1. АдрРФ — структурированные сведения об адресе на территории Российской Федерации.
  2. АдрИнф — произвольное текстовое представление адреса (включая адреса за пределами РФ).
  3. КодГАР — уникальный номер адреса объекта адресации в Государственном адресном реестре (актуальный аналог ФИАС).

Спецификация xs:choice накладывает строгое ограничение: в XML-документе должен присутствовать только один из этих трех элементов. Попытка выгрузить одновременно несколько тегов приведет к ошибке ФЛК на этапе отправки файла оператору ЭДО.

Некоторые компании (например, крупные маркетплейсы) часто упрощают выгрузку, заполняя исключительно тег АдрИнф текстовой строкой и указывая код страны (например, КодСтр="643" для РФ). Рассмотрим типичный пример такой упрощенной выгрузки:


<СвПрод>
  <ИдСв>
    <СвЮЛУч ИННЮЛ="7721546864" НаимОрг="Общество с ограниченной ответственностью 'Вайлдберриз'" КПП="997750001"/>
  </ИдСв>
  <Адрес>
    <АдрИнф КодСтр="643" АдрТекст="142715, Московская обл, Ленинский р-н, Мильково д, владение 1"/>
  </Адрес>
</СвПрод>

Несмотря на то, что ФЛК оператора пропускает документы с тегом АдрИнф для российских адресов, использовать этот подход на постоянной основе крайне не рекомендуется. Многие крупные торговые сети (например, X5 Group, Магнит, Лента) требуют исключительно структурированный адрес в формате АдрРФ. Если передать им неструктурированную строку, их внутренние учетные системы не смогут автоматически обработать и сопоставить адрес грузоотправителя или грузополучателя. Это приведет к ручному отклонению документа и задержке оплат.

Поэтому правильным подходом является формирование тега АдрРФ со структурированными дочерними реквизитами:


<Адрес>
    <АдрРФ КодРегион="77" Индекс="103473" Город="Москва г" Улица="Суворовская пл-дь" Дом="1"/>
</Адрес>

Сопоставление полей КЛАДР/ФИАС с тегами XML-формата

При заполнении тега АдрРФ возникает задача корректного переноса адресных сведений из базы 1С. В типовых конфигурациях 1С адрес хранится в виде структурированной информации КЛАДР или ФИАС, однако состав полей в XML-схеме ФНС может отличаться. Проанализируем оптимальную схему мэппинга полей при выгрузке:

  1. Поле «Дом»: В XML-схеме присутствует ограниченный набор атрибутов. Сведения о доме, владении или домовладении следует аккумулировать и выгружать в единый атрибут Дом.
  2. Поле «Корпус»: Сюда необходимо транслировать информацию из таких полей источника, как непосредственно корпус, строение, литера, сооружение или земельный участок. Все эти данные объединяются в атрибут Корпус.
  3. Поле «Квартира»: Данные об офисах, квартирах, боксах, помещениях и комнатах необходимо переносить в атрибут Кварт.

Рассмотрим пример кода на языке 1С для сопоставления структуры адреса перед выводом в XML:


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

При выгрузке адресов для федеральных городов значения имеют свои особенности. Для Москвы (код региона 77), Санкт-Петербурга (код региона 78) и Севастополя (код региона 92) поле Город в XML-файле может не заполняться, если адрес находится непосредственно внутри границ самого города-субъекта. Однако, если адрес относится к городу-спутнику (например, г. Зеленоград в составе Москвы или г. Колпино в составе Санкт-Петербурга), название этого населенного пункта обязательно должно быть выгружено в атрибут Город.

Алгоритм автоматического определения кода региона

Согласно требованиям формата, в элементе АдрРФ атрибут КодРегион является строго обязательным. Для юридических лиц его можно относительно легко получить, отрезав первые два символа от КПП контрагента (за исключением крупнейших налогоплательщиков с КПП, начинающимися на «99», для которых код региона нужно определять по юридическому адресу). Но как быть с индивидуальными предпринимателями (ИП), у которых КПП отсутствует в принципе, а адреса в базе зачастую забиты в виде неструктурированной строки?

Для решения этой проблемы спроектируем и разберем пошаговый алгоритм парсинга неструктурированного адреса в 1С:

  1. Анализ страны: Проверяем текстовое представление адреса на наличие иностранных государств. Если в строке присутствует название другой страны (например, «Казахстан», «Беларусь»), мы определяем код страны по классификатору ОКСМ и принудительно выгружаем адрес через тег АдрИнф.
  2. Получение региона по КПП: Для юридических лиц анализируем КПП. Если первые два символа соответствуют диапазону кодов субъектов РФ (от 01 до 99), используем их в качестве КодРегион.
  3. Парсинг строки адреса: Если код региона не определен, разбиваем строку адреса на составляющие по символу запятой. Очищаем каждый элемент от пробелов и приводим к нижнему регистру.
  4. Поиск соответствия: Сопоставляем полученные части строки со списком регионов РФ. Для этого в коде или в макете конфигурации необходимо хранить таблицу соответствия наименований регионов и их цифровых кодов ФНС (включая общепринятые сокращения, такие как «обл.», «респ.», «край», «АО»).
  5. Резервный вариант: Если автоматический парсинг не дал результатов (например, адрес записан некорректно), система должна выдать предупреждение пользователю в журнал регистрации или окно сообщений и выгрузить адрес в упрощенном формате АдрИнф, чтобы не заблокировать процесс отправки документа.

Рассмотрим пример реализации функции парсинга региона по строке адреса на языке 1С:


// Функция возвращает двузначный код региона РФ по текстовому адресу
Функция ОпределитьКодРегионаПоСтроке(Знач ТекстАдреса, ТаблицаРегионов) Экспорт
    ТекстАдреса = ВРег(ТекстАдреса);
    
    // Проверим простейшие вхождения
    Для Каждого СтрокаРегиона Из ТаблицаРегионов Цикл
        // Ищем точное вхождение названия региона, например "СВЕРДЛОВСКАЯ" или "МОСКВА"
        Если Найти(ТекстАдреса, ВРег(СтрокаРегиона.Наименование)) > 0 Тогда
            Возврат СтрокаРегиона.Код;
        КонецЕсли;
        
        // Проверяем синонимы и сокращения
        Если ЗначениеЗаполнено(СтрокаРегиона.Синоним) И Найти(ТекстАдреса, ВРег(СтрокаРегиона.Синоним)) > 0 Тогда
            Возврат СтрокаРегиона.Код;
        КонецЕсли;
    КонецДляОбохода;
    
    // Если регион не найден, возвращаем пустую строку
    Возврат "";
КонецФункции

Архитектурный подход к генерации XML: метод шаблонизации

Традиционный путь создания XML-файлов в 1С через объектную модель документов DOM или использование механизмов XDTO-пакетов имеет очевидные недостатки. Он требует написания огромного объема кода для инициализации каждого узла, строгой типизации всех элементов и потребляет значительные ресурсы сервера при обработке больших пакетов документов (что критично для высоконагруженных систем выгрузки и старых платформ типа 1С 7.7).

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

Шаблоны хранятся в виде текстовых макетов в конфигурации. Внутри шаблонов прописываются специальные маркеры (плейсхолдеры) со знаком процента, например: %FILEID%, %DOCNUM%, %FIRMADDR%. При формировании документа мы просто заполняем структуру данных в 1С и производим быструю замену маркеров на реальные значения с помощью функции СтрЗаменить().

Рассмотрим структуру типового шаблона для выгрузки УПД:


<?xml version="1.0" encoding="windows-1251"?>
<Файл ИдФайл="%FILEID%" ВерсФорм="5.01" ВерсПрог="1C">
  <СвУчДокОбор ИдОтпр="%SENDERID%" ИдПол="%RECEIVERID%">
    <СвОЭДОтпр НаимОрг="%SENDEROPERNAME%" ИННЮЛ="%SENDEROPERINN%" ИдЭДО="%SENDEROPERID%" />
  </СвУчДокОбор>
  <Документ КНД="1115125" Функция="СЧФДОП" ПоФактХЖ="Документ об отгрузке товаров" ДатаИнфПр="%FORMDATE%" ВремИнфПр="%FORMTIME%" НаимЭконСубСост="%FIRMNAME%">
    <СвСчФакт НомерСчФ="%DOCNUM%" ДатаСчФ="%DOCDATE%" КодОКВ="643">
      %CORRECTIONDATA%
      <СвПрод>
        <ИдСв>
          <СвЮЛУч НаимОрг="%FIRMNAME%" ИННЮЛ="%FIRMINN%" КПП="%FIRMKPP%" />
        </ИдСв>
        <Адрес>
          %FIRMADDR%
        </Адрес>
      </СвПрод>
      <ГрузОт>
        <ОнЖе>он же</ОнЖе>
      </ГрузОт>
      <ГрузПолуч>
        <ИдСв>
          <СвЮЛУч НаимОрг="%CONSNAME%" ИННЮЛ="%CONSINN%" КПП="%CONSKPP%" />
        </ИдСв>
        <Адрес>
          %CONSADDR%
        </Адрес>
      </ГрузПолуч>
      <СвПокуп>
        <ИдСв>
          <СвЮЛУч НаимОрг="%CONTNAME%" ИННЮЛ="%CONTINN%" КПП="%CONTKPP%" />
        </ИдСв>
        <Адрес>
          %CONTADDR%
        </Адрес>
      </СвПокуп>
    </СвСчФакт>
    <ТаблСчФакт>
      %GOODSTABLE%
      <ВсегоОпл СтТовБезНДСВсего="%TOTALWOVAT%" СтТовУчНалВсего="%TOTALWITHVAT%">
        <СумНалВсего>
          <СумНал>%TOTALVAT%</СумНал>
        </СумНалВсего>
        <НеттоВс>%TOTALQTY%</НеттоВс>
      </ВсегоОпл>
    </ТаблСчФакт>
    <Подписант ОблПолн="6" Статус="1" ОснПолн="Должностные обязанности">
      <ЮЛ НаимОрг="%FIRMNAME%" ИННЮЛ="%FIRMINN%" Должн="%SIGNEREMPNAME%">
        <ФИО Имя="%SIGNERNAME%" Фамилия="%SIGNERFAMILY%" Отчество="%SIGNERSURNAME%" />
      </ЮЛ>
    </Подписант>
  </Документ>
</Файл>

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


Процедура СформироватьXMLДокумент(ДокументСсылка, ПутьВыгрузки)
    // Получаем текст основного шаблона из макета
    ТекстДокумента = ПолучитьТекстШаблона("МакетШаблонаУПД");
    
    // Заполняем простые реквизиты шапки
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FILEID%", ПолучитьУникальныйИдентификаторФайла(ДокументСсылка));
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%DOCNUM%", ДокументСсылка.Номер);
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%DOCDATE%", Формат(ДокументСсылка.Дата, "ДФ=гггг-ММ-дд"));
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FORMDATE%", Формат(ТекущаяДата(), "ДФ=гггг-ММ-дд"));
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FORMTIME%", Формат(ТекущаяДата(), "ДФ=ЧХ:ММ:СС"));
    
    // Заполняем реквизиты нашей организации (Продавца)
    Организация = ДокументСсылка.Организация;
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FIRMNAME%", Организация.НаименованиеПолное);
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FIRMINN%", Организация.ИНН);
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FIRMKPP%", Организация.КПП);
    
    // Формируем блок адреса продавца
    ТекстАдресаПродавца = СформироватьXMLБлокАдреса(Организация.ЮридическийАдрес);
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%FIRMADDR%", ТекстАдресаПродавца);
    
    // Формируем табличную часть товаров
    ТекстТаблицы = "";
    Для Каждого СтрокаТЧ Из ДокументСсылка.Товары Цикл
        ШаблонСтроки = ПолучитьТекстШаблона("МакетСтрокиТовара");
        ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%NOMNAME%", СтрокаТЧ.Номенклатура.Наименование);
        ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%QTY%", СтрокаТЧ.Количество);
        ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%PRICE%", СтрокаТЧ.Цена);
        ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%SUM%", СтрокаТЧ.Сумма);
        
        ТекстТаблицы = ТекстТаблицы + ШаблонСтроки + Символы.ПС;
    КонецДляОбохода;
    ТекстДокумента = СтрЗаменить(ТекстДокумента, "%GOODSTABLE%", ТекстТаблицы);
    
    // Сохраняем готовый файл на диск в кодировке Windows-1251
    ЗаписьТекста = Новый ЗаписьТекста(ПутьВыгрузки, КодировкаТекста.ANSI);
    ЗаписьТекста.Записать(ТекстДокумента);
    ЗаписьТекста.Закрыть();
КонецПроцедуры

Этот подход обладает колоссальной гибкостью. Если у вас появляется контрагент (например, торговая сеть) с уникальными требованиями к информационным полям ИнфПолФХЖ1 (передача GLN номеров, кодов артикулов покупателя, номеров заказов), вам не нужно переписывать сложную логику формирования объектов XML. Достаточно создать отдельный шаблон под этого контрагента, прописать в нем специфические маркеры и заменять их в коде при выгрузке.

Взаимосвязь тега «Подписант» и электронной подписи (КЭП)

Частым вопросом при разработке выгрузки XML является передача сведений о лице, подписывающем документ. Важно понимать, что сам по себе XML-файл, генерируемый в 1С, содержит лишь текстовое описание физического лица в блоке Подписант (его ФИО, должность и полномочия). Сама электронная цифровая подпись (криптографический КЭП) накладывается на файл позже — либо средствами специального крипто-компонента непосредственно внутри 1С при отправке, либо в личном кабинете (ЛК) оператора ЭДО (СБИС, Диадок и др.) после ручной загрузки XML. Для реализации наложения подписи на стороне учетной системы подойдёт обработка для подписания файлов с помощью сертификата ЭЦП средствами 1С.

На практике часто возникает ситуация, когда в теге Подписант указан генеральный директор предприятия, а фактическое подписание файла в ЛК ЭДО производит бухгалтер или менеджер по своей личной КЭП. С технической стороны операторы ЭДО пропускают такие документы, однако с юридической точки зрения это несет серьезные риски. По регламенту ФНС, сведения в XML-файле должны строго соответствовать реквизитам сертификата КЭП, которым подписывается документ.

С развитием законодательства компромиссные схемы, когда сотрудники подписывали документы КЭП директора, стали нелегальными. Современные стандарты ЭДО требуют соблюдения двух правил:

  1. Каждое физическое лицо (бухгалтер, менеджер, кладовщик) подписывает XML-документ своей личной подписью физического лица.
  2. К передаваемому пакету документов обязательно прикладывается или указывается в XML-структуре уникальный номер Машиночитаемой доверенности (МЧД), зарегистрированной в едином реестре ФНС. В формате УПД версии 5.03 для этого предусмотрены специализированные XML-блоки, содержащие GUID доверенности и адрес системы хранения.

Таким образом, при проектировании структуры 1С для работы с ЭДО необходимо сразу закладывать справочник «Подписанты» с возможностью привязки КЭП конкретных пользователей и хранения GUID их машиночитаемых доверенностей. Это позволит динамически подставлять правильные ФИО и должности в XML-теги и избежать расхождений с реквизитами накладываемых подписей. Для организации ведения и контроля таких сведений можно использовать конфигурацию для учета ЭЦП и МЧД.

← На главную