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 @@
+
+
+
+
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 @@
+
+
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';
+ КонецПопытки;
+
+КонецФункции
+
+#КонецОбласти