Добавление штрих-кодов в Рознице
Клиенту понадобился удобный инструмент для назначения штрих-кодов для характеристик товаров. Дело в том, что у разных товаров в ассортименте был одинаковый код, нужно было назначить новые внутренние штрих-кода на каждую позицию из ассортимента, нанести потом их на этикетку, чтобы товар продавался по каждой характеристике отдельно.
Решил, что самое удобное место, чтобы назначать штрих-кода — это обработка печати этикеток и ценников, потому что там можно заполнять остатками товаров, подбирать вручную и заполнять строки обработки из документа.
Добавил кнопку «Назначить ШК» в обработку печати этикеток и ценников:
При ее нажатии открываю дополнительную обработку, куда передаю только выбранные галочками товары:
&НаКлиенте
Процедура дор_дор_НазначитьШтрихкодаПосле(Команда)
ПараметрыОбработки = Новый Структура();
ПараметрыОбработки.Вставить(«Коллекция», Новый Массив());
Для Каждого Строка ИЗ Объект.Товары Цикл
Если НЕ Строка.Выбран Тогда
Продолжить;
КонецЕсли;
ПараметрыОбработки.Коллекция.Добавить(
Новый Структура(«Номенклатура, Характеристика», Строка.Номенклатура, Строка.Характеристика)
);
КонецЦикла;
ОткрытьФорму(«Обработка.дор_НазначитьШК.Форма.Форма», ПараметрыОбработки);
КонецПроцедуры
Решил использовать галочки, т.к. в печати ценников используются именно галочки для выделения строк к печати, пусть такая же логика будет и в строках для обработки.
В форме обработки справочно вывожу текущий префикс внутреннего штрих-кода штучного товара. Пользователь проверяет, что штрих-кода он выбрал правильно, выбирает вид обработки и запускает обработку:
Штрих-кода я вычисляю отдельными запросами. Это не очень производительно, но и не очень критично.
Как назначать штрих-код, сразу не нашел. В форме характеристики и номенклатуры кнопки не нашел соответствующей кнопки. Пришлось запустить поиск по префиксу внутреннего ШК:
В итоге была найдена функция СформироватьШтрихкод в модуле ПодключаемоеОборудованиеРТВызовСервера. Внимание! Она работает только для EAN13!
Чтобы не заполнять каждый раз табличную часть ценников при отладке, я просто нажимал Заполнить. Думало секунд 30, но зато не нужно было добавлять вручную.
Чтобы дважды не получать список штрих-кодов, сериализовал их в строку, получил сообщение «Ошибка формата потока»:
Оказывается, по ошибке для хранения сериализированной строки использовал строку длиной 10 (по умолчанию), расширил до нуля — заработало.
Отладка на сервере не работала. Поэтому очищать наборы записей было рискованно без проверки — можно было бы очистить весь регистр штрих-кодво. Пришлось написать код, который сообщал о количестве удаляемых записей:
НЗ.Прочитать();
//НЗ.Записать();
Сообщить(Символы.Таб + «Старых записей: » + НЗ.Количество());
Сообщить(Символы.Таб + «Удален ШК: » + ШтрихКод);
После этого последовательно запустил и проверил протокол для разных операций:
Убедился, что все отрабатывает корректно, как задумано.
Потом еще была ошибка, что «Тип штрихкода» — это не перечисление «Типы штрихкодов» а одноименное ПВХ. Хотя и перечисление в конфигурации тоже имеется, что затруднило диагностику.
Также после назначения ШК нужно их перезаполнять, иначе может быть такая ситуация:
Т.е. если нажать несколько раз «Назначить ШК», обработка не узнает, что новые ШК уже созданы. Поэтому нужно обновлять колонку «Штрих-коды» после назначения ШК.
Время факт: 2 час. Розница 2.3.4.33
Итоговый код обработки:
&НаСервере
Процедура НазначитьШКНаСервере()
Для Каждого Строка ИЗ Объект.Состав Цикл
ШтрихКоды = ЗначениеИзСтрокиВнутр(Строка.ШтрихКодыСтрокой);
ВнешниеШК = Новый Массив();
ВнутренниеШК = Новый Массив();
ЕстьВнутренний = ложь;
Для Каждого ШтрихКод ИЗ ШтрихКоды Цикл
Если Лев(ШтрихКод, СтрДлина(ПрефиксШК)) = ПрефиксШК Тогда
ЕстьВнутренний = истина;
ВнутренниеШК.Добавить(ШтрихКод);
Иначе
ВнешниеШК.Добавить(ШтрихКод);
КонецЕсли;
КонецЦикла;
ЕстьШК = ШтрихКоды.Количество() > 0;
//Обработки по умолчанию
ЗаписатьНовыйШК = ложь;
ОчищатьВнешниеШК = ложь;
//Определяем вид обработки и что нужно делать
Если ВидОбработки = «ТолькоВнутренний» Тогда
Если НЕ ЕстьВнутренний Тогда
ЗаписатьНовыйШК = истина;
КонецЕсли;
ОчищатьВнешниеШК = истина;
ИначеЕсли ВидОбработки = «ДобавлятьВнутренний» Тогда
Если НЕ ЕстьВнутренний Тогда
ЗаписатьНовыйШК = истина;
КонецЕсли;
ИначеЕсли ВидОбработки = «» Тогда
Если НЕ ЕстьШК Тогда
ЗаписатьНовыйШК = истина;
КонецЕсли;
КонецЕсли;
Сообщить(«Номенклатура: » + Строка.Номенклатура + » хар-ка: » + Строка.Характеристика);
Если ОчищатьВнешниеШК Тогда
Для Каждого ШтрихКод ИЗ ВнешниеШК Цикл
НЗ = РегистрыСведений.ШтрихКоды.СоздатьНаборЗаписей();
НЗ.Отбор.Штрихкод.Значение = ШтрихКод;
НЗ.Отбор.Штрихкод.Использование = истина;
НЗ.Отбор.Владелец.Значение = Строка.Номенклатура;
НЗ.Отбор.Владелец.Использование = истина;
НЗ.Отбор.Характеристика.Значение = Строка.Характеристика;
НЗ.Отбор.Характеристика.Использование = истина;
//НЗ.Прочитать();
НЗ.Записать();
//Сообщить(Символы.Таб + «Старых записей: » + НЗ.Количество());
Сообщить(Символы.Таб + «Удален ШК: » + ШтрихКод);
КонецЦикла;
КонецЕсли;
Если ЗаписатьНовыйШК Тогда
ШтрихКод = ПодключаемоеОборудованиеРТВызовСервера.СформироватьШтрихкод(ПрефиксШК);
МЗ = РегистрыСведений.ШтрихКоды.СоздатьМенеджерЗаписи();
МЗ.Штрихкод = ШтрихКод;
МЗ.Владелец = Строка.Номенклатура;
МЗ.Характеристика = Строка.Характеристика;
МЗ.ТипШтрихкода = ПланыВидовХарактеристик.ТипыШтрихкодов.EAN13;
МЗ.Записать();
Сообщить(Символы.Таб + «Добавлен ШК: » + ШтрихКод);
КонецЕсли;
КонецЦикла;
ОбновитьШтрихКоды();
КонецПроцедуры
&НаКлиенте
Процедура НазначитьШК(Команда)
НазначитьШКНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
УстановитьПривилегированныйРежим(истина);
ПрефиксШК = Константы.ПрефиксВнутреннегоШтрихкодаШтучногоТовара.Получить();
Объект.Состав.Очистить();
Для Каждого Строка ИЗ Параметры.Коллекция Цикл
НСтр = Объект.Состав.Добавить();
НСтр.Номенклатура = Строка.Номенклатура;
НСтр.Характеристика = Строка.Характеристика;
КонецЦикла;
ОбновитьШтрихКоды();
КонецПроцедуры
&НаСервере
Процедура ОбновитьШтрихКоды()
Для Каждого Строка ИЗ Объект.Состав Цикл
СтруктураШК = ПолучитьШтрихКоды(Строка.Номенклатура, Строка.Характеристика);
Строка.ШтрихКоды = СтруктураШК.ШтрихКоды;
Строка.ШтрихКодыСтрокой = СтруктураШК.ШтрихКодыСтрокой;
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция ПолучитьШтрихКоды(Номенклатура, Характеристика)
Р = Новый Структура(«ШтрихКоды,ШтрихКодыСтрокой»);
Запрос = Новый Запрос(
«ВЫБРАТЬ
| Т.Штрихкод КАК Штрихкод,
| Т.Владелец КАК Номенклатура,
| Т.Характеристика КАК Характеристика
|ИЗ
| РегистрСведений.Штрихкоды КАК Т
|ГДЕ
| Т.Владелец = &Номенклатура
| И Т.Характеристика = &Характеристика
| И Т.Владелец ССЫЛКА Справочник.Номенклатура»);
Запрос.УстановитьПараметр(«Номенклатура», Номенклатура);
Запрос.УстановитьПараметр(«Характеристика», Характеристика);
ТЗ = Запрос.Выполнить().Выгрузить();
Р.ШтрихКоды = «»;
Для Каждого Строка ИЗ ТЗ Цикл
Р.ШтрихКоды = Р.ШтрихКоды + ?(Р.ШтрихКоды = «», «», «,») + Строка.ШтрихКод;
КонецЦикла;
Р.ШтрихКодыСтрокой = ЗначениеВСтрокуВнутр(ТЗ.ВыгрузитьКолонку(«ШтрихКод»));
//Сообщить(Р.ШтрихКодыСтрокой);
Возврат Р;
КонецФункции
о, вложенный в цикл запрос — классика плохого кодирования. кстати, это не ты ли писал когда-то, что твой код в облако не приняли из-за таких запросов?
Не стоит фанатично подходить к таким запретам. Если скорость разработки важнее производительности, можно использовать запросы в цикле. Без проблем.
ты так пишешь, как будто вынести запрос из цикла — это какой-то rocket science
не вижу ничего криминального в запросе в цикле