Обмен crm3-dev→crm3-26: номенклатура, склады, серии, НДС22 (1.3.0.37).

Защита учётных реквизитов номенклатуры, пропуск обновления видов и складов,
нормализация серий, ПКПД НДС22/НДС22_122.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2 changed files with 306 additions and 16 deletions
+1 -1
View File
@@ -1 +1 @@
1.3.0.35 1.3.0.37
@@ -1,10 +1,13 @@
#Область СлужебныйПрограммныйИнтерфейс #Область СлужебныйПрограммныйИнтерфейс
#Область ПКПД #Область ПКПД
// Заполняет таблицу правил конвертации предопределенных данных. // &После ЗаполнитьПравилаКонвертацииПредопределенныхДанных.
// Дополняет правило ПКПД «Перечисление_СтавкиНДС» значениями НДС22 и НДС22_122
// для обмена crm3-dev → crm3-26 (EnterpriseData 1.8+).
// //
// Параметры: // Параметры:
// НаправлениеОбмена - Строка - "Отправка" либо "Получение". // НаправлениеОбмена - Строка - "Отправка" либо "Получение".
// ПравилаКонвертации - ТаблицаЗначений - таблица значений, в которую будут добавлены правила. // ПравилаКонвертации - ТаблицаЗначений - таблица правил конвертации предопределённых данных.
//
&После("ЗаполнитьПравилаКонвертацииПредопределенныхДанных") &После("ЗаполнитьПравилаКонвертацииПредопределенныхДанных")
Процедура РК_ЗаполнитьПравилаКонвертацииПредопределенныхДанных(НаправлениеОбмена, ПравилаКонвертации) Процедура РК_ЗаполнитьПравилаКонвертацииПредопределенныхДанных(НаправлениеОбмена, ПравилаКонвертации)
ПоискПравилКонвертации = ПравилаКонвертации.НайтиСтроки( ПоискПравилКонвертации = ПравилаКонвертации.НайтиСтроки(
@@ -39,11 +42,55 @@
#Область Синхронизация_crm3_dev_crm3_26 #Область Синхронизация_crm3_dev_crm3_26
// 01.07.2026 — синхронизация crm3-dev → crm3-26 (ПКО Справочник_Номенклатура_Получение). // Ограничения обмена номенклатурой и видами номенклатуры (crm3-dev → crm3-26).
// Суть: не менять способ учёта номенклатуры в целевой ИБ при обновлении существующих // Существующие элементы: не перезаписывать складской/финансовый учёт из источника.
// элементов. Перед типовой обработкой сохраняем снимок учётных реквизитов целевой базы, // Новые элементы: применить настройки учёта вида номенклатуры целевой ИБ.
// после — восстанавливаем их в объект записи (ВидНоменклатуры, ОсобенностьУчета и др.). // См. docs/transfer/Анализ_синхронизации_crm3-dev_crm3-26.md, §3.2.
// Возвращает список реквизитов номенклатуры, подлежащих защите от перезаписи при обмене.
//
// Возвращаемое значение:
// Строка - имена реквизитов через запятую для конструктора Структура.
//
Функция РК_УчетныеРеквизитыНоменклатурыДляЗащиты()
Возврат "ВидНоменклатуры, ОсобенностьУчета, ТипНоменклатуры, ИспользованиеХарактеристик,"
+ "ВладелецСерий, ВладелецХарактеристик, ГруппаФинансовогоУчета, СкладскаяГруппа";
КонецФункции
// Создаёт в параметрах конвертации соответствие для хранения снимков учётных реквизитов номенклатуры.
//
// Параметры:
// КомпонентыОбмена - Структура - контекст текущей сессии обмена (ПараметрыКонвертации).
//
Процедура РК_ИнициализироватьСнимкиУчетаНоменклатуры(КомпонентыОбмена)
Если Не КомпонентыОбмена.ПараметрыКонвертации.Свойство("РК_СнимкиУчетаНоменклатуры") Тогда
КомпонентыОбмена.ПараметрыКонвертации.Вставить("РК_СнимкиУчетаНоменклатуры", Новый Соответствие);
КонецЕсли;
КонецПроцедуры
// Сохраняет снимок учётных реквизитов номенклатуры для последующего восстановления
// после типовой обработки и отложенного заполнения.
//
// Параметры:
// СсылкаНоменклатуры - СправочникСсылка.Номенклатура - элемент целевой ИБ.
// СнимокУчета - Структура - значения защищаемых реквизитов.
// КомпонентыОбмена - Структура - контекст текущей сессии обмена.
//
Процедура РК_СохранитьСнимокУчетаНоменклатуры(СсылкаНоменклатуры, СнимокУчета, КомпонентыОбмена)
РК_ИнициализироватьСнимкиУчетаНоменклатуры(КомпонентыОбмена);
КомпонентыОбмена.ПараметрыКонвертации.РК_СнимкиУчетаНоменклатуры.Вставить(СсылкаНоменклатуры, СнимокУчета);
КонецПроцедуры
// &Перед ПКО_Справочник_Номенклатура_Получение_ПередЗаписьюПолученныхДанных.
// Для существующей в целевой ИБ номенклатуры сохраняет снимок учётных реквизитов
// до выполнения типового обработчика получения.
//
// Параметры:
// ПолученныеДанные - СправочникОбъект.Номенклатура - данные из пакета обмена.
// ДанныеИБ - СправочникОбъект.Номенклатура - существующий объект целевой ИБ; Неопределено для нового.
// КонвертацияСвойств - ТаблицаЗначений - правила конвертации свойств ПКО.
// КомпонентыОбмена - Структура - контекст текущей сессии обмена.
//
&Перед("ПКО_Справочник_Номенклатура_Получение_ПередЗаписьюПолученныхДанных") &Перед("ПКО_Справочник_Номенклатура_Получение_ПередЗаписьюПолученныхДанных")
Процедура РК_ПКО_Справочник_Номенклатура_Получение_ПередЗаписью_СохранитьУчет(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена) Процедура РК_ПКО_Справочник_Номенклатура_Получение_ПередЗаписью_СохранитьУчет(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
@@ -51,17 +98,31 @@
Возврат; Возврат;
КонецЕсли; КонецЕсли;
СнимокУчета = Новый Структура( СнимокУчета = Новый Структура(РК_УчетныеРеквизитыНоменклатурыДляЗащиты());
"ВидНоменклатуры, ОсобенностьУчета, ТипНоменклатуры, ИспользованиеХарактеристик, ВладелецСерий, ВладелецХарактеристик");
ЗаполнитьЗначенияСвойств(СнимокУчета, ДанныеИБ); ЗаполнитьЗначенияСвойств(СнимокУчета, ДанныеИБ);
ПолученныеДанные.ДополнительныеСвойства.Вставить("РК_СнимокУчетаНоменклатуры", СнимокУчета); ПолученныеДанные.ДополнительныеСвойства.Вставить("РК_СнимокУчетаНоменклатуры", СнимокУчета);
РК_СохранитьСнимокУчетаНоменклатуры(ДанныеИБ.Ссылка, СнимокУчета, КомпонентыОбмена);
КонецПроцедуры КонецПроцедуры
// &После ПКО_Справочник_Номенклатура_Получение_ПередЗаписьюПолученныхДанных.
// Для существующей номенклатуры восстанавливает учётные реквизиты целевой ИБ из снимка.
// Для новой номенклатуры заполняет складской и финансовый учёт по виду номенклатуры целевой ИБ.
//
// Параметры:
// ПолученныеДанные - СправочникОбъект.Номенклатура - данные из пакета обмена.
// ДанныеИБ - СправочникОбъект.Номенклатура - существующий объект целевой ИБ; Неопределено для нового.
// КонвертацияСвойств - ТаблицаЗначений - правила конвертации свойств ПКО.
// КомпонентыОбмена - Структура - контекст текущей сессии обмена.
//
&После("ПКО_Справочник_Номенклатура_Получение_ПередЗаписьюПолученныхДанных") &После("ПКО_Справочник_Номенклатура_Получение_ПередЗаписьюПолученныхДанных")
Процедура РК_ПКО_Справочник_Номенклатура_Получение_ПередЗаписью_ВосстановитьУчет(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена) Процедура РК_ПКО_Справочник_Номенклатура_Получение_ПередЗаписью_УчетПослеБазы(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
Если ДанныеИБ = Неопределено Тогда Если ДанныеИБ = Неопределено Тогда
// Новая номенклатура: настройки складского и финансового учёта — из вида целевой ИБ.
Если ЗначениеЗаполнено(ПолученныеДанные.ВидНоменклатуры) Тогда
Справочники.Номенклатура.ЗаполнитьРеквизитыПоВидуНоменклатуры(ПолученныеДанные);
КонецЕсли;
Возврат; Возврат;
КонецЕсли; КонецЕсли;
@@ -73,15 +134,71 @@
КонецПроцедуры КонецПроцедуры
// &ИзменениеИКонтроль ПКО_Справочник_ВидыНоменклатуры_ПередЗаписьюПолученныхДанных.
// Пропускает обновление видов номенклатуры, уже существующих в целевой ИБ
// (сопоставление по GUID сохраняется, учётные настройки целевой ИБ не меняются).
//
// Параметры:
// ПолученныеДанные - СправочникОбъект.ВидыНоменклатуры - данные из пакета обмена.
// ДанныеИБ - СправочникОбъект.ВидыНоменклатуры - существующий объект целевой ИБ; Неопределено для нового.
// КонвертацияСвойств - ТаблицаЗначений - правила конвертации свойств ПКО.
// КомпонентыОбмена - Структура - контекст текущей сессии обмена.
//
&ИзменениеИКонтроль("ПКО_Справочник_ВидыНоменклатуры_ПередЗаписьюПолученныхДанных")
Процедура РК_ПКО_Справочник_ВидыНоменклатуры_ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
#Вставка
Если ДанныеИБ <> Неопределено Тогда
ПолученныеДанные = Неопределено;
Возврат;
КонецЕсли;
#КонецВставки
ДанныеДляЗаписиВИБ = ?(ДанныеИБ = Неопределено, ПолученныеДанные, ДанныеИБ);
Если НЕ ЗначениеЗаполнено(ДанныеДляЗаписиВИБ.ВариантОформленияПродажи) Тогда
ДанныеДляЗаписиВИБ.ВариантОформленияПродажи = Перечисления.ВариантыОформленияПродажи.РеализацияТоваровУслуг;
КонецЕсли;
Если НЕ ЗначениеЗаполнено(ДанныеДляЗаписиВИБ.ИспользованиеХарактеристик) Тогда
ДанныеДляЗаписиВИБ.ИспользованиеХарактеристик = Перечисления.ВариантыИспользованияХарактеристикНоменклатуры.НеИспользовать;
КонецЕсли;
Если Не ЗначениеЗаполнено(ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоНоменклатуре) Тогда
ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоНоменклатуре = Перечисления.ВариантОтбораДляКлючаЦен.Использовать;
КонецЕсли;
Если Не ЗначениеЗаполнено(ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоХарактеристике) Тогда
ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоХарактеристике = Перечисления.ВариантОтбораДляКлючаЦен.НеИспользовать;
КонецЕсли;
Если Не ЗначениеЗаполнено(ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоСерии) Тогда
ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоСерии = Перечисления.ВариантОтбораДляКлючаЦен.НеИспользовать;
КонецЕсли;
Если Не ЗначениеЗаполнено(ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоУпаковке) Тогда
ДанныеДляЗаписиВИБ.НастройкиКлючаЦенПоУпаковке = Перечисления.ВариантОтбораДляКлючаЦен.НеИспользовать;
КонецЕсли;
Если Не ПолученныеДанные.ИспользоватьСерии = Истина Тогда
ПолученныеДанные.ИспользоватьСерии = ДанныеДляЗаписиВИБ.ИспользоватьСерии;
КонецЕсли;
КонецПроцедуры
// &ИзменениеИКонтроль ПКО_Справочник_Склады_Получение_ПередЗаписьюПолученныхДанных.
// Пропускает обновление складов, уже существующих в целевой ИБ
// (сопоставление по GUID сохраняется, реквизиты целевого склада не меняются).
//
// Параметры:
// ПолученныеДанные - СправочникОбъект.Склады - данные из пакета обмена.
// ДанныеИБ - СправочникОбъект.Склады - существующий объект целевой ИБ; Неопределено для нового.
// КонвертацияСвойств - ТаблицаЗначений - правила конвертации свойств ПКО.
// КомпонентыОбмена - Структура - контекст текущей сессии обмена.
//
&ИзменениеИКонтроль("ПКО_Справочник_Склады_Получение_ПередЗаписьюПолученныхДанных") &ИзменениеИКонтроль("ПКО_Справочник_Склады_Получение_ПередЗаписьюПолученныхДанных")
Процедура РК_ПКО_Справочник_Склады_Получение_ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена) Процедура РК_ПКО_Справочник_Склады_Получение_ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
#Вставка #Вставка
// 01.07.2026 — синхронизация crm3-dev → crm3-26 (ПКО Справочник_Склады_Получение).
// Суть: не обновлять склады, уже существующие в целевой ИБ (ДанныеИБ заполнен,
// сопоставление по GUID сохраняется). Типовой обмен перезаписывал бы наименование,
// тип склада, контактную информацию данными из источника.
// Новые склады (ДанныеИБ = Неопределено) по-прежнему создаются при первой выгрузке.
Если ДанныеИБ <> Неопределено Тогда Если ДанныеИБ <> Неопределено Тогда
ПолученныеДанные = Неопределено; ПолученныеДанные = Неопределено;
Возврат; Возврат;
@@ -92,4 +209,177 @@
ПолученныеДанные.ДополнительныеСвойства, КомпонентыОбмена); ПолученныеДанные.ДополнительныеСвойства, КомпонентыОбмена);
КонецПроцедуры КонецПроцедуры
// &После ОтложеннаяОбработка_ЗаполнитьНоменклатуру.
// Восстанавливает учётные реквизиты номенклатуры из снимков после типовой отложенной обработки,
// которая перезаписывает ИспользованиеХарактеристик значением из вида номенклатуры.
//
// Параметры:
// КомпонентыОбмена - Структура - контекст текущей сессии обмена (ПараметрыКонвертации.РК_СнимкиУчетаНоменклатуры).
//
&После("ОтложеннаяОбработка_ЗаполнитьНоменклатуру")
Процедура РК_ОтложеннаяОбработка_ВосстановитьУчетНоменклатуры(КомпонентыОбмена)
Если Не КомпонентыОбмена.ПараметрыКонвертации.Свойство("РК_СнимкиУчетаНоменклатуры") Тогда
Возврат;
КонецЕсли;
Снимки = КомпонентыОбмена.ПараметрыКонвертации.РК_СнимкиУчетаНоменклатуры;
Если Снимки.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Для Каждого КлючИЗначение Из Снимки Цикл
НоменклатураСсылка = КлючИЗначение.Ключ;
СнимокУчета = КлючИЗначение.Значение;
Если Не ОбщегоНазначения.СсылкаСуществует(НоменклатураСсылка) Тогда
Продолжить;
КонецЕсли;
НоменклатураОбъект = НоменклатураСсылка.ПолучитьОбъект();
ЗаполнитьЗначенияСвойств(НоменклатураОбъект, СнимокУчета);
НоменклатураОбъект.ОбменДанными.Загрузка = Истина;
Попытка
НоменклатураОбъект.Записать();
Исключение
ЗаписатьОшибкуВЖурналРегистрации(НоменклатураСсылка,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()), КомпонентыОбмена);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
// Возвращает владельца серий для вида номенклатуры в целевой ИБ
// (с учётом НастройкиСерийБерутсяИзДругогоВидаНоменклатуры).
//
// Параметры:
// ВидНоменклатуры - СправочникСсылка.ВидыНоменклатуры - вид из пакета обмена или номенклатуры.
//
// Возвращаемое значение:
// СправочникСсылка.ВидыНоменклатуры - вид-владелец для справочника СерииНоменклатуры.
//
Функция РК_ВладелецСерийДляВидаНоменклатуры(ВидНоменклатуры)
Если Не ЗначениеЗаполнено(ВидНоменклатуры) Тогда
Возврат Справочники.ВидыНоменклатуры.ПустаяСсылка();
КонецЕсли;
НастройкиСерий = Справочники.ВидыНоменклатуры.НастройкиИспользованияСерий(ВидНоменклатуры);
ВладелецСерий = НастройкиСерий.ВладелецСерий;
Если Не ЗначениеЗаполнено(ВладелецСерий) Тогда
ВладелецСерий = ВидНоменклатуры;
КонецЕсли;
Возврат ВладелецСерий;
КонецФункции
// &После ДобавитьПКО_Справочник_СерииНоменклатуры.
// Подключает обработчик проверки владельца серии при получении из пакета обмена.
//
// Параметры:
// ПравилаКонвертации - ТаблицаЗначений - таблица правил конвертации объектов.
//
&После("ДобавитьПКО_Справочник_СерииНоменклатуры")
Процедура РК_ДобавитьПКО_Справочник_СерииНоменклатуры_УстановитьПередЗаписью(ПравилаКонвертации)
СтрокиПКО = ПравилаКонвертации.НайтиСтроки(Новый Структура("ИмяПКО", "Справочник_СерииНоменклатуры"));
Если СтрокиПКО.Количество() = 0 Тогда
Возврат;
КонецЕсли;
СтрокиПКО[0].ПередЗаписьюПолученныхДанных = "РК_ПКО_Справочник_СерииНоменклатуры_ПередЗаписьюПолученныхДанных";
КонецПроцедуры
// ПКО Справочник_СерииНоменклатуры — ПередЗаписьюПолученныхДанных.
// Проверяет и нормализует привязку серии к виду-владельцу в целевой ИБ.
// При несовпадении владельца у сопоставленной по полям поиска серии — пропуск записи.
//
// Параметры:
// ПолученныеДанные - СправочникОбъект.СерииНоменклатуры - данные из пакета обмена.
// ДанныеИБ - СправочникОбъект.СерииНоменклатуры - существующий объект; Неопределено для нового.
// КонвертацияСвойств - ТаблицаЗначений - правила конвертации свойств ПКО.
// КомпонентыОбмена - Структура - контекст текущей сессии обмена.
//
Процедура РК_ПКО_Справочник_СерииНоменклатуры_ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
Если ПолученныеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(ПолученныеДанные.ВидНоменклатуры) Тогда
Возврат;
КонецЕсли;
КорректныйВладелец = РК_ВладелецСерийДляВидаНоменклатуры(ПолученныеДанные.ВидНоменклатуры);
Если Не ЗначениеЗаполнено(КорректныйВладелец) Тогда
Возврат;
КонецЕсли;
СсылкаДляЖурнала = ?(ДанныеИБ = Неопределено, ПолученныеДанные.ПолучитьСсылкуНового(), ДанныеИБ.Ссылка);
Если ДанныеИБ <> Неопределено Тогда
Если ЗначениеЗаполнено(ДанныеИБ.ВидНоменклатуры)
И ДанныеИБ.ВидНоменклатуры <> КорректныйВладелец
И ПолученныеДанные.ВидНоменклатуры <> ДанныеИБ.ВидНоменклатуры Тогда
ТекстОшибки = СтрШаблон(
"Неверная привязка серии по владельцу: в ИБ %1, из пакета (норм.) %2, наименование ""%3"", номер ""%4"".",
ДанныеИБ.ВидНоменклатуры,
КорректныйВладелец,
ПолученныеДанные.Наименование,
ПолученныеДанные.Номер);
ЗаписатьОшибкуВЖурналРегистрации(СсылкаДляЖурнала, ТекстОшибки, КомпонентыОбмена,
НСтр("ru = 'записать серию номенклатуры'"), УровеньЖурналаРегистрации.Предупреждение);
ПолученныеДанные = Неопределено;
Возврат;
КонецЕсли;
Если ЗначениеЗаполнено(ДанныеИБ.ВидНоменклатуры) Тогда
ПолученныеДанные.ВидНоменклатуры = ДанныеИБ.ВидНоменклатуры;
Иначе
ПолученныеДанные.ВидНоменклатуры = КорректныйВладелец;
КонецЕсли;
Иначе
ПолученныеДанные.ВидНоменклатуры = КорректныйВладелец;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Серии.Ссылка КАК Ссылка
|ИЗ
| Справочник.СерииНоменклатуры КАК Серии
|ГДЕ
| Серии.ВидНоменклатуры = &Владелец
| И НЕ Серии.ПометкаУдаления
| И (Серии.Наименование = &Наименование
| ИЛИ Серии.Номер = &Номер
| И &НомерЗаполнен)";
Запрос.УстановитьПараметр("Владелец", КорректныйВладелец);
Запрос.УстановитьПараметр("Наименование", ПолученныеДанные.Наименование);
Запрос.УстановитьПараметр("Номер", ПолученныеДанные.Номер);
Запрос.УстановитьПараметр("НомерЗаполнен", ЗначениеЗаполнено(ПолученныеДанные.Номер));
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий()
И Выборка.Ссылка <> СсылкаДляЖурнала Тогда
ТекстОшибки = СтрШаблон(
"Серия с наименованием ""%1"" уже существует у владельца %2 (%3), GUID отличается от пакета.",
ПолученныеДанные.Наименование,
КорректныйВладелец,
Выборка.Ссылка);
ЗаписатьОшибкуВЖурналРегистрации(СсылкаДляЖурнала, ТекстОшибки, КомпонентыОбмена,
НСтр("ru = 'создать серию номенклатуры'"), УровеньЖурналаРегистрации.Предупреждение);
ПолученныеДанные = Неопределено;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
#КонецОбласти #КонецОбласти