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

26.09.22

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

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

Скачать файлы

Наименование Файл Версия Размер
Конфигурация мобильного приложения приемки.
.cf 93,69Kb
6
.cf 0.0.0.1 93,69Kb 6 Скачать
Конфигурация мобильного приложения приемки (с обработкой внешнего события)
.cf 2,36Mb
16
.cf 0.0.0.2 2,36Mb 16 Скачать

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

Версия платформы 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С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Управленческий учет Платные (руб)

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

2880 руб.

03.12.2018    54610    137    102    

161

SALE! 25%

Что нам стоит бота построить? Нарисуем - будет жить! Графический конструктор телеграм-ботов/Telegram

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

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

13200 9900 руб.

27.12.2021    33278    80    157    

174

"Мобильный ТСД" - инвентаризация и сбор штрихкодов для iOS и Android

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

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

2000 руб.

22.04.2019    91943    511    186    

293

Магазин 15 - приемка товара по штрихкодам или инвентаризация в торговом зале

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

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

12950 руб.

30.05.2023    3388    2    0    

4

Работа с графикой в браузере (SimpleWEB). Векторный редактор

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

В SimpleWEB добавились средства для работы с графикой и отслеживание событий мыши, в онлайн редактор https://seditor.ru:1555/ добавился «Векторный редактор» на этом API. Теперь можно нарисовать схемы складов на ПК, сделать карты (*.sug-файлы) для мобильной платформы SimpleUI, выводить данные из 1С в графическом виде. Таким образом, API для работы с векторными файлами теперь есть и в веб- и в мобильной платформе, а также средства для создания и редактирования векторных файлов есть тоже в обеих платформах.

1 стартмани

20.03.2024    1471    0    informa1555    1    

39

Зачем нам 1С:Элемент

Мобильная разработка Языки и среды Бесплатно (free)

Flutter может быть использован с 1С:Предприятием для разработки кроссплатформенных мобильных приложений, обеспечивая единый интерфейс и функциональность на устройствах под управлением iOS и Android. Это позволяет создавать приложения с высокой производительностью благодаря использованию собственного движка рендеринга Flutter. Интеграция Flutter с 1С:Предприятием позволяет создавать мобильные приложения любого уровня сложности, интегрировать их в корпоративные информационные системы, а также реализовывать бизнес-логику

19.03.2024    6851    ROk_dev    56    

37

JavaScript в Simple

Мобильная разработка Бесплатно (free)

В SimpleUI и SimpleWEB, наряду с обработчиками на python и онлайн (1С и т.д.) добавляется интерпретатор JavaScript. В андроид платформе он скорее играет на поле python, т.к. является оффлайновым решением для самостоятельной обработки и расширяет аудиторию разработчиков для разработки самостоятельных решений. Дополнение к основной статье https://infostart.ru/1c/tools/1153616/

12.02.2024    1628    informa1555    0    

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

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

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

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