Введение
Мобильная платформа 1С работает только с одной конфигурацией. Под каждую конфигурацию создается свой мобильный клиент.
Если посмотреть объекты в конфигурации, то в основном это справочники, документы и регистры.
А это уже процентов 80% тех данных, которым нужно обмениваться с любым клиентом.
Но ведь справочники и документы это стандартные объекты, у них есть стандартные реквизиты и стандартное поведение. И поведение справочников и документов не меняется при переходе например от УТ к БП. Например документ можно провести, а справочник поставить пометку на удаление.
В этой статье мы попробуем описать решение, в котором мы стандартную логику вынесем в общие модули, которые не будут меняться при переходе от одной конфигурации к другой. И напишем добавленную логику, которая будет зависеть от конкретной конфигурации 1С.
Инфраструктура
Договоримся, что мобильное приложение работать через HTTP сервисы. Для этого 1С должна быть опубликована на веб-сервере. Обмен будет происходит через обычные запросы с использование JSON.
Также в 1С будет создан ПланОбмена, в котором будет хранится регистрация изменений объектов
В мобильном приложении сохранен логин и пароль для авторизации к 1С и выполнения запросов.
План обмена
У нас может быть одна база 1С и несколько мобильных устройств на каждом из которых стоит мобильный клиент. Значит, нужно знать какие изменения были для каждого устройства. Для этого при первом обмене мобильного клиента в 1С создается экземпляр плана обмена с ID устройством. Это поможет идентифицировать план обмена для каждого устройства и знать, какие данные изменились для каждого устройства.
HTTP сервис 1С
В нашем HTTP сервисе будет несколько эндпоинтов:
- ЗарегистрироватьОбъекты
- ВыгрузитьРегистрациюОбъектов
- ВыгрузитьОбъекты
- УдалитьРегистрациюОбъектов
- ЗагрузитьОбъекты
- ВыгрузитьОбновленныеДанные
1 ЗарегистрироватьОбъекты
Этот метод нужен для регистрации какого либо типа объекта в плане обмена при первой синхронизации данных. В мобильном клиенте еще не было синхронизаций например справочника Номенклатуры. Значит нужно сходить в 1С и зарегистрировать все объекты Номенклатуры чтобы потом их загрузить.
Возвращаем успешный ответ или ошибку.
2 ВыгрузитьРегистрациюОбъектов
В этом методе мы выгражаем зарегистрированные объекты какого либо типа данных из шага 1. Почему мы выгружаем не сами данные а их регистрацию ? Потому что данных может быть очень много и это нужно разбить на запросы.
Возвращаем массив данных или ошибку.
3 ВыгрузитьОбъекты
В этом методе зная регистрацию объекта мы идем в 1С и получаем данные этого объекта.
Возвращаем JSON данные или ошибку.
4 УдалитьРегистрациюОбъектов
При успешном шаге 3 мы в 1С удаляем регистрацию изменений тех объектов которые успешно загрузили
Возвращаем успешный ответ или ошибку.
5 ЗагрузитьОбъекты
В этом методе мы загружаем из мобильного клиента например документ Заказ покупателя.
Возвращаем успешный ответ или ошибку.
6 ВыгрузитьОбновленныеДанные
После шага 5 мы в 1С уже что то загрузили и объект после загрузки в 1С мог получить дополнительные свойства. Например документ получает номер из базы 1С.
Так вот в этом методе мы возвращаем новые данные которых не было на шаге 3. Мы не выполняем заново шаг 3 на мобильном клиенте чтобы сэкономить на траффике и скорости обмена.
Возвращаем JSON данные или ошибку.
Маппинг данных
Давайте подумаем, как мы можем разделить данные на те, которые не меняются от разных конфигураций и те, которые будут меняться в зависимости от конфигурации.
Например регистрация объекта. Справочник и документ идентифицируются в базе по ссылке. У ссылки есть уникальный идентификатор. Уникальный идентификатор не меняется в зависимости от конфигурации.
А вот тип данных меняется. В УТ есть справочник Номенклатура, а в базе ЗУП справочник Сотрудники. Это разные типы данных. Значит 1С должна уметь понимать какой тип данных. С другой стороны справочник имеет стандартные реквизиты: код, наименование, пометка удаления. Стандартные реквизиты не меняются.
Архитектурная идея
Представим, что мы выполняем запрос 3 ВыгрузитьОбъекты. Давайте распишем по шагам.
- 1 Мобильный клиент отправляет запрос, в котором передает, что он хочет получить данные справочника номенклатуры и передает ссылку на номенклатуру.
type: catalogNomenclature
uuid: UUID
- 2 1С получила запрос с type: catalogNomenclature. 1С нужно понять какой это тип данных. Для этого в 1С сделаем общий модуль "МобильноеПриложение_МаппингДанныхПовтИспЧастный" в котором будет функция которая зная type: catalogNomenclature может вернуть тип данных 1С.
Зная тип данных 1С можно получить менеджер этого тип данных. В нашем примере мы получим "СправочникМенеджер.Номенклатура".
Зная менеджер справочника мы в менеджере напишем формирование данных для объекта с конкретным UUID.
- 3 1С формирует данные и возвращает их в ответе на запрос
Из этих 3 шагов у нас для разных конфигураций 1С будет только отличаться будет только маппинг типа данных в менеджер объекта.
Например база УТ
type: catalogNomenclature - "СправочникМенеджер.Номенклатура"
База ЗУП
type: catalogEmployee - "СправочникМенеджер.Сотрудники"
Но ведь это логично. Разные базы, разные объекты, для каждой базы свой маппинг.
Также для каждой базы свой "СправочникМенеджер". Но внутри модуля "СправочникМенеджер" и будет формирование данных этого типа. Мы все равно при установки расширения в новую базу будет выгружать другие объекты, значит другие менеджеры справочников, значит этот код завязан на конкретную конфигурацию.
Структура модулей расширения

Давайте посмотрим на структуру модулей. Красным цветом я выделил те модули которые будут менятся при установке расширения на новую конфигурацию 1С.
А весь остальной код будет неизменным.
Давайте посмотрим модуль МобильноеПриложение_МаппингДанныхПовтИспЧастный.
Функция ПолучитьСоотвествиеМенеджеры() Экспорт
Соответствие = Новый Соответствие;
//Справочники
Соответствие.Вставить("catalogNomenclature", Справочники.Номенклатура);
//Документы
Соответствие.Вставить("documentOrder", Документы.ЗаказКлиента);
Возврат Соответствие;
КонецФункции
Тут как пример мы формируем соответствие типов данных для мобильного клиента и менеджера объекта в 1С.
Следующий интересный модуль будет МобильноеПриложение_ФормированиеДанных.
Функция ПодготовитьДанныеОбъекта(Регистрация)
ТипОбъекта = МобильноеПриложение_ЧтениеДанных.ПолучитьСвойство(Регистрация, МобильноеПриложение_МаппингДанныхПовтИспОбщий.ПолучитьКлючТип());
Менеджер = МобильноеПриложение_МаппингДанныхПовтИспОбщий.ПолучитьМенеджерОбъекта(ТипОбъекта);
Если Менеджер = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Данные = Менеджер.ПодготовитьДанныеРегистрация(Регистрация);
Возврат Данные;
КонецФункции
Самое интересное тут то, что зная тип объекта мы получаем менеджер объекта. Но мы тут ссылаемся на МобильноеПриложение_МаппингДанныхПовтИспОбщий.
Давайте и его посмотрим МобильноеПриложение_МаппингДанныхПовтИспОбщий
Функция ПолучитьМенеджерОбъекта(ТипОбъектаПриложения) Экспорт
СоотвествиеМенеджеров = МобильноеПриложение_МаппингДанныхПовтИспЧастный.ПолучитьСоотвествиеМенеджеры();
МенеджерОбъекта = СоотвествиеМенеджеров.Получить(ТипОбъектаПриложения);
Если МенеджерОбъекта = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Возврат МенеджерОбъекта;
КонецФункции
Такие образом зная тип объекта, мы можем получить его менеджер.
Далее давайте посмотрим на формирование данных в менеджере. Метод ПодготовитьДанныеРегистрация.
Функция ПодготовитьДанныеРегистрация(Регистрация) Экспорт
УИСтрока = МобильноеПриложение_ЧтениеДанных.ПолучитьСвойство(Регистрация, МобильноеПриложение_МаппингДанныхПовтИспОбщий.ПолучитьКлючИдентификацияОбъекта());
УникальныйИдентификатор = Новый УникальныйИдентификатор(УИСтрока);
Данные = ПодготовитьДанныеУИ(УникальныйИдентификатор);
Возврат Данные;
КонецФункции
Функция ПодготовитьДанныеУИ(УникальныйИдентификатор) Экспорт
СправочникСсылка = ПолучитьСсылку(УникальныйИдентификатор);
Данные = ПодготовитьДанныеСсылка(СправочникСсылка);
Возврат Данные;
КонецФункции
Функция ПодготовитьДанныеСсылка(СправочникСсылка) Экспорт
СтруктураДанных = МобильноеПриложение_ФормированиеДанных.ПодготовитьСтруктуруСправочника(СправочникСсылка);
Если СправочникСсылка.ЭтоГруппа Тогда
Возврат СтруктураДанных;
КонецЕсли;
СтруктураДанных.Вставить(МобильноеПриложение_МаппингДанныхПовтИспОбщий.ПолучитьКлючАртикул(), СправочникСсылка.Артикул);
СтруктураДанных.Вставить(МобильноеПриложение_МаппингДанныхПовтИспЧастный.ПолучитьКлючЕдиницаИзмерения(), Справочники.УпаковкиЕдиницыИзмерения.ПодготовитьДанныеСсылка(СправочникСсылка.ЕдиницаИзмерения));
СтруктураДанных.Вставить(МобильноеПриложение_МаппингДанныхПовтИспЧастный.ПолучитьКлючВидНоменклатуры(), Справочники.ВидыНоменклатуры.ПодготовитьДанныеСсылка(СправочникСсылка.ВидНоменклатуры));
СтруктураДанных.Вставить(МобильноеПриложение_МаппингДанныхПовтИспЧастный.ПолучитьКлючСтавкаНДС(), Справочники.СтавкиНДС.ПодготовитьДанныеСсылка(СправочникСсылка.СтавкаНДС));
ДанныеКартинки = Неопределено;
Если ЗначениеЗаполнено(СправочникСсылка.ФайлКартинки) Тогда
ДанныеКартинки = МобильноеПриложение_ФормированиеДанных.ПодготовитьОбщуюСтруктуруСправочника(СправочникСсылка.ФайлКартинки)
КонецЕсли;
СтруктураДанных.Вставить(МобильноеПриложение_МаппингДанныхПовтИспЧастный.ПолучитьКлючКартинка(), ДанныеКартинки);
Возврат СтруктураДанных;
КонецФункции
В суть в методе ПодготовитьДанныеСсылка. Именно тут и происходит формирование данных.
Помните, в самом начале я говорил, что у справочников есть стандартные реквизиты.
СтруктураДанных = МобильноеПриложение_ФормированиеДанных.ПодготовитьСтруктуруСправочника(СправочникСсылка);
Эта строчка и формирует общие данные для справочников. То есть при переходе в новую базу мы просто возьмем формирование этих данных и вставим сюда.
А вот дальше идет формирование бизнес данных конкретного справочника. Проще говоря, мы формируем структуру реквизитов для мобильного клиента.
Теперь давайте посмотрим на модуль МобильноеПриложение_ПланОбменаЧастный.
Процедура ЗарегистрироватьОбъекты(ПланОбмена, ИмяОбъекта) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| &ВыгружатьНоменклатуру";
Запрос.УстановитьПараметр("ПланОбмена", ПланОбмена);
Запрос.УстановитьПараметр("ВыгружатьНоменклатуру", ИмяОбъекта = "Номенклатура");
Массив = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
МобильноеПриложение_ПланОбменаОбщий.ДобавитьРегистрациюМассивДанных(ПланОбмена, Массив);
КонецПроцедуры
Функция ПолучитьРегистрациюОбъектов(ПланОбмена, ИмяОбъекта) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| НоменклатураИзменения.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура.Изменения КАК НоменклатураИзменения
|ГДЕ
| НоменклатураИзменения.Узел = &ПланОбмена
| И &ВыгружатьНоменклатуру";
Запрос.УстановитьПараметр("ПланОбмена", ПланОбмена);
Запрос.УстановитьПараметр("ВыгружатьНоменклатуру", ИмяОбъекта = "Номенклатура");
Массив = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
Возврат Массив
КонецФункции
Поскольку это частный модуль, он зависит от конкретных объектов конфигурации.
1 ЗарегистрироватьОбъекты. Это метод из шага 1. Тут мы зная тип данных который смаппили регистрируем объекты на плане обмена.
2 ПолучитьРегистрациюОбъектов. Это метод из шага 2. Тут мы зная тип данных выгружаем регистрацию например ссылки справочника в виде UUID.
Краткие выводы
Такое решение позволит нам гибко маппить типы данных для разных конфигураций 1С.
Формирование данных происходит в менеджере объекта.
Нет смысла выносить формирование данных в общие модули. Поскольку формирование данных объекта очень тесно связано с самим объектов и его типом данных. Лучше внутри менеджера использовать общий инфраструктурный код который поможет сформировать данные этого объекта.
При масштабировании у нас будет меняться
- 2 общих модуля
МобильноеПриложение_МаппингДанныхПовтИспЧастный.
МобильноеПриложение_ПланОбменаЧастный.
- Менеджеры объектов
СправочникМенеджерНоменклатура
СправочникМенеджерСклады
и т.д.
Но у нас будет много инфраструктурного кода который будет помогать нам формировать данные, формировать JSON, формировать ключи для структур и прочий полезный код.
Проблемы которые ждут это решение
Поскольку это расширение нужно четко вести версионирование кода.
Каждая версия мобильного клиента должна работать с конкретной версией расширения. Иначе клиент сделает запрос, на который 1С не сможет ответить.
Также будет проблема версионирования самой конфигурации. Представим что мы дали это расширение для работы с УТ 2 клиентам у которых разная версия самой базы УТ.
У первого клиента в справочнике номенклатуры есть новый реквизит. А у второго клиенте еще нет. Это проблема.
Финальные мысли
В этой статье мы коснулись разработки решения для обмена с мобильными клиентами. Мы не затронули работу самих мобильных клиентов. А это тоже очень важная и большая часть. Ведь раз мы хотим масштабировать решение 1С мы также должны масштабировать решение и самого мобильного клиента. То есть мобильные клиент не должен каждый раз писаться с нуля. А должен использовать различные библиотеки например для выполнения запросов. Также мобильный клиент должен как то хранить данные. А также понимать что на мобильном клиенте изменилось чтобы эти изменения выгрузить обратно. Но не все так плохо. На самом деле уже вышла первая версия приложения. Ниже будут опубликованы ссылки.
Полезные ссылки
iOS Приложение Управление торговлей в AppStore
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 11, релизы 11.5.17.213
Вступайте в нашу телеграмм-группу Инфостарт