При переносе данных между базами часто возникает ситуация, когда движения документов переносить не требуется, а перенесенные документы следует проводить в базе-приёмнике. Например, в базе-источнике ведется управленческий учет, а в базе-приемнике регламентированный. Если при переносе не учитывать свойство «Проведен» документа, то можно получить в приемнике проведенные документы, у которых данные в движениях и в объекте не соответствуют друг другу.
В правилах конвертации объектов (ПКО) в обработчике «Перед загрузкой» существуют параметры «РежимЗаписи» и «РежимПроведения», указание которых обеспечивает необходимый режим записи объекта, но в этом случае, запись происходит во время загрузки данных и если, по каким-то причинам, документ не запишется, загрузка данных будет прервана. Правильней записывать новые документы в конце загрузки, когда все перенесенные объекты уже будут в базе - приемнике.
Несколько основных моментов:
- Нам необходим параметр конвертации с типом «Таблица значений», куда можно будет записывать ссылки на документ и информацию о том, что с документом делать. Создать параметр на вкладке «Параметры» конвертации – не получится, но его спокойно можно создать программным способом. После использования наш параметр следует удалить, в противном случае при использовании управляемой формы обработки система будет выдавать сообщение об ошибке, т.к. управляемая форма не использует таблицу значений. Несмотря на сообщение об ошибке, обработка все действия выполнит, но нервировать пользователей подобными сообщениями не следует.
- Для анализа, новый это объект или существующий в обработке используется параметр ОбъектНайден.
- Для анализа состояния ранее записанного объекта в приемнике используем обращение к его ссылке (Объект.Ссылка).
- Для записи ссылки нового для приемника документа нам необходимо документ записать. Чтобы избежать повторной записи документа обработкой обмена следует выставить параметр ОбъектМодифицирован в значение Ложь.
- Обработка обмена данными при записи документа обнуляет перенесенную пометку удаления. Это необходимо учитывать.
-
Для решения стоящей задачи наиболее удобно использовать обработчики событий конвертации в целом. Но нам необходимо определить – объект - это документ, и если документ – то проводится ли он. Для идентификации документа используем параметр обработчика ИмяТипаОбъекта.
I. Первый, более простой, случай: требуется оставлять в базе-приемнике документы непроведенными.
Подразумевается, что пользователи в базе-приемнике проверят документы и потом их проведут. Если не переносить движения и просто указать в свойстве «Проведен» - «Значение = Ложь», то можем получить при повторном переносе документы внешне не проведенные, но с движениями. К этому получим справедливое возмущение пользователей, которые не смогут понять результатов отчетов.
Свойство «Проведен» необходимо исключить из переноса в каждом документе. Нам необходимо при выгрузке данных запоминать необходимые для отмены проведения документы и после загрузки данных записать их с режимом отмены проведения. Помимо ссылки на документ необходимо сохранять и информацию об его пометке удаления. Для получения информации о пометке удаления данное свойство каждого проводимого документа необходимо передавать в параметр, который назовем также, как и имя свойства - ПометкаУдаления. (Рис.1)
1. В обработчике «Перед загрузкой данных» конвертации создаем параметр с типом значений «Таблица значений». В колонку "Действие" строкой будем записывать – что делать с документом: просто отменять проведение или еще проставлять пометку на удаление.
ТаблицаДокументов = Новый ТаблицаЗначений;
ТаблицаДокументов.Колонки.Добавить("Ссылка");
ТаблицаДокументов.Колонки.Добавить("Действие");
Параметры.Вставить("ТаблицаДокументов",ТаблицаДокументов);
2. В обработчике «После загрузки объекта» конвертации, определяем найден ли объект, является ли объект документом, проводится ли он, и если в приемнике он проведен, то только тогда помещаем ссылку на него в наш параметр ТаблицаДокументов.
Если ОбъектНайден
И ИмяТипаОбъекта = "Документ"
И Объект.Метаданные().Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить
И Объект.Ссылка.Проведен Тогда
НоваяСтрока = Параметры.ТаблицаДокументов.Добавить();
НоваяСтрока.Ссылка = Объект.Ссылка;
Если ПараметрыОбъекта.Получить("ПометкаУдаления") Тогда
НоваяСтрока.Действие = "Удаление";
Иначе
НоваяСтрока.Действие = "Отмена";
КонецЕсли;
ИначеЕсли ПараметрыОбъекта <> Неопределено И Лев(Строка(ТипЗнч(Объект)),8) = "Документ" Тогда
Объект.ПометкаУдаления = ПараметрыОбъекта.Получить("ПометкаУдаления"); //Пометка удаления у новых объектов и непроведенных старых
КонецЕсли;
3. В обработчике «После загрузки данных» конвертации отменяем проведение у записанных документов, проставляем при необходимости пометку на удаление и удаляем наш параметр. При желании отследить процесс удаления код обработчика может выглядеть так:
ТекстСообщенияОтмены = "";
ТекстСообщенияОшибки = "";
Для каждого СтрокаТч Из Параметры.ТаблицаДокументов Цикл
Попытка
ДокОбъект = СтрокаТч.Ссылка.ПолучитьОбъект();
Если СтрокаТч.Ссылка.Проведен Тогда
ДокОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;
Если СтрокаТч.Действие = "Удаление" Тогда
ДокОбъект.ПометкаУдаления = Истина;
ДокОбъект.Записать();
КонецЕсли;
ТекстСообщенияОтмены = ТекстСообщенияОтмены + Строка(СтрокаТч.Ссылка) + Символы.ПС;
Исключение
ТекстСообщенияОшибки = ТекстСообщенияОшибки + Строка(СтрокаТч.Ссылка) + " : "+ ОписаниеОшибки() + Символы.ПС;
КонецПопытки;
КонецЦикла;
Если Не ПустаяСтрока(ТекстСообщенияОтмены) Тогда
Сообщить("Отменено проведение документов:" + Символы.ПС + ТекстСообщенияОтмены);
КонецЕсли;
Если Не ПустаяСтрока(ТекстСообщенияОшибки) Тогда
Сообщить("Ошибки при отмене проведения: "+ Символы.ПС + ТекстСообщенияОшибки);
КонецЕсли;
Параметры.Удалить("ТаблицаДокументов");
II. Требуется обеспечить проведение документов в базе-приемнике при переносе.
В этом случае необходимо помимо пометки удаления передавать значение свойства «Проведен» в параметр «Проведен» и данный параметр анализировать в обработчике «После загрузки объекта» (Рис.2).
1. «Перед загрузкой данных» Повторяем создание параметра конвертации, как в первом примере
ТаблицаДокументов = Новый ТаблицаЗначений;
ТаблицаДокументов.Колонки.Добавить("Ссылка");
ТаблицаДокументов.Колонки.Добавить("Действие");
Параметры.Вставить("ТаблицаДокументов",ТаблицаДокументов);
2. «После загрузки объекта» После загрузки мы должны уже работать с объектами, которые еще не записаны в базе. Документы можно выделить по типу значения, а новый объект, перед внесением в таблицу параметра, необходимо предварительно записать. Не забываем установить параметр «ОбъектМодифицирован» в «Ложь».
Если ИмяТипаОбъекта = "Документ"
И Объект.Метаданные().Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
Если Не ОбъектНайден Тогда
Объект.Записать();
ОбъектМодифицирован = Ложь;
КонецЕсли;
НоваяСтрока = Параметры.ТаблицаДокументов.Добавить();
НоваяСтрока.Ссылка = Объект.Ссылка;
Если ПараметрыОбъекта.Получить("Проведен") Тогда
НоваяСтрока.Действие = "Проведение";
ИначеЕсли ПараметрыОбъекта.Получить("ПометкаУдаления") Тогда
НоваяСтрока.Действие = "Удаление";
Иначе
НоваяСтрока.Действие = "Отмена";
КонецЕсли;
КонецЕсли;
3. «После загрузки данных» После загрузки мы должны пропустить запись документа, если он не проведен в базе-источнике и в базе приемника. Также необходимо проследить за пометкой удаления.
ТекстСообщенияЗаписи = "";
ТекстСообщенияОшибки = "";
Для каждого СтрокаТч Из Параметры.ТаблицаДокументов Цикл
Если СтрокаТч.Действие = "Отмена" И Не СтрокаТч.Ссылка.Проведен Тогда
Если СтрокаТч.Ссылка.ПометкаУдаления Тогда //Для снятия пометки удаления
Попытка
ДокОбъект = СтрокаТч.Ссылка.ПолучитьОбъект();
ДокОбъект.ПометкаУдаления = Ложь;
ДокОбъект.Записать();
Исключение
КонецПопытки;
КонецЕсли;
Продолжить;
КонецЕсли;
Если СтрокаТч.Действие = "Проведение" Тогда
РежимЗаписи = РежимЗаписиДокумента.Проведение;
Иначе
РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения;
КонецЕсли;
Попытка
ДокОбъект = СтрокаТч.Ссылка.ПолучитьОбъект();
Если (СтрокаТч.Действие <> "Удаление" Или СтрокаТч.Ссылка.Проведен) Тогда
ДокОбъект.Записать(РежимЗаписи);
ТекстСообщенияЗаписи = ТекстСообщенияЗаписи +?(РежимЗаписи = РежимЗаписиДокумента.Проведение,
"Проведен ","Отменено проведение ")
+ Строка(СтрокаТч.Ссылка) + Символы.ПС;
КонецЕсли;
Если СтрокаТч.Действие = "Удаление" Тогда
ДокОбъект.ПометкаУдаления = Истина;
ДокОбъект.Записать();
ИначеЕсли СтрокаТч.Ссылка.ПометкаУдаления Тогда
ДокОбъект.ПометкаУдаления = Ложь;
ДокОбъект.Записать();
КонецЕсли;
Исключение
ТекстСообщенияОшибки = ТекстСообщенияОшибки + Строка(СтрокаТч.Ссылка)+ " : "+ОписаниеОшибки()+ Символы.ПС;
КонецПопытки;
КонецЦикла;
Если Не ПустаяСтрока(ТекстСообщенияЗаписи) Тогда
Сообщить(ТекстСообщенияЗаписи);
КонецЕсли;
Если Не ПустаяСтрока(ТекстСообщенияОшибки) Тогда
Сообщить("Ошибки при отмене проведения: "+ Символы.ПС + ТекстСообщенияОшибки);
КонецЕсли;
Параметры.Удалить("ТаблицаДокументов");