Как передать число с двумя знаками после запятой в XDTO (на примере ЕГИССО) и избежать ошибок валидации?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции систем 1С со сторонними сервисами и государственными информационными системами (такими как ЕГИССО, ГИС ЖКХ, Честный Знак и др.) разработчики часто сталкиваются со строгими ограничениями входящих форматов данных. Одна из классических проблем — передача числовых значений, например, сумм с копейками, в пакеты XDTO. В этой статье мы подробно разберем, почему возникает популярная ошибка несоответствия типов XDTO, в чем разница между внутренним представлением числа в 1С и его текстовым XML-эквивалентом, а также как правильно составить форматную строку для выгрузки данных.

Постановка проблемы и типичные заблуждения

Рассмотрим стандартную ситуацию. У нас есть числовое значение — например, 555. Нам необходимо выгрузить его в XML-файл через механизм XDTO-пакетов так, чтобы оно приняло вид 555.00. На первый взгляд, задача кажется тривиальной, однако попытки решить ее "в лоб" приводят к ошибкам.

Многие начинающие разработчики пытаются сделать следующее:

  1. Использовать функцию Формат(555, "ЧДЦ=2"). Функция отрабатывает отлично, но возвращает тип Строка ("555,00"). Пытаясь вернуть типу статус числа, разработчик пишет Число(Формат(555, "ЧДЦ=2")), и платформа 1С мгновенно отбрасывает "лишние" хвостовые нули, возвращая исходное число 555.
  2. Напрямую присвоить числовое значение свойству XDTO-пакета в надежде, что сериализатор сам разберется с форматом. В этот момент система выбрасывает критическую ошибку валидации схемы.

Давайте проанализируем реальный пример ошибки, возникающей при выгрузке данных в ЕГИССО:


Ошибка при установке значения атрибута контекста (amount)
tFactAssignment_XDTO.assignment_info.monetary_form.amount = Сумма;
по причине:
Несоответствие типов XDTO
по причине:
Ошибка проверки данных XDTO:
Значение: '1 398,94' не соответствует простому типу: {urn://egisso-ru/types/basic/1.0.4}tMoney
Значение не соответствует образцу

Почему возникает ошибка: разбираем регулярное выражение в XDTO

Выясним причину этой ошибки. В схеме XDTO (в данном случае ЕГИССО) тип данных tMoney часто объявляется не как классическое число (decimal), а как простая строка (string), на которую наложено ограничение в виде регулярного выражения (паттерна):

[0-9]+[.,]\d{2}

Давайте расшифруем, какие требования предъявляет этот шаблон к передаваемому значению:

Когда мы передаем число через стандартную функцию Формат(Сумма, "ЧДЦ=2"), платформа 1С ориентируется на региональные настройки операционной системы. В русскоязычной локали операционная система по умолчанию разделяет группы разрядов (тысячи от сотен) неразрывным пробелом (символ с кодом 160). В результате число 1398.94 превращается в строку "1 398,94". Наличие этого скрытого спецсимвола пробела нарушает условие регулярного выражения [0-9]+, что и приводит к падению выгрузки с ошибкой "Несоответствие типов XDTO".

Решение проблемы с помощью правильного форматирования

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

В платформе 1С для этого используется параметр форматной строки ЧГ=0 (ЧГ — число групп, значение 0 полностью отключает группировку разрядов). Посмотрим на пример правильного формирования строки:


// Правильное форматирование для передачи в XDTO
ИтоговаяСтрока = Формат(ТекСтр.Сумма, "ЧДЦ=2; ЧГ=0");
tFactAssignment_XDTO.assignment_info.monetary_form.amount = ИтоговаяСтрока;

При использовании такой конструкции число 1398.94 преобразуется в строку "1398,94" (без пробелов), а число 555 — в строку "555,00". Обе строки идеально подходят под регулярное выражение XDTO-пакета.

Скрытая опасность: почему нельзя использовать параметр "ЧН=Ноль"

Обратим внимание на частую ошибку, которую допускают разработчики при настройке формата. Иногда в форматную строку добавляют параметр представления нулевого значения: ЧН=Ноль. Например:


// Опасный вариант с ошибкой для нулевых значений!
Формат(ТекСтр.Сумма, "ЧДЦ=2; ЧН=Ноль; ЧГ=0");

Если в выгрузку попадет строка с нулевой суммой (0.00 руб.), функция Формат() вернет текстовое слово "Ноль". Текст "Ноль" не содержит цифр и разделителей, поэтому валидатор XDTO тут же заблокирует отправку пакета из-за несоответствия паттерну [0-9]+[.,]\d{2}.

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


// Вариант 1: Использование ЧН=0.00 в строке формата
ПодготовленнаяСумма = Формат(ТекСтр.Сумма, "ЧДЦ=2; ЧГ=0; ЧН=0.00");

// Вариант 2: Проверка условия через тернарный оператор
ПодготовленнаяСумма = ?(ТекСтр.Сумма = 0, "0.00", Формат(ТекСтр.Сумма, "ЧДЦ=2; ЧГ=0"));

Универсальное решение: явное указание разделителя дробной части

Хотя паттерн ЕГИССО лояльно относится к запятой, большинство современных веб-сервисов и баз данных принимают в качестве разделителя дробной части исключительно точку (согласно стандарту XML Schema W3C). Чтобы ваш код не зависел от локализации сервера (например, если сервер 1С запущен под англоязычной ОС, где разделителем по умолчанию является точка, а на вашем локальном компьютере — запятая), рекомендуется всегда принудительно указывать символ разделителя с помощью параметра ЧРД=. (Число Разделитель Дробной части):


// Идеальный вариант для любых XML и XDTO интеграций
ФорматированнаяСумма = Формат(ТекСтр.Сумма, "ЧДЦ=2; ЧГ=0; ЧРД=.");
tFactAssignment_XDTO.assignment_info.monetary_form.amount = ФорматированнаяСумма;

Почему не подходит стандартная функция "XMLСтрока"?

У опытных разработчиков может возникнуть логичный вопрос: почему бы не использовать встроенную функцию платформы XMLСтрока(Число)? Ведь она спроектирована специально для сериализации данных в XML-формат, сама убирает группировки и подставляет точку в качестве разделителя.

Разберем поведение этой функции на примерах:


Результат1 = XMLСтрока(555.25); // Вернет "555.25" - отлично!
Результат2 = XMLСтрока(555);    // Вернет "555"    - ошибка для нашего паттерна!
Результат3 = XMLСтрока(555.2);  // Вернет "555.2"  - ошибка для нашего паттерна!

Поскольку функция XMLСтрока() оптимизирует размер XML-файла и отбрасывает незначащие нули в дробной части, возвращаемые строки "555" и "555.2" не содержат ровно двух знаков после точки. В результате валидация XDTO по маске \d{2} завершится ошибкой. Именно поэтому явное использование функции Формат() с отключением группировки разрядов является единственным надежным программным обходным путем.

← На главную