1С ERP: определение партнера при получении электронного УПД через ЭДО с помощью дополнительного поля
Данная шпаргалка не содержит готового решения (оно может быть весьма объёмным), а только подсказывает метод доработки и ключевые места в конфигурации 1С ERP, где можно вписать свои точки входа.
Описание проблемы
Клиент закупает материалы у торговой сети, действующей от имени одного юридического лица, соответственно в 1С ERP создан один элемент справочника Контрагенты, и множество элементов справочника Партнеры с иерархией, отражающей некую структуру (заводы, магазины, склады, региональные представительства и т.д.).
Торговая сеть через ЭДО присылает клиенту электронные УПД с дополнительными полями, одно из которых идентифицирует нужного партнера. Проблема состоит в том, что в формате УПД указываются только реквизиты юридического лица, а дополнительные данные при приёме в ERP никак не обрабатываются. В итоге система в новый документ приобретения товаров и услуг подбирает головного партнера - того который указан в форме справочника Контрагенты.
Кроме подбора не того партнера происходит вещь и похуже: при сопоставлении номенклатуры из УПД и информационной базы система ошибочно предлагает сопоставить номенклатуру только по головному партнеру. Таким образом, этап сопоставления номенклатуры в подсистеме ЭДО невозможно пройти даже в ручном режиме. В итоге документ 'Приобретение товаров и услуг' приходится создавать и заполнять целиком вручную.
Реализация входящего электронного документа в 1С ЭДО
Прежде всего, посмотрим как устроен входящий электронный документооборот, чтобы понять куда бежать. Как видно из рисунка ниже, в нашем случае партнера нужно определять на основе дополнительной информации из поля номер 7 с наименованием "СкладОтправитель":
Все полученные электронные документы записываются в документ ЭлектронныйДокументВходящийЭДО:
Содержание полученного через ЭДО подписанного документа в формате XML хранится в присодиненном файле, запрятанном глубоко посредством справочников и регистров сведений. Выглядит сложно и запутанно, но хорошая новость состоит в том, что копаться во всех этих хитросплетениях вам не придётся.
Путь для решения задачи
На самом деле, точка вмешательства будет всего в трёх общих модулях, а рутинные функции получения документа из присоединенного файла и разбора электронного документа в дерево уже реализованы в ERP и писать их с нуля не потребуется.
Каждую задачу решаем поэтапно, но так как корень всех проблем лежит в подборе неправильного партнёра, то для начала вам нужно добавить собственный модуль и написать в нём функцию, которая возвращает нужного партнера в зависимости от переданного параметра, в моем случае это номер склада-отправителя. Способ сопоставления вы определяете сами: через дополнительный реквизит для справочника "Партнеры", или создаете новый регистр сведений, или добавляете новый реквизит, или ещё каким другим способом. У вас должно получится что-то примерно такое:
Функция ПолучитьНастройкиЭДО(СкладОтправитель) Экспорт
ЗаполнениеПриобретениеЭДО = Новый Структура("Партнер, Соглашение, Подразделение");
...
Возврат ЗаполнениеПриобретениеЭДО;
КонецФункции
Как видите, вместо одного партнера возвращается структура с другими дополнительными данными. Тут я просто попутно решил автоматически заполнять ещё и другие поля в документе приобретения, потому что они в подсистеме ЭДО тоже заполняются (или не заполняются) неконтролируемым способом, как и Партнер. Вы можете этого не делать и ограничиться только полем Партнер.
Этап 1: Контроль сопоставления номенклатуры
Идём в общий модуль ИнтеграцияЭДО и находим функцию ВыполнитьКонтрольСопоставленияНоменклатуры:
Функция ВыполнитьКонтрольСопоставленияНоменклатуры(Знач ДанныеЭлектронногоДокумента = Неопределено,
Знач НаборНоменклатурыКонтрагентов = Неопределено, Знач Сохранить = Истина) Экспорт
...
// Извлекаем данные о номенклатуре контрагента из электронного документа.
Если Не ЗначениеЗаполнено(НаборНоменклатурыКонтрагентов) И ЗначениеЗаполнено(ЭлектронныйДокумент) Тогда
...
Контрагент = ДанныеЭлектронногоДокумента.Отправитель;
Владелец = СопоставлениеНоменклатурыКонтрагентовСлужебный.ВладелецНоменклатурыКонтрагента(Контрагент);
...
КонецЕсли;
...
КонецФункции
Здесь вы ясно можете увидеть причину проблемы. Задача будет состоять в подменене значения переменной Владелец на правильного Партнера, используя ранее написанную собственную функцию подбора. Поставьте на этом месте закладку.
Можно было бы пойти путём модификации функции модуля СопоставлениеНоменклатурыКонтрагентовСлужебный, но для нашей задачи придётся либо добавлять новые параметры, либо превращать единственный параметр 'Контрагент' в структуру. Рекомендую самостоятельно посмотреть полную цепочку вызова и постичь глубину дна, и поиском получить список вызывающих мест, чтобы отказаться от этой затеи.
Этап 2: Правильный партнёр в обработке ручного сопоставления номенклатуры
В том же общем модуле ИнтеграцияЭДО находим процедуру ЗаполнитьНоменклатуруИБВДеревеДокумента:
Процедура ЗаполнитьНоменклатуруИБВДеревеДокумента(Контрагент, ДеревоДокумента) Экспорт
...
Владелец = СопоставлениеНоменклатурыКонтрагентовСлужебный.ВладелецНоменклатурыКонтрагента(Контрагент);
...
КонецФункции
Здесь аналогично как в Этапе 1, нужно делать подмену значения переменной Владелец. Ставим вторую закладку.
Этап 3: Контроль сопоставления номенклатуры (дополнительно)
Отладчиком я не отловил где именно используется этот кусок кода, но судя по вызову сервера где-то при интерактивной работе на форме. Здесь тоже потребуется подмена значения переменной Владелец. Общий модуль ИнтеграцияЭДОВызовСервера:
Функция ВыполнитьКонтрольСопоставленияНоменклатурыЭлектронногоДокумента(ДанныеЭлектронногоДокумента) Экспорт
...
Владелец = СопоставлениеНоменклатурыКонтрагентовСлужебный.ВладелецНоменклатурыКонтрагента(Контрагент);
...
КонецФункции
Этап 4: Создание документа 'Приобретение товаров и услуг'
На данном этапе решается проблема формирования документа 'Приобретение товаров и услуг' с правильными реквизитами. Идём в модуль ОбменСКонтрагентамиУТ и находим функцию ПодготовитьСтруктуруДляПриобретенияТоваровУслугУПД_2019. В самом конце перед возвратом данных вставим строчку кода для вызова пока ещё не написанной процедуры, в нём и будем производить манипуляции с возвращаемой структурой ДанныеДляЗаполнения:
Функция ПодготовитьСтруктуруДляПриобретенияТоваровУслугУПД_2019(ДеревоДанных) Экспорт
...
_ВашМодуль_.КорректировкаПартнераПоДеревуДанных(ДанныеДляЗаполнения, ДеревоДанных);
Возврат ДанныеДляЗаполнения;
КонецФункции
Код процедуры нужно писать примерно по следующему шаблону:
// Ищет в дереве электронного документа поле СкладОтправитель и корректирует соответственно ему значение
// поля Партнер, а также добавляет новые поля Подразделение и Соглашение в структуре ДанныеДляЗаполнения.Шапка
Процедура КорректировкаПартнераПоДеревуДанных(ДанныеДляЗаполнения, ДеревоДанных) Экспорт
Контрагент = ДанныеДляЗаполнения.Шапка.Контрагент;
Если Контрагент <> _ВашКонтрагент_ Тогда
Возврат; // обрабатываем УПД только от конкретного контрагента
КонецЕсли;
// Партнер
ДанныеДляЗаполнения.Шапка.Партнер = ...;
// Здесь также можно вставить реквизиты документа, которых изначально не было.
// К примеру, допустим у нас есть договор, тогда можно сразу заполнить для документа
// реквизиты 'ГруппаФинансовогоУчета' и 'НаправлениеДеятельности':
Договор = ...
ДанныеДляЗаполнения.Шапка.Вставить("ГруппаФинансовогоУчета", ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Договор, "ГруппаФинансовогоУчета"));
ДанныеДляЗаполнения.Шапка.Вставить("НаправлениеДеятельности", ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Договор, "НаправлениеДеятельности"));
КонецПроцедуры
Так как же извлечь дополнительные данные из электронного УПД?
Почти во всех вышеуказанных местах, помеченных закладками, уже есть значение типа ДеревоЗначений, из которого можно извлечь требуемое значение 'СкладОтправитель'. Это ДеревоДанных:
НастрЭДО = Неопределено;
СкладОтправитель = "";
ДопСведения = ДеревоДанных.Строки.Найти("ДопДанныеСчетаФактуры.ТекстоваяИнформация", "ПолныйПуть", Истина);
Если Не ЗначениеЗаполнено(ДопСведения) Тогда
Возврат НастрЭДО;
КонецЕсли;
Для Каждого СтрокаДопИнформации Из ДопСведения.Строки Цикл
НаименованиеДопИнформации = ЭлектронноеВзаимодействие.ЗначениеРеквизитаВДереве(СтрокаДопИнформации, "ДопДанныеСчетаФактуры.ТекстоваяИнформация.НомерСтроки.Идентификатор");
Если ЗначениеЗаполнено(НаименованиеДопИнформации) И НаименованиеДопИнформации = "СкладОтправитель" Тогда
СкладОтправитель = ЭлектронноеВзаимодействие.ЗначениеРеквизитаВДереве(СтрокаДопИнформации, "ДопДанныеСчетаФактуры.ТекстоваяИнформация.НомерСтроки.Значение");
Если ЗначениеЗаполнено(СкладОтправитель) Тогда
СкладОтправитель = СокрЛП(СкладОтправитель);
КонецЕсли;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(СкладОтправитель) Тогда
НастрЭДО = ПолучитьНастройкиЭДО(СкладОтправитель); // ваша функция, определяющая Партнера по доп.значению
КонецЕсли;
В процедуре ЗаполнитьНоменклатуруИБВДеревеДокумента ДеревоДанных запрятано внутри ДереваДокумента:
ДеревоДанных = ДеревоДокумента.ЗначениеРеквизита;
В процедуре ВыполнитьКонтрольСопоставленияНоменклатуры ДеревоДанных можно извлечь из параметра ДанныеЭлектронногоДокумента по аналогии, как это сделано в других процедурах:
Если ДанныеЭлектронногоДокумента.Отправитель <> _ВашКонтрагент_ Тогда
Возврат; // обрабатываем УПД только от конкретного контрагента
КонецЕсли;
Если ДанныеЭлектронногоДокумента.ТипДокумента <> Перечисления.ТипыДокументовЭДО.УПД Тогда
Возврат; // обрабатываем только УПД
КонецЕсли;
ПараметрыПолучения = ЭлектронныеДокументыЭДО.НовыеПараметрыПолученияДанныхДокумента();
ПараметрыПолучения.ОсновнойФайл = ДанныеЭлектронногоДокумента.ДанныеОсновногоФайла;
ПараметрыПолучения.ДополнительныйФайл = ДанныеЭлектронногоДокумента.ДанныеДополнительногоФайла;
Результат = ЭлектронныеДокументыЭДО.ДанныеДокументаДляЗагрузкиПросмотра(ПараметрыПолучения);
ДеревоДанных = Результат.НовыйЭД.ЗначениеРеквизита;
...
Заключение
Всё что мог рассказал, надеюсь кому-то помог. Не забудьте при реализации своего решения вставить проверки заполненности полей и наличия реквизитов, к которым обращаетесь, т.к. нет никакой гарантии что в параметрах и переменных придёт именно то, что вы ожидаете получить.