Взаимодействие мобильного приложения 1С и центральной информационной базы с использованием http-сервиса

26.09.22

Разработка - Мобильная разработка

Видимо, настала пора и мне написать статью на Инфостарте. Данная статья призвана помочь программистам 1С, которые занимаются разработкой мобильных приложений на мобильной платформе 1С и перед которыми стоит задача обеспечить взаимодействие мобильного приложения и центральной базы 1С.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Конфигурация мобильного приложения приемки.
.cf 93,69Kb ver:0.0.0.1
6
6 Скачать (1 SM) Купить за 1 850 руб.
Конфигурация мобильного приложения приемки (с обработкой внешнего события)
.cf 2,36Mb ver:0.0.0.2
16
16 Скачать (2 SM) Купить за 2 150 руб.

Описание версий платформ и другого ПО:

Версия платформы 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.

Для каждой из этих моделей используются разные методы инициализации компоненты. Поэтому в настройках мобильного приложения добавил выбор модели.

 

См. также

Мобильная разработка Мессенджеры и боты Платформа 1С v8.3 1С:Конвертация данных Платные (руб)

Теперь создать telegram-бота - элементарно. Достаточно просто нарисовать блок-схему телеграм-бота, и он сразу заработает. Это возможно при использовании Графического конструктора телеграм-ботов. Это единственный конструктор ботов для telegram, чье качество и функционал подтверждены фирмой 1С, есть сертификат 1С:Совместимо. Расширение в интерактивном режиме, с помощью блок-схем, позволяет с минимальными трудозатратами создать телеграм-ботов в любой конфигурации, работающей на платформе «1С:Предприятие 8.3».

13200 руб.

27.12.2021    38193    108    161    

201

Мобильная разработка Сканер штрих-кода Терминал сбора данных Управляемые формы Мобильная платформа 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Управленческий учет Платные (руб)

Сбор заказов, инвентаризация, проверка ценников, просмотр полной информации об остатках и ценах со смартфона Онлайн - все это содержит в себе решение 1С "Штрихкод-информер" (штрих-код чекер). Отправка данных со смартфона выполняется либо напрямую в открытую форму документа, отсканировав QR-код, либо в общую корзину учетной системы, не подходя к компьютеру. Кассир или оператор сможет просмотреть список присланных данных и загрузить в любую форму, поддерживающую работу с ТСД. Для работы с мобильным приложением требуется опубликовать HTTP-сервис из поставляемого расширения.

3000 руб.

03.12.2018    59288    192    103    

172

Сканер штрих-кода Терминал сбора данных Мобильная разработка Монитор заказов Оптовая торговля Розничная торговля Ценообразование, анализ цен Программист Пользователь Платформа 1С v8.3 Мобильная платформа 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Управленческий учет Платные (руб)

Простой мобильный ТСД (терминал сбора данных) сканер для 1С для смартфонов на iOS и Android, не требующий сложных настроек и установки дополнительных программ. Обмен между Вашей 1С и мобильным приложением осуществляется через облачный сервис и расширение конфигурации. Работает с конфигурациями УТ 11, ERP, КА2, Розница 2, Розница 3, УНФ 1.6, УНФ 3.0. Полнофункциональный демо-доступ для своей конфигурации можно запросить в настройках мобильного приложения - все необходимое придет на почту автоматически.

2000 руб.

22.04.2019    97216    586    189    

321

Логистика, склад и ТМЦ Сканер штрих-кода Терминал сбора данных Мобильная разработка Платформа 1С v8.3 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Бухгалтерский учет Управленческий учет Платные (руб)

Вашему вниманию предлагается специализированное программное обеспечение для терминалов сбора данных со встроенным сканером штрихкода. Предназначено для цифровизации всех товароучетных операций на любых складах, в том числе с адресным хранением различной сложности. Позволяет ускорить и упростить работу кладовщиков, а также снизить вероятность ошибок при работе, обусловленных человеческим фактором.

3450 руб.

28.04.2023    9468    15    0    

9

Мобильная разработка Платформа 1С v8.3 Конфигурации 1cv8 Финансовые услуги, инвестиции Управленческий учет Платные (руб)

Мобильное приложение и конфигурация 1С для автоматической торговли на бирже через API Тинькофф банка. Достаточно задать настройки, нажать «Пуск», и робот сам торгует ежедневно.

7000 руб.

25.05.2022    4643    1    0    

6

Мобильная разработка WEB-интеграция Программист Мобильная платформа Абонемент ($m)

Экспериментальный релиз и простенький скрипт к нему закрывает потребности в любых видах синхронизации между устройствами Simple и между Simple и бек-системами (например 1С). По сути – это очень простой python-скрипт, который можно запустить на доступной машине, сервере или VPS и он будет связывать клиентские устройства между собой и с 1С или другими бек-системами. В самой платформе появилось для этого множество доработок для поддержки стабильного постоянного соединения, докачки больших файлов и работе в фоне. Дополнение к основной статье https://infostart.ru/1c/tools/1153616/

1 стартмани

23.08.2024    1215    6    informa1555    1    

13

Мобильная разработка Мобильная платформа Абонемент ($m)

В этом релизе собрано много нового из области интерфейса, связи, хранения и важные новые способы управления. Дополнение к основной статье https://infostart.ru/1c/tools/1153616/

1 стартмани

25.06.2024    2605    29    informa1555    0    

33
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. suepifanov 1071 07.06.22 13:54 Сейчас в теме
Скачал вам на стартмани)
А логирования ошибок вообще не делали?
4. 3dice 26 09.06.22 11:38 Сейчас в теме
(1) Обычно, конечно, делаю, примерно так:

Процедура ЗаписьПодробнойОшибкиВЖурнал(ИнформацияОбОшибке, Данные = Неопределено)
	
	МассивСообщенийВЖурнал = Новый Массив;

	МассивСообщенийВЖурнал.Добавить(ИнформацияОбОшибке.ИмяМодуля + ", в строке "+Строка(ИнформацияОбОшибке.НомерСтроки));
	МассивСообщенийВЖурнал.Добавить(ИнформацияОбОшибке.ИсходнаяСтрока);
	МассивСообщенийВЖурнал.Добавить(ИнформацияОбОшибке.Описание);
	
	СтрокаСообщенияДляЖурнала = СтрСоединить(МассивСообщенийВЖурнал, Символы.ПС);

	ЗаписьЖурналаРегистрации("HTTP-сервис: обмен с УТП",
							УровеньЖурналаРегистрации.Ошибка,
							Метаданные.ПланыОбмена.ОбменСУТП,
							Данные,
							СтрокаСообщенияДляЖурнала);
КонецПроцедуры
Показать
2. malikov_pro 1324 07.06.22 14:38 Сейчас в теме
Если есть желание реализовать на 1С https://github.com/gothinkster/realworld, можем скооперироваться
HTTP запросы лучше оборачивать в https://github.com/vbondarevsky/Connector
3. malikov_pro 1324 07.06.22 14:47 Сейчас в теме
(1) как хотите организовать логирование? Cам для HTTP запросов форматирую под sentry (статья в процессе).
5. eeeio 126 19.07.22 02:42 Сейчас в теме
Вы для сканеров случайно не делали воспроизведение звуков (при сканировании, например)?
6. 3dice 26 19.07.22 14:01 Сейчас в теме
(5) Не совсем понял. Встроенный в ТСД сканер и так пищит при сканировании.
7. eeeio 126 19.07.22 15:04 Сейчас в теме
(6) я неверно сформулировал. вопрос про ТСД - нужно звук удачного/неудачного распознавания выводить. Но сборка приложения почему-то не требует разрешений на вывод звука (хотя галочки стоят) и потом приложение жалуется, что доступа на воспроизведение звуков нет. Хочу найти конфу, которая собирается успешно и умеет нормально сигналить.
8. 3dice 26 19.07.22 23:00 Сейчас в теме
(7) Насколько я понял, необходимо при обработке полученного штрих-кода, если он не найден в базе данных, выводить какой-то специфический звуковой сигнал. Я правильно понял? Я такого не пробовал, но обычно хватает какого-то диалогового окна о том что штрих-код не найден. Но думаю не проблема прикрутить воспроизведение звука.
Оставьте свое сообщение