В процессе сопровождения торговых решений на платформе 1С (таких как «1С:Розница» или «1С:Управление торговлей») администраторы и разработчики часто сталкиваются с необходимостью наведения порядка в справочниках и регистрах. Одной из типичных задач является перекодирование весового товара (PLU-кодов). Попытка решить эту задачу простым перебором записей регистра в лоб часто приводит к ошибке: «Значение кода не уникально и запись с такими параметрами уже существует». Даже если в конфигураторе разрядность кода увеличена, система может выдавать ошибку на старых лимитах (например, на значении 99 999).
В этой статье мы подробно разберем, почему возникает данная ошибка, как правильно работать с измерениями регистров сведений и какие безопасные программные методы существуют для массового изменения ключевых полей.
Давайте проанализируем ситуацию, описанную автором темы. Он пытается записать новые шестизначные коды, начинающиеся с пятерки (например, 500000, 500001), но платформа упорно сообщает об ошибке уникальности на коде 99 999. При этом в конфигураторе длина кода весового товара расширена до 10 символов.
Здесь кроются сразу две проблемы:
500000) до максимально возможного пятизначного — 99 999. При следующей итерации цикла следующий код тоже превратится в 99 999, что вызовет конфликт уникальности ключа записи.КодыВесовогоТовара поле Код является измерением. Измерения составляют уникальный ключ записи. Платформа 1С устроена так, что мы не можем просто прочитать набор записей, поменять значение измерения в цикле и записать набор обратно. Для платформы изменение измерения эквивалентно созданию новой ключевой записи, при этом старая запись никуда не исчезает, вызывая конфликты при записи набора.Перед тем как приступать к программному изменению кодов, обязательно зайдите в настройки параметров учета вашей информационной базы и увеличьте параметр «Длина кода весового товара» до нужного значения (в нашем случае — 6 или более знаков).
Давайте рассмотрим первый правильный методологический подход. Поскольку код является измерением регистра, для его изменения нам необходимо сначала удалить старую запись с прежним кодом, а затем создать новую запись с новым кодом. Чтобы гарантировать целостность данных и не потерять информацию в случае сбоя, все действия обязательно нужно выполнять в единой транзакции.
Разберем по шагам алгоритм с использованием объекта РегистрСведенийМенеджерЗаписи:
НачатьТранзакцию();
Попытка
// Выбираем все текущие записи регистра сведений
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КодыВесовогоТовара.Номенклатура КАК Номенклатура,
| КодыВесовогоТовара.Код КАК Код,
| КодыВесовогоТовара.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| КодыВесовогоТовара.Качество КАК Качество
|ИЗ
| РегистрСведений.КодыВесовогоТовара КАК КодыВесовогоТовара";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
НовыйНомер = 500000;
Пока Выборка.Следующий() Цикл
// 1. Удаляем старую запись
МенеджерЗаписиСтарый = РегистрыСведений.КодыВесовогоТовара.СоздатьМенеджерЗаписи();
МенеджерЗаписиСтарый.Код = Выборка.Код; // Передаем старое измерение
МенеджерЗаписиСтарый.Прочитать();
Если МенеджерЗаписиСтарый.Выбран() Тогда
// Сохраняем значения ресурсов во временные переменные
ТекущаяНоменклатура = МенеджерЗаписиСтарый.Номенклатура;
ТекущаяХарактеристика = МенеджерЗаписиСтарый.ХарактеристикаНоменклатуры;
ТекущееКачество = МенеджерЗаписиСтарый.Качество;
// Удаляем старую ключевую запись
МенеджерЗаписиСтарый.Удалить();
Иначе
Продолжить;
КонецЕсли;
// 2. Создаем новую запись с новым измерением
МенеджерЗаписиНовый = РегистрыСведений.КодыВесовогоТовара.СоздатьМенеджерЗаписи();
МенеджерЗаписиНовый.Код = НовыйНомер; // Устанавливаем новое измерение
// Заполняем ресурсы сохраненными данными
МенеджерЗаписиНовый.Номенклатура = ТекущаяНоменклатура;
МенеджерЗаписиНовый.ХарактеристикаНоменклатуры = ТекущаяХарактеристика;
МенеджерЗаписиНовый.Качество = ТекущееКачество;
// Записываем новую строку
МенеджерЗаписиНовый.Записать();
НовыйНомер = НовыйНомер + 1;
КонецЦикла;
ЗафиксироватьТранзакцию();
Сообщить("Перекодирование весовых товаров успешно завершено!");
Исключение
ОтменитьТранзакцию();
Сообщить("Произошла ошибка при изменении кодов: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
Этот метод гарантирует, что если на каком-то шаге (например, на 5000-й записи) произойдет системная ошибка, транзакция полностью откатится, и все коды весовых товаров вернутся в исходное состояние. База данных не останется в разрушенном или частично измененном виде.
Если в вашем регистре содержатся десятки тысяч записей, построчный метод через МенеджерЗаписи может работать достаточно медленно из-за большого количества обращений к базе данных. В этом случае мы можем применить пакетный метод: выгрузить все записи в Таблицу Значений (ТЗ), модифицировать их в памяти компьютера, полностью очистить регистр одним движением и загрузить новые данные.
Важное предупреждение: Метод очистки регистра с последующей записью несет в себе риски. Если очистка пройдет успешно, а на этапе записи новых данных возникнет непредвиденная ошибка (например, аварийно завершится служба СУБД или пропадет электропитание сервера), регистр останется пустым. Поэтому данный код также критически важно выполнять внутри транзакции и блока обработки исключений.
Давайте проанализируем и реализуем этот алгоритм:
НачатьТранзакцию();
Попытка
// Шаг 1. Создаем набор записей для чтения всей информации из регистра
НаборЗаписей = РегистрыСведений.КодыВесовогоТовара.СоздатьНаборЗаписей();
НаборЗаписей.Прочитать();
// Шаг 2. Выгружаем данные в Таблицу Значений
ТаблицаДанных = НаборЗаписей.Выгрузить();
// Шаг 3. Модифицируем измерения в Таблице Значений
НовыйНомер = 500000;
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
СтрокаДанных.Код = НовыйНомер;
НовыйНомер = НовыйНомер + 1;
КонецЦикла;
// Шаг 4. Полностью очищаем регистр сведений
НаборОчистки = РегистрыСведений.КодыВесовогоТовара.СоздатьНаборЗаписей();
// Запись пустого набора без отборов очищает всю таблицу регистра в БД
НаборОчистки.Записать();
// Шаг 5. Загружаем измененную таблицу данных обратно в регистр
НаборЗагрузки = РегистрыСведений.КодыВесовогоТовара.СоздатьНаборЗаписей();
НаборЗагрузки.Загрузить(ТаблицаДанных);
НаборЗагрузки.Записать();
ЗафиксироватьТранзакцию();
Сообщить("Данные успешно обновлены пакетным методом!");
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка выполнения пакета. Регистр восстановлен в исходное состояние. Описание: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
Просто обновить цифры в базе данных 1С недостаточно для восстановления корректной работы розничного магазина. Весовые товары имеют тесную связь с торговым оборудованием. Давайте разберем, какие шаги обязательно нужно выполнить после проведения групповой обработки кодов:
21XXXXXYYYYYК, где 21 — префикс весового товара, XXXXX — пятизначный код PLU, а YYYYY — вес товара). Если вы изменили разрядность кода с 5 до 6 знаков (сделав его 500000), вам необходимо проверить и перенастроить правила (шаблоны) формирования весовых штрихкодов в настройках программы. В противном случае кассовые аппараты и сканеры не смогут корректно декодировать считанный штрихкод при продаже на кассе.