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

04.03.19

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

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Пример к статье. Базы и пакетные файлы для сборки.
.zip 240,55Kb
3
3 Скачать (1 SM) Купить за 1 850 руб.

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

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

27900 руб.

01.04.2020    145911    645    358    

235

Обновление 1С Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Абонемент ($m)

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

1 стартмани

26.09.2024    371    1    milkers    2    

7

Обновление 1С Пользователь Платформа 1С v8.3 1С:Управление торговлей 11 Россия Бесплатно (free)

Вышел новый релиз для УТ11 5.19.63. На копии базы было выполнено обновление и вылезли проблемы с номенклатурой, подлежащей маркировке. В публикации описаны проблемы, обнаруженные в копии базы конкретной организации.

24.09.2024    514    gull22    1    

7

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

Как исправить медленное сравнение конфигурации с файлом cf, сохраненным из хранилища.

17.09.2024    3963    vatkir    14    

9

Обновление 1С Пользователь Платформа 1С v8.3 1С:Управление торговлей 11 Абонемент ($m)

Упрощенное обновление конфигураций 1С (предпочтительно самописных) с помощью батника и Яндекс Диска (по публичной ссылке)

1 стартмани

22.08.2024    448    0    user1694357    0    

3

Обновление 1С Системный администратор Россия Абонемент ($m)

На ИТС есть статья, в которой поверхностно описан процесс автоматического обновления тонких клиентов. В качестве примера, что логично, представлены методы конфигурации 1С. Но, в отличие от того же управления списками баз, для обновления не требуется хранить информацию, потому я решил переписать код на php, чтобы можно было отвязаться от 1С. Не работает для файловых баз, подключенных как File="ПутьКПапкеБазы"; (а жаль), для опубликованных файловых - работает.

1 стартмани

20.08.2024    501    MikeSh    10    

1

Обновление 1С Программист Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бухгалтерский учет Бесплатно (free)

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

05.08.2024    643    NikiforovVA    0    

1

Обновление 1С Программист Платформа 1С v8.3 Платформа 1C v8.2 Конфигурации 1cv8 Бесплатно (free)

По нашему опыту, есть 2 ситуации, когда хочется отдать обновление нетиповой 1С кому-то другому. А) Если конфигурация и её доработки отлично знакомы, но не хочется заниматься рутиной. Б) Когда обновление длительно откладывалось, накопился «снежный ком» изменений, а команда, которая их делала, давно и неоднократно менялась.

26.06.2024    1138    1c-izh    4    

5
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. pm74 203 04.03.19 09:27 Сейчас в теме
где и как определяется порядок выполнения процедур
2. Alxby 1111 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 1111 31.05.19 16:49 Сейчас в теме
(3)Спасибо за ссылки! Все-таки это не совсем (а точнее совсем не) наследование классов. У меня не было цели моделировать соответствующий подход ООП. В Вашем примере, насколько я понял, дочерний класс унаследован от родительского и точно известно, метод какого родительского класса будет выполнен при вызове из дочернего. В моем же случае итоговая конфигурация может быть собрана из произвольного набора библиотек, поэтому вызов «предыдущего» метода означает вызов метода какой-то библиотеки, которая стоит предыдущей в последовательности. Больше всего это похоже на механизм hook-ов или подписок на события в 1С – мы выполняем свою реализацию какого-то существующего функционала, и при необходимости передаем управление дальше по цепочке стандартному обработчику. Или наоборот – выполняем стандартный обработчик, а потом свой. Причем в общем случае мы не знаем ни о наличии других обработчиков, ни об их порядке.
Леонов Александр; +1 Ответить
Оставьте свое сообщение