Доработки конфигурации – необходимое зло в 1С. В данной публикации автор предлагает несколько простых подходов и приемов, позволяющих хотя бы немного, но оптимизировать объем доработок конфигурации, упростить их, и облегчить дальнейшие доработки и обновления конфигурации. Все примеры и подходы взяты автором из реальной жизни и основаны на собственных наблюдениях. Примеры ниже будут даваться по конфигурациям семейства "Зарплата", хотя годятся для любых конфигураций. Версия конфигурации и платформы особой роли не играет.
Доработать это? А оно мне надо?
Аксиомой является факт, что стандартный функционал документов, обработок и отчетов, поставляемых 1С, часто не удовлетворяет конкретную организацию. Другая аксиома, что одной из наиболее сильных сторон 1С является возможность его настройки и доработки "под себя", в том числе - глубокой программной переработки (т.н. "доработки конфигурации").
Сегодня, как известно, доработать "под себя" функционал 1С можно четырьмя основными способами:
1. Доработать саму конфигурацию, т.е. изменить стандартные документы (регистры, отчеты, обработки и т.п.) системы под свои нужды.
2. Использовать вместо доработок конфигурации - механизм расширений, т.е. механизм своих "надстроек" над конфигурацией, не затрагивающих саму эту конфигурацию.
3. Использовать внешние обработки (в том числе, обработки табличной части), печатные формы и внешние отчеты.
4. Использовать тонкую настройку в режиме «1С: Предприятие» (т.е. провести настройки самой программы на уровне пользователя).
У всех способов есть свои преимущества и недостатки.
- После доработки стандартных документов 1С мы в будущем столкнемся с проблемами обновления. Опыт обновлений последних лет говорит, что 1С часто переделывает или модифицирует стандартные документы. Ясно, что при любом обновлении от 1С - провести «свое» обновление на уже измененный вами документ, есть удовольствие ниже среднего, мягко говоря.
- Внешние обработки лишены этого недостатка, но при всех своих преимуществах, однако, и они имеют недостатки - их работа не оставляет "следов" в виде документов.
- Тонкая настройка на уровне пользователя в режиме «1С: Предприятие», к сожалению, очень ограничена по возможностям.
- Почти идеальным кажется вариант с расширениями. Однако, несмотря на достижения расширений, не все доработки можно выполнить через них, или это трудоемко (неудобно).
Пока автор излагает то, что все знают и так, как «Отче наш». Ему, впрочем, видится вполне приемлемое решение в некоем компромиссе между озвученными способами - по сути, комбинации способов 1 и 2. Суть предложения сводится к следующему: производится доработка конфигурации (не расширения, не внешние обработки), но НИКАКИЕ стандартные документы (обработки, отчеты, регистры) НЕ дорабатываются. Вместо этого в систему вводятся НОВЫЕ объекты (документы, регистры и т.п.), которые осуществляют необходимые нам расчеты и действия.
На первый взгляд идея кажется абсурдной - нам что, предлагается копировать и подменить, например, документ "Премия" в ЗУП 3.1.? Ничего подобного! Более того, сама идея подобного копирования - глупая и ненужная. Новые, введенными нами объекты НЕ ЗАМЕНЯЮТ стандартные, а дополняют их! Они существуют отдельно в дереве метаданных конфигурации - как отдельные документы, отчеты, обработки.
Задача таких объектов - провести нужные нам расчеты, показать нужные данные, или преобразовать данные в системе нужным нам способом, а затем передать эти сведения (в нужном нам виде) на вход в обработку стандартных документов. Никаких движений в стандартные регистры эти документы НЕ делают при своем проведении, они максимально «автономны» от прочих объектов конфигурации.
Такие функциональные расчетные документы можно условно назвать "документы расчета верхнего уровня", или "интерфейсный документ". Смысл такого названия в том, что пользователь напрямую работает с этими документами в своем интерфейсе (они выводятся в интерфейс), проводит в них расчеты, а не в стандартных документах.
Приведем условный пример, чтобы было яснее:
В систему добавлен документ «Расчет премии за продажи». Этот документ в свою табличную часть собирает по определенным алгоритмам сотрудников, которым положена премия за продажи. Затем сумма премии рассчитывается на основе данных в системе 1С, согласно правилам расчета премии на этом предприятии. Сумма премии, данные по сотрудникам и любая прочая вспомогательная информация – все это прекрасно видно пользователю в документе «Расчет премии за продажи», который хранится в своем журнале документов и т.п. После расчета суммы премии, при проведении документа или нажатию на определенную кнопку, документ «Расчет премии за продажи» программно создает стандартный документ «Премии», запоминает его шапку, и помещает в него сотрудников с уже рассчитанной суммой премии за продажи (ссылка на этот документ «Премии» хранится в реквизите нашего документа). При дальнейшем изменении документа «Расчет премии за продажи» - меняется и документ «Премии».
Итог: у нас есть полностью готовый стандартный документ «Премии» с рассчитанной премией за продажи. Все исходные данные остались в документе «Расчет премии за продажи».
Если бы нашего документа «Расчет премии за продажи» не было бы, то рассчитать премию за продажи нам бы пришлось вручную, и вписать затем эти суммы сразу в документ «Премии». Да, в ряде случаев можно настроить формулу в виде расчета в 1С, но практика говорит, что схемы мотивации часто настолько «замудрены», что это крайне непростая, часто невыполнимая задача. Можно было бы использовать обработку, которая проводит эти расчеты и создает документы «Премии», однако обработка не оставляет «следов», а мы эти следы имеем (документы «Расчет премии за продажи»).
В виде картинки это можно представить так:
Используя предложенный механизм "интерфейсных" документов, разработчик достигает следующих выгод:
- Отсутствуют доработки стандартных документов 1С. При описанном выше способе, это исключено. Стандартные обновления 1С в дальнейшем без проблем обновляют стандартные документы (а вы попробуйте обновить документ с хорошо доработанным кодом – посмеемся вместе J ). На функционале наших доработок это может сказаться только, если в стандартных документах будут затронуты основные реквизиты, которые мы используем в «интерфейсном» заполнении.
- Новые документы и объекты хорошо видны в конфигурации, в том числе, при обновлениях, особенно, если не забыть выделить их имена, например, префиксами вроде «Д_МоеИмя». Разработчик, в том числе, пришедший позже, четко знает - где находится доработка, они не размазаны по множеству объектов системы в коде, а вынесены в отдельные, легко локализуемые сущности дерева метаданных. Такой подход существенно облегчает нам дальнейшую доработку наших разработок - нужно будет "ковырять" только наш же добавленный блок, и наши добавленные документы. Как живут и поживают стандартные документы – нам неинтересно, повторюсь, мы их не трогали, и не будем трогать.
Естественно, предложенный способ имеет и свои недостатки. Прежде всего, это ограничение по сфере применения – далеко не всегда и не везде этот способ применим, он выгоден только на больших и массовых доработках. Я бы сказал больше – его следует применять только в том случае, когда возможные издержки любых других вариантов (например, расширений) могут стоить больших денежных, временных, и «нервных» затрат. Кроме того, предложенный способ все равно является доработкой конфигурации, и лишает нас возможности проводить автоматические обновления.
Храните константы в сберегательном справочнике. Если конечно они у вас есть…
Вновь вернемся к известной аксиоме, что многие организации, использующие 1С, вынуждены вводить в конфигурацию свои доработки. Естественно, что при доработках адекватные программисты пытаются писать адекватный же код с использованием, в том числе, неких постоянных переменных, констант и т.п. И тут возникает проблема - если нам для наших доработок нужна новая константа, например, вид расчета "премия за красивые глаза", то логично что эту константу нужно где-то хранить?
Не писать же в коде, например, "ПланыВидовРасчета.Начисления.НайтиПоНаименованию("Премия за красивые глаза")" в стиле незабвенных "индийских программистов"? А завтра бухгалтер Иванесса Карповна переименует в базе наш вид премии, и вся наша доработка накроется медным тазом...
Чтобы не плодить в системе константы, значения по умолчанию, флаги активации для тех или иных наших доработок, есть предложение: держать все эти константы и флаги в одном месте (нет, не там, где вы подумали), а именно - в качестве отдельного элемента метаданных 1С. Автор публикации несколько раз прибегал к подобному методу в практической работе на проектах. По его мнению, наилучшим вариантом будет отдельный дополнительный справочник (с названием, например, "КонстантыДоработки"), добавленный в конфигурацию.
Весь справочник состоит из предопределенных элементов, является иерархическим, и не имеет никаких реквизитов, кроме стандартных (т.е. наименования и кода) и реквизита «Значение» (который имеет составной тип «Любая ссылка, Число, Булево, Строка, Дата»). В режиме Конфигуратора мы заполняем список предопределенных элементов (т.е. устанавливаем имя, код и наименование). Каждый такой предопределенный элемент справочника - одна отдельная константа. Значения констант мы всегда можем удобно посмотреть и выставить в базе, просто открыв в системе в режиме "1С: Предприятие" справочник "КонстантыДоработки".
Теперь в коде легко вызвать нужную константу простейшей конструкцией, например, "Справочники.КонстантыДоработки.ВидПремии.Значение" – даст нам значение константы «Вид премии». Нам, как программисту, не нужно беспокоится, какое конкретно значение заполнено в этом элементе. Разве что проверить на заполнение, и не забыть конечно в базе саму константу выставить.
Иерархический режим справочника нужен, чтобы, если констант много – в режиме Предприятия расфасовать их по папкам. Единственная сложность - пополнять справочник можно только в режиме Конфигуратора.
Стоит ли говорить, что использование подобного справочника констант также избавляет нас от необходимости увеличивать и без того громадный перечень стандартных констант в дереве метаданных и облегчает обновления нестандартных конфигураций?
Это еще не все. В том же справочнике констант можно держать в отдельных элементах, например, пути к каталогам загрузки-выгрузки для ваших доработок, строковые и численные значения, даты, значения для подстановки "по умолчанию" из других справочников, даже списки значений и картинки (например, для логотипов на печатные формы).
С помощью справочника констант можно также хранить и "флаги", и через это "включать" и "выключать" наши доработки. Например, в системе есть наша доработка расчета премии. В справочнике констант "КонстантыДоработки" вводим через конфигуратор элемент "АктивностьБлокаПремии" с типом "Булево". Далее программная конструкция:
ФлагАктивности = Справочники.КонстантыДоработки.АктивностьБлокаПремии.Значение;
Если ФлагАктивности = Истина тогда
// код нашей доработки
КонецЕсли;
позволит нам всегда проверить в коде - "включена" ли наша некая доработка в базе данных. Мы же в любой момент в режиме "1С: Предприятие", зайдя в форму нашего справочника констант - можем включить или выключить наш флаг.
Большая Советская Энциклопедия своих функций и процедур
Эта очень простая идея вытекает из предыдущей. Нам, то есть программистам, так удобно пользоваться в работе всякого рода стандартными функциями и процедурами 1С! Но бывает, что их нам не хватает!
"Так напиши свою!" – скажет мне кто-то, и этот совет будет правильным. Ну хорошо, я написал "свою" функцию для очередного отчета или обработки, и она замечательная. Но в другом месте мне нужна эта же функция! Снова ее писать? Копипастить? Нет, есть более разумное решение.
Добавим в конфигурацию новый общий модуль, и в него поместим все наши замечательные «самописные» функции, укажем, что они экспортные, а потом будем в коде просто вызывать их по имени через имя общего модуля.
Этот совет при всей своей чудовищной старости и очевидности, однако, используется куда как реже, чем стоило бы. Автор сам видел, как многие доработки пестрели "местными" самописными функциями, напиханными в десятке мест методом "копипасты". Есть, кстати, другой, почти равнозначный вариант этого совета – поместить разного рода процедуры в код обработки, а затем в коде вызвать эту обработку и далее вызывать эти процедуры из обработки.
Я также рекомендовал бы подобные процедуры, и особенно, функции, делать максимально «универсальными», т.е. такими, которые могли бы возвращать различные значения, в зависимости от поданных параметров. Т.е. не создавать 10 функций, каждая из которых возвращает какое-то одно, похожее на другое поле. Например, одна функция возвращает дату приема сотрудника, другая – дату увольнения, третья – должность. Вместо 10 функций сделаем одну универсальную.
Приведу упрощенный пример, чтобы была понятна суть. Пусть есть функция («самописная», вызывается из «самописного» общего модуля «МойМодуль»), с именем, ну например: «ВернутьДанныеПоСотруднику(ДатаПоиска,ПолеВозврата,Сотрудник)». Внутри функции имеется запрос, который возвращает по указанному сотруднику (параметр «Сотрудник») на заданную дату (параметр «ДатаПоиска») целый набор полей кадровых и зарплатных данных – должность, подразделение, оклад, количество ставок, дата приема и т.п. Однако функция возвращает не весь результат запроса, а только то поле, которое передано в параметре «ПолеВозврата». Например, мы пишем в коде:
Сотрудник = Справочники.Сотрудники.НайтиПоНаименованию(«Иванов Иван Иванович»);
ДолжностьСотрудника = МойМодуль.ВернутьДанныеПоСотруднику(ТекущаяДата(),«Должность»,Сотрудник);
ДатаПриемаСотрудникаСотрудника = МойМодуль.ВернутьДанныеПоСотруднику(ТекущаяДата(),«ДатаПриема»,Сотрудник)
И т.п. Внутри самой функции получается примерная программная конструкция вида:
Запрос = Новый Запрос("
//тут текст запроса с выборкой множества полей
");
Запрос.УстановитьПараметр("ДатаПоиска", ДатаПоиска);
Запрос.УстановитьПараметр("Сотрудник", Сотрудник);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Количество() > 0 тогда
Выборка.Следующий();
Попытка
Возврат Выборка[ПолеВозврата];
Исключение
Возврат Сотрудник;
КонецПопытки;
иначе
Возврат Сотрудник;
КонецЕсли;
В итоге мы имеем универсальную функцию-«черный ящик», подавая на вход имя нужного нам поля, мы получаем в результате только то, что нам нужно, и не плодим множества ненужных нам функций. Если мы ошибемся с именем поля – результат вернет нам сотрудника.
Доработка функции очень легкая – добавляем в запрос с выборкой полей новые поля, и потом просто можно вызывать «новые» поля в коде, не меняя самой конструкции вызова. Конечно, надо следить, чтобы запрос-выборка не был перегружен и усложнен без нужды, но поскольку мы изначально выбираем данные только для одного сотрудника – он никогда не будет слишком уж «тяжелым».