При разработке механизмов взаимодействия 1С:Предприятия 7.7 с современными онлайн-кассами (ККТ) через Web-интерфейс или драйверы (например, АТОЛ 10) основной сложностью становится отсутствие встроенных средств работы с форматом JSON. В отличие от версии 8.3, где существуют объекты ЗаписьJSON и ЧтениеJSON, в «семерке» программистам приходится либо собирать строки вручную, либо использовать внешние компоненты и COM-объекты.
В данной статье мы разберем несколько подходов к генерации корректных JSON-запросов, проанализируем их плюсы и минусы, а также выясним, почему «ручная» склейка строк может стать источником серьезных ошибок при печати чеков.
Рассмотрим стандартный подход, который часто выбирают разработчики на начальном этапе. Он заключается в последовательной проверке заполненности полей и склеивании их в одну длинную строку. Разберем пример функции для формирования объекта operator (кассир):
Функция ОбъектОператор(name, vatin="")
name = СокрЛП(name);
vatin = СокрЛП(vatin);
Если ПустаяСтрока(name)=1 Тогда
Сообщить("ОбъектОператор: Параметр name не заполнен!");
Возврат "null";
КонецЕсли;
MainSection = """operator"":{""name"":""" + name + """";
Если ПустоеЗначение(vatin)=0 Тогда
MainSection = MainSection + ",""vatin"":""" + vatin + """";
КонецЕсли;
MainSection = MainSection + "}";
Возврат MainSection;
КонецФункции
Проанализируем этот код. Основная проблема здесь заключается в управлении разделителями (запятыми) и экранировании спецсимволов. Если параметров становится больше (например, 10-15 тегов для позиции товара), количество условий Если растет в геометрической прогрессии, а риск забыть или поставить лишнюю запятую превращает отладку в кошмар. Более того, если в имени оператора встретится кавычка (например, ООО "Ромашка"), сформированный JSON будет невалидным, и касса вернет ошибку.
Одним из элегантных решений для 1С 7.7 является использование объекта СписокЗначений для хранения пар «Ключ-Значение». Мы можем создать универсальную функцию, которая будет обходить этот список и формировать JSON автоматически. Рассмотрим пример функции, которая преобразует СписокЗначений в JSON-объект:
Функция СформироватьJSONИзСписка(лСЗ)
Перем ТекстJSON, Сч, Ключ, Значение, ТипЗнач;
ТекстJSON = "{";
Для Сч = 1 По лСЗ.РазмерСписка() Цикл
Значение = лСЗ.ПолучитьЗначение(Сч, Ключ);
// Пропускаем пустые значения, если это критично для ККТ
Если ПустоеЗначение(Значение) = 1 Тогда
Продолжить;
КонецЕсли;
// Добавляем запятую перед всеми элементами, кроме первого
Если СтрДлина(ТекстJSON) > 1 Тогда
ТекстJSON = ТекстJSON + ",";
КонецЕсли;
ТекстJSON = ТекстJSON + """" + Ключ + """:";
// Определяем тип и добавляем кавычки только для строк
Если ТипЗначенияСтр(Значение) = "Число" Тогда
ТекстJSON = ТекстJSON + Строка(Значение);
Иначе
// Здесь должна быть функция ЭкранироватьСпецСимволы(Значение)
ТекстJSON = ТекстJSON + """" + Значение + """";
КонецЕсли;
КонецЦикла;
ТекстJSON = ТекстJSON + "}";
Возврат ТекстJSON;
КонецФункции
Такой подход позволяет писать код в стиле «конструктора», что гораздо нагляднее и проще для восприятия:
лСЗ = СоздатьОбъект("СписокЗначений");
лСЗ.ДобавитьЗначение("Иванов И.И.", "name");
лСЗ.ДобавитьЗначение("123456789012", "vatin");
Запрос = СформироватьJSONИзСписка(лСЗ);
Для создания более сложных, вложенных структур идеально подходит COM-объект Scripting.Dictionary. Он работает быстрее, чем СписокЗначений, и позволяет создавать настоящие деревья объектов, которые легко сериализовать в JSON. Выясним преимущества этого метода:
СписокЗначений (массив).Это особенно важно для драйверов АТОЛ 10-й версии. Согласно формату фискальных данных (ФФД), многие теги являются необязательными. Если вы передадите в JSON пустое поле "vatin": "", драйвер может выдать ошибку «Некорректный реквизит», тогда как полное отсутствие этого поля в структуре будет воспринято корректно.
Если вам нужно гарантировать 100% валидность JSON без написания собственных парсеров, можно делегировать эту задачу среде JavaScript через COM-объект MSScriptControl.ScriptControl. Проанализируем, как это работает:
// Создаем объект скрипта
sc = СоздатьОбъект("MSScriptControl.ScriptControl");
sc.Language = "JScript";
// Добавляем вспомогательную функцию
sc.AddCode("function toJSON(obj) { return JSON.stringify(obj); }");
// В JScript можно динамически создавать объекты
// В 1С 7.7 мы можем передать данные через Dictionary
// и вызвать метод stringify
Этот метод позволяет избежать проблем с экранированием символов \, ", /, а также корректно обрабатывать переносы строк в названиях товаров, что часто встречается в розничной торговле.
Не менее важной задачей является разбор ответа от веб-сервиса кассы. Рассмотрим пример рекурсивной процедуры, предложенной участниками сообщества, которая разбирает JSON-строку и заполняет СписокЗначений:
Процедура ЗаполнитьДанныеИзОтветаJSON(Результат, ТекстJSON, ТипДанных)
ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));
НомерЗначения = 0;
Пока ТекстJSON <> "" Цикл
ПервыйСимвол = Лев(ТекстJSON, 1);
Если ПервыйСимвол = "{" Тогда
Значение = СоздатьОбъект("СписокЗначений");
ЗаполнитьДанныеИзОтветаJSON(Значение, ТекстJSON, "Структура");
// Логика добавления в Результат...
ИначеЕсли ПервыйСимвол = "]" Тогда
// Обработка закрытия массива...
Возврат;
// ... (далее идет логика поиска двоеточия и извлечения ключей)
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: При парсинге ответов в 1С 7.7 штатными средствами необходимо предварительно очищать строку от экранированных кавычек \" и других спецсимволов с помощью функции СтрЗаменить(), чтобы алгоритм поиска разделителей работал корректно.
Подведем итоги и сформируем рекомендации для разработки обмена с онлайн-кассами:
ЭкранироватьJSON(Стр), которая заменяет кавычки на \". Без этого ваша обработка «упадет» на первом же товаре с кавычками в названии.1С++ и его класс JSON или Scripting.Dictionary. Это стандарт де-факто для профессиональной разработки на 7.7.Рациональный подход к структуре JSON не только ускорит разработку, но и обеспечит стабильную работу кассового узла, исключая простои из-за ошибок формирования чека.