Как программно заполнить форму электронного заказа-заявки (ЭЗЗ) и транспортной накладной (ЭТрН) в 1С?

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

При интеграции подсистемы электронных перевозочных документов (ЭПД) с внешними системами или документами-основаниями часто возникает задача: заполнить форму ЭПД на клиенте программно, не сохраняя при этом документ в базу данных сразу. Это необходимо для того, чтобы пользователь мог проверить заполненные реквизиты и в случае необходимости отказаться от проведения без появления лишних «черновиков» в системе. Если задача сводится к типовым БП 3.0 или УНФ 3.0 и не требуется писать собственный алгоритм, расширение ввода ЭПД на основании реализации создает ЭТрН и электронный заказ-заявку и автоматически переносит участников, адреса, транспорт, водителя и сведения о грузе.

Рассмотрим детально, как устроена работа с управляемыми формами подсистемы БЭД/ЭПД, как правильно заполнять простые поля, табличные части и специфические ссылки на сохраненные параметры.

Особенности внутреннего устройства форм подсистемы ЭПД

В типовых конфигурациях 1С (Бухгалтерия предприятия 3.0, ERP, Комплексная автоматизация) визуальные таблицы титула документа (грузы, адреса погрузки/выгрузки, стороны договора) не являются привычными табличными частями самого объекта 1С. Данные титулов хранятся в регистре сведений ЗначенияРеквизитовДокументовЭПД, а на форме управляются служебной структурой.

При вызове метода записи подсистема разбирает ключи специальной структуры, сформированной по правилу: ИмяТаблицы__НомерСтроки__ИмяКолонки (с двумя знаками подчеркивания в качестве разделителя).

Основные механизмы подсистемы, с которыми мы будем работать:

  1. ОбменСГИСЭПДКлиентСервер.УстановитьЗначениеРеквизитаВСтруктуреФормы — универсальная процедура, добавляющая значение в контекст формы ЭПД.
  2. ОбменСГИСЭПДКлиентСервер.УстановитьЗначениеПодчиненнойСтрокиВСтруктуреФормы — используется для связывания родительских и дочерних таблиц (например, груза и пунктов его выгрузки).
  3. ОбменСГИСЭПДКлиентСервер.КонтейнерОтображаемойВерсииРеквизита — кэширующий контейнер, предотвращающий постоянное рекурсивное копирование структуры при массовой установке полей.

Сквозной пример программного заполнения формы ЭЗЗ

Разберем готовый алгоритм заполнения основной формы документа ЭлектронныйЗаказЗаявка. Код выполняется на клиенте в модуле расширения формы или подключаемом модуле.


&НаКлиенте
Процедура ЗаполнитьФормуЗаказаЗаявки(ДанныеЗаполнения)

    // 1. Инициализируем контейнер отображаемой версии один раз для всех вызовов
    КонтейнерВерсииТитула = ОбменСГИСЭПДКлиентСервер.КонтейнерОтображаемойВерсииРеквизита(
        ЭтотОбъект, 
        "ТитулГрузоотправителяГрузы"
    );

    // 2. Установка шапочных (однократных) реквизитов
    ПростыеРеквизиты = Новый Структура;
    ПростыеРеквизиты.Вставить("СсылкаТитулГрузоотправителяГрузоотправитель", ДанныеЗаполнения.Клиент);
    ПростыеРеквизиты.Вставить("СсылкаТитулГрузоотправителяСоставитель", ДанныеЗаполнения.Организация);
    ПростыеРеквизиты.Вставить("СсылкаТитулГрузоотправителяПеревозчик", ДанныеЗаполнения.Перевозчик);
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяФункция", "Заявка");
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяЗаказНомер", "13/37");
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяЗаказДата", ДанныеЗаполнения.ДатаСеанса);
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяЗаявленныеДатаВремяПодачи", ДанныеЗаполнения.ДатаСеанса);
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяДоговорНаименование", "Договор перевозки груза");
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяДоговорНомер", "13/37");
    ПростыеРеквизиты.Вставить("ТитулГрузоотправителяДоговорДата", ДанныеЗаполнения.ДатаСеанса);

    Для Каждого ОписаниеРеквизита Из ПростыеРеквизиты Цикл
        ОбменСГИСЭПДКлиентСервер.УстановитьЗначениеРеквизитаВСтруктуреФормы(
            ЭтотОбъект, 
            ОписаниеРеквизита.Ключ, 
            ОписаниеРеквизита.Значение, 
            Истина, 
            КонтейнерВерсииТитула
        );
    КонецЦикла;

    // 3. Заполнение строки таблицы грузов
    ИдентификаторСтрокиГруза = Строка(Новый УникальныйИдентификатор);
    ЗначенияГруза = Новый Структура;
    ЗначенияГруза.Вставить("ИдентификаторСтроки", ИдентификаторСтрокиГруза);
    ЗначенияГруза.Вставить("ОтгрузочноеНаименованиеГруза", "Продукция пищевая");
    ЗначенияГруза.Вставить("СостояниеГруза", "Исправное");
    ЗначенияГруза.Вставить("ВидТары", "BA");
    ЗначенияГруза.Вставить("КоличествоГрузовыхМест", 100);
    ЗначенияГруза.Вставить("МетодОпределенияМассыГруза", "01");
    ЗначенияГруза.Вставить("ОбъемГруза", 48);
    ЗначенияГруза.Вставить("МассаБрутто", 25000);
    ЗначенияГруза.Вставить("МассаНетто", 24000);
    ЗначенияГруза.Вставить("Высота", 2);
    ЗначенияГруза.Вставить("Длина", 12);
    ЗначенияГруза.Вставить("Ширина", 2);
    // Булевы поля обязательны к передаче (даже со значением Ложь!)
    ЗначенияГруза.Вставить("ВозможностьРаспределенияПоДлинеПлатформы", Ложь);
    ЗначенияГруза.Вставить("ДелимостьГруза", Ложь);

    Для Каждого ЗначениеКолонки Из ЗначенияГруза Цикл
        ОбменСГИСЭПДКлиентСервер.УстановитьЗначениеРеквизитаВСтруктуреФормы(
            ЭтотОбъект, 
            "ТитулГрузоотправителяГрузы__1__" + ЗначениеКолонки.Ключ, 
            ЗначениеКолонки.Значение, 
            Истина, 
            КонтейнерВерсииТитула
        );
    КонецЦикла;

    // 4. Заполнение подчиненной таблицы пунктов погрузки/выгрузки
    ЗначенияПунктаГруза = Новый Структура;
    ЗначенияПунктаГруза.Вставить("ИдентификаторСтроки", Строка(Новый УникальныйИдентификатор));
    ЗначенияПунктаГруза.Вставить("ПунктПогрузки", "1");
    ЗначенияПунктаГруза.Вставить("ПунктВыгрузки", "2");
    ЗначенияПунктаГруза.Вставить("КоличествоГрузовыхМест", 100);

    ОбменСГИСЭПДКлиентСервер.УстановитьЗначениеПодчиненнойСтрокиВСтруктуреФормы(
        ЭтотОбъект, 
        "ТитулГрузоотправителяГрузыПунктыПогрузкиВыгрузки", 
        ИдентификаторСтрокиГруза, 
        ЗначенияПунктаГруза, 
        Истина, 
        КонтейнерВерсииТитула
    );

    // 5. Фиксация обновленной структуры в форме
    ЭтотОбъект.СтруктураРеквизитов = ОбменСГИСЭПДКлиентСервер.СкопироватьВФиксированноеЗначенияРекурсивно(
        КонтейнерВерсииТитула.СтруктураРеквизитовЗаполнение
    );

    // 6. Обновление визуального состояния оформлений и гиперссылок
    ИменаУчастников = "СсылкаТитулГрузоотправителяГрузоотправитель,СсылкаТитулГрузоотправителяСоставитель,СсылкаТитулГрузоотправителяПеревозчик";
    Для Каждого ИмяЭлемента Из СтрРазделить(ИменаУчастников, ",") Цикл
        ОбменСГИСЭПДКлиентСервер.ЗаполнитьРеквизитыПоСсылке(Элементы[ИмяЭлемента], ЭтотОбъект);
    КонецЦикла;

    ИзменитьОформлениеКнопок(Новый ФиксированнаяСтруктура("ИмяКнопки, ИдентификаторСтроки"));

КонецПроцедуры

Работа со справочником «Хранимые данные ЭПД»

Реквизиты с типом СправочникСсылка.ХранимыеДанныеЭПД (например, параметры транспортных средств, данные водителей или стороны договора) не могут быть корректно отображены простым присвоением текстовых полей или ИНН. Подсистема ожидает ссылку на объект этого справочника.

Для создания такой записи без ручного формирования табличной части справочника в подсистеме БЭД есть специальная серверная функция ОбменСГИСЭПД.ЗаписатьХранимыеДанныеЭПД.

Рассмотрим, как програмно сформировать запись для стороны договора:


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

    // Если элемент не найден — формируем структуру и записываем
    ЗначенияСтороны = Новый Структура;
    ЗначенияСтороны.Вставить("ОбщееПолеВводаИНН", ИННСтороны);
    ЗначенияСтороны.Вставить("ЮЛ_ИНН", ИННСтороны);

    ПредставленияСтороны = Новый Структура;
    Для Каждого ОписаниеПоля Из ЗначенияСтороны Цикл
        ПредставленияСтороны.Вставить(ОписаниеПоля.Ключ, Строка(ОписаниеПоля.Значение));
    КонецЦикла;

    ОписаниеДанных = Новый Структура;
    ОписаниеДанных.Вставить("ИмяФормы", "Документ.ЭлектронныйЗаказЗаявка.Форма.СторонаПодписавшаяДокумент");
    ОписаниеДанных.Вставить("ДанныеЗаполненияРеквизитовФормы", ЗначенияСтороны);
    ОписаниеДанных.Вставить("ОписаниеРеквизитовФормы", Новый Структура("Представления", ПредставленияСтороны));
    ОписаниеДанных.Вставить("ДанныеЗаполненияТаблицФормы", Новый Структура);

    Возврат ОбменСГИСЭПД.ЗаписатьХранимыеДанныеЭПД(
        "СторонаПодписавшаяДокумент", 
        Организация, 
        Контрагент, 
        "", 
        ОписаниеДанных
    );
КонецФункции

Для связывания одиночной группы (например, параметры ТС) с формой, после получения ссылки следует задействовать метод:


ЭтотОбъект.ХранимыеДанныеТитулГрузоотправителяПараметрыТранспортногоСредства = СсылкаНаПараметрыТС;
ОбменСГИСЭПДКлиент.ХранимыеДанныеПриИзменении(
    ЭтотОбъект, 
    СсылкаНаПараметрыТС, 
    Элементы.ХранимыеДанныеТитулГрузоотправителяПараметрыТранспортногоСредства, 
    , 
    КонтейнерВерсииТитула, 
    Ложь
);

Распространенные ошибки и способы их диагностики

Часто после заполнения реквизитов программным путем гиперссылки в форме остаются красными со значением «Заполнить» или «Не заполнено» вместо синей надписи (например, «1 груз»). Проанализируем основные причины такого поведения:

  1. Пропущены обязательные булевы флаги. Если в структуру строки груза не передать параметры ВозможностьРаспределенияПоДлинеПлатформы или ДелимостьГруза, подсистема считает их равными Неопределено. Проверка обязательности узлов в XML-схеме выдаст ошибку, и кнопка останется неактивной.
  2. Заполнение контактных телефонов участников до вызова служебных функций. Метод ОбменСГИСЭПДКлиентСервер.ЗаполнитьРеквизитыПоСсылке считывает контактную информацию из карточки контрагента в базе. Если у контрагента телефон не указан, функция перетрет ранее переданный вами телефон пустым значением. Поэтому номера телефонов участников следует устанавливать строго после вызова данной процедуры.
  3. Формирование подчиненных таблиц. Если в таблице ТитулГрузоотправителяГрузыПунктыПогрузкиВыгрузки была создана строка, подсистема подписи требует заполнения трех обязательных колонок: ПунктПогрузки, ПунктВыгрузки и КоличествоГрузовыхМест. В противном случае весь блок отмечен как ошибочный.

Чтобы быстро найти отсутствующее поле и не подбирать варианты наугад, используем штатную функцию самодиагностики подсистемы БЭД:


// Диагностика заполнения формы на клиенте
СтруктураПоТитулу = ОбменСГИСЭПДКлиентСервер.ПолучитьСтруктуруПоТитулуИВерсии(ЭтотОбъект);
ОписанияОшибок = ОбменСГИСЭПДВызовСервера.ПроверитьЗаполнениеДокументаЭПД(
    СтруктураПоТитулу, 
    Объект.ТекущийТитул, 
    Объект.ВидДокумента
);

Для Каждого ОписаниеОшибки Из ОписанияОшибок Цикл
    Сообщить(Строка(ОписаниеОшибки.Узел) + ": " + СтрСоединить(ОписаниеОшибки.Текст, " "));
КонецЦикла;

Этот код выведет список незаполненных полей XML-схемы прямо в окно сообщений, позволяя мгновенно локализовать проблему. Для проверки данных до формирования ЭТрН можно использовать обработку аудита готовности базы к ЭТрН, которая ищет незаполненные реквизиты по документам-основаниям и автоматически заполняет однозначно определяемые значения после предпросмотра.

← На главную