Иерархия библиотек. Автоматическое обновление или как отказаться от переопределяемых модулей

04.03.19

База данных - Обновление 1С

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

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

Наименование Файл Версия Размер
Пример к статье. Базы и пакетные файлы для сборки.
.zip 240,55Kb
3
.zip 240,55Kb 3 Скачать

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

...трудоемкость последующих обновлений переопределяемых модулей в конфигурации-потребителе...

а также

При обновлении версии библиотеки в конфигурации-потребителе особого внимания требуют модули корневого объекта конфигурации и переопределяемые общие модули, так как автоматическое обновление таких «узких мест» конфигурации-потребителя невозможно. 

А почему бы нам не сделать то, что кажется невозможным? Попробуем это на простом примере.

Итак, предположим нашей целью является автоматизация процесса продаж. Допустим, что в нашей системе должен быть документ "Продажа" с табличной частью "Товары", содержащей реквизиты "Номенклатура", "Цена", "Количество" и "Сумма". Базовым функционалом будет являться расчет 

Сумма = Количество * Цена

Этот расчет – функционал базовой библиотеки, которая будет лежать в основе остальных библиотек.

Возможно нам понадобится расчет налогов. Не вдаваясь в тонкости налогового учета, допустим что налог – это некая сумма, рассчитанная по ставке и просто добавляемая к основной сумме.

Сумма = Сумма * (100 + Ставка) / 100

Аналогичным образом формализуем учет скидок:

Сумма = Сумма * (100 - Скидка) / 100

Каждая из этих формул, а также объекты, содержащие все необходимые для расчета данные, реализованы в своей библиотеке. Но проблема в том, что запуск расчета производится в форме документа, в базовой библиотеке, в которой может быть ничего не известно о функционале, да и вообще о наличии других библиотек. Классический подход подразумевает реализацию в базовой библиотеке переопределяемого модуля расчета суммы, который в итоговой конфигурации должен быть дополнен (изменен) вызовами методов других библиотек. 

Но можно поступить иначе. Предположим, в итоговой конфигурации у нас есть некий перечень методов, вызывая которые, мы сделаем все необходимые расчеты. Список этих методов может быть различным, в зависимости от конкретной конфигурации. Каждый метод реализован в модуле своей библиотеки. Все что нужно сделать при запуске расчета в базовой библиотеке – это передать такой перечень механизму, который обработает каждый элемент этого списка. Но где задать нам этот список методов? Опять использовать переопределяемый модуль и получить проблемы с обновлением? А пусть он создается сам, в зависимости от наличия той или иной библиотеки! Давайте придумаем некий механизм, который в зависимости от наличия каких-нибудь объектов метаданных, поймет, какие методы каких модулей надо включить в список для выполнения расчета. Здесь появляется небольшая проблема: для поиска среди объектов метаданных можно использовать только имя, а объекты одного вида с одинаковым именем создавать нельзя. Т.е. нельзя в каждой библиотеке создать свой общий модуль с именем "РасчетСуммы" и объединить их в одну конфигурацию. Но можно создавать подсистемы с одинаковыми именами, если они принадлежат разным родителям. Получается следующая схема:

Для каждой библиотеки создана своя подсистема, в которой есть подсистема с именем "РасчетСумм". В составе последних включены общие модули, в которых реализован экспортный метод, выполняющий расчет (имена методов также одинаковы). Подсистемы библиотек лежат в пределах одной группы, для упрощения поиска. Таким образом, ориентируясь на имя подсистем "РасчетСумм" мы легко можем получить список модулей и методов для проведения расчета. 

Несколько слов по поводу выполнения этих методов. Самый простой вариант – создание некоего "менеджера", который будет последовательно вызывать каждую процедуру. Но я решил остановиться на другом способе – вызывать самую последнюю процедуру из списка и передавать ей управление. Решение о вызове предыдущего метода полностью возлагается на эту процедуру. Такой вариант более гибок – предыдущий метод может быть вызван в любом месте, а может и быть просто проигнорирован, если в нем нет нужды. Порядок методов в списке определяется порядком расположения подсистем библиотек внутри "ПереопределяемыеОбъектыБиблиотек".

Как это выглядит на практике:

В документе "Продажа" реализована команда:

&НаСервере
Процедура РассчитатьНаСервере(ИД)	
	ПараметрыРасчета = Объект.Товары.НайтиПоИдентификатору(ИД);
	Последовательность = УправлениеБиблиотекамиКлиентСервер.ПоследовательностьМодулейПроцедур("РасчетСумм");
	УправлениеБиблиотеками.ВыполнитьПредыдущуюПроцедуруНаСервере(ПараметрыРасчета, Последовательность);	
КонецПроцедуры

&НаКлиенте
Процедура Рассчитать(Команда)
	ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
	Если ТекущиеДанные <> Неопределено   Тогда   
		РассчитатьНаСервере(ТекущиеДанные.ПолучитьИдентификатор());	
	КонецЕсли; 	
КонецПроцедуры

В серверной процедуре получаем последовательность описаний методов и запускаем выполнение последнего из них. В нашем случае это будет РасчетСуммСоСкидкой.РасчетСумм

Процедура РасчетСумм(Параметр,Последовательность)Экспорт
	УправлениеБиблиотеками.ВыполнитьПредыдущуюПроцедуруНаСервере(Параметр, Последовательность);
	Скидка = РегистрыСведений.СкидкиНоменклатуры.Получить(новый Структура("Номенклатура",Параметр.Номенклатура)).Скидка;
	Параметр.Сумма = Параметр.Сумма * (100 - Скидка) / 100;
КонецПроцедуры

В процессе расчета мы сначала выполняем предыдущий метод РасчетСуммСНалогом.РасчетСумм, а затем производим обработку скидки.

Перед налоговым расчетом мы так же вызываем предыдущий метод РасчетСуммБазовый.РасчетСумм:

Процедура РасчетСумм(Параметр,Последовательность)Экспорт
	УправлениеБиблиотеками.ВыполнитьПредыдущуюПроцедуруНаСервере(Параметр, Последовательность);
	Параметр.Сумма = Параметр.Сумма * (100 + Константы.СтавкаНалога.Получить()) / 100;
КонецПроцедуры

В котором выполняем самый первый расчет.

Процедура РасчетСумм(Параметр,Последовательность)Экспорт
	УправлениеБиблиотеками.ВыполнитьПредыдущуюПроцедуруНаСервере(Параметр, Последовательность);
	Параметр.Сумма = Параметр.Количество * Параметр.Цена;
КонецПроцедуры

в последнем случае метод  УправлениеБиблиотеками.ВыполнитьПредыдущуюПроцедуруНаСервере не выполнит ничего, так как предыдущих процедур не осталось.

Описанный выше механизм можно применять и для других целей, например для создания общего списка строковых или табличных ресурсов. Вот так реализовано описание конфигурации, которое создается на основе табличных макетов, принадлежащих разным библиотекам:

В обработке "Инфо" создается общий табличный документ:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	ОписанияМакетов = УправлениеБиблиотекамиВызовСервера.ДопОбъектыПоВиду("Инфо");	
	Для каждого ОписаниеМакета Из ОписанияМакетов Цикл  		
		Таблица.Вывести(ПолучитьОбщийМакет(ОписаниеМакета.ИмяОбъекта));
	КонецЦикла; 	
КонецПроцедуры

Как внедрять или обновлять получившиеся библиотеки.

Процесс внедрения и обновления библиотек – обычное сравнение объединение конфигураций. В этом режиме надо отметить объекты по подсистемам файла: 

и выполнить объединение. При этом никаких других действий, таких как редактирования модулей, делать не надо. 

Подобное объединение можно проводить в автоматическом режиме. Для этого служит специальная команда пакетного режима конфигуратора. Пример такой команды:

1cv8.exe DESIGNER /F"c:\bases\prod\" /MergeCfg"c:\bases\lib2.cf" -Settings"c:\bases\UpdLib2Settings.xml"

здесь c:\bases\prod\ - путь к файловой базе, c:\bases\lib1.cf - конфигурация библиотеки, c:\bases\UpdLib1Settings.xml  - файл настроек объединения.

Файл настроек нужен для того, чтобы указать платформе, какие объекты следует объединить и правила такого объединения. Описание формата файла: https://its.1c.ru/db/v8314doc#bookmark:adm:TI000000713 . Пример файла:

<?xml version="1.0" encoding="UTF-8"?>
<Settings xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://v8.1c.ru/8.3/config/merge/settings" version="1.1">
	<Parameters>
		<AllowMainConfigurationObjectDeletion>true</AllowMainConfigurationObjectDeletion>
	</Parameters>
	<Objects>
		<Configuration>
			<MergeRule>DoNotMerge</MergeRule>
		</Configuration>
		<Object fullNameInSecondConfiguration="Подсистема.Скидки">
			<MergeRule>GetFromSecondConfiguration</MergeRule>
			<Subsystem configuration="Second" includeObjectsFromSubordinateSubsystems="true">
				<MergeRule>GetFromSecondConfiguration</MergeRule>
			</Subsystem>
		</Object>
		<Object fullName="Подсистема.Скидки">
			<MergeRule>GetFromSecondConfiguration</MergeRule>
			<Subsystem configuration="Main" includeObjectsFromSubordinateSubsystems="true">
				<MergeRule>GetFromSecondConfiguration</MergeRule>
			</Subsystem>
		</Object>
		<Object fullNameInSecondConfiguration="Подсистема.ПереопределяемыеОбъектыБиблиотек.Подсистема.Скидки">
			<MergeRule>GetFromSecondConfiguration</MergeRule>
			<Subsystem configuration="Second" includeObjectsFromSubordinateSubsystems="true">
				<MergeRule>GetFromSecondConfiguration</MergeRule>
			</Subsystem>
		</Object>
		<Object fullName="Подсистема.ПереопределяемыеОбъектыБиблиотек.Подсистема.Скидки">
			<MergeRule>GetFromSecondConfiguration</MergeRule>
			<Subsystem configuration="Main" includeObjectsFromSubordinateSubsystems="true">
				<MergeRule>GetFromSecondConfiguration</MergeRule>
			</Subsystem>
		</Object>
	</Objects>
</Settings>

здесь мы указываем, что не меняем свойства конфигурации, разрешаем удалять объекты, помечаем для объединения объекты нужных нам подсистем. Обратите внимание, что каждую подсистему мы указываем дважды: в новой конфигурации (для добавленных и измененных объектов) и в основной конфигурации (для измененных и удаленных объектов).

В результате обновления мы получим итоговую конфигурацию, в которой может быть (а может и не быть) одна или две библиотеки. Существуют несложные средства, которые позволят нам так же автоматически поместить эти изменения в хранилище 1С или же в Git.

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

Конечно же, предлагаемый подход не панацея. Так, он не поможет при работе с определяемыми типами, с переопределяемыми макетами и некоторыми другими объектами, но облегчить работу он может значительно. Надо отметить, что и стандартные возможности платформы включают в себе нечто подобное, хотя и менее функциональное. Это - подписки на события.

Рассмотренный пример вы можете увидеть в приложенном к статье файле. Это архив, содержащий в себе:

  • Папка base – базовая библиотека
  • Папки lib1, lib2 – 2 библиотеки
  • Папка prod – итоговая конфигурация
  • 1_CreateBase.bat – пакетный файл для создания итоговой конфигурации на основе базовой библиотеки
  • 2_AddLib1.bat, 3_AddLib2.bat – пакетные файлы для первоначального внедрения в итоговую конфигурацию библиотек lib1, lib2
  • 4_UpdLib1.bat, 5_UpdLib2.bat – пакетные файлы для обновления в итоговой конфигурации библиотек lib1, lib2
  • *Settings.xml – файлы с настройками объединения

Желательно чтобы все эти папки и файлы находились в каталоге c:\bases, так как в пакетных файлах используются абсолютные пути. Также надо указать путь к файлу 1cv8.exe в зависимости от версии платформы.

Библиотеки Переопределяемые CI CD Непрерывная интеграция автоматическое обновление объединение конфигураций

См. также

Обновление для КА 1.1, ЗУП 2.5, БУХ 2.0: НДС, ЕФС-1, Расчет страховых взносов, Мобилизация, Статистика, Электронные трудовые книжки, 2-НДФЛ, Регламентированная отчетность, Кадровый учет, Прослеживаемость импортных товаров

Зарплата Регламентированный учет и отчетность Кадровый учет Обновление 1С Платформа 1С v8.3 Сложные периодические расчеты 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Зарплата и Управление Персоналом 2.5 Бухгалтерский учет Налоговый учет Управленческий учет Акцизы ЕНВД ЕСН Земельный налог ИП, ПБОЮЛ, КФХ Налог на имущество Налог на прибыль НДС НДФЛ ФОМС, ЕФС Транспортный налог УСН ПСН (патентная система налогообложения) Платные (руб)

Обновления для конфигураций: КА 1.1; ЗУП 2.5; БУХ 2.0; КА 1.1 Комплексная автоматизация торговли алкогольной продукцией; КА 1.1 Комплексный учет сельскохозяйственного предприятия

19900 руб.

01.04.2020    140422    676    352    

232

Автоматическое подтверждение легальности обновления базы или как обновить 100 типовых баз 1С за 5 часов

DevOps и автоматизация разработки Обновление 1С Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Расширение для конфигураций 1С для автоматического подтверждения легальности обновления и выполнения обработчиков обновления при пакетном автоматическом обновлении большого числа баз 1С. А также сам модуль обработки по автоматическому обновлению баз.

2400 руб.

08.05.2019    24117    58    26    

26

Скрипт для обновления базы с расширением из хранилища

Обновление 1С Платформа 1С v8.3 Бесплатно (free)

Небольшая оптимизация рабочего времени через скрипт обновления базы 1С с расширением из хранилища конфигураций.

22.01.2024    1053    ke.92@mail.ru    2    

24

Многопоточное обновление 1С: Управление холдингом

Обновление 1С 8.3.14 1С:Управление холдингом Абонемент ($m)

Что делать, если обновление базы в режиме предприятия выполняется значительно больше вашего технологического окна, даже если это окно - с вечера пятницы и до утра понедельника.

1 стартмани

10.01.2024    3117    saver77    18    

24

Не обновляется типовая конфигурация 1С через конфигуратор

Обновление 1С Платформа 1С v8.3 Россия Бесплатно (free)

Столкнулся с проблемой. Нужно было поднять до текущего релиза Розницу 2.3. Обновлял по старинке, через конфигуратор (база клиент-серверная). Указывал логин и пароль, ждал скачивания обновления и обновлял. Но после накатывания 5 релизов следующий устанавливаться не хотел, а точнее конфигуратор гордо говорил, что обновлений больше нет. Решение нашел здесь на форуме и хочу зафиксировать. Чтобы самому не забыть и передать опыт начинающим.

29.11.2023    1264    shestopalovpro    4    

7

Принудительный запуск дополнительных процедур обработки данных после обновления

Обновление 1С Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Ручной запуск процедур обработки обработчиков после обновлений. Может быть полезно стажерам, консультантам, разработчикам, администраторам, всем, кто обновляет информационные базы.

1 стартмани

20.11.2023    560    6    IvanTerentev    0    

2

Ошибка SDBL "Нет таблицы или отсутствует RefSelf"

Инструменты администратора БД Обновление 1С Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Известно несколько способов разной степени шаманства. Предлагаю ещё один, проверенный на практике и базирующийся на точном понимании своих действий.

15.11.2023    1467    Yashazz    1    

9
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. pm74 199 04.03.19 09:27 Сейчас в теме
где и как определяется порядок выполнения процедур
2. Alxby 1134 04.03.19 10:30 Сейчас в теме
(1)
Порядок методов в списке определяется порядком расположения подсистем библиотек внутри "ПереопределяемыеОбъектыБиблиотек".
Первой вызывается последняя процедура списка. В каждой процедуре вызов предыдущей может располагаться как в начале, до ее выполнения, так и в конце, как впрочем и в любом другом месте. Вызов предыдущей процедуры может и вовсе отсутствовать.
Леонов Александр; +1 Ответить
3. sdf_tm 01.04.19 13:35 Сейчас в теме
Супер!
Вы изобрели наследование классов в 1с :)

кстати - в аксапте именно super() вызывает родительский класс (из вышестоящего слоя)
см. напр

http://gennadyyun.blogspot.com/2007/07/1_23.html
http://gennadyyun.blogspot.com/2007/07/2_23.html
http://gennadyyun.blogspot.com/2007/07/x-1.html
4. Alxby 1134 31.05.19 16:49 Сейчас в теме
(3)Спасибо за ссылки! Все-таки это не совсем (а точнее совсем не) наследование классов. У меня не было цели моделировать соответствующий подход ООП. В Вашем примере, насколько я понял, дочерний класс унаследован от родительского и точно известно, метод какого родительского класса будет выполнен при вызове из дочернего. В моем же случае итоговая конфигурация может быть собрана из произвольного набора библиотек, поэтому вызов «предыдущего» метода означает вызов метода какой-то библиотеки, которая стоит предыдущей в последовательности. Больше всего это похоже на механизм hook-ов или подписок на события в 1С – мы выполняем свою реализацию какого-то существующего функционала, и при необходимости передаем управление дальше по цепочке стандартному обработчику. Или наоборот – выполняем стандартный обработчик, а потом свой. Причем в общем случае мы не знаем ни о наличии других обработчиков, ни об их порядке.
Леонов Александр; +1 Ответить
Оставьте свое сообщение