Приступим...
1. Создадим подписку на событие ПередЗаписью. Подписка нужна для запоминания таблицы движений документа по партиям до проведения. Включим в подписку все документы, входящие в список последовательности партионного учета.
2. Создадим в общем модуле процедуру для подписки. Для хранения таблицы движений документа используем встроенный реквизит документа ДополнительныеСвойства. Информация, помещаемая в эту структуру, хранится всё время "путешествия" объекта по подпискам. Запомним движения по партиям до проведения, а также границу последовательности, которая была на момент проведения документа.
Процедура ПередЗаписьюСписанияТоваров(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Если НЕ Источник.ЭтоНовый() Тогда
Если Источник.Движения.Найти("ПартииТоваровНаСкладах") <> Неопределено Тогда
ТаблицаДвиженийПоПартиям = ВернутьТаблицуДвиженийПоПартиям(Источник.Ссылка);
Источник.ДополнительныеСвойства.Вставить("ПартииДоПроведения", ТаблицаДвиженийПоПартиям);
КонецЕсли;
ГраницаПартионногоУчета = Последовательности.ПартионныйУчет.ПолучитьГраницу();
Источник.ДополнительныеСвойства.Вставить("ГраницаПоследовательности", ГраницаПартионногоУчета);
КонецЕсли;
КонецПроцедуры
Функция ВернутьТаблицуДвиженийПоПартиям(СсылкаНаОбъект) Экспорт
Запрос = Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ПартииТоваровНаСкладах.Номенклатура,
| ПартииТоваровНаСкладах.Склад,
| ПартииТоваровНаСкладах.ХарактеристикаНоменклатуры,
| ПартииТоваровНаСкладах.СерияНоменклатуры,
| ПартииТоваровНаСкладах.ДокументОприходования,
| ПартииТоваровНаСкладах.СтатусПартии,
| ПартииТоваровНаСкладах.Заказ,
| ПартииТоваровНаСкладах.Качество,
| ПартииТоваровНаСкладах.Количество,
| ПартииТоваровНаСкладах.Стоимость
|ИЗ
| РегистрНакопления.ПартииТоваровНаСкладах КАК ПартииТоваровНаСкладах
|ГДЕ
| ПартииТоваровНаСкладах.Регистратор = &Регистратор");
Запрос.УстановитьПараметр("Регистратор", СсылкаНаОбъект);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Возврат Новый ТаблицаЗначений;
Иначе
Возврат РезультатЗапроса.Выгрузить();
КонецЕсли;
КонецФункции
Таблицу движений по партиям получили и запомнили. Теперь надо сравнить с тем, что получилось после проведения. Создаем еще одну подписку на событие ОбработкаПроведения, также включаем туда документы из последовательности партионного учета. Таблицу движения по партиям после проведения также поместим в ДополнительныеСвойства.
Процедура ОбработкаПроведенияДляКонтроляГП(Источник, Отказ, РежимПроведения) Экспорт
ВыполнитьКонтрольГП(Источник);
КонецПроцедуры
Процедура ВыполнитьКонтрольГП(Источник) Экспорт
Если Источник.Метаданные().Реквизиты.Найти("ОтражатьВУправленческомУчете") <> Неопределено Тогда
Если НЕ Источник.ОтражатьВУправленческомУчете Тогда
Возврат;
КонецЕсли;
КонецЕсли;
Если НЕ Источник.ЭтоНовый() Тогда
Если Источник.Движения.Найти("ПартииТоваровНаСкладах") <> Неопределено Тогда
ПартииПослеПроведения = Источник.Движения.ПартииТоваровНаСкладах.Выгрузить();
Если ПартииПослеПроведения.Количество() = 0 Тогда
// для части документов партии появляются после записи объекта в базу
ПартииПослеПроведения = ВернутьТаблицуДвиженийПоПартиям(Источник.Ссылка);
КонецЕсли;
Источник.ДополнительныеСвойства.Вставить("ПартииПослеПроведения", ПартииПослеПроведения);
ОпределитьНеобходимостьВозвращенияГП(Источник);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Ну и, наконец, анализ необходимости возвращения последовательности.
Функция ОпределитьНеобходимостьВозвращенияГП(Источник) Экспорт
ДополнительныеСвойства = Источник.ДополнительныеСвойства;
ГраницаПоследовательностиДокумента = Неопределено;
ДополнительныеСвойства.Свойство("ГраницаПоследовательности", ГраницаПоследовательностиДокумента);
Идентичность = УстановитьИдентичностьТаблицДвиженийПоПартиям(ДополнительныеСвойства);
ГраницаПоследовательностиТекущая = Последовательности.ПартионныйУчет.ПолучитьГраницу();
Если ГраницаПоследовательностиДокумента <> Неопределено Тогда
Если Идентичность И ГраницаПоследовательностиТекущая.Дата < ГраницаПоследовательностиДокумента.Дата Тогда
// если таблицы идентичны, но текущая граница сдвинулась назад - вернем обратно
Последовательности.ПартионныйУчет.УстановитьГраницу(ГраницаПоследовательностиДокумента);
ЗаписьЖурналаРегистрации("Контроль ГП", УровеньЖурналаРегистрации.Информация, Источник.Метаданные(), Источник.Ссылка, "Граница последовательности возвращена на " + Строка(ГраницаПоследовательностиДокумента.Дата) + ", документ: " + Строка(ГраницаПоследовательностиДокумента.Ссылка));
КонецЕсли;
КонецЕсли;
КонецФункции
Функция УстановитьИдентичностьТаблицДвиженийПоПартиям(ДополнительныеСвойства) Экспорт
Идентичность = Ложь;
ПартииДоПроведения = Неопределено;
ДополнительныеСвойства.Свойство("ПартииДоПроведения", ПартииДоПроведения);
ПартииПослеПроведения = Неопределено;
ДополнительныеСвойства.Свойство("ПартииПослеПроведения", ПартииПослеПроведения);
Если СравнитьТаблицыЗначений(ПартииДоПроведения, ПартииПослеПроведения) Тогда
Идентичность = Истина;
Иначе
Идентичность = Ложь;
КонецЕсли;
Возврат Идентичность;
КонецФункции
Извлекли из ДополнительныеСвойства таблицы движений до и после, сравнили, определили необходимость возвращения последовательности и вернули при необходимости на место.
Механизм также полезен для ситуаций, когда пользователь открывает документ, проведенный задним числом, и вместо закрытия нажимает ОК. Граница улетает на "закрытый" таким образом документ.
Если еще углубляться в детали, в стандартной конфигурации граница последовательности сбрасывается программно кодом:
Если мУдалятьДвижения Тогда
ОбщегоНазначения.УдалитьДвиженияРегистратора(ЭтотОбъект, Отказ);
КонецЕсли;
То есть при перепроведении независимо ни от чего движения документа очищаются и записываются заново. В более современных продвинутых конфигурациях вроде это уже не так, но на родной переписанной до почти неузнаваемости УТ 10.3 вопрос восстановления границы последовательности потребовал программного решения.