diff --git a/CHANGELOG.md b/CHANGELOG.md index 6795ccc..652297b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ --- +## 1.3.1.70 (2026-08-17) + +### РК_ПроверкаСерий — проверка и исправление серий (#14) + +- Обработка **Проверка серий**: форма поиска проблем в `СерииНоменклатуры`. +- Учитываются настройки вида (`ИспользоватьНомерСерии`, `ИспользоватьСрокГодностиСерии`). +- Предложения: номер и срок из наименования; наименование «до dd.MM.yy» для серий без номера. +- Режим тест (без записи), исправление отмеченных строк. + ## 1.3.1.69 (2026-08-17) ### РК_ЗагрузкаОстатков — исправление кнопки «Заполнить справочники отбора» (#12) diff --git a/VERSION b/VERSION index d33a99f..3e96bb9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.1.69 +1.3.1.70 diff --git a/src/ConfigDumpInfo.xml b/src/ConfigDumpInfo.xml index 9aae52f..611e878 100644 --- a/src/ConfigDumpInfo.xml +++ b/src/ConfigDumpInfo.xml @@ -200,7 +200,25 @@ - + + + + + + + + + + + + + + + + + + + diff --git a/src/DataProcessors/РК_ПроверкаСерий.xml b/src/DataProcessors/РК_ПроверкаСерий.xml index 8dad093..e34ed80 100644 --- a/src/DataProcessors/РК_ПроверкаСерий.xml +++ b/src/DataProcessors/РК_ПроверкаСерий.xml @@ -21,12 +21,577 @@ true - + DataProcessor.РК_ПроверкаСерий.Form.Форма false - + + + + РежимТест + + + ru + Режим тест (без записи) + + + + + xs:boolean + + false + + + + + ru + Если включено — только показать, что будет исправлено, без записи в базу + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + + f14e0003-0003-4001-8000-000000000003 + f14e0003-0003-4002-8000-000000000003 + + + f14e0003-0003-4003-8000-000000000003 + f14e0003-0003-4004-8000-000000000003 + + + + ПроблемныеСерии + + + ru + Проблемные серии + + + + + DontCheck + + + + + Отметка + + + ru + Отметка + + + + + xs:boolean + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Серия + + + ru + Серия + + + + + cfg:CatalogRef.СерииНоменклатуры + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Номенклатура + + + ru + Номенклатура + + + + + cfg:CatalogRef.Номенклатура + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + ВидНоменклатуры + + + ru + Вид номенклатуры + + + + + cfg:CatalogRef.ВидыНоменклатуры + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Наименование + + + ru + Наименование + + + + + xs:string + + 150 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Номер + + + ru + Номер + + + + + xs:string + + 200 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + ГоденДо + + + ru + Годен до + + + + + xs:dateTime + + DateTime + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Проблема + + + ru + Проблема + + + + + xs:string + + 100 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + ПредложенныйНомер + + + ru + Предложенный номер + + + + + xs:string + + 200 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + ПредложенныйГоденДо + + + ru + Предложенный годен до + + + + + xs:dateTime + + DateTime + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + ПредложенноеНаименование + + + ru + Предложенное наименование + + + + + xs:string + + 150 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Исправлено + + + ru + Исправлено + + + + + xs:boolean + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Комментарий + + + ru + Комментарий + + + + + xs:string + + 0 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + +
Форма
+
- \ No newline at end of file + diff --git a/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма.xml b/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма.xml new file mode 100644 index 0000000..cd8c645 --- /dev/null +++ b/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма.xml @@ -0,0 +1,22 @@ + + +
+ + Форма + + + ru + Форма + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + + +
+
diff --git a/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма/Ext/Form.xml b/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма/Ext/Form.xml new file mode 100644 index 0000000..48f07dd --- /dev/null +++ b/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма/Ext/Form.xml @@ -0,0 +1,273 @@ + +
+ + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Проверка и исправление серий номенклатуры</v8:content> + </v8:item> + + + + + + + + + ПриСозданииНаСервере + + + + Объект.РежимТест + Right + + + ru + Без записи в базу — только показать результат исправления + + + ShowRight + Auto + + + + + List + false + false + false + false + false + Объект.ПроблемныеСерии + + + false + + + + + + + + + + + + + + + ПроблемныеСерии + SearchStringRepresentation + + + + + + + ПроблемныеСерии + ViewStatusRepresentation + + + + + + + ПроблемныеСерии + SearchControl + + + + + + + Объект.ПроблемныеСерии.Отметка + EnterOnInput + Auto + + + + + Объект.ПроблемныеСерии.Серия + true + EnterOnInput + true + + + + + Объект.ПроблемныеСерии.Проблема + true + EnterOnInput + + + + + Объект.ПроблемныеСерии.Номенклатура + true + EnterOnInput + + + + + Объект.ПроблемныеСерии.ВидНоменклатуры + true + EnterOnInput + + + + + Объект.ПроблемныеСерии.Наименование + true + EnterOnInput + + + + + Объект.ПроблемныеСерии.Номер + true + EnterOnInput + + + + + Объект.ПроблемныеСерии.ГоденДо + true + EnterOnInput + + + + + Объект.ПроблемныеСерии.ПредложенныйНомер + EnterOnInput + + + + + Объект.ПроблемныеСерии.ПредложенныйГоденДо + EnterOnInput + + + + + Объект.ПроблемныеСерии.ПредложенноеНаименование + EnterOnInput + + + + + Объект.ПроблемныеСерии.Исправлено + true + EnterOnInput + Auto + + + + + Объект.ПроблемныеСерии.Комментарий + true + EnterOnInput + + + + +
+
+ + + + cfg:DataProcessorObject.РК_ПроверкаСерий + + true + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Найти проблемы</v8:content> + </v8:item> + + + + ru + Заполнить таблицу сериями с пустым номером или сроком годности (с учётом настроек вида) + + + + StdPicture.Find + true + + НайтиПроблемы + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Исправить отмеченные</v8:content> + </v8:item> + + + + ru + Записать предложенные значения в отмеченные серии + + + + StdPicture.Write + true + + ИсправитьОтмеченные + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Отметить</v8:content> + </v8:item> + + + StdPicture.CheckAll + true + + Отметить + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Снять отметку</v8:content> + </v8:item> + + + StdPicture.UncheckAll + true + + СнятьОтметку + + +
diff --git a/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма/Ext/Form/Module.bsl b/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма/Ext/Form/Module.bsl new file mode 100644 index 0000000..6b53a76 --- /dev/null +++ b/src/DataProcessors/РК_ПроверкаСерий/Forms/Форма/Ext/Form/Module.bsl @@ -0,0 +1,390 @@ +// Проверка и исправление данных Справочник.СерииНоменклатуры (#14). +// Логика заполнения номера/срока из наименования — как docs/transfer/Код_исправления_серий_crm3-26.bsl. + +#Область ОбработчикиСобытийФормы + +&НаСервере +Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) + + Объект.РежимТест = Истина; + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиКомандФормы + +&НаКлиенте +Процедура НайтиПроблемы(Команда) + + Попытка + Количество = НайтиПроблемыНаСервере(); + Исключение + ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); + Возврат; + КонецПопытки; + ПоказатьОповещениеПользователя("Проверка серий", , + "Найдено проблем: " + Формат(Количество, "ЧН=0; ЧГ=0")); + +КонецПроцедуры + +&НаКлиенте +Процедура ИсправитьОтмеченные(Команда) + + Если Объект.ПроблемныеСерии.Количество() = 0 Тогда + ПоказатьПредупреждение(, "Сначала выполните поиск проблем"); + Возврат; + КонецЕсли; + + Если Не ЕстьОтмеченныеСтроки() Тогда + ПоказатьПредупреждение(, "Отметьте строки для исправления"); + Возврат; + КонецЕсли; + + Если Не Объект.РежимТест Тогда + Описание = Новый ОписаниеОповещения("ИсправитьОтмеченныеПослеВопроса", ЭтотОбъект); + ПоказатьВопрос(Описание, + "Записать исправления в справочник серий?", + РежимДиалогаВопрос.ДаНет); + Возврат; + КонецЕсли; + + ВыполнитьИсправлениеНаКлиенте(); + +КонецПроцедуры + +&НаКлиенте +Процедура ИсправитьОтмеченныеПослеВопроса(РезультатВопроса, ДопПараметры) Экспорт + + Если РезультатВопроса <> КодВозвратаДиалога.Да Тогда + Возврат; + КонецЕсли; + ВыполнитьИсправлениеНаКлиенте(); + +КонецПроцедуры + +&НаКлиенте +Процедура ВыполнитьИсправлениеНаКлиенте() + + Попытка + Результат = ИсправитьОтмеченныеНаСервере(); + Исключение + ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); + Возврат; + КонецПопытки; + + Текст = СтрШаблон("Исправлено: %1; ошибок: %2%3", + Формат(Результат.Исправлено, "ЧН=0; ЧГ=0"), + Формат(Результат.Ошибок, "ЧН=0; ЧГ=0"), + ?(Объект.РежимТест, " (тест)", "")); + ПоказатьОповещениеПользователя("Проверка серий", , Текст); + +КонецПроцедуры + +&НаКлиенте +Процедура Отметить(Команда) + УстановитьОтметкуВыделенныхСтрок(Истина); +КонецПроцедуры + +&НаКлиенте +Процедура СнятьОтметку(Команда) + УстановитьОтметкуВыделенныхСтрок(Ложь); +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +&НаКлиенте +Функция ЕстьОтмеченныеСтроки() + + Для Каждого Стр Из Объект.ПроблемныеСерии Цикл + Если Стр.Отметка Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + Возврат Ложь; + +КонецФункции + +&НаКлиенте +Процедура УстановитьОтметкуВыделенныхСтрок(Отметка) + + ТаблицаФормы = Элементы.ПроблемныеСерии; + Выделенные = ТаблицаФормы.ВыделенныеСтроки; + Если Выделенные.Количество() = 0 Тогда + ПоказатьПредупреждение(, "Выделите строки в таблице"); + Возврат; + КонецЕсли; + + Для Каждого ИдентификаторСтроки Из Выделенные Цикл + СтрокаТЗ = Объект.ПроблемныеСерии.НайтиПоИдентификатору(ИдентификаторСтроки); + Если СтрокаТЗ <> Неопределено Тогда + СтрокаТЗ.Отметка = Отметка; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +&НаСервере +Функция НайтиПроблемыНаСервере() + + Объект.ПроблемныеСерии.Очистить(); + КэшНастроек = Новый Соответствие; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | Сер.Ссылка КАК Серия, + | Сер.Владелец КАК Номенклатура, + | Сер.ВидНоменклатуры КАК ВидНоменклатуры, + | Сер.Наименование КАК Наименование, + | Сер.Номер КАК Номер, + | Сер.ГоденДо КАК ГоденДо + |ИЗ + | Справочник.СерииНоменклатуры КАК Сер + |ГДЕ + | НЕ Сер.ПометкаУдаления + | И ( + | Сер.Номер = """" + | ИЛИ Сер.Номер ЕСТЬ NULL + | ИЛИ Сер.ГоденДо <= ДАТАВРЕМЯ(1, 1, 1) + | ИЛИ Сер.ГоденДо ЕСТЬ NULL + | ИЛИ ( + | (Сер.Наименование = """" ИЛИ Сер.Наименование ЕСТЬ NULL) + | И Сер.ГоденДо > ДАТАВРЕМЯ(2000, 1, 1) + | ) + | )"; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + ДобавитьСтрокуПроблемы(Выборка, КэшНастроек); + КонецЦикла; + + Возврат Объект.ПроблемныеСерии.Количество(); + +КонецФункции + +&НаСервере +Процедура ДобавитьСтрокуПроблемы(Выборка, КэшНастроек) + + Настройки = НастройкиСерийВида(Выборка.ВидНоменклатуры, КэшНастроек); + ИспНомер = Настройки.ИспользоватьНомерСерии; + ИспСрок = Настройки.ИспользоватьСрокГодностиСерии; + + ПустойНомер = Не ЗначениеЗаполнено(СокрЛП(Выборка.Номер)); + ПустойСрок = Не СрокГодностиЗаполнен(Выборка.ГоденДо); + ПустоеИмя = Не ЗначениеЗаполнено(СокрЛП(Выборка.Наименование)); + + Проблемы = Новый Массив; + ПредложенныйНомер = ""; + ПредложенныйГоденДо = '00010101'; + ПредложенноеНаименование = ""; + + Если ИспНомер И ПустойНомер Тогда + ПредложенныйНомер = ИзвлечьНомерИзНаименования(Выборка.Наименование); + Проблемы.Добавить("Пустой номер"); + КонецЕсли; + + Если ИспСрок И ПустойСрок Тогда + ПредложенныйГоденДо = ИзвлечьГоденДоИзНаименования(Выборка.Наименование); + Проблемы.Добавить("Пустой срок годности"); + Если Не СрокГодностиЗаполнен(ПредложенныйГоденДо) Тогда + ПредложенныйГоденДо = '00010101'; + КонецЕсли; + КонецЕсли; + + Если Не ИспНомер И ПустоеИмя И СрокГодностиЗаполнен(Выборка.ГоденДо) Тогда + ПредложенноеНаименование = "до " + Формат(Выборка.ГоденДо, "ДФ=dd.MM.yy"); + Проблемы.Добавить("Пустое наименование"); + КонецЕсли; + + Если Проблемы.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + НовСтр = Объект.ПроблемныеСерии.Добавить(); + НовСтр.Отметка = Истина; + НовСтр.Серия = Выборка.Серия; + НовСтр.Номенклатура = Выборка.Номенклатура; + НовСтр.ВидНоменклатуры = Выборка.ВидНоменклатуры; + НовСтр.Наименование = Выборка.Наименование; + НовСтр.Номер = Выборка.Номер; + НовСтр.ГоденДо = Выборка.ГоденДо; + НовСтр.Проблема = СтрСоединить(Проблемы, "; "); + НовСтр.ПредложенныйНомер = ПредложенныйНомер; + НовСтр.ПредложенныйГоденДо = ПредложенныйГоденДо; + НовСтр.ПредложенноеНаименование = ПредложенноеНаименование; + +КонецПроцедуры + +&НаСервере +Функция ИсправитьОтмеченныеНаСервере() + + Результат = Новый Структура("Исправлено, Ошибок", 0, 0); + + Для Каждого Стр Из Объект.ПроблемныеСерии Цикл + + Если Не Стр.Отметка Или Стр.Исправлено Тогда + Продолжить; + КонецЕсли; + + Стр.Комментарий = ""; + ЕстьИзменения = Ложь; + + Если СтрНайти(Стр.Проблема, "Пустой номер") > 0 + И ЗначениеЗаполнено(СокрЛП(Стр.ПредложенныйНомер)) + И Не ЗначениеЗаполнено(СокрЛП(Стр.Номер)) Тогда + ЕстьИзменения = Истина; + КонецЕсли; + + Если СтрНайти(Стр.Проблема, "Пустой срок годности") > 0 + И СрокГодностиЗаполнен(Стр.ПредложенныйГоденДо) + И Не СрокГодностиЗаполнен(Стр.ГоденДо) Тогда + ЕстьИзменения = Истина; + КонецЕсли; + + Если СтрНайти(Стр.Проблема, "Пустое наименование") > 0 + И ЗначениеЗаполнено(СокрЛП(Стр.ПредложенноеНаименование)) + И Не ЗначениеЗаполнено(СокрЛП(Стр.Наименование)) Тогда + ЕстьИзменения = Истина; + КонецЕсли; + + Если Не ЕстьИзменения Тогда + Стр.Комментарий = "Нет данных для исправления"; + Продолжить; + КонецЕсли; + + Попытка + Если Объект.РежимТест Тогда + Стр.Исправлено = Истина; + Результат.Исправлено = Результат.Исправлено + 1; + Иначе + ОбСерии = Стр.Серия.ПолучитьОбъект(); + Если СтрНайти(Стр.Проблема, "Пустой номер") > 0 + И ЗначениеЗаполнено(СокрЛП(Стр.ПредложенныйНомер)) Тогда + ОбСерии.Номер = СокрЛП(Стр.ПредложенныйНомер); + КонецЕсли; + Если СтрНайти(Стр.Проблема, "Пустой срок годности") > 0 + И СрокГодностиЗаполнен(Стр.ПредложенныйГоденДо) Тогда + ОбСерии.ГоденДо = Стр.ПредложенныйГоденДо; + КонецЕсли; + Если СтрНайти(Стр.Проблема, "Пустое наименование") > 0 + И ЗначениеЗаполнено(СокрЛП(Стр.ПредложенноеНаименование)) Тогда + ОбСерии.Наименование = СокрЛП(Стр.ПредложенноеНаименование); + КонецЕсли; + ОбСерии.Записать(); + Стр.Исправлено = Истина; + Стр.Номер = ОбСерии.Номер; + Стр.ГоденДо = ОбСерии.ГоденДо; + Стр.Наименование = ОбСерии.Наименование; + Результат.Исправлено = Результат.Исправлено + 1; + КонецЕсли; + Исключение + Стр.Комментарий = КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); + Результат.Ошибок = Результат.Ошибок + 1; + КонецПопытки; + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +&НаСервере +Функция НастройкиСерийВида(ВидНоменклатуры, КэшНастроек) + + Ключ = Строка(ВидНоменклатуры); + Настройки = КэшНастроек.Получить(Ключ); + Если Настройки <> Неопределено Тогда + Возврат Настройки; + КонецЕсли; + + Настройки = Новый Структура("ИспользоватьНомерСерии, ИспользоватьСрокГодностиСерии", Ложь, Ложь); + Если ЗначениеЗаполнено(ВидНоменклатуры) Тогда + Попытка + Настр = Справочники.ВидыНоменклатуры.НастройкиИспользованияСерий(ВидНоменклатуры); + Настройки.ИспользоватьНомерСерии = Настр.ИспользоватьНомерСерии; + Настройки.ИспользоватьСрокГодностиСерии = Настр.ИспользоватьСрокГодностиСерии; + Исключение + КонецПопытки; + КонецЕсли; + + КэшНастроек.Вставить(Ключ, Настройки); + Возврат Настройки; + +КонецФункции + +&НаСервере +Функция СрокГодностиЗаполнен(ГоденДо) + + Возврат ЗначениеЗаполнено(ГоденДо) И ГоденДо > '20000101'; + +КонецФункции + +&НаСервере +Функция ИзвлечьНомерИзНаименования(Текст) + + Текст = СокрЛП(Текст); + Если Не ЗначениеЗаполнено(Текст) Тогда + Возврат ""; + КонецЕсли; + + ПозДо = Найти(НРег(Текст), "до "); + Если ПозДо > 0 Тогда + ЛеваяЧасть = СокрЛП(Лев(Текст, ПозДо - 1)); + Если Не ЗначениеЗаполнено(ЛеваяЧасть) Тогда + Возврат ""; + КонецЕсли; + ПозСлэш = СтрНайти(ЛеваяЧасть, "/"); + Если ПозСлэш > 0 Тогда + Возврат СокрЛП(Сред(ЛеваяЧасть, ПозСлэш + 1)); + КонецЕсли; + Возврат ЛеваяЧасть; + КонецЕсли; + + Возврат Текст; + +КонецФункции + +&НаСервере +Функция ИзвлечьГоденДоИзНаименования(Текст) + + Текст = СокрЛП(Текст); + Если Не ЗначениеЗаполнено(Текст) Тогда + Возврат '00010101'; + КонецЕсли; + + ПозДо = Найти(НРег(Текст), "до "); + Если ПозДо = 0 Тогда + Возврат '00010101'; + КонецЕсли; + + Фрагмент = СокрЛП(Сред(Текст, ПозДо + 3)); + Возврат РазобратьДатуИзФрагмента(Фрагмент); + +КонецФункции + +&НаСервере +Функция РазобратьДатуИзФрагмента(Фрагмент) + + Части = СтрРазделить(Фрагмент, ".", Ложь); + Если Части.Количество() < 3 Тогда + Возврат '00010101'; + КонецЕсли; + + Попытка + День = Число(СокрЛП(Части[0])); + Месяц = Число(СокрЛП(Части[1])); + Год = Число(СокрЛП(Части[2])); + Если Год < 100 Тогда + Год = Год + 2000; + КонецЕсли; + Возврат Дата(Год, Месяц, День); + Исключение + Возврат '00010101'; + КонецПопытки; + +КонецФункции + +#КонецОбласти