gifts2017

Спасаем документ, запись которого невозможна. Или как скопировать документ, имея только его открытую форму (для обычных и управляемых форм)

Опубликовал Владимир Литвиненко (VladimirL) в раздел Программирование - Практика программирования

Публикация предназначена для тех, кому интересны неочевидные возможности программной работы с формами

Дело было так. Проверки табличной части при проведении документа были добавлены в неподходящий для этих целей обработчик события "ПередЗаписью". Для самой проверки вызывался серверный код. Отладка на сервере отключена. В алгоритм проверки закралась ошибка, вызывающая исключение при наличии в табличной части некоторых элементов справочника. Эта бомба замедленного действия сработала на документе, в который было добавлено несколько сотен строк. Как обычно в процессе заполнения кнопка "Сохранить" ни разу не нажималась. В результате сохранение с трудом заполненного документа оказалось невозможным, а ручной поиск строк, мешающих записи, по времени был сопоставим с повторным заполнением документа.

Запросы к БД были бесполезны - документ не записан. Внешних обработок заполнения к документу подключено не было и нечего было подменить, чтобы обработать табличную часть уже открытого документа. Работа велась в толстом клиенте обычном приложении, что делало невозможным применение метода ПолучитьОкна(). Документ нужно было спасать другим методом.

 


Решение оказалось простым. Каждая форма документа, в том числе обычная, связана с ее ключом - ссылкой на документ. То же справедливо для форм и других объектных типов 1С. У нового документа эта ссылка пустая. Платформа 1С имеет особенность. Если для ссылки-ключа производится попытка получения/открытия формы, которая уже была открыта, то новая форма не создается. Возвращается уже открытая форма! Дальше остается только обратиться к ее свойствам и прочитать хранимый в ней объект, создать на его основе новый и записать, по ходу дела удаляя из него информацию, мешающую записи.

То есть ключевая идея выражается всего в одной строчке кода:

Форма = ПолучитьФорму("Документ."+Ссылка.Метаданные().Имя+".ФормаОбъекта", Новый Структура("Ключ", Ссылка));

При этом Ссылка может быть и пустой. Дальше остается обратиться к свойству Форма.Объект или Форма.ДокументОбъект. В справочник внешних обработок была загружена обработка, получавшая данные формы. Документ был спасен путем создания его копии на основе данных формы без строк мешающих записи. Информация по удаленным из него строкам сохранена в файл и после исправления ошибки алгоритма занесена обратно.


Понятно, что такое стечение обстоятельств вряд ли может еще когда-нибудь повториться и практическая ценность описанного метода почти нулевая. Однако он демонстрирует интересную возможность работы с формами. Ниже приводится пример кода , который позволяет получить форму открытого документа и вытянуть из нее все данные. Код может работать как в обычной, так и в управляемой форме обработки без каких либо изменений, копируя данные как из обычной, так и управляемой формы открытого документа. Для применения кода нужно создать внешнюю обработку, добавить в нее реквизит СсылкаНаДокумент (ссылка на любой документ) и назначить обработчиком нашей команды метод "КнопкаВыполнитьНажатие(Команда)".

Заметьте, что использование директив компиляции &НаКлиенте и &НаСервере не запрещено в том числе и в обычной форме обработки. Если интересно посмотреть на работу кода, но лень создавать обработку, можно скачать приложенный к публикации файл :)

&НаКлиенте
Процедура КнопкаВыполнитьНажатие(Команда)

   
ЭтоУправляемаяФормаОбработки = ТипЗнч(ЭтаФорма) = Тип("УправляемаяФорма");

    Если НЕ
ЭтоУправляемаяФормаОбработки Тогда//в обычной форме основной реквизит называется ОбработкаОбъект,
       
Объект = ЭтаФорма.ОбработкаОбъект;    //для однотипности кода будем всегда работать с переменной Объект
   
КонецЕсли;

    Если
Объект.СсылкаНаДокумент = Неопределено Тогда
       
Сообщить("Необходимо выбрать тип документа или указать конкретный документ");
        Возврат;
    КонецЕсли;

    Если
ЭтоУправляемаяФормаОбработки Тогда
       
#Если ТолстыйКлиентУправляемоеПриложение ИЛИ ТонкийКлиент Тогда
           
ИмяМетаданных = ПолучитьИмяМетаданныхНаСервереУправляемойФормы(Объект.СсылкаНаДокумент);
       
#КонецЕсли
   
Иначе
       
#Если ТолстыйКлиентОбычноеПриложение Тогда
           
ИмяМетаданных = Объект.СсылкаНаДокумент.Метаданные().Имя;
       
#КонецЕсли
   
КонецЕсли;

   
Форма = ПолучитьФорму("Документ."+ИмяМетаданных+".ФормаОбъекта", Новый Структура("Ключ", Объект.СсылкаНаДокумент));

    Если НЕ
Форма.Открыта() Тогда
       
Сообщить("Вы выбрали документ, форма которого не открыта. Сначала откройте форму документа.");
        Возврат;
    КонецЕсли;

    Если
ТипЗнч(Форма) = Тип("УправляемаяФорма") Тогда
       
ОбъектКопирования = Форма.Объект; //здесь не учитываем, что в редких случаях объект может быть переименован
   
ИначеЕсли ТипЗнч(Форма) = Тип("Форма") Тогда
       
ОбъектКопирования = Форма.ДокументОбъект; //здесь не учитываем, что в редких случаях объект может быть переименован
   
КонецЕсли;

    Если
ЭтоУправляемаяФормаОбработки Тогда
       
#Если ТолстыйКлиентУправляемоеПриложение ИЛИ ТонкийКлиент Тогда
           
СсылкаНаНовыйДокумент = СкопироватьОбъектНаСервереВУправляемомПриложении(ОбъектКопирования, ИмяМетаданных);
           
ОткрытьЗначение(СсылкаНаНовыйДокумент);
       
#КонецЕсли
   
Иначе
       
#Если ТолстыйКлиентОбычноеПриложение Тогда
           
СкопироватьОбъектНаКлиентеВОбычномПриложении(ОбъектКопирования, ИмяМетаданных);
       
#КонецЕсли
   
КонецЕсли;

КонецПроцедуры

&НаСервере
Функция ПолучитьИмяМетаданныхНаСервереУправляемойФормы(Ссылка)
    Возврат
Ссылка.Метаданные().Имя;
КонецФункции


&НаСервере
Функция СкопироватьОбъектНаСервереВУправляемомПриложении(Объект, ИмяМетаданных)
   
//В управляемом приложении будем расчитывать на данные
   
ДокументОбъект = ДанныеФормыВЗначение(Объект, Тип("ДокументОбъект."+ИмяМетаданных));
   
НовыйОбъект = ДокументОбъект.Скопировать();

   
//Здесь можно провести программную модификацию документа, например удалить строки, мешающие записи

   
НовыйОбъект.Дата = ДокументОбъект.Дата;
   
НовыйОбъект.Записать();
    Возврат
НовыйОбъект.Ссылка;
КонецФункции

#Если ТолстыйКлиентОбычноеПриложение Тогда
Функция СкопироватьОбъектНаКлиентеВОбычномПриложении(Объект, ИмяМетаданных)

    Если
ТипЗнч(Объект) = Тип("ДанныеФормыСтруктура") Тогда //данные упр.формы
       
ДокументОбъект = ДанныеФормыВЗначение(Объект, Тип("ДокументОбъект."+ИмяМетаданных));
       
НовыйОбъект = ДокументОбъект.Скопировать();
    Иначе  
//объект из обычной формы
       
НовыйОбъект = Объект.Скопировать();
    КонецЕсли;

   
//Здесь можно провести программную модификацию документа, например удалить строки, мешающие записи

   
ОткрытьЗначение(НовыйОбъект); //В обычном приложении документ можно открыть не записывая в базу данных
КонецФункции
#КонецЕсли

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
КопированиеДокументаИзЕгоФормы.epf
.epf 10,45Kb
25.10.13
24
.epf 10,45Kb 24 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Serg Eli (elizarovs) 30.10.13 09:12
Нужная вещь! Работает. Проверил на УПП+УАТ.
2. bulpi bulpi (bulpi) 30.10.13 15:17
Замечание :
Функция СкопироватьОбъектНаКлиентеВОбычномПриложении(Объект, ИмяМетаданных)
Если ТипЗнч(Объект) = Тип("ДанныеФормыСтруктура") Тогда

Это условие, ИМХО, никогда не реализуется. Ведь речь идет об обычном приложении.

Что же касается самой причины появления обработки, то условия нужно ставить в процедуре ПередЗаписью с учетом режима записи -т.е. сохранять можно, проводить нельзя.
3. Victor Victor (skvic) 31.10.13 07:13
ПО быстрому (при обычных формах) делал сохранение в excel, правил код, а потом обработочкой с диска ИТС ЗагрузкаДанныхИзТабличногоДокумента :-) а за обработочку +1, вариант отличный.
6. uno dos (unoDosTres) 14.06.14 23:44
способ то классный с ключом формы, но не понятно как вы потом документ собирались записывать с тем же самым составом строк, ведь при записи снова будет проверка документа на стороне сервера, т.е. каким образом вы поняли
спасен путем создания его копии на основе данных формы без строк мешающих записи
какие строки являлись мешающими, допустим не скопировав код исполняемые на стороне сервера во внешнюю обработку и там уже смотреть, хотя и это тоже не всегда будет очевидным, если там какая то "забавная" проверка, один хрен анализировать строки. может можно как то сериализовать данные скопированные с формы, тогда это уже как то лучше и быстрей, если конечно возможна сериализация не записанного объекта
7. Алексей Зикеев (a.zikeev) 17.01.15 22:54
Благодаря автору у меня появился шанс спасти документ, который не записывается из-за нехватки прав...
За название темы отдельный респект !
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа