Описание версий платформ и другого ПО:
Версия платформы 1С: 8.3.18.1563
Версия мобильной платформы: 8.3.18.77
Версия web-сервера Apache: 2.4.48
Все ПО имеет разрядность х64.
По мере возрастания количества целей этой статьи, я невольно пришел к необходимости этого. Чтобы у читателя не возникало ощущение праздности, я постараюсь описать задачу и эти самые цели.
Наше предприятие занимается оптовой и розничной торговлей.
Задача была следующей: разработать простое мобильное приложение 1С для ТСД, чтобы принимать передаваемый с оптовой базы в розничные точки товар.
Приемка имеет два режима работы: прием грузовых мест и прием товарного состава грузового места.
Данные об отгруженных местах и товарном составе записываются и хранятся в двух регистрах сведений в центральной базе:
Регистр сведений "МестаДляПередачиТоваров"
Регистр сведений "НоменклатураПоМестамДляПередачиТоваров"
Мобильное приложение должно уметь:
- Отправлять запрос на получение списка пользователей базы данных и выводить их на ТСД для выбора и авторизации;
- Отправлять запрос авторизации;
- Получать список документов передачи товаров и отображать его на ТСД;
- При выборе документа - получать список грузовых мест из учетной системы;
- При сканировании или выборе уже отсканированного грузового места - получать список товаров;
- При сканировании товара - записывать принятое количество в центральную базу.
Для связи мобильного приложения и центральной базы, в последней был создан http-сервис c именем "invent" и реализован один единственный метод "main" методом POST. Все остальные процедуры и функции вынесены в отдельный модуль "интеркомВызовСервера".
Текст обработчика метода main(POST)
Функция mainPOST(Запрос)
Отказ = Ложь;
ТекстОшибки = "";
Тело = "";
СтрокаТелаЗапроса = Запрос.ПолучитьТелоКакСтроку();
Попытка
ТелоЗапроса = интеркомВызовСервера.ДесериализоватьИзJSON(СтрокаТелаЗапроса);
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка десериализации запроса.";
КонецПопытки;
Отказ = ТелоЗапроса = Неопределено;
ТекстОшибки = ?(Отказ,"Запрос неопределен.", "");
//Формируем структуру с данными из тела запроса и проверяем состав полей
Если НЕ Отказ Тогда
СтруктураЗапроса = Новый Структура;
интеркомВызовСервера.СформироватьСтруктуруЗапроса(ТелоЗапроса, СтруктураЗапроса, Отказ, ТекстОшибки);
КонецЕсли;
Если НЕ Отказ Тогда
интеркомВызовСервера.ОбработатьЗапросТСД(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
КонецЕсли;
СтруктураТелаОтвета = Новый Структура;
СтруктураТелаОтвета.Вставить("success", НЕ Отказ);
СтруктураТелаОтвета.Вставить("error", ТекстОшибки);
СтруктураТелаОтвета.Вставить("body", Тело);
Попытка
ТелоОтвета = интеркомВызовСервера.СериализоватьВJSON(СтруктураТелаОтвета);
Исключение
Отказ = Истина;
СтруктураТелаОтвета = Новый Структура;
СтруктураТелаОтвета.Вставить("success", Ложь);
СтруктураТелаОтвета.Вставить("error", "Ошибка сериализации ответа.");
СтруктураТелаОтвета.Вставить("body", "");
ТелоОтвета = интеркомВызовСервера.СериализоватьВJSON(СтруктураТелаОтвета);
КонецПопытки;
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки(ТелоОтвета, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Возврат Ответ;
КонецФункции
Текст модуля интеркомВызовСервера
Функция ДесериализоватьИзJSON(Значение, ИменаСвойствСоЗначениямиДата = Неопределено) Экспорт
Если ПустаяСтрока(Значение) Тогда
Структура = Неопределено;
Иначе
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Значение);
Если ИменаСвойствСоЗначениямиДата = Неопределено Тогда
Структура = ПрочитатьJSON(ЧтениеJSON, Истина);
Иначе
Структура = ПрочитатьJSON(ЧтениеJSON, Истина, ИменаСвойствСоЗначениямиДата)
КонецЕсли;
ЧтениеJSON.Закрыть();
КонецЕсли;
Возврат Структура;
КонецФункции
Функция СериализоватьВJSON(Значение) Экспорт
ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписиJSON);
ЗаписатьJSON(ЗаписьJSON, Значение);
СериализованнаяСтрока = ЗаписьJSON.Закрыть();
Возврат СериализованнаяСтрока;
КонецФункции
//Формируем структуру с данными из полученного запроса и заодно проверяем, все ли поля есть
Процедура СформироватьСтруктуруЗапроса(ТелоЗапроса, СтруктураЗапроса, Отказ, ТекстОшибки) Экспорт
МассивОбязательныхПолейЗапроса = МассивОбязательныхПолейЗапроса();
Для каждого ИмяПоля ИЗ МассивОбязательныхПолейЗапроса Цикл
ЗначениеПоля = ТелоЗапроса.Получить(ИмяПоля);
Если ЗначениеПоля <> Неопределено Тогда
СтруктураЗапроса.Вставить(ИмяПоля, ЗначениеПоля);
Иначе
Отказ = Истина;
ТекстОшибки = "Переданы неверные параметры.";
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
//Массив обязательных полей которые должны присутствовать в теле запроса JSON
Функция МассивОбязательныхПолейЗапроса()
МассивПолей = Новый Массив;
МассивПолей.Добавить("org");
МассивПолей.Добавить("doc");
МассивПолей.Добавить("user");
МассивПолей.Добавить("method");
МассивПолей.Добавить("body");
Возврат МассивПолей;
КонецФункции
Процедура ОбработатьЗапросТСД(СтруктураЗапроса, Тело, Отказ, ТекстОшибки) Экспорт
Если СтруктураЗапроса.method = "get_users" Тогда
ОбработатьМетод_get_users(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ИначеЕсли СтруктураЗапроса.method = "auth" Тогда
ОбработатьМетод_auth(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ИначеЕсли СтруктураЗапроса.method = "get_docs" Тогда
ОбработатьМетод_get_docs(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ИначеЕсли СтруктураЗапроса.method = "cargo" Тогда
ОбработатьМетод_cargo(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ИначеЕсли СтруктураЗапроса.method = "check_cargo" Тогда
ОбработатьМетод_check_cargo(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ИначеЕсли СтруктураЗапроса.method = "check_good" Тогда
ОбработатьМетод_check_good(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
Иначе
Отказ = Истина;
ТекстОшибки = "Метод " + СтруктураЗапроса.method + " не найден";
Возврат;
КонецЕсли;
КонецПроцедуры
//Обработки методов
Процедура ОбработатьМетод_get_users(СтруктураЗапроса, Тело, Отказ, ТекстОшибки)
Попытка
Организация = Справочники.Организации.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.org));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найдена организация по идентификатору " + СтруктураЗапроса.org;
Возврат;
КонецПопытки;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| интеркомДополнительныеНастройкиПользователей.Пользователь.Ссылка КАК Ссылка,
| интеркомДополнительныеНастройкиПользователей.Пользователь.Наименование КАК Наименование
|ИЗ
| РегистрСведений.интеркомДополнительныеНастройкиПользователей КАК интеркомДополнительныеНастройкиПользователей
|ГДЕ
| интеркомДополнительныеНастройкиПользователей.ОсновнаяОрганизация = &ОсновнаяОрганизация
| И интеркомДополнительныеНастройкиПользователей.ПользовательТСД
| И интеркомДополнительныеНастройкиПользователей.Пользователь.ФизическоеЛицо <> ЗНАЧЕНИЕ(Справочник.ФизическиеЛица.ПустаяСсылка)";
Запрос.УстановитьПараметр("ОсновнаяОрганизация", Организация);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при выполнении запроса метода get_users";
Возврат;
КонецПопытки;
Если РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
ТекстОшибки = "Не найдено ни одного пользователя";
Возврат;
КонецЕсли;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Тело = Новый Массив;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
СтруктураПользователя = Новый Структура;
СтруктураПользователя.Вставить("id", XMLСтрока(ВыборкаДетальныеЗаписи.Ссылка));
СтруктураПользователя.Вставить("name", ВыборкаДетальныеЗаписи.Наименование);
Тело.Добавить(СтруктураПользователя);
КонецЦикла;
КонецПроцедуры
Процедура ОбработатьМетод_auth(СтруктураЗапроса, Тело, Отказ, ТекстОшибки)
Пароль = СтруктураЗапроса.body;
Попытка
ПользовательСсылка = Справочники.Пользователи.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.user));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найден пользователь по идентификатору " + СтруктураЗапроса.user;
Возврат;
КонецПопытки;
УстановитьПривилегированныйРежим(Истина);
Попытка
ХешТекущегоПароля = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(ПользовательСсылка.ИдентификаторПользователяИБ).СохраняемоеЗначениеПароля;
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при авторизации пользователя " + СтруктураЗапроса.user;
Возврат;
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);
Если ХешТекущегоПароля = "" Тогда
Возврат; // Пустой пароль
КонецЕсли;
ПозицияРазделителя = Найти(ХешТекущегоПароля, ",");
Отказ = НЕ (Пароль = Лев(ХешТекущегоПароля, ПозицияРазделителя - 1));
ТекстОшибки = "Пароль не подходит";
Возврат;
КонецПроцедуры
Процедура ОбработатьМетод_get_docs(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
Попытка
Организация = Справочники.Организации.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.org));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найдена организация по идентификатору " + СтруктураЗапроса.org;
Возврат;
КонецПопытки;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПередачаТоваровМеждуОрганизациями.Ссылка КАК Ссылка,
| ПередачаТоваровМеждуОрганизациями.Номер КАК Номер,
| ПередачаТоваровМеждуОрганизациями.Дата КАК Дата
|ИЗ
| Документ.ПередачаТоваровМеждуОрганизациями КАК ПередачаТоваровМеждуОрганизациями
|ГДЕ
| ПередачаТоваровМеждуОрганизациями.Проведен
| И ПередачаТоваровМеждуОрганизациями.интеркомСтатус = ЗНАЧЕНИЕ(Перечисление.интеркомСтатусыПередачиТоваровМеждуОрганизациями.Отправлено)
| И ПередачаТоваровМеждуОрганизациями.ОрганизацияПолучатель = &Организация";
Запрос.УстановитьПараметр("Организация", Организация);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при выполнении запроса метода get_docs";
Возврат;
КонецПопытки;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Тело = Новый Массив;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
СтруктураДокумента = Новый Структура;
СтруктураДокумента.Вставить("id", XMLСтрока(ВыборкаДетальныеЗаписи.Ссылка));
СтруктураДокумента.Вставить("number", ВыборкаДетальныеЗаписи.Номер);
СтруктураДокумента.Вставить("date", Формат(ВыборкаДетальныеЗаписи.Дата,"ДФ=dd.MM.yy"));
Тело.Добавить(СтруктураДокумента);
КонецЦикла;
КонецПроцедуры
Процедура ОбработатьМетод_cargo(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
Попытка
ПередачаСсылка = Документы.ПередачаТоваровМеждуОрганизациями.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.doc));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найден документ передачи по идентификатору " + СтруктураЗапроса.doc;
Возврат;
КонецПопытки;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МестаДляПередачиТоваров.НомерМеста КАК НомерМеста,
| МестаДляПередачиТоваров.Принято КАК Принято,
| МестаДляПередачиТоваров.ВремяПриемкиМеста КАК ВремяПриемкиМеста,
| МестаДляПередачиТоваров.ШтрихкодМеста КАК ШтрихкодМеста
|ИЗ
| РегистрСведений.МестаДляПередачиТоваров КАК МестаДляПередачиТоваров
|ГДЕ
| МестаДляПередачиТоваров.ПередачаТоваров = &ПередачаТоваров
|
|УПОРЯДОЧИТЬ ПО
| НомерМеста";
Запрос.УстановитьПараметр("ПередачаТоваров", ПередачаСсылка);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при выполнении запроса метода cargo";
Возврат;
КонецПопытки;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Тело = Новый Массив;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
СтруктураМеста = Новый Структура;
СтруктураМеста.Вставить("checked", ВыборкаДетальныеЗаписи.Принято);
СтруктураМеста.Вставить("number", ВыборкаДетальныеЗаписи.НомерМеста);
СтруктураМеста.Вставить("date", Формат(ВыборкаДетальныеЗаписи.ВремяПриемкиМеста,""));
СтруктураМеста.Вставить("barcode", ВыборкаДетальныеЗаписи.ШтрихкодМеста);
Тело.Добавить(СтруктураМеста);
КонецЦикла;
КонецПроцедуры
Процедура ОбработатьМетод_check_cargo(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ШтрихкодМеста = СтруктураЗапроса.body;
Попытка
ПередачаСсылка = Документы.ПередачаТоваровМеждуОрганизациями.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.doc));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найден документ передачи по идентификатору " + СтруктураЗапроса.doc;
Возврат;
КонецПопытки;
Попытка
ПользовательСсылка = Справочники.Пользователи.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.user));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найден пользователь по идентификатору " + СтруктураЗапроса.user;
Возврат;
КонецПопытки;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МестаДляПередачиТоваров.НомерМеста КАК НомерМеста
|ИЗ
| РегистрСведений.МестаДляПередачиТоваров КАК МестаДляПередачиТоваров
|ГДЕ
| МестаДляПередачиТоваров.ПередачаТоваров = &ПередачаТоваров
| И МестаДляПередачиТоваров.ШтрихкодМеста = &ШтрихкодМеста";
Запрос.УстановитьПараметр("ПередачаТоваров", ПередачаСсылка);
Запрос.УстановитьПараметр("ШтрихкодМеста", ШтрихкодМеста);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при запросе грузового места с штрихкодом " + ШтрихкодМеста;
Возврат;
КонецПопытки;
Если РезультатЗапроса.Пустой() Тогда
//Если не нашли место в текущем документе, пробуем общий поиск документа
Отказ = Истина;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МестаДляПередачиТоваров.Принято КАК Принято,
| МестаДляПередачиТоваров.ПередачаТоваров.Номер КАК Номер,
| МестаДляПередачиТоваров.ПередачаТоваров.Дата КАК Дата
|ИЗ
| РегистрСведений.МестаДляПередачиТоваров КАК МестаДляПередачиТоваров
|ГДЕ
| МестаДляПередачиТоваров.ШтрихкодМеста = &ШтрихкодМеста";
Запрос.УстановитьПараметр("ШтрихкодМеста", ШтрихкодМеста);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
ТекстОшибки = "Ошибка при повторном запросе грузового места с штрихкодом " + ШтрихкодМеста;
Возврат;
КонецПопытки;
Если РезультатЗапроса.Пустой() Тогда
ТекстОшибки = "Грузовое место с штрихкодом " + ШтрихкодМеста + " не найдено.";
Возврат;
КонецЕсли;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
ВыборкаДетальныеЗаписи.Следующий();
ТекстОшибки = "Грузовое место с штрихкодом " + ШтрихкодМеста + " отгружено другим документом (Передача товаров №" + ВыборкаДетальныеЗаписи.Номер + " от " + ВыборкаДетальныеЗаписи.Дата;
Возврат;
КонецЕсли;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
ВыборкаДетальныеЗаписи.Следующий();
НомерМеста = ВыборкаДетальныеЗаписи.НомерМеста;
НаборЗаписей = РегистрыСведений.МестаДляПередачиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ПередачаТоваров.Установить(ПередачаСсылка);
НаборЗаписей.Отбор.ШтрихкодМеста.Установить(ШтрихкодМеста);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ПередачаТоваров = ПередачаСсылка;
НоваяЗапись.ШтрихкодМеста = ШтрихкодМеста;
НоваяЗапись.Принято = Истина;
НоваяЗапись.ФизическоеЛицо = ПользовательСсылка.ФизическоеЛицо;
НоваяЗапись.ВремяПриемкиМеста = ТекущаяДата();
НоваяЗапись.НомерМеста = НомерМеста;
Тело = Новый Структура;
Тело.Вставить("date" ,Формат(НоваяЗапись.ВремяПриемкиМеста,""));
Попытка
НаборЗаписей.Записать();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при записи грузового места с штрихкодом " + ШтрихкодМеста;
Возврат;
КонецПопытки;
//Формируем сразу товарный состав места
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НоменклатураПоМестамДляПередачиТоваров.Номенклатура КАК Ссылка,
| НоменклатураПоМестамДляПередачиТоваров.КоличествоПринято КАК КоличествоПринято,
| НоменклатураПоМестамДляПередачиТоваров.Номенклатура.Наименование КАК Наименование
|ИЗ
| РегистрСведений.НоменклатураПоМестамДляПередачиТоваров КАК НоменклатураПоМестамДляПередачиТоваров
|ГДЕ
| НоменклатураПоМестамДляПередачиТоваров.ПередачаТоваров = &ПередачаТоваров
| И НоменклатураПоМестамДляПередачиТоваров.НомерМеста = &НомерМеста";
Запрос.УстановитьПараметр("НомерМеста", НомерМеста);
Запрос.УстановитьПараметр("ПередачаТоваров", ПередачаСсылка);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Тело.Вставить("goods" , Неопределено);
ТекстОшибки = "Ошибка при получении товарного состава грузового места " + ШтрихкодМеста;
Возврат;
КонецПопытки;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
МассивТоваров = Новый Массив;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
СтруктураТовара = Новый Структура;
СтруктураТовара.Вставить("id", XMLСтрока(ВыборкаДетальныеЗаписи.Ссылка));
СтруктураТовара.Вставить("name", ВыборкаДетальныеЗаписи.Наименование);
СтруктураТовара.Вставить("qnt", ВыборкаДетальныеЗаписи.КоличествоПринято);
МассивТоваров.Добавить(СтруктураТовара);
КонецЦикла;
Тело.Вставить("goods" , МассивТоваров);
КонецПроцедуры
Процедура ОбработатьМетод_check_good(СтруктураЗапроса, Тело, Отказ, ТекстОшибки);
ШтрихкодНоменклатуры = СтруктураЗапроса.body["barcode"];
НомерМеста = СтруктураЗапроса.body["cargo"];
Количество = СтруктураЗапроса.body["qnt"];
Попытка
ПередачаСсылка = Документы.ПередачаТоваровМеждуОрганизациями.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.doc));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найден документ передачи по идентификатору " + СтруктураЗапроса.doc;
Возврат;
КонецПопытки;
Попытка
ПользовательСсылка = Справочники.Пользователи.ПолучитьСсылку(Новый УникальныйИдентификатор(СтруктураЗапроса.user));
Исключение
Отказ = Истина;
ТекстОшибки = "Не найден пользователь по идентификатору " + СтруктураЗапроса.user;
Возврат;
КонецПопытки;
//Поиск номенклатуры по штрихкоду
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ШтрихкодыНоменклатуры.Номенклатура КАК Номенклатура
|ИЗ
| РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыНоменклатуры
|ГДЕ
| ШтрихкодыНоменклатуры.Штрихкод = &Штрихкод";
Запрос.УстановитьПараметр("Штрихкод", ШтрихкодНоменклатуры);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при запросе номенклатуры по штрихкоду " + ШтрихкодНоменклатуры;
Возврат;
КонецПопытки;
Если РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
ТекстОшибки = "Номенклатура с штрихкодом " + ШтрихкодНоменклатуры + " не найдена";
Возврат;
КонецЕсли;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
ВыборкаДетальныеЗаписи.Следующий();
Номенклатура = ВыборкаДетальныеЗаписи.Номенклатура;
//Запрос уже принятого количества
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НоменклатураПоМестамДляПередачиТоваров.КоличествоПринято КАК КоличествоПринято
|ИЗ
| РегистрСведений.НоменклатураПоМестамДляПередачиТоваров КАК НоменклатураПоМестамДляПередачиТоваров
|ГДЕ
| НоменклатураПоМестамДляПередачиТоваров.ПередачаТоваров = &ПередачаТоваров
| И НоменклатураПоМестамДляПередачиТоваров.НомерМеста = &НомерМеста
| И НоменклатураПоМестамДляПередачиТоваров.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("ПередачаТоваров", ПередачаСсылка);
Запрос.УстановитьПараметр("НомерМеста", НомерМеста);
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Попытка
РезультатЗапроса = Запрос.Выполнить();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при запросе принятого количества для " + Номенклатура;
Возврат;
КонецПопытки;
Если РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
ТекстОшибки = "Номенклатура " + Номенклатура + " не найдена";
Возврат;
КонецЕсли;
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
ВыборкаДетальныеЗаписи.Следующий();
КоличествоПринято = ВыборкаДетальныеЗаписи.КоличествоПринято;
НаборЗаписей = РегистрыСведений.НоменклатураПоМестамДляПередачиТоваров.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ПередачаТоваров.Установить(ПередачаСсылка);
НаборЗаписей.Отбор.НомерМеста.Установить(НомерМеста);
НаборЗаписей.Отбор.Номенклатура.Установить(Номенклатура);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ПередачаТоваров = ПередачаСсылка;
НоваяЗапись.НомерМеста = НомерМеста;
НоваяЗапись.Номенклатура = Номенклатура;
ОбщееКоличество = КоличествоПринято + Количество;
НоваяЗапись.КоличествоПринято = ОбщееКоличество;
НоваяЗапись.ФизическоеЛицо = ПользовательСсылка.ФизическоеЛицо;
Попытка
НаборЗаписей.Записать();
Исключение
Отказ = Истина;
ТекстОшибки = "Ошибка при проверке количества номенклатуры " + Номенклатура;
Возврат;
КонецПопытки;
Тело = Новый Структура;
Тело.Вставить("id" , XMLСтрока(Номенклатура));
Тело.Вставить("qnt" , ОбщееКоличество);
КонецПроцедуры
Некоторые моменты кода требуют уточнений.
Для хранения дополнительных настроек создан регистр "интеркомДополнительныеНастройкиПользователей".
Все пользователи базы на ТСД нам не нужны, отбор пользователей происходит из данного регистра по Организации и признаку "Пользователь ТСД". Идентификатор организации заносится в одноименную константу на мобильном устройстве и передается в запросе. Так же проверяется заполненность поля "Физическое лицо" у пользователя, так как это значение нам понадобится при записи факта приемки (кто принял и когда).
Полную конфигурацию приводить не буду, так как реализовано это все в Комплексной автоматизации.
Конфигурация мобильного приложения прилагается к статье.
Кроме того приведу текст двух общих модулей мобильного приложения и пример вызова метода сервиса из модуля формы.
Текст модуля "Взаимодействие" (Сервер/ВызовСервера)
//Выполняет метод сервиса
//СтруктураЗапроса:
// - ИмяМетода - строка.
// - ТелоЗапроса - Структура с передаваемыми в метод полями и значениями
// - ТелоОтвета - Структура, возвращенная в ответе метода сервиса
Функция ВыполнитьМетодPOST(ИмяМетода, ПараметрыМетода = "", Документ = "") Экспорт
СтруктураЗапроса = ПодготовитьСтруктуруЗапросаДляМетода(ИмяМетода, ПараметрыМетода, Документ);
ServerAddress = Повторно.ПолучитьКонстанту("ServerAddress");
AuthString = Повторно.ПолучитьКонстанту("AuthString");
PubPath = Повторно.ПолучитьКонстанту("PubPath");
//Проверяем настройки
Если НЕ (ЗначениеЗаполнено(PubPath)
И ЗначениеЗаполнено(AuthString)
И ЗначениеЗаполнено(ServerAddress)
И СтруктураЗапроса.ТелоЗапроса <> Неопределено) Тогда
Сообщить("Не заполнены обязательные настройки.");
Возврат СтруктураЗапроса.ТелоОтвета;
КонецЕсли;
//Запрос
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураЗапроса.ТелоЗапроса);
СтрокаJSON = ЗаписьJSON.Закрыть();
Заголовки = Новый Соответствие();
Заголовки.Вставить("Authorization", AuthString);
Заголовки.Вставить("Content-Type", "application/json");
HTTPСоединение = Новый HTTPСоединение(ServerAddress);
HTTPЗапрос = Новый HTTPЗапрос(PubPath, Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, "UTF-8");
//Пинг
Попытка
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Исключение
Сообщить("Ошибка при отправке запроса на сервер " + ServerAddress);
Возврат СтруктураЗапроса.ТелоОтвета;
КонецПопытки;
//Понг
Если HTTPОтвет.КодСостояния = 200 Тогда
ОтветСервиса = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ОтветСервиса);
Попытка
СтруктураЗапроса.ТелоОтвета = ПрочитатьJSON(ЧтениеJSON);
Если НЕ СтруктураЗапроса.ТелоОтвета.success Тогда
Сообщить(СтруктураЗапроса.ТелоОтвета.error);
СтруктураЗапроса.ТелоОтвета = Неопределено;
КонецЕсли;
Исключение
Сообщить("Метод " + ИмяМетода + " получил неверные данные от сервиса " + ServerAddress + PubPath);
СтруктураЗапроса.ТелоОтвета = Неопределено;
КонецПопытки;
Иначе
Сообщить("Метод " + ИмяМетода + " вернул код состояния " + Строка(HTTPОтвет.КодСостояния) + " от сервиса " + ServerAddress + PubPath);
КонецЕсли;
Возврат СтруктураЗапроса.ТелоОтвета;
КонецФункции
Функция ПодготовитьСтруктуруЗапросаДляМетода(ИмяМетода, ПараметрыМетода, Документ)
СтруктураЗапроса = Новый Структура;
ТелоЗапроса = Новый Структура;
ТелоОтвета = Неопределено;
Организация = Повторно.ПолучитьКонстанту("OrgId");
ТекущийПользователь = Повторно.ПолучитьКонстанту("ТекущийПользователь");
ИмяМетода = ИмяМетода;
Если НЕ (ЗначениеЗаполнено(Организация)) Тогда
ТелоЗапроса = Неопределено;
Иначе
ТелоЗапроса.Вставить("org", Организация);
ТелоЗапроса.Вставить("doc", Документ);
ТелоЗапроса.Вставить("user", ТекущийПользователь);
ТелоЗапроса.Вставить("method", ИмяМетода);
ТелоЗапроса.Вставить("body", ПараметрыМетода);
КонецЕсли;
СтруктураЗапроса.Вставить("ТелоЗапроса", ТелоЗапроса);
СтруктураЗапроса.Вставить("ТелоОтвета", ТелоОтвета);
Возврат СтруктураЗапроса;
КонецФункции
Функция ПолучитьХешПароля(Пароль) Экспорт
Хеш = Новый ХешированиеДанных(ХешФункция.SHA1);
Хеш.Добавить(Пароль);
Возврат Base64Строка(Хеш.ХешСумма);
КонецФункции
Текст модуля "Повторно" (Сервер/ВызовСервера/На время сеанса)
Функция ПолучитьКонстанту(ИмяКонстанты) Экспорт
Возврат Константы[ИмяКонстанты].Получить();
КонецФункции
Процедура ЗаписатьКонстанту(ИмяКонстанты, Значение) Экспорт
Константы[ИмяКонстанты].Установить(Значение);
КонецПроцедуры
Пример вызова метода сервиса для получения списка пользователей, выбора пользователя и авторизации.
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ЛокальныйОтказ = Ложь;
ПолучитьСписокПользователей(ЛокальныйОтказ);
ВыбратьЛогин(ЛокальныйОтказ);
КонецПроцедуры
&НаСервере
Процедура ПолучитьСписокПользователей(Отказ = Ложь)
Ответ = Взаимодействие.ВыполнитьМетодPOST("get_users");
Если Ответ <> Неопределено Тогда
СписокПользователей.Очистить();
Для Каждого Пользователь Из Ответ.body Цикл
СписокПользователей.Добавить(Пользователь.id, Пользователь.name);
КонецЦикла;
Иначе
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыбратьЛогин(Отказ)
Если Отказ Тогда Возврат; КонецЕсли;
ВыбранныйПользователь = СписокПользователей.ВыбратьЭлемент("Выберите пользователя", Повторно.ПолучитьКонстанту("ТекущийПользователь"));
Если ВыбранныйПользователь = Неопределено Тогда
ВыбратьЛогин(Отказ);
Иначе
ЭтаФорма.Заголовок = ВыбранныйПользователь.Представление;
Повторно.ЗаписатьКонстанту("ТекущийПользователь", ВыбранныйПользователь.Значение);
Если Повторно.ПолучитьКонстанту("ИспользоватьАвторизацию") Тогда
Пароль = "";
ВвестиСтроку(Пароль,"Введите пароль",15);
Пароль = Взаимодействие.ПолучитьХешПароля(Пароль);
Ответ = Взаимодействие.ВыполнитьМетодPOST("auth", Пароль);
Если Ответ <> Неопределено Тогда
//НачатьРаботу();
КонецЕсли;
Иначе
//НачатьРаботу();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Для того чтобы вызывать сервис, его, понятное дело, необходимо опубликовать на вэб-сервере. Как это делать, я описывать не буду, благо статей об этом уже написано и переписано очень много.
В начале работы с мобильным приложением необходимо заполнить обязательные константы:
ServerAddress (Адрес сервера) - это адрес сервера, где опубликован сервис.
AuthString (Строка авторизации) - строка HTTP аутентификации вида: Basic 0JDQtNC80LjQvdC40YHRgtGA0LDRgtC+0YA6. (Это пользователь 1С с именем "Администратор" и без пароля)
PubPath (Путь к публикации) - это путь к публикации http-сервиса вида: /ka/hs/invent/main.
OrgId (Идентификатор организации) - Уникальный идентификатор элемента справочника "Организации" (для разделения ТСД по организациям)
ПрефиксГрузовогоМеста - префикс грузового места :). (Чтобы при сканировании отделить штрихкоды грузовых мест от штрихкодов товаров)
Думаю, что к этому моменту у самого пытливого читателя возникнет резонный вопрос, а к чему вся эта статья?
Что нового и инновационного она в себе несет? Ведь это же еще одна из многих реализация самого обычного функционала!
Тут я бы хотел вернуться в начало и все-таки обозначить цели этой статьи.
Первая цель - это деньги. Вернее - стартмани... Все началось с того, что реализовать внешнее событие от встроенного сканера мне так и не удалось, используя БПО для мобилок от 1С. Поэтому, пока что считывание происходит в поле на форме. После поисков, я наткнулся на ряд интересных решений на нашем любимом Инфостарте. Но как оказалось, ничего скачать я не могу, потому что у меня даже 1 стартманюшки нет. Возможно эта статья окажется кому-то интересной и мне что-то перепадет.
Вторая цель - создать обсуждение и возможно совместными усилиями сможем решить задачу внешнего события.
И третья цель - нетленка :) Инфостартом я пользуюсь уже давно, таким образом решил сделать закладку на будущее самому себе.
А посему приглашаю в комменты на обсуждение сего творения. Приветствуется любая, даже неконструктивная критика.
Всем спасибо!
Обновление от 21.06.2022
В общем, мне удалось решить проблему отлова внешнего события от сканера с помощью внешней компоненты: //infostart.ru/public/1230245/. Спасибо большое Евгению за его труды.
Обновил мобильное приложение.
У нас используются две модели сканеров: Honeywell EDA50K и Zebra MC3300.
Для каждой из этих моделей используются разные методы инициализации компоненты. Поэтому в настройках мобильного приложения добавил выбор модели.