"Двойные штрихкода и история одной обработки"
Опубликовано Вс 08 Сентябрь 2013 в "Программирование"
Теги: Практика программирования 1С, Обработка, Запрос,
Преамбула
В какой то момент в базе встала проблема двойных штрихкодов. Причем ситация до того как на нее обратили внимание, приобрела катосторофический характер и имела полторы тысячи дублей штрихкодов (когда один штрихкод принадлежит нескольким товарам) и порядка 25ти тысяч дублей товаров (когда у одного товарам есть несколько штрихкодов). Что тому виной? На текущий момент уже сложно сказать. Возможно РИБ, когда одному и тому же товару присваивают штрихкод в разных базах. Возможно свою лепту внесли слияния нескольких баз с одинаковым товаром, но разными штрихкодами. Скорее всего все вместе + какой то еще фактор, который мы пока не можем найти. Слишком много вышло дублей, почти четверть базы. Так или иначе встала задача с этими штрихкодами что то сделать.
Постановка задачи.
Необходимо найти задублирововашиеся штрихкода и показить пользователю в удобном виде. Дать возможность что то сделать сразу с этими штрихкодами без необходимости лазить по справочникам и регистрам. Если говорить конкретно, то у пользователя должна быть возможность:
- Удалить все штрихкода у владельца, кроме выделенного.
- Удалить конкретный лишний штрихкод.
- Одним махом удалить все лишние дубли, оставив по одному на владельца.
- Удалить все штрихкода которые засветились как задублированные.
Приступим к реализации первой части.
Поиск лишних штрихкодов. Сам поиск достататочно банален: нужно воспользоваться функций КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СюдаУказатьПолеДляГруппировки). В самом простом случае, запрос будет выглядеть вот так:
ВЫБРАТЬ Штрихкоды.Штрихкод, КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Штрихкоды.Владелец) КАК Владелец ИЗ РегистрСведений.Штрихкоды КАК Штрихкоды СГРУППИРОВАТЬ ПО Штрихкоды.Штрихкод
Для того, что бы отфильтровать результаты запроса необходимо его обернуть во вложеный запрос и тогда уже можно накладывать условия на результат его работы. В целом нормально, но как то неудобно, для удобства наверно не помешает сгруппировать результаты по штрихкодам. В результате мы можем получить вот такой запрос. Вот результат его работы в консоли.
Этот вариант удобен для первого варианта поиска, сделать запрос для второго варианта по аналогии не должно составить труда. Запросы готовы, но не будет же пользователь смотреть на результат его работы из консоли. Здесь нам и поможет дерево значений. Смысл работы с деревом следующий: дерево содержит колекцию колонок и строк. Коллекция колонок не отличается от коллекции колонок в таблице значений и нас не интересует. Коллекция строк немного инетереснее, каждая строка ее может содержать такую же коллекцию строк, каждая строка которой... вообщем я думаю мысль понятна, таким образом и организуется иерархия. Используем обход результатов запроса по группировкам, для того что сформировать удобное дерево:
Выборка = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
ЭтаФорма.Заголовок = "Найдено " + Выборка.Количество();
Пока Выборка.Следующий() Цикл
НоваяСтрокаТП = ТабличноеПоле.Строки.Добавить();
НоваяСтрокаТП.Номенклатура = Выборка.Штрихкод;
ВыборкаШтрихКода = Выборка.Выбрать();
Пока ВыборкаШтрихКода.Следующий() Цикл
НоваяСтрокаВладелец = НоваяСтрокаТП.Строки.Добавить();
НоваяСтрокаВладелец.Номенклатура = ВыборкаШтрихКода.Владелец;
КонецЦикла;
КонецЦикла;
Как следствие мы можем получить вот такую форму:
Работа с регистром штрихкодов
Когда есть все нужные данные можно начинать работать с регистром штрихкодов. Так как у нас ищутся не только штрихкода с несколькими владельцами, но и владельцы с несколькими штрихкодами, то состав табличного поля может быть разным, это необходимо учитывать. Приступим к реализации п1 - Удалить все штрихкода кроме выделенного. Для этого подготовим данные для записи в регистр. Выделим значение отобора и штрихкод который нам надо оставить:
СтруктураВРегистр = Новый Структура("КлючОтбора, ЗначениеОтбора, ШтрихКод, Владелец");
Если ТипЗнч(СтрокаДерева.Номенклатура) = Тип("СправочникСсылка.Номенклатура")
ИЛИ ТипЗнч(СтрокаДерева.Номенклатура) = Тип("СправочникСсылка.ИнформационныеКарты") Тогда
СтруктураВРегистр.КлючОтбора = "Штрихкод";
СтруктураВРегистр.ЗначениеОтбора = СтрокаДерева.Родитель.Номенклатура;
СтруктураВРегистр.Штрихкод = СтрокаДерева.Родитель.Номенклатура;
СтруктураВРегистр.Владелец = СтрокаДерева.Номенклатура;
Иначе
СтруктураВРегистр.КлючОтбора = "Владелец";
СтруктураВРегистр.ЗначениеОтбора = СтрокаДерева.Родитель.Номенклатура;
СтруктураВРегистр.Штрихкод = СтрокаДерева.Номенклатура;
СтруктураВРегистр.Владелец = СтрокаДерева.Родитель.Номенклатура;
КонецЕсли;
Теперь надо удалить все "лишние" штрихкода кроме конкретного, того на который указал пользователь. Я решил этот вопрос просто: я очищаю набор по указанному отбору и добавляю нужный штрихкод. По моему это самый простой и быстрый способ. Вот код:
НаборЗаписей = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();
НаборЗаписей.Отбор[СтруктураСДанными.КлючОтбора].Установить(СтруктураСДанными.ЗначениеОтбора);
НаборЗаписей.Записать();
НоваяЗаписьНабора = НаборЗаписей.Добавить();
НоваяЗаписьНабора.Владелец = СтруктураСДанными.Владелец;
НоваяЗаписьНабора.ЕдиницаИзмерения = СтруктураСДанными.Владелец.ЕдиницаХраненияОстатков;
НоваяЗаписьНабора.ТипШтрихкода = ПланыВидовХарактеристик.ТипыШтрихкодов.EAN13;
НоваяЗаписьНабора.Штрихкод = СтруктураСДанными.ШтрихКод;
НоваяЗаписьНабора.Качество = Справочники.Качество.Новый;
НаборЗаписей.Записать();
Перебирая строки дерева значений можно реализовать и п.3. Мы же идем дальше и приступаем к п.2. Для этих целей я использовал менеджер записи, в целом тут все просто до безобразия:
Если ТипЗнч(ЭлементыФормы.ТабличноеПоле.ТекущиеДанные.Номенклатура) = Тип("СправочникСсылка.Номенклатура")
ИЛИ ТипЗнч(ЭлементыФормы.ТабличноеПоле.ТекущиеДанные.Номенклатура) = Тип("СправочникСсылка.ИнформационныеКарты") Тогда
Штрихкод = ЭлементыФормы.ТабличноеПоле.ТекущаяСтрока.Родитель.Номенклатура;
Владелец = ЭлементыФормы.ТабличноеПоле.ТекущиеДанные.Номенклатура;
Иначе
Штрихкод = ЭлементыФормы.ТабличноеПоле.ТекущиеДанные.Номенклатура;
Владелец = ЭлементыФормы.ТабличноеПоле.ТекущаяСтрока.Родитель.Номенклатура;
КонецЕсли;
МенеджерЗаписи = РегистрыСведений.Штрихкоды.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Штрихкод = Штрихкод;
МенеджерЗаписи.Владелец = Владелец;
МенеджерЗаписи.ТипШтрихкода = ПланыВидовХарактеристик.ТипыШтрихкодов.EAN13;
МенеджерЗаписи.ЕдиницаИзмерения = Владелец.ЕдиницаХраненияОстатков;
МенеджерЗаписи.Качество = Справочники.Качество.Новый;
МенеджерЗаписи.Прочитать();
МенеджерЗаписи.Удалить();
Остался последний самый простой пункт. Я думаю тут даже код не нужен. Все и так просто. Делаем отбор в наборе и записываем не читая. Вот такая получилась обработка. Почти весь нужный код для работы обработки в этой статье есть. За бортом осталась косметика, украшательства и тд, то, что каждый настраивает по своему вкусу, но если все таки у вас не вышло собрать обработку, то обработку можно скачать на инфостарте.