Постановка задачи вот такая:
Необходимо с помощью программных средств платформы и языка 1С разработать внешнюю обработку. Обработка должна запускаться в режиме управляемого приложения.
1. На форме обработки должны быть обеспечены следующие возможности:
- Выбор ссылки документа произвольного типа
- Выбор каталога, для сохранения и открытия файла
- Команда выгрузки документа
- Команда загрузки документа
2. При нажатии кнопки «Выгрузить», информация, содержащаяся в выбранном пользователем документе, должна выгрузиться в указанный каталог. Информация должна быть исчерпывающей, то есть выгружаться должны данные, чтобы при нажатии кнопки «Загрузить», в базе создавалась бы копия исходного документа (за исключением номера, т.к. номера документа уникальны).
3. Выгрузка должна осуществляться в формате Excel. Для этого необходимо разработать собственный формат файла выгрузки.
4. При написании обработки необходимо использовать Метаданные. Это делается для универсализации программного кода.
5. При написании обработки нельзя использовать функции ЗначениеВСтрокуВнутр(), УникальныйИдентификатор() и прочие подобные функции, выгружающие уникальные идентификаторы объектов, а также нельзя делать выгрузку и загрузку в формате XML или JSON.
6. Для проверки работоспособности рекомендуется использовать максимально заполненный данными документ.
Основная цель данной публикации - показать, что можно, имея базовые навыки программирования, решать довольно сложные задачи.
У Вас есть понимание, что задача простая, но не знаете с чего начать? В обработке и во вложенном файле "Краткая информация о ходе выполнения задачи" будет рассмотрена вся последовательность действий, которую необходимо пройти для достижения результата.
Вам кажется, что задача большая и вы не понимаете, как выглядит готовое решение? Цель публикации - дать понять, что важно понимать лишь 1, 2 следующих шага, и это уже позволит Вам дойти до конца. Ведь если не начать, то финишировать невозможно! Разбиваем задачу на мелкие кусочки, каждый из которых решается элементарно.
Есть трудности с отладкой? Считаете, что напишете код, который невозможно отладить? И эта "проблема" устранится в процессе решения задачи.
Чем Вам поможет изучение данной обработки:
1. Читать. Как бы это странно не звучало.
Также в помощь серия статей "Как читать чужой код".
Доработка типовой конфигурации. Обновление доработанной типовой конфигурации
Доработка чужого кода. Code review
Разбор и доработка запросов
Программный интерфейс. Исправление чужих доработок
2. Перестанете думать, что программирование и конфигуратор - это страшные слова.
3. Разбивать большие задачи на маленькие и понятные шаги.
4. Пользоваться простыми конструкциями языка 1С и универсальными коллекциями значений.
5. Решать задачи универсально, т.е. когда на входе много неизвестных параметров.
6. Писать запросы, не используя конструктор запроса.
7. Записывать данные в Excel с использованием обычных макетов.
8. Разбираться в типах данных и их настройках. Даже в страшных регистрах расчета.
9. Читать файл Excel через COM объект.
Как правильно читать файл Excel можно посмотреть в этой публикации:
Универсальный шаблон для загрузки данных из Excel
10. Знать особенности поиска ссылок в разных объектах метаданных.
11. Вести разработку в режиме отладчика.
В качестве примера, вставлю кусок кода, который формируется описание структуры документа:
&НаСервере
Функция ПолучитьСтруктуруДокумента(МетаданныеВыгружаемогоДокумента)
СтруктураДокумента = Новый Структура;
//В соответствии каждой табличной части соответствует массив структур с описанием всех реквизитов табличной части
//В соответствии будет такой же массив как и РеквизитыШапки
ТабличныеЧасти = Новый Соответствие;
//Каждый элемент массива содержит структуру с описанием одного реквизита
РеквизитыШапки = ПолучитьСтруктуруОписанияРеквизитов(МетаданныеВыгружаемогоДокумента.Реквизиты);
//Добавим стандартный реквизит Дата
РеквизитыШапки = ПолучитьСтруктуруОписанияРеквизитов(МетаданныеВыгружаемогоДокумента.СтандартныеРеквизиты, РеквизитыШапки);
//В цикле по табличным частям заполняем соответствие.
//Ключом является идентификатор табличной части, значением массив описвания реквизитов
Для Каждого ТекТабличнаяЧасть Из МетаданныеВыгружаемогоДокумента.ТабличныеЧасти Цикл
РеквизитыТабличнойЧасти = ПолучитьСтруктуруОписанияРеквизитов(ТекТабличнаяЧасть.Реквизиты);
ТабличныеЧасти.Вставить(ТекТабличнаяЧасть.Имя, РеквизитыТабличнойЧасти);
КонецЦикла;
//Опишем поля структуры документа
СтруктураДокумента.Вставить("РеквизитыШапки", РеквизитыШапки);
СтруктураДокумента.Вставить("ТабличныеЧасти", ТабличныеЧасти);
Возврат СтруктураДокумента;
КонецФункции // ПолучитьСтруктуруДокумента()
&НаСервере
Функция ПолучитьСтруктуруОписанияРеквизитов(КоллекцияРеквизитов, ИсходныйМассивРеквизитов = Неопределено)
//Стандартные реквизиты дописываем в реквизиты шапки
ЭтоСтандартныеРеквизиты = Не ИсходныйМассивРеквизитов = Неопределено;
Если ЭтоСтандартныеРеквизиты Тогда
МассивРеквизитов = ИсходныйМассивРеквизитов;
Иначе
МассивРеквизитов = Новый Массив;
КонецЕсли;
Для Каждого ТекРеквизит Из КоллекцияРеквизитов Цикл
//Из стандартных реквизитов выгружаем только дату документа
Если ЭтоСтандартныеРеквизиты Тогда
Если Не ТекРеквизит.Имя = "Дата" Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
//Получим структуру описания реквизита
ОписаниеРеквизита = ПолучитьСтруктуруОписанияРеквизита();
ОписаниеРеквизита.ИмяРеквизита = ТекРеквизит.Имя;
//Переменная будет хранить массив структур
//Каждая структура описывает один тип значения
МассивТипов = Новый Соответствие;
МассивТиповОбъектаМетаданных = ТекРеквизит.Тип.Типы();
Для Каждого ТекТип Из МассивТиповОбъектаМетаданных Цикл
ТипРеквизита = Строка(ТекТип);
ЭтоПримитивныйТипДанных = Не ПримитивныеТипыДанных.Найти(ТипРеквизита) = Неопределено;
//Получим структуру описание для каждого типа значения
ОписаниеТипаЗначения = ПолучитьСтруктуруОписанияТипаЗначения();
Если ЭтоПримитивныйТипДанных Тогда
ОписаниеТипаЗначения.ОбъектМетаданных = ТипРеквизита;
ОписаниеТипаЗначения.РазделМетаданных = "";
ОписаниеТипаЗначения.ЕстьИерархия = Ложь;
ОписаниеТипаЗначения.ВидИерархии = "";
ОписаниеТипаЗначения.УникальныйКод = Ложь;
ОписаниеТипаЗначения.ПредставлениеВВидеНаименования = Ложь;
ОписаниеТипаЗначения.ЕстьКод = Ложь;
ОписаниеТипаЗначения.ТипКода = "";
ОписаниеТипаЗначения.ЕстьНаименование = Ложь;
ОписаниеТипаЗначения.ЕстьВладельцы = Ложь;
ОписаниеТипаЗначения.Серийность = "";
Иначе
МетаданныеСсылочногоТипа = Метаданные.НайтиПоТипу(ТекТип);
ТипРеквизита = МетаданныеСсылочногоТипа.Имя;
РазделМетаданных = ПолучитьРазделМетаданныхПоТипу(ТипРеквизита);
ОписаниеТипаЗначения.ОбъектМетаданных = ТипРеквизита;
ОписаниеТипаЗначения.РазделМетаданных = РазделМетаданных;
Если РазделМетаданных = "Справочник" Или РазделМетаданных = "ПланВидовХарактеристик" Тогда
ОписаниеТипаЗначения.ЕстьИерархия = МетаданныеСсылочногоТипа.Иерархический;
//Вид иерархии есть только у справочников
Если РазделМетаданных = "Справочник" Тогда
Если МетаданныеСсылочногоТипа.Иерархический Тогда
ОписаниеТипаЗначения.ВидИерархии = Строка(МетаданныеСсылочногоТипа.ВидИерархии);
Иначе
ОписаниеТипаЗначения.ВидИерархии = "";
КонецЕсли;
Иначе
ОписаниеТипаЗначения.ВидИерархии = "";
КонецЕсли;
Иначе
ОписаниеТипаЗначения.ЕстьИерархия = Ложь;
ОписаниеТипаЗначения.ВидИерархии = "";
КонецЕсли;
Если РазделМетаданных = "Справочник" Тогда
ОписаниеТипаЗначения.ЕстьВладельцы = Не МетаданныеСсылочногоТипа.Владельцы.Количество() = 0;
//Для каждого владельца получим описание его типа и запишем в массив типов владельцев
Для Каждого ТекВладелец Из МетаданныеСсылочногоТипа.Владельцы Цикл
ОписаниеТипаЗначенияВладельца = ПолучитьСтруктуруОписанияТипаЗначения();
РазделМетаданныхВладельца = ПолучитьРазделМетаданныхПоТипу(ТекВладелец.Имя);
ОписаниеТипаЗначенияВладельца.ОбъектМетаданных = ТекВладелец.Имя;
ОписаниеТипаЗначенияВладельца.РазделМетаданных = РазделМетаданныхВладельца;
ОписаниеТипаЗначенияВладельца.ЕстьВладельцы = Ложь;
ОписаниеТипаЗначенияВладельца.ЕстьИерархия = ТекВладелец.Иерархический;
Если ТекВладелец.Иерархический И РазделМетаданныхВладельца = "Справочник" Тогда
ОписаниеТипаЗначенияВладельца.ВидИерархии = Строка(ТекВладелец.ВидИерархии);
Иначе
ОписаниеТипаЗначенияВладельца.ВидИерархии = "";
КонецЕсли;
Если РазделМетаданныхВладельца = "ПланВидовХарактеристик" Тогда
ОписаниеТипаЗначенияВладельца.ТипКода = "";
Иначе
ОписаниеТипаЗначенияВладельца.ТипКода = Строка(ТекВладелец.ТипКода);
КонецЕсли;
ОписаниеТипаЗначенияВладельца.ЕстьКод = Не ТекВладелец.ДлинаКода = 0;
ОписаниеТипаЗначенияВладельца.ЕстьНаименование = Не ТекВладелец.ДлинаНаименования = 0;
ОписаниеТипаЗначенияВладельца.ПредставлениеВВидеНаименования = ТекВладелец.ОсновноеПредставление = Метаданные.СвойстваОбъектов.ОсновноеПредставлениеСправочника.ВВидеНаименования;
ОписаниеТипаЗначенияВладельца.Серийность = Строка(ТекВладелец.СерииКодов);
ОписаниеТипаЗначенияВладельца.УникальныйКод = ТекВладелец.КонтрольУникальности;
ОписаниеТипаЗначения.МассивТиповВладельцев.Добавить(ОписаниеТипаЗначенияВладельца);
КонецЦикла;
Иначе
ОписаниеТипаЗначения.ЕстьВладельцы = Ложь;
КонецЕсли;
Если РазделМетаданных = "Перечисление" Или РазделМетаданных = "ПланВидовРасчета" Тогда
ОписаниеТипаЗначения.УникальныйКод = Ложь;
Иначе
ОписаниеТипаЗначения.УникальныйКод = МетаданныеСсылочногоТипа.КонтрольУникальности;
КонецЕсли;
Если РазделМетаданных = "Перечисление" Или РазделМетаданных = "Документ" Тогда
ОписаниеТипаЗначения.ПредставлениеВВидеНаименования = Ложь;
ОписаниеТипаЗначения.ЕстьКод = Ложь;
ОписаниеТипаЗначения.ЕстьНаименование = Ложь;
Если РазделМетаданных = "Документ" Тогда
ОписаниеТипаЗначения.ТипКода = Строка(МетаданныеСсылочногоТипа.ТипНомера);
Иначе
ОписаниеТипаЗначения.ТипКода = "";
КонецЕсли;
Иначе
Если РазделМетаданных = "ПланВидовРасчета" Тогда
ОписаниеТипаЗначения.ПредставлениеВВидеНаименования = МетаданныеСсылочногоТипа.ОсновноеПредставление = Метаданные.СвойстваОбъектов.ОсновноеПредставлениеВидаРасчета.ВВидеНаименования;
ИначеЕсли РазделМетаданных = "ПланВидовХарактеристик" Тогда
ОписаниеТипаЗначения.ПредставлениеВВидеНаименования = МетаданныеСсылочногоТипа.ОсновноеПредставление = Метаданные.СвойстваОбъектов.ОсновноеПредставлениеВидаХарактеристики.ВВидеНаименования;
Иначе
ОписаниеТипаЗначения.ПредставлениеВВидеНаименования = МетаданныеСсылочногоТипа.ОсновноеПредставление = Метаданные.СвойстваОбъектов.ОсновноеПредставлениеСправочника.ВВидеНаименования;
КонецЕсли;
Если Не РазделМетаданных = "ПланВидовХарактеристик" Тогда
ОписаниеТипаЗначения.ТипКода = Строка(МетаданныеСсылочногоТипа.ТипКода);
Иначе
ОписаниеТипаЗначения.ТипКода = "";
КонецЕсли;
ОписаниеТипаЗначения.ЕстьКод = Не МетаданныеСсылочногоТипа.ДлинаКода = 0;
ОписаниеТипаЗначения.ЕстьНаименование = Не МетаданныеСсылочногоТипа.ДлинаНаименования = 0;
КонецЕсли;
Если РазделМетаданных = "Перечисление" Или РазделМетаданных = "ПланВидовРасчета" Или РазделМетаданных = "Документ" Тогда
ОписаниеТипаЗначения.Серийность = Ложь;
Иначе
ОписаниеТипаЗначения.Серийность = Строка(МетаданныеСсылочногоТипа.СерииКодов);
КонецЕсли;
КонецЕсли;
//Массив типов делаем соответствием, для удобства поиска по названию объекта метаданных
//Для примитивных типов данных ключем будет название примитивного типа данных
МассивТипов.Вставить(ОписаниеТипаЗначения.ОбъектМетаданных, ОписаниеТипаЗначения);
КонецЦикла;
ОписаниеРеквизита.МассивТипов = МассивТипов;
МассивРеквизитов.Добавить(ОписаниеРеквизита);
КонецЦикла;
Возврат МассивРеквизитов;
КонецФункции // ПолучитьСтруктуруОписанияРеквизитов()
Обработка имеет одно ограничение: т.к. мой профиль - ЗУП, объект ПланСчетов не обработан в коде.
Это не сложно сделать по образцу. Конфигурация и номер релиза указан только для соблюдения формальностей.
Обработка работает на всех конфигурациях.
Коллеги, предлагаю поучаствовать в вебинаре по представлениям в ЗУП. Все подробности по ссылке:
Вебинар по представлениям в ЗУП.
Примеры моих обработок:
Пример работы с файлами odt в клиент-серверной модели работы
Просмотр регистров по НДФЛ
График вахты в ЗУП: Помощник заполнения и расчет переработок
Есть проблемы, потребность в обучении или вопросы по ЗУП - пишите в телегу @PabloFilatelly.