Создавая или разрабатывая новый документа в системе 1С всегда сталкиваешься с некоторыми особенностями платформы. Это не удивительно, ведь 1С изначально "заточен" именно как база данных всевозможных таблиц. Все документы одного типа, например те же реализации всегда создаются с одинаковым набором реквизитов и табличных частей. Есть конечно механизм дополнительных реквизитов, но он тоже зачастую реализован и настраивается для всех документов одного типа сразу.
В этой статье я решил поделиться мыслью о создании по настоящему произвольных документов с помощью 1С. Под произвольным документом будет пониматься некий документ с абсолютно произвольными реквизитами, вид и количество которых пользователь сможет настраивать самостоятельно.
Итак начну с постановки задачи - создать настраиваемый документ в 1С, с произвольным количеством реквизитов. Заведу в пустой базе для примера некий документ, который будет играть роль сразу множества различных типов документов, каждый из которых можно будет ещё и настраивать при этом отдельно - менять имена и состав реквизитов.
Практическое применение здесь налицо. При минимальном изменении базы - 1 документ и 2 справочника, можно запрограммировать "хотелки" всего вашего предприятия. Завести огромное количество нетиповых документов всего в одном объёкте ПроизвольныйДокумент который будет нетиповым и никак не повлияет на обновление типовой базы. Этот объект можно будет дорабатывать не спеша под нужды ваших сотрудников.
Просьба строго не судить пример только лишь абстрактный, я взял наиболее часто встречающиеся вещи - реализацию и списание, а способом о котором идет речь можно конструировать абсолютно любой документ с любым функционалом.
Для начала пару справочников:
1. ИмяДокумента - в этом справочнике будем заводить наименования наших произвольных документов (для важных документов лучше сделать предопределённые элементы справочника).
2. Реквизиты - будет хранить наименования реквизитов документов.
Остальные справочники обычно имеются в типовых базах, но моя база пустая, поэтому создам - Контрагенты, Номенклатура, ФизическиеЛица, Материалы.... и всё что угодно душе так сказать.
Далее перехожу собственно к созданию нашего Произвольного документа. Объект в дереве конфигураций так и назову, "ПроизвольныйДокумент". Создадим реквизит ссылочного типа "Имя" и Табличную часть "Шапка". Реквизит "Имя" будет ссылаться на справочник "ИмяДокумента". У табличной части Шапка заведу два реквизита - "Реквизит" - ссылка на справочник "Реквизиты" и "СвойствоРеквизита" - составной тип данных (в моём случае строка 500 символов, число 15 точность 3, все документы и все справочники).
Скриншот дерева конфигурации
Итак откроем базу и посмотрим, что даже без программирования как такового, мы уже получили некий вполне рабочий результат.
Скриншоты нашего Произвольного документа
Форма списка.
Форма документа Подарки детям на праздники
Форма документа Реализация товаров.
Форма документа Списание материалов.
Реквизит "Имя" играет роль наименования создаваемого документа в табличной части "Шапка" храним реквизиты документа. Поэтому чтобы не вводить вручную каждый раз набор реквизитов для конкретного документа, немножко по программируем. Создадим объекту "ПроизвольныйДокумент" форму документа. Для Реквизита "Имя" создадим процедуру ПриИзменении.
Код основной Формы документа
&НаСервере
Процедура ИмяПриИзмененииНаСервере()
Если Объект.Проведен = Ложь Тогда
Если Объект.Имя = Справочники.ИмяДокумента.НайтиПоНаименованию("Реализация товара") Тогда
ЗаполнитьРеализацию();
ИначеЕсли Объект.Имя = Справочники.ИмяДокумента.НайтиПоНаименованию("Списание материалов") Тогда
ЗаполнитьСписание();
ИначеЕсли Объект.Имя = Справочники.ИмяДокумента.НайтиПоНаименованию("Помощь детским садам") Тогда
ПомощьДетскимСадам();
ИначеЕсли Объект.Имя = Справочники.ИмяДокумента.НайтиПоНаименованию("Подарки детям на праздники") Тогда
ПодаркиДетямНаПраздники();
Иначе
КонецЕсли;
Иначе
Сообщить("Нельзя менять состав проведенного документа при изменении типа документа, если есть необходимость проделайте изменение вручную.")
КонецЕсли
КонецПроцедуры
&НаКлиенте
Процедура ИмяПриИзменении(Элемент)
ИмяПриИзмененииНаСервере();
КонецПроцедуры
Процедуры ЗаполнитьРеализацию(), ЗаполнитьСписание() сделал чтобы было удобнее читать незагромождая код ПриИзмененииНаСервере().
Раз уж пример тестовый то и процедуры заполнения табличных частей написал без цикла, с циклом конечно было бы "покрасивше", но кода не меньше.
Процедура ЗаполнитьРеализацию()
ОписаниеТипа = Новый ОписаниеТипов("Число");
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка");
Объект.Шапка.Очистить();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Номенклатура");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.Номенклатура.ПустаяСсылка();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Контрагент");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.Контрагенты.ПустаяСсылка();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Количество");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипа.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Цена (ед.)");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипа.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Сумма");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипа.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Примечание");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипаСтрока.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
КонецПроцедуры
Процедура ЗаполнитьСписание()
ОписаниеТипа = Новый ОписаниеТипов("Число");
Объект.Шапка.Очистить();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Ответственный");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.ФизическиеЛица.ПустаяСсылка();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Материал");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.Материалы.ПустаяСсылка();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Количество");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипа.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
КонецПроцедуры
Процедура ПодаркиДетямНаПраздники()
Объект.Шапка.Очистить();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Номенклатура");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.Номенклатура.ПустаяСсылка();
КонецПроцедуры
Процедура ПомощьДетскимСадам()
ОписаниеТипа = Новый ОписаниеТипов("Число");
ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка");
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Контрагент");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.Контрагенты.ПустаяСсылка();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Сумма");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипа.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Ответственный");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = Справочники.ФизическиеЛица.ПустаяСсылка();
Объект.Шапка.Добавить();
Объект.Шапка[Объект.Шапка.Количество() - 1].Реквизит = Справочники.Реквизиты.НайтиПоНаименованию("Примечание");
Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита = ОписаниеТипаСтрока.ПривестиЗначение(Объект.Шапка[Объект.Шапка.Количество() - 1].СвойствоРеквизита);
КонецПроцедуры
Затем в написанный код можно добавить всё что угодно:
- Все возможные проверки на запись документа. Так, чтобы при изменении одного и того же документа не стиралась и перезаписывалась табличная часть с реквизитами таблицы.
- Можно для каждого вида документа при записи или проведении в модуле документа сделать проведение по нужным этому документу регистрам.
- Сделать настройку по ролям пользователей.
- и т.д. список можно продолжать и продолжать...
Небольшой анализ такого программирования показывает, что данный метод разработки имеет как плюсы так и минусы.
Плюсы:
- объект "ПроизвольныйДокумент" может заменить множество других документов и позволяет вводить новые "свежепридуманные" документы непосредственно в режиме 1С:Предприятие;
- количество и тип реквизитов в абсолютно любом из документов можно настроить индивидуально.
- все пользовательские "хотелки" собраны в одном месте;
- доработка программистом будет в основном затрагивать модули нетипового объекта "ПроизвольныйДокумент" и модули его форм, механизмы типовых конфигураций при этом можно вообще не использовать.
Минусы:
- разработка проверки заполнения документа, проверок записи, проведения и удаления усложняется, т к. нужно пользоваться отдельным алгоритмом для каждого элемента в справочнике "ИмяДокумента". Это множество всевозможных вложенных Если.. Тогда.. Иначе.
- если потребуется отчетность по таким документам, строить её тоже сложнее. этот пункт касается только документов для которых нет проводок по регистрам, если вы написали проводки проведения - тогда проще;
- пример был простым, табличная часть "Шапка" содержала все реквизиты и обрабатывалась в одном цикле. Конечно же задумка такая, что программисту нужно зайти дальше и реализовать несколько табличных частей в нашем объекте - но сложность программирования при этом возрастёт.
Реализация данной задачи естественно не обязательна именно в таком виде как я написал. Можно, к примеру вместо справочников "ИмяДокумента" и "Реквизиты" сделать регистр/регистры сведений или вообще не создавать справочники, а воспользоваться любым типовым справочником (например в справочнике Номенклатура создадим папку Настройки документов и введем нужные наименования документов и реквизитов туда). Всё исходит от целей конкретно поставленной задачи.
Подобным же образом можно пользоваться не при разработке документа, а при разработке какого-нибудь справочника.
Идея по созданию подобной вещи пришла ко мне не сразу. Изначально появилась задача создать документ тестирующий сотрудников компании. В этом документе наименованием служило название теста. В табличных частях хранился вопросник и правильные ответы. При открытии теста администратором можно было ввести вопросы и проставить галочки правильных ответов, настройки так сказать. При открытии обычным пользователем открывалась другая форма документа с временной таблицей вариантов выбора ответов на время. После решения теста и проведения документа сразу был виден результат выполнения теста и устанавливался запрет на редактирование пользователем. После некоторого времени "танцев с бубном" появился результат, идеи и принципы которого привели собственно к созданию полностью настраиваемого произвольного документа. Может быть сама мысль подобного программирования покажется кому то неправильной или бессмысленной, но мне почему то помогла решить ряд насущных задач и заработать немножко денежек на хлебушек. В общем в комментариях можете написать что вы думаете по поводу таких вот настраиваемых документов и собственно есть ли у них будущее на воплощение к конкретно вашим задачам.
Благодарю за внимание к статье. На этом всё.