From ae64d7b127e14d3cccd0b34e73e1cb76a947d9cd Mon Sep 17 00:00:00 2001 From: mihailkudravcev Date: Wed, 2 Sep 2026 17:13:25 +0300 Subject: [PATCH] =?UTF-8?q?1.3.1.110:=20=D1=81=D0=B5=D1=80=D0=B8=D0=B8=20?= =?UTF-8?q?=E2=80=94=20=D0=93=D0=BE=D0=B4=D0=B5=D0=BD=D0=94=D0=BE=20=D0=B8?= =?UTF-8?q?=D0=B7=20API=20=D0=B8=20=D0=B7=D0=B0=D0=B3=D0=BB=D1=83=D1=88?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D0=BD=D0=BE=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=82=D1=83=D1=80=D0=B5=20(#30,=20#31).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit series_expire → СерияГоденДо; при создании серии заполняются обязательные реквизиты; ключ заглушки = владелец серий + номенклатура + ГоденДо. Co-authored-by: Cursor --- CHANGELOG.md | 8 + VERSION | 2 +- src/ConfigDumpInfo.xml | 6 +- src/Configuration.xml | 2 +- src/DataProcessors/РК_ЗагрузкаОстатков.xml | 78 +++++ .../РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl | 296 +++++++++++++++--- 6 files changed, 337 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad42ad0..652f880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ --- +## 1.3.1.110 (2026-09-02) + +### РК_ЗагрузкаОстатков — серии: ГоденДо и заглушки по номенклатуре (#30, #31) + +- `series_expire` из API → реквизит ТЧ `СерияГоденДо`; при создании серии заполняются `ГоденДо`, `ДатаПроизводства`, `ВидНоменклатуры`. +- Fallback срока из имени серии (`до DD.MM.YY`); при отсутствии данных — дата среза cutover. +- Заглушки: ключ `ВидСер + Номенклатура + ГоденДо`, номер `Перенос_{код номенклатуры}_{yyyyMMdd}` (не одна серия на склад). + ## 1.3.1.109 (2026-09-01) ### РК_ЗагрузкаОстатков — маппинг соглашений комиссии cutover (#24) diff --git a/VERSION b/VERSION index 9f0b865..823727f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.1.109 +1.3.1.110 diff --git a/src/ConfigDumpInfo.xml b/src/ConfigDumpInfo.xml index 4041d0b..158f846 100644 --- a/src/ConfigDumpInfo.xml +++ b/src/ConfigDumpInfo.xml @@ -57,7 +57,7 @@ - + @@ -130,6 +130,8 @@ + + @@ -201,7 +203,7 @@ - + diff --git a/src/Configuration.xml b/src/Configuration.xml index 0e532cc..afa84f5 100644 --- a/src/Configuration.xml +++ b/src/Configuration.xml @@ -62,7 +62,7 @@ Role.РК_ОсновнаяРоль - 1.3.1.109 + 1.3.1.110 Language.Русский diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков.xml b/src/DataProcessors/РК_ЗагрузкаОстатков.xml index b2efc60..c060eab 100644 --- a/src/DataProcessors/РК_ЗагрузкаОстатков.xml +++ b/src/DataProcessors/РК_ЗагрузкаОстатков.xml @@ -1301,6 +1301,45 @@ Auto + + + СерияГоденДо + + + ru + Срок годности серии + + + + + xs:dateTime + + DateTime + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + СерияСсылка @@ -2788,6 +2827,45 @@ Auto + + + СерияГоденДо + + + ru + Срок годности серии + + + + + xs:dateTime + + DateTime + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + СерияСсылка diff --git a/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl b/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl index e14104e..2456af7 100644 --- a/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl +++ b/src/DataProcessors/РК_ЗагрузкаОстатков/Ext/ObjectModule.bsl @@ -98,7 +98,7 @@ КонецПроцедуры // Сопоставление строк ТЧ с НСИ целевой ИБ. -// Серии создаются только если не найдены; заглушки Перенос_* — только при СоздаватьЗаглушкиСерий. +// Серии создаются только если не найдены; заглушки Перенос_{номенклатура}_{срок} — только при СоздаватьЗаглушкиСерий. // // Параметры: // РежимТест - Булево - Истина: только поиск, без создания серий/характеристик @@ -835,6 +835,7 @@ НовСтр.СерияИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "series_guid", "")); НовСтр.Серия = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "series_name", ""))); НовСтр.СерияНомер = СокрЛП(Строка(ЗначениеСвойства(СтрокаAPI, "series_number", ""))); + НовСтр.СерияГоденДо = ДатаИзSeriesExpire(ЗначениеСвойства(СтрокаAPI, "series_expire", "")); Если ПустаяСтрока(НовСтр.Серия) И Не ПустаяСтрока(НовСтр.СерияНомер) Тогда НовСтр.Серия = НовСтр.СерияНомер; КонецЕсли; @@ -1169,6 +1170,173 @@ КонецПроцедуры +Функция ДатаИзSeriesExpire(СтрокаДаты) + + Текст = СокрЛП(Строка(СтрокаДаты)); + Если ПустаяСтрока(Текст) Тогда + Возврат '00010101'; + КонецЕсли; + + Попытка + ПозT = СтрНайти(Текст, "T"); + Если ПозT > 0 Тогда + Текст = Лев(Текст, ПозT - 1); + КонецЕсли; + ПозПроб = СтрНайти(Текст, " "); + Если ПозПроб > 0 Тогда + Текст = Лев(Текст, ПозПроб - 1); + КонецЕсли; + Части = СтрРазделить(Текст, "-", Ложь); + Если Части.Количество() >= 3 Тогда + Возврат Дата(Число(Части[0]), Число(Части[1]), Число(Части[2])); + КонецЕсли; + Исключение + КонецПопытки; + + Возврат '00010101'; + +КонецФункции + +Функция ДатаИзИмениСерии(ИмяСерии) + + Текст = СокрЛП(Строка(ИмяСерии)); + Если ПустаяСтрока(Текст) Тогда + Возврат '00010101'; + КонецЕсли; + + Позиция = СтрНайти(НРег(Текст), " до "); + Если Позиция = 0 Тогда + Возврат '00010101'; + КонецЕсли; + + Хвост = СокрЛП(Сред(Текст, Позиция + 4)); + Части = СтрРазделить(Хвост, ".", Ложь); + Если Части.Количество() < 3 Тогда + Возврат '00010101'; + КонецЕсли; + + Попытка + День = Число(Части[0]); + Месяц = Число(Части[1]); + Год = Число(Части[2]); + Если Год < 100 Тогда + Если Год >= 50 Тогда + Год = 1900 + Год; + Иначе + Год = 2000 + Год; + КонецЕсли; + КонецЕсли; + Возврат Дата(Год, Месяц, День); + Исключение + Возврат '00010101'; + КонецПопытки; + +КонецФункции + +Функция ДатаСрезаОстатковОбработки() + + Если ЗначениеЗаполнено(ДатаДокументовВвода) Тогда + Возврат ДатаДокументовВвода; + КонецЕсли; + Если ЗначениеЗаполнено(ДатаОстатков) Тогда + Возврат ДатаОстатков; + КонецЕсли; + Возврат ТекущаяДатаСеанса(); + +КонецФункции + +Функция ОпределитьГоденДоСерииСтроки(СтрТ) + + Если ЗначениеЗаполнено(СтрТ.СерияГоденДо) Тогда + Возврат СтрТ.СерияГоденДо; + КонецЕсли; + + ДатаИзИмени = ДатаИзИмениСерии(СокрЛП(СтрТ.Серия)); + Если ЗначениеЗаполнено(ДатаИзИмени) Тогда + Возврат ДатаИзИмени; + КонецЕсли; + + Возврат '00010101'; + +КонецФункции + +Функция КодНоменклатурыДляЗаглушкиСерии(СтрТ, Ном) + + Арт = СокрЛП(СтрТ.Артикул); + Если ЗначениеЗаполнено(Арт) Тогда + Возврат Лев(СтрЗаменить(СтрЗаменить(Арт, " ", "_"), "/", "_"), 20); + КонецЕсли; + + Код = СокрЛП(СтрТ.НоменклатураКод); + Если ЗначениеЗаполнено(Код) Тогда + Возврат Лев(СтрЗаменить(Код, " ", "_"), 20); + КонецЕсли; + + Если ЗначениеЗаполнено(Ном) Тогда + Попытка + КодНом = СокрЛП(Строка(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ном, "Код"))); + Если ЗначениеЗаполнено(КодНом) Тогда + Возврат Лев(СтрЗаменить(КодНом, " ", "_"), 20); + КонецЕсли; + Исключение + КонецПопытки; + Возврат Лев(СтрЗаменить(Строка(Ном.УникальныйИдентификатор()), "-", ""), 8); + КонецЕсли; + + Возврат Лев(СтрЗаменить(Строка(СтрТ.НоменклатураИдентификатор), "-", ""), 8); + +КонецФункции + +Функция СформироватьНомерЗаглушкиСерии(СтрТ, Ном, ГоденДо) + + КодНом = КодНоменклатурыДляЗаглушкиСерии(СтрТ, Ном); + СуффиксСрока = Формат(ГоденДо, "ДФ=yyyyMMdd"); + Возврат "Перенос_" + КодНом + "_" + СуффиксСрока; + +КонецФункции + +Функция СформироватьИмяЗаглушкиСерии(СтрТ, Ном, ГоденДо) + + Номер = СформироватьНомерЗаглушкиСерии(СтрТ, Ном, ГоденДо); + Возврат Номер + " до " + Формат(ГоденДо, "ДФ=dd.MM.yyyy"); + +КонецФункции + +Функция КлючКэшаСерииЗаглушки(ВидСер, Ном, ГоденДо) + + Возврат Строка(ВидСер.УникальныйИдентификатор()) + "|" + + Строка(Ном.УникальныйИдентификатор()) + "|" + + Формат(ГоденДо, "ДФ=yyyyMMdd"); + +КонецФункции + +Функция ОпределитьДатуПроизводстваСерии(ГоденДо, ЭтоЗаглушка) + + // Политика cutover: дата производства в API не передаётся — дата среза остатков. + Возврат НачалоДня(ДатаСрезаОстатковОбработки()); + +КонецФункции + +Процедура ЗаполнитьОбязательныеРеквизитыСерии(ОбСер, ГоденДо, ВидНом, ЭтоЗаглушка) + + Если ЗначениеЗаполнено(ГоденДо) Тогда + ОбСер.ГоденДо = КонецДня(ГоденДо); + КонецЕсли; + + Попытка + ОбСер.ДатаПроизводства = ОпределитьДатуПроизводстваСерии(ГоденДо, ЭтоЗаглушка); + Исключение + КонецПопытки; + + Попытка + Если ЗначениеЗаполнено(ВидНом) Тогда + ОбСер.ВидНоменклатуры = ВидНом; + КонецЕсли; + Исключение + КонецПопытки; + +КонецПроцедуры + Функция НайтиИлиСоздатьСерию(СтрТ, Ном, СкладЦель, СуффиксДатыСер, РежимТест, КэшТребуетсяСерия, КэшСерий, Результат) @@ -1176,39 +1344,6 @@ ВидНом = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ном, "ВидНоменклатуры"); ТребуетсяСерия = НоменклатураИспользуетСерии(Ном, КэшТребуетсяСерия); - ИмяСерии = СокрЛП(СтрТ.Серия); - НомерСерии = СокрЛП(СтрТ.СерияНомер); - ЭтоЗаглушка = Ложь; - - Если Не ЗначениеЗаполнено(ИмяСерии) И Не ЗначениеЗаполнено(НомерСерии) Тогда - Если Не ТребуетсяСерия Тогда - Возврат Сер; - КонецЕсли; - Если Не СоздаватьЗаглушкиСерий Тогда - СтрТ.КомментарийСопоставления = "Серия обязательна, в источнике пустая (заглушки выключены)"; - Возврат Сер; - КонецЕсли; - КодСклЗагл = "КОМ"; - Если ЗначениеЗаполнено(СкладЦель) Тогда - Попытка - КодСклЗагл = СокрЛП(Строка(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СкладЦель, "Код"))); - Исключение - КодСклЗагл = ""; - КонецПопытки; - Если ПустаяСтрока(КодСклЗагл) Тогда - КодСклЗагл = Лев(СтрЗаменить(Строка(СкладЦель.УникальныйИдентификатор()), "-", ""), 8); - КонецЕсли; - КонецЕсли; - ИмяСерии = "Перенос_" + КодСклЗагл + "_" + СуффиксДатыСер; - СтрТ.Серия = ИмяСерии; - ЭтоЗаглушка = Истина; - КонецЕсли; - - СсылкаПоГуид = СсылкаПоUUID(Справочники.СерииНоменклатуры, СтрТ.СерияИдентификатор); - Если ЗначениеЗаполнено(СсылкаПоГуид) И ОбщегоНазначения.СсылкаСуществует(СсылкаПоГуид) Тогда - Возврат СсылкаПоГуид; - КонецЕсли; - ВидСер = Неопределено; ИспНомерСерии = Истина; Попытка @@ -1222,43 +1357,102 @@ ВидСер = ВидНом; КонецЕсли; - КлючПоискаНомера = ?(ЗначениеЗаполнено(НомерСерии), НомерСерии, ИмяСерии); - КлючКэшСер = Строка(ВидСер.УникальныйИдентификатор()) + "|" + ИмяСерии + "|" + КлючПоискаНомера; + ИмяСерии = СокрЛП(СтрТ.Серия); + НомерСерии = СокрЛП(СтрТ.СерияНомер); + ЭтоЗаглушка = Ложь; + ГоденДо = ОпределитьГоденДоСерииСтроки(СтрТ); + + Если Не ЗначениеЗаполнено(ИмяСерии) И Не ЗначениеЗаполнено(НомерСерии) Тогда + Если Не ТребуетсяСерия Тогда + Возврат Сер; + КонецЕсли; + Если Не СоздаватьЗаглушкиСерий Тогда + СтрТ.КомментарийСопоставления = "Серия обязательна, в источнике пустая (заглушки выключены)"; + Возврат Сер; + КонецЕсли; + Если Не ЗначениеЗаполнено(ГоденДо) Тогда + ГоденДо = КонецДня(ДатаСрезаОстатковОбработки()); + КонецЕсли; + СтрТ.СерияГоденДо = ГоденДо; + НомерСерии = СформироватьНомерЗаглушкиСерии(СтрТ, Ном, ГоденДо); + ИмяСерии = СформироватьИмяЗаглушкиСерии(СтрТ, Ном, ГоденДо); + СтрТ.Серия = ИмяСерии; + СтрТ.СерияНомер = НомерСерии; + ЭтоЗаглушка = Истина; + Иначе + Если Не ЗначениеЗаполнено(ГоденДо) Тогда + ГоденДо = ДатаИзИмениСерии(ИмяСерии); + КонецЕсли; + Если ЗначениеЗаполнено(ГоденДо) Тогда + СтрТ.СерияГоденДо = ГоденДо; + КонецЕсли; + КонецЕсли; + + СсылкаПоГуид = СсылкаПоUUID(Справочники.СерииНоменклатуры, СтрТ.СерияИдентификатор); + Если ЗначениеЗаполнено(СсылкаПоГуид) И ОбщегоНазначения.СсылкаСуществует(СсылкаПоГуид) Тогда + Если ЭтоЗаглушка Тогда + КэшСерий.Вставить(КлючКэшаСерииЗаглушки(ВидСер, Ном, ГоденДо), СсылкаПоГуид); + КонецЕсли; + Возврат СсылкаПоГуид; + КонецЕсли; + + Если ЭтоЗаглушка Тогда + КлючКэшСер = КлючКэшаСерииЗаглушки(ВидСер, Ном, ГоденДо); + Иначе + КлючПоискаНомера = ?(ЗначениеЗаполнено(НомерСерии), НомерСерии, ИмяСерии); + КлючКэшСер = Строка(ВидСер.УникальныйИдентификатор()) + "|" + ИмяСерии + "|" + КлючПоискаНомера; + Если ЗначениеЗаполнено(ГоденДо) Тогда + КлючКэшСер = КлючКэшСер + "|" + Формат(ГоденДо, "ДФ=yyyyMMdd"); + КонецЕсли; + КонецЕсли; + СерИзКэш = КэшСерий.Получить(КлючКэшСер); Если СерИзКэш <> Неопределено Тогда Возврат СерИзКэш; КонецЕсли; - Если ИспНомерСерии И ЗначениеЗаполнено(КлючПоискаНомера) Тогда - Сер = Справочники.СерииНоменклатуры.НайтиПоРеквизиту("Номер", КлючПоискаНомера, , ВидСер); - КонецЕсли; - Если Не ЗначениеЗаполнено(Сер) И ЗначениеЗаполнено(ИмяСерии) Тогда - Сер = Справочники.СерииНоменклатуры.НайтиПоНаименованию(ИмяСерии, Истина, , ВидСер); - КонецЕсли; - Если Не ЗначениеЗаполнено(Сер) И ЗначениеЗаполнено(НомерСерии) И НомерСерии <> ИмяСерии Тогда - Сер = Справочники.СерииНоменклатуры.НайтиПоНаименованию(НомерСерии, Истина, , ВидСер); + Если ЭтоЗаглушка Тогда + Если ИспНомерСерии И ЗначениеЗаполнено(НомерСерии) Тогда + Сер = Справочники.СерииНоменклатуры.НайтиПоРеквизиту("Номер", НомерСерии, , ВидСер); + КонецЕсли; + Если Не ЗначениеЗаполнено(Сер) И ЗначениеЗаполнено(ИмяСерии) Тогда + Сер = Справочники.СерииНоменклатуры.НайтиПоНаименованию(ИмяСерии, Истина, , ВидСер); + КонецЕсли; + Иначе + КлючПоискаНомера = ?(ЗначениеЗаполнено(НомерСерии), НомерСерии, ИмяСерии); + Если ИспНомерСерии И ЗначениеЗаполнено(КлючПоискаНомера) Тогда + Сер = Справочники.СерииНоменклатуры.НайтиПоРеквизиту("Номер", КлючПоискаНомера, , ВидСер); + КонецЕсли; + Если Не ЗначениеЗаполнено(Сер) И ЗначениеЗаполнено(ИмяСерии) Тогда + Сер = Справочники.СерииНоменклатуры.НайтиПоНаименованию(ИмяСерии, Истина, , ВидСер); + КонецЕсли; + Если Не ЗначениеЗаполнено(Сер) И ЗначениеЗаполнено(НомерСерии) И НомерСерии <> ИмяСерии Тогда + Сер = Справочники.СерииНоменклатуры.НайтиПоНаименованию(НомерСерии, Истина, , ВидСер); + КонецЕсли; КонецЕсли; - МожноСоздать = Не РежимТест И ЗначениеЗаполнено(ИмяСерии); + МожноСоздать = Не РежимТест И (ЗначениеЗаполнено(ИмяСерии) Или ЗначениеЗаполнено(НомерСерии)); Если ЭтоЗаглушка Тогда - МожноСоздать = МожноСоздать И СоздаватьЗаглушкиСерий; + МожноСоздать = МожноСоздать И СоздаватьЗаглушкиСерий И ЗначениеЗаполнено(ГоденДо); КонецЕсли; Если Не ЗначениеЗаполнено(Сер) И МожноСоздать Тогда Попытка + Если Не ЗначениеЗаполнено(ГоденДо) Тогда + ГоденДо = КонецДня(ДатаСрезаОстатковОбработки()); + СтрТ.СерияГоденДо = ГоденДо; + КонецЕсли; ОбСер = Справочники.СерииНоменклатуры.ПустойОбъект(ВидСер); Если ИспНомерСерии Тогда - НомерСер = КлючПоискаНомера; - Если ЭтоЗаглушка И СтрНачинаетсяС(ИмяСерии, "Перенос_") Тогда - НомерСер = Сред(ИмяСерии, СтрДлина("Перенос_") + 1); - КонецЕсли; - ОбСер.Номер = НомерСер; + ОбСер.Номер = ?(ЗначениеЗаполнено(НомерСерии), НомерСерии, + ?(ЗначениеЗаполнено(ИмяСерии), ИмяСерии, "")); Иначе Попытка ОбСер.Наименование = ИмяСерии; Исключение КонецПопытки; КонецЕсли; + ЗаполнитьОбязательныеРеквизитыСерии(ОбСер, ГоденДо, ВидНом, ЭтоЗаглушка); ОбСер.Записать(); Сер = ОбСер.Ссылка; Результат.СозданоСерий = Результат.СозданоСерий + 1;