From 34d893461370f970dd1d5018476e9b1f0de528c4 Mon Sep 17 00:00:00 2001 From: Maximov Valery Date: Wed, 19 Nov 2025 20:39:07 +0300 Subject: [PATCH 1/9] =?UTF-8?q?=D0=B8=D0=BD=D0=BA=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BF=D0=B0?= =?UTF-8?q?=D1=80=D1=81=D0=B5=D1=80=20=D0=B4=D0=BB=D1=8F=20bsl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/antlr/BSLParser.g4 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/antlr/BSLParser.g4 b/src/main/antlr/BSLParser.g4 index 5fd02905..3cf88b5d 100644 --- a/src/main/antlr/BSLParser.g4 +++ b/src/main/antlr/BSLParser.g4 @@ -23,6 +23,7 @@ parser grammar BSLParser; options { tokenVocab = BSLLexer; + incremental = true; } // ROOT From 98a0367dfae79e2127fadd1524350b7eb23d9c85 Mon Sep 17 00:00:00 2001 From: Maximov Valery Date: Thu, 20 Nov 2025 15:55:47 +0300 Subject: [PATCH 2/9] deps --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5f6f1056..4e6b11a2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -49,13 +49,13 @@ gitVersioning.apply { } dependencies { - antlr("io.github.1c-syntax", "antlr4", "0.2.0-rc.1") + antlr("io.github.1c-syntax", "antlr4", "0.2.0-alpha.1") // stat analysis compileOnly("com.github.spotbugs", "spotbugs-annotations", "4.8.6") // testing - testImplementation("io.github.1c-syntax", "bsl-parser-testing", "0.4.0-rc.1") + testImplementation("io.github.1c-syntax", "bsl-parser-testing", "0.4.0-alpha.1") testImplementation("org.junit.jupiter", "junit-jupiter-api", "5.11.4") testImplementation("org.junit.jupiter", "junit-jupiter-engine", "5.11.4") From e15af016c3c25b6e9a3cd4db87eb53196624e32a Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Sat, 29 Nov 2025 11:18:22 +0100 Subject: [PATCH 3/9] Create .gitkeep --- src/jmh/resources/.gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/jmh/resources/.gitkeep diff --git a/src/jmh/resources/.gitkeep b/src/jmh/resources/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/jmh/resources/.gitkeep @@ -0,0 +1 @@ + From a7f4a6550982d6774f5fdf52cd5b97e1f1b9c195 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Sat, 29 Nov 2025 11:18:34 +0100 Subject: [PATCH 4/9] Add files via upload --- src/jmh/resources/Module.bsl | 47361 +++++++++++++++++++++++++++++++++ 1 file changed, 47361 insertions(+) create mode 100644 src/jmh/resources/Module.bsl diff --git a/src/jmh/resources/Module.bsl b/src/jmh/resources/Module.bsl new file mode 100644 index 00000000..7767d748 --- /dev/null +++ b/src/jmh/resources/Module.bsl @@ -0,0 +1,47361 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2024, ООО 1С-Софт +// Все права защищены. Эта программа и сопроводительные материалы предоставляются +// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0) +// Текст лицензии доступен по ссылке: +// https://creativecommons.org/licenses/by/4.0/legalcode +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +#Область СлужебныйПрограммныйИнтерфейс + +#Область ОсновныеПроцедурыИФункции + +// Добавляет пользователя в группу доступа, соответствующую поставляемому профилю. +// Группа доступа определяется по идентификатору ссылки поставляемого профиля. +// Если группа доступа не будет найдена, она будет создана. +// +// Параметры: +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей - участник, которого нужно включить в группу доступа. +// +// ПоставляемыйПрофиль - Строка - строка идентификатора поставляемого профиля. +// - СправочникСсылка.ПрофилиГруппДоступа - ссылка на профиль, который +// создан по описанию в модуле УправлениеДоступомПереопределяемый +// в процедуре ПриЗаполненииПоставляемыхПрофилейГруппДоступа. +// Профили с непустым списком видов доступа не поддерживаются. +// Профиль групп доступа Администратор не поддерживается. +// +Процедура ВключитьПользователяВГруппуДоступа(Пользователь, ПоставляемыйПрофиль) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.ВключитьПользователяВГруппуДоступа"); + + ОбработатьСвязьПользователяСГруппойДоступа(Пользователь, ПоставляемыйПрофиль, Истина); + +КонецПроцедуры + +// Обновляет состав пользователей указанных групп исполнителей. +// +// Требуется вызывать при изменении состава пользователей у групп исполнителей, +// например, у групп исполнителей задач. +// +// В качестве значений параметра передается группы исполнителей, состав которых изменился. +// +// Параметры: +// ГруппыИсполнителей - СправочникСсылка.ГруппыИсполнителейЗадач - одна группа, +// - Массив из СправочникСсылка.ГруппыИсполнителейЗадач - несколько групп, +// - Неопределено - без отбора. +// +Процедура ОбновитьПользователейГруппИсполнителей(ГруппыИсполнителей = Неопределено) Экспорт + + Если ТипЗнч(ГруппыИсполнителей) = Тип("Массив") И ГруппыИсполнителей.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Параметры = Новый Структура; + Параметры.Вставить("ГруппыИсполнителей", ГруппыИсполнителей); + + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); + +КонецПроцедуры + +// Проверяет существование вида доступа с указанным именем. +// Применяется для автоматизации условного встраивания подсистем. +// +// Параметры: +// ИмяВидаДоступа - Строка - имя вида доступа. +// +// Возвращаемое значение: +// Структура: +// +Функция ВидДоступаСуществует(ИмяВидаДоступа) Экспорт + + Возврат СвойстваВидаДоступа(ИмяВидаДоступа) <> Неопределено; + +КонецФункции + +// Возвращает вид интерфейса пользователя для настройки доступа. +// +// Возвращаемое значение: +// Булево +// +Функция УпрощенныйИнтерфейсНастройкиПравДоступа() Экспорт + + УпрощенныйИнтерфейс = Ложь; + УправлениеДоступомПереопределяемый.ПриОпределенииИнтерфейсаНастройкиДоступа(УпрощенныйИнтерфейс); + + Возврат УпрощенныйИнтерфейс = Истина; + +КонецФункции + +// Возвращает массив разрешенных значений указанных типов в рамках всех групп доступа. +// Используется в процедуре НастроитьОтборыДинамическогоСписка для ускорения открытия динамических списков. +// +// Параметры: +// Таблица - Строка - полное имя объекта метаданных, например, "Документ.РасходнаяНакладная". +// ТипЗначений - Тип - тип значений доступа, разрешенные значения которых нужно вернуть. +// - Массив - массив указанных выше типов. +// +// Значения - Неопределено - не учитывать. +// - Массив - массив значений типов, указанных в параметре ТипЗначений. +// +// Пользователь - Неопределено - вернуть разрешенные значения для авторизованного пользователя. +// - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи - вернуть +// разрешенные значения для указанного пользователя. +// +// ВернутьВсе - Булево - если установить Истина, тогда будут возвращены все значение даже тогда, +// когда их более 100. +// +// Возвращаемое значение: +// Неопределено - либо все значения разрешены для типов, указанных в параметре ТипЗначений, +// либо (когда ВернутьВсе = Ложь) количество разрешенных значений превышает 100. +// Массив - ссылки разрешенных значений указанных типов. +// +Функция РазрешенныеЗначенияДляДинамическогоСписка(Таблица, ТипЗначений, Значения = Неопределено, Пользователь = Неопределено, ВернутьВсе = Ложь) Экспорт + + Если ТипЗнч(ТипЗначений) <> Тип("Массив") Тогда + ТипыЗначений = Новый Массив; + ТипыЗначений.Добавить(ТипЗначений); + + ИначеЕсли ТипЗначений.Количество() = 0 Тогда + Возврат Неопределено; + Иначе + ТипыЗначений = ТипЗначений; + КонецЕсли; + + УстановитьПривилегированныйРежим(Истина); + + ТекстЗапросаЗначенийБезГрупп = + "ВЫБРАТЬ ПЕРВЫЕ 101 + | ЗначенияБезГрупп.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | &ЗначениеПустойСсылки КАК Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ЗначенияБезПустойСсылки.Ссылка + | ИЗ + | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ЗначенияБезГрупп + |ГДЕ + | ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ГруппыДоступаПользователя КАК ГруппыДоступа + | ГДЕ + | ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступа КАК Значения + | ГДЕ + | Значения.ГруппаДоступа = ГруппыДоступа.Ссылка + | И Значения.ЗначениеДоступа = ЗначенияБезГрупп.Ссылка) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ = ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ГДЕ + | ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступа.Ссылка + | И ТИПЗНАЧЕНИЯ(ЗначенияПоУмолчанию.ТипЗначенийДоступа) = ТИПЗНАЧЕНИЯ(ЗначенияБезГрупп.Ссылка) + | И ЗначенияПоУмолчанию.ВсеРазрешены = ЛОЖЬ) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ) + | И ЗначенияБезГрупп.Ссылка В(&Значения)"; + + Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда + ТекстЗапросаЗначенийБезГрупп = СтрЗаменить(ТекстЗапросаЗначенийБезГрупп, "ПЕРВЫЕ 101", ""); // @query-part-1 + КонецЕсли; + Если ТипЗнч(Значения) <> Тип("Массив") Тогда + ТекстЗапросаЗначенийБезГрупп = СтрЗаменить(ТекстЗапросаЗначенийБезГрупп, "ЗначенияБезГрупп.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 + КонецЕсли; + + ТекстЗапросаЗначенийСГруппами = + "ВЫБРАТЬ ПЕРВЫЕ 101 + | ЗначенияСГруппами.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | &ЗначениеПустойСсылки КАК Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ЗначенияБезПустойСсылки.Ссылка + | ИЗ + | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ЗначенияСГруппами + |ГДЕ + | ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ГруппыДоступаПользователя КАК ГруппыДоступа + | ГДЕ + | ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступа КАК Значения + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначений + | ПО + | Значения.ГруппаДоступа = ГруппыДоступа.Ссылка + | И Значения.ЗначениеДоступа = ГруппыЗначений.ГруппаЗначенийДоступа + | И ГруппыЗначений.ЗначениеДоступа = ЗначенияСГруппами.Ссылка) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ = ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ГДЕ + | ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступа.Ссылка + | И ТИПЗНАЧЕНИЯ(ЗначенияПоУмолчанию.ТипЗначенийДоступа) = ТИПЗНАЧЕНИЯ(ЗначенияСГруппами.Ссылка) + | И ЗначенияПоУмолчанию.ВсеРазрешены = ЛОЖЬ) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ) + | И ЗначенияСГруппами.Ссылка В(&Значения)"; + + Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда + ТекстЗапросаЗначенийСГруппами = СтрЗаменить(ТекстЗапросаЗначенийСГруппами, "ПЕРВЫЕ 101", ""); // @query-part-1 + КонецЕсли; + Если ТипЗнч(Значения) <> Тип("Массив") Тогда + ТекстЗапросаЗначенийСГруппами = СтрЗаменить(ТекстЗапросаЗначенийСГруппами, "ЗначенияСГруппами.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 + КонецЕсли; + + ТекстЗапросаВсеЗначения = + "ВЫБРАТЬ ПЕРВЫЕ 101 + | ВсеЗначения.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | &ЗначениеПустойСсылки КАК Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ЗначенияБезПустойСсылки.Ссылка + | ИЗ + | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ВсеЗначения + |ГДЕ + | ВсеЗначения.Ссылка В(&Значения)"; + + Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда + ТекстЗапросаВсеЗначения = СтрЗаменить(ТекстЗапросаВсеЗначения, "ПЕРВЫЕ 101", ""); // @query-part-1 + КонецЕсли; + Если ТипЗнч(Значения) <> Тип("Массив") Тогда + ТекстЗапросаВсеЗначения = СтрЗаменить(ТекстЗапросаВсеЗначения, "ВсеЗначения.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 + КонецЕсли; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ТекстЗапроса = ""; + Если Пользователь <> Неопределено Тогда + АвторизованныйПользователь = Пользователь; + Иначе + АвторизованныйПользователь = Пользователи.АвторизованныйПользователь(); + КонецЕсли; + ДобавитьТекущегоПользователя = Ложь; + ЕстьИспользуемыеВидыДоступа = Ложь; + ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); + + Для Каждого ТекущийТип Из ТипыЗначений Цикл + Свойства = СвойстваВидовДоступа.ПоТипамЗначений.Получить(ТекущийТип); // См. СвойстваВидаДоступа + Если Свойства = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Тип ""%1"" не является типом значений доступа'"), Строка(ТекущийТип)); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ИспользуемыеВидыДоступа.Получить(Свойства.Ссылка) = Неопределено Тогда + ТекущийТекстЗапроса = ТекстЗапросаВсеЗначения; + Иначе + Если СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами.Получить(ТекущийТип) = Неопределено Тогда + ТекущийТекстЗапроса = ТекстЗапросаЗначенийБезГрупп; + Иначе + ТекущийТекстЗапроса = ТекстЗапросаЗначенийСГруппами; + КонецЕсли; + ЕстьИспользуемыеВидыДоступа = Истина; + КонецЕсли; + ТаблицаЗначенийДоступа = Метаданные.НайтиПоТипу(ТекущийТип).ПолноеИмя(); + ТекущийТекстЗапроса = СтрЗаменить(ТекущийТекстЗапроса, "&ТаблицаЗначенийДоступа", ТаблицаЗначенийДоступа); + ТекущийТекстЗапроса = СтрЗаменить(ТекущийТекстЗапроса, "&ЗначениеПустойСсылки", + "ЗНАЧЕНИЕ(" + ТаблицаЗначенийДоступа + ".ПустаяСсылка)"); // @query-part-2 + Если ЗначениеЗаполнено(ТекстЗапроса) Тогда + ОбъединитьЗапросСЗапросом(ТекстЗапроса, ТекущийТекстЗапроса); + Иначе + ТекстЗапроса = ТекущийТекстЗапроса; + КонецЕсли; + Если ТекущийТип = ТипЗнч(АвторизованныйПользователь) Тогда + ДобавитьТекущегоПользователя = Истина; + КонецЕсли; + КонецЦикла; + + Если Не ЕстьИспользуемыеВидыДоступа Тогда + Возврат Неопределено; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИмяОсновнойТаблицыСписка", Таблица); + Запрос.УстановитьПараметр("АвторизованныйПользователь", АвторизованныйПользователь); + Запрос.Текст = ТекстЗапросаГруппДоступа(); + Если ТипЗнч(Значения) = Тип("Массив") Тогда + Запрос.УстановитьПараметр("Значения", Значения); + КонецЕсли; + + ДобавитьЗапросВПакет(Запрос.Текст, ТекстЗапроса); + + Выгрузка = Запрос.Выполнить().Выгрузить(); + + Если ТипЗнч(Значения) <> Тип("Массив") + И Не ВернутьВсе + И Выгрузка.Количество() > 100 Тогда + + Возврат Неопределено; + КонецЕсли; + + РазрешенныеЗначения = Выгрузка.ВыгрузитьКолонку("Ссылка"); + + Если ДобавитьТекущегоПользователя Тогда + РазрешенныеЗначения.Добавить(АвторизованныйПользователь); + КонецЕсли; + + Возврат РазрешенныеЗначения; + +КонецФункции + +// Добавляет администраторов системы в группу доступа, +// связанную с предопределенным профилем ОткрытиеВнешнихОтчетовИОбработок. +// +Процедура УстановитьПравоОткрытияВнешнихОтчетовИОбработок(ОткрытиеРазрешено) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.УстановитьПравоОткрытияВнешнихОтчетовИОбработок"); + + СвойстваПрофиля = ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок(); + СвойстваПрофиля.Вставить("Ссылка", Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( + СвойстваПрофиля.Имя, Истина)); + + ИдентификаторРоли = ОбщегоНазначения.ИдентификаторОбъектаМетаданных( + Метаданные.Роли.ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок); + + // В упрощенном интерфейсе группу доступа создавать не требуется (только профиль). + УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); + Если Не УпрощенныйИнтерфейс Тогда + ГруппаПрофиля = ГруппаДоступаОткрытиеВнешнихОтчетовИОбработок(СвойстваПрофиля); + КонецЕсли; + + Если ОткрытиеРазрешено Тогда + // Включение администраторов в группы доступа с этим профилем. + РольАдминистратора = Метаданные.Роли.АдминистраторСистемы; + ПользователиИБ = ПользователиИнформационнойБазы.ПолучитьПользователей(); + СоставПользователей = Новый Массив; + Для Каждого ПользовательИБ Из ПользователиИБ Цикл + Если ПользовательИБ.Роли.Содержит(РольАдминистратора) Тогда + Пользователь = Справочники.Пользователи.НайтиПоРеквизиту( + "ИдентификаторПользователяИБ", + ПользовательИБ.УникальныйИдентификатор); + Если Пользователь = Неопределено Тогда + Продолжить; + КонецЕсли; + Если УпрощенныйИнтерфейс Тогда + // В упрощенном интерфейсе каждый администратор включаются в отдельную группу. + УправлениеДоступом.ВключитьПрофильПользователю(Пользователь, СвойстваПрофиля.Ссылка); + Иначе + // В расширенном интерфейсе администраторы включаются в одну группу, связанную с предопределенным профилем. + СоставПользователей.Добавить(Пользователь); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Не УпрощенныйИнтерфейс Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаПрофиля); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ГруппаДоступаОбъект = ГруппаПрофиля.ПолучитьОбъект(); + Для Каждого Пользователь Из СоставПользователей Цикл + Если ГруппаДоступаОбъект.Пользователи.Найти(Пользователь, "Пользователь") = Неопределено Тогда + ГруппаДоступаОбъект.Пользователи.Добавить().Пользователь = Пользователь; + КонецЕсли; + КонецЦикла; + Если ГруппаДоступаОбъект.Модифицированность() Тогда + ГруппаДоступаОбъект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + Иначе + // Удаление роли из всех профилей, за исключением предопределенного. + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПрофилиГруппДоступаРоли.Ссылка + |ИЗ + | Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиГруппДоступаРоли + |ГДЕ + | ПрофилиГруппДоступаРоли.Роль = &Роль + | И ПрофилиГруппДоступаРоли.Ссылка <> &ИсключаемыйПрофиль"; + Запрос.УстановитьПараметр("Роль", ИдентификаторРоли); + Запрос.УстановитьПараметр("ИсключаемыйПрофиль", СвойстваПрофиля.Ссылка); + МассивПрофилей = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + Для Каждого Профиль Из МассивПрофилей Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Профиль); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПрофильОбъект = Профиль.ПолучитьОбъект(); + Найденные = ПрофильОбъект.Роли.НайтиСтроки(Новый Структура("Роль", ИдентификаторРоли)); + Для Каждого СтрокаТаблицы Из Найденные Цикл + ПрофильОбъект.Роли.Удалить(СтрокаТаблицы); + КонецЦикла; + ПрофильОбъект.Записать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + + // Очистка состава групп доступа, связанных с предопределенным профилем. + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &Профиль"; + Запрос.УстановитьПараметр("Профиль", СвойстваПрофиля.Ссылка); + МассивГрупп = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + Для Каждого ГруппаДоступа Из МассивГрупп Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступа); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ГруппаДоступаОбъект = ГруппаДоступа.ПолучитьОбъект(); + ГруппаДоступаОбъект.Пользователи.Очистить(); + ГруппаДоступаОбъект.Записать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Только для внутреннего использования. +Процедура ПриРегистрацииИспользованияВерсииРасширенийВНеразделенномСеансе() Экспорт + + Если ТекущийРежимЗапуска() = Неопределено + Или ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей(); + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// Булево +// +Функция ВариантВстроенногоЯзыкаРусский() Экспорт + + Возврат Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский; + +КонецФункции + +// Обновляет список ролей пользователей информационной базы +// по их текущим принадлежностям к группам доступа. +// Пользователи с ролью "ПолныеПрава" игнорируется. +// +// Параметры: +// ОписаниеПользователей - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - Массив - значений указанных выше типов. +// - Неопределено - обновить роли всех пользователей. +// - Тип - по которому будет найден объект метаданных: +// если будет найден Справочник.ВнешниеПользователи, +// то будут обновлены роли всех внешних пользователей, +// иначе будут обновлены роли всех пользователей. +// +// ПарольПользователяСервиса - Строка - пароль для авторизации в менеджере сервиса. +// +// ЕстьИзменения - Булево - возвращаемое значение. В этот параметр возвращается +// значение Истина, если производилась запись, иначе не изменяется. +// +Процедура ОбновитьРолиПользователей(Знач ОписаниеПользователей = Неопределено, + Знач ПарольПользователяСервиса = Неопределено, + ЕстьИзменения = Ложь) Экспорт + + Если НЕ ПользователиСлужебный.ЗапретРедактированияРолей() Тогда + // Роли устанавливаются механизмами подсистем Пользователи и ВнешниеПользователи. + Возврат; + КонецЕсли; + + Если ОписаниеПользователей = Неопределено Тогда + МассивПользователей = Неопределено; + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + + ИначеЕсли ТипЗнч(ОписаниеПользователей) = Тип("Массив") Тогда + МассивПользователей = ОписаниеПользователей; + Если МассивПользователей.Количество() = 0 Тогда + Возврат; + ИначеЕсли МассивПользователей.Количество() = 1 Тогда + Пользователи.НайтиНеоднозначныхПользователейИБ(МассивПользователей[0]); + Иначе + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + КонецЕсли; + + ИначеЕсли ТипЗнч(ОписаниеПользователей) = Тип("Тип") Тогда + МассивПользователей = ОписаниеПользователей; + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + Иначе + МассивПользователей = Новый Массив; + МассивПользователей.Добавить(ОписаниеПользователей); + Пользователи.НайтиНеоднозначныхПользователейИБ(ОписаниеПользователей); + КонецЕсли; + + УстановитьПривилегированныйРежим(Истина); + + ТекущиеСвойстваПользователей = ТекущиеСвойстваПользователей(МассивПользователей); + + // Параметры проверки в цикле. + ВсеРоли = ПользователиСлужебный.ВсеРоли().Соответствие; + ИдентификаторыПользователейИБ = ТекущиеСвойстваПользователей.ИдентификаторыПользователейИБ; + НовыеРолиПользователей = ТекущиеСвойстваПользователей.РолиПользователей; + ИдентификаторыРолей = ТекущиеСвойстваПользователей.ИдентификаторыРолей; + ИменаРолей = ТекущиеСвойстваПользователей.ИменаРолей; + ОбязательныеРолиАдминистратора = ТекущиеСвойстваПользователей.ОбязательныеРолиАдминистратора; + ДополнительныеРолиАдминистратора = ТекущиеСвойстваПользователей.ДополнительныеРолиАдминистратора; + Администраторы = ТекущиеСвойстваПользователей.Администраторы; + РазделениеВключено = ОбщегоНазначения.РазделениеВключено(); + НеобходимоОбновлениеИБ = ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы(); + ИдентификаторТекущегоПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор; + + // Будущий итог после цикла. + НовыеАдминистраторыИБ = Новый Соответствие; + ОбновляемыеПользователиИБ = Новый Соответствие; + НекорректныеРоли = НовыеНекорректныеРоли(НовыеРолиПользователей); + + Для Каждого ОписаниеПользователя Из ИдентификаторыПользователейИБ Цикл + + ТекущийПользователь = ОписаниеПользователя.Пользователь; + ИдентификаторПользователяИБ = ОписаниеПользователя.ИдентификаторПользователяИБ; + НовыйАдминистраторИБ = Ложь; + + // Поиск пользователя ИБ. + Если ТипЗнч(ИдентификаторПользователяИБ) = Тип("УникальныйИдентификатор") Тогда + ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( + ИдентификаторПользователяИБ); + Иначе + ПользовательИБ = Неопределено; + КонецЕсли; + + Если ПользовательИБ = Неопределено + Или Не ЗначениеЗаполнено(ПользовательИБ.Имя) Тогда + Продолжить; + КонецЕсли; + + Если НеобходимоОбновлениеИБ + И ИдентификаторПользователяИБ = ИдентификаторТекущегоПользователяИБ Тогда + Продолжить; + КонецЕсли; + + Отказ = Ложь; + ИнтеграцияПодсистемБСП.ПриОбновленииРолейПользователяИБ(ИдентификаторПользователяИБ, Отказ); + Если Отказ Тогда + Продолжить; + КонецЕсли; + + Отбор = Новый Структура("Пользователь", ТекущийПользователь); + НовыеРоли = НовыеРолиПользователей.Скопировать( + НовыеРолиПользователей.НайтиСтроки(Отбор), "Роль, РольСсылка"); + + НовыеРоли.Индексы.Добавить("РольСсылка"); + + Если Администраторы[ТекущийПользователь] <> Неопределено Тогда + ТекущиеНовыеРоли = НовыеРоли; + НовыеРоли = ТекущиеНовыеРоли.Скопировать(Новый Массив); + Для Каждого КлючИЗначение Из ОбязательныеРолиАдминистратора Цикл + НовыеРоли.Добавить().РольСсылка = КлючИЗначение.Значение; + КонецЦикла; + Для Каждого КлючИЗначение Из ДополнительныеРолиАдминистратора Цикл + Если ТекущиеНовыеРоли.Найти(КлючИЗначение.Значение, "РольСсылка") = Неопределено Тогда + Продолжить; + КонецЕсли; + НовыеРоли.Добавить().РольСсылка = КлючИЗначение.Значение; + КонецЦикла; + КонецЕсли; + + НедоступныеРоли = ПользователиСлужебный.НедоступныеРолиПоТипуПользователя( + ТипЗнч(ТекущийПользователь) = Тип("СправочникСсылка.ВнешниеПользователи")); + + // Проверка старых ролей. + РолиДляДобавления = Новый Соответствие; + РолиДляУдаления = Новый Соответствие; + + Для Каждого Роль Из ПользовательИБ.Роли Цикл + ИмяРоли = Роль.Имя; + РольСсылка = ИдентификаторыРолей.Получить(ИмяРоли); + Если РольСсылка = Неопределено Тогда + КлючРоли = Справочники.ИдентификаторыОбъектовМетаданных.КлючОбъектаМетаданныхРоль(Роль); + РольСсылка = ИдентификаторыРолей.Получить(КлючРоли); + КонецЕсли; + Строка = НовыеРоли.Найти(РольСсылка, "РольСсылка"); + Если Строка = Неопределено Тогда + РолиДляУдаления.Вставить(ИмяРоли, Роль); + Иначе + Если РазделениеВключено И НедоступныеРоли.Получить(ИмяРоли) <> Неопределено Тогда + Строка.Роль = ИмяРоли; + ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Ложь); + РолиДляУдаления.Вставить(ИмяРоли, Роль); + КонецЕсли; + НовыеРоли.Удалить(Строка); + КонецЕсли; + КонецЦикла; + + // Проверка новых ролей. + Для Каждого Строка Из НовыеРоли Цикл + Строка.Роль = ИменаРолей.Получить(Строка.РольСсылка); + + Если ВсеРоли.Получить(Строка.Роль) = Неопределено Тогда + ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Истина); + Продолжить; + КонецЕсли; + + Если НедоступныеРоли.Получить(Строка.Роль) <> Неопределено Тогда + ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Ложь); + Продолжить; + КонецЕсли; + + РолиДляДобавления.Вставить(Строка.Роль, Истина); + + Если Строка.Роль = "АдминистраторСистемы" Тогда + НовыйАдминистраторИБ = Истина; + КонецЕсли; + КонецЦикла; + + // Завершение обработки текущего пользователя. + Если РолиДляДобавления.Количество() = 0 + И РолиДляУдаления.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + + ИзмененияРолей = Новый Структура; + ИзмененияРолей.Вставить("ПользовательСсылка", ТекущийПользователь); + ИзмененияРолей.Вставить("ПользовательИБ", ПользовательИБ); + ИзмененияРолей.Вставить("РолиДляДобавления", РолиДляДобавления); + ИзмененияРолей.Вставить("РолиДляУдаления", РолиДляУдаления); + + Если НовыйАдминистраторИБ Тогда + НовыеАдминистраторыИБ.Вставить(ТекущийПользователь, ИзмененияРолей); + Иначе + ОбновляемыеПользователиИБ.Вставить(ТекущийПользователь, ИзмененияРолей); + КонецЕсли; + + ЕстьИзменения = Истина; + КонецЦикла; + + ЗарегистрироватьНекорректныеРоли(НекорректныеРоли); + + // Добавление новых администраторов. + Если НовыеАдминистраторыИБ.Количество() > 0 Тогда + ОбновитьРолиПользователейИБ(НовыеАдминистраторыИБ, ПарольПользователяСервиса); + КонецЕсли; + + // Удаление старых администраторов и обновление остальных пользователей. + Если ОбновляемыеПользователиИБ.Количество() > 0 Тогда + ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса); + КонецЕсли; + + ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей(); + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// Булево +// +Функция ПоддерживаетсяРегистрацияИзмененийПраваДоступа() Экспорт + Возврат Истина; +КонецФункции + +// Возвращаемое значение: +// Строка +// +Функция ИмяСобытияИзменениеУчастниковГруппДоступаДляЖурналаРегистрации() Экспорт + + Возврат НСтр("ru = 'Управление доступом.Изменение участников групп доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()); + +КонецФункции + +// Возвращаемое значение: +// Строка +// +Функция ИмяСобытияИзменениеРазрешенныхЗначенийДляЖурналаРегистрации() Экспорт + + Возврат НСтр("ru = 'Управление доступом.Изменение разрешенных значений'", + ОбщегоНазначения.КодОсновногоЯзыка()); + +КонецФункции + +// Возвращаемое значение: +// Строка +// +Функция ИмяСобытияИзменениеРолейПрофилейДляЖурналаРегистрации() Экспорт + + Возврат НСтр("ru = 'Управление доступом.Изменение ролей профилей'", + ОбщегоНазначения.КодОсновногоЯзыка()); + +КонецФункции + +// См. СвойстваВидовДоступа +Функция СвойстваВсехВидовДоступа() Экспорт + Возврат СвойстваВидовДоступа(); +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПолноеИмяФормыСпискаГруппДоступа - Строка +// * ПолноеИмяФормыЭлементаГруппДоступа - Строка +// * ПолноеИмяФормыСпискаПрофилей - Строка +// * ПолноеИмяФормыЭлементаПрофилей - Строка +// * ТипСправочникСсылкаГруппыДоступа - Тип +// * ТипСправочникСсылкаПрофилиГруппДоступа - Тип +// * ТипыЗначенийДоступа - Массив из Тип +// +Функция ПараметрыДляОтчетов() Экспорт + + Результат = Новый Структура; + Результат.Вставить("ПолноеИмяФормыСпискаГруппДоступа", "Справочник.ГруппыДоступа.Форма.ФормаСписка"); + Результат.Вставить("ПолноеИмяФормыЭлементаГруппДоступа", "Справочник.ГруппыДоступа.Форма.ФормаЭлемента"); + Результат.Вставить("ПолноеИмяФормыСпискаПрофилей", "Справочник.ПрофилиГруппДоступа.Форма.ФормаСписка"); + Результат.Вставить("ПолноеИмяФормыЭлементаПрофилей", "Справочник.ПрофилиГруппДоступа.Форма.ФормаЭлемента"); + Результат.Вставить("ТипСправочникСсылкаГруппыДоступа", Тип("СправочникСсылка.ГруппыДоступа")); + Результат.Вставить("ТипСправочникСсылкаПрофилиГруппДоступа", Тип("СправочникСсылка.ПрофилиГруппДоступа")); + Результат.Вставить("ТипыЗначенийДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип.Типы()); + + Возврат Результат; + +КонецФункции + +#КонецОбласти + +#Область УниверсальноеОграничение + +Функция ОграничиватьДоступНаУровнеЗаписейУниверсально(СУчетомКонстантыОграничениеДоступаНаУровнеЗаписей = Истина, + КогдаПервоеОбновлениеДоступаЗавершилось = Ложь, ОбновлятьПараметрыСеансаКогдаТребуется = Истина) Экспорт + + Если СУчетомКонстантыОграничениеДоступаНаУровнеЗаписей Тогда + Значение = КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + + Если ОбновлятьПараметрыСеансаКогдаТребуется + И (Значение <> УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() + Или Значение + И Не ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально + И КонстантаПервоеОбновлениеДоступаЗавершилось()) Тогда + + ОбновитьПараметрыСеанса(); + Значение = УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + КонецЕсли; + + Возврат Значение + И (Не КогдаПервоеОбновлениеДоступаЗавершилось + Или КонстантаПервоеОбновлениеДоступаЗавершилось()); + КонецЕсли; + + Если ОбновлятьПараметрыСеансаКогдаТребуется + И Не ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа.Полное + И Не ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально Тогда + + ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); + Если ПоследняяПроверка.Дата + 3 <= ТекущаяДатаСеанса() Тогда + + Значение = КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + Если Значение И КонстантаПервоеОбновлениеДоступаЗавершилось() + Или Значение <> УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + + ОбновитьПараметрыСеанса(); + Значение = УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); + КонецЕсли; + ПоследняяПроверка.Дата = ТекущаяДатаСеанса(); + КонецЕсли; + КонецЕсли; + + Если Не КогдаПервоеОбновлениеДоступаЗавершилось Тогда + Возврат УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + КонецЕсли; + + Возврат ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально; + +КонецФункции + +Функция КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() Экспорт + + Значение = Константы.ОграничиватьДоступНаУровнеЗаписейУниверсально.Получить(); + + Если Не Значение И Не ВариантВстроенногоЯзыкаРусский() Тогда + Значение = Истина; + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + МенеджерЗначения = СлужебныйМенеджерЗначения( + Константы.ОграничиватьДоступНаУровнеЗаписейУниверсально); + МенеджерЗначения.Значение = Значение; + МенеджерЗначения.Записать(); + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +// Устанавливает использование регламентного задания ОбновлениеДоступа. +// +// Параметры: +// Использование - Булево - Истина, если задание нужно включить, иначе Ложь. +// БезПроверкиВыполненияОбновленияИБ - Булево +// +Процедура УстановитьОбновлениеДоступа(Использование, БезПроверкиВыполненияОбновленияИБ = Ложь) Экспорт + + Если Использование + И Не БезПроверкиВыполненияОбновленияИБ + И ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда + + Возврат; // После обновления ИБ задание включается безусловно. + КонецЕсли; + + Если Использование Тогда + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(); + Если ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + Если Использование Тогда + ВключитьЗадание = ?(ОбщегоНазначения.ИнформационнаяБазаФайловая(), + ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь, Ложь, Ложь), + ОграничиватьДоступНаУровнеЗаписейУниверсально()); + Иначе + ВключитьЗадание = Ложь; + КонецЕсли; + + Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); + Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); + + ТребуетсяИзменение = Ложь; + Для Каждого Задание Из Задания Цикл + Если ВключитьЗадание <> Задание.Использование Тогда + ТребуетсяИзменение = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Если Не ТребуетсяИзменение Тогда + Возврат; + КонецЕсли; + + Если ВключитьЗадание И ЭтоСеансФоновогоОбновленияДоступа() Тогда + Возврат; + КонецЕсли; + + Если МонопольныйРежим() + Или Не ТранзакцияАктивна() + Или ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + + ИзменитьРегламентноеЗаданиеОбновленияДоступа(ВключитьЗадание); + + ИначеЕсли ВключитьЗадание Тогда + ФоновыеЗадания.Выполнить("УправлениеДоступомСлужебный.ВключитьРегламентноеЗаданиеОбновленияДоступа",,, + НСтр("ru = 'Управление доступом: Включение регламентного задания обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка())); + Иначе + ФоновыеЗадания.Выполнить("УправлениеДоступомСлужебный.ОтключитьРегламентноеЗаданиеОбновленияДоступа",,, + НСтр("ru = 'Управление доступом: Отключение регламентного задания обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка())); + КонецЕсли; + +КонецПроцедуры + +// Возвращает ошибки текстов ограничений доступа объектов без учета зависимостей между объектами. +// Тексты проверяются в режиме максимальных ограничений (как будто включены все виды ограничений). +// Функция должна вызываться перед функцией НастройкиВнедрения, чтобы собрать весь пакет ошибок. +// +// Возвращаемое значение: +// Массив из Структура: +// * ПолноеИмя - Строка - полное имя объекта метаданных. +// * ТекстОшибки - Строка - текст ошибки в ограничении доступа. +// +Функция ОшибкиОграниченийДоступа() Экспорт + + Ошибки = Новый Массив; + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Истина, Ложь); + + Попытка + СпискиСОграничением = УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Списки с ограничением доступа некорректно указаны + |в процедуре %1 + |общего модуля %2 по причине: + | + |%3'"), + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + ОбъектОшибки = "ОбщийМодуль.УправлениеДоступомПереопределяемый"; + Ошибки.Добавить(Новый Структура("ПолноеИмя, ТекстОшибки", ОбъектОшибки, ТекстОшибки)); + Возврат Ошибки; + КонецПопытки; + + ТекстыОшибок = Новый Соответствие; + ОбщийКонтекст.Вставить("СпискиСОграничением", СпискиСОграничением); + ОбщийКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); + + Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + Попытка + ТекстОшибки = ОшибкаОграниченияДоступа(ОбщийКонтекст, ПолноеИмя); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Если ЗначениеЗаполнено(ТекстОшибки) И ТекстыОшибок.Получить(ТекстОшибки) = Неопределено Тогда + ТекстыОшибок.Вставить(ТекстОшибки, Истина); + Ошибки.Добавить(Новый Структура("ПолноеИмя, ТекстОшибки", ПолноеИмя, ТекстОшибки)); + КонецЕсли; + КонецЦикла; + + Возврат Ошибки; + +КонецФункции + +// Возвращает настройки внедрения для инструментов разработчика. +// +// Параметры: +// ДействующиеПараметры - Неопределено - значение по умолчанию. +// - Структура - только для вызова из функции РезультатПроверкиОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ОграниченияВРолях - Структура: +// ** ДляПользователей - Соответствие из КлючИЗначение: +// *** Ключ - Строка - полное имя объекта метаданных (списка). Имя коллекции на английском. +// В форме объекта должна вставка ПриЧтенииНаСервере. +// *** Значение - Структура: +// **** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, +// если Ложь, тогда используется шаблон #ДляРегистра. +// **** Параметры - Массив из Строка - параметры шаблона (для объекта 1, для регистра 6). +// Например, имя поля "Владелец" или опорного поля регистра "Организация". +// ** ДляВнешнихПользователей - Соответствие из КлючИЗначение - как для пользователей выше: +// *** Ключ - Строка - полное имя объекта метаданных (списка). Имя коллекции на английском. +// В форме объекта должна вставка ПриЧтенииНаСервере. +// *** Значение - Структура: +// **** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, +// если Ложь, тогда используется шаблон #ДляРегистра. +// **** Параметры - Массив из Строка - параметры шаблона (для объекта 1, для регистра 6). +// Например, имя поля "Владелец" или опорного поля регистра "Организация". +// +// * ПредопределенныеИдентификаторы - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя требуемого предопределенного элемента справочника +// ИдентификаторыОбъектовМетаданных или ИдентификаторыОбъектовРасширений +// в формате "<ИмяСправочника>.<ИмяПредопределенного>". +// ** Значение - Строка - полное имя соответствующего объекта метаданных. +// +// * ВладельцыЗначенийКлючейДоступа - Структура - для группы определяемых типов: +// ** Ссылки - Массив из Строка - полные имена типов ссылки (имя коллекции на английском). +// ** Документы - Массив из Строка - полные имена типов объекта (имя коллекции на английском). +// ** Объекты - Массив из Строка - то же, что в предыдущем пункте. +// ** НаборыЗаписей - Массив из Строка - то же, что в предыдущем пункте. +// ** НаборыЗаписейРегистраРасчета - Массив из Строка - то же, что в предыдущем пункте. +// +// * ЗначенияДоступа - Массив из Строка - полные имена типов ссылки (имя коллекции на английском). +// Для дополнения определяемого типа ЗначениеДоступа. +// +// * ТипыИзмеренийРегистровКлючей - Соответствие из КлючИЗначение: +// Для измерений с именем Поле регистра КлючиДоступаКРегистрам и регистров КлючиДоступаКРегистру<*>: +// ** Ключ - Строка - имя регистра. +// ** Значение - Структура: +// *** ИменаТипов - Массив из Строка - полные имена типов (на английском). +// *** ПоляРегистров - Соответствие из КлючИЗначение: +// **** Ключ - Строка - полное имя регистра, который ограничивается. +// **** Значение - Массив из Структура: +// ***** Поле - Строка - имя поля регистра. +// ***** Тип - ОписаниеТипов - типы поля регистра. +// Порядок полей в массиве соответствуют +// служебным полям Поле1, Поле2, ... +// *** ПоляРегистровПоТипам - Соответствие из КлючИЗначение: +// **** Ключ - Строка - полное имя типа (на английском). +// **** Значение - Массив из Строка - полные имена полей, например, +// "РегистрСведений.ДополнительныеСведения.Свойство". +// +Функция НастройкиВнедрения(ДействующиеПараметры = Неопределено) Экспорт + + ОграниченияВРолях = Новый Структура; + ОграниченияВРолях.Вставить("ДляПользователей", Новый Соответствие); + ОграниченияВРолях.Вставить("ДляВнешнихПользователей", Новый Соответствие); + + ВладельцыЗначенийКлючейДоступа = Новый Структура; + ВладельцыЗначенийКлючейДоступа.Вставить("Ссылки", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("Документы", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("Объекты", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("НаборыЗаписей", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("НаборыЗаписейРегистраРасчета", Новый Массив); + + ПредопределенныеИдентификаторы = Новый Соответствие; + ЗначенияДоступа = Новый Массив; + ТипыИзмеренийРегистровКлючей = Новый Соответствие; + ТипыИзмеренийРегистраКлючей(ТипыИзмеренийРегистровКлючей, "КлючиДоступаКРегистрам"); + + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + ЗначенияДоступа.Добавить(ИмяТипаСсылкиXML(Метаданные.Справочники.КлючиДоступа.ПолноеИмя(), ТипыТаблицПоИменам)); + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + Для Каждого ОписаниеВозможныхПрав Из ВозможныеПрава.ПоПолнымИменам Цикл + ЗначенияДоступа.Добавить(ИмяТипаСсылкиXML(ОписаниеВозможныхПрав.Ключ, ТипыТаблицПоИменам)); + КонецЦикла; + + Если ДействующиеПараметры = Неопределено Тогда + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Истина); + НовыеХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст); + ДействующиеПараметры = Новый Структура(НовыеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); // см. НоваяСтруктураХранимыхПараметровЗаписи + КонецЕсли; + + Контекст = Новый Структура; + Контекст.Вставить("ПредопределенныеИдентификаторы", ПредопределенныеИдентификаторы); + Контекст.Вставить("ТипыИзмеренийРегистровКлючей", ТипыИзмеренийРегистровКлючей); + Контекст.Вставить("ТипыТаблицПоИменам", ТипыТаблицПоИменам); + + ДобавленныеСписки = Новый Соответствие; + Для Каждого ОписаниеВерсии Из ДействующиеПараметры.ВерсииОграниченийСписков Цикл + ПолноеИмя = ОписаниеВерсии.Ключ; + ПолноеИмяXML = ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам); + ИмяТипаСсылкиXML = ИмяТипаСсылкиXML(ПолноеИмя, ТипыТаблицПоИменам); + ИмяТипаОбъектаXML = ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам); + + Если ЗначениеЗаполнено(ИмяТипаСсылкиXML) Тогда + ВладельцыЗначенийКлючейДоступа.Ссылки.Добавить(ИмяТипаСсылкиXML); + КонецЕсли; + + ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа); + ДобавленныеСписки.Вставить(ВРег(ПолноеИмя), Истина); + + Если ОписаниеВерсии.Значение = Неопределено Тогда + Продолжить; + КонецЕсли; + + ДобавитьОграниченияВРолях(ПолноеИмяXML, + ПолноеИмя, + ОграниченияВРолях.ДляПользователей, + ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков, + Контекст); + + ДобавитьОграниченияВРолях(ПолноеИмяXML, + ПолноеИмя, + ОграниченияВРолях.ДляВнешнихПользователей, + ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков, + Контекст); + КонецЦикла; + + Для Каждого ВедущийСписок Из ДействующиеПараметры.ВедущиеСписки Цикл + ПолноеИмя = ВедущийСписок.Ключ; + Если ДобавленныеСписки.Получить(ВРег(ПолноеИмя)) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ИмяТипаОбъектаXML = ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам); + ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа); + КонецЦикла; + + Настройки = Новый Структура; + Настройки.Вставить("ОграниченияВРолях", ОграниченияВРолях); + Настройки.Вставить("ПредопределенныеИдентификаторы", ПредопределенныеИдентификаторы); + Настройки.Вставить("ВладельцыЗначенийКлючейДоступа", ВладельцыЗначенийКлючейДоступа); + Настройки.Вставить("ЗначенияДоступа", ЗначенияДоступа); + Настройки.Вставить("ТипыИзмеренийРегистровКлючей", ТипыИзмеренийРегистровКлючей); + + Возврат Настройки; + +КонецФункции + +// Возвращает результат проверки ограничения доступа для инструмента разработчика. +// +// Параметры: +// ПолноеИмя - Строка - полное имя объекта метаданных. +// ДополнительныеПараметры - Неопределено - проверить и вернуть текущее ограничение. +// - Структура: +// * Текст - Строка - новый текст ограничения для пользователей. +// * ТекстДляВнешнихПользователей - Строка - новый текст ограничения для внешних пользователей. +// * УчитыватьЗависимости - Булево - учитывать зависимости между ограничениями объектов. +// * ВсеВидыДоступаИспользуются - Неопределено - вычислить по текущим настройками. +// - Булево - Истина (по умолчанию) - используются все, +// Ложь - не используется ни одного. +// +// Возвращаемое значение: +// Структура: +// * ОшибкаОписанияОграничения - Строка - если не пустая, то описание ограничения не удалось получить. +// Если при этом УчитыватьЗависимости = Истина, то это текст первой ошибки при получении всех описаний. +// +// * ТекстВМодулеМенеджера - Неопределено - когда заполнена ОшибкаОписанияОграничения. +// - Булево - возвращает место размещения текста ограничения, +// когда Истина - в модуле менеджера, иначе в переопределяемом модуле. +// +// * ДляПользователей - Структура: +// ** ПроверяемоеОграничение - Неопределено +// - Строка - проверенный текст ограничения. +// ** ОписаниеОшибок - см. ОписаниеОшибок +// ** ОшибкаФормированияПараметровОграничения - Неопределено +// - Строка - текст ошибки. +// ** ОшибкаФормированияТекстовЗапросов - Неопределено +// - Строка - текст ошибки. +// ** ОграничениеПоВладельцуВозможно - Неопределено +// - Булево - свойство проверенного ограничения. +// ** ОграничениеПоВладельцуИспользуется - Неопределено +// - Булево - когда УчитыватьЗависимости указано Истина. +// ** ОграниченияВРолях - Неопределено +// - Структура: +// *** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, +// если Ложь, тогда используется шаблон #ДляРегистра. +// *** Параметры - Массив - параметры шаблона (для объекта 1, для регистра 6): +// **** Значение - Строка - например, имя поля "Владелец" или +// опорного поля регистра "Организация". +// ** ОграничениеВМодуле - Неопределено +// - Строка - текст ограничения, который установлен в конфигурации. +// ** ПоВладельцуБезЗаписиКлючейДоступа - Неопределено +// - Булево - настройка ограничения, +// установленная в конфигурации. +// +// * ДляВнешнихПользователей - Структура - со свойствами, как ДляПользователей. +// +// * ВладелецЗначенийКлючейДоступа - Строка - типы для одноименного определяемого типа. +// * ВладелецЗначенийКлючейДоступаОбъект - Строка - типы для одноименного определяемого типа. +// * ВладелецЗначенийКлючейДоступаНаборЗаписей - Строка - типы для одноименного определяемого типа. +// * ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета - Строка - типы для одноименного определяемого типа. +// * ПолеРегистраКлючейДоступаКРегистрам - Строка - типы для одноименного определяемого типа. +// * ЗначениеДоступа - Строка - типы для одноименного определяемого типа. +// +// * ТипыИзмеренийОтдельногоРегистраКлючей - Неопределено +// - Структура: +// ** ИмяРегистраСведений - Строка - имя регистра ключей доступа. +// ** ТипыИзмерений - Строка - типы для соответствующих измерений регистра. +// +// * ПредопределенныйИдентификатор - Неопределено +// - Структура: +// ** ИмяСправочника - Строка - имя справочника идентификаторы объектов метаданных (или расширений). +// ** ИмяПредопределенного - Строка - имя предопределенного в справочнике. +// +Функция РезультатПроверкиОграниченияДоступа(ПолноеИмя, ДополнительныеПараметры = Неопределено) Экспорт + + Возврат РезультатПроверкиОграниченияДоступаОбъекта(ПолноеИмя, ДополнительныеПараметры); + +КонецФункции + +// Добавляет обновление доступа для указанных списков или всех списков. +// +// Параметры: +// Списки - Неопределено - запланировать полное обновление доступа. +// - Строка - полное имя объекта метаданных. +// - СправочникСсылка.ИдентификаторыОбъектовМетаданных - идентификатор. +// - Массив +// - ФиксированныйМассив - значения типов указанные выше, кроме Неопределено. +// +// ПараметрыПланирования - см. ПараметрыПланированияОбновленияДоступа +// +Процедура ЗапланироватьОбновлениеДоступа(Списки = Неопределено, ПараметрыПланирования = Неопределено) Экспорт + + Если ПараметрыПланирования = Неопределено Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Не ПараметрыПланирования.КлючиДоступаКДанным + И Не ПараметрыПланирования.РазрешенныеКлючиДоступа Тогда + + Возврат; + КонецЕсли; + + ИдентификаторыРегистров = Новый Массив; + ИдентификаторыСписковКлючей = Новый Массив; + + Если Списки = Неопределено Тогда + Если ПараметрыПланирования.ВерсииОграниченийСписков = Неопределено Тогда + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + ВерсииОграниченийСписков = Новый Соответствие(ДействующиеПараметры.ВерсииОграниченийСписков); + Иначе + ВерсииОграниченийСписков = Новый Соответствие(Новый ФиксированноеСоответствие( + ПараметрыПланирования.ВерсииОграниченийСписков)); + КонецЕсли; + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("РазрешенныйКлючДоступа", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа()); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) КАК ТипСсылки + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаКДанным.Регистр КАК Регистр + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКДанным + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступа.Список КАК Список + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Ссылка <> &РазрешенныйКлючДоступа"; + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + ИдентификаторыРегистров = РезультатыЗапроса[1].Выгрузить().ВыгрузитьКолонку("Регистр"); + ИдентификаторыСписковКлючей = РезультатыЗапроса[2].Выгрузить().ВыгрузитьКолонку("Список"); + + Выборка = РезультатыЗапроса[0].Выбрать(); + ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповСсылокДопустимыхОбъектов(); + ЕстьНедопустимыйТип = Ложь; + Пока Выборка.Следующий() Цикл + Если ТипЗнч(Выборка.ТипСсылки) <> Тип("Тип") Тогда + Продолжить; + ИначеЕсли Выборка.ТипСсылки = Тип("Неопределено") + Или Не ДопустимыеТипы.СодержитТип(Выборка.ТипСсылки) Тогда + ЕстьНедопустимыйТип = Истина; + Продолжить; + КонецЕсли; + ОбъектМетаданных = Метаданные.НайтиПоТипу(Выборка.ТипСсылки); + Если ОбъектМетаданных = Неопределено Тогда + Продолжить; + КонецЕсли; + ВерсииОграниченийСписков.Вставить(ОбъектМетаданных.ПолноеИмя(), Истина); + КонецЦикла; + ВерсииОграниченийСписков.Вставить("Справочник.НаборыГруппДоступа", Истина); + Если ЕстьНедопустимыйТип Тогда + ИдентификаторыРегистров.Добавить(Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка()); + КонецЕсли; + + СпискиДляОбновления = Новый Массив; + Для Каждого КлючИЗначение Из ВерсииОграниченийСписков Цикл + СпискиДляОбновления.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + + // При планировании полного обновления добавляются: + // а) списки с ограничением, + // б) списки, которые пишут ключи доступа для ограничений по полю-владельцу, + // в) списки без ограничения, для которых есть записи в регистрах ключей доступа к данным, + // в) списки, для которых рассчитываются разрешенные ключи доступа, + // г) списки без расчета разрешенных ключей доступа, для которых есть записи в регистрах + // разрешенных ключей доступа. + + ИначеЕсли ТипЗнч(Списки) <> Тип("Массив") + И ТипЗнч(Списки) <> Тип("ФиксированныйМассив") Тогда + + СпискиДляОбновления = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Списки); + Иначе + СпискиДляОбновления = Списки; + КонецЕсли; + + Если СпискиДляОбновления.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + СпискиПоИдентификаторам = Новый Соответствие; + Если ТипЗнч(СпискиДляОбновления[0]) = Тип("Строка") Тогда + ИдентификаторыСписков = ?(ПараметрыПланирования.ИдентификаторыВсехСписков = Неопределено, + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(СпискиДляОбновления, Списки <> Неопределено), + ПараметрыПланирования.ИдентификаторыВсехСписков); + Для Каждого ПолноеИмя Из СпискиДляОбновления Цикл + Идентификатор = ИдентификаторыСписков.Получить(ПолноеИмя); + Если Идентификатор <> Неопределено И Идентификатор <> Null Тогда + СпискиПоИдентификаторам.Вставить(Идентификатор, ПолноеИмя); + ИначеЕсли Списки <> Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не найден идентификатор объекта метаданных ""%1"".'"), ПолноеИмя); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого Идентификатор Из СпискиДляОбновления Цикл + СпискиПоИдентификаторам.Вставить(Идентификатор, ""); + КонецЦикла; + КонецЕсли; + + Если ЗначениеЗаполнено(ИдентификаторыРегистров) + Или ЗначениеЗаполнено(ИдентификаторыСписковКлючей) Тогда + + Для Каждого ИдентификаторРегистра Из ИдентификаторыРегистров Цикл + Если ИдентификаторРегистра = Неопределено Тогда + СпискиПоИдентификаторам.Вставить( + Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка(), ""); + КонецЕсли; + СпискиПоИдентификаторам.Вставить(ИдентификаторРегистра, ""); + КонецЦикла; + Для Каждого ИдентификаторРазрешенных Из ИдентификаторыСписковКлючей Цикл + СпискиПоИдентификаторам.Вставить(ИдентификаторРазрешенных, ""); + КонецЦикла; + КонецЕсли; + + ИдентификаторСправочникаНаборыГруппДоступа = + СлужебныйИдентификатор("Справочник.НаборыГруппДоступа"); + + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + КлючУникальностиЗаписей = Новый УникальныйИдентификатор; + + ЭтоТочечноеЗадание = Ложь; + ПараметрыЗадания = Новый Структура; + РазмерЗадания = 3; + + Если ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов Тогда + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + УстановитьВидКлючаДанных(ПараметрыЗадания, "УстаревшиеЭлементы"); + ДатаПоследнегоОбновленногоЭлемента = '00010101'; + РазмерЗадания = 2; + Иначе + ВедущийОбъект = ПараметрыПланирования.ВедущийОбъект; // См. ОписаниеВедущегоОбъекта + Если ВедущийОбъект <> Неопределено + И Не ( ВедущийОбъект.Свойство("ПоДаннымКэшаРасчетаПрав") + Или ВедущийОбъект.Свойство("ПоКлючамДоступа") + Или ВедущийОбъект.Свойство("ПоЗначениямСГруппами") + Или ВедущийОбъект.Свойство("ПоЗначениямПолей") + И ТипЗнч(ВедущийОбъект.ПоЗначениямПолей.СоставИзменений) = Тип("ТаблицаЗначений") ) Тогда + ВедущийОбъект = Неопределено; + КонецЕсли; + Если ВедущийОбъект <> Неопределено Тогда + ЭтоТочечноеЗадание = Истина; + ПараметрыПланирования = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыПланирования)); + ПараметрыПланирования.Вставить("ЭтоТочечноеЗадание"); + РазмерЗадания = 1; + ПараметрыЗадания.Вставить("ТочечноеЗадание", ВедущийОбъект); + КонецЕсли; + ДатаПоследнегоОбновленногоЭлемента = ?(ПараметрыПланирования.ЭтоПродолжениеОбновления, + МаксимальнаяДатаПриПродолжении(), МаксимальнаяДата()); + КонецЕсли; + Если ПараметрыЗадания.Количество() = 0 Тогда + ПараметрыЗадания = Неопределено; + КонецЕсли; + ХранилищеПараметровЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); + + ОбновлениеКлючейДоступаКДанным = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + ОбновлениеКлючейДоступаПользователей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаПользователей); + + Для Каждого ОписаниеСписка Из СпискиПоИдентификаторам Цикл + ИдентификаторСписка = ОписаниеСписка.Ключ; + + Если ПараметрыПланирования.КлючиДоступаКДанным Тогда + Если ПараметрыПланирования.ДляПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаКДанным.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = ДатаПоследнегоОбновленногоЭлемента; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + Если ПараметрыПланирования.ДляВнешнихПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаКДанным.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Истина; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = ДатаПоследнегоОбновленногоЭлемента; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + КонецЕсли; + + Если ИдентификаторСписка = ИдентификаторСправочникаНаборыГруппДоступа Тогда + Продолжить; + КонецЕсли; + + Если ПараметрыПланирования.РазрешенныеКлючиДоступа Тогда + Если ПараметрыПланирования.ДляПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаПользователей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + Если ПараметрыПланирования.ДляВнешнихПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаПользователей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Истина; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + + Если ОбновлениеКлючейДоступаКДанным.Количество() > 0 Тогда + ОбновлениеКлючейДоступаКДанным.Записать(Ложь); + КонецЕсли; + + Если ОбновлениеКлючейДоступаПользователей.Количество() > 0 Тогда + ОбновлениеКлючейДоступаПользователей.Записать(Ложь); + КонецЕсли; + + ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, + ПараметрыПланирования, Списки = Неопределено); + + Если ОбновлениеКлючейДоступаКДанным.Количество() > 0 + Или ОбновлениеКлючейДоступаПользователей.Количество() > 0 Тогда + + УстановитьОбновлениеДоступа(Истина); + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Конструктор структуры дополнительных параметров для процедуры ЗапланироватьОбновлениеДоступа. +// +// Возвращаемое значение: +// Структура: +// * КлючиДоступаКДанным - Булево - по умолчанию Истина - запланировать обновление ключей доступа +// к данным. +// * РазрешенныеКлючиДоступа - Булево - по умолчанию Истина - запланировать обновление ключей доступа +// пользователей и групп доступа. +// * ДляПользователей - Булево - по умолчанию Истина - запланировать обновление для пользователей. +// * ДляВнешнихПользователей - Булево - по умолчанию значение константы ИспользоватьВнешнихПользователей +// запланировать обновление для внешних пользователей. +// +Функция ПараметрыПланированияОбновленияДоступа(ВычислитьДляВнешнихПользователей = Истина) Экспорт + + ДляВнешнихПользователей = ?(ВычислитьДляВнешнихПользователей, + Константы.ИспользоватьВнешнихПользователей.Получить(), Истина); + + Результат = Новый Структура; + Результат.Вставить("КлючиДоступаКДанным", Истина); + Результат.Вставить("РазрешенныеКлючиДоступа", Истина); + Результат.Вставить("ДляПользователей", Истина); + Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Результат.Вставить("ВедущийОбъект", Неопределено); + Результат.Вставить("ВерсииОграниченийСписков", Неопределено); + Результат.Вставить("ИдентификаторыВсехСписков", Неопределено); + Результат.Вставить("Описание", ""); + Результат.Вставить("ЭтоПродолжениеОбновления", Ложь); + Результат.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); + + Возврат Результат; + +КонецФункции + +// Параметры: +// Описание - Строка - имя процедуры, которая вызвала планирование, +// используемое для расширенной регистрации в журнале. +// ЗапуститьОбновление - Булево - если Истина, то планирование будет +// негарантированным, так как при наличии транзакции +// выполняется в фоне "как есть" для возможности запуска обновления. +// +Процедура ЗапланироватьОбновлениеПараметровОграниченияДоступа(Описание, ЗапуститьОбновление = Ложь) Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Возврат; + КонецЕсли; + + Если Не ТранзакцияАктивна() Или Не ЗапуститьОбновление Тогда + ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа(Описание, ЗапуститьОбновление); + Возврат; + КонецЕсли; + + ПараметрыПроцедуры = Новый Массив; + ПараметрыПроцедуры.Добавить(Описание); + ПараметрыПроцедуры.Добавить(ЗапуститьОбновление); + + ФоновыеЗадания.Выполнить( + "УправлениеДоступомСлужебный.ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа", + ПараметрыПроцедуры,, НСтр("ru = 'Управление доступом: планирование обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка())); + +КонецПроцедуры + +// Только для процедуры ЗапланироватьОбновлениеПараметровОграниченияДоступа. +Процедура ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа(Описание, ЗапуститьОбновление) Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Возврат; + КонецЕсли; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.Описание = Описание; + + Идентификатор = СлужебныйИдентификатор("РегистрСведений.ПараметрыОграниченияДоступа"); + Если Идентификатор <> Null Тогда + ЗапланироватьОбновлениеДоступа(Идентификатор, ПараметрыПланирования); + Если ЗапуститьОбновление Тогда + ЗапуститьОбновлениеДоступа(); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Запускает обновление доступа, если оно запланировано и еще не запущено. +Процедура ЗапуститьОбновлениеДоступа() Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь) + Или МонопольныйРежим() + Или ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(Истина) + И Не ЕстьЗапланированныеТочечныеЗадания() Тогда + Возврат; + КонецЕсли; + + ЗапуститьОбновлениеДоступаНаУровнеЗаписей(,, Истина); + +КонецПроцедуры + +// Только для внутреннего использования. +Процедура ОбновитьДоступПослеОбновленияИнформационнойБазы(ВыполнитьОтложенноеОбновлениеСейчас) Экспорт + + Если ОбщегоНазначения.РазделениеВключено() + И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + Если ВыполнитьОтложенноеОбновлениеСейчас + И ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + + ВыполнитьОбновлениеДоступаНаУровнеЗаписей(Истина, Ложь, 0, Истина); + КонецЕсли; + +КонецПроцедуры + +// Для функции ПраваРолейРасширений и функции ЗаполнитьВсеПараметрыРаботыРасширений +// модуля менеджера регистра сведений ПараметрыРаботыВерсийРасширений. +// +Процедура УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Включить) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; + ИмяСвойства = "ЗаписьПараметровОграниченияДоступаВТекущемСеансе"; + + Если Не Включить И Не ТекущиеПараметры.Свойство(ИмяСвойства) Тогда + Возврат; + КонецЕсли; + + НовыеПараметры = Новый Структура(ТекущиеПараметры); + + Если Включить Тогда + Если Не НовыеПараметры.Свойство(ИмяСвойства) Тогда + НовыеПараметры.Вставить(ИмяСвойства, 0); + КонецЕсли; + НовыеПараметры[ИмяСвойства] = НовыеПараметры[ИмяСвойства] + 1; + Иначе + НовыеПараметры[ИмяСвойства] = НовыеПараметры[ИмяСвойства] - 1; + Если НовыеПараметры[ИмяСвойства] < 1 Тогда + НовыеПараметры.Удалить(ИмяСвойства); + КонецЕсли; + КонецЕсли; + + ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(НовыеПараметры); + + УстановитьПривилегированныйРежим(Ложь); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытийПодсистемКонфигурации + +// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами. +Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт + Объекты.Вставить(Метаданные.Справочники.ГруппыДоступа.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке"); + Объекты.Вставить(Метаданные.Справочники.ПрофилиГруппДоступа.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке"); +КонецПроцедуры + +// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса. +Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт + + Обработчики.Вставить("ОграничениеДоступаНаУровнеЗаписейИспользуется", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВидыДоступаБезГруппДляЗначенияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВидыДоступаСОднойГруппойДляЗначенияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВидыДоступаСОтключеннымИспользованием", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВсеВидыДоступаКромеСпециальных", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТаблицыСОтдельнымиНастройкамиПрав", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТипыЗначенийДоступаСГруппами", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТипыВладельцевНастроекПрав", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТаблицыРасширенийСОграничениемДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + +#Область УниверсальноеОграничение + + Обработчики.Вставить("ОграничениеДоступаНаУровнеЗаписейУниверсально", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ОтключениеОбновленияКлючейДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВерсииШаблоновОграниченияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйНаборГруппДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйПустойНаборГруппДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйНаборГруппПользователей", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйПользователь", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ОбщиеПараметрыШаблоновОграниченияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОграничениемПоПолям", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОграничениемЧерезКлючиДоступаПользователей", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОтключеннымОграничениемЧтения", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ПараметрыОграниченияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + +#КонецОбласти + +КонецПроцедуры + +// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий +Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт + + Настройка = Настройки.Добавить(); + Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа; + Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ОграничиватьДоступНаУровнеЗаписей; + + Настройка = Настройки.Добавить(); + Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей; + Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ОграничиватьДоступНаУровнеЗаписейУниверсально; + +КонецПроцедуры + +// Обновляет вспомогательные данные, которые зависят только от конфигурации. +// Записывает изменения этих данных по версиям конфигурации(если изменения есть), +// чтобы использовать эти изменения при обновлении остальных вспомогательных данных, +// например, в обработчике ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации. +// +Процедура ОбновитьПараметрыОграниченияДоступа(ЕстьИзменения = Неопределено) Экспорт + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". + РегистрыСведений.ПраваРолей.ОбновитьДанныеРегистра(ЕстьИзменения); + + // ЗависимостиПравДоступа + РегистрыСведений.ЗависимостиПравДоступа.ОбновитьДанныеРегистра(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". + ОбновитьОписаниеСвойствВидовДоступа(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". + РегистрыСведений.НастройкиПравОбъектов.ОбновитьВозможныеПраваДляНастройкиПравОбъектов(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". + Справочники.ПрофилиГруппДоступа.ОбновитьОписаниеПоставляемыхПрофилей(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". + Справочники.ПрофилиГруппДоступа.ОбновитьСоставПредопределенныхПрофилей(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". + РегистрыСведений.ПараметрыОграниченияДоступа.ОбновитьВерсиюТекстовОграниченияДоступа(ЕстьИзменения); + +КонецПроцедуры + +// Обновляет описание свойств видов доступа в параметрах работы программы. +// +// Параметры: +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +Процедура ОбновитьОписаниеСвойствВидовДоступа(ЕстьИзменения = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); + НовоеЗначение = Кэш.ХешСуммы; + + НачатьТранзакцию(); + Попытка + ЕстьТекущиеИзменения = Ложь; + СтароеЗначение = Неопределено; + + СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы( + "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа", + НовоеЗначение, ЕстьТекущиеИзменения, СтароеЗначение); + + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + + ЕстьИзмененияТиповГруппИЗначенийДоступа = + НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа + <> СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа; + + СтандартныеПодсистемыСервер.ДобавитьИзмененияПараметраРаботыПрограммы( + "СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа", + ?(ЕстьИзмененияТиповГруппИЗначенийДоступа, + Новый ФиксированнаяСтруктура("ЕстьИзменения", Истина), + Новый ФиксированнаяСтруктура()) ); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЕстьТекущиеИзменения Тогда + ЕстьИзменения = Истина; + КонецЕсли; + +КонецПроцедуры + +// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления. +Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт + + // Обработчики обновления неразделенных данных. + Обработчик = Обработчики.Добавить(); + Обработчик.ОбщиеДанные = Истина; + Обработчик.УправлениеОбработчиками = Истина; + Обработчик.Приоритет = 1; + Обработчик.Версия = "*"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ЗаполнитьОбработчикиРазделенныхДанных"; + + // Обработчики обновления разделенных данных. + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "*"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации"; + + // Должен выполнятся после обработчика ЗаполнитьИдентификаторыПоставляемыхДанных. + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "1.0.0.1"; + Обработчик.НачальноеЗаполнение = Истина; + Обработчик.Процедура = "Справочники.ГруппыДоступа.ЗаполнитьПрофильГруппыДоступаАдминистраторы"; + Обработчик.РежимВыполнения = "Монопольно"; + Обработчик.ВыполнятьВГруппеОбязательных = Истина; + Обработчик.Приоритет = 1; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "2.4.1.1"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьДанныеПрофиляОткрытиеВнешнихОтчетовИОбработок"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.ВыполнятьВГруппеОбязательных = Истина; + Обработчик.Приоритет = 1; + + Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда + Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика(); + НоваяСтрока = Обработчик.ПриоритетыВыполнения.Добавить(); + НоваяСтрока.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + НоваяСтрока.Порядок = "До"; + КонецЕсли; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.1.3.135"; + Обработчик.Процедура = "РегистрыСведений.ГруппыЗначенийДоступа.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + Обработчик.РежимВыполнения = "Отложенно"; + Обработчик.Комментарий = НСтр("ru = 'Обновление вспомогательных данных.'"); + Обработчик.Идентификатор = Новый УникальныйИдентификатор("b3cb643e-d5cf-40b7-9db3-6315a88c063d"); + Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.ГруппыЗначенийДоступа.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; + Обработчик.ЧитаемыеОбъекты = "РегистрСведений.ГруппыЗначенийДоступа"; + Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ГруппыЗначенийДоступа"; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.0.2.174"; + Обработчик.Процедура = "РегистрыСведений.НастройкиПравОбъектов.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + Обработчик.РежимВыполнения = "Отложенно"; + Обработчик.Комментарий = НСтр("ru = 'Обновление вспомогательных данных настроек прав.'"); + Обработчик.Идентификатор = Новый УникальныйИдентификатор("40d1c62f-c3f1-4608-8985-2dc618c3d758"); + Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.НастройкиПравОбъектов.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; + Обработчик.ЧитаемыеОбъекты = "РегистрСведений.НастройкиПравОбъектов"; + Обработчик.ИзменяемыеОбъекты = "РегистрСведений.НастройкиПравОбъектов"; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.1.10.80"; + Обработчик.Процедура = "Справочники.ГруппыДоступа.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + Обработчик.РежимВыполнения = "Отложенно"; + Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина; + Обработчик.Комментарий = НСтр("ru = 'Удаляет служебных пользователей из групп доступа.'"); + Обработчик.Идентификатор = Новый УникальныйИдентификатор("4795e622-6115-4abc-a8de-cf2e838b7ea2"); + Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы"; + Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ГруппыДоступа.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; + Обработчик.ЧитаемыеОбъекты = "Справочник.ГруппыДоступа"; + Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ТаблицыГруппДоступа,РегистрСведений.ЗначенияГруппДоступа,РегистрСведений.ЗначенияГруппДоступаПоУмолчанию"; + + // Должен выполнятся до прикладных обработчиков обновления. + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.1.11.49"; + Обработчик.Процедура = "РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.ВыполнятьВГруппеОбязательных = Истина; + Обработчик.Приоритет = 1; + +КонецПроцедуры + +// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек +// +// Параметры: +// Объекты - Массив из ОбъектМетаданных +// +Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт + + Объекты.Добавить(Метаданные.Справочники.ПрофилиГруппДоступа); + Объекты.Добавить(Метаданные.Справочники.ГруппыДоступа); + +КонецПроцедуры + +// См. ОбновлениеИнформационнойБазыБСП.ПослеОбновленияИнформационнойБазы. +Процедура ПослеОбновленияИнформационнойБазы(Знач ПредыдущаяВерсия, Знач ТекущаяВерсия, + Знач ВыполненныеОбработчики, ВыводитьОписаниеОбновлений, МонопольныйРежим) Экспорт + + Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); + + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); + УстановитьОбновлениеДоступа(Истина, Истина); + +КонецПроцедуры + +// См. ОбновлениеИнформационнойБазыПереопределяемый.ПриЗаполненииОбъектовПланируемыхКУдалению. +Процедура ПриЗаполненииОбъектовПланируемыхКУдалению(Объекты) Экспорт + + // РегистрСведений.ЗависимостиПравДоступа.ТипВедущейТаблицы + ЗависимостиПравДоступа = РегистрыСведений.ЗависимостиПравДоступа.ЗависимостиПравДоступа(); + ТипыВедущихТаблиц = Новый Массив; + Для Каждого Строка Из ЗависимостиПравДоступа Цикл + ТипыВедущихТаблиц.Добавить(ТипЗнч(Строка.ТипВедущейТаблицы)); + КонецЦикла; + ТребуемыйТипВедущейТаблицы = Новый ОписаниеТипов(ТипыВедущихТаблиц); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВедущейТаблицы, + Метаданные.РегистрыСведений.ЗависимостиПравДоступа.Измерения.ТипВедущейТаблицы); + + Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + НастройкиВнедрения = НастройкиВнедрения(); + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + СлужебныеТипы = Новый Массив; + СлужебныеТипы.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + СлужебныеТипы.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + СлужебныеТипы.Добавить(Тип("ПеречислениеСсылка.ДополнительныеЗначенияДоступа")); + + // ОпределяемыйТип.ЗначениеДоступа + ТипыГруппИЗначений = Новый Массив; + Для Каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамГруппИЗначений Цикл + ТипыГруппИЗначений.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов( + СтрСоединить(НастройкиВнедрения.ЗначенияДоступа, ",")); + ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов(ТребуемыйТипЗначенияДоступа, ТипыГруппИЗначений); + ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов(ТребуемыйТипЗначенияДоступа, СлужебныеТипы); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ЗначенияГруппДоступа.Измерения.ЗначениеДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию.Измерения.ТипЗначенийДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ГруппыЗначенийДоступа.Измерения.ЗначениеДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ГруппыЗначенийДоступа.Измерения.ГруппаЗначенийДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ИспользуемыеВидыДоступа.Измерения.ТипЗначенийДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ИспользуемыеВидыДоступаПоТаблицам.Измерения.ТипЗначенийДоступа); + + // ОпределяемыйТип.ВладелецНастроекПрав + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ТипыВладельцевНастроекПрав = Новый Массив; + Для Каждого ВладелецПрав Из ВозможныеПрава.ТипыВладельцев Цикл + ТипыВладельцевНастроекПрав.Добавить(ТипЗнч(ВладелецПрав)); + КонецЦикла; + ТребуемыйТипВладельцаНастроекПрав = Новый ОписаниеТипов(ТипыВладельцевНастроекПрав); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, + Метаданные.РегистрыСведений.НастройкиПравОбъектов.Измерения.Объект); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, + Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.Измерения.Объект); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, + Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.Измерения.Родитель); + + // ОпределяемыйТип.ВладелецЗначенийКлючейДоступа + ДобавитьОбъектПланируемыйКУдалению(Объекты, + Новый ОписаниеТипов(СтрСоединить(НастройкиВнедрения.ВладельцыЗначенийКлючейДоступа.Ссылки, ",")), + Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект); + + // ОпределяемыйТип.ПолеРегистраКлючейДоступаКРегистрам + Для Каждого ОписаниеРегистровКлючей Из НастройкиВнедрения.ТипыИзмеренийРегистровКлючей Цикл + ИмяРегистраКлючей = ОписаниеРегистровКлючей.Ключ; + МетаданныеРегистраКлючей = Метаданные.РегистрыСведений[ИмяРегистраКлючей]; + КоличествоПолей = УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистраКлючей); + ТребуемыйТипПоля = Новый ОписаниеТипов(СтрСоединить(ОписаниеРегистровКлючей.Значение.ИменаТипов, ",")); + ТребуемыйТипПоля = Новый ОписаниеТипов(ТребуемыйТипПоля, СлужебныеТипы); + Для НомерПоля = 1 По КоличествоПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипПоля, + МетаданныеРегистраКлючей.Измерения[ИмяПоля]); + КонецЦикла; + КонецЦикла; + + // РегистрСведений.НаборыЗначенийДоступа.Объект + ТипыОбъектовПодписок = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа"); + ТипыСсылокОбъектовПодписок = Новый Массив; + Для Каждого КлючИЗначение Из ТипыОбъектовПодписок Цикл + МетаданныеОбъекта = Метаданные.НайтиПоТипу(КлючИЗначение.Ключ); + МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъекта.ПолноеИмя()); + ПустаяСсылка = МенеджерОбъекта.ПустаяСсылка(); + ТипыСсылокОбъектовПодписок.Добавить(ТипЗнч(ПустаяСсылка)); + КонецЦикла; + ТребуемыйТипТаблицСЗаписьюНаборовЗначенийДоступа = Новый ОписаниеТипов( + Новый ОписаниеТипов(ТипыСсылокОбъектовПодписок),, СлужебныеТипы); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипТаблицСЗаписьюНаборовЗначенийДоступа, + Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект); + + // РегистрСведений.НаборыЗначенийДоступа.ЗначениеДоступа + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.ЗначениеДоступа); + +КонецПроцедуры + +// Параметры: +// ИзменениеЯзыков - см. МультиязычностьСервер.ОписаниеСтарыхИНовыхНастроекЯзыков +// +Процедура ПриИзмененииЯзыкаИнформационнойБазы(ИзменениеЯзыков) Экспорт + + Справочники.ПрофилиГруппДоступа.ПриИзмененииЯзыкаИнформационнойБазы(ИзменениеЯзыков); + +КонецПроцедуры + +// Заполняет структуру параметров, необходимых для работы клиентского кода +// конфигурации. +// +// Параметры: +// Параметры - Структура - структура параметров. +// +Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт + + Параметры.Вставить("УпрощенныйИнтерфейсНастройкиПравДоступа", + УпрощенныйИнтерфейсНастройкиПравДоступа()); + +КонецПроцедуры + +// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок. +Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт + + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ГруппыЗначенийДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗависимостиПравДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗначенияГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.НаборыЗначенийДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ПраваРолей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ТаблицыГруппДоступа); + + ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(ИсключенияПоискаСсылок); + +КонецПроцедуры + +// Объекты с отложенным удалением. +// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок +// +// Параметры: +// ИсключенияПоискаСсылок - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.ИсключенияПоискаСсылок +// +Процедура ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(ИсключенияПоискаСсылок) Экспорт + + ИсключенияПоискаСсылок.Добавить(Метаданные.Справочники.КлючиДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.Справочники.НаборыГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаВнешнихПользователей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаКОбъектам); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаКРегистрам); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаПользователей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ОбновлениеКлючейДоступаПользователей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа); + + Для Каждого РегистрСведений Из Метаданные.РегистрыСведений Цикл + Если СтрНачинаетсяС(ВРег(РегистрСведений.Имя), ВРег("КлючиДоступаКРегистру")) Тогда + ИсключенияПоискаСсылок.Добавить(РегистрСведений); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Вызывается при загрузке ссылок предопределенных элементов в процессе загрузки важных данных. +// Позволяет выполнить действия по исправлению или регистрации сведений о не уникальности +// предопределенных элементов, а также позволяет отказаться от продолжения, если это недопустимо. +// +// Параметры: +// Объект - СправочникОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект - +// объект предопределенного элемента после записи которого обнаружено наличие не уникальности. +// ЗаписатьВЖурнал - Булево - возвращаемое значение. Если указать Ложь, тогда сведения о не уникальности не будут +// добавлены в журнал регистрации в общем сообщении. +// Нужно установить Ложь, если не уникальность была устранена автоматически. +// Отказ - Булево - возвращаемое значение. Если указать Истина, будет вызвано общее исключение, +// содержащее все причины отказа. +// ОписаниеОтказа - Строка - возвращаемое значение. Если Отказ установлен в Истина, то описание будет добавлено +// в список причин невозможности продолжения. +// +Процедура ПриОбнаруженииНеУникальностиПредопределенного(Объект, ЗаписатьВЖурнал, Отказ, ОписаниеОтказа) Экспорт + + Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") + И Объект.ИмяПредопределенныхДанных = "Администратор" Тогда + + ЗаписатьВЖурнал = Ложь; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка); + Запрос.УстановитьПараметр("ИмяПредопределенныхДанных", "Администратор"); + Запрос.Текст = + "ВЫБРАТЬ + | ПрофилиГруппДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + |ГДЕ + | ПрофилиГруппДоступа.Ссылка <> &Ссылка + | И ПрофилиГруппДоступа.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; + + Выборка = Запрос.Выполнить().Выбрать(); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + + Пока Выборка.Следующий() Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект(); + ТекущийОбъект.ИмяПредопределенныхДанных = ""; + ТекущийОбъект.ИдентификаторПоставляемыхДанных = ""; + ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + + ИначеЕсли ТипЗнч(Объект) = Тип("СправочникОбъект.ГруппыДоступа") + И Объект.ИмяПредопределенныхДанных = "Администраторы" Тогда + + ЗаписатьВЖурнал = Ложь; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИмяПредопределенныхДанных", "Администраторы"); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступаПользователи.Пользователь + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + |ГДЕ + | ГруппыДоступаПользователи.Ссылка.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; + ВсеПользователи = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Пользователь"); + + Записать = Ложь; + Для каждого Пользователь Из ВсеПользователи Цикл + Если Объект.Пользователи.Найти(Пользователь, "Пользователь") = Неопределено Тогда + Объект.Пользователи.Добавить().Пользователь = Пользователь; + Записать = Истина; + КонецЕсли; + КонецЦикла; + + Если Записать Тогда + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + КонецЕсли; + + Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Ссылка <> &Ссылка + | И ГруппыДоступа.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; + + Выборка = Запрос.Выполнить().Выбрать(); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + + Пока Выборка.Следующий() Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект(); + ТекущийОбъект.ИмяПредопределенныхДанных = ""; + ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// См. ОбменДаннымиПереопределяемый.ПриНастройкеПодчиненногоУзлаРИБ. +Процедура ПриНастройкеПодчиненногоУзлаРИБ() Экспорт + + // Роли расширений назначаются независимо во всех РИБ-узлах. + Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширенийВоВсехПрофиляхГруппДоступа(); + + // Администраторы назначаются независимо во всех РИБ-узлах. + Справочники.ГруппыДоступа.УдалитьУчастниковГруппыДоступаАдминистраторыБезПользователяИБ(); + + Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); + Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.Описание = "ПриНастройкеПодчиненногоУзлаРИБ"; + ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); + КонецЕсли; + +КонецПроцедуры + +// См. ПользователиСлужебный.ПриЗаполненииВидовРегистрируемыхСсылок. +Процедура ПриЗаполненииВидовРегистрируемыхСсылок(ВидыСсылок) Экспорт + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ОграничиватьДоступНаУровнеЗаписей"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("Булево"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписейИзменениеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ИспользуемыеВидыДоступа"; + ВидСсылок.ДопустимыеТипы = Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип; + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ИспользуемыеВидыДоступаИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ПрофилиГруппДоступа"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ПрофилиГруппДоступа"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ПрофилиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ПрофилиГруппДоступаРоли"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( + "СправочникСсылка.ИдентификаторыОбъектовМетаданных,СправочникСсылка.ИдентификаторыОбъектовРасширений"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ПрофилиГруппДоступаРолиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступа"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ГруппыДоступа"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступаРоли"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( + "СправочникСсылка.ИдентификаторыОбъектовМетаданных,СправочникСсылка.ИдентификаторыОбъектовРасширений"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаРолиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступаПользователи"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( + "СправочникСсылка.Пользователи,СправочникСсылка.ВнешниеПользователи"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаПользователиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступаЗначенийСИерархией"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ГруппыДоступа"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаЗначенийСИерархиейИзмененныхПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ЗначенияДоступа"; + ВидСсылок.ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ТипыСсылокИзЗначениеДоступаОбъект(); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ЗначенияДоступаИзмененныеПриЗагрузке"; + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхГлавному. +Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель) Экспорт + + ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Ложь, Ложь); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному. +Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель) Экспорт + + ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Истина, СозданиеНачальногоОбраза); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного. +Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт + + ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Ложь); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтПодчиненного. +Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт + + ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Истина); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПослеПолученияДанных. +Процедура ПослеПолученияДанных(Отправитель, Отказ, ПолучениеИзГлавногоУзла) Экспорт + + Если ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда + Возврат; + КонецЕсли; + + ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); + +КонецПроцедуры + +// См. описание в процедуре ЗаполнитьВсеПараметрыРаботыРасширений +// модуля менеджера регистра сведений ПараметрыРаботыВерсийРасширений. +// +Процедура ПриЗаполненииВсехПараметровРаботыРасширений() Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); + + Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда + // Обновление выполняется в процедуре + // ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации + // или ПриНастройкеПодчиненногоУзлаРИБ. + Возврат; + КонецЕсли; + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); + ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". + РегистрыСведений.НастройкиПравОбъектов.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". + Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); + Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". + Справочники.ГруппыДоступа.ПометитьНаУдалениеГруппыДоступаПомеченныхПрофилей(); + + // Если были нештатные ситуации и обновление не завершилось. + ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); + + // Обновление ролей пользователей ИБ после таких изменений расширений, + // которые приводят к рассогласованию ролей между пользователями ИБ и профилями, + // но не меняют состав ролей профилей. + ОбновитьРолиПользователей(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "ПриЗаполненииВсехПараметровРаботыРасширений"); + +КонецПроцедуры + +// Параметры: +// * Задание - РегламентноеЗадание +// +Процедура ПередЗапускомРегламентногоЗаданияНеВФоне(Задание) Экспорт + + Если Задание.Метаданные <> Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей Тогда + Возврат; + КонецЕсли; + + Задание.Параметры.Добавить(Истина); + Задание.Параметры.Добавить(Истина); + +КонецПроцедуры + +// Обработчики событий подсистемы Пользователи. + +// См. ПользователиПереопределяемый.ПриОпределенииНастроек. +Процедура ПриОпределенииНастроек(Настройки) Экспорт + + // Роли устанавливаются автоматически по данным групп доступа + // через связь: ПользователиГруппыДоступа -> Профиль -> РолиПрофиля. + Настройки.РедактированиеРолей = Ложь; + +КонецПроцедуры + +// См. ПользователиПереопределяемый.ИзменитьДействияВФорме. +Процедура ПриОпределенииДействийВФорме(Знач ПользовательИлиГруппа, Знач ДействияВФорме) Экспорт + + ДействияВФорме.Роли = ""; + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПослеЗаписиАдминистратораПриАвторизации. +Процедура ПослеЗаписиАдминистратораПриАвторизации(Комментарий) Экспорт + + Комментарий = + НСтр("ru = 'Выполнен запуск от имени пользователя с ролью ""Полные права"", + |который не зарегистрирован в списке пользователей. + |Выполнена автоматическая регистрация в списке пользователей. + |Пользователь добавлен в группу доступа Администраторы. + | + |Для ведения списка и настройки прав пользователей предназначен список Пользователи, + |режим конфигурирования 1С:Предприятия для этого использовать не следует.'"); + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПослеУстановкиПользователяИБ. +Процедура ПослеУстановкиПользователяИБ(Ссылка, ПарольПользователяСервиса) Экспорт + + ОбновитьРолиПользователей(Ссылка, ПарольПользователяСервиса); + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + КонецЕсли; + ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Ссылка),, Истина); + КонецЕсли; + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПриОпределенииТекстаВопросаПередЗаписьюПервогоАдминистратора. +Процедура ПриОпределенииТекстаВопросаПередЗаписьюПервогоАдминистратора(ТекстВопроса) Экспорт + + ТекстВопроса = + НСтр("ru = 'В список пользователей приложения добавляется первый пользователь, + |поэтому он будет автоматически включен в группу доступа Администраторы. + |Продолжить?'") + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПриСозданииАдминистратора. +Процедура ПриСозданииИлиАвторизацииАдминистратора(Администратор, Уточнение) Экспорт + + Если ТипЗнч(Администратор) <> Тип("СправочникСсылка.Пользователи") Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Пользователь", Администратор); + Запрос.УстановитьПараметр("ГруппаДоступаАдминистраторы", + УправлениеДоступом.ГруппаДоступаАдминистраторы()); + Запрос.Текст = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + |ГДЕ + | ГруппыДоступаПользователи.Ссылка = &ГруппаДоступаАдминистраторы + | И ГруппыДоступаПользователи.Пользователь = &Пользователь + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ИСТИНА + |ИЗ + | Справочник.Пользователи КАК Пользователи + |ГДЕ + | Пользователи.Служебный + | И Пользователи.Ссылка = &Пользователь"; + + Если Не Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + + КомментарийДляЖурнала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Пользователь ""%1"" добавлен в группу доступа Администраторы по причине: + |%2'"), + Администратор, + Уточнение); + + ГруппаДоступаАдминистраторы = УправлениеДоступом.ГруппаДоступаАдминистраторы(); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступаАдминистраторы); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = ГруппаДоступаАдминистраторы.ПолучитьОбъект(); + ЗаблокироватьДанныеДляРедактирования(Объект.Ссылка, Объект.ВерсияДанных); + Если Объект.Пользователи.Найти(Администратор, "Пользователь") = Неопределено Тогда + Объект.Пользователи.Добавить().Пользователь = Администратор; + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Автоматическое изменение группы доступа Администраторы'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + Метаданные.Справочники.Пользователи, + Администратор, + КомментарийДляЖурнала, + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + КонецЕсли; + РазблокироватьДанныеДляРедактирования(Объект.Ссылка); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПослеОбновленияСоставовГруппПользователей. +Процедура ПослеОбновленияСоставовГруппПользователей(УчастникиИзменений, ИзмененныеГруппы) Экспорт + + Параметры = Новый Структура; + Параметры.Вставить("Пользователи", УчастникиИзменений); + Параметры.Вставить("ГруппыПользователей", ИзмененныеГруппы); + + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); + + ОбновитьРолиПользователей(УчастникиИзменений); + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(УчастникиИзменений); + ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(ИзмененныеГруппы); + КонецЕсли; + +КонецПроцедуры + +// Доопределяет действия, необходимые после изменении объекта авторизации внешнего пользователя. +// +// Параметры: +// ОбъектыАвторизации - Массив из ОпределяемыйТип.ВнешнийПользователь - новый объект авторизации и +// старый объект авторизации (если есть). +// - Неопределено - все объекты авторизации. +// +Процедура ПослеИзмененияОбъектаАвторизацииВнешнегоПользователя(ОбъектыАвторизации) Экспорт + + Параметры = Новый Структура; + Параметры.Вставить("ОбъектыАвторизации", ОбъектыАвторизации); + + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); + +КонецПроцедуры + +// Выполняет копирование прав от одного пользователя другому. +Процедура ПриКопированииПравНовомуПользователю(Источник, Приемник) Экспорт + + Если ТранзакцияАктивна() + И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("Справочник.ГруппыДоступа"); + // АПК:1320-выкл - №499, №783.1.3 Допустимо вызывать блокировку во внешней транзакции для файловой ИБ. + // Требуется для предотвращения взаимоблокировки: ниже запрос, который ставит неявную + // разделяемую блокировку и далее блокировка усиливается до исключительной явным вызовом, + // что приводит к взаимоблокировке в некоторых случаях. + Блокировка.Заблокировать(); + // АПК:1320-вкл. + КонецЕсли; + + УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Пользователь", Источник); + + Если УпрощенныйИнтерфейс Тогда + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Профиль КАК Профиль + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО + | ГруппыДоступа.Пользователь = &Пользователь + | И ГруппыДоступаПользователи.Ссылка = ГруппыДоступа.Ссылка + | И ГруппыДоступаПользователи.Пользователь = &Пользователь"; + Иначе + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + |ГДЕ + | ГруппыДоступаПользователи.Пользователь = &Пользователь"; + КонецЕсли; + + РезультатЗапроса = Запрос.Выполнить(); + Если РезультатЗапроса.Пустой() Тогда + Возврат; + КонецЕсли; + + Выборка = РезультатЗапроса.Выбрать(); + + Если Не УпрощенныйИнтерфейс Тогда + Блокировка = Новый БлокировкаДанных(); + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.ИсточникДанных = РезультатЗапроса; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "ГруппаДоступа"); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Если УпрощенныйИнтерфейс Тогда + Пока Выборка.Следующий() Цикл + УправлениеДоступом.ВключитьОтключитьПрофильПользователя(Приемник, Выборка.Профиль, Истина, Источник); + КонецЦикла; + Иначе + Блокировка.Заблокировать(); + Пока Выборка.Следующий() Цикл + ГруппаДоступаОбъект = Выборка.ГруппаДоступа.ПолучитьОбъект(); // СправочникОбъект.ГруппыДоступа + Если ГруппаДоступаОбъект.Пользователи.Найти(Приемник, "Пользователь") = Неопределено Тогда + Строка = ГруппаДоступаОбъект.Пользователи.Добавить(); + Строка.Пользователь = Приемник; + ГруппаДоступаОбъект.Записать(); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Обработчики событий подсистемы ВариантыОтчетов. + +// См. ВариантыОтчетовПереопределяемый.НастроитьВариантыОтчетов. +Процедура ПриНастройкеВариантовОтчетов(Настройки) Экспорт + + МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов"); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПраваДоступа); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.АнализПравДоступа); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПраваРолей); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.УчастникиГруппДоступа); + +КонецПроцедуры + +// См. ВариантыОтчетовПереопределяемый.ПередДобавлениемКомандОтчетов. +Процедура ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка) Экспорт + + Отчеты.АнализПравДоступа.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); + Отчеты.ПраваРолей.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); + Отчеты.УчастникиГруппДоступа.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); + +КонецПроцедуры + +// Обработчики событий подсистемы РассылкаОтчетов. + +// См. РассылкаОтчетовПереопределяемый.ОпределитьИсключаемыеОтчеты +Процедура ПриОпределенииИсключаемыхОтчетов(ИсключаемыеОтчеты) Экспорт + + ИсключаемыеОтчеты.Добавить(Метаданные.Отчеты.ПраваДоступа); + +КонецПроцедуры + +// Обработчики событий подсистемы КонтрольВеденияУчета. + +// См. ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовИсключаемыхИзПроверки +Процедура ПриОпределенииОбъектовИсключаемыхИзПроверки(Объекты) Экспорт + ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(Объекты); +КонецПроцедуры + +// Обработчики событий подсистемы УправлениеДоступом. + +// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа. +Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт + + Списки.Вставить(Метаданные.Справочники.ПрофилиГруппДоступа, Истина); + Списки.Вставить(Метаданные.Справочники.ГруппыДоступа, Истина); + +КонецПроцедуры + +// Обработчики событий библиотеки ТехнологияСервиса. + +// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных +Процедура ПриРегистрацииОбработчиковВыгрузкиДанных(ТаблицаОбработчиков) Экспорт + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.Справочники.ПрофилиГруппДоступа; + Обработчик.Обработчик = Справочники.ПрофилиГруппДоступа; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.Справочники.ГруппыДоступа; + Обработчик.Обработчик = Справочники.ГруппыДоступа; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ЗначенияГруппДоступа; + Обработчик.Обработчик = РегистрыСведений.ЗначенияГруппДоступа; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию; + Обработчик.Обработчик = РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + +КонецПроцедуры + +// Процедуры и функция для подсистемы Пользователи. + +Функция ТекстЗапросаГруппДоступаПриИзмененииУчастниковГруппПользователей() Экспорт + + Возврат + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | УчастникиГруппДоступа.Ссылка КАК ГруппаДоступа, + | УчастникиГруппДоступа.Пользователь КАК Участник, + | УчастникиГруппДоступа.СрокДействия КАК СрокДействия + |ПОМЕСТИТЬ УчастникиГруппДоступа + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ЛЕВОЕ СОЕДИНЕНИЕ ИзмененияСоставов КАК ИзмененияСоставовГрупп + | ПО (ИзмененияСоставовГрупп.ГруппаПользователей = УчастникиГруппДоступа.Пользователь) + | ЛЕВОЕ СОЕДИНЕНИЕ ИзмененияСоставов КАК ИзмененияАктивностиПользователей + | ПО (ИзмененияАктивностиПользователей.Пользователь = УчастникиГруппДоступа.Пользователь) + | И (ИзмененияАктивностиПользователей.ГруппаПользователей = &ГруппаВсеПользователи) + |ГДЕ + | (НЕ ИзмененияСоставовГрупп.ГруппаПользователей ЕСТЬ NULL + | ИЛИ НЕ ИзмененияАктивностиПользователей.Пользователь ЕСТЬ NULL) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | УчастникиГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | УчастникиГруппДоступа.Участник КАК Участник, + | УчастникиГруппДоступа.СрокДействия КАК СрокДействия + |ИЗ + | УчастникиГруппДоступа КАК УчастникиГруппДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК ГруппаДоступа, + | ПРЕДСТАВЛЕНИЕ(ГруппыДоступа.Ссылка) КАК Представление, + | ГруппыДоступа.ПометкаУдаления КАК ПометкаУдаления, + | ГруппыДоступа.Профиль КАК Профиль, + | ПРЕДСТАВЛЕНИЕ(ГруппыДоступа.Профиль) КАК ПредставлениеПрофиля, + | ЕСТЬNULL(ГруппыДоступа.Профиль.ПометкаУдаления, ИСТИНА) КАК ПометкаУдаленияПрофиля + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Ссылка В + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | УчастникиГруппДоступа.ГруппаДоступа + | ИЗ + | УчастникиГруппДоступа КАК УчастникиГруппДоступа)"; + +КонецФункции + +// Процедуры и функции подсистемы ЦентрМониторинга. + +// Возвращает текст запроса для сбора статистической информации об использовании профилей групп доступа и ролей. +// +// Возвращаемое значение: +// Строка +// +Функция ТекстЗапросаИспользованияРолей() Экспорт + + Возврат + "ВЫБРАТЬ + | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, + | СведенияОПользователях.Пользователь КАК Пользователь, + | ВЫБОР + | КОГДА РАЗНОСТЬДАТ(СведенияОПользователях.ДатаПоследнейАктивности, &ТекущаяДата, ДЕНЬ) <= 7 + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ КАК АктивныхЗаНеделю, + | ВЫБОР + | КОГДА РАЗНОСТЬДАТ(СведенияОПользователях.ДатаПоследнейАктивности, &ТекущаяДата, ДЕНЬ) <= 30 + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ КАК АктивныхЗаМесяц + |ПОМЕСТИТЬ ВТСоставыГруппИАктивность + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОПользователях КАК СведенияОПользователях + | ПО СоставыГруппПользователей.Пользователь = СведенияОПользователях.Пользователь + |ГДЕ + | СоставыГруппПользователей.Используется + | И НЕ СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ = &ПустойУИД + | + |ИНДЕКСИРОВАТЬ ПО + | ГруппаПользователей, + | Пользователь + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ПрофилиГруппДоступа.Ссылка КАК Профиль, + | ПрофилиГруппДоступа.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, + | ПрофилиГруппДоступа.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен, + | ПрофилиГруппДоступа.Наименование КАК Наименование, + | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа, + | ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = НЕОПРЕДЕЛЕНО КАК ОбщаяГруппаДоступа, + | ГруппыДоступаПользователи.Пользователь КАК ПользовательТЧ, + | СоставыГруппПользователей.Пользователь КАК ПользовательРС, + | СоставыГруппПользователей.АктивныхЗаНеделю КАК АктивныхЗаНеделю, + | СоставыГруппПользователей.АктивныхЗаМесяц КАК АктивныхЗаМесяц + |ПОМЕСТИТЬ ВТДанныеПрофилей + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТСоставыГруппИАктивность КАК СоставыГруппПользователей + | ПО ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + | ПО (ПрофилиГруппДоступа.Ссылка = ГруппыДоступаПользователи.Ссылка.Профиль) + | И (НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления) + |ГДЕ + | НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления + | + |СГРУППИРОВАТЬ ПО + | ПрофилиГруппДоступа.Ссылка, + | ПрофилиГруппДоступа.Наименование, + | ГруппыДоступаПользователи.Пользователь, + | СоставыГруппПользователей.Пользователь, + | СоставыГруппПользователей.АктивныхЗаНеделю, + | СоставыГруппПользователей.АктивныхЗаМесяц, + | ГруппыДоступаПользователи.Ссылка, + | ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = НЕОПРЕДЕЛЕНО, + | ПрофилиГруппДоступа.ИдентификаторПоставляемыхДанных, + | ПрофилиГруппДоступа.ПоставляемыйПрофильИзменен + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.Наименование КАК Наименование, + | ВТДанныеПрофилей.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, + | ВТДанныеПрофилей.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен + |ПОМЕСТИТЬ Профили + |ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Профили.Профиль КАК Профиль, + | СУММА(ВЫБОР + | КОГДА НЕ ПрофилиГруппДоступаВидыДоступа.ВидДоступа ЕСТЬ NULL + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ВсегоВидовДоступа, + | СУММА(ВЫБОР + | КОГДА ЕСТЬNULL(ПрофилиГруппДоступаВидыДоступа.Предустановленный, ЛОЖЬ) + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ПредустановленныхВидовДоступа + |ПОМЕСТИТЬ ВидыДоступа + |ИЗ + | Профили КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.ВидыДоступа КАК ПрофилиГруппДоступаВидыДоступа + | ПО Профили.Профиль = ПрофилиГруппДоступаВидыДоступа.Ссылка + | + |СГРУППИРОВАТЬ ПО + | Профили.Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Вложенный.Профиль КАК Профиль, + | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Вложенный.ГруппаДоступа) КАК ГруппаДоступа, + | СУММА(ВЫБОР + | КОГДА НЕ Вложенный.ОбщаяГруппаДоступа + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ПерсональнаяГруппа + |ПОМЕСТИТЬ ГруппыДоступа + |ИЗ + | (ВЫБРАТЬ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.ГруппаДоступа КАК ГруппаДоступа, + | ВТДанныеПрофилей.ОбщаяГруппаДоступа КАК ОбщаяГруппаДоступа + | ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + | СГРУППИРОВАТЬ ПО + | ВТДанныеПрофилей.Профиль, + | ВТДанныеПрофилей.ГруппаДоступа, + | ВТДанныеПрофилей.ОбщаяГруппаДоступа) КАК Вложенный + | + |СГРУППИРОВАТЬ ПО + | Вложенный.Профиль + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Вложенный.Профиль КАК Профиль, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательТЧ ССЫЛКА Справочник.ГруппыПользователей + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ГруппПользователей, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательТЧ ССЫЛКА Справочник.ГруппыВнешнихПользователей + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ГруппВнешнихПользователей + |ПОМЕСТИТЬ ГруппыПользователей + |ИЗ + | (ВЫБРАТЬ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.ПользовательТЧ КАК ПользовательТЧ + | ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + | СГРУППИРОВАТЬ ПО + | ВТДанныеПрофилей.Профиль, + | ВТДанныеПрофилей.ПользовательТЧ) КАК Вложенный + | + |СГРУППИРОВАТЬ ПО + | Вложенный.Профиль + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Вложенный.Профиль КАК Профиль, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательРС ССЫЛКА Справочник.Пользователи + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК Пользователи, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательРС ССЫЛКА Справочник.ВнешниеПользователи + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ВнешниеПользователи, + | СУММА(Вложенный.АктивныхЗаНеделю) КАК АктивныхЗаНеделю, + | СУММА(Вложенный.АктивныхЗаМесяц) КАК АктивныхЗаМесяц + |ПОМЕСТИТЬ ПользователиПрофиля + |ИЗ + | (ВЫБРАТЬ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.ПользовательРС КАК ПользовательРС, + | СУММА(ВТДанныеПрофилей.АктивныхЗаНеделю) КАК АктивныхЗаНеделю, + | СУММА(ВТДанныеПрофилей.АктивныхЗаМесяц) КАК АктивныхЗаМесяц + | ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + | СГРУППИРОВАТЬ ПО + | ВТДанныеПрофилей.Профиль, + | ВТДанныеПрофилей.ПользовательРС) КАК Вложенный + | + |СГРУППИРОВАТЬ ПО + | Вложенный.Профиль + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Профили.Профиль КАК Профиль, + | Профили.Наименование КАК Наименование, + | Профили.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, + | Профили.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен, + | ЕСТЬNULL(ГруппыДоступа.ГруппаДоступа, 0) КАК ГруппаДоступа, + | ЕСТЬNULL(ГруппыДоступа.ПерсональнаяГруппа, 0) КАК ПерсональнаяГруппа, + | ЕСТЬNULL(ГруппыПользователей.ГруппПользователей, 0) КАК ГруппПользователей, + | ЕСТЬNULL(ГруппыПользователей.ГруппВнешнихПользователей, 0) КАК ГруппВнешнихПользователей, + | ЕСТЬNULL(ПользователиПрофиля.Пользователи, 0) КАК Пользователи, + | ЕСТЬNULL(ПользователиПрофиля.ВнешниеПользователи, 0) КАК ВнешниеПользователи, + | ЕСТЬNULL(ПользователиПрофиля.АктивныхЗаНеделю, 0) КАК АктивныхЗаНеделю, + | ЕСТЬNULL(ПользователиПрофиля.АктивныхЗаМесяц, 0) КАК АктивныхЗаМесяц, + | ЕСТЬNULL(ВидыДоступа.ВсегоВидовДоступа, 0) КАК ВсегоВидовДоступа, + | ЕСТЬNULL(ВидыДоступа.ПредустановленныхВидовДоступа, 0) КАК ПредустановленныхВидовДоступа + |ИЗ + | Профили КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ ПользователиПрофиля КАК ПользователиПрофиля + | ПО Профили.Профиль = ПользователиПрофиля.Профиль + | ЛЕВОЕ СОЕДИНЕНИЕ ГруппыПользователей КАК ГруппыПользователей + | ПО Профили.Профиль = ГруппыПользователей.Профиль + | ЛЕВОЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа + | ПО Профили.Профиль = ГруппыДоступа.Профиль + | ЛЕВОЕ СОЕДИНЕНИЕ ВидыДоступа КАК ВидыДоступа + | ПО Профили.Профиль = ВидыДоступа.Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | Профили.Профиль КАК Профиль, + | ЕСТЬNULL(ПрофилиГруппДоступаРоли.Роль.Имя, """") КАК РольИмя + |ИЗ + | Профили КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиГруппДоступаРоли + | ПО Профили.Профиль = ПрофилиГруппДоступаРоли.Ссылка + | И (Профили.ИдентификаторПоставляемыхДанных = &ПустойУИД + | ИЛИ Профили.ПоставляемыйПрофильИзменен) + | + |УПОРЯДОЧИТЬ ПО + | Профиль"; + +КонецФункции + +// Проверяет доступность общей команды НастроитьПрава. +// +// Возвращаемое значение: +// Булево +// +Функция ДоступнаКомандаНастройкиПрав() Экспорт + Возврат ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.НастроитьПрава); +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных. +Процедура ПередВыгрузкойОбъекта(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт + + // Роли расширений назначаются независимо в коробке и в сервисе. + Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширений(Объект); + КонецЕсли; + + // В модели сервиса право открытия внешних отчетов и обработок не используется для пользователей областей данных, + // поэтому проверка применяется только при переходе Коробка -> Сервис. + Если ОбщегоНазначения.РазделениеВключено() Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + Профиль = Объект; + + ИначеЕсли ТипЗнч(Объект) = Тип("СправочникОбъект.ГруппыДоступа") И Не Объект.ЭтоГруппа Тогда + Профиль = Объект.Профиль; + Иначе + Возврат; + КонецЕсли; + + Если ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(Профиль) Тогда + Отказ = Истина; + КонецЕсли; + +КонецПроцедуры + +// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных. +Процедура ПередВыгрузкойНабораЗаписей(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт + + // В модели сервиса право открытия внешних отчетов и обработок не используется для пользователей областей данных, + // поэтому проверка применяется только при переходе Коробка -> Сервис. + Если ОбщегоНазначения.РазделениеВключено() Тогда + Возврат; + КонецЕсли; + + ГруппыДоступа = ГруппыДоступаПрофиляОткрытиеВнешнихОтчетовИОбработок(); + + Индекс = Объект.Количество() - 1; + Пока Индекс >= 0 Цикл + Если ГруппыДоступа.Найти(Объект[Индекс].ГруппаДоступа) <> Неопределено Тогда + Объект.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + +КонецПроцедуры + +// Параметры: +// ИмяПараметра - Строка +// УстановленныеПараметры - Массив из Строка +// +Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт + +#Область УниверсальноеОграничение + Если ИмяПараметра = "ПараметрыОграниченияДоступа" Тогда + ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(Новый Структура); + УстановленныеПараметры.Добавить("ПараметрыОграниченияДоступа"); + Возврат; + КонецЕсли; + + Если ИмяПараметра = "ОтключениеОбновленияКлючейДоступа" Тогда + ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа = НовоеОтключениеОбновленияКлючейДоступа(); + УстановленныеПараметры.Добавить("ОтключениеОбновленияКлючейДоступа"); + Возврат; + КонецЕсли; + + УниверсальноеОграничение = ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина, Ложь); + + Если ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально" + Или ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально <> УниверсальноеОграничение Тогда + + ПередИзменениемПараметровСеансаДляШаблонов( + Новый Структура("ОграничениеДоступаНаУровнеЗаписейУниверсально", УниверсальноеОграничение), + ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально"); + + ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально = УниверсальноеОграничение; + КонецЕсли; + + УстановленныеПараметры.Добавить("ОграничениеДоступаНаУровнеЗаписейУниверсально"); + Если ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально" Тогда + Возврат; + КонецЕсли; +#КонецОбласти + + // Для корректной работы препроцессора в ограничениях доступа, требуется инициализации всех + // параметров сеанса, которые могут быть востребованы в работе препроцессора. + ОграничиватьДоступНаУровнеЗаписей = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + ИнформационнаяБазаЗаблокированаДляОбновления = ЗначениеЗаполнено( + ОбновлениеИнформационнойБазыСлужебный.ИнформационнаяБазаЗаблокированаДляОбновления(Ложь)); + +#Область УниверсальноеОграничение + Если Не ОграничиватьДоступНаУровнеЗаписей + Или Не УниверсальноеОграничение + Или ИнформационнаяБазаЗаблокированаДляОбновления Тогда + + ПараметрыСеанса.СпискиСОтключеннымОграничениемЧтения = + ?(ИнформационнаяБазаЗаблокированаДляОбновления + Или Не УниверсальноеОграничение, "Неопределено", "Все"); + + ПустойНаборГруппДоступа = Справочники.НаборыГруппДоступа.ПустаяСсылка(); + + ПараметрыСеанса.ВерсииШаблоновОграниченияДоступа = ВерсииШаблоновОграниченияДоступа(); + ПараметрыСеанса.РазрешенныйНаборГруппДоступа = ПустойНаборГруппДоступа; + ПараметрыСеанса.РазрешенныйПустойНаборГруппДоступа = ПустойНаборГруппДоступа; + ПараметрыСеанса.РазрешенныйНаборГруппПользователей = ПустойНаборГруппДоступа; + ПараметрыСеанса.РазрешенныйПользователь = ПустойНаборГруппДоступа; + ПараметрыСеанса.ОбщиеПараметрыШаблоновОграниченияДоступа = ""; + ПараметрыСеанса.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = ""; + ПараметрыСеанса.СпискиСОграничениемЧерезКлючиДоступаПользователей = ""; + ПараметрыСеанса.СпискиСОграничениемПоПолям = ""; + + УстановленныеПараметры.Добавить("СпискиСОтключеннымОграничениемЧтения"); + УстановленныеПараметры.Добавить("ВерсииШаблоновОграниченияДоступа"); + УстановленныеПараметры.Добавить("РазрешенныйНаборГруппДоступа"); + УстановленныеПараметры.Добавить("РазрешенныйПустойНаборГруппДоступа"); + УстановленныеПараметры.Добавить("РазрешенныйНаборГруппПользователей"); + УстановленныеПараметры.Добавить("РазрешенныйПользователь"); + УстановленныеПараметры.Добавить("ОбщиеПараметрыШаблоновОграниченияДоступа"); + УстановленныеПараметры.Добавить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа"); + УстановленныеПараметры.Добавить("СпискиСОграничениемЧерезКлючиДоступаПользователей"); + УстановленныеПараметры.Добавить("СпискиСОграничениемПоПолям"); + КонецЕсли; +#КонецОбласти + + Если Не ОграничиватьДоступНаУровнеЗаписей + Или УниверсальноеОграничение + Или ИнформационнаяБазаЗаблокированаДляОбновления Тогда + + ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейИспользуется = + ?(ИнформационнаяБазаЗаблокированаДляОбновления + Или УниверсальноеОграничение, "", Ложь); + + ПараметрыСеанса.ВсеВидыДоступаКромеСпециальных = ""; + ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием = ""; + ПараметрыСеанса.ВидыДоступаБезГруппДляЗначенияДоступа = ""; + ПараметрыСеанса.ВидыДоступаСОднойГруппойДляЗначенияДоступа = ""; + + ПараметрыСеанса.ТипыЗначенийДоступаСГруппами + = Новый ФиксированныйМассив(Новый Массив); + + ПараметрыСеанса.ТаблицыСОтдельнымиНастройкамиПрав = ""; + + ПараметрыСеанса.ИдентификаторыТаблицСОтдельнымиНастройкамиПрав + = Новый ФиксированныйМассив(Новый Массив); + + ПараметрыСеанса.ТипыВладельцевНастроекПрав + = Новый ФиксированныйМассив(Новый Массив); + + ПараметрыСеанса.ТаблицыРасширенийСОграничениемДоступа = ""; + + УстановленныеПараметры.Добавить("ОграничениеДоступаНаУровнеЗаписейИспользуется"); + УстановленныеПараметры.Добавить("ВсеВидыДоступаКромеСпециальных"); + УстановленныеПараметры.Добавить("ВидыДоступаСОтключеннымИспользованием"); + УстановленныеПараметры.Добавить("ВидыДоступаБезГруппДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ВидыДоступаСОднойГруппойДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ТипыЗначенийДоступаСГруппами"); + УстановленныеПараметры.Добавить("ТаблицыСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ТипыВладельцевНастроекПрав"); + УстановленныеПараметры.Добавить("ТаблицыРасширенийСОграничениемДоступа"); + КонецЕсли; + + Если ИнформационнаяБазаЗаблокированаДляОбновления Тогда + Возврат; + КонецЕсли; + +#Область УниверсальноеОграничение + Если УниверсальноеОграничение Тогда + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь, Истина); + Возврат; + КонецЕсли; +#КонецОбласти + + Если Не ОграничиватьДоступНаУровнеЗаписей Тогда + Возврат; + КонецЕсли; + + ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейИспользуется = Истина; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.АвторизованныйПользователь()); + Запрос.Текст = + "ВЫБРАТЬ + | ЗначенияПоУмолчанию.ТипЗначенийДоступа КАК ТипЗначений + |ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Ссылка = ЗначенияПоУмолчанию.ГруппаДоступа) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) + | И (СоставыГруппПользователей.Пользователь = &ТекущийПользователь) + | + |СГРУППИРОВАТЬ ПО + | ЗначенияПоУмолчанию.ТипЗначенийДоступа + | + |ИМЕЮЩИЕ + | МИНИМУМ(ЗначенияПоУмолчанию.ВсеРазрешеныБезИсключений) = ИСТИНА"; + + ТипыЗначенийВсеРазрешеныБезИсключений = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ТипЗначений"); + + // Установка параметров ВсеВидыДоступаКромеСпециальных, ВидыДоступаСОтключеннымИспользованием. + ВсеВидыДоступаКромеСпециальных = Новый Массив; + ВидыДоступаСОтключеннымИспользованием = Новый Массив; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); + + Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл + ВсеВидыДоступаКромеСпециальных.Добавить(СвойстваВидаДоступа.Имя); + + Если ИспользуемыеВидыДоступа.Получить(СвойстваВидаДоступа.Ссылка) = Неопределено + Или ТипыЗначенийВсеРазрешеныБезИсключений.Найти(СвойстваВидаДоступа.Ссылка) <> Неопределено Тогда + + ВидыДоступаСОтключеннымИспользованием.Добавить(СвойстваВидаДоступа.Имя); + КонецЕсли; + КонецЦикла; + + ПараметрыСеанса.ВсеВидыДоступаКромеСпециальных = ВсеКомбинацииВидовДоступа(ВсеВидыДоступаКромеСпециальных); + + УстановленныеПараметры.Добавить("ВсеВидыДоступаКромеСпециальных"); + + ВсеВидыДоступаКромеСпециальныхОтключены = (ВсеВидыДоступаКромеСпециальных.Количество() + = ВидыДоступаСОтключеннымИспользованием.Количество()); + + Если ВсеВидыДоступаКромеСпециальныхОтключены Тогда + ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием = "Все"; + Иначе + ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием + = ВсеКомбинацииВидовДоступа(ВидыДоступаСОтключеннымИспользованием); + КонецЕсли; + + УстановленныеПараметры.Добавить("ВидыДоступаСОтключеннымИспользованием"); + + // Установка параметров ВидыДоступаБезГруппДляЗначенияДоступа, + // ВидыДоступаСОднойГруппойДляЗначенияДоступа, ТипыЗначенийДоступаСГруппами. + ПараметрыСеанса.ВидыДоступаБезГруппДляЗначенияДоступа = + ВсеКомбинацииВидовДоступа(СвойстваВидовДоступа.БезГруппДляЗначенияДоступа); + ПараметрыСеанса.ВидыДоступаСОднойГруппойДляЗначенияДоступа = + ВсеКомбинацииВидовДоступа(СвойстваВидовДоступа.СОднойГруппойДляЗначенияДоступа); + + ТипыЗначенийДоступаСГруппами = Новый Массив; + Для каждого КлючИЗначение Из СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами Цикл + ТипыЗначенийДоступаСГруппами.Добавить(КлючИЗначение.Значение); + КонецЦикла; + ПараметрыСеанса.ТипыЗначенийДоступаСГруппами = Новый ФиксированныйМассив(ТипыЗначенийДоступаСГруппами); + + УстановленныеПараметры.Добавить("ВидыДоступаБезГруппДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ВидыДоступаСОднойГруппойДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ТипыЗначенийДоступаСГруппами"); + + // Установка параметров ТаблицыСОтдельнымиНастройкамиПрав, + // ИдентификаторыТаблицСОтдельнымиНастройкамиПрав, ТипыВладельцевНастроекПрав. + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ОтдельныеТаблицы = ВозможныеПрава.ОтдельныеТаблицы; + ТаблицыСОтдельнымиНастройкамиПрав = ""; + ИдентификаторыТаблицСОтдельнымиНастройкамиПрав = Новый Массив; + Для каждого КлючИЗначение Из ОтдельныеТаблицы Цикл + ТаблицыСОтдельнымиНастройкамиПрав = ТаблицыСОтдельнымиНастройкамиПрав + + "|" + КлючИЗначение.Значение + ";" + Символы.ПС; + ИдентификаторыТаблицСОтдельнымиНастройкамиПрав.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + + ПараметрыСеанса.ТаблицыСОтдельнымиНастройкамиПрав = ТаблицыСОтдельнымиНастройкамиПрав; + + ПараметрыСеанса.ИдентификаторыТаблицСОтдельнымиНастройкамиПрав = + Новый ФиксированныйМассив(ИдентификаторыТаблицСОтдельнымиНастройкамиПрав); + + ПараметрыСеанса.ТипыВладельцевНастроекПрав = ВозможныеПрава.ТипыВладельцев; + + ПолныеИмена = Справочники.ИдентификаторыОбъектовРасширений.ПолныеИменаТаблицСДанными(); + ТаблицыРасширений = СтрСоединить(ПолныеИмена, ";" + Символы.ПС + "|"); + ТаблицыРасширений = ?(ТаблицыРасширений = "", "", "|" + ТаблицыРасширений + ";" + Символы.ПС); + + ПараметрыСеанса.ТаблицыРасширенийСОграничениемДоступа = ТаблицыРасширений; + + УстановленныеПараметры.Добавить("ТаблицыСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ТипыВладельцевНастроекПрав"); + УстановленныеПараметры.Добавить("ТаблицыРасширенийСОграничениемДоступа"); + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Стандартное - Булево +// * Полное - Булево +// * ВложенныеОтключения - ФиксированныйМассив +// * ИзмененныеСписки - ХранилищеЗначения +// +Функция НовоеОтключениеОбновленияКлючейДоступа() Экспорт + + Свойства = Новый Структура; + Свойства.Вставить("Стандартное", Ложь); + Свойства.Вставить("Полное", Ложь); + Свойства.Вставить("ВложенныеОтключения", Новый ФиксированныйМассив(Новый Массив)); + Свойства.Вставить("ИзмененныеСписки", Новый ХранилищеЗначения(Новый Соответствие)); + + Возврат Новый ФиксированнаяСтруктура(Свойства); + +КонецФункции + +// Только для внутреннего использования. +Процедура ОбновитьПараметрыСеанса() Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + УстановленныеПараметры = Новый Массив; + УстановкаПараметровСеанса("", УстановленныеПараметры); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + ОбновитьПовторноИспользуемыеЗначения(); + +КонецПроцедуры + +// Проверка группы доступа Администраторы перед записью. +Процедура ПроверитьНаличиеПользователяИБВГруппеДоступаАдминистраторы(ПользователиГруппы, ОписаниеОшибки) Экспорт + + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + + // Проверка пустого списка пользователей ИБ в группе доступа Администраторы. + УстановитьПривилегированныйРежим(Истина); + НайденДействующийАдминистратор = Ложь; + + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + + Если Не ЗначениеЗаполнено(ОписаниеПользователя.Пользователь) + Или ТипЗнч(ОписаниеПользователя.Пользователь) <> Тип("СправочникСсылка.Пользователи") + И ТипЗнч(ОписаниеПользователя.Пользователь) <> Тип("СправочникСсылка.Пользователи") Тогда + Продолжить; + КонецЕсли; + + ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( + ОписаниеПользователя.Пользователь.ИдентификаторПользователяИБ); + + Если ПользовательИБ <> Неопределено + И Пользователи.ВходВПрограммуРазрешен(ПользовательИБ) Тогда + + НайденДействующийАдминистратор = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Если НЕ НайденДействующийАдминистратор Тогда + ОписаниеОшибки = + НСтр("ru = 'В группе доступа Администраторы + |должен быть хотя бы один пользователь, + |которому разрешен вход в приложение.'"); + КонецЕсли; + +КонецПроцедуры + +// См. УправлениеДоступом.ЕстьОграничениеТаблицыПоВидуДоступа +Функция ЕстьОграничениеТаблицыПоВидуДоступа(Таблица, ВидДоступа, ВсеВидыДоступа) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + ВидыДоступаСОтключеннымИспользованием = ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием; + Если ВидыДоступаСОтключеннымИспользованием = "Все" + Или СтрНайти(ВидыДоступаСОтключеннымИспользованием, "," + ВидДоступа + ",") > 0 Тогда + Возврат Ложь; + КонецЕсли; + + МассивВидовДоступа = СтрРазделить(ВсеВидыДоступа, ",", Ложь); + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в функции %1 общего модуля %2.'"), + "ЕстьОграничениеТаблицыПоВидуДоступа", "УправлениеДоступом") + + Символы.ПС; + + СвойстваВидаДоступа = СвойстваВидовДоступа.ПоИменам.Получить(ВидДоступа); + Если СвойстваВидаДоступа = Неопределено Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует вид доступа ""%1"", указанный в параметре %2.'"), + ВидДоступа, "ВидДоступа"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + ВидДоступаСсылка = СвойстваВидаДоступа.Ссылка; + + ВсеВидыДоступаТаблицыСОтключеннымИспользованием = Истина; + ИспользованиеВидовДоступа = Новый Соответствие; + ВидДоступаУказанВоВсехВидахДоступа = Ложь; + + Для Каждого ТекущийВидДоступа Из МассивВидовДоступа Цикл + ТекущийВидДоступа = СокрЛП(ТекущийВидДоступа); + СвойстваВидаДоступа = СвойстваВидовДоступа.ПоИменам.Получить(ТекущийВидДоступа); + Если СвойстваВидаДоступа = Неопределено Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует вид доступа ""%1"", указанный в параметре + |%2: ""%3"".'"), + ТекущийВидДоступа, "ВсеВидыДоступа", ВсеВидыДоступа); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + Если СвойстваВидаДоступа.Имя = ВидДоступа Тогда + ВидДоступаУказанВоВсехВидахДоступа = Истина; + КонецЕсли; + Используется = СтрНайти(ВидыДоступаСОтключеннымИспользованием, "," + СвойстваВидаДоступа.Имя + ",") = 0; + ИспользованиеВидовДоступа.Вставить(СвойстваВидаДоступа.Ссылка, Используется); + Если Используется Тогда + ВсеВидыДоступаТаблицыСОтключеннымИспользованием = Ложь; + КонецЕсли; + КонецЦикла; + + Если Не ВидДоступаУказанВоВсехВидахДоступа Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Вид доступа ""%1"", указанный в параметре %2 не существует в параметре + |%3: ""%4"".'"), + ВидДоступа, "ВидДоступа", "ВсеВидыДоступа", ВсеВидыДоступа); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если ВсеВидыДоступаТаблицыСОтключеннымИспользованием Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИмяОсновнойТаблицыСписка", Таблица); + Запрос.УстановитьПараметр("АвторизованныйПользователь", Пользователи.АвторизованныйПользователь()); + + Запрос.Текст = ТекстЗапросаГруппДоступа(); + + ТекстЗапроса = + "ВЫБРАТЬ + | ЗначенияПоУмолчанию.ГруппаДоступа КАК ГруппаДоступа, + | ЗначенияПоУмолчанию.ТипЗначенийДоступа КАК ВидДоступа + |ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступаПользователя КАК ГруппыДоступаПользователя + | ПО ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступаПользователя.Ссылка + |ГДЕ + | НЕ ЗначенияПоУмолчанию.ВсеРазрешеныБезИсключений + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | ГруппыДоступаПользователи.Ссылка = ЗначенияПоУмолчанию.ГруппаДоступа + | И ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | И СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь)"; + + ДобавитьЗапросВПакет(Запрос.Текст, ТекстЗапроса); + Выборка = Запрос.Выполнить().Выбрать(); + + НастроенныеВидыДоступаГруппДоступа = Новый Соответствие; + ЕстьГруппаДоступаСОграничениемПоВидуДоступа = Ложь; + + Пока Выборка.Следующий() Цикл + НастроенныеВидыДоступа = НастроенныеВидыДоступаГруппДоступа.Получить(Выборка.ГруппаДоступа); + Если НастроенныеВидыДоступа = Неопределено Тогда + НастроенныеВидыДоступа = Новый Соответствие; + НастроенныеВидыДоступаГруппДоступа.Вставить(Выборка.ГруппаДоступа, НастроенныеВидыДоступа); + КонецЕсли; + Если ИспользованиеВидовДоступа.Получить(Выборка.ВидДоступа) = Неопределено Тогда + Продолжить; + КонецЕсли; + НастроенныеВидыДоступа.Вставить(Выборка.ВидДоступа, Истина); + Если Выборка.ВидДоступа = ВидДоступаСсылка Тогда + ЕстьГруппаДоступаСОграничениемПоВидуДоступа = Истина; + КонецЕсли; + КонецЦикла; + + ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа = Ложь; + + Для Каждого ОписаниеГруппыДоступа Из НастроенныеВидыДоступаГруппДоступа Цикл + НастроенныеВидыДоступа = ОписаниеГруппыДоступа.Значение; + ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа = Истина; + Для Каждого ОписаниеИспользованияВидаДоступа Из ИспользованиеВидовДоступа Цикл + Если Не ОписаниеИспользованияВидаДоступа.Значение Тогда + Продолжить; // Не используется. + КонецЕсли; + Если НастроенныеВидыДоступа.Получить(ОписаниеИспользованияВидаДоступа.Ключ) = Неопределено Тогда + Продолжить; // ВсеРазрешеныБезИсключений или ограничения по виду доступа нет. + КонецЕсли; + ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа = Ложь; + Прервать; + КонецЦикла; + Если ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа Тогда + ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Если ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа Тогда + Возврат Ложь; + КонецЕсли; + + Возврат ЕстьГруппаДоступаСОграничениемПоВидуДоступа; + +КонецФункции + +// Параметры: +// Объекты - см. ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению.Объекты +// ПолноеИмяИзмерения - см. ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению.Объект +// ТребуемыеТипы - ОписаниеТипов +// УказанныеТипы - ОписаниеТипов +// +Процедура ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыеТипы, МетаданныеИзмерения) + + Если ТребуемыеТипы.Типы().Количество() = 0 Тогда + ЛишниеТипы = МетаданныеИзмерения.Тип; + Иначе + ЛишниеТипы = Новый ОписаниеТипов(МетаданныеИзмерения.Тип,, ТребуемыеТипы.Типы()); + КонецЕсли; + + Если ЛишниеТипы.Типы().Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ЧастиИмени = СтрРазделить(МетаданныеИзмерения.ПолноеИмя(), "."); + ЧастиИмени.Удалить(2); + + ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению(Объекты, + СтрСоединить(ЧастиИмени, "."), ЛишниеТипы); + +КонецПроцедуры + +#Область ОбработчикиПодписокНаСобытия + +// Обработчик подписки ОбновитьГруппыЗначенийДоступаПередЗаписью: +// - проверяет изменение родителя и готовит группы доступа, в которых +// нужно обновить значения доступа, выбранные с учетом иерархии. +// +Процедура ОбновитьГруппыЗначенийДоступаПередЗаписью(Знач Источник, Отказ) Экспорт + + // АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал. + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) + Или Источник.ОбменДанными.Загрузка + И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + Если ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() + Или Не Источник.ОбменДанными.Загрузка Тогда + + Если Не ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + УправлениеДоступом.УстановитьБлокировкуПередЗаписьюВФайловойИБ(, Истина); + КонецЕсли; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + СтарыеЗначения = Новый Структура; + Если СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(ТипЗнч(Источник)) <> Неопределено Тогда + СтарыеЗначения.Вставить("Родитель", ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "Родитель")); + КонецЕсли; + Свойства = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипЗнч(Источник)); + Если Свойства <> Неопределено + И Свойства.ТипГруппЗначений <> Тип("Неопределено") + И ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() Тогда + + ИмяПоля = ?(Свойства.НесколькоГруппЗначений, "ГруппыДоступа", "ГруппаДоступа"); + Попытка + ЗначениеПоля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, ИмяПоля); + Исключение + ИменаТаблиц = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Источник.Метаданные().ПолноеИмя()); + ПоТипамСсылокДляОбновления = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления; + РегистрыСведений.ГруппыЗначенийДоступа.ПроверитьМетаданныеТаблиц(ИменаТаблиц, ПоТипамСсылокДляОбновления); + ВызватьИсключение; + КонецПопытки; + СтарыеЗначения.Вставить(ИмяПоля, ЗначениеПоля); + КонецЕсли; + Если ЗначениеЗаполнено(СтарыеЗначения) Тогда + Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомСтарыеЗначения", СтарыеЗначения); + КонецЕсли; + КонецЕсли; + // АПК:75-вкл + + Если Источник.ОбменДанными.Загрузка Тогда + Возврат; + КонецЕсли; + + Если Свойства <> Неопределено Тогда + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(Источник); + КонецЕсли; + +КонецПроцедуры + +// Обработчик подписки ОбновитьГруппыЗначенийДоступаПриЗаписи: +// - вызывает метод записи групп значений доступа в +// регистр сведений ГруппыЗначенийДоступа для требуемых объектов метаданных, +// - обновляет значения групп доступа, выбранные с учетом иерархии. +// +Процедура ОбновитьГруппыЗначенийДоступаПриЗаписи(Источник) Экспорт + + // АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал. + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) + Или Источник.ОбменДанными.Загрузка + И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + Если ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() + И Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомСтарыеЗначения") Тогда + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеРазрешенныхЗначений(Источник, + Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + КонецЕсли; + // АПК:75-вкл + + Если Источник.ОбменДанными.Загрузка Тогда + Возврат; + КонецЕсли; + + Если Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомСтарыеЗначения") + И Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения.Свойство("Родитель") + И Источник.Родитель <> Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения.Родитель Тогда + + ГруппыДоступа = ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипЗнч(Источник.Ссылка)); + РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(ГруппыДоступа); + КонецЕсли; + +КонецПроцедуры + +// Обработчик подписки ОбновитьГруппыВладельцевНастроекПрав на событие ПередЗаписью: +// - вызывает метод записи иерархии владельцев настроек прав объектов в +// регистр сведений НаследованиеНастроекПравОбъектов для требуемых объектов метаданных. +// +Процедура ОбновитьГруппыВладельцевНастроекПрав(Знач Объект, Отказ) Экспорт + + Если Объект.ОбменДанными.Загрузка Тогда + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда + Возврат; + КонецЕсли; + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ВозможныеПраваПоТипам = ВозможныеПрава.ПоТипам; + + Если ВозможныеПраваПоТипам.Получить(ТипЗнч(Объект)) <> Неопределено Тогда + РегистрыСведений.НаследованиеНастроекПравОбъектов.ОбновитьДанныеРегистра(Объект); + КонецЕсли; + +КонецПроцедуры + +// Обработчик подписки ЗаписатьНаборыЗначенийДоступа на событие ПриЗаписи +// вызывает метод записи значений доступа объекта в РегистрСведений.НаборыЗначенийДоступа. +// Возможен случай использования подсистемы "УправлениеДоступом", когда +// указанной подписки не существует, если наборы значений доступа не применяются. +// +Процедура ЗаписатьНаборыЗначенийДоступаПриЗаписи(Знач Объект, Отказ) Экспорт + + // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, + // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. + // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная + // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. + Если Объект.ОбменДанными.Загрузка + И НЕ Объект.ДополнительныеСвойства.Свойство("ЗаписатьНаборыЗначенийДоступа") Тогда + + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда + Возврат; + КонецЕсли; + + ЗаписатьНаборыЗначенийДоступа(Объект, , Объект.ДополнительныеСвойства.Свойство( + "ЗаписьНаборовЗначенийДоступаПриОбновленииИБ")); + +КонецПроцедуры + +// Обработчик подписки ЗаписатьЗависимыеНаборыЗначенийДоступа события ПриЗаписи +// вызывает перезапись зависимых наборов значений доступа в регистре сведений НаборыЗначенийДоступа. +// +// Возможен случай использования подсистемы "УправлениеДоступом", когда +// указанной подписки не существует, если зависимые наборы значений доступа не применяются. +// +Процедура ЗаписатьЗависимыеНаборыЗначенийДоступаПриЗаписи(Знач Объект, Отказ) Экспорт + + // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, + // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. + // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная + // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. + Если Объект.ОбменДанными.Загрузка + И НЕ Объект.ДополнительныеСвойства.Свойство("ЗаписатьЗависимыеНаборыЗначенийДоступа") Тогда + + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда + Возврат; + КонецЕсли; + + ЗаписатьЗависимыеНаборыЗначенийДоступа(Объект, Объект.ДополнительныеСвойства.Свойство( + "ЗаписьНаборовЗначенийДоступаПриОбновленииИБ")); + +КонецПроцедуры + +// Обработчик подписок ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей* на событие ПередЗаписью +// вызывает заполнение значений доступа табличной части объекта НаборыЗначенийДоступа, +// когда для ограничения доступа к самому объекту используется шаблон #ПоНаборамЗначений. +// Возможен случай использования подсистемы Управление доступом, когда +// указанной подписки не существует, если для указанной цели наборы не применяются. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередЗаписью. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// +// РежимЗаписи - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда тип параметра Источник - ДокументОбъект. +// +// РежимПроведения - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда тип параметра Источник - ДокументОбъект. +// +Процедура ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей(Источник, Отказ = Неопределено, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт + + // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, + // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. + // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная + // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. + Если Источник.ОбменДанными.Загрузка + И НЕ Источник.ДополнительныеСвойства.Свойство("ЗаписатьНаборыЗначенийДоступа") Тогда + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда + Возврат; + КонецЕсли; + + Если НЕ ( ПривилегированныйРежим() + И Источник.ДополнительныеСвойства.Свойство( + "НаборыЗначенийДоступаТабличнойЧастиЗаполнены")) Тогда + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() + И Не ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + + Если Источник.ЭтоНовый() Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + Иначе + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + КонецЕсли; + + Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Источник); + ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); + Источник.НаборыЗначенийДоступа.Загрузить(Таблица); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиРегламентныхЗаданий + +// Обработчик регламентного задания ЗаполнениеДанныхДляОграниченияДоступа. +Процедура ЗаполнениеДанныхДляОграниченияДоступаОбработчикЗадания() Экспорт + + ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания( + Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа); + + ЗаполнениеДанныхДляОграниченияДоступа(); + +КонецПроцедуры + +// Выполняет последовательное заполнение и обновление данных, необходимых для работы +// подсистемы УправленияДоступом в режиме ограничения доступа на уровне записей. +// +// При включенном режиме ограничения доступа на уровне записей заполняет наборы +// значений доступа. Заполнение выполняется частями при каждом запуске, пока все +// наборы значений доступа не будут заполнены. +// При отключении режима ограничения доступа на уровне записей наборы значений доступа +// (заполненные ранее) удаляются при перезаписи объектов, а не все сразу. +// Независимо от режима ограничения доступа на уровне записей обновляет кэш-реквизиты. +// После завершения всех обновлений и заполнений отключает использование регламентного задания. +// +// Сведения о состоянии работы записываются в журнал регистрации. +// +// Возможно вызывать программно, например, при обновлении информационной базы. +// Также для целей обновления есть форма Справочник.ГруппыДоступа.ОбновлениеДанныхОграниченияДоступа, +// с помощью которой можно сделать интерактивное обновление данных ограничения доступа +// при обновлении информационной базы. +// +Процедура ЗаполнениеДанныхДляОграниченияДоступа(КоличествоДанных = 0, ТолькоКэшРеквизиты = Ложь, ЕстьИзменения = Неопределено) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.ЗаполнениеДанныхДляОграниченияДоступа"); + + УстановитьПривилегированныйРежим(Истина); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами; + + Если Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() И НЕ ТолькоКэшРеквизиты Тогда + + // Заполнение групп значений доступа в регистре сведений ГруппыЗначенийДоступа. + Для Каждого ИмяТаблицы Из ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления Цикл + + Пока КоличествоДанных < 10000 Цикл + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | ТекущаяТаблица.Ссылка + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа + | ПО ТекущаяТаблица.Ссылка = ГруппыЗначенийДоступа.ЗначениеДоступа + | И (ГруппыЗначенийДоступа.ГруппаДанных = 0) + |ГДЕ + | ГруппыЗначенийДоступа.ЗначениеДоступа ЕСТЬ NULL"; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", ИмяТаблицы); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", ИмяТаблицы); + // @skip-check query-in-loop - Порционная обработка данных + Значения = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + Если Не ЗначениеЗаполнено(Значения) Тогда + Прервать; + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(Значения, ЕстьИзменения); + КоличествоДанных = КоличествоДанных + Значения.Количество(); + Если Значения.Количество() < 1000 Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + Если КоличествоДанных < 10000 Тогда + Продолжить; + КонецЕсли; + + Прервать; + + КонецЦикла; + + Если КоличествоДанных < 10000 Тогда + // Обновление оставшихся неактуальных записей, если есть. + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьДанныеРегистра(ЕстьИзменения); + КонецЕсли; + + Если КоличествоДанных < 10000 И Не УправлениеДоступом.ПроизводительныйВариант() Тогда + + // Заполнение регистра сведений НаборыЗначенийДоступа. + ТипыОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа"); + + Для каждого ОписаниеТипа Из ТипыОбъектов Цикл + Тип = ОписаниеТипа.Ключ; + + Если КоличествоДанных < 10000 И Тип <> Тип("Строка") Тогда + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 10000 + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НаборыЗначенийДоступа КАК РегистрСведенийНаборыЗначенийДоступа + | ПО ТекущаяТаблица.Ссылка = РегистрСведенийНаборыЗначенийДоступа.Объект + |ГДЕ + | РегистрСведенийНаборыЗначенийДоступа.Объект ЕСТЬ NULL "; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Метаданные.НайтиПоТипу(Тип).ПолноеИмя()); + // @skip-check query-in-loop - Порционная обработка данных + Выборка = Запрос.Выполнить().Выбрать(); + КоличествоДанных = КоличествоДанных + Выборка.Количество(); + + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьНаборыЗначенийДоступа(Выборка.Ссылка, ЕстьИзменения); + КонецЦикла; + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + + // Обновление кэш-реквизитов в наборах значений доступа. + Если КоличествоДанных < 10000 И Не УправлениеДоступом.ПроизводительныйВариант() Тогда + + ТипыЗначенийДоступа = СвойстваВидовДоступа.ПоТипамЗначений; + ТипыЗначенийДоступаСГруппами = СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами; + + ТаблицаТиповЗначений = Новый ТаблицаЗначений; + ТаблицаТиповЗначений.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + Для каждого КлючИЗначение Из ТипыЗначенийДоступа Цикл + ТаблицаТиповЗначений.Добавить().ТипЗначений = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); + КонецЦикла; + + ТаблицаТиповЗначенийСГруппами = Новый ТаблицаЗначений; + ТаблицаТиповЗначенийСГруппами.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + Для каждого КлючИЗначение Из ТипыЗначенийДоступаСГруппами Цикл + ТаблицаТиповЗначенийСГруппами.Добавить().ТипЗначений = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТаблицаТиповЗначений", ТаблицаТиповЗначений); + Запрос.УстановитьПараметр("ТаблицаТиповЗначенийСГруппами", ТаблицаТиповЗначенийСГруппами); + Запрос.Текст = + "ВЫБРАТЬ + | ТаблицаТипов.ТипЗначений + |ПОМЕСТИТЬ ТаблицаТиповЗначений + |ИЗ + | &ТаблицаТиповЗначений КАК ТаблицаТипов + | + |ИНДЕКСИРОВАТЬ ПО + | ТаблицаТипов.ТипЗначений + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ТаблицаТипов.ТипЗначений + |ПОМЕСТИТЬ ТаблицаТиповЗначенийСГруппами + |ИЗ + | &ТаблицаТиповЗначенийСГруппами КАК ТаблицаТипов + | + |ИНДЕКСИРОВАТЬ ПО + | ТаблицаТипов.ТипЗначений + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 10000 + | НаборыЗначенийДоступа.Объект, + | НаборыЗначенийДоступа.НомерНабора, + | НаборыЗначенийДоступа.ЗначениеДоступа, + | НаборыЗначенийДоступа.Уточнение, + | НаборыЗначенийДоступа.Чтение, + | НаборыЗначенийДоступа.Изменение + |ИЗ + | РегистрСведений.НаборыЗначенийДоступа КАК НаборыЗначенийДоступа + |ГДЕ + | ВЫБОР + | КОГДА НаборыЗначенийДоступа.СтандартноеЗначение <> ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ТаблицаТиповЗначений КАК ТаблицаТиповЗначений + | ГДЕ + | ТИПЗНАЧЕНИЯ(ТаблицаТиповЗначений.ТипЗначений) = ТИПЗНАЧЕНИЯ(НаборыЗначенийДоступа.ЗначениеДоступа)) + | ТОГДА ИСТИНА + | КОГДА НаборыЗначенийДоступа.СтандартноеЗначение = ИСТИНА + | ТОГДА НаборыЗначенийДоступа.ЗначениеБезГрупп = ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ТаблицаТиповЗначенийСГруппами КАК ТаблицаТиповЗначенийСГруппами + | ГДЕ + | ТИПЗНАЧЕНИЯ(ТаблицаТиповЗначенийСГруппами.ТипЗначений) = ТИПЗНАЧЕНИЯ(НаборыЗначенийДоступа.ЗначениеДоступа)) + | ИНАЧЕ НаборыЗначенийДоступа.ЗначениеБезГрупп = ИСТИНА + | КОНЕЦ"; + Выборка = Запрос.Выполнить().Выбрать(); + КоличествоДанных = КоличествоДанных + Выборка.Количество(); + + Пока Выборка.Следующий() Цикл + МенеджерЗаписи = РегистрыСведений.НаборыЗначенийДоступа.СоздатьМенеджерЗаписи(); + ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка); + + ТипЗначенияДоступа = ТипЗнч(Выборка.ЗначениеДоступа); + + Если ТипыЗначенийДоступа.Получить(ТипЗначенияДоступа) <> Неопределено Тогда + МенеджерЗаписи.СтандартноеЗначение = Истина; + Если ТипыЗначенийДоступаСГруппами.Получить(ТипЗначенияДоступа) = Неопределено Тогда + МенеджерЗаписи.ЗначениеБезГрупп = Истина; + КонецЕсли; + КонецЕсли; + + МенеджерЗаписи.Записать(); + ЕстьИзменения = Истина; + КонецЦикла; + КонецЕсли; + + Если КоличествоДанных < 10000 Тогда + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + , + , + НСтр("ru = 'Завершено заполнение данных для ограничения доступа.'"), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + + УстановитьЗаполнениеДанныхДляОграниченияДоступа(Ложь); + Иначе + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + , + , + НСтр("ru = 'Выполнена запись части данных для ограничения доступа.'"), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + КонецЕсли; + +КонецПроцедуры + +// Устанавливает использование регламентного задания заполнения данных управления доступом. +// +// Параметры: +// Использование - Булево - Истина, если задание нужно включить, иначе Ложь. +// +Процедура УстановитьЗаполнениеДанныхДляОграниченияДоступа(Знач Использование) Экспорт + + РегламентныеЗаданияСервер.УстановитьИспользованиеПредопределенногоРегламентногоЗадания( + Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа, Использование); + +КонецПроцедуры + +#КонецОбласти + +#Область ПроцедурыИФункцииДляРаботыСВидамиДоступа + +// Возвращает Истина, если вид доступа включен по функциональным опциям для всех сеансов. +// +// Параметры: +// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. +// - Строка - имя вида доступа. +// +// Возвращаемое значение: +// Булево +// +Функция ВидДоступаИспользуется(Знач ВидДоступа) Экспорт + + Если Не УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда + Возврат Ложь; + КонецЕсли; + + СвойстваВидаДоступа = СвойстваВидаДоступа(ВидДоступа); + Если СвойстваВидаДоступа = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТипЗначенийДоступа", СвойстваВидаДоступа.Ссылка); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа + |ГДЕ + | ИспользуемыеВидыДоступа.ТипЗначенийДоступа = &ТипЗначенийДоступа + | И ИспользуемыеВидыДоступа.Используется = ИСТИНА"; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Используется = Не Запрос.Выполнить().Пустой(); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Возврат Используется; + +КонецФункции + +// Параметры: +// БезУчетаОграниченияДоступа - Булево +// +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. +// * Значение - Булево - значение Истина. +// +Функция ИспользуемыеВидыДоступа(БезУчетаОграниченияДоступа = Ложь) Экспорт + + Результат = Новый Соответствие; + + Если Не БезУчетаОграниченияДоступа + И Не УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда + Возврат Результат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ИспользуемыеВидыДоступа.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа + |ГДЕ + | ИспользуемыеВидыДоступа.Используется = ИСТИНА"; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Выборка = Запрос.Выполнить().Выбрать(); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + Пока Выборка.Следующий() Цикл + Если СвойстваВидовДоступа.ПоСсылкам.Получить(Выборка.ТипЗначенийДоступа) = Неопределено Тогда + Продолжить; + КонецЕсли; + Результат.Вставить(Выборка.ТипЗначенийДоступа, Истина); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Возвращает свойства вида доступа или всех видов доступа. +// +// Параметры: +// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. +// - Строка - имя вида доступа. +// +// Возвращаемое значение: +// Структура: +// * Имя - Строка +// * Ссылка - ОпределяемыйТип.ЗначениеДоступа +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// * ДополнительныеТипы - ФиксированныйМассив из см. ДополнительныйТипВидаДоступа +// * ТипыВыбираемыхЗначений - ФиксированныйМассив из Тип +// Неопределено +// +Функция СвойстваВидаДоступа(ВидДоступа) Экспорт + + Свойства = СвойстваВидовДоступа(); + + Если ТипЗнч(ВидДоступа) = Тип("Строка") Тогда + СвойстваВидаДоступа = Свойства.ПоИменам.Получить(ВидДоступа); + Иначе + СвойстваВидаДоступа = Свойства.ПоСсылкам.Получить(ВидДоступа); + КонецЕсли; + + Возврат СвойстваВидаДоступа; + +КонецФункции + +#КонецОбласти + +#Область ПроцедурыИФункцииДляРаботыСНаборамиЗначенийДоступа + +// Возвращает новые наборы для заполнения табличной части. +// +// Параметры: +// Объект - ОпределяемыйТип.ВладелецСОграничениемПоНаборамЗначенийДоступаОбъект +// - ОпределяемыйТип.ВладелецСОграничениемПоНаборамЗначенийДоступаДокумент +// +// Возвращаемое значение: +// см. УправлениеДоступом.ТаблицаНаборыЗначенийДоступа +// +Функция ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект) + + ТипЗначенияОбъект = ТипЗнч(Объект); + + Если Объект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |У объекта типа ""%1"" + |не существует табличная часть %2.'"), + ТипЗначенияОбъект, "НаборыЗначенийДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Таблица = УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(); + + Если НЕ УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда + Возврат Таблица; + КонецЕсли; + + УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(Объект, Таблица); + + УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( + Таблица, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); + + Возврат Таблица; + +КонецФункции + +// Выполняет обновление наборов значений доступа объекта, если они изменились. +// Наборы обновляются в табличной части (если используется) и +// в регистре сведений НаборыЗначенийДоступа. +// +// Параметры: +// СсылкаИлиОбъект - ЛюбаяСсылка +// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - ссылка или объект, +// для которого записываются наборы значений доступа. +// +// ЕстьИзменения - Булево +// - Неопределено +// +// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// +Процедура ОбновитьНаборыЗначенийДоступа(СсылкаИлиОбъект, ЕстьИзменения = Неопределено, ОбновлениеИБ = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + Объект = ?(СсылкаИлиОбъект = СсылкаИлиОбъект.Ссылка, СсылкаИлиОбъект.ПолучитьОбъект(), СсылкаИлиОбъект); + СсылкаНаОбъект = Объект.Ссылка; + ТипЗначенияОбъект = ТипЗнч(Объект); + + НаборыЗаписываются = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ НаборыЗаписываются Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписке на событие %2.'"), + ТипЗначенияОбъект, + "ЗаписатьНаборыЗначенийДоступа"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип.Типы().Найти(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка при записи наборов значений доступа: + |в регистре сведений %1 в измерении %2 + |не задан тип ""%3""'"), + "НаборыЗначенийДоступа", + "Объект", + ТипЗнч(СсылкаНаОбъект)); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если СсылкаНаОбъект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") <> Неопределено Тогда + // Обновление объекта требуется. + Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект); + + Если НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаОбъект, Таблица) Тогда + ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); + + Объект.ДополнительныеСвойства.Вставить("ЗаписатьНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("ЗаписатьЗависимыеНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("НаборыЗначенийДоступаТабличнойЧастиЗаполнены"); + Объект.НаборыЗначенийДоступа.Загрузить(Таблица); + Если ОбновлениеИБ Тогда + Объект.ДополнительныеСвойства.Вставить("ЗаписьНаборовЗначенийДоступаПриОбновленииИБ"); + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + Иначе + Объект.ОбменДанными.Загрузка = Истина; + // АПК:1327-выкл - №783.1.4.1 Допустимо оставить запись без + // предварительной управляемой блокировки объекта, так как только + // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. + Объект.Записать(); + // АПК:1327-вкл. + КонецЕсли; + ЕстьИзменения = Истина; + КонецЕсли; + КонецЕсли; + + // Обновление объекта не требуется или объект уже обновлен. + ЗаписатьНаборыЗначенийДоступа(Объект, ЕстьИзменения, ОбновлениеИБ); + +КонецПроцедуры + +// Заполняет вспомогательные данные, ускоряющие работу шаблонов ограничений доступа. +// Выполняется перед записью в регистр НаборыЗначенийДоступа. +// +// Параметры: +// СсылкаНаОбъект - ЛюбаяСсылка - ссылка на объект для которого заполняются наборы значений доступа. +// Таблица - ТаблицаЗначений +// ДобавитьКэшРеквизиты - Булево +// +Процедура ПодготовитьНаборыЗначенийДоступаКЗаписи(СсылкаНаОбъект, Таблица, ДобавитьКэшРеквизиты = Ложь) Экспорт + + Если ДобавитьКэшРеквизиты Тогда + + Таблица.Колонки.Добавить("Объект", Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип); + Таблица.Колонки.Добавить("СтандартноеЗначение", Новый ОписаниеТипов("Булево")); + Таблица.Колонки.Добавить("ЗначениеБезГрупп", Новый ОписаниеТипов("Булево")); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ТипыЗначенийДоступаСГруппами = СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами; + ТипыЗначенийДоступа = СвойстваВидовДоступа.ПоТипамЗначений; + КонецЕсли; + + // Нормализация ресурсов Чтение, Изменение. + НомерНабора = -1; + Для каждого Строка Из Таблица Цикл + + Если ДобавитьКэшРеквизиты Тогда + // Установка значения измерения Объект. + Строка.Объект = СсылкаНаОбъект; + + ТипЗначенияДоступа = ТипЗнч(Строка.ЗначениеДоступа); + + Если ТипыЗначенийДоступа.Получить(ТипЗначенияДоступа) <> Неопределено Тогда + Строка.СтандартноеЗначение = Истина; + Если ТипыЗначенийДоступаСГруппами.Получить(ТипЗначенияДоступа) = Неопределено Тогда + Строка.ЗначениеБезГрупп = Истина; + КонецЕсли; + КонецЕсли; + + КонецЕсли; + + // Очистка флажков прав и соответствующих им вторичных данных + // для всех строк каждого набора, кроме первой строки. + Если НомерНабора = Строка.НомерНабора Тогда + Строка.Чтение = Ложь; + Строка.Изменение = Ложь; + Иначе + НомерНабора = Строка.НомерНабора; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти + +#Область ПроцедурыИФункцииДляДействийПриИзмененийНастроекПодсистемы + +// Если необходимо, включает заполнение данных для ограничения доступа и +// обновляет некоторые данные сразу. +// +// Вызывается из обработчика ПриЗаписи константы ОграничиватьДоступаНаУровнеЗаписей. +// +Процедура ПриИзмененииОграниченияДоступаНаУровнеЗаписей(ОграничениеДоступаНаУровнеЗаписейВключено) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(, Истина); + РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); + + Если ОграничениеДоступаНаУровнеЗаписейВключено Тогда + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + , + , + НСтр("ru = 'Начато заполнение данных для ограничения доступа.'"), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + + УстановитьЗаполнениеДанныхДляОграниченияДоступа(Истина); + КонецЕсли; + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина) Тогда + + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "ПриИзмененииОграниченияДоступаНаУровнеЗаписей"); + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + ПараметрыПланирования.Описание = "ОграничиватьДоступНаУровнеЗаписейПриЗаписи"; + ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); + + УстановитьОбновлениеДоступа(Истина); + КонецЕсли; + + ОбновитьПараметрыСеанса(); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбслуживаниеТаблицВидыДоступаИЗначенияДоступаВФормахРедактирования + +// Заполняет вспомогательные данные, требуемые для работы формы, +// которые не зависят от содержания объекта или заполняются для нового объекта. +// +// Форма должна содержать реквизиты, указанные ниже. +// Реквизиты отмеченные символом & заполняются автоматически, но их нужно создать в форме. +// Реквизиты отмеченные символом # должны быть созданы в форме, если +// в форме будет создан реквизит ТекущаяГруппаДоступа (см. ниже). +// Реквизиты отмеченные символом @ будут созданы автоматически. +// +// ТекущаяГруппаДоступа - необязательный реквизит, +// если не создан в форме, тогда не используется. +// +// ВидыДоступа - Таблица с полями: +// #ГруппаДоступа - СправочникСсылка.ГруппыДоступа, +// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, +// Предустановленный - Булево (только для профиля), +// ВсеРазрешены - Булево, +// &ВидДоступаПредставление - Строка - представление настройки, +// &ВсеРазрешеныПредставление - Строка - представление настройки, +// @Используется - Булево. +// +// ЗначенияДоступа - Таблица с полями: +// #ГруппаДоступа - СправочникСсылка.ГруппыДоступа, +// &ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, +// ЗначениеДоступа - ОпределяемыйТип.ЗначениеДоступа, +// &НомерСтрокиПоВиду - Число. +// +// &ИспользоватьВнешнихПользователей - Булево - реквизит будет создан, если нет в форме. +// &НадписьВидДоступа - Строка - представление текущего вида доступа в форме. +// @ЭтоПрофильГруппДоступа - Булево. +// @ТекущийВидДоступа - ОпределяемыйТип.ЗначениеДоступа. +// @ТекущиеТипыВыбираемыхЗначений - СписокЗначений. +// @ТекущийТипВыбираемыхЗначений - ОпределяемыйТип.ЗначениеДоступа. +// @ИмяРеквизитаХранилищаТаблиц - Строка. +// @ВидДоступаПользователи - ОпределяемыйТип.ЗначениеДоступа. +// @ВидДоступаВнешниеПользователи - ОпределяемыйТип.ЗначениеДоступа. +// +// @ВсеВидыДоступа - Таблица с полями: +// @Ссылка - ОпределяемыйТип.ЗначениеДоступа, +// @Представление - Строка, +// @Используется - Булево. +// +// @ПредставленияВсеРазрешены - Таблица с полями: +// @Имя - Строка, +// @Представление - Строка. +// +// @ВсеТипыВыбираемыхЗначений - Таблица с полями: +// @ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, +// @ТипЗначений - ОпределяемыйТип.ЗначениеДоступа, +// @ПредставлениеТипа - Строка, +// @ИмяТаблицы - Строка, +// @ИерархияЭлементов - Булево. +// +// Параметры: +// Форма - см. УправлениеДоступомСлужебныйКлиентСервер.ПараметрыФормыРедактированияРазрешенныхЗначений +// +// ЭтоПрофиль - Булево - указывает, что возможна настройка видов доступа +// в том числе представление настройки содержит 4 значения, а не 2. +// +// ИмяРеквизитаХранилищаТаблиц - Строка - содержащая, например, строку "Объект", которая +// содержит таблицы ВидыДоступа и ЗначенияДоступа (см. ниже). +// Если указана пустая строка, тогда считается, +// что таблицы хранятся в реквизитах формы. +// +Процедура ПриСозданииНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ЭтоПрофиль = Ложь, ИмяРеквизитаХранилищаТаблиц = "Объект") Экспорт + + ДобавитьРеквизитыВспомогательныхДанныхВФорму(Форма, ИмяРеквизитаХранилищаТаблиц); + + Форма.ИмяРеквизитаХранилищаТаблиц = ИмяРеквизитаХранилищаТаблиц; + Форма.ЭтоПрофильГруппДоступа = ЭтоПрофиль; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + // Заполнение типов значений доступа всех видов доступа. + Для каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл + Для каждого Тип Из СвойстваВидаДоступа.ТипыВыбираемыхЗначений Цикл + МассивТипов = Новый Массив; + МассивТипов.Добавить(Тип); + ОписаниеТипа = Новый ОписаниеТипов(МассивТипов); + + МетаданныеТипа = Метаданные.НайтиПоТипу(Тип); + Если Метаданные.Перечисления.Найти(МетаданныеТипа.Имя) = МетаданныеТипа Тогда + ПредставлениеТипа = МетаданныеТипа.Представление(); + Иначе + ПредставлениеТипа = ?(ЗначениеЗаполнено(МетаданныеТипа.ПредставлениеОбъекта), + МетаданныеТипа.ПредставлениеОбъекта, + МетаданныеТипа.Представление()); + КонецЕсли; + + НоваяСтрока = Форма.ВсеТипыВыбираемыхЗначений.Добавить(); + НоваяСтрока.ВидДоступа = СвойстваВидаДоступа.Ссылка; + НоваяСтрока.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + НоваяСтрока.ПредставлениеТипа = ПредставлениеТипа; + НоваяСтрока.ИмяТаблицы = МетаданныеТипа.ПолноеИмя(); + НоваяСтрока.ИерархияЭлементов = СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(Тип) <> Неопределено; + КонецЦикла; + КонецЦикла; + + Форма.ВидДоступаПользователи = Справочники.Пользователи.ПустаяСсылка(); + Форма.ВидДоступаВнешниеПользователи = Справочники.ВнешниеПользователи.ПустаяСсылка(); + Форма.ИспользоватьВнешнихПользователей = ВнешниеПользователи.ИспользоватьВнешнихПользователей(); + + ЗаполнитьТаблицуВсеВидыДоступаВФорме(Форма); + + ЗаполнитьТаблицуПредставленияВсеРазрешеныВФорме(Форма, ЭтоПрофиль); + + ОформитьТаблицуВидыДоступаВФорме(Форма); + + ОформитьТаблицуЗначенияДоступаВФорме(Форма); + + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); + УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); + + ОбновитьОтображениеНеиспользуемыхВидовДоступа(Форма, Истина); + + // Настройка параметров выбора значения доступа. + ПараметрыВыбора = Новый Массив; + ПараметрыВыбора.Добавить(Новый ПараметрВыбора("ЭтоВыборЗначенияДоступа", Истина)); + Форма.Элементы.ЗначенияДоступаЗначениеДоступа.ПараметрыВыбора = Новый ФиксированныйМассив(ПараметрыВыбора); + +КонецПроцедуры + +// При повторном чтении заполняет или обновляет вспомогательные данные, +// требуемые для работы формы, которые зависят от содержания объекта. +// +Процедура ПриПовторномЧтенииНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект) Экспорт + + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект); + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); + + УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); + + УправлениеДоступомСлужебныйКлиентСервер.ПриИзмененииТекущегоВидаДоступа(Форма, Ложь); + +КонецПроцедуры + +// Удаляет лишние значения доступа перед записью. +// Лишние значения доступа могут появиться, если заменить или удалить вид доступа, +// для которого введены значения доступа. +// +Процедура ПередЗаписьюНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект) Экспорт + + УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект); + УдалитьЛишниеЗначенияДоступа(Форма); + +КонецПроцедуры + +// Обновляет свойства видов доступа. +Процедура ПослеЗаписиНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект, ПараметрыЗаписи) Экспорт + + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект); + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); + + УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); + +КонецПроцедуры + +// Скрывает или показывает неиспользуемые виды доступа. +Процедура ОбновитьОтображениеНеиспользуемыхВидовДоступа(Форма, ПриСозданииНаСервере = Ложь) Экспорт + + Элементы = Форма.Элементы; + + Если Не ПриСозданииНаСервере Тогда + Элементы.ПоказыватьНеИспользуемыеВидыДоступа.Пометка = + НЕ Элементы.ПоказыватьНеИспользуемыеВидыДоступа.Пометка; + КонецЕсли; + + Отбор = УправлениеДоступомСлужебныйКлиентСервер.ОтборВТаблицахФормыРедактированияРазрешенныхЗначений( + Форма); + + Если Не Элементы.ПоказыватьНеиспользуемыеВидыДоступа.Пометка Тогда + Отбор.Вставить("Используется", Истина); + КонецЕсли; + + Элементы.ВидыДоступа.ОтборСтрок = Новый ФиксированнаяСтруктура(Отбор); + + Элементы.ВидыДоступаВидДоступаПредставление.СписокВыбора.Очистить(); + + Для каждого Строка Из Форма.ВсеВидыДоступа Цикл + + Если Не Элементы.ПоказыватьНеиспользуемыеВидыДоступа.Пометка + И Не Строка.Используется Тогда + + Продолжить; + КонецЕсли; + + Элементы.ВидыДоступаВидДоступаПредставление.СписокВыбора.Добавить(Строка.Представление); + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти + +#Область УниверсальныеПроцедурыИФункции + +// Только для внутреннего использования. +Процедура УстановитьУсловиеОтбораВЗапросе(Знач Запрос, Знач Значения, Знач ИмяПараметраЗначений, Знач ИмяПараметраУсловияОтбораИмяПоля) Экспорт + + Если Значения = Неопределено Тогда + + ИначеЕсли ТипЗнч(Значения) <> Тип("Массив") + И ТипЗнч(Значения) <> Тип("ФиксированныйМассив") Тогда + + Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения); + + ИначеЕсли Значения.Количество() = 1 Тогда + Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения[0]); + Иначе + Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения); + КонецЕсли; + + Для НомерСтроки = 1 По СтрЧислоСтрок(ИмяПараметраУсловияОтбораИмяПоля) Цикл + ТекущаяСтрока = СтрПолучитьСтроку(ИмяПараметраУсловияОтбораИмяПоля, НомерСтроки); + Если НЕ ЗначениеЗаполнено(ТекущаяСтрока) Тогда + Продолжить; + КонецЕсли; + ИндексРазделителя = СтрНайти(ТекущаяСтрока, ":"); + Если ИндексРазделителя = 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка при выполнении процедуры %1. + | + |В параметре %2 не существует разделитель (двоеточие) + |в следующей строке формата ""%3"" + |""%4"".'"), + "УправлениеДоступом.УстановитьУсловиеОтбораВЗапросе", + "ИмяПараметраУсловияОтбораИмяПоля", + "<ИмяПараметраУсловия>:<ИмяПоля>", + ТекущаяСтрока); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + ИмяПараметраУсловияОтбора = Лев(ТекущаяСтрока, ИндексРазделителя-1); + ИмяПоля = Сред(ТекущаяСтрока, ИндексРазделителя+1); + Если Значения = Неопределено Тогда + УсловиеОтбора = "Истина"; + + ИначеЕсли ТипЗнч(Значения) <> Тип("Массив") + И ТипЗнч(Значения) <> Тип("ФиксированныйМассив") Тогда + + УсловиеОтбора = ИмяПоля + " = &" + ИмяПараметраЗначений; + + ИначеЕсли Значения.Количество() = 1 Тогда + УсловиеОтбора = ИмяПоля + " = &" + ИмяПараметраЗначений; + Иначе + УсловиеОтбора = ИмяПоля + " В (&" + ИмяПараметраЗначений + ")"; + КонецЕсли; + Запрос.Текст = СтрЗаменить(Запрос.Текст, ИмяПараметраУсловияОтбора, УсловиеОтбора); + КонецЦикла; + +КонецПроцедуры + +// Обновляет набор записей в базе данных, +// если записи набора отличаются от записей в базе данных. +// +// Параметры: +// Данные - Структура: +// * НаборЗаписей - РегистрСведенийНаборЗаписей - пустой или прочитанный с заданным отбором или без. +// - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. +// +// * НовыеЗаписи - ТаблицаЗначений - в формате регистра. +// +// * ПоляСравнения - Строка - содержит список полей по значениям которых требуется вычислять +// отличие записей набора. Например, "Измерение1, Измерение2, Ресурс1", +// а реквизит ДатаИзмерения не входит в список. +// +// * ПолеОтбора - Неопределено - записывается весь регистр или +// отбор уже задан в наборе записей. +// Строка - имя поля по которому нужно установить отбор. +// +// * ЗначениеОтбора - Отбор - значение, которое будет установлено в качестве отбора +// по полю отбора, если поле отбора задано. +// +// * НаборЗаписейПрочитан - Булево - если Истина, тогда не заданный набор записей уже содержит +// прочитанные записи блокировка данных этих записей установлена и +// транзакция открыта. +// +// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, +// а лишь выявить необходимость записи и установить +// свойство ЕстьИзменения. +// +// * ДополнительныеСвойства - Структура +// - Неопределено - если Структура, тогда в +// объекты <Регистр*>НаборЗаписей в свойство ДополнительныеСвойства +// будут вставлены все параметры структуры. +// +// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций +// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления +// общего модуля ОбновлениеИнформационнойБазы. +// +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +// ИзмененныеЗаписи - Неопределено - никаких действий, иначе +// возвращает таблицу значений в формате регистра с полем ВидИзмененияСтроки +// типа Число (-1 запись удалена, 1 запись добавлена). +// +Процедура ОбновитьНаборЗаписей(Знач Данные, ЕстьИзменения = Неопределено, ИзмененныеЗаписи = Неопределено) Экспорт + + ВсеПараметры = Новый Структура; + ВсеПараметры.Вставить("НаборЗаписей"); + ВсеПараметры.Вставить("НовыеЗаписи"); + ВсеПараметры.Вставить("ПоляСравнения"); + ВсеПараметры.Вставить("ПолеОтбора"); + ВсеПараметры.Вставить("ЗначениеОтбора"); + ВсеПараметры.Вставить("НаборЗаписейПрочитан", Ложь); + ВсеПараметры.Вставить("БезПерезаписи", Ложь); + ВсеПараметры.Вставить("ТолькоПроверка", Ложь); + ВсеПараметры.Вставить("ДополнительныеСвойства"); + ВсеПараметры.Вставить("ОбновлениеИБ", + ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() + Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); + + ЗаполнитьПараметры(Данные, ВсеПараметры, "НаборЗаписей, НовыеЗаписи"); + + ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(Данные.НаборЗаписей)).ПолноеИмя(); + МенеджерРегистра = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяРегистра); + Если Данные.НаборЗаписей = МенеджерРегистра Тогда + НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей(); // РегистрСведенийНаборЗаписей + Иначе + НаборЗаписей = Данные.НаборЗаписей; // РегистрСведенийНаборЗаписей + КонецЕсли; + НовыеЗаписи = Данные.НовыеЗаписи; + ПолеОтбора = Данные.ПолеОтбора; + ЗначениеОтбора = Данные.ЗначениеОтбора; + + Если ЗначениеЗаполнено(ПолеОтбора) Тогда + УстановитьОтбор(НаборЗаписей.Отбор[ПолеОтбора], ЗначениеОтбора); + КонецЕсли; + + Если НЕ Данные.НаборЗаписейПрочитан Тогда + ЗаблокироватьОбластьНабораЗаписей(НаборЗаписей, ПолноеИмяРегистра); + НаборЗаписей.Прочитать(); + КонецЕсли; + + Данные.ПоляСравнения = ?(Данные.ПоляСравнения = Неопределено, + ПоляНабораЗаписей(НаборЗаписей), Данные.ПоляСравнения); + + Если Данные.БезПерезаписи Тогда + НаборЗаписи = МенеджерРегистра.СоздатьНаборЗаписей(); + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); + ОтборЗаписи = Новый Структура(ОписаниеКлючаЗаписи.СписокПолей); + ПоляОстальныхИзмерений = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + Если ОписаниеПоля.Имя <> ПолеОтбора Тогда + ПоляОстальныхИзмерений.Добавить(ОписаниеПоля.Имя); + КонецЕсли; + КонецЦикла; + УдаляемыеЗаписи = Новый ТаблицаЗначений; + Для каждого Поле Из ПоляОстальныхИзмерений Цикл + УдаляемыеЗаписи.Колонки.Добавить(Поле); + КонецЦикла; + Данные.НовыеЗаписи = НовыеЗаписи.Скопировать(); + НовыеЗаписи = Данные.НовыеЗаписи; + КонецЕсли; + + ЕстьТекущиеИзменения = Ложь; + Если ИзмененныеЗаписи = Неопределено Тогда + Если НаборЗаписей.Количество() = НовыеЗаписи.Количество() ИЛИ Данные.БезПерезаписи Тогда + Отбор = Новый Структура(Данные.ПоляСравнения); + НовыеЗаписи.Индексы.Добавить(Данные.ПоляСравнения); + Для Каждого Запись Из НаборЗаписей Цикл + ЗаполнитьЗначенияСвойств(Отбор, Запись); + НайденныеСтроки = НовыеЗаписи.НайтиСтроки(Отбор); + Если НайденныеСтроки.Количество() = 0 Тогда + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + Если Данные.БезПерезаписи Тогда + ЗаполнитьЗначенияСвойств(ОтборЗаписи, Запись); + Если НовыеЗаписи.НайтиСтроки(ОтборЗаписи).Количество() = 0 Тогда + ЗаполнитьЗначенияСвойств(УдаляемыеЗаписи.Добавить(), ОтборЗаписи); + КонецЕсли; + Иначе + Прервать; + КонецЕсли; + ИначеЕсли Данные.БезПерезаписи Тогда + НовыеЗаписи.Удалить(НайденныеСтроки[0]); + КонецЕсли; + КонецЦикла; + Если Данные.БезПерезаписи И НовыеЗаписи.Количество() > 0 Тогда + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + КонецЕсли; + Иначе + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + КонецЕсли; + Иначе + Если НаборЗаписей.Количество() <> НовыеЗаписи.Количество() Тогда + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + КонецЕсли; + Если НаборЗаписей.Количество() > НовыеЗаписи.Количество() Тогда + ИзмененныеЗаписи = НаборЗаписей.Выгрузить(); + ИскомыеЗаписи = НовыеЗаписи; + ВидИзмененияСтроки = -1; + Иначе + ИзмененныеЗаписи = НовыеЗаписи.Скопировать(); + ИскомыеЗаписи = НаборЗаписей.Выгрузить(); + ВидИзмененияСтроки = 1; + КонецЕсли; + ИзмененныеЗаписи.Колонки.Добавить("ВидИзмененияСтроки", Новый ОписаниеТипов("Число")); + ИзмененныеЗаписи.ЗаполнитьЗначения(ВидИзмененияСтроки, "ВидИзмененияСтроки"); + ВидИзмененияСтроки = ?(ВидИзмененияСтроки = 1, -1, 1); + Отбор = Новый Структура(Данные.ПоляСравнения); + + Для каждого Строка Из ИскомыеЗаписи Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Строки = ИзмененныеЗаписи.НайтиСтроки(Отбор); + Если Строки.Количество() = 0 Тогда + НоваяСтрока = ИзмененныеЗаписи.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Отбор); + НоваяСтрока.ВидИзмененияСтроки = ВидИзмененияСтроки; + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + Иначе + ИзмененныеЗаписи.Удалить(Строки[0]); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если ЕстьТекущиеИзменения Тогда + Если Данные.ТолькоПроверка Тогда + Возврат; + КонецЕсли; + Если Данные.БезПерезаписи Тогда + УстановитьДополнительныеСвойства(НаборЗаписи, Данные.ДополнительныеСвойства); + Для каждого Строка Из УдаляемыеЗаписи Цикл + Если ЗначениеЗаполнено(ПолеОтбора) Тогда + УстановитьОтбор(НаборЗаписи.Отбор[ПолеОтбора], ЗначениеОтбора); + КонецЕсли; + Для каждого Поле Из ПоляОстальныхИзмерений Цикл + УстановитьОтбор(НаборЗаписи.Отбор[Поле], Строка[Поле]); + КонецЦикла; + ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписи); + КонецЦикла; + НаборЗаписи.Добавить(); + Для каждого Строка Из НовыеЗаписи Цикл + Если ЗначениеЗаполнено(ПолеОтбора) Тогда + УстановитьОтбор(НаборЗаписи.Отбор[ПолеОтбора], ЗначениеОтбора); + КонецЕсли; + Для каждого Поле Из ПоляОстальныхИзмерений Цикл + УстановитьОтбор(НаборЗаписи.Отбор[Поле], Строка[Поле]); + КонецЦикла; + ЗаполнитьЗначенияСвойств(НаборЗаписи[0], Строка); + ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписи); + КонецЦикла; + Иначе + УстановитьДополнительныеСвойства(НаборЗаписей, Данные.ДополнительныеСвойства); + НаборЗаписей.Загрузить(НовыеЗаписи); + ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписей); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Обновляет строки регистра с отбором по нескольким значениям для одного или +// для двух измерений регистра, выполняется проверка наличия изменений, +// если изменений нет, перезапись не производится. +// +// Параметры: +// Данные - Структура: +// * МенеджерРегистра - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. +// +// * НовыеЗаписи - ТаблицаЗначений - в формате регистра. +// +// * ПоляСравнения - Строка - содержит список полей по значениям которых требуется +// вычислять отличие записей набора, например, "Измерение1, Измерение2, +// Ресурс1", а реквизит ДатаИзменения не входит в список. +// +// * ИмяПервогоИзмерения - Неопределено - нет отбора по измерению. +// - Строка - содержит имя первого измерения, для которого задано +// несколько значений. +// +// * ЗначенияПервогоИзмерения - Неопределено - нет отбора по измерению, аналогично, +// ИмяПервогоИзмерения = Неопределено. +// - ЛюбаяСсылка - содержит одно значение отбора регистра для +// обновляемых записей. +// - Массив - содержит массив значений отбора регистра для +// обновляемых записей, пустой массив - значит +// действий не требуется. +// +// * ИмяВторогоИзмерения - Неопределено +// - Строка - аналогично ИмяПервогоИзмерения. +// * ЗначенияВторогоИзмерения - Неопределено +// - ЛюбаяСсылка +// - Массив - аналогично ЗначенияПервогоИзмерения. +// * ИмяТретьегоИзмерения - Неопределено +// - Строка - аналогично ИмяПервогоИзмерения. +// * ЗначенияТретьегоИзмерения - Неопределено +// - ЛюбаяСсылка +// - Массив - аналогично ЗначенияПервогоИзмерения. +// +// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, +// а лишь выявить необходимость записи и установить +// свойство ЕстьИзменения. +// +// * ДополнительныеСвойства - Неопределено +// - Структура - если Структура, тогда в +// объекты <Регистр*>НаборЗаписей в свойство +// ДополнительныеСвойства будут вставлены все параметры структуры. +// +// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций +// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления +// общего модуля ОбновлениеИнформационнойБазы. +// +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +Процедура ОбновитьНаборыЗаписей(Знач Данные, ЕстьИзменения) + + ВсеПараметры = Новый Структура; + ВсеПараметры.Вставить("МенеджерРегистра"); + ВсеПараметры.Вставить("НовыеЗаписи"); + ВсеПараметры.Вставить("ПоляСравнения"); + ВсеПараметры.Вставить("ИмяПервогоИзмерения"); + ВсеПараметры.Вставить("ЗначенияПервогоИзмерения"); + ВсеПараметры.Вставить("ИмяВторогоИзмерения"); + ВсеПараметры.Вставить("ЗначенияВторогоИзмерения"); + ВсеПараметры.Вставить("ИмяТретьегоИзмерения"); + ВсеПараметры.Вставить("ЗначенияТретьегоИзмерения"); + ВсеПараметры.Вставить("НовыеЗаписиСодержатТолькоРазличия", Ложь); + ВсеПараметры.Вставить("ФиксированныйОтбор"); + ВсеПараметры.Вставить("ТолькоПроверка", Ложь); + ВсеПараметры.Вставить("ДополнительныеСвойства"); + ВсеПараметры.Вставить("ОбновлениеИБ", + ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() + Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); + + ЗаполнитьПараметры(Данные, ВсеПараметры, "МенеджерРегистра, НовыеЗаписи"); + + // Предварительная обработка параметров. + + Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяПервогоИзмерения, Данные.ЗначенияПервогоИзмерения) Тогда + ЕстьИзменения = Истина; + Возврат; + КонецЕсли; + Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяВторогоИзмерения, Данные.ЗначенияВторогоИзмерения) Тогда + ЕстьИзменения = Истина; + Возврат; + КонецЕсли; + Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяТретьегоИзмерения, Данные.ЗначенияТретьегоИзмерения) Тогда + ЕстьИзменения = Истина; + Возврат; + КонецЕсли; + + УпорядочитьГруппыПараметровИзмерений(Данные); + + // Проверка и обновление данных. + Данные.Вставить("НаборЗаписей", Данные.МенеджерРегистра.СоздатьНаборЗаписей()); + Данные.Вставить("МетаданныеРегистра", Метаданные.НайтиПоТипу(ТипЗнч(Данные.НаборЗаписей))); + Данные.Вставить("ПолноеИмяРегистра", Данные.МетаданныеРегистра.ПолноеИмя()); + + Если Данные.НовыеЗаписиСодержатТолькоРазличия Тогда + Данные.Вставить("НаборДляОднойЗаписи", Данные.МенеджерРегистра.СоздатьНаборЗаписей()); + КонецЕсли; + + Если Данные.ФиксированныйОтбор <> Неопределено Тогда + Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[КлючИЗначение.Ключ], КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + Если Данные.НовыеЗаписиСодержатТолькоРазличия Тогда + + Если Данные.ИмяПервогоИзмерения = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректные параметры в процедуре %1.'"), + "ОбновитьНаборыЗаписей"); + ВызватьИсключение ТекстОшибки; + Иначе + Если Данные.ИмяВторогоИзмерения = Неопределено Тогда + ЗаписьНесколькимиНаборами = Ложь; + Иначе + ЗаписьНесколькимиНаборами = ЗаписьНесколькимиНаборами(Данные, + Новый Структура, Данные.ИмяПервогоИзмерения, Данные.ЗначенияПервогоИзмерения); + КонецЕсли; + + Если ЗаписьНесколькимиНаборами Тогда + СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения; + Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); + + КоличествоПоЗначениямПервогоИзмерения = Данные.КоличествоПоЗначениям; + + Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл + Отбор = Новый Структура(Данные.ИмяПервогоИзмерения, ПервоеЗначение); + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); + + Если Данные.ИмяТретьегоИзмерения = Неопределено Тогда + ЗаписьНесколькимиНаборами = Ложь; + Иначе + // @skip-check query-in-loop - Порционная обработка данных + ЗаписьНесколькимиНаборами = ЗаписьНесколькимиНаборами(Данные, + Отбор, Данные.ИмяВторогоИзмерения, Данные.ЗначенияВторогоИзмерения); + КонецЕсли; + + Если ЗаписьНесколькимиНаборами Тогда + Для каждого ВтороеЗначение Из Данные.ЗначенияВторогоИзмерения Цикл + Отбор.Вставить(Данные.ИмяВторогоИзмерения, ВтороеЗначение); + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения], ВтороеЗначение); + + // Обновление по трем измерениям. + ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Отбор, ЕстьИзменения); + КонецЦикла; + Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения].Использование = Ложь; + Иначе + // Обновление по двум измерениям. + Данные.Вставить("КоличествоПоЗначениям", КоличествоПоЗначениямПервогоИзмерения); + ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Отбор, ЕстьИзменения); + КонецЕсли; + КонецЦикла; + Иначе + // Обновление по одному измерению. + ПрочитатьКоличествоДляЧтения(Данные); + ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Новый Структура, ЕстьИзменения); + КонецЕсли; + КонецЕсли; + Иначе + Если Данные.ИмяПервогоИзмерения = Неопределено Тогда + // Обновление всех записей. + + ТекущиеДанные = Новый Структура("НаборЗаписей, НовыеЗаписи, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + + ИначеЕсли Данные.ИмяВторогоИзмерения = Неопределено Тогда + // Обновление по одному измерению. + Отбор = Новый Структура(Данные.ИмяПервогоИзмерения); + Для каждого Значение Из Данные.ЗначенияПервогоИзмерения Цикл + + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], Значение); + Отбор[Данные.ИмяПервогоИзмерения] = Значение; + + Если Данные.ЗначенияПервогоИзмерения.Количество() <> 1 Тогда + НовыеЗаписиНабора = Данные.НовыеЗаписи; + Иначе + НовыеЗаписиНабора = Данные.НовыеЗаписи.Скопировать(Отбор); + КонецЕсли; + + ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); + + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + КонецЦикла; + + ИначеЕсли Данные.ИмяТретьегоИзмерения = Неопределено Тогда + // Обновление по двум измерениям. + СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения; + Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); + Отбор = Новый Структура(СписокПолей); + + Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); + Отбор[Данные.ИмяПервогоИзмерения] = ПервоеЗначение; + + ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям( + Данные, + Отбор, + СписокПолей, + Данные.ИмяВторогоИзмерения, + Данные.ЗначенияВторогоИзмерения, + ЕстьИзменения); + КонецЦикла; + Иначе + // Обновление по трем измерениям. + СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения + ", " + Данные.ИмяТретьегоИзмерения; + Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); + Отбор = Новый Структура(СписокПолей); + + Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); + Отбор[Данные.ИмяПервогоИзмерения] = ПервоеЗначение; + + Для каждого ВтороеЗначение Из Данные.ЗначенияВторогоИзмерения Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения], ВтороеЗначение); + Отбор[Данные.ИмяВторогоИзмерения] = ВтороеЗначение; + + ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям( + Данные, + Отбор, + СписокПолей, + Данные.ИмяВторогоИзмерения, + Данные.ЗначенияВторогоИзмерения, + ЕстьИзменения); + КонецЦикла; + КонецЦикла; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Обновляет регистр сведений по данным в таблице значений ИзмененияСтрок. +// +// Параметры: +// Данные - Структура: +// +// * МенеджерРегистра - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. +// +// * ИзмененияСоставаСтрок - ТаблицаЗначений - содержащей поля регистра и +// поле ВидИзмененияСтроки (Число): +// " 1" - значит, что строку нужно добавить, +// "-1" - значит, что строку нужно удалить. +// +// * ФиксированныйОтбор - Структура - содержащая имя измерения в ключе и значение +// отбора в значении. Может быть указана, когда измерений +// более 3-х и заранее известно, что по измерениям сверх 3-х +// будет единственное значение. Измерения указанные в +// фиксированном отборе не используются при формировании +// наборов записей для выполнения обновления. +// +// * ИзмеренияОтбора - Строка - измерений перечисленных через запятую, которые +// нужно использовать при формировании наборов записей +// для выполнения обновления (не более 3-х). Не указанные +// измерения будут превращены в фиксированный отбор, +// если по ним все значения совпадают. +// +// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, +// а лишь выявить необходимость записи и установить +// свойство ЕстьИзменения. +// +// * ДополнительныеСвойства - Неопределено +// - Структура - если Структура, тогда в +// объекты <Регистр*>НаборЗаписей в свойство +// ДополнительныеСвойства будут вставлены все параметры структуры. +// +// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций +// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления +// общего модуля ОбновлениеИнформационнойБазы. +// +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +Процедура ОбновитьРегистрСведений(Знач Данные, ЕстьИзменения = Неопределено) Экспорт + + Если Данные.ИзмененияСоставаСтрок.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ВсеПараметры = Новый Структура; + ВсеПараметры.Вставить("МенеджерРегистра"); + ВсеПараметры.Вставить("ИзмененияСоставаСтрок"); + ВсеПараметры.Вставить("ФиксированныйОтбор", Новый Структура); + ВсеПараметры.Вставить("ИзмеренияОтбора"); + ВсеПараметры.Вставить("ТолькоПроверка", Ложь); + ВсеПараметры.Вставить("ДополнительныеСвойства"); + ВсеПараметры.Вставить("ОбновлениеИБ", + ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() + Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); + + ЗаполнитьПараметры(Данные, ВсеПараметры, "МенеджерРегистра, ИзмененияСоставаСтрок"); + + МетаданныеРегистра = Метаданные.НайтиПоТипу(ТипЗнч(Данные.МенеджерРегистра.ПустойКлюч())); + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(МетаданныеРегистра.ПолноеИмя()); + + Если Данные.ИзмеренияОтбора <> Неопределено Тогда + Данные.ИзмеренияОтбора = Новый Структура(Данные.ИзмеренияОтбора); + КонецЕсли; + + МассивИзмеренийОтбора = Новый Массив; + ЗначенияИзмеренийОтбора = Новый Структура; + ИзмерениеБезФиксированногоОтбора = Новый Структура; + + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + Поле = ОписаниеПоля.Имя; + Если Не Данные.ФиксированныйОтбор.Свойство(Поле) Тогда + Значения = ЗначенияКолонкиТаблицы(Данные.ИзмененияСоставаСтрок, Поле); + + Если Значения.Количество() = 1 Тогда + Данные.ФиксированныйОтбор.Вставить(Поле, Значения[0]); + Продолжить; + КонецЕсли; + + Если Данные.ИзмеренияОтбора = Неопределено + Или Данные.ИзмеренияОтбора.Свойство(Поле) Тогда + + МассивИзмеренийОтбора.Добавить(Поле); + ЗначенияИзмеренийОтбора.Вставить(Поле, Значения); + + ИначеЕсли Не ЗначениеЗаполнено(ИзмерениеБезФиксированногоОтбора) Тогда + ИзмерениеБезФиксированногоОтбора.Вставить("Поле", Поле); + ИзмерениеБезФиксированногоОтбора.Вставить("Значения", Значения); + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если МассивИзмеренийОтбора.Количество() = 0 Тогда + Если ЗначениеЗаполнено(ИзмерениеБезФиксированногоОтбора) Тогда + Поле = ИзмерениеБезФиксированногоОтбора.Поле; + Значения = ИзмерениеБезФиксированногоОтбора.Значения; + КонецЕсли; + МассивИзмеренийОтбора.Добавить(Поле); + ЗначенияИзмеренийОтбора.Вставить(Поле, Значения); + КонецЕсли; + + Данные.Вставить("ИмяПервогоИзмерения", МассивИзмеренийОтбора[0]); + Данные.Вставить("ЗначенияПервогоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяПервогоИзмерения]); + + Если МассивИзмеренийОтбора.Количество() > 1 Тогда + Данные.Вставить("ИмяВторогоИзмерения", МассивИзмеренийОтбора[1]); + Данные.Вставить("ЗначенияВторогоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяВторогоИзмерения]); + Иначе + Данные.Вставить("ИмяВторогоИзмерения", Неопределено); + Данные.Вставить("ЗначенияВторогоИзмерения", Неопределено); + КонецЕсли; + + Если МассивИзмеренийОтбора.Количество() > 2 Тогда + Данные.Вставить("ИмяТретьегоИзмерения", МассивИзмеренийОтбора[2]); + Данные.Вставить("ЗначенияТретьегоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяТретьегоИзмерения]); + Иначе + Данные.Вставить("ИмяТретьегоИзмерения", Неопределено); + Данные.Вставить("ЗначенияТретьегоИзмерения", Неопределено); + КонецЕсли; + + Данные.Вставить("ПоляСравнения", ОписаниеКлючаЗаписи.СписокПолей); + Данные.Вставить("НовыеЗаписиСодержатТолькоРазличия", Истина); + Данные.Вставить("НовыеЗаписи", Данные.ИзмененияСоставаСтрок); + Данные.Удалить("ИзмененияСоставаСтрок"); + Данные.Удалить("ИзмеренияОтбора"); + + ОбновитьНаборыЗаписей(Данные, ЕстьИзменения); + +КонецПроцедуры + +// Возвращает пустую ссылку объекта метаданных ссылочного типа. +// +// Параметры: +// ОписаниеОбъектаМетаданных - ОбъектМетаданных, +// - Тип - по которому можно найти объект метаданных, +// - Строка - полное имя объекта метаданных. +// Возвращаемое значение: +// ЛюбаяСсылка +// +Функция ПустаяСсылкаОбъектаМетаданных(ОписаниеОбъектаМетаданных) Экспорт + + Если ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("ОбъектМетаданных") Тогда + ОбъектМетаданных = ОписаниеОбъектаМетаданных; + + ИначеЕсли ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("Тип") Тогда + ОбъектМетаданных = Метаданные.НайтиПоТипу(ОписаниеОбъектаМетаданных); + Иначе + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ОписаниеОбъектаМетаданных); + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в функции %1 + |общего модуля %2. + | + |Неверный параметр %3.'"), + "ПустаяСсылкаОбъектаМетаданных", + "УправлениеДоступомСлужебный", + "ОписаниеОбъектаМетаданных"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ПустаяСсылка = Неопределено; + Попытка + МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя()); + ПустаяСсылка = МенеджерОбъекта.ПустаяСсылка(); + Исключение + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в функции %1 + |общего модуля %2. + | + |Не удалось получить пустую ссылка для объекта метаданных + |""%3"".'"), + "ПустаяСсылкаОбъектаМетаданных", + "УправлениеДоступомСлужебный", + ОбъектМетаданных.ПолноеИмя()); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецПопытки; + + Возврат ПустаяСсылка; + +КонецФункции + +#КонецОбласти + +#Область ПрочиеПроцедурыИФункции + +// Создает запрос выбора различий между строками регистра в заданной области данных +// (на основе отборов в параметре ПоляИОтбор). +// +// Параметры: +// ТекстЗапросаВыбораНовых - Строка. +// +// ПоляИОтбор - Массив из Структура - со свойствами "ИмяПоля", ИмяПараметраУсловияОтбора. +// +// ПолноеИмяРегистра - Строка - запрос старых формируется автоматически. +// - Неопределено - запрос старых берется из следующего параметра. +// +// ТекстЗапросовВременныхТаблиц - Строка - запрос временных таблиц, если требуется. +// +// ТекстЗапросаВыбораСтарых - Строка - запрос старых, с учетом нестандартных отборов. +// - Неопределено - когда полное имя регистра определено. +// +// Возвращаемое значение: +// Строка - текст запроса +// +Функция ТекстЗапросаВыбораИзменений(ТекстЗапросаВыбораНовых, + ПоляИОтбор, + ПолноеИмяРегистра = Неопределено, + ТекстЗапросовВременныхТаблиц = Неопределено, + ТекстЗапросаВыбораСтарых = Неопределено) Экспорт + + // Подготовка текста запроса старых данных. + Если ПолноеИмяРегистра <> Неопределено Тогда + ТекстЗапросаВыбораСтарых = + "ВЫБРАТЬ + | &ВыбираемыеПоля, + | &ПодстановкаПоляВидИзмененияСтроки + |ИЗ + | ПолноеИмяРегистра КАК СтарыеДанные + |ГДЕ + | &УсловияОтбора"; + КонецЕсли; + + ВыбираемыеПоля = ""; + УсловияОтбора = "ИСТИНА"; + Для Каждого ОписаниеПоля Из ПоляИОтбор Цикл + // Сборка выбираемых полей. + ВыбираемыеПоля = ВыбираемыеПоля + СтрЗаменить( + " + | СтарыеДанные.Поле,", + "Поле", + КлючИЗначение(ОписаниеПоля).Ключ); + + // Сборка условий отбора. + Если ЗначениеЗаполнено(КлючИЗначение(ОписаниеПоля).Значение) Тогда + УсловияОтбора = УсловияОтбора + СтрЗаменить( + " + | И &ИмяПараметраУсловияОтбора", "&ИмяПараметраУсловияОтбора", // @query-part-1 + КлючИЗначение(ОписаниеПоля).Значение); + КонецЕсли; + КонецЦикла; + + ТекстЗапросаВыбораСтарых = + СтрЗаменить(ТекстЗапросаВыбораСтарых, "&ВыбираемыеПоля,", ВыбираемыеПоля); + + ТекстЗапросаВыбораСтарых = + СтрЗаменить(ТекстЗапросаВыбораСтарых, "&УсловияОтбора", УсловияОтбора); + + ТекстЗапросаВыбораСтарых = + СтрЗаменить(ТекстЗапросаВыбораСтарых, "ПолноеИмяРегистра", ПолноеИмяРегистра); + + Если СтрНайти(ТекстЗапросаВыбораСтарых, "&ПодстановкаПоляВидИзмененияСтроки") = 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в значении параметра %1 + |процедуры %2 модуля %3. + | + |В тексте запроса отсутствует строка ""%4"".'"), + "ТекстЗапросаВыбораСтарых", + "ТекстЗапросаВыбораИзменений", + "УправлениеДоступомСлужебный", + "&ПодстановкаПоляВидИзмененияСтроки"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ТекстЗапросаВыбораСтарых = СтрЗаменить( + ТекстЗапросаВыбораСтарых, "&ПодстановкаПоляВидИзмененияСтроки", "-1 КАК ВидИзмененияСтроки"); + + Если СтрНайти(ТекстЗапросаВыбораНовых, "&ПодстановкаПоляВидИзмененияСтроки") = 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в значении параметра %1 + |процедуры %2 модуля %3. + | + |В тексте запроса отсутствует строка ""%1"".'"), + "ТекстЗапросаВыбораНовых", + "ТекстЗапросаВыбораИзменений", + "УправлениеДоступомСлужебный", + "&ПодстановкаПоляВидИзмененияСтроки"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ТекстЗапросаВыбораНовых = СтрЗаменить( + ТекстЗапросаВыбораНовых, "&ПодстановкаПоляВидИзмененияСтроки", "1 КАК ВидИзмененияСтроки"); + + // Подготовка текста запроса выбора изменений. + ТекстЗапроса = + "ВЫБРАТЬ + | &ВыбираемыеПоля, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | ТекстЗапросаВыбораНовыхИСтарыхСтрок КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | &ПоляГруппировки + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0"; + + ТекстЗапросаВыбораНовыхИСтарыхСтрок = + " (" + ТекстЗапросаВыбораНовых + " + | + | ОБЪЕДИНИТЬ ВСЕ + | + | " + ТекстЗапросаВыбораСтарых + ")"; // @query-part-2 + + ВыбираемыеПоля = ""; + ПоляГруппировки = ""; + Для Каждого ОписаниеПоля Из ПоляИОтбор Цикл + // Сборка выбираемых полей. + ВыбираемыеПоля = ВыбираемыеПоля + СтрЗаменить( + " + | ВсеСтроки.Поле,", + "Поле", + КлючИЗначение(ОписаниеПоля).Ключ); + + // Сборка полей соединения. + ПоляГруппировки = ПоляГруппировки + СтрЗаменить( + " + | ВсеСтроки.Поле,", + "Поле", + КлючИЗначение(ОписаниеПоля).Ключ); + КонецЦикла; + ПоляГруппировки = Лев(ПоляГруппировки, СтрДлина(ПоляГруппировки)-1); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВыбираемыеПоля,", ВыбираемыеПоля); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляГруппировки", ПоляГруппировки); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекстЗапросаВыбораНовыхИСтарыхСтрок", ТекстЗапросаВыбораНовыхИСтарыхСтрок); + + Если ЗначениеЗаполнено(ТекстЗапросовВременныхТаблиц) Тогда + ТекстЗапроса = ТекстЗапросовВременныхТаблиц + + " + |; + |" + ТекстЗапроса; + КонецЕсли; + + Возврат ТекстЗапроса; + +КонецФункции + +Функция ПоддерживаетсяУправлениеДоступомВМоделиСервиса() Экспорт + + Возврат ОбщегоНазначения.ПодсистемаСуществует( + "СтандартныеПодсистемы.РаботаВМоделиСервиса.УправлениеДоступомВМоделиСервиса"); + +КонецФункции + +Функция ПоддерживаетсяНастройкаПравПользователейБТС() Экспорт + + Если Не ПоддерживаетсяУправлениеДоступомВМоделиСервиса() Тогда + Возврат Ложь; + КонецЕсли; + + МодульУправлениеДоступомСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль( + "УправлениеДоступомСлужебныйВМоделиСервиса"); + + Возврат МодульУправлениеДоступомСлужебныйВМоделиСервиса.ПоддерживаетсяНастройкаПравПользователейБТС(); + +КонецФункции + +#КонецОбласти + +#Область ОбновлениеИнформационнойБазы + +// Заполняет обработчик разделенных данных, зависимый от изменения неразделенных данных. +// +// Параметры: +// Параметры - Структура - структура параметров обработчиков: +// * РазделенныеОбработчики - см. ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления +// +Процедура ЗаполнитьОбработчикиРазделенныхДанных(Параметры = Неопределено) Экспорт + + Если Параметры <> Неопределено И ЕстьИзмененияПараметровОграниченияДоступа() Тогда + Обработчики = Параметры.РазделенныеОбработчики; + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "*"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации"; + КонецЕсли; + +КонецПроцедуры + +// Обновляет вспомогательные данные, которые зависят от конфигурации частично. +// +// Обновляется при наличии изменений конфигурации, записанных в параметры +// ограничения доступа при обновлении базы данных на текущую версию конфигурации. +// +Процедура ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации(Параметры = Неопределено) Экспорт + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". + РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистраПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); + ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". + РегистрыСведений.НастройкиПравОбъектов.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". + Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); + Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". + Справочники.ГруппыДоступа.ПометитьНаУдалениеГруппыДоступаПомеченныхПрофилей(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". + РегистрыСведений.ПараметрыОграниченияДоступа.ЗапланироватьОбновлениеДоступаПоИзменениямКонфигурации(); + +КонецПроцедуры + +// Обновляет настройки и включает регламентное задание. +Процедура ВключитьЗаполнениеДанныхДляОграниченияДоступа() Экспорт + + Использование = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + + Если ОбщегоНазначения.РазделениеВключено() Тогда + УстановитьЗаполнениеДанныхДляОграниченияДоступа(Использование); + Иначе + Расписание = Новый РасписаниеРегламентногоЗадания; + Расписание.ПериодНедель = 1; + Расписание.ПериодПовтораДней = 1; + Расписание.ПериодПовтораВТечениеДня = 300; + Расписание.ПаузаПовтора = 90; + + ЗаданиеМетаданные = Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа; + Задание = РегламентныеЗаданияСервер.ПолучитьРегламентноеЗадание(ЗаданиеМетаданные); + + Задание.Использование = Использование; + Задание.Расписание = Расписание; + + Задание.ИнтервалПовтораПриАварийномЗавершении + = ЗаданиеМетаданные.ИнтервалПовтораПриАварийномЗавершении; + + Задание.КоличествоПовторовПриАварийномЗавершении + = ЗаданиеМетаданные.КоличествоПовторовПриАварийномЗавершении; + + Задание.Записать(); + КонецЕсли; + +КонецПроцедуры + +// Обновляет данные профиля "ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок". +Процедура ОбновитьДанныеПрофиляОткрытиеВнешнихОтчетовИОбработок() Экспорт + + УникальныйИдентификаторПрофиля = Новый УникальныйИдентификатор( + ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок()); + + Ссылка = Справочники.ПрофилиГруппДоступа.ПолучитьСсылку(УникальныйИдентификаторПрофиля); + Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ссылка") = Неопределено Тогда + Возврат; + КонецЕсли; + СсылкаПометитьНаУдаление = Ложь; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка); + + Если ОбщегоНазначения.РазделениеВключено() Тогда + СсылкаПометитьНаУдаление = Истина; + Иначе + ОписаниеПрофиля = ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок(); + ПоставляемыйПрофильСсылка = Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( + ОписаниеПрофиля.Имя); + + Если Ссылка <> ПоставляемыйПрофильСсылка Тогда + Если ПоставляемыйПрофильСсылка <> Неопределено Тогда + СсылкаПометитьНаУдаление = Истина; + Иначе + // Установка идентификатора поставляемых данных. + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПрофильОбъект = Ссылка.ПолучитьОбъект(); + ПрофильОбъект.ИдентификаторПоставляемыхДанных = УникальныйИдентификаторПрофиля; + ПрофильОбъект.Комментарий = ""; + ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ПрофильОбъект, Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если СсылкаПометитьНаУдаление Тогда + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПрофильОбъект = Ссылка.ПолучитьОбъект(); + ПрофильОбъект.ПометкаУдаления = Истина; + ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ПрофильОбъект, Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + ГруппыПрофиля = ГруппыПрофиля(Ссылка, Ложь); + Для Каждого СсылкаГруппы Из ГруппыПрофиля Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаГруппы); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ГруппаОбъект = СсылкаГруппы.ПолучитьОбъект(); + ГруппаОбъект.ПометкаУдаления = Истина; + ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ГруппаОбъект, Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Только для внутреннего использования. +Процедура ОбновитьВспомогательныеДанныеГруппДоступа(Параметры) Экспорт + + Справочники.ГруппыДоступа.ОбновитьВспомогательныеДанныеГруппДоступа(Параметры); + +КонецПроцедуры + +#КонецОбласти + +#Область ВспомогательныеПроцедурыИФункции + +// Возвращаемое значение: +// см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Функция ПраваРолейРасширений() Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ПраваРолейРасширений = Неопределено; + + УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Истина); + Попытка + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(ПраваРолейРасширений); + Исключение + УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Ложь); + ВызватьИсключение; + КонецПопытки; + УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Ложь); + + Возврат ПраваРолейРасширений; + +КонецФункции + +// Параметры: +// ПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Процедура ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(ПраваРолейРасширений = Неопределено) + + ПустыеПраваРолейРасширений = РегистрыСведений.ПраваРолей.ТаблицаПравРолей(Истина, Истина, Истина); + + Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда + МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер"); + Если МодульОбменДаннымиСервер.НастройкаПодчиненногоУзлаРИБ() Тогда + ПраваРолейРасширений = ПустыеПраваРолейРасширений; + Возврат; + КонецЕсли; + КонецЕсли; + + // Заполнение прав ролей расширений, которые состоят + // из изменений прав на объекты конфигурации и прав на объекты расширений. + УстановитьНовыеПраваРолейРасширений = Ложь; + Если ЗначениеЗаполнено(ПараметрыСеанса.ПодключенныеРасширения) Тогда + ХранилищеПравРолейРасширений = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения( + "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей"); // ХранилищеЗначения + + Если ХранилищеПравРолейРасширений = Неопределено Тогда + ПраваРолейРасширений = Неопределено; + Иначе + ПраваРолейРасширений = ЗначениеИзХранилища(ХранилищеПравРолейРасширений); + Если Не ЭтоПраваРолейРасширений(ПраваРолейРасширений, ПустыеПраваРолейРасширений) Тогда + ПраваРолейРасширений = Неопределено; + КонецЕсли; + КонецЕсли; + Если ПраваРолейРасширений = Неопределено Тогда + Запрос = РегистрыСведений.ПраваРолей.ЗапросИзменений(Истина); + ПраваРолейРасширений = Запрос.Выполнить().Выгрузить(); + УстановитьНовыеПраваРолейРасширений = Истина; + КонецЕсли; + Иначе + ПраваРолейРасширений = ПустыеПраваРолейРасширений; + КонецЕсли; + + // Проверка необходимости обновления регистра ТаблицыГруппДоступа. + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ПараметрыОбновленияТаблицГруппДоступа"; + ПараметрыОбновления = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + + Если ТипЗнч(ПараметрыОбновления) <> Тип("Структура") + Или Не ПараметрыОбновления.Свойство("ПоследниеПраваРолейРасширений") + Или Не ЭтоПраваРолейРасширений(ПараметрыОбновления.ПоследниеПраваРолейРасширений, ПустыеПраваРолейРасширений) Тогда + + ТребуетсяОбновление = Истина; + ПоследниеПраваРолейРасширений = Неопределено; + Иначе + ПоследниеПраваРолейРасширений = ПараметрыОбновления.ПоследниеПраваРолейРасширений; + ТребуетсяОбновление = ПраваРолейРасширенийИзменились(ПраваРолейРасширений, ПоследниеПраваРолейРасширений); + КонецЕсли; + + Если Не ТребуетсяОбновление Тогда + Если УстановитьНовыеПраваРолейРасширений Тогда; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения( + "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей", + Новый ХранилищеЗначения(ПраваРолейРасширений)); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПоследниеПраваРолейРасширений = Неопределено Тогда + // Так как последние права ролей расширений недоступны, требуется обновить весь регистр. + ОбъектыСИзменениемПравДляОбновления = Неопределено; + Иначе + ТекущиеОбъектыСИзменениемПрав = РегистрыСведений.ПраваРолей.ИзмененныеОбъектыМетаданных( + ПраваРолейРасширений.Скопировать()); + + ПоследниеОбъектыСИзменениемПрав = РегистрыСведений.ПраваРолей.ИзмененныеОбъектыМетаданных( + ПоследниеПраваРолейРасширений.Скопировать()); + + ОбъектыСИзменениемПравДляОбновления = Новый Массив(ТекущиеОбъектыСИзменениемПрав); + Для Каждого Идентификатор Из ПоследниеОбъектыСИзменениемПрав Цикл + ОбъектыСИзменениемПравДляОбновления.Добавить(Идентификатор); + КонецЦикла; + КонецЕсли; + + НовыеПараметрыОбновления = Новый Структура; + НовыеПараметрыОбновления.Вставить("ПоследниеПраваРолейРасширений", ПраваРолейРасширений); + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + Если Не ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + // Предварительное кэширование в файловой ИБ вне транзакции для предотвращения конфликтов блокировок. + УправлениеДоступомСлужебныйПовтИсп.ПрофильАдминистратор(); + ПроверитьОбъектыНастроекДоступа(); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + Если УжеИзменен Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + Если УстановитьНовыеПраваРолейРасширений Тогда; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения( + "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей", + Новый ХранилищеЗначения(ПраваРолейРасширений)); + КонецЕсли; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + НовыеПараметрыОбновления, Истина); + РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра(, ОбъектыСИзменениемПравДляОбновления); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. +// +// Параметры: +// ПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// ПустыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Функция ЭтоПраваРолейРасширений(ПраваРолейРасширений, ПустыеПраваРолейРасширений) + + Если ТипЗнч(ПраваРолейРасширений) <> Тип("ТаблицаЗначений") Тогда + Возврат Ложь; + КонецЕсли; + + Если ПраваРолейРасширений.Колонки.Количество() <> ПустыеПраваРолейРасширений.Колонки.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого Колонка Из ПустыеПраваРолейРасширений.Колонки Цикл + НайденнаяКолонка = ПраваРолейРасширений.Колонки.Найти(Колонка.Имя); + Если НайденнаяКолонка = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + Если Колонка.ТипЗначения <> НайденнаяКолонка.ТипЗначения Тогда + Возврат Ложь; + КонецЕсли; + КонецЦикла; + + Возврат Истина; + +КонецФункции + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. +// +// Параметры: +// НовыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// СтарыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Функция ПраваРолейРасширенийИзменились(НовыеПраваРолейРасширений, СтарыеПраваРолейРасширений) + + Если НовыеПраваРолейРасширений.Количество() <> СтарыеПраваРолейРасширений.Количество() Тогда + Возврат Истина; + КонецЕсли; + + Отбор = Новый Структура; + Поля = Новый Массив; + Для Каждого Колонка Из НовыеПраваРолейРасширений.Колонки Цикл + Поля.Добавить(Колонка.Имя); + Отбор.Вставить(Колонка.Имя); + КонецЦикла; + СтарыеПраваРолейРасширений.Индексы.Добавить(СтрСоединить(Поля, ",")); + + Для Каждого Строка Из НовыеПраваРолейРасширений Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Если СтарыеПраваРолейРасширений.НайтиСтроки(Отбор).Количество() <> 1 Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +Процедура ПриИзмененииНаборовЗначенийДоступа(Знач СсылкаНаОбъект, ОбновлениеИБ = Ложь) + + СсылкиНаЗависимыеОбъекты = Новый Массив; + + УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа( + СсылкаНаОбъект, СсылкиНаЗависимыеОбъекты); + + Для каждого СсылкаНаЗависимыйОбъект Из СсылкиНаЗависимыеОбъекты Цикл + + Если СсылкаНаЗависимыйОбъект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда + // Изменение объекта не требуется. + // @skip-check query-in-loop - Порционная обработка данных + ЗаписатьНаборыЗначенийДоступа(СсылкаНаЗависимыйОбъект, , ОбновлениеИБ); + Иначе + // Изменение объекта требуется. + Объект = СсылкаНаЗависимыйОбъект.ПолучитьОбъект(); + Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект); + Если НЕ НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаЗависимыйОбъект, Таблица) Тогда + Продолжить; + КонецЕсли; + ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); + Попытка + ЗаблокироватьДанныеДляРедактирования(СсылкаНаЗависимыйОбъект, Объект.ВерсияДанных); + Объект.ДополнительныеСвойства.Вставить("ЗаписатьНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("ЗаписатьЗависимыеНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("НаборыЗначенийДоступаТабличнойЧастиЗаполнены"); + Объект.НаборыЗначенийДоступа.Загрузить(Таблица); + Если ОбновлениеИБ Тогда + Объект.ДополнительныеСвойства.Вставить("ЗаписьНаборовЗначенийДоступаПриОбновленииИБ"); + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + Иначе + Объект.ОбменДанными.Загрузка = Истина; + // АПК:1327-выкл - №783.1.4.1 Допустимо оставить запись без + // предварительной управляемой блокировки объекта, так как только + // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. + Объект.Записать(); + // АПК:1327-вкл. + КонецЕсли; + РазблокироватьДанныеДляРедактирования(СсылкаНаЗависимыйОбъект); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить зависимый набор значений доступа объекта + |""%1"" по причине: + | + |%2'"), + Строка(СсылкаНаЗависимыйОбъект), + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)); + ВызватьИсключение ТекстОшибки; + КонецПопытки; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Функция ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок() + + Возврат "1b3472f6-4d87-11e6-8264-5404a6a6895d"; + +КонецФункции + +Функция ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(Профиль) Экспорт + + Если ТипЗнч(Профиль) = Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда + ИдентификаторПрофиля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Профиль, "ИдентификаторПоставляемыхДанных"); + + ИначеЕсли Не Профиль.ЭтоГруппа Тогда + ИдентификаторПрофиля = Профиль.ИдентификаторПоставляемыхДанных; + Иначе + Возврат Ложь; + КонецЕсли; + + Возврат ВРег(Строка(ИдентификаторПрофиля)) = ВРег(ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок()); + +КонецФункции + +Функция ГруппыДоступаПрофиляОткрытиеВнешнихОтчетовИОбработок() + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторПоставляемыхДанных", + Новый УникальныйИдентификатор(ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок())); + + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль.ИдентификаторПоставляемыхДанных = &ИдентификаторПоставляемыхДанных"; + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +Функция ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок() Экспорт + + ОписаниеПрофиля = УправлениеДоступом.НовоеОписаниеПрофиляГруппДоступа(); + ОписаниеПрофиля.Имя = "ОткрытиеВнешнихОтчетовИОбработок"; + ОписаниеПрофиля.Родитель = "ДополнительныеПрофили"; + ОписаниеПрофиля.Идентификатор = ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок(); + + ОписаниеПрофиля.Наименование = + НСтр("ru = 'Открытие внешних отчетов и обработок'", ОбщегоНазначения.КодОсновногоЯзыка()); + + ОписаниеПрофиля.Описание = + НСтр("ru = 'Предоставляет право открытия внешних отчетов и обработок из меню ""Файл - Открыть"". + |Состав ролей профиля не рекомендуется изменять.'"); + + ОписаниеПрофиля.Роли.Добавить("ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок"); + + Возврат ОписаниеПрофиля; + +КонецФункции + +Функция ГруппаДоступаОткрытиеВнешнихОтчетовИОбработок(СвойстваПрофиля) + + // Поиск по идентификатору. + УникальныйИдентификатор = Новый УникальныйИдентификатор("f6929bcb-532f-11e6-a20f-5404a6a6895d"); + Ссылка = Справочники.ГруппыДоступа.ПолучитьСсылку(УникальныйИдентификатор); + СсылкаСуществует = (ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ссылка") <> Неопределено); + Если СсылкаСуществует Тогда + Возврат Ссылка; + КонецЕсли; + + // Поиск по профилю. + ГруппыПрофиля = ГруппыПрофиля(СвойстваПрофиля.Ссылка, Неопределено); + Если ГруппыПрофиля.Количество() > 0 Тогда + Возврат ГруппыПрофиля[0]; + КонецЕсли; + + // Создание группы. + ГруппаДоступаОбъект = Справочники.ГруппыДоступа.СоздатьЭлемент(); + ГруппаДоступаОбъект.УстановитьСсылкуНового(Ссылка); + ГруппаДоступаОбъект.Наименование = СвойстваПрофиля.Наименование; + ГруппаДоступаОбъект.Профиль = СвойстваПрофиля.Ссылка; + ГруппаДоступаОбъект.Комментарий = + НСтр("ru = 'Предоставляет право открытия внешних отчетов и обработок из меню ""Файл - Открыть"".'", + ОбщегоНазначения.КодОсновногоЯзыка()); + + ГруппаДоступаОбъект.Записать(); // Важно, чтобы созданная группа "уехала" в подчиненный узел. + + Возврат ГруппаДоступаОбъект.Ссылка; + +КонецФункции + +Функция ГруппыПрофиля(СсылкаПрофиля, ПометкаУдаления) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &Профиль + | И ГруппыДоступа.ПометкаУдаления = &ПометкаУдаления + | + |УПОРЯДОЧИТЬ ПО + | ГруппыДоступа.ПометкаУдаления"; + + Запрос.УстановитьПараметр("Профиль", СсылкаПрофиля); + + Если ПометкаУдаления = Неопределено Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "И ГруппыДоступа.ПометкаУдаления = &ПометкаУдаления", ""); // @query-part-1 + Иначе + Запрос.УстановитьПараметр("ПометкаУдаления", ПометкаУдаления); + КонецЕсли; + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +// Для функция РазрешенныеЗначенияДляДинамическогоСписка, ЕстьОграничениеПоВидуДоступа. +Функция ТекстЗапросаГруппДоступа() + + Возврат + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ГруппыДоступаПользователя + |ИЗ + | Справочник.ИдентификаторыОбъектовМетаданных КАК СвойстваТекущейТаблицы + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа + | ПО (СвойстваТекущейТаблицы.ПолноеИмя = &ИмяОсновнойТаблицыСписка) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ГДЕ + | ТаблицыГруппДоступа.Таблица = СвойстваТекущейТаблицы.Ссылка + | И ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступа.Ссылка)) + | И (ГруппыДоступа.Ссылка В + | (ВЫБРАТЬ + | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь + | И СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь))"; + +КонецФункции + +// Для процедур ОбновитьНаборЗаписей, ОбновитьНаборыЗаписей, ОбновитьРегистрСведений. +Процедура ЗаполнитьПараметры(ВходныеПараметры, Знач ВсеПараметры, Знач ОбязательныеПараметры = "") + + Если ТипЗнч(ВходныеПараметры) = Тип("Структура") Тогда + Параметры = ВходныеПараметры; + ИначеЕсли ВходныеПараметры = Неопределено Тогда + Параметры = Новый Структура; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректный тип набора свойств ""%1"". + |Допустимые типы: %2, %3.'"), + ТипЗнч(ВходныеПараметры), "Структура", "Неопределено"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Для каждого КлючИЗначение Из Параметры Цикл + Если Не ВсеПараметры.Свойство(КлючИЗначение.Ключ) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Указан несуществующий параметр %1'"), + КлючИЗначение.Ключ); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ВсеПараметры[КлючИЗначение.Ключ] = Параметры[КлючИЗначение.Ключ]; + КонецЦикла; + + Если ЗначениеЗаполнено(ОбязательныеПараметры) Тогда + ОбязательныеПараметры = Новый Структура(ОбязательныеПараметры); + + Для каждого КлючИЗначение Из ОбязательныеПараметры Цикл + Если Не Параметры.Свойство(КлючИЗначение.Ключ) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не указан обязательный параметр %1'"), + КлючИЗначение.Ключ); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ВходныеПараметры = ВсеПараметры; + +КонецПроцедуры + +// Для процедур ПриОтправкеДанныхГлавному, ПриОтправкеДанныхПодчиненному, +// ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного. +// +Функция ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) + + Возврат ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ПраваРолей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗависимостиПравДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ТаблицыГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗначенияГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗначенияГруппДоступаПоУмолчанию") + Или ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.КлючиДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.НаборыГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаВнешнихПользователей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаНаборовГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаКОбъектам") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаКРегистрам") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаПользователей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ОбновлениеКлючейДоступаКДанным") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ОбновлениеКлючейДоступаПользователей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ПараметрыОграниченияДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступаПоТаблицам") + Или ТипЗнч(ЭлементДанных) = Тип("КонстантаМенеджерЗначения.ПервоеОбновлениеДоступаЗавершилось"); + +КонецФункции + +// Для процедур ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного +Процедура ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Подчиненному, СозданиеНачальногоОбраза) + + Если СозданиеНачальногоОбраза Тогда // Отправка подчиненному узлу. + // Частичное изменение объектов при создании начального образа не поддерживается, + // обработку смотри в процедуре ПриНастройкеПодчиненногоУзлаРИБ. + // + // Роли расширений назначаются независимо во всех РИБ-узлах. + // Администраторы назначаются независимо во всех РИБ-узлах. + Возврат; + КонецЕсли; + + // Стандартная обработка не переопределяется. + Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить + Или ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда + Возврат; + КонецЕсли; + + Если ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) Тогда + ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать; + Возврат; + КонецЕсли; + + Если Подчиненному Тогда + Возврат; + КонецЕсли; + + ТипЭлемента = ТипЗнч(ЭлементДанных); + + // Профиль и группа доступа открытия внешних отчетов и обработок + // недоступны в сервисе, но доступны в автономном рабочем месте. + Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() + И ( ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") + И ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(ЭлементДанных) + Или ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") + И Не ЭлементДанных.ЭтоГруппа + И ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(ЭлементДанных.Профиль) ) Тогда + + ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать; + КонецЕсли; + + // Роли расширений назначаются независимо во всех РИБ-узлах. + Если ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширений(ЭлементДанных); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного +Процедура ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, ОтПодчиненного) + + // Стандартная обработка не переопределяется. + Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда + Возврат; + КонецЕсли; + + Если ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) Тогда + ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; + Возврат; + КонецЕсли; + + ТипЭлемента = ТипЗнч(ЭлементДанных); + + Если ОтПодчиненного И ОбщегоНазначения.РазделениеВключено() Тогда + Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") + Или ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписейУниверсально") + Или ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") + Или ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ГруппыЗначенийДоступа") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НаборыЗначенийДоступа") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НаследованиеНастроекПравОбъектов") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НастройкиПравОбъектов") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступа") Тогда + // Получение данных из автономного рабочего места пропускается, а для соответствия + // данных в узлах, текущие данные отправляются обратно в автономное рабочее место. + ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; + ОтправкаНазад = Истина; + Возврат; + КонецЕсли; + + ИначеЕсли ОтПодчиненного Тогда + Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") + Или ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписейУниверсально") Тогда + // Получение данных из подчиненного узла пропускается, а для соответствия + // данных в узлах, текущие данные отправляются обратно в автономное рабочее место. + ОтправкаНазад = Истина; + ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; + Возврат; + КонецЕсли; + КонецЕсли; + + Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") Тогда + Константы.ОграничиватьДоступНаУровнеЗаписей.СоздатьМенеджерЗначения().ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступа") Тогда + РегистрыСведений.ИспользуемыеВидыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + // Роли расширений назначаются независимо во всех РИБ-узлах. + Справочники.ПрофилиГруппДоступа.ВосстановитьСоставРолейРасширений(ЭлементДанных); + // Регистрация измененного профиля для обновления вспомогательных данных. + Справочники.ПрофилиГруппДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") Тогда + // Администраторы назначаются независимо во всех РИБ-узлах. + Справочники.ГруппыДоступа.ВосстановитьСоставУчастниковГруппыДоступаАдминистраторы(ЭлементДанных); + // Регистрация измененной группы доступа для обновления вспомогательных данных. + Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли Метаданные.ОпределяемыеТипы.ЗначениеДоступаОбъект.Тип.СодержитТип(ТипЭлемента) Тогда + // Регистрация измененных значений доступа для обновления вспомогательных данных после загрузки. + ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных); + КонецЕсли; + + Если ТипЭлемента <> Тип("УдалениеОбъекта") Тогда + Возврат; + КонецЕсли; + + ЭлементДанных = ЭлементДанных; // УдалениеОбъекта + ТипСсылки = ТипЗнч(ЭлементДанных.Ссылка); + + Если ТипСсылки = Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда + // Регистрация измененного профиля для обновления вспомогательных данных после загрузки. + Справочники.ПрофилиГруппДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипСсылки = Тип("СправочникСсылка.ГруппыДоступа") Тогда + // Регистрация измененной группы доступа для обновления вспомогательных данных после загрузки. + Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + КонецЕсли; + + // Регистрация измененных значений доступа для обновления вспомогательных данных после загрузки. + Если УправлениеДоступомСлужебныйПовтИсп.ТипыСсылокИзЗначениеДоступаОбъект().СодержитТип(ТипСсылки) Тогда + ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПриПолученииДанныхОтГлавногоИлиОтПодчиненного. +Процедура ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных) + + УстановитьПривилегированныйРежим(Истина); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами; + ТипСсылки = ТипЗнч(ЭлементДанных.Ссылка); + + Если ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипСсылки) = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта") Тогда + РегистрироватьГруппыДоступа = Истина; + СсылкаОбъекта = ЭлементДанных.Ссылка; + Иначе + РегистрироватьГруппыДоступа = ЭлементДанных.ЭтоНовый(); + СсылкаОбъекта = ПользователиСлужебный.СсылкаОбъекта(ЭлементДанных); + КонецЕсли; + + ПользователиСлужебный.ЗарегистрироватьСсылки("ЗначенияДоступа", СсылкаОбъекта); + + Если СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(ТипСсылки) <> Неопределено Тогда + Если Не РегистрироватьГруппыДоступа Тогда + СтарыйРодитель = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЭлементДанных.Ссылка, "Родитель"); + Если ЭлементДанных.Родитель <> СтарыйРодитель Тогда + РегистрироватьГруппыДоступа = Истина; + КонецЕсли; + КонецЕсли; + Если РегистрироватьГруппыДоступа Тогда + ГруппыДоступа = ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипСсылки); + ПользователиСлужебный.ЗарегистрироватьСсылки("ГруппыДоступаЗначенийСИерархией", ГруппыДоступа); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПослеПолученияДанных, ПослеОбновленияИнформационнойБазы. +Процедура ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных() + + РегистрыСведений.ПараметрыРаботыВерсийРасширений.ЗаблокироватьДляИзмененияВФайловойИБ(); + + УстановитьПривилегированныйРежим(Истина); + Константы.ОграничиватьДоступНаУровнеЗаписей.СоздатьМенеджерЗначения().ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + РегистрыСведений.ИспользуемыеВидыДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + Справочники.ПрофилиГруппДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + Справочники.ГруппыДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных(); + +КонецПроцедуры + +// Для процедуры ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных. +Процедура ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных() + + ОчисткаРегистрации = Новый Массив; + + ОбработатьЗарегистрированноеИзменениеЗначенийДоступа("ЗначенияДоступа", ОчисткаРегистрации); + ОбработатьЗарегистрированноеИзменениеИерархииЗначенийДоступа("ГруппыДоступаЗначенийСИерархией", + ОчисткаРегистрации); + + Для Каждого ИмяВидаСсылок Из ОчисткаРегистрации Цикл + ПользователиСлужебный.ЗарегистрироватьСсылки(ИмяВидаСсылок, Null); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных. +Процедура ОбработатьЗарегистрированноеИзменениеЗначенийДоступа(ИмяВидаСсылок, ОчисткаРегистрации) + + ЗначенияДоступа = ПользователиСлужебный.ЗарегистрированныеСсылки(ИмяВидаСсылок); + + Если ЗначенияДоступа.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если ЗначенияДоступа.Количество() = 1 И ЗначенияДоступа[0] = Неопределено Тогда + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(); + Иначе + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(ЗначенияДоступа); + КонецЕсли; + + ОчисткаРегистрации.Добавить(ИмяВидаСсылок); + +КонецПроцедуры + +// Для процедуры ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных. +Процедура ОбработатьЗарегистрированноеИзменениеИерархииЗначенийДоступа(ИмяВидаСсылок, ОчисткаРегистрации) + + ГруппыДоступа = ПользователиСлужебный.ЗарегистрированныеСсылки(ИмяВидаСсылок); + + Если ГруппыДоступа.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если ГруппыДоступа.Количество() = 1 И ГруппыДоступа[0] = Неопределено Тогда + РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(); + Иначе + РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(ГруппыДоступа); + КонецЕсли; + + ОчисткаРегистрации.Добавить(ИмяВидаСсылок); + +КонецПроцедуры + +// Для процедур ВключитьПользователяВГруппуДоступа. +Функция ОбработатьСвязьПользователяСГруппойДоступа(Пользователь, ПоставляемыйПрофиль, Включить = Неопределено) + + Если ТипЗнч(Пользователь) <> Тип("СправочникСсылка.Пользователи") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ГруппыПользователей") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ВнешниеПользователи") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ГруппыВнешнихПользователей") Тогда + + Возврат Ложь; + КонецЕсли; + + ИдентификаторПоставляемогоПрофиля = Неопределено; + + Если ТипЗнч(ПоставляемыйПрофиль) = Тип("Строка") Тогда + Если СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(ПоставляемыйПрофиль) Тогда + + ИдентификаторПоставляемогоПрофиля = ПоставляемыйПрофиль; + + ПоставляемыйПрофиль = Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( + ИдентификаторПоставляемогоПрофиля,, Истина); + Иначе + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Если ТипЗнч(ПоставляемыйПрофиль) <> Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда + Возврат Ложь; + КонецЕсли; + + Если ИдентификаторПоставляемогоПрофиля = Неопределено Тогда + ИдентификаторПоставляемогоПрофиля = + Справочники.ПрофилиГруппДоступа.ИдентификаторПоставляемогоПрофиля(ПоставляемыйПрофиль); + КонецЕсли; + + Если ИдентификаторПоставляемогоПрофиля = Справочники.ПрофилиГруппДоступа.ИдентификаторПрофиляАдминистратор() Тогда + Возврат Ложь; + КонецЕсли; + + СвойстваПрофиля = Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля(ИдентификаторПоставляемогоПрофиля); + + Если СвойстваПрофиля = Неопределено + ИЛИ СвойстваПрофиля.ВидыДоступа.Количество() <> 0 Тогда + + Возврат Ложь; + КонецЕсли; + + ГруппаДоступа = Неопределено; + + Если УпрощенныйИнтерфейсНастройкиПравДоступа() Тогда + + Если ТипЗнч(Пользователь) <> Тип("СправочникСсылка.Пользователи") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ВнешниеПользователи") Тогда + + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Профиль", ПоставляемыйПрофиль); + Запрос.УстановитьПараметр("Пользователь", Пользователь); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &Профиль + | И ГруппыДоступа.Пользователь = &Пользователь"; + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + ГруппаДоступа = Выборка.Ссылка; + КонецЕсли; + + Если ГруппаДоступа = Неопределено Тогда + Если Включить <> Истина Тогда + Возврат Ложь; + Иначе + ГруппаДоступа = Справочники.ГруппыДоступа.СоздатьЭлемент(); + ГруппаДоступа.Наименование = СвойстваПрофиля.Наименование; + ГруппаДоступа.Профиль = ПоставляемыйПрофиль; + ГруппаДоступа.Пользователь = Пользователь; + ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; + ГруппаДоступа.Записать(); + Возврат Истина; + КонецЕсли; + КонецЕсли; + Иначе + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПоставляемыйПрофиль", ПоставляемыйПрофиль); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка, + | ГруппыДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &ПоставляемыйПрофиль + | + |УПОРЯДОЧИТЬ ПО + | ГруппыДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля УБЫВ"; + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + ГруппаДоступа = Выборка.Ссылка; // СправочникСсылка.ГруппыДоступа - + КонецЕсли; + + Если ГруппаДоступа = Неопределено Тогда + Если Включить <> Истина Тогда + Возврат Ложь; + Иначе + ГруппаДоступа = Справочники.ГруппыДоступа.СоздатьЭлемент(); + ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля = Истина; + ГруппаДоступа.Наименование = СвойстваПрофиля.Наименование; + ГруппаДоступа.Профиль = ПоставляемыйПрофиль; + ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; + ГруппаДоступа.Записать(); + Возврат Истина; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Ссылка", ГруппаДоступа); + Запрос.УстановитьПараметр("Пользователь", Пользователь); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппы + |ГДЕ + | УчастникиГруппы.Ссылка = &Ссылка + | И УчастникиГруппы.Пользователь = &Пользователь"; + ПользовательНайден = НЕ Запрос.Выполнить().Пустой(); + + Если Включить = Неопределено Тогда + Возврат ПользовательНайден; + КонецЕсли; + + Если Включить И ПользовательНайден Тогда + Возврат Истина; + КонецЕсли; + + Если НЕ Включить И НЕ ПользовательНайден Тогда + Возврат Истина; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступа); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + ГруппаДоступа = ГруппаДоступа.ПолучитьОбъект(); + + Если НЕ УпрощенныйИнтерфейсНастройкиПравДоступа() + И НЕ ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля Тогда + + ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля = Истина; + КонецЕсли; + + Если Включить Тогда + ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; + Иначе + Отбор = Новый Структура("Пользователь", Пользователь); + Строки = ГруппаДоступа.Пользователи.НайтиСтроки(Отбор); + Для каждого Строка Из Строки Цикл + ГруппаДоступа.Пользователи.Удалить(Строка); + КонецЦикла; + КонецЕсли; + + ГруппаДоступа.Записать(); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Возврат Истина; + +КонецФункции + +// Для процедуры ЗаписатьНаборыЗначенийДоступаПриЗаписи. + +// Перезаписывает наборы значений доступа проверяемого объекта +// в РегистрСведений.НаборыЗначенийДоступа, используя процедуру +// УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(). +// +// Процедура вызывается из УправлениеДоступомСлужебный.ЗаписатьНаборыЗначенийДоступа(), +// но может быть вызвана из любого места, например, +// при включении ограничения доступа на уровне записей. +// +// Вызывает процедуру прикладного разработчика +// УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа(), +// которая используется для перезаписи зависимых наборов значений доступа. +// +// Параметры: +// Объект - ЛюбаяСсылка +// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - +// В случае вызова с клиента можно передать только ссылку, а нужен объект. +// Если получена ссылка, то по ней будет получен объект. +// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// +Процедура ЗаписатьНаборыЗначенийДоступа(Знач Объект, ЕстьИзменения = Неопределено, ОбновлениеИБ = Ложь) + + УстановитьПривилегированныйРежим(Истина); + + // Если передача параметра Объект производилась с клиента на сервер, + // то передавалась ссылка, и объект требуется получить. + Объект = ?(Объект = Объект.Ссылка, Объект.ПолучитьОбъект(), Объект); + СсылкаНаОбъект = Объект.Ссылка; + ТипЗначенияОбъект = ТипЗнч(Объект); + + НаборыЗаписываются = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ НаборыЗаписываются Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписках на события %2.'"), + ТипЗначенияОбъект, + "ЗаписатьНаборыЗначенийДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ВозможныеТипыОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы( + "РегистрСведений.НаборыЗначенийДоступа.Измерение.Объект"); + + Если ВозможныеТипыОбъектов.Получить(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка при записи наборов значений доступа: + |в регистре сведений %1 в измерении %2 + |не задан тип ""%3"".'"), + "НаборыЗначенийДоступа", + "Объект", + ТипЗнч(СсылкаНаОбъект)); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() + И Не УправлениеДоступом.ПроизводительныйВариант() Тогда + + Если Метаданные.НайтиПоТипу(ТипЗначенияОбъект).ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда + + Таблица = УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(); + УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(Объект, Таблица); + + УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( + Таблица, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); + Иначе + ТабличнаяЧастьЗаполняется = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей + |ЗаполнитьНаборыЗначенийДоступаТабличныхЧастейДокументов").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ ТабличнаяЧастьЗаполняется Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписках на события %2.'"), + ТипЗначенияОбъект, + "ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + // Записан объект с уже заполненной табличной частью НаборыЗначенийДоступа. + Таблица = Объект.НаборыЗначенийДоступа.Выгрузить(); + КонецЕсли; + + ПодготовитьНаборыЗначенийДоступаКЗаписи(СсылкаНаОбъект, Таблица, Истина); + + Данные = Новый Структура; + Данные.Вставить("МенеджерРегистра", РегистрыСведений.НаборыЗначенийДоступа); + Данные.Вставить("ФиксированныйОтбор", Новый Структура("Объект", СсылкаНаОбъект)); + Данные.Вставить("НовыеЗаписи", Таблица); + Данные.Вставить("ОбновлениеИБ", ОбновлениеИБ); + + НачатьТранзакцию(); + Попытка + ОбновитьНаборыЗаписей(Данные, ЕстьИзменения); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЕстьИзменения = Истина Тогда + ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); + КонецЕсли; + Иначе + Запрос = Новый Запрос( + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.НаборыЗначенийДоступа КАК НаборыЗначенийДоступа + |ГДЕ + | НаборыЗначенийДоступа.Объект = &СсылкаНаОбъект"); + + Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект); + + // АПК:1328-выкл - №648.1.1 Допустимо чтение без предварительной + // управляемой разделяемой блокировки объекта, так как только + // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. + Если НЕ Запрос.Выполнить().Пустой() Тогда + // АПК:1328-вкл. + + // Очистка устаревшего набора. + // Запись нового набора будет выполнена регламентным заданием, + // после включения ограничения на уровне записей. + НаборЗаписей = РегистрыСведений.НаборыЗначенийДоступа.СоздатьНаборЗаписей(); + НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект); + НаборЗаписей.Записать(); + ЕстьИзменения = Истина; + + // Очистка устаревших зависимых наборов. + ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаписатьЗависимыеНаборыЗначенийДоступаПриЗаписи. + +// Перезаписывает наборы значений доступа зависимых объектов. +// +// Процедура вызывается из УправлениеДоступомСлужебный.ЗаписатьЗависимыеНаборыЗначенийДоступа(), +// состав типов подписки дополняет (без пересечения) состав типов подписки ЗаписатьНаборыЗначенийДоступа, +// теми типами, для которых выполнять запись наборов в регистр сведений НаборыЗначенийДоступа +// не требуется, но сами наборы входят в состав других наборов, например, наборы некоторых файлов +// из справочника "Файлы" могут входить в состав некоторых бизнес-процессов "Задание", созданных +// на основании файлов, при этом наборы файлов записывать в регистр не требуется. +// +// Вызывает процедуру прикладного разработчика +// УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа(), +// которая используется для перезаписи зависимых наборов значений доступа, +// то есть организуется рекурсия. +// +// Параметры: +// Объект - ЛюбаяСсылка +// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - +// В случае вызова с клиента можно передать только ссылку, а нужен объект. +// Если получена ссылка, то по ней будет получен объект. +// +// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// +Процедура ЗаписатьЗависимыеНаборыЗначенийДоступа(Знач Объект, ОбновлениеИБ = Ложь) + + УстановитьПривилегированныйРежим(Истина); + + // Если передача параметра Объект производилась с клиента на сервер, + // то передавалась ссылка, и объект требуется получить. + Объект = ?(Объект = Объект.Ссылка, Объект.ПолучитьОбъект(), Объект); + СсылкаНаОбъект = Объект.Ссылка; + ТипЗначенияОбъект = ТипЗнч(Объект); + + ЭтоВедущийОбъект = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьЗависимыеНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ ЭтоВедущийОбъект Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписке на события %2.'"), + ТипЗначенияОбъект, + "ЗаписатьЗависимыеНаборыЗначенийДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); + +КонецПроцедуры + +// Для процедур ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации и +// ЗаполнитьОбработчикиРазделенныхДанных. + +// Проверяет были ли изменения неразделенных данных для какой-нибудь области данных. +Функция ЕстьИзмененияПараметровОграниченияДоступа() + + УстановитьПривилегированныйРежим(Истина); + + Параметры = Новый Массив; + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ОбъектыМетаданныхПравРолей"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"); + + Для Каждого Параметр Из Параметры Цикл + + ПоследниеИзменения = СтандартныеПодсистемыСервер.ИзмененияПараметраРаботыПрограммы(Параметр); + + Если ПоследниеИзменения = Неопределено + ИЛИ ПоследниеИзменения.Количество() > 0 Тогда + + Возврат Истина; + КонецЕсли; + + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ОбновитьРолиПользователей. + +// Для тестирования. +// +// Параметры: +// ДополнительныеРоли - Соответствие из КлючИЗначение: +// * Ключ - Строка - имя роли, которую можно назначить администратору. +// * Значение - Булево - Истина. +// +Процедура ПриПодготовкеДополнительныхРолейАдминистратора(ДополнительныеРоли) + Возврат; +КонецПроцедуры + +Функция ТекущиеСвойстваПользователей(МассивПользователей) + + Запрос = Новый Запрос; + + Запрос.УстановитьПараметр("ГруппаДоступаАдминистраторы", + УправлениеДоступом.ГруппаДоступаАдминистраторы()); + + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Если МассивПользователей = Неопределено Тогда + Запрос.Текст = + "ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.Пользователи КАК Пользователи + |ГДЕ + | Пользователи.Служебный = ЛОЖЬ + | И Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ВнешниеПользователи.Ссылка, + | ВнешниеПользователи.ИдентификаторПользователяИБ + |ИЗ + | Справочник.ВнешниеПользователи КАК ВнешниеПользователи + |ГДЕ + | ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + + ИначеЕсли ТипЗнч(МассивПользователей) = Тип("Тип") Тогда + Если Метаданные.НайтиПоТипу(МассивПользователей) = Метаданные.Справочники.ВнешниеПользователи Тогда + Запрос.Текст = + "ВЫБРАТЬ + | ВнешниеПользователи.Ссылка КАК Пользователь, + | ВнешниеПользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.ВнешниеПользователи КАК ВнешниеПользователи + |ГДЕ + | ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + Иначе + Запрос.Текст = + "ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.Пользователи КАК Пользователи + |ГДЕ + | Пользователи.Служебный = ЛОЖЬ + | И Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + КонецЕсли; + Иначе + ИсходныеПользователи = Новый ТаблицаЗначений; + ИсходныеПользователи.Колонки.Добавить("Пользователь", Новый ОписаниеТипов( + "СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи")); + + Для каждого Пользователь Из МассивПользователей Цикл + ИсходныеПользователи.Добавить().Пользователь = Пользователь; + КонецЦикла; + + Запрос.УстановитьПараметр("ИсходныеПользователи", ИсходныеПользователи); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ИсходныеПользователи.Пользователь + |ПОМЕСТИТЬ ИсходныеПользователи + |ИЗ + | &ИсходныеПользователи КАК ИсходныеПользователи + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.Пользователи КАК Пользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсходныеПользователи КАК ИсходныеПользователи + | ПО Пользователи.Ссылка = ИсходныеПользователи.Пользователь + | И (Пользователи.Служебный = ЛОЖЬ) + | И (Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор) + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ВнешниеПользователи.Ссылка, + | ВнешниеПользователи.ИдентификаторПользователяИБ + |ИЗ + | Справочник.ВнешниеПользователи КАК ВнешниеПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсходныеПользователи КАК ИсходныеПользователи + | ПО ВнешниеПользователи.Ссылка = ИсходныеПользователи.Пользователь + | И (ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор) + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи + | ПО (ГруппыДоступаПользователи.Ссылка = &ГруппаДоступаАдминистраторы) + | И ГруппыДоступаПользователи.Пользователь = Пользователи.Ссылка + | И (НЕ Пользователи.ПометкаУдаления) + | И (НЕ Пользователи.Недействителен) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ПроверяемыеПользователи.Пользователь, + | ПроверяемыеПользователи.ИдентификаторПользователяИБ + |ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПроверяемыеПользователи.Пользователь КАК Пользователь, + | ГруппыДоступаПользователи.Ссылка.Профиль КАК Профиль + |ПОМЕСТИТЬ ПрофилиПользователей + |ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО ПроверяемыеПользователи.Пользователь = СоставыГруппПользователей.Пользователь + | И (СоставыГруппПользователей.Используется) + | И (&ИсключитьВнешнихПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь) + | И (НЕ ГруппыДоступаПользователи.Ссылка.ПометкаУдаления) + | И (НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПрофилиПользователей.Пользователь, + | Роли.Роль КАК РольСсылка + |ИЗ + | ПрофилиПользователей КАК ПрофилиПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК Роли + | ПО (Роли.Ссылка = ПрофилиПользователей.Профиль) + |ГДЕ + | Роли.Роль <> НЕОПРЕДЕЛЕНО"; + + Запрос.Текст = Запрос.Текст + " + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |" + ТекстЗапроса; + + Если Константы.ИспользоватьВнешнихПользователей.Получить() Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИсключитьВнешнихПользователей", "ИСТИНА"); + Иначе + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИсключитьВнешнихПользователей", + "ТИПЗНАЧЕНИЯ(ПроверяемыеПользователи.Пользователь) = ТИП(Справочник.Пользователи)"); // @query-part-2 + КонецЕсли; + + РезультатыЗапросов = Запрос.ВыполнитьПакет(); + ПоследнийРезультат = РезультатыЗапросов.Количество()-1; + Итог = Новый Структура; + + Итог.Вставить("Администраторы", Новый Соответствие); + + Для каждого Строка Из РезультатыЗапросов[ПоследнийРезультат-3].Выгрузить() Цикл + Итог.Администраторы.Вставить(Строка.Пользователь, Истина); + КонецЦикла; + + Итог.Вставить("ИдентификаторыПользователейИБ", РезультатыЗапросов[ПоследнийРезультат-2].Выгрузить()); + + Если ПользователиСлужебный.СостояниеДоВызоваАвторизоватьТекущегоПользователя(Истина) Тогда + Отбор = Новый Структура("ИдентификаторПользователяИБ", + ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор); + НайденныеСтроки = Итог.ИдентификаторыПользователейИБ.НайтиСтроки(Отбор); + Если ЗначениеЗаполнено(НайденныеСтроки) Тогда + Итог.Администраторы.Вставить(НайденныеСтроки[0].Пользователь, Истина); + КонецЕсли; + КонецЕсли; + + Итог.Вставить("РолиПользователей", РезультатыЗапросов[ПоследнийРезультат].Выгрузить()); + Итог.РолиПользователей.Колонки.Добавить("Роль", Новый ОписаниеТипов("Строка")); + Итог.РолиПользователей.Индексы.Добавить("Пользователь"); + + РолиВсехПользователей = Итог.РолиПользователей.Скопировать(, "РольСсылка"); + РолиВсехПользователей.Свернуть("РольСсылка"); + ИдентификаторыРолей = РолиВсехПользователей.ВыгрузитьКолонку("РольСсылка"); + ПроверитьАктуальностьНовыхРолейПользователейВСеансе(ИдентификаторыРолей); + МетаданныеРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИдентификаторыРолей, Ложь); + + ИдентификаторыРолей = Новый Соответствие; + ИменаРолей = Новый Соответствие; + БезОбъектовМетаданных = Новый Массив; + Для Каждого ОписаниеРоли Из МетаданныеРолей Цикл + Если ТипЗнч(ОписаниеРоли.Значение) = Тип("ОбъектМетаданных") Тогда + ИмяРоли = ОписаниеРоли.Значение.Имя; + ИдентификаторыРолей.Вставить(ИмяРоли, ОписаниеРоли.Ключ); + ИменаРолей.Вставить(ОписаниеРоли.Ключ, ИмяРоли); + Иначе + БезОбъектовМетаданных.Добавить(ОписаниеРоли.Ключ); + КонецЕсли; + КонецЦикла; + + Если ЗначениеЗаполнено(БезОбъектовМетаданных) Тогда + ДобавитьИдентификаторыРолейБезОбъектовМетаданных(БезОбъектовМетаданных, ИдентификаторыРолей); + КонецЕсли; + + ОбязательныеРолиАдминистратора = Новый Соответствие; + ОбязательныеРолиАдминистратора.Вставить("ПолныеПрава"); + Если Не ОбщегоНазначения.РазделениеВключено() Тогда + ОбязательныеРолиАдминистратора.Вставить("АдминистраторСистемы"); + КонецЕсли; + СтандартныеРолиРасширений = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСтандартныхРолейРасширенийСеанса().РолиСеанса; + ДополнительныеРолиАдминистратора = Новый Соответствие(СтандартныеРолиРасширений.ДополнительныеРолиАдминистратора); + ПриПодготовкеДополнительныхРолейАдминистратора(ДополнительныеРолиАдминистратора); + ДополнительныеРолиАдминистратора.Вставить("ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок"); + + ПолныеИменаРолей = Новый Массив; + ДобавитьИменаРолей(ОбязательныеРолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей); + ДобавитьИменаРолей(ДополнительныеРолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей); + Если ЗначениеЗаполнено(ПолныеИменаРолей) Тогда + ДобавитьИдентификаторыРолей(ПолныеИменаРолей, ИдентификаторыРолей, ИменаРолей); + КонецЕсли; + + ЗаполнитьИдентификаторыРолей(ОбязательныеРолиАдминистратора, ИдентификаторыРолей, ИменаРолей); + ЗаполнитьИдентификаторыРолей(ДополнительныеРолиАдминистратора, ИдентификаторыРолей); + + Итог.Вставить("ИдентификаторыРолей", ИдентификаторыРолей); + Итог.Вставить("ИменаРолей", ИменаРолей); + + Итог.Вставить("ОбязательныеРолиАдминистратора", ОбязательныеРолиАдминистратора); + Итог.Вставить("ДополнительныеРолиАдминистратора", ДополнительныеРолиАдминистратора); + + Возврат Итог; + +КонецФункции + +// Для функции ТекущиеСвойстваПользователей. +Процедура ПроверитьАктуальностьНовыхРолейПользователейВСеансе(ИдентификаторыРолей) + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ИдентификаторыРолей"; + ЗначениеСеанса = УправлениеДоступомСлужебныйПовтИсп.ИдентификаторыРолейСеанса(); + + ТекущееЗначение = ПоследниеИдентификаторыРолей(ИмяПараметра); + + Если ТекущееЗначение.ХешСумма = ЗначениеСеанса.ХешСумма Тогда + Возврат; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + ТекущееЗначение = ПоследниеИдентификаторыРолей(ИмяПараметра, УжеИзменен); + Если ТекущееЗначение.ХешСумма <> ЗначениеСеанса.ХешСумма Тогда + ПропуститьОбновление = Ложь; + Если УжеИзменен Тогда + Попытка + ПроверитьАктуальностьМетаданных(); + Исключение + ИдентификаторыСеанса = ЗначениеСеанса.ИдентификаторыРолей; + ТекущиеИдентификаторы = ТекущееЗначение.ИдентификаторыРолей; + Для Каждого ИдентификаторРоли Из ИдентификаторыРолей Цикл + ЕстьВТекущих = ТекущиеИдентификаторы.Получить(ИдентификаторРоли) <> Неопределено; + ЕстьВСеансе = ИдентификаторыСеанса.Получить(ИдентификаторРоли) <> Неопределено; + Если ЕстьВТекущих <> ЕстьВСеансе Тогда + ВызватьИсключение; + КонецЕсли; + КонецЦикла; + ПропуститьОбновление = Истина; + КонецПопытки; + КонецЕсли; + Если Не ПропуститьОбновление Тогда + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ЗначениеСеанса, Истина); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ДобавитьИменаРолей(РолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей) + + Для Каждого КлючИЗначение Из РолиАдминистратора Цикл + Если ИдентификаторыРолей.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда + Продолжить; + КонецЕсли; + МетаданныеРоли = Метаданные.Роли.Найти(КлючИЗначение.Ключ); + Если МетаданныеРоли = Неопределено Тогда + Продолжить; + КонецЕсли; + ПолноеИмяРоли = МетаданныеРоли.ПолноеИмя(); + Если ПолныеИменаРолей.Найти(ПолноеИмяРоли) = Неопределено Тогда + ПолныеИменаРолей.Добавить(ПолноеИмяРоли); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ДобавитьИдентификаторыРолей(ПолныеИменаРолей, ИдентификаторыРолей, ИменаРолей) + + ДополнительныеИдентификаторыРолей = + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИменаРолей, Ложь); + + Для Каждого КлючИЗначение Из ДополнительныеИдентификаторыРолей Цикл + ИдентификаторРоли = КлючИЗначение.Значение; + Если ИдентификаторРоли = Неопределено Тогда + Продолжить; + КонецЕсли; + ИмяРоли = СтрРазделить(КлючИЗначение.Ключ, ".")[1]; + ИдентификаторыРолей.Вставить(ИмяРоли, ИдентификаторРоли); + ИменаРолей.Вставить(ИдентификаторРоли, ИмяРоли); + КонецЦикла; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ДобавитьИдентификаторыРолейБезОбъектовМетаданных(БезОбъектовМетаданных, ИдентификаторыРолей) + + КлючиРолей = Справочники.ИдентификаторыОбъектовМетаданных.КлючиРолей(БезОбъектовМетаданных); + + Для Каждого КлючИЗначение Из КлючиРолей Цикл + Если ЗначениеЗаполнено(КлючИЗначение.Значение) Тогда + ИдентификаторыРолей.Вставить(КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ЗаполнитьИдентификаторыРолей(РолиАдминистратора, ИдентификаторыРолей, ИменаРолей = Неопределено) + + НовыеРолиАдминистратора = Новый Соответствие; + + Для Каждого КлючИЗначение Из РолиАдминистратора Цикл + ИмяРоли = КлючИЗначение.Ключ; + ИдентификаторРоли = ИдентификаторыРолей.Получить(ИмяРоли); + Если ИдентификаторРоли = Неопределено Тогда + Если ИменаРолей <> Неопределено Тогда + ИдентификаторРоли = Справочники.ИдентификаторыОбъектовМетаданных.ПолучитьСсылку(); + ИдентификаторыРолей.Вставить(ИмяРоли, ИдентификаторРоли); + ИменаРолей.Вставить(ИдентификаторРоли, ИмяРоли); + Иначе + Продолжить; + КонецЕсли; + КонецЕсли; + НовыеРолиАдминистратора.Вставить(ИмяРоли, ИдентификаторРоли); + КонецЦикла; + + РолиАдминистратора = НовыеРолиАдминистратора; + +КонецПроцедуры + +// См. УправлениеДоступомСлужебныйПовтИсп.ИдентификаторыРолейСеанса +Функция ПоследниеИдентификаторыРолей(ИмяПараметра, УжеИзменен = Ложь) + + Значение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + Если ТипЗнч(Значение) <> Тип("ФиксированнаяСтруктура") + Или Не Значение.Свойство("ХешСумма") + Или Не Значение.Свойство("ИдентификаторыРолей") + Или ТипЗнч(Значение.ИдентификаторыРолей) <> Тип("ФиксированноеСоответствие") Тогда + + Значение = Новый Структура("ХешСумма, ИдентификаторыРолей", "", Новый Соответствие); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +// Параметры: +// НовыеРолиПользователей - ТаблицаЗначений +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// * РольСсылка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * Роль - Строка - имя роли. +// +Функция НовыеНекорректныеРоли(НовыеРолиПользователей) + + Результат = НовыеРолиПользователей.Скопировать( + Новый Массив, "Пользователь, Роль, РольСсылка"); + + Результат.Колонки.Добавить("ЭтоНенайденнаяРоль", Новый ОписаниеТипов("Булево")); + + Возврат Результат; + +КонецФункции + +// Параметры: +// НекорректныеРоли - см. НовыеНекорректныеРоли +// ОписаниеРоли - СтрокаТаблицыЗначений +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// +Процедура ДобавитьНекорректнуюРоль(НекорректныеРоли, ОписаниеРоли, Пользователь, ЭтоНенайденнаяРоль) + + НоваяСтрока = НекорректныеРоли.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ОписаниеРоли); + НоваяСтрока.Пользователь = Пользователь; + НоваяСтрока.ЭтоНенайденнаяРоль = ЭтоНенайденнаяРоль; + +КонецПроцедуры + +// Параметры: +// НекорректныеРоли - см. НовыеНекорректныеРоли +// +Процедура ЗарегистрироватьНекорректныеРоли(НекорректныеРоли) + + Если Не ЗначениеЗаполнено(НекорректныеРоли) Тогда + Возврат; + КонецЕсли; + + ЗаполнитьИменаНенайденныхРолей(НекорректныеРоли); + + ПрофилиНекорректныхРолей = ПрофилиПользователейСРолями(НекорректныеРоли); + ПрофилиНекорректныхРолей.Индексы.Добавить("Пользователь, РольСсылка"); + Отбор = Новый Структура("Пользователь, РольСсылка"); + + Для Каждого НекорректнаяРоль Из НекорректныеРоли Цикл + ЗаполнитьЗначенияСвойств(Отбор, НекорректнаяРоль); + Строки = ПрофилиНекорректныхРолей.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + Если НекорректнаяРоль.ЭтоНенайденнаяРоль Тогда + ЗарегистрироватьНенайденнуюРоль(НекорректнаяРоль, Строка.Профиль); + Иначе + ЗарегистрироватьНедоступнуюРоль(НекорректнаяРоль, Строка.Профиль); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗарегистрироватьНекорректныеРоли. +Процедура ЗаполнитьИменаНенайденныхРолей(НекорректныеРоли) + + Отбор = Новый Структура("ЭтоНенайденнаяРоль", Истина); + Строки = НекорректныеРоли.НайтиСтроки(Отбор); + Если Не ЗначениеЗаполнено(Строки) Тогда + Возврат; + КонецЕсли; + НенайденныеРоли = НекорректныеРоли.Скопировать(Строки, "РольСсылка"); + Ссылки = НенайденныеРоли.ВыгрузитьКолонку("РольСсылка"); + + Результат = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(Ссылки, + Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.Имя.Имя); + + Для Каждого Строка Из Строки Цикл + Строка.Роль = Результат.Получить(Строка.РольСсылка); + Если Не ЗначениеЗаполнено(Строка.Роль) Тогда + Строка.Роль = Строка(Строка.РольСсылка); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ЗарегистрироватьНедоступнуюРоль(ОписаниеРоли, Профиль) + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Роль недоступна пользователю'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка, + Метаданные.Справочники.ПрофилиГруппДоступа, + Профиль, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При обновлении ролей пользователя ""%1"" + |роль ""%2"" + |%3 + |профиля групп доступа ""%4"" + |%5 + |недоступна пользователю.'"), + Строка(ОписаниеРоли.Пользователь), + ОписаниеРоли.Роль, + ПолучитьНавигационнуюСсылку(ОписаниеРоли.РольСсылка), + Строка(Профиль), + ПолучитьНавигационнуюСсылку(Профиль)), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +Процедура ЗарегистрироватьНенайденнуюРоль(ОписаниеРоли, Профиль) + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Роль не найдена в метаданных'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка, + Метаданные.Справочники.ПрофилиГруппДоступа, + Профиль, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При обновлении ролей пользователя ""%1"" + |роль ""%2"" + |%3 + |профиля групп доступа ""%4"" + |%5 + |не существует в метаданных.'"), + Строка(ОписаниеРоли.Пользователь), + ОписаниеРоли.Роль, + ПолучитьНавигационнуюСсылку(ОписаниеРоли.РольСсылка), + Строка(Профиль), + ПолучитьНавигационнуюСсылку(Профиль)), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +Процедура ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса) + + ВнешняяТранзакцияАктивна = ТранзакцияАктивна(); + ИзмененныеПользователи = Новый Массив; + СообщатьВМенеджерСервиса = ОбщегоНазначения.РазделениеВключено() + И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ПользователиВМоделиСервиса"); + + Для Каждого КлючИЗначение Из ОбновляемыеПользователиИБ Цикл + РолиДляДобавления = КлючИЗначение.Значение.РолиДляДобавления; + РолиДляУдаления = КлючИЗначение.Значение.РолиДляУдаления; + ПользовательИБ = КлючИЗначение.Значение.ПользовательИБ; + ПользовательСсылка = КлючИЗначение.Значение.ПользовательСсылка; + ИзмененныеПользователи.Добавить(ПользовательСсылка); + + Если СообщатьВМенеджерСервиса Тогда + БылиПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава); + БылиПраваНаВход = Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь); + КонецЕсли; + + Для Каждого КлючИЗначение Из РолиДляДобавления Цикл + ПользовательИБ.Роли.Добавить(Метаданные.Роли[КлючИЗначение.Ключ]); + КонецЦикла; + + Для Каждого КлючИЗначение Из РолиДляУдаления Цикл + ПользовательИБ.Роли.Удалить(КлючИЗначение.Значение); + КонецЦикла; + + НачатьТранзакцию(); + Попытка + ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, + ПользовательИБ, БылиПолныеПрава, БылиПраваНаВход, ПарольПользователяСервиса, ВнешняяТранзакцияАктивна); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + + Если ВнешняяТранзакцияАктивна Тогда + РегистрыСведений.СведенияОПользователях.ОбновитьДанныеРегистра(ИзмененныеПользователи); + КонецЕсли; + +КонецПроцедуры + +Процедура ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей() + + Отбор = Новый Структура("ИспользоватьОсновныеРолиДляВсехПользователей", Истина); + Расширения = РасширенияКонфигурации.Получить(Отбор); + РазделениеВключено = ОбщегоНазначения.РазделениеВключено(); + ТекущаяОбластьДействия = ?(ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных(), + ОбластьДействияРасширенияКонфигурации.РазделениеДанных, + ОбластьДействияРасширенияКонфигурации.ИнформационнаяБаза); + + Для Каждого Расширение Из Расширения Цикл + Если Не Расширение.ИспользоватьОсновныеРолиДляВсехПользователей + Или РазделениеВключено + И Расширение.ОбластьДействия <> ТекущаяОбластьДействия Тогда + Продолжить; + КонецЕсли; + Справочники.ВерсииРасширений.ОтключитьПредупрежденияБезопасности(Расширение); + Справочники.ВерсииРасширений.ОтключитьИспользованиеОсновныхРолейДляВсехПользователей(Расширение); + // АПК:280-выкл - №499.3.4 Допустимо пропустить обработку исключения, так как + // это не останавливающая операция и будет выполнена успешно при очередном обновлении ролей. + // Запись расширения не является транзакционной операцией, поэтому не создает ошибок в транзакции. + Попытка + Расширение.Записать(); + Исключение + // Обработка не требуется. + КонецПопытки; + // АПК:280-вкл. + КонецЦикла; + +КонецПроцедуры + +// Параметры: +// НекорректныеРоли - см. НовыеНекорректныеРоли +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// * РольСсылка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * Профиль - СправочникСсылка.ПрофилиГруппДоступа +// +Функция ПрофилиПользователейСРолями(НекорректныеРоли) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("НекорректныеРоли", НекорректныеРоли); + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | НекорректныеРоли.Пользователь КАК Пользователь, + | НекорректныеРоли.РольСсылка КАК РольСсылка + |ПОМЕСТИТЬ НекорректныеРоли + |ИЗ + | &НекорректныеРоли КАК НекорректныеРоли + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь, + | РольСсылка + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | НекорректныеРоли.Пользователь КАК Пользователь, + | НекорректныеРоли.РольСсылка КАК РольСсылка, + | Роли.Ссылка КАК Профиль + |ИЗ + | НекорректныеРоли КАК НекорректныеРоли + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.Пользователь = НекорректныеРоли.Пользователь) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) + | И (НЕ ГруппыДоступаПользователи.Ссылка.ПометкаУдаления) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК Роли + | ПО (Роли.Ссылка = ГруппыДоступаПользователи.Ссылка.Профиль) + | И (НЕ Роли.Ссылка.ПометкаУдаления) + | И (Роли.Роль = НекорректныеРоли.РольСсылка)"; + + Возврат Запрос.Выполнить().Выгрузить(); + +КонецФункции + +// Для процедуры ОбновитьРолиПользователейИБ. +Процедура ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, ПользовательИБ, + БылиПолныеПрава, БылиПраваНаВход, ПарольПользователяСервиса, ВнешняяТранзакцияАктивна) + + ПользователиСлужебный.ЗаписатьПользователяИнформационнойБазы(ПользовательИБ, + ТипЗнч(ПользовательСсылка) = Тип("СправочникСсылка.ВнешниеПользователи"), + ПользовательСсылка, + ?(ВнешняяТранзакцияАктивна, Null, Ложь)); + + Если БылиПолныеПрава = Неопределено Тогда + Возврат; + КонецЕсли; + + ЕстьПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава); + ЕстьПраваНаВход = Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь); + + Если ЕстьПолныеПрава = БылиПолныеПрава + И ЕстьПраваНаВход = БылиПраваНаВход + Или Не Пользователи.ВходВПрограммуРазрешен(ПользовательИБ) Тогда + Возврат; + КонецЕсли; + + МодульПользователиСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ПользователиСлужебныйВМоделиСервиса"); + + Если ЕстьПолныеПрава <> БылиПолныеПрава Тогда + Если ПарольПользователяСервиса = Неопределено Тогда + Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда + МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса"); + СеансЗапущенБезРазделителей = МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей(); + Иначе + СеансЗапущенБезРазделителей = Истина; + КонецЕсли; + Если Не СеансЗапущенБезРазделителей Тогда + УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); + + Если БылиПолныеПрава Тогда + Шаблон = НСтр("ru = 'Для отключения административного доступа пользователю ""%1"" требуется пароль текущего пользователя сервиса ""%2"".'"); + Иначе + Шаблон = НСтр("ru = 'Для установки административного доступа пользователю ""%1"" требуется пароль текущего пользователя сервиса ""%2"".'"); + КонецЕсли; + + Если БылиПолныеПрава И УпрощенныйИнтерфейс Тогда + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке пользователя при отключении ему профиля Администратор.'"); + ИначеЕсли Не БылиПолныеПрава И УпрощенныйИнтерфейс Тогда + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке пользователя при включении ему профиля Администратор.'"); + ИначеЕсли БылиПолныеПрава Тогда + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке группы доступа Администраторы или в карточке пользователя при исключении его из группы доступа Администраторы.'"); + Иначе + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке группы доступа Администраторы или в карточке пользователя при включении его в группу доступа Администраторы.'"); + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, + ПользовательИБ.Имя, ПользователиИнформационнойБазы.ТекущийПользователь().Имя); + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + Уточнение; + + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Иначе + МодульПользователиСлужебныйВМоделиСервиса.ЗаписатьПользователяСервиса(ПользовательСсылка, + Ложь, ПарольПользователяСервиса); + Возврат; + КонецЕсли; + КонецЕсли; + + Если ЕстьПраваНаВход <> БылиПраваНаВход Тогда + МодульПользователиСлужебныйВМоделиСервиса.СообщитьИзмененЗапускПриложения(ПользовательСсылка, + ПользовательИБ); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ТекстЗапросаВыбораИзменений. + +Функция КлючИЗначение(Структура) + + Для Каждого КлючИЗначение Из Структура Цикл + Возврат КлючИЗначение; + КонецЦикла; + + Возврат ""; + +КонецФункции + +// Для процедур ОбновитьНаборЗаписей, ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям. + +Процедура ЗаписатьОбъектИлиНаборЗаписей(Данные, ОбъектИлиНаборЗаписей) + + Если Данные.ОбновлениеИБ Тогда + ОбновлениеИнформационнойБазы.ЗаписатьДанные(ОбъектИлиНаборЗаписей); + Иначе + ОбъектИлиНаборЗаписей.Записать(); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьНаборЗаписей и ОбновитьНаборыЗаписей. + +Функция ГруппаПараметровИзмеренияОбработана(ИмяИзмерения, ЗначенияИзмерения) + + Если ИмяИзмерения = Неопределено Тогда + ЗначенияИзмерения = Неопределено; + + ИначеЕсли ЗначенияИзмерения = Неопределено Тогда + ИмяИзмерения = Неопределено; + + ИначеЕсли ТипЗнч(ЗначенияИзмерения) <> Тип("Массив") + И ТипЗнч(ЗначенияИзмерения) <> Тип("ФиксированныйМассив") Тогда + + ЗначениеИзмерения = ЗначенияИзмерения; + ЗначенияИзмерения = Новый Массив; + ЗначенияИзмерения.Добавить(ЗначениеИзмерения); + + ИначеЕсли ЗначенияИзмерения.Количество() = 0 Тогда + Возврат Ложь; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +Процедура УпорядочитьГруппыПараметровИзмерений(Данные) + + Если Данные.ИмяВторогоИзмерения = Неопределено Тогда + Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; + Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; + Данные.ИмяТретьегоИзмерения = Неопределено; + Данные.ЗначенияТретьегоИзмерения = Неопределено; + КонецЕсли; + + Если Данные.ИмяПервогоИзмерения = Неопределено Тогда + Данные.ИмяПервогоИзмерения = Данные.ИмяВторогоИзмерения; + Данные.ЗначенияПервогоИзмерения = Данные.ЗначенияВторогоИзмерения; + Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; + Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; + Данные.ИмяТретьегоИзмерения = Неопределено; + Данные.ЗначенияТретьегоИзмерения = Неопределено; + КонецЕсли; + + Если Данные.ЗначенияВторогоИзмерения <> Неопределено + И Данные.ЗначенияТретьегоИзмерения <> Неопределено + И Данные.ЗначенияВторогоИзмерения.Количество() + > Данные.ЗначенияТретьегоИзмерения.Количество() Тогда + + ИмяИзмерения = Данные.ИмяВторогоИзмерения; + ЗначенияИзмерения = Данные.ЗначенияВторогоИзмерения; + + Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; + Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; + Данные.ИмяТретьегоИзмерения = ИмяИзмерения; + Данные.ЗначенияТретьегоИзмерения = ЗначенияИзмерения; + КонецЕсли; + + Если Данные.ЗначенияПервогоИзмерения <> Неопределено + И Данные.ЗначенияВторогоИзмерения <> Неопределено + И Данные.ЗначенияПервогоИзмерения.Количество() + > Данные.ЗначенияВторогоИзмерения.Количество() Тогда + + ИмяИзмерения = Данные.ИмяПервогоИзмерения; + ЗначенияИзмерения = Данные.ЗначенияПервогоИзмерения; + + Данные.ИмяПервогоИзмерения = Данные.ИмяВторогоИзмерения; + Данные.ЗначенияПервогоИзмерения = Данные.ЗначенияВторогоИзмерения; + Данные.ИмяВторогоИзмерения = ИмяИзмерения; + Данные.ЗначенияВторогоИзмерения = ЗначенияИзмерения; + КонецЕсли; + +КонецПроцедуры + +Функция ПоляНабораЗаписей(НаборЗаписей) + + ПоляСравнения = ""; + Таблица = НаборЗаписей.Выгрузить(Новый Массив); + Для каждого Колонка Из Таблица.Колонки Цикл + ПоляСравнения = ПоляСравнения + "," + Колонка.Имя; + КонецЦикла; + ПоляСравнения = Сред(ПоляСравнения, 2); + + Возврат ПоляСравнения; + +КонецФункции + +Процедура ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям(Знач Данные, Знач Отбор, Знач СписокПолей, + Знач ИмяИзмерения, Знач ЗначенияИзмерения, ЕстьИзменения) + + ЗаблокироватьОбластьНабораЗаписей(Данные.НаборЗаписей, Данные.ПолноеИмяРегистра); + + Данные.НаборЗаписей.Прочитать(); + НовыеЗаписиНабора = Данные.НаборЗаписей.Выгрузить(); + НовыеЗаписиНабора.Индексы.Добавить(СписокПолей); + + Для каждого Значение Из ЗначенияИзмерения Цикл + Отбор[ИмяИзмерения] = Значение; + Для каждого НайденнаяЗапись Из НовыеЗаписиНабора.НайтиСтроки(Отбор) Цикл + НовыеЗаписиНабора.Удалить(НайденнаяЗапись); + КонецЦикла; + Для каждого НайденнаяЗапись Из Данные.НовыеЗаписи.НайтиСтроки(Отбор) Цикл + ЗаполнитьЗначенияСвойств(НовыеЗаписиНабора.Добавить(), НайденнаяЗапись); + КонецЦикла; + КонецЦикла; + + ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); + ТекущиеДанные.Вставить("НаборЗаписейПрочитан", Истина); + + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + +КонецПроцедуры + +Процедура ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Знач Данные, Знач Отбор, ЕстьИзменения) + + // Получение количества записей для чтения. + + Если Отбор.Количество() = 0 Тогда + ТекущиеНовыеЗаписи = Данные.НовыеЗаписи.Скопировать(); // ТаблицаЗначений + КоличествоДляЧтения = Данные.КоличествоДляЧтения; + Иначе + ТекущиеНовыеЗаписи = Данные.НовыеЗаписи.Скопировать(Отбор); // ТаблицаЗначений + + КоличествоПоЗначениям = Данные.КоличествоПоЗначениям; // ТаблицаЗначений + ИмяПоля = КоличествоПоЗначениям.Колонки[0].Имя; + СтрокаКоличества = Данные.КоличествоПоЗначениям.Найти(Отбор[ИмяПоля], ИмяПоля); + КоличествоДляЧтения = ?(СтрокаКоличества = Неопределено, 0, СтрокаКоличества.Количество); + КонецЕсли; + + ОтборНовойЗаписи = Новый Структура("ВидИзмененияСтроки, " + Данные.ПоляСравнения, 1); + ТекущиеНовыеЗаписи.Индексы.Добавить("ВидИзмененияСтроки, " + Данные.ПоляСравнения); + + КлючиЗаписей = ТекущиеНовыеЗаписи.Скопировать(, "ВидИзмененияСтроки, " + Данные.ПоляСравнения); + КлючиЗаписей.Свернуть("ВидИзмененияСтроки, " + Данные.ПоляСравнения); + КлючиЗаписей.Свернуть(Данные.ПоляСравнения, "ВидИзмененияСтроки"); + + ОтборПоКлючуЗаписи = Новый Структура(Данные.ПоляСравнения); + + Если ОбновлятьНаборЗаписейЦеликом(КоличествоДляЧтения, КлючиЗаписей) Тогда + + ЗаблокироватьОбластьНабораЗаписей(Данные.НаборЗаписей, Данные.ПолноеИмяРегистра); + Данные.НаборЗаписей.Прочитать(); + НовыеЗаписиНабора = Данные.НаборЗаписей.Выгрузить(); // ТаблицаЗначений + НовыеЗаписиНабора.Индексы.Добавить(Данные.ПоляСравнения); + + Для каждого Строка Из КлючиЗаписей Цикл + ЗаполнитьЗначенияСвойств(ОтборПоКлючуЗаписи, Строка); + НайденныеСтроки = НовыеЗаписиНабора.НайтиСтроки(ОтборПоКлючуЗаписи); + Если Строка.ВидИзмененияСтроки = -1 Тогда + Если НайденныеСтроки.Количество() > 0 Тогда + // Удаление старой строки. + НовыеЗаписиНабора.Удалить(НайденныеСтроки[0]); + КонецЕсли; + Иначе + // Добавление новой или обновление старой строки. + Если НайденныеСтроки.Количество() = 0 Тогда + ЗаполняемаяСтрока = НовыеЗаписиНабора.Добавить(); + Иначе + ЗаполняемаяСтрока = НайденныеСтроки[0]; + КонецЕсли; + ЗаполнитьЗначенияСвойств(ОтборНовойЗаписи, ОтборПоКлючуЗаписи); + НайденныеЗаписи = ТекущиеНовыеЗаписи.НайтиСтроки(ОтборНовойЗаписи); + Если НайденныеЗаписи.Количество() = 1 Тогда + НоваяЗапись = НайденныеЗаписи[0]; + Иначе // Ошибка в параметре НовыеЗаписи. + ИсключениеПриОшибкеПоискаЗаписи(Данные); + КонецЕсли; + ЗаполнитьЗначенияСвойств(ЗаполняемаяСтрока, НоваяЗапись); + КонецЕсли; + КонецЦикла; + // Изменение набора записей, чтобы он отличался от новых записей набора. + Если Данные.НаборЗаписей.Количество() = НовыеЗаписиНабора.Количество() Тогда + Данные.НаборЗаписей.Добавить(); + КонецЕсли; + + ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); + ТекущиеДанные.Вставить("НаборЗаписейПрочитан", Истина); + + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + Иначе + // Построчное обновление. + УстановитьДополнительныеСвойства(Данные.НаборДляОднойЗаписи, Данные.ДополнительныеСвойства); + Для каждого Строка Из КлючиЗаписей Цикл + Данные.НаборДляОднойЗаписи.Очистить(); + ЗаполнитьЗначенияСвойств(ОтборПоКлючуЗаписи, Строка); + Для каждого КлючИЗначение Из ОтборПоКлючуЗаписи Цикл + УстановитьОтбор( + Данные.НаборДляОднойЗаписи.Отбор[КлючИЗначение.Ключ], КлючИЗначение.Значение); + КонецЦикла; + ЗаблокироватьОбластьНабораЗаписей(Данные.НаборДляОднойЗаписи, Данные.ПолноеИмяРегистра); + Если Строка.ВидИзмененияСтроки > -1 Тогда + // Добавление новой или обновление существующей строки. + ЗаполнитьЗначенияСвойств(ОтборНовойЗаписи, ОтборПоКлючуЗаписи); + НайденныеЗаписи = ТекущиеНовыеЗаписи.НайтиСтроки(ОтборНовойЗаписи); + Если НайденныеЗаписи.Количество() = 1 Тогда + НоваяЗапись = НайденныеЗаписи[0]; + Иначе // Ошибка в параметре НовыеЗаписи. + ИсключениеПриОшибкеПоискаЗаписи(Данные); + КонецЕсли; + ЗаполнитьЗначенияСвойств(Данные.НаборДляОднойЗаписи.Добавить(), НоваяЗапись); + КонецЕсли; + ЕстьИзменения = Истина; + Если Данные.ТолькоПроверка Тогда + Возврат; + КонецЕсли; + ЗаписатьОбъектИлиНаборЗаписей(Данные, Данные.НаборДляОднойЗаписи); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям. +Функция ОбновлятьНаборЗаписейЦеликом(КоличествоДляЧтения, КлючиЗаписей) + + Если КоличествоДляЧтения > 10000 Тогда + Возврат Ложь; // Слишком большой набор записей. + КонецЕсли; + + КоличествоУдаляемых = КлючиЗаписей.НайтиСтроки( + Новый Структура("ВидИзмененияСтроки", -1)).Количество(); + + КоличествоДобавляемых = КлючиЗаписей.НайтиСтроки( + Новый Структура("ВидИзмененияСтроки", 1)).Количество(); + + КоличествоДляЗаписи = КоличествоДляЧтения - КоличествоУдаляемых + + КоличествоДобавляемых; + + Если КоличествоДляЗаписи > 10000 Тогда + Возврат Ложь; // Слишком большой набор записей. + КонецЕсли; + + КоличествоИзменяемых = КлючиЗаписей.Количество() + - (КоличествоУдаляемых + КоличествоДобавляемых); + + КоличествоНеизменных = КоличествоДляЧтения + - (КоличествоУдаляемых + КоличествоИзменяемых); + + ЗатратыНаПерезаписьЦеликом = + // Операции: |Чтение|Удаление|Вставка| + КоличествоУдаляемых * ( 0.05 + 0.1 ) + + КоличествоИзменяемых * ( 0.05 + 0.1 + 1 ) + + КоличествоДобавляемых * ( 1 ) + + КоличествоНеизменных * ( 0.05 + 0.1 + 1 ); + + ЗатратыНаПерезаписьПоОднойЗаписи = + // Операции: |Удаление|Вставка| + КоличествоУдаляемых * ( 0.5 ) + + КоличествоИзменяемых * ( 0.5 + 1.2 ) + + КоличествоДобавляемых * ( 0.5 + 1.2 ); + + Возврат ЗатратыНаПерезаписьЦеликом < ЗатратыНаПерезаписьПоОднойЗаписи; + +КонецФункции + +Процедура ИсключениеПриОшибкеПоискаЗаписи(Параметры) + + Для каждого СтрокаИзменений Из Параметры.НовыеЗаписи Цикл + Если СтрокаИзменений.ВидИзмененияСтроки <> 1 + И СтрокаИзменений.ВидИзмененияСтроки <> -1 Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в процедуре %1 + |общего модуля %2. + | + |Неверное значение параметра %3 - колонка + |%4 содержит недопустимое значение ""%5"". + | + |Допустимо только 2 значения: ""1"" и ""-1"".'"), + "ОбновитьНаборыЗаписей", + "УправлениеДоступомСлужебный", + "НовыеЗаписи", + "ВидИзмененияСтроки", + Строка(СтрокаИзменений.ВидИзмененияСтроки)); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + КонецЦикла; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в процедуре %1 + |общего модуля %2. + | + |Не удалось найти требуемую в строку + |в значении параметра %3.'"), + "ОбновитьНаборыЗаписей", + "УправлениеДоступомСлужебный", + "НовыеЗаписи"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + +КонецПроцедуры + +Процедура ЗаблокироватьОбластьНабораЗаписей(НаборЗаписей, ПолноеИмяРегистра = Неопределено) + + Если НЕ ТранзакцияАктивна() Тогда + Возврат; + КонецЕсли; + + Если ПолноеИмяРегистра = Неопределено Тогда + ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(НаборЗаписей)).ПолноеИмя(); + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + Для каждого ЭлементОтбора Из НаборЗаписей.Отбор Цикл + Если ЭлементОтбора.Использование Тогда + ЭлементБлокировки.УстановитьЗначение(ЭлементОтбора.ПутьКДанным, ЭлементОтбора.Значение); + КонецЕсли; + КонецЦикла; + Блокировка.Заблокировать(); + +КонецПроцедуры + +Процедура УстановитьОтбор(ЭлементОтбора, ЗначениеОтбора) + + Попытка + ЭлементОтбора.Значение = ЗначениеОтбора; + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ВсеТипы = Новый Массив; + Для Каждого Тип Из ЭлементОтбора.ТипЗначения.Типы() Цикл + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + ВсеТипы.Добавить(Строка(Тип) + ?(ОбъектМетаданных = Неопределено, + "", " (" + ОбъектМетаданных.ПолноеИмя() + ")")); + КонецЦикла; + СвойстваОтбора = Новый Массив; + СвойстваОтбора.Добавить("Имя" + " = " + ЭлементОтбора.Имя); + СвойстваОтбора.Добавить("ПутьКДанным" + " = " + ЭлементОтбора.ПутьКДанным); + СвойстваОтбора.Добавить("ТипЗначения" + " = " + Символы.ПС + Символы.Таб + + СтрСоединить(ВсеТипы, Символы.ПС + Символы.Таб)); + МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеОтбора)); + Попытка + Если МетаданныеЗначения <> Неопределено Тогда + НавигационнаяСсылка = ПолучитьНавигационнуюСсылку(ЗначениеОтбора); + Иначе + НавигационнаяСсылка = ""; + КонецЕсли; + Исключение + НавигационнаяСсылка = ""; + КонецПопытки; + Попытка + ВнутренняяСтрока = ЗначениеВСтрокуВнутр(ЗначениеОтбора); + Исключение + ВнутренняяСтрока = ""; + КонецПопытки; + ДляАдминистратора = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось установить значение ""%1"" тип ""%2"" + | Навигационная ссылка: %3 + | Внутренняя строка: %4 + |в элемент отбора со свойствами: + |%5'"), + Строка(ЗначениеОтбора), + Строка(ТипЗнч(ЗначениеОтбора)) + ?(МетаданныеЗначения = Неопределено, + "", " (" + МетаданныеЗначения.ПолноеИмя() + ")"), + НавигационнаяСсылка, + ВнутренняяСтрока, + СтрСоединить(СвойстваОтбора, Символы.ПС)); + Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке); + Попытка + ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,, ДляАдминистратора, ИнформацияОбОшибке); + Исключение + ЗаписьЖурналаРегистрации(НСтр("ru = 'Ошибка выполнения'", ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка,,, + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); + ВызватьИсключение; + КонецПопытки; + КонецПопытки; + + ЭлементОтбора.Использование = Истина; + +КонецПроцедуры + +Функция ЗаписьНесколькимиНаборами(Данные, Отбор, ИмяПоля, ЗначенияПоля) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ЗначенияПоля", ЗначенияПоля); + Запрос.Текст = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &УсловиеОтбора + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.ИмяПоля В(&ЗначенияПоля) + | И &УсловиеОтбора + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ТекущаяТаблица.ИмяПоля КАК ИмяПоля, + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.ИмяПоля В(&ЗначенияПоля) + | И &УсловиеОтбора + | + |СГРУППИРОВАТЬ ПО + | ТекущаяТаблица.ИмяПоля"; + + УсловиеОтбора = "ИСТИНА"; + Если Данные.ФиксированныйОтбор <> Неопределено Тогда + Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл + УсловиеОтбора = УсловиеОтбора + " + | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + ОтборДобавляемых = Новый Структура; + ОтборДобавляемых.Вставить("ВидИзмененияСтроки", 1); + ОтборУдаляемых = Новый Структура; + ОтборУдаляемых.Вставить("ВидИзмененияСтроки", -1); + + Для каждого КлючИЗначение Из Отбор Цикл + УсловиеОтбора = УсловиеОтбора + " + | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + ОтборДобавляемых.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + ОтборУдаляемых.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "ИмяПоля", ИмяПоля); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Данные.ПолноеИмяРегистра); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", УсловиеОтбора); + + РезультатыЗапросов = Запрос.ВыполнитьПакет(); + + // Количество всех без отбора. + КоличествоВсех = РезультатыЗапросов[0].Выгрузить()[0].Количество; + Данные.Вставить("КоличествоДляЧтения", КоличествоВсех); + + // Количество обновляемых с отбором. + КоличествоОбновляемых = РезультатыЗапросов[1].Выгрузить()[0].Количество; + + КоличествоДобавляемых = Данные.НовыеЗаписи.НайтиСтроки(ОтборДобавляемых).Количество(); + Если КоличествоДобавляемых > КоличествоОбновляемых Тогда + КоличествоОбновляемых = КоличествоДобавляемых; + КонецЕсли; + + КоличествоУдаляемых = Данные.НовыеЗаписи.НайтиСтроки(ОтборУдаляемых).Количество(); + Если КоличествоУдаляемых > КоличествоОбновляемых Тогда + КоличествоОбновляемых = КоличествоУдаляемых; + КонецЕсли; + + // Количество для чтения по значениям отбора. + КоличествоПоЗначениям = РезультатыЗапросов[2].Выгрузить(); + КоличествоПоЗначениям.Индексы.Добавить(ИмяПоля); + Данные.Вставить("КоличествоПоЗначениям", КоличествоПоЗначениям); + + Возврат КоличествоВсех * 0.7 > КоличествоОбновляемых; + +КонецФункции + +Процедура ПрочитатьКоличествоДляЧтения(Данные) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &УсловиеОтбора"; + + УсловиеОтбора = "ИСТИНА"; + Если Данные.ФиксированныйОтбор <> Неопределено Тогда + Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл + УсловиеОтбора = УсловиеОтбора + " + | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Данные.ПолноеИмяРегистра); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", УсловиеОтбора); + + Данные.Вставить("КоличествоДляЧтения", Запрос.Выполнить().Выгрузить()[0].Количество); + +КонецПроцедуры + +Процедура УстановитьДополнительныеСвойства(НаборЗаписей, ДополнительныеСвойства) + + Если ТипЗнч(ДополнительныеСвойства) = Тип("Структура") Тогда + Для каждого КлючИЗначение Из ДополнительныеСвойства Цикл + НаборЗаписей.ДополнительныеСвойства.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьРегистрСведений. + +Функция ЗначенияКолонкиТаблицы(Таблица, ИмяКолонки) + + НоваяТаблица = Таблица.Скопировать(, ИмяКолонки); + + НоваяТаблица.Свернуть(ИмяКолонки); + + Возврат НоваяТаблица.ВыгрузитьКолонку(ИмяКолонки); + +КонецФункции + +// Обслуживание таблиц ВидыДоступа и ЗначенияДоступа в формах редактирования. + +Процедура ДобавитьРеквизитыВспомогательныхДанныхВФорму(Форма, ИмяРеквизитаХранилищаТаблиц) + + ДобавляемыеРеквизиты = Новый Массив; + ОписаниеТиповЗначенийДоступа = Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип; + + ПутьКОбъекту = ?(ЗначениеЗаполнено(ИмяРеквизитаХранилищаТаблиц), ИмяРеквизитаХранилищаТаблиц + ".", ""); + + // Добавление реквизитов в таблицу ВидыДоступа. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Используется", Новый ОписаниеТипов("Булево"), ПутьКОбъекту + "ВидыДоступа")); + + // Добавление отдельных реквизитов. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТекущийВидДоступа", ОписаниеТиповЗначенийДоступа)); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТекущиеТипыВыбираемыхЗначений", Новый ОписаниеТипов("СписокЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТекущийТипВыбираемыхЗначений", ОписаниеТиповЗначенийДоступа)); + + Если НЕ РеквизитФормыСуществует(Форма, "ИспользоватьВнешнихПользователей") Тогда + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИспользоватьВнешнихПользователей", Новый ОписаниеТипов("Булево"))); + КонецЕсли; + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИмяРеквизитаХранилищаТаблиц", Новый ОписаниеТипов("Строка"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ЭтоПрофильГруппДоступа", Новый ОписаниеТипов("Булево"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВидДоступаПользователи", ОписаниеТиповЗначенийДоступа)); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВидДоступаВнешниеПользователи", ОписаниеТиповЗначенийДоступа)); + + // Добавление таблицы ВсеВидыДоступа. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВсеВидыДоступа", Новый ОписаниеТипов("ТаблицаЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Ссылка", ОписаниеТиповЗначенийДоступа, "ВсеВидыДоступа")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Представление", Новый ОписаниеТипов("Строка"), "ВсеВидыДоступа")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Используется", Новый ОписаниеТипов("Булево"), "ВсеВидыДоступа")); + + // Добавление таблицы ПредставленияВсеРазрешены. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ПредставленияВсеРазрешены", Новый ОписаниеТипов("ТаблицаЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Имя", Новый ОписаниеТипов("Строка"), "ПредставленияВсеРазрешены")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Представление", Новый ОписаниеТипов("Строка"), "ПредставленияВсеРазрешены")); + + // Добавление таблицы ВсеТипыВыбираемыхЗначений. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВсеТипыВыбираемыхЗначений", Новый ОписаниеТипов("ТаблицаЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВидДоступа", ОписаниеТиповЗначенийДоступа, "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТипЗначений", ОписаниеТиповЗначенийДоступа, "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ПредставлениеТипа", Новый ОписаниеТипов("Строка"), "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИмяТаблицы", Новый ОписаниеТипов("Строка"), "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИерархияЭлементов", Новый ОписаниеТипов("Булево"), "ВсеТипыВыбираемыхЗначений")); + + Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты); + +КонецПроцедуры + +Процедура ЗаполнитьТаблицуВсеВидыДоступаВФорме(Форма) + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ВсеВидыДоступа = Форма.ВсеВидыДоступа; + ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); + + Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл + Строка = ВсеВидыДоступа.Добавить(); + Строка.Ссылка = СвойстваВидаДоступа.Ссылка; + Строка.Используется = ИспользуемыеВидыДоступа.Получить(Строка.Ссылка) <> Неопределено; + // Обеспечение уникальности представлений. + Представление = ПредставлениеВидаДоступа(СвойстваВидаДоступа); + Отбор = Новый Структура("Представление", Представление); + Пока ВсеВидыДоступа.НайтиСтроки(Отбор).Количество() > 0 Цикл + Отбор.Представление = Отбор.Представление + " "; + КонецЦикла; + Строка.Представление = Отбор.Представление; + КонецЦикла; + +КонецПроцедуры + +Процедура ЗаполнитьТаблицуПредставленияВсеРазрешеныВФорме(Форма, ЭтоПрофиль) + + ПредставленияВсеРазрешены = Форма.ПредставленияВсеРазрешены; + + Если ЭтоПрофиль Тогда + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВначалеВсеЗапрещены"; + Строка.Представление = НСтр("ru = 'Все запрещены, исключения назначаются в группах доступа'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВначалеВсеРазрешены"; + Строка.Представление = НСтр("ru = 'Все разрешены, исключения назначаются в группах доступа'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеЗапрещены"; + Строка.Представление = НСтр("ru = 'Все запрещены, исключения назначаются в профиле'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеРазрешены"; + Строка.Представление = НСтр("ru = 'Все разрешены, исключения назначаются в профиле'"); + Иначе + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеЗапрещены"; + Строка.Представление = НСтр("ru = 'Все запрещены'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеРазрешены"; + Строка.Представление = НСтр("ru = 'Все разрешены'"); + КонецЕсли; + + СписокВыбора = Форма.Элементы.ВидыДоступаВсеРазрешеныПредставление.СписокВыбора; // СписокЗначений + + Для каждого Строка Из ПредставленияВсеРазрешены Цикл + СписокВыбора.Добавить(Строка.Представление); + КонецЦикла; + +КонецПроцедуры + +Процедура ОформитьТаблицуВидыДоступаВФорме(Форма) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма); + + // Оформление отображения неиспользуемых видов доступа. + ЭлементУсловногоОформления = Форма.УсловноеОформление.Элементы.Добавить(); + + ЭлементЦветаОформления = ЭлементУсловногоОформления.Оформление.Элементы.Найти("TextColor"); + ЭлементЦветаОформления.Значение = WebЦвета.Серый; + ЭлементЦветаОформления.Использование = Истина; + + ГруппаЭлементовОтбораДанных = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных")); + ГруппаЭлементовОтбораДанных.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ; + ГруппаЭлементовОтбораДанных.Использование = Истина; + + ЭлементОтбораДанных = ГруппаЭлементовОтбораДанных.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); + ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ВидыДоступа.ВидДоступа"); + ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.НеРавно; + ЭлементОтбораДанных.ПравоеЗначение = Неопределено; + ЭлементОтбораДанных.Использование = Истина; + + ЭлементОтбораДанных = ГруппаЭлементовОтбораДанных.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); + ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ВидыДоступа.Используется"); + ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; + ЭлементОтбораДанных.ПравоеЗначение = Ложь; + ЭлементОтбораДанных.Использование = Истина; + + ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить(); + ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("ВидыДоступа"); + ЭлементОформляемогоПоля.Использование = Истина; + +КонецПроцедуры + +Процедура ОформитьТаблицуЗначенияДоступаВФорме(Форма) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма); + ПустыеСсылкиЗначенийДоступа = ПустыеСсылкиЗначенийДоступа(); + + // Оформление отображения пустых ссылок значений доступа. + Для Каждого Строка Из ПустыеСсылкиЗначенийДоступа Цикл + ЭлементУсловногоОформления = Форма.УсловноеОформление.Элементы.Добавить(); + + ЭлементОформленияТекст = ЭлементУсловногоОформления.Оформление.Элементы.Найти("Text"); + ЭлементОформленияТекст.Значение = Строка.Представление; + ЭлементОформленияТекст.Использование = Истина; + + ЭлементОтбораДанных = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); + ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ЗначенияДоступа.ЗначениеДоступа"); + ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; + ЭлементОтбораДанных.ПравоеЗначение = Строка.ПустаяСсылка; + ЭлементОтбораДанных.Использование = Истина; + + ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить(); + ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("ЗначенияДоступаЗначениеДоступа"); + ЭлементОформляемогоПоля.Использование = Истина; + КонецЦикла; + +КонецПроцедуры + +Процедура УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект = Неопределено) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ПоТипамГруппИЗначений = СвойстваВидовДоступа.ПоТипамГруппИЗначений; + + Отбор = УправлениеДоступомСлужебныйКлиентСервер.ОтборВТаблицахФормыРедактированияРазрешенныхЗначений( + Форма, ""); + + Индекс = Параметры.ЗначенияДоступа.Количество()-1; + Пока Индекс >= 0 Цикл + ЗначениеДоступа = Параметры.ЗначенияДоступа[Индекс].ЗначениеДоступа; + + СвойстваВидаДоступа = ПоТипамГруппИЗначений.Получить(ТипЗнч(ЗначениеДоступа)); // См. СвойстваВидаДоступа + Если СвойстваВидаДоступа <> Неопределено Тогда + ЗаполнитьЗначенияСвойств(Отбор, Параметры.ЗначенияДоступа[Индекс]); + Отбор.Вставить("ВидДоступа", СвойстваВидаДоступа.Ссылка); + КонецЕсли; + + Если СвойстваВидаДоступа = Неопределено + ИЛИ Параметры.ЗначенияДоступа[Индекс].ВидДоступа <> Отбор.ВидДоступа + ИЛИ Параметры.ВидыДоступа.НайтиСтроки(Отбор).Количество() = 0 Тогда + + Параметры.ЗначенияДоступа.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + +КонецПроцедуры + +Процедура УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект = Неопределено) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект); + + Индекс = Параметры.ВидыДоступа.Количество()-1; + Пока Индекс >= 0 Цикл + ВидДоступа = Параметры.ВидыДоступа[Индекс].ВидДоступа; + Если СвойстваВидаДоступа(ВидДоступа) = Неопределено Тогда + Параметры.ВидыДоступа.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + + УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект); + +КонецПроцедуры + +Функция ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект = Неопределено) + + Возврат УправлениеДоступомСлужебныйКлиентСервер.ПараметрыФормыРедактированияРазрешенныхЗначений( + Форма, ТекущийОбъект); + +КонецФункции + +Функция РеквизитФормыСуществует(Форма, ИмяРеквизита) + + Структура = Новый Структура(ИмяРеквизита, Null); + + ЗаполнитьЗначенияСвойств(Структура, Форма); + + Возврат Структура[ИмяРеквизита] <> Null; + +КонецФункции + +Функция ПустыеСсылкиЗначенийДоступа() Экспорт + + Таблица = Новый ТаблицаЗначений; + Таблица.Колонки.Добавить("ПустаяСсылка", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + Таблица.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка", + ,,, Новый КвалификаторыСтроки(150, ДопустимаяДлина.Переменная))); + + Для Каждого Тип Из Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип.Типы() Цикл + Типы = Новый Массив; + Типы.Добавить(Тип); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + НоваяСтрока = Таблица.Добавить(); + НоваяСтрока.ПустаяСсылка = ОписаниеТипа.ПривестиЗначение(Неопределено); + НоваяСтрока.Представление = "<" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Пустая ссылка %1'"), Строка(Тип)) + ">"; + КонецЦикла; + + Возврат Таблица; + +КонецФункции + +// Для процедуры УстановкаПараметровСеанса. + +Функция ВсеКомбинацииВидовДоступа(НеупорядоченныйМассивИмен) + + // Ограничение на максимальную длину комбинации, чтобы не допустить + // перегрузку параметров сеанса и препроцессора шаблонов ОДД. + МаксимальнаяДлинаКомбинации = 4; + + Список = Новый СписокЗначений; + Если ТипЗнч(НеупорядоченныйМассивИмен) = Тип("ФиксированныйМассив") Тогда + Список.ЗагрузитьЗначения(Новый Массив(НеупорядоченныйМассивИмен)); + Иначе + Список.ЗагрузитьЗначения(НеупорядоченныйМассивИмен); + КонецЕсли; + Список.СортироватьПоЗначению(); + МассивИмен = Список.ВыгрузитьЗначения(); + + ИтогСтроки = Новый Массив; + ИтогСтрока = Новый Массив; + + // Полный список поддерживается всегда. + Для каждого Имя Из МассивИмен Цикл + ИтогСтрока.Добавить(Имя); + КонецЦикла; + + ИтогСтроки.Добавить(ИтогСтрока); + + Если МассивИмен.Количество() < 3 Тогда + Возврат ГруппыСтрокВСтроку(ИтогСтроки); + КонецЕсли; + + ПервоеИмя = МассивИмен[0]; + МассивИмен.Удалить(0); + + ПоследнееИмя = МассивИмен[МассивИмен.Количество()-1]; + МассивИмен.Удалить(МассивИмен.Количество()-1); + + КоличествоИменВКомбинации = МассивИмен.Количество(); + + Если КоличествоИменВКомбинации > 1 Тогда + + Если (КоличествоИменВКомбинации-1) <= МаксимальнаяДлинаКомбинации Тогда + ДлинаКомбинации = КоличествоИменВКомбинации-1; + Иначе + ДлинаКомбинации = МаксимальнаяДлинаКомбинации; + КонецЕсли; + + ПозицииИменВКомбинации = Новый Массив; + Для Счетчик = 1 По ДлинаКомбинации Цикл + ПозицииИменВКомбинации.Добавить(Счетчик); + КонецЦикла; + + Пока ДлинаКомбинации > 0 Цикл + Пока Истина Цикл + // Добавление комбинации из текущих позиций. + ИтогСтрока = Новый Массив; + ИтогСтрока.Добавить(ПервоеИмя); + Для Индекс = 0 По ДлинаКомбинации-1 Цикл + ИтогСтрока.Добавить(МассивИмен[ПозицииИменВКомбинации[Индекс]-1]); + КонецЦикла; + ИтогСтрока.Добавить(ПоследнееИмя); + ИтогСтроки.Добавить(ИтогСтрока); + // Продвижение позиции в комбинации. + Индекс = ДлинаКомбинации-1; + Пока Индекс >= 0 Цикл + Если ПозицииИменВКомбинации[Индекс] < КоличествоИменВКомбинации - (ДлинаКомбинации - (Индекс+1)) Тогда + ПозицииИменВКомбинации[Индекс] = ПозицииИменВКомбинации[Индекс] + 1; + // Заполнение старших позиций начальными значениями. + Для ИндексСтаршейПозиции = Индекс+1 По ДлинаКомбинации-1 Цикл + ПозицииИменВКомбинации[ИндексСтаршейПозиции] = + ПозицииИменВКомбинации[Индекс] + ИндексСтаршейПозиции - Индекс; + КонецЦикла; + Прервать; + Иначе + Индекс = Индекс - 1; + КонецЕсли; + КонецЦикла; + Если Индекс < 0 Тогда + Прервать; + КонецЕсли; + КонецЦикла; + ДлинаКомбинации = ДлинаКомбинации - 1; + Для Индекс = 0 По ДлинаКомбинации - 1 Цикл + ПозицииИменВКомбинации[Индекс] = Индекс + 1; + КонецЦикла; + КонецЦикла; + КонецЕсли; + + ИтогСтрока = Новый Массив; + ИтогСтрока.Добавить(ПервоеИмя); + ИтогСтрока.Добавить(ПоследнееИмя); + ИтогСтроки.Добавить(ИтогСтрока); + + Возврат ГруппыСтрокВСтроку(ИтогСтроки); + +КонецФункции + +Функция ГруппыСтрокВСтроку(ГруппыСтрок) + + ИтогСтроки = Новый Массив; + + Для Каждого ИтогСтрока Из ГруппыСтрок Цикл + ИтогСтроки.Добавить(СтрСоединить(ИтогСтрока, ",")); + КонецЦикла; + + Строки = СтрСоединить( + ИтогСтроки, + ", + |,"); + + Шаблон = + "%2%1%2 + |"; + + Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, Строки, ","); + +КонецФункции + +// Для процедур ОбновитьНаборыЗначенийДоступа, ПриИзмененииНаборовЗначенийДоступа. + +// Проверяет, что наборы в табличной части отличаются от новых наборов. +Функция НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаОбъект, НовыеНаборы) + + СтарыеНаборы = ОбщегоНазначения.ЗначениеРеквизитаОбъекта( + СсылкаНаОбъект, "НаборыЗначенийДоступа").Выгрузить(); + + Если СтарыеНаборы.Количество() <> НовыеНаборы.Количество() Тогда + Возврат Истина; + КонецЕсли; + + СтарыеНаборы.Колонки.Добавить("ВидДоступа", Новый ОписаниеТипов("Строка")); + УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( + СтарыеНаборы, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); + + ПоляПоиска = "НомерНабора, ЗначениеДоступа, Уточнение, Чтение, Изменение"; + + НовыеНаборы.Индексы.Добавить(ПоляПоиска); + Отбор = Новый Структура(ПоляПоиска); + + Для каждого Строка Из СтарыеНаборы Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Если НовыеНаборы.НайтиСтроки(Отбор).Количество() <> 1 Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции РазрешенныеЗначенияДляДинамическогоСписка. +Процедура ДобавитьЗапросВПакет(ТекстПакета, ТекстЗапроса) + + Разделитель = + " + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |"; + + ТекстПакета = ТекстПакета + Разделитель + ТекстЗапроса; + +КонецПроцедуры + +// Для функции РазрешенныеЗначенияДляДинамическогоСписка. +Процедура ОбъединитьЗапросСЗапросом(ТекстЗапроса, ДобавляемыйТекстЗапроса) + + Объединитель = + " + | + |ОБЪЕДИНИТЬ ВСЕ + | + |"; // @query-part-1 + + ТекстЗапроса = ТекстЗапроса + Объединитель + ДобавляемыйТекстЗапроса; + +КонецПроцедуры + +// Обновление свойств видов доступа. + +// Для функций ПроверенныеСвойстваВидовДоступаСеанса, ПредставлениеВидовДоступа. +// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Имя - Строка +// * Представление - Строка +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// * ДополнительныеТипы - см. НоваяТаблицаДополнительныеТипыВидаДоступа +// +Функция ЗаполненныеВидыДоступаСеанса() + + // 1. Заполнение данных, указанных при внедрении. + + ВидыДоступа = Новый ТаблицаЗначений; + ВидыДоступа.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка")); + ВидыДоступа.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка")); + ВидыДоступа.Колонки.Добавить("ТипЗначений", Новый ОписаниеТипов("Тип")); + ВидыДоступа.Колонки.Добавить("ТипГруппЗначений", Новый ОписаниеТипов("Тип")); + ВидыДоступа.Колонки.Добавить("НесколькоГруппЗначений", Новый ОписаниеТипов("Булево")); + ВидыДоступа.Колонки.Добавить("ДополнительныеТипы", Новый ОписаниеТипов("ТаблицаЗначений")); + + ИнтеграцияПодсистемБСП.ПриЗаполненииВидовДоступа(ВидыДоступа); + УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа(ВидыДоступа); + + Возврат ВидыДоступа; + +КонецФункции + +// Для функции ЗаполненныеВидыДоступаСеанса и +// процедуры ДобавитьДополнительныеТипыВидаДоступа общего модуля УправлениеДоступом. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// +Функция НоваяТаблицаДополнительныеТипыВидаДоступа() Экспорт + + ДополнительныеТипы = Новый ТаблицаЗначений; + ДополнительныеТипы.Колонки.Добавить("ТипЗначений", Новый ОписаниеТипов("Тип")); + ДополнительныеТипы.Колонки.Добавить("ТипГруппЗначений", Новый ОписаниеТипов("Тип")); + ДополнительныеТипы.Колонки.Добавить("НесколькоГруппЗначений", Новый ОписаниеТипов("Булево")); + + Возврат ДополнительныеТипы; + +КонецФункции + +// Для процедур ПриЗаполненииВсехПараметровРаботыРасширений и +// ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации. +// +Процедура ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений() + + Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); + НовоеЗначение = Кэш.ХешСуммы; + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа"; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + + Если СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа + = НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа Тогда + Возврат; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + Если СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа + <> НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа Тогда + Если УжеИзменен Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + РегистрыСведений.НаборыЗначенийДоступа.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. +// Смотри также заполнение в функции ПроверенныеСвойстваВидовДоступаСеанса. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Массив - ФиксированныйМассив из см. СвойстваВидаДоступа +// * ПоИменам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - см. СвойстваВидаДоступа +// * ПоСсылкам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамЗначений - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамГруппИЗначений - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамЗначенийСИерархией - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ЗначенияДоступаСГруппами - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. ЗначенияДоступаСГруппами +// * БезГруппДляЗначенияДоступа - ФиксированныйМассив из Строка +// * СОднойГруппойДляЗначенияДоступа - ФиксированныйМассив из Строка +// * ТипыЗначенийДоступаСГруппами - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - СправочникСсылка +// +Функция СвойстваВидовДоступа() Экспорт + + Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); + + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + Если Кэш.Проверка.Дата + 3 > ТекущаяДатаСеанса Тогда + Возврат Кэш.СвойстваСеанса; + КонецЕсли; + + НовоеЗначение = Кэш.ХешСуммы; + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа"; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + + Если СтароеЗначение.ХешСумма <> НовоеЗначение.ХешСумма Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + Если СтароеЗначение.ХешСумма <> НовоеЗначение.ХешСумма Тогда + Если УжеИзменен Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Кэш.Проверка.Дата = ТекущаяДатаСеанса; + + Возврат Кэш.СвойстваСеанса; + +КонецФункции + +// Для процедуры УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса. +// Возвращает свойства видов доступа, заполняемых при внедрении в процедуре ПриЗаполненииВидовДоступа +// общего модуля УправлениеДоступомПереопределяемый и одноименных обработчиках этого события. +// +// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. +// +// Параметры: +// ХешСуммы - см. НовыеХешСуммыСвойствВидовДоступа +// +// Возвращаемое значение: +// см. СвойстваВидовДоступа +// +Функция ПроверенныеСвойстваВидовДоступаСеанса(ХешСуммы) Экспорт + + ВидыДоступа = ЗаполненныеВидыДоступаСеанса(); + + // 1. Проверки: + // - тип значений доступа не указан для 2-х видов доступа + // - тип значений доступа Пользователи, ГруппыПользователей используется только для вида доступа Пользователи + // - тип значений доступа ВнешниеПользователи, ГруппыВнешнихПользователей используется только для вида доступа + // ВнешниеПользователи + // - имена видов доступа Объект, Условие, НастройкиПрав, ПравоЧтения, ПравоИзменения не указаны + // - тип групп значений не совпадает с типом значений. + // + // 2. Подготовка различных коллекций свойств видов доступа, используемых при работе программы. + + МассивСвойств = Новый Массив; // Массив из см. СвойстваВидаДоступа + ПоСсылкам = Новый Соответствие; + ПоИменам = Новый Соответствие; + ПоТипамЗначений = Новый Соответствие; + ПоТипамГруппИЗначений = Новый Соответствие; + + ЗначенияДоступаСГруппами = ЗначенияДоступаСГруппами(); + + Параметры = Новый Структура; + Параметры.Вставить("ОпределяемыеТипыЗначенийДоступа", + УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ЗначениеДоступа")); + + ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в процедуре %1 общего модуля %2.'"), + "ПриЗаполненииВидовДоступа", "УправлениеДоступомПереопределяемый") + + Символы.ПС + + Символы.ПС; + + Параметры.Вставить("ЗаголовокОшибки", ЗаголовокОшибки); + + ВсеИменаВидовДоступа = Новый Соответствие; + ВсеИменаВидовДоступа.Вставить(ВРег("Объект"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("Условие"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("НастройкиПрав"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("ПравоЧтения"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("ПравоИзменения"), Истина); + + ВсеТипыЗначений = Новый Соответствие; + ВсеТипыГруппЗначений = Новый Соответствие; + ВсеСвойства = Новый Соответствие; + + ОписаниеВерсии = Новый Структура("СвойстваВерсии", Новый Массив); + ДобавитьЭлементВерсии(ОписаниеВерсии, "Версия", "1"); + + Для Каждого ВидДоступа Из ВидыДоступа Цикл + Если ВсеИменаВидовДоступа[ВРег(ВидДоступа.Имя)] <> Неопределено Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Имя вида доступа ""%1"" уже определено.'"), + ВидДоступа.Имя); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + // Проверка повторения типов значений и групп. + ПроверитьТип(ВидДоступа, ВидДоступа.ТипЗначений, ВсеТипыЗначений, Параметры); + ПроверитьТип(ВидДоступа, ВидДоступа.ТипГруппЗначений, ВсеТипыГруппЗначений, Параметры, Истина); + // Проверка пересечения типов значений и групп. + ПроверитьТип(ВидДоступа, ВидДоступа.ТипЗначений, ВсеТипыГруппЗначений, Параметры, , Истина); + ПроверитьТип(ВидДоступа, ВидДоступа.ТипГруппЗначений, ВсеТипыЗначений, Параметры, Истина, Истина); + + ТаблицаДополнительныеТипы = ВидДоступа.ДополнительныеТипы; // См. НоваяТаблицаДополнительныеТипыВидаДоступа + + Для Каждого Строка Из ТаблицаДополнительныеТипы Цикл + // Проверка повторения типов значений и групп. + ПроверитьТип(ВидДоступа, Строка.ТипЗначений, ВсеТипыЗначений, Параметры); + ПроверитьТип(ВидДоступа, Строка.ТипГруппЗначений, ВсеТипыГруппЗначений, Параметры, Истина); + // Проверка пересечения типов значений и групп. + ПроверитьТип(ВидДоступа, Строка.ТипЗначений, ВсеТипыГруппЗначений, Параметры, , Истина); + ПроверитьТип(ВидДоступа, Строка.ТипГруппЗначений, ВсеТипыЗначений, Параметры, Истина, Истина); + КонецЦикла; + + ПустаяСсылкаТипаЗначений = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени( + Метаданные.НайтиПоТипу(ВидДоступа.ТипЗначений).ПолноеИмя()).ПустаяСсылка(); + + Свойства = НовыеСвойстваВидаДоступа(ВидДоступа, ПустаяСсылкаТипаЗначений); + ОписаниеВерсии.СвойстваВерсии.Добавить(""); + ДобавитьСвойстваВерсии(ОписаниеВерсии, Свойства, + "Имя, ТипЗначений, ТипГруппЗначений, НесколькоГруппЗначений"); + + ТипыВыбираемыхЗначений = Новый Массив; + ЗаполнитьЗначенияДоступаСГруппами(Свойства, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений); + ДополнительныеТипы = Новый Массив; + Для Каждого Строка Из ТаблицаДополнительныеТипы Цикл + ДополнительныйТип = ДополнительныйТипВидаДоступа(Строка); + ДополнительныеТипы.Добавить(ДополнительныйТип); + ДобавитьСвойстваВерсии(ОписаниеВерсии, Свойства, + "ТипЗначений, ТипГруппЗначений, НесколькоГруппЗначений"); + ЗаполнитьЗначенияДоступаСГруппами(Строка, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений); + КонецЦикла; + + Свойства.ТипыВыбираемыхЗначений = Новый ФиксированныйМассив(ТипыВыбираемыхЗначений); + Свойства.ДополнительныеТипы = Новый ФиксированныйМассив(ДополнительныеТипы); + ВсеСвойства.Вставить(Свойства, Новый ФиксированнаяСтруктура(Свойства)); + Свойства = ВсеСвойства.Получить(Свойства); + + МассивСвойств.Добавить(Свойства); + ПоИменам.Вставить(Свойства.Имя, Свойства); + ПоСсылкам.Вставить(ПустаяСсылкаТипаЗначений, Свойства); + ПоТипамЗначений.Вставить(Свойства.ТипЗначений, Свойства); + ПоТипамГруппИЗначений.Вставить(Свойства.ТипЗначений, Свойства); + Если Свойства.ТипГруппЗначений <> Тип("Неопределено") Тогда + ПоТипамГруппИЗначений.Вставить(Свойства.ТипГруппЗначений, Свойства); + КонецЕсли; + + Для Каждого Строка Из ВидДоступа.ДополнительныеТипы Цикл + ПоТипамЗначений.Вставить(Строка.ТипЗначений, Свойства); + ПоТипамГруппИЗначений.Вставить(Строка.ТипЗначений, Свойства); + Если Строка.ТипГруппЗначений <> Тип("Неопределено") Тогда + ПоТипамГруппИЗначений.Вставить(Строка.ТипГруппЗначений, Свойства); + КонецЕсли; + КонецЦикла; + + КонецЦикла; + + БезГруппДляЗначенияДоступа = Новый Массив; + СОднойГруппойДляЗначенияДоступа = Новый Массив; + ТипыЗначенийДоступаСГруппами = Новый Соответствие; + + ВидыДоступаСГруппами = Новый Соответствие; + + Для Каждого КлючИЗначение Из ЗначенияДоступаСГруппами.ПоТипамСсылок Цикл + ВидДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа + ИмяВидаДоступа = ВидДоступа.Имя; + ВидыДоступаСГруппами.Вставить(ИмяВидаДоступа, Истина); + + ПустаяСсылка = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); + ТипыЗначенийДоступаСГруппами.Вставить(ТипЗнч(ПустаяСсылка), ПустаяСсылка); + + Если НЕ КлючИЗначение.Значение.НесколькоГруппЗначений + И СОднойГруппойДляЗначенияДоступа.Найти(ИмяВидаДоступа) = Неопределено Тогда + + СОднойГруппойДляЗначенияДоступа.Добавить(ИмяВидаДоступа); + КонецЕсли; + КонецЦикла; + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.Пользователи"), + Справочники.Пользователи.ПустаяСсылка()); + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ГруппыПользователей"), + Справочники.ГруппыПользователей.ПустаяСсылка()); + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ВнешниеПользователи"), + Справочники.ВнешниеПользователи.ПустаяСсылка()); + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ГруппыВнешнихПользователей"), + Справочники.ГруппыВнешнихПользователей.ПустаяСсылка()); + + ПоТипамЗначенийСИерархией = Новый Соответствие; + Для Каждого КлючИЗначение Из ПоТипамЗначений Цикл + ТипСсылка = КлючИЗначение.Ключ; + Если ТипыЗначенийДоступаСГруппами[ТипСсылка] <> Неопределено Тогда + Продолжить; + КонецЕсли; + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипСсылка); + Если ОбъектМетаданных <> Неопределено + И (ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) + Или ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)) + И ОбъектМетаданных.Иерархический Тогда + + ТипОбъект = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных(ОбъектМетаданных); + ПоТипамЗначенийСИерархией.Вставить(ТипСсылка, КлючИЗначение.Значение); + ПоТипамЗначенийСИерархией.Вставить(ТипОбъект, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + + Для Каждого СвойстваВидаДоступа Из МассивСвойств Цикл + Если ВидыДоступаСГруппами.Получить(СвойстваВидаДоступа.Имя) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Если СвойстваВидаДоступа.Имя = "Пользователи" + ИЛИ СвойстваВидаДоступа.Имя = "ВнешниеПользователи" Тогда + Продолжить; + КонецЕсли; + БезГруппДляЗначенияДоступа.Добавить(СвойстваВидаДоступа.Имя); + КонецЦикла; + + ПроверитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ЗначенияДоступаСГруппами); + + // Окончательная фиксация данных. + + ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления = + Новый ФиксированныйМассив(ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления); + + ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления = + Новый ФиксированноеСоответствие(ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления); + + Для Каждого ОписаниеСвойства Из ЗначенияДоступаСГруппами Цикл + ТекущееСоответствие = ОписаниеСвойства.Значение; + Если ТипЗнч(ТекущееСоответствие) <> Тип("Соответствие") Тогда + Продолжить; + КонецЕсли; + Для Каждого КлючИЗначение Из ТекущееСоответствие Цикл + ТекущееСоответствие.Вставить(КлючИЗначение.Ключ, + ВсеСвойства.Получить(КлючИЗначение.Значение)); + КонецЦикла; + ЗначенияДоступаСГруппами[ОписаниеСвойства.Ключ] = + Новый ФиксированноеСоответствие(ТекущееСоответствие); + КонецЦикла; + + СвойстваВидовДоступа = Новый Структура; + СвойстваВидовДоступа.Вставить("Массив", + Новый ФиксированныйМассив(МассивСвойств)); + + СвойстваВидовДоступа.Вставить("ПоИменам", + Новый ФиксированноеСоответствие(ПоИменам)); + + СвойстваВидовДоступа.Вставить("ПоСсылкам", + Новый ФиксированноеСоответствие(ПоСсылкам)); + + СвойстваВидовДоступа.Вставить("ПоТипамЗначений", + Новый ФиксированноеСоответствие(ПоТипамЗначений)); + + СвойстваВидовДоступа.Вставить("ПоТипамЗначенийСИерархией", + Новый ФиксированноеСоответствие(ПоТипамЗначенийСИерархией)); + + СвойстваВидовДоступа.Вставить("ПоТипамГруппИЗначений", + Новый ФиксированноеСоответствие(ПоТипамГруппИЗначений)); + + СвойстваВидовДоступа.Вставить("ЗначенияДоступаСГруппами", + Новый ФиксированнаяСтруктура(ЗначенияДоступаСГруппами)); + + СвойстваВидовДоступа.Вставить("БезГруппДляЗначенияДоступа", + Новый ФиксированныйМассив(БезГруппДляЗначенияДоступа)); + + СвойстваВидовДоступа.Вставить("СОднойГруппойДляЗначенияДоступа", + Новый ФиксированныйМассив(СОднойГруппойДляЗначенияДоступа)); + + СвойстваВидовДоступа.Вставить("ТипыЗначенийДоступаСГруппами", + Новый ФиксированноеСоответствие(ТипыЗначенийДоступаСГруппами)); + + Результат = Новый ФиксированнаяСтруктура(СвойстваВидовДоступа); + + ХешСуммы.ХешСуммаТиповГруппИЗначенийДоступа = + ХешСуммаТиповГруппИЗначенийДоступа(СвойстваВидовДоступа); + + СтрокаВерсии = СтрСоединить(ОписаниеВерсии.СвойстваВерсии, Символы.ПС); + ХешСуммы.ХешСумма = ХешСуммаДанных(СтрокаВерсии); + + Возврат Результат; + +КонецФункции + +// Для функции СвойстваВидовДоступа. +// +// Возвращаемое значение: +// см. СвойстваВидаДоступа +// +Функция НовыеСвойстваВидаДоступа(ВидДоступа, ПустаяСсылкаТипаЗначений) + + Свойства = Новый Структура; + Свойства.Вставить("Имя", ВидДоступа.Имя); + Свойства.Вставить("Ссылка", ПустаяСсылкаТипаЗначений); + Свойства.Вставить("ТипЗначений", ВидДоступа.ТипЗначений); + Свойства.Вставить("ТипГруппЗначений", ВидДоступа.ТипГруппЗначений); + Свойства.Вставить("НесколькоГруппЗначений", ВидДоступа.НесколькоГруппЗначений); + Свойства.Вставить("ДополнительныеТипы"); + Свойства.Вставить("ТипыВыбираемыхЗначений"); + + Возврат Свойства; + +КонецФункции + +// Для функции СвойстваВидовДоступа. +// +// Возвращаемое значение: +// Структура: +// * ПоТипам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамСсылок - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ИменаТаблицДляОбновления - ФиксированныйМассив из Строка +// * ТипыГруппЗначенийДляОбновления - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - СправочникСсылка +// * ПоТипамСсылокДляОбновления - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// +Функция ЗначенияДоступаСГруппами() + + ЗначенияДоступаСГруппами = Новый Структура; + ЗначенияДоступаСГруппами.Вставить("ПоТипам", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ПоТипамСсылок", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ИменаТаблицДляОбновления", Новый Массив); + ЗначенияДоступаСГруппами.Вставить("ТипыГруппЗначенийДляОбновления", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ПоТипамДляОбновления", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ПоТипамСсылокДляОбновления", Новый Соответствие); + + Возврат ЗначенияДоступаСГруппами; + +КонецФункции + +// Для функции СвойстваВидовДоступа. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// +Функция ДополнительныйТипВидаДоступа(Строка) + + Элемент = Новый Структура; + Элемент.Вставить("ТипЗначений", Строка.ТипЗначений); + Элемент.Вставить("ТипГруппЗначений", Строка.ТипГруппЗначений); + Элемент.Вставить("НесколькоГруппЗначений", Строка.НесколькоГруппЗначений); + + Возврат Новый ФиксированнаяСтруктура(Элемент); + +КонецФункции + +// Для функции СвойстваВидовДоступа. +Процедура ЗаполнитьЗначенияДоступаСГруппами(Строка, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений) + + Если Свойства.Имя = "Пользователи" Тогда + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.Пользователи")); + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ГруппыПользователей")); + Возврат; + КонецЕсли; + + Если Свойства.Имя = "ВнешниеПользователи" Тогда + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ВнешниеПользователи")); + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ГруппыВнешнихПользователей")); + Возврат; + КонецЕсли; + + ТипСсылки = Строка.ТипЗначений; + + МетаданныеТипаЗначений = Метаданные.НайтиПоТипу(Строка.ТипЗначений); + Если ОбщегоНазначения.ЭтоПеречисление(МетаданныеТипаЗначений) Тогда + ТипОбъекта = ТипСсылки; + Иначе + ТипОбъекта = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных( + МетаданныеТипаЗначений); + КонецЕсли; + + Если Строка.ТипГруппЗначений = Тип("Неопределено") Тогда + ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, + ТипОбъекта, МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, Неопределено); + ДобавитьВМассив(ТипыВыбираемыхЗначений, Строка.ТипЗначений); + Возврат; + КонецЕсли; + + Если Строка.ТипГруппЗначений <> Тип("Неопределено") Тогда + ДобавитьВМассив(ТипыВыбираемыхЗначений, Строка.ТипГруппЗначений); + КонецЕсли; + + ЗначенияДоступаСГруппами.ПоТипам.Вставить(ТипСсылки, Свойства); + ЗначенияДоступаСГруппами.ПоТипам.Вставить(ТипОбъекта, Свойства); + ЗначенияДоступаСГруппами.ПоТипамСсылок.Вставить(ТипСсылки, Свойства); + + МетаданныеТипаГруппЗначений = Метаданные.НайтиПоТипу(Строка.ТипГруппЗначений); + + ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, + ТипОбъекта, МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, МетаданныеТипаГруппЗначений); + +КонецПроцедуры + +// Для функции СвойстваВидовДоступа и процедуры ЗаполнитьЗначенияДоступаСГруппами. +Процедура ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, ТипОбъекта, + МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, МетаданныеТипаГруппЗначений) + + ПустаяСсылкаТипаЗначений = ПредопределенноеЗначение(МетаданныеТипаЗначений.ПолноеИмя() + ".ПустаяСсылка"); + + Если МетаданныеТипаГруппЗначений = Неопределено Тогда + ПустаяСсылкаТипаГруппЗначений = ПустаяСсылкаТипаЗначений; + Иначе + ПустаяСсылкаТипаГруппЗначений = ПустаяСсылкаОбъектаМетаданных(МетаданныеТипаГруппЗначений); + КонецЕсли; + + ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления.Добавить(МетаданныеТипаЗначений.ПолноеИмя()); + + ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления.Вставить(ТипСсылки, + ПустаяСсылкаТипаГруппЗначений); + + ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления.Вставить(ПустаяСсылкаТипаЗначений, + ПустаяСсылкаТипаГруппЗначений); + + ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Вставить(ТипСсылки, Свойства); + ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Вставить(ТипСсылки, Свойства); + ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Вставить(ТипОбъекта, Свойства); + +КонецПроцедуры + +// Для функции СвойстваВидовДоступа. +Процедура ПроверитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ЗначенияДоступаСГруппами) + + ТекущиеТипыПодписки = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы( + "ОпределяемыйТип.ЗначениеДоступаОбъект"); + + ТребуемыеТипыПодписки = Новый Соответствие; + Для Каждого КлючИЗначение Из ЗначенияДоступаСГруппами.ПоТипамДляОбновления Цикл + Если ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ТребуемыеТипыПодписки.Вставить(КлючИЗначение.Ключ, Истина); + КонецЦикла; + + НедостающиеТипы = Новый Массив; + + Для Каждого КлючИЗначение Из ТребуемыеТипыПодписки Цикл + Если ТекущиеТипыПодписки.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + НедостающиеТипы.Добавить(КлючИЗначение.Ключ); + КонецЕсли; + КонецЦикла; + + Если НедостающиеТипы.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'По данным, полученным из процедуры %1 + |общего модуля %2, + |в определяемом типе %3 не указаны требуемые типы: + |- %4'"), + "ПриЗаполненииВидовДоступа", + "УправлениеДоступомПереопределяемый", + "ЗначениеДоступаОбъект", + СтрСоединить(НедостающиеТипы, "," + Символы.ПС + "- ")); + + ВызватьИсключение ТекстОшибки; + +КонецПроцедуры + +// Для функции СвойстваВидовДоступа. +Процедура ПроверитьТип(ВидДоступа, Тип, ВсеТипы, Параметры, ПроверкаТиповГрупп = Ложь, ПроверкаПересечения = Ложь) + + Если Тип = Тип("Неопределено") Тогда + Если ПроверкаТиповГрупп Тогда + Возврат; + КонецЕсли; + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Для вида доступа ""%1"" не указан тип значений доступа.'"), + ВидДоступа.Имя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + // Проверка, что указан тип ссылки. + Если НЕ ОбщегоНазначения.ЭтоСсылка(Тип) Тогда + Если ПроверкаТиповГрупп Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип групп значений, для вида доступа ""%2"". + |Однако это не тип ссылки.'"); + Иначе + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип значений, для вида доступа ""%2"". + |Однако это не тип ссылки.'"); + КонецЕсли; + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ОписаниеОшибки, Тип, ВидДоступа.Имя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + // Проверка повторения и пересечения типов значений и групп значений. + ДляТогоЖеВидаДоступаОшибкиНет = Ложь; + + Если ПроверкаТиповГрупп Тогда + Если ПроверкаПересечения Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип значений, для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать, как тип групп значений.'"); + Иначе + ДляТогоЖеВидаДоступаОшибкиНет = Истина; + ОписаниеОшибки = + НСтр("ru = 'Тип групп значений ""%1"" уже указан для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать.'"); + КонецЕсли; + Иначе + Если ПроверкаПересечения Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип групп значений, для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать, как тип значений.'"); + Иначе + ОписаниеОшибки = + НСтр("ru = 'Тип значений ""%1"" уже указан для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать.'"); + КонецЕсли; + КонецЕсли; + + Если ВсеТипы.Получить(Тип) <> Неопределено Тогда + Если НЕ (ДляТогоЖеВидаДоступаОшибкиНет И ВидДоступа.Имя = ВсеТипы.Получить(Тип)) Тогда + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ОписаниеОшибки, Тип, ВсеТипы.Получить(Тип), ВидДоступа.Имя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ИначеЕсли НЕ ПроверкаПересечения Тогда + ВсеТипы.Вставить(Тип, ВидДоступа.Имя); + КонецЕсли; + + // Проверка состава определяемых типов. + ОписаниеОшибки = ""; + Если Параметры.ОпределяемыеТипыЗначенийДоступа.Получить(Тип) = Неопределено Тогда + Если ПроверкаТиповГрупп Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип групп значений доступа ""%1"" вида доступа ""%2"" + |не указан в определяемом типе %3.'"); + Иначе + ОписаниеОшибки = + НСтр("ru = 'Тип значений доступа ""%1"" вида доступа ""%2"" + |не указан в определяемом типе %3.'"); + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ОписаниеОшибки, Тип, ВидДоступа.Имя, "ЗначениеДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Тип +// * Значение - Строка +// +Функция ПредставлениеВидовДоступа() Экспорт + + ВидыДоступа = ЗаполненныеВидыДоступаСеанса(); + + ПредставлениеВидовДоступа = Новый Соответствие; + + Для Каждого ВидДоступа Из ВидыДоступа Цикл + ПредставлениеВидовДоступа.Вставить(ВидДоступа.ТипЗначений, ВидДоступа.Представление); + КонецЦикла; + + Возврат Новый ФиксированноеСоответствие(ПредставлениеВидовДоступа); + +КонецФункции + +Функция ПредставлениеВидаДоступа(СвойстваВидаДоступа) Экспорт + + ПредставлениеВидовДоступа = УправлениеДоступомСлужебныйПовтИсп.ПредставлениеВидовДоступа(); + + Представление = ПредставлениеВидовДоступа.Получить(СвойстваВидаДоступа.ТипЗначений); + + Если Не ЗначениеЗаполнено(Представление) Тогда + Представление = СвойстваВидаДоступа.Имя; + КонецЕсли; + + Возврат Представление; + +КонецФункции + +// Для процедуры ЗаполнитьЗначенияДоступаСГруппами. +Процедура ДобавитьВМассив(Массив, Значение) + + Если Массив.Найти(Значение) = Неопределено Тогда + Массив.Добавить(Значение); + КонецЕсли; + +КонецПроцедуры + +// Для функций УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса, +// СвойстваВидовДоступа и процедур ОбновитьОписаниеСвойствВидовДоступа, +// ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений. +// +// Параметры: +// Значение - Неопределено +// - ФиксированнаяСтруктура +// +// Возвращаемое значение: +// Структура: +// * ХешСумма - Строка +// * ХешСуммаТиповГруппИЗначенийДоступа - Строка +// +Функция НовыеХешСуммыСвойствВидовДоступа(Значение = Неопределено) Экспорт + + Результат = Новый Структура; + Результат.Вставить("ХешСумма", ""); + Результат.Вставить("ХешСуммаТиповГруппИЗначенийДоступа", ""); + + Если ТипЗнч(Значение) = Тип("ФиксированнаяСтруктура") Тогда + ЗаполнитьЗначенияСвойств(Результат, Значение); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Для процедуры ПроверенныеСвойстваВидовДоступаСеанса. +Функция ХешСуммаТиповГруппИЗначенийДоступа(СвойстваВидовДоступа) + + Данные = Новый Массив; + Данные.Добавить(ОписаниеТиповИзКлючейСоответствия(СвойстваВидовДоступа.ПоТипамЗначений)); + Данные.Добавить(ОписаниеТиповИзКлючейСоответствия(СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами)); + + ИменаТаблицДляОбновления = Новый СписокЗначений; + ИменаТаблицДляОбновления.ЗагрузитьЗначения(Новый Массив( + СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления)); + ИменаТаблицДляОбновления.СортироватьПоЗначению(); + + Данные.Добавить(ИменаТаблицДляОбновления.ВыгрузитьЗначения()); + + Данные.Добавить(Метаданные.ОпределяемыеТипы.ВладелецНаборовЗначенийДоступаОбъект.Тип); + + Возврат ХешСуммаДанных(Данные); + +КонецФункции + +// Для функции ХешСуммаТиповГруппИЗначенийДоступа. +Функция ОписаниеТиповИзКлючейСоответствия(Данные) + + Типы = Новый Массив; + Для Каждого КлючИЗначение Из Данные Цикл + Типы.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + + Возврат Новый ОписаниеТипов(Типы); + +КонецФункции + +Функция ХешСуммаДанных(Данные) Экспорт + + СтрокаДляХеширования = СтрокаДанныхДляХеширования(Данные); + + Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); + Хеширование.Добавить(СтрокаДляХеширования); + ХешСумма = Хеширование.ХешСумма; + СтрокаХешСуммы = Base64Строка(ХешСумма); + + Возврат СтрокаХешСуммы; + +КонецФункции + +Функция ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипЗначенияВидаДоступа) + + УстановитьПривилегированныйРежим(Истина); + + ТекстЗапроса = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка, + | ГруппыДоступа.Профиль КАК Профиль + |ПОМЕСТИТЬ ГруппыДоступа + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + | ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка + | И (ГруппыДоступа.Профиль <> &ПрофильАдминистратор) + | И (НЕ ГруппыДоступа.ПометкаУдаления) + | И (НЕ ПрофилиГруппДоступа.ПометкаУдаления) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ГДЕ + | УчастникиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка)) + | + |ИНДЕКСИРОВАТЬ ПО + | Ссылка, + | ГруппыДоступа.Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа.ЗначенияДоступа КАК ГруппыДоступаЗначенияДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа + | ПО ГруппыДоступаЗначенияДоступа.Ссылка = ГруппыДоступа.Ссылка + |ГДЕ + | ГруппыДоступаЗначенияДоступа.ВключаяНижестоящие + | И ТИПЗНАЧЕНИЯ(ГруппыДоступаЗначенияДоступа.ЗначениеДоступа) = &ТипЗначенияВидаДоступа + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Ссылка + |ИЗ + | Справочник.ПрофилиГруппДоступа.ЗначенияДоступа КАК ПрофилиГруппДоступаЗначенияДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа + | ПО ПрофилиГруппДоступаЗначенияДоступа.Ссылка = ГруппыДоступа.Профиль + |ГДЕ + | ПрофилиГруппДоступаЗначенияДоступа.ВключаяНижестоящие + | И ТИПЗНАЧЕНИЯ(ПрофилиГруппДоступаЗначенияДоступа.ЗначениеДоступа) = &ТипЗначенияВидаДоступа"; + + Запрос = Новый Запрос(ТекстЗапроса); + Запрос.УстановитьПараметр("ТипЗначенияВидаДоступа", ТипЗначенияВидаДоступа); + Запрос.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +// Возвращает таблицу значений, содержащую вид ограничений доступа по каждому праву +// объектов метаданных. +// Если записи по праву нет, значит ограничений по праву нет. +// Таблица содержит только виды доступа, заданные разработчиком, +// исходя из их применения в текстах ограничений. +// В стандартном варианте ограничения доступа для получения видов доступа объектов, +// которые ограничиваются с помощью шаблона ПоНаборамЗначений, используется текущее +// состояние регистра сведений НаборыЗначенийДоступа. Признаком такого ограничения +// является строка, в которой таблица ограничивается по виду ограничения Объект +// с той же ведущей таблицей (кроме случая, когда таблица является владельцем настроек прав). +// +// Параметры: +// ДляПроверки - Булево - вернуть текстовое описание ограничений прав, заполненное +// в переопределяемых модулях без проверки. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ДляВнешнихПользователей - Булево - если Ложь, тогда ограничение для пользователей, +// если Истина, тогда для внешних пользователей. +// Колонка присутствует только для универсального ограничения. +// * ПолноеИмя - Строка - полное имя таблицы. +// * Таблица - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы. +// * Право - Строка - "Чтение", "Изменение". +// * ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа значений вида доступа. +// Неопределено если ограничение с помощью стандартного шаблона ПоНаборамЗначений. +// Перечисление.ДополнительныеЗначенияДоступа.Неопределено для +// специальных ограничений Объект и НастройкиПрав. +// * ЭтоАвторизованныйПользователь - Булево - Истина, если вид доступа Пользователи или ВнешниеПользователи, +// но проверка только с помощью ограничения ФункцияЭтоАвторизованныйПользователь. +// * ТаблицаОбъекта - ЛюбаяСсылка - пустая ссылка объекта, который ограничивается с помощью +// стандартного шаблона ПоНаборамЗначений. +// - Неопределено - если ВидДоступа <> Неопределено. +// Колонка присутствует только для стандартного ограничения. +// +// Строка - когда ДляПроверки равно Истина, тогда ограничения прав, как они добавлены в переопределяемом модуле. +// +Функция ПостоянныеВидыОграниченийПравОбъектовМетаданных(ДляПроверки = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + УниверсальноеОграничение = ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина); + + Если ДляПроверки Или Не УниверсальноеОграничение Тогда + ОграниченияПрав = ""; + ИнтеграцияПодсистемБСП.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(ОграниченияПрав); + УправлениеДоступомПереопределяемый.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(ОграниченияПрав); + Если ДляПроверки Тогда + Возврат ОграниченияПрав; + КонецЕсли; + КонецЕсли; + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + ВидыОграниченийПрав = Новый ТаблицаЗначений; + ВидыОграниченийПрав.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + ВидыОграниченийПрав.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(430))); + ВидыОграниченийПрав.Колонки.Добавить("Таблица", Новый ОписаниеТипов(ТипыИдентификаторов)); + ВидыОграниченийПрав.Колонки.Добавить("Право", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))); + ВидыОграниченийПрав.Колонки.Добавить("ВидДоступа", УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); + ВидыОграниченийПрав.Колонки.Добавить("ЭтоАвторизованныйПользователь", Новый ОписаниеТипов("Булево")); + ВидыОграниченийПрав.Колонки.Добавить("ТаблицаОбъекта", + Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип); + ВидыОграниченийПрав.Колонки.Добавить("ВедущееПраво", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))); + + ВидыДоступаПоИменам = СвойстваВидовДоступа().ПоИменам; + + Если УниверсальноеОграничение Тогда + ВсеВидыОграничений = ВсеВидыОграниченийПравДляОтчетаПраваДоступа(); + ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, + ВсеВидыОграничений.ДляПользователей, ВидыДоступаПоИменам, Истина, Ложь); + ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, + ВсеВидыОграничений.ДляВнешнихПользователей, ВидыДоступаПоИменам, Истина, Истина); + Иначе + ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, + ОграниченияПрав, ВидыДоступаПоИменам, Ложь); + КонецЕсли; + + ВидыОграниченийПрав.Индексы.Добавить("ПолноеИмя"); + ПолныеИмена = ВидыОграниченийПрав.ВыгрузитьКолонку("ПолноеИмя"); + ИдентификаторыИмен = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена); + Для Каждого Строка Из ВидыОграниченийПрав Цикл + Строка.Таблица = ИдентификаторыИмен.Получить(Строка.ПолноеИмя); + КонецЦикла; + + ВидыОграниченийПрав.Колонки.Удалить("ВедущееПраво"); + Если УниверсальноеОграничение Тогда + ВидыОграниченийПрав.Колонки.Удалить("ТаблицаОбъекта"); + Иначе + ВидыОграниченийПрав.Колонки.Удалить("ДляВнешнихПользователей"); + КонецЕсли; + + Возврат ВидыОграниченийПрав; + +КонецФункции + +// Для функции ПостоянныеВидыОграниченийПравОбъектовМетаданных. +Процедура ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, ОграниченияПрав, ВидыДоступаПоИменам, + УниверсальноеОграничение, ДляВнешнихПользователей = Неопределено) + + Для НомерСтроки = 1 По СтрЧислоСтрок(ОграниченияПрав) Цикл + ТекущаяСтрока = СокрЛП(СтрПолучитьСтроку(ОграниченияПрав, НомерСтроки)); + Если ЗначениеЗаполнено(ТекущаяСтрока) Тогда + ПояснениеОшибки = ""; + ЧастиСтроки = СтрРазделить(ТекущаяСтрока, "."); + Если Не УниверсальноеОграничение + И ЧастиСтроки.Количество() <> 4 + И ЧастиСтроки.Количество() <> 6 Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Строка должна быть в формате %1.'"), + "<ПолноеИмяТаблицы>.<ИмяПрава>.<ИмяВидаДоступа>[.<ПолноеИмяТаблицыОбъекта>]"); + ИначеЕсли УниверсальноеОграничение + И ЧастиСтроки.Количество() <> 4 + И ЧастиСтроки.Количество() <> 7 Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Строка должна быть в формате %1.'"), + "<ПолноеИмяТаблицы>.<ИмяПрава>.<ИмяВидаДоступа>[.<ПолноеИмяТаблицыОбъекта>.<ИмяВедущегоПрава>]"); + Иначе + Таблица = ЧастиСтроки[0] + "." + ЧастиСтроки[1]; + Право = ЧастиСтроки[2]; + ВидДоступа = ЧастиСтроки[3]; + Если ЧастиСтроки.Количество() = 4 Тогда + ТаблицаОбъекта = ""; + ВедущееПраво = ""; + Иначе + ТаблицаОбъекта = ЧастиСтроки[4] + "." + ЧастиСтроки[5]; + ВедущееПраво = ?(УниверсальноеОграничение, ЧастиСтроки[6], ""); + КонецЕсли; + + ОбъектМетаданныхТаблицы = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Таблица); + Если ОбъектМетаданныхТаблицы = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица ""%1"".'"), Таблица); + + ИначеЕсли Право <> "Чтение" И Право <> "Изменение" Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует право ""%1"".'"), Право); + + ИначеЕсли ВРег(ВидДоступа) = ВРег("Объект") Тогда + ОбъектМетаданныхТаблицыОбъекта = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ТаблицаОбъекта); + Если ОбъектМетаданныхТаблицыОбъекта = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица объекта ""%1"".'"), + ТаблицаОбъекта); + Иначе + Если ОбъектМетаданныхТаблицы = ОбъектМетаданныхТаблицыОбъекта Тогда + ВидДоступаСсылка = Неопределено; + ТаблицаОбъектаСсылка = ПустаяСсылкаОбъектаМетаданных(ТаблицаОбъекта); + Иначе + ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + ТаблицаОбъектаСсылка = Неопределено; + КонецЕсли; + Если УниверсальноеОграничение + И ВедущееПраво <> "Чтение" + И ВедущееПраво <> "Изменение" Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует ведущее право ""%1"".'"), ВедущееПраво); + КонецЕсли; + КонецЕсли; + + ИначеЕсли ВРег(ВидДоступа) = ВРег("НастройкиПрав") Тогда + Если ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ТаблицаОбъекта) = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица владельца настроек прав ""%1"".'"), + ТаблицаОбъекта); + Иначе + ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + ТаблицаОбъектаСсылка = Неопределено; + КонецЕсли; + + ИначеЕсли ВРег(ВидДоступа) = ВРег("ПравоЧтения") + Или ВРег(ВидДоступа) = ВРег("ПравоИзменения") + Или ВРег(ВидДоступа) = ВРег("ФункцияЭтоАвторизованныйПользователь") + Или ВРег(ВидДоступа) = ВРег("ФункцияПравоДоступаИлиРольДоступна") Тогда + + ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + ТаблицаОбъектаСсылка = Неопределено; + + ИначеЕсли ВидыДоступаПоИменам.Получить(ВидДоступа) = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует вид доступа ""%1"".'"), ВидДоступа); + Иначе + СвойстваВидаДоступа = ВидыДоступаПоИменам.Получить(ВидДоступа); // См. СвойстваВидаДоступа + ВидДоступаСсылка = СвойстваВидаДоступа.Ссылка; + ТаблицаОбъектаСсылка = Неопределено; + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(ПояснениеОшибки) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в строке описания вида ограничений права объекта метаданных: + |""%1"".'") + + Символы.ПС + + Символы.ПС, + ТекущаяСтрока) + + ПояснениеОшибки; + + Если Не УниверсальноеОграничение Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное внедрение подсистемы %1 + |в процедуре %2 + |общего модуля %3. + | + |%4'"), + "УправлениеДоступом", + "ПриЗаполненииВидовОграниченийПравОбъектовМетаданных", + "УправлениеДоступомПереопределяемый", + ТекстОшибки); + КонецЕсли; + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + Иначе + НовоеОписание = ВидыОграниченийПрав.Добавить(); + НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; + НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); + НовоеОписание.Право = Право; + НовоеОписание.ВидДоступа = ВидДоступаСсылка; + НовоеОписание.ТаблицаОбъекта = ТаблицаОбъектаСсылка; + НовоеОписание.ВедущееПраво = ВедущееПраво; + Если ВРег(ВидДоступа) = ВРег("ФункцияЭтоАвторизованныйПользователь") Тогда + Если ДляВнешнихПользователей <> Истина Тогда + НовоеОписание = ВидыОграниченийПрав.Добавить(); + НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; + НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); + НовоеОписание.Право = Право; + НовоеОписание.ВидДоступа = Справочники.Пользователи.ПустаяСсылка(); + НовоеОписание.ЭтоАвторизованныйПользователь = Истина; + КонецЕсли; + Если ДляВнешнихПользователей <> Ложь Тогда + НовоеОписание = ВидыОграниченийПрав.Добавить(); + НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; + НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); + НовоеОписание.Право = Право; + НовоеОписание.ВидДоступа = Справочники.ВнешниеПользователи.ПустаяСсылка(); + НовоеОписание.ЭтоАвторизованныйПользователь = Истина; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка +// * ТипГруппИЗначений - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка +// +Функция ТипыГруппИЗначенийВидовДоступа() Экспорт + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ТипыГруппИЗначенийВидовДоступа = Новый ТаблицаЗначений; + ТипыГруппИЗначенийВидовДоступа.Колонки.Добавить("ВидДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + ТипыГруппИЗначенийВидовДоступа.Колонки.Добавить("ТипГруппИЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + + Для Каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамГруппИЗначений Цикл + Строка = ТипыГруппИЗначенийВидовДоступа.Добавить(); + СвойстваВидаДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа + Строка.ВидДоступа = СвойстваВидаДоступа.Ссылка; + + Типы = Новый Массив; + Типы.Добавить(КлючИЗначение.Ключ); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + + Строка.ТипГруппИЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + КонецЦикла; + + Возврат ТипыГруппИЗначенийВидовДоступа; + +КонецФункции + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ВидДоступа - ЛюбаяСсылка +// * ТипЗначений - ЛюбаяСсылка +// +Функция ТипыЗначенийВидовДоступаИВладельцевНастроекПрав() Экспорт + + ТипыЗначенийВидовДоступаИВладельцевНастроекПрав = Новый ТаблицаЗначений; + + ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Колонки.Добавить("ВидДоступа", + УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); + + ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Колонки.Добавить("ТипЗначений", + УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); + + ТипыЗначенийВидовДоступа = ТипыЗначенийВидовДоступа(); + + Для Каждого Строка Из ТипыЗначенийВидовДоступа Цикл + ЗаполнитьЗначенияСвойств(ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Добавить(), Строка); + КонецЦикла; + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ВладельцыПрав = ВозможныеПрава.ПоТипамСсылок; + + Для Каждого КлючИЗначение Из ВладельцыПрав Цикл + + Типы = Новый Массив; + Типы.Добавить(КлючИЗначение.Ключ); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + + Строка = ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Добавить(); + Строка.ВидДоступа = ОписаниеТипа.ПривестиЗначение(Неопределено); + Строка.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + КонецЦикла; + + Возврат ТипыЗначенийВидовДоступаИВладельцевНастроекПрав; + +КонецФункции + +// Для функции ТипыЗначенийВидовДоступаИВладельцевНастроекПрав. +Функция ТипыЗначенийВидовДоступа() + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ТипыЗначенийВидовДоступа = Новый ТаблицаЗначений; + ТипыЗначенийВидовДоступа.Колонки.Добавить("ВидДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + ТипыЗначенийВидовДоступа.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + + Для каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамЗначений Цикл + Строка = ТипыЗначенийВидовДоступа.Добавить(); + СвойстваВидаДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа + Строка.ВидДоступа = СвойстваВидаДоступа.Ссылка; + + Типы = Новый Массив; + Типы.Добавить(КлючИЗначение.Ключ); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + + Строка.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + КонецЦикла; + + Возврат ТипыЗначенийВидовДоступа; + +КонецФункции + +// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов. +// Смотри также заполнение в функции РегистрыСведений.НастройкиПравОбъектов.ВозможныеПраваСеанса. +// +// Возвращаемое значение: +// Структура: +// * ПоТипам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип - тип ссылки или объекта из ОпределяемыйТип.ВладельцыНастроекПрав +// ** Значение - ФиксированноеСоответствие из КлючИЗначение: +// *** Ключ - Строка - имя возможного права +// *** Значение - см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава +// * ПоТипамСсылок - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип - тип ссылки из ОпределяемыйТип.ВладельцыНастроекПрав +// ** Значение - ФиксированныйМассив из см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава +// * ПоПолнымИменам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка - владелец прав (полное имя таблицы) +// ** Значение - см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава +// * ТипыВладельцев - ФиксированныйМассив из ОпределяемыйТип.ВладелецНастроекПрав +// * ОтдельныеТаблицы - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы +// ** Значение - Строка - полное имя таблицы +// * ИерархическиеТаблицы - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип - тип ссылки или объекта из ОпределяемыйТип.ВладельцыНастроекПрав +// ** Значение - Булево - Истина. +// +Функция ВозможныеПраваДляНастройкиПравОбъектов() Экспорт + + Возврат РегистрыСведений.НастройкиПравОбъектов.ВозможныеПраваДляНастройкиПравОбъектов(); + +КонецФункции + +// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииПоставляемыхПрофилейГруппДоступа. +// Смотри также заполнение в функции Справочники.ПрофилиГруппДоступа.ПроверенныеПоставляемыеПрофилиСеанса. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ОписанияПрофилей - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - см. Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля +// * ОписанияПрофилейМассив - ФиксированныйМассив из см. Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля +// * ПапкиПоРодителям - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - ФиксированноеСоответствие из КлючИЗначение: +// *** Ключ - Строка +// *** Значение - Булево +// * ПараметрыОбновления - ФиксированнаяСтруктура: +// ** ОбновлятьИзмененныеПрофили - Булево +// ** ЗапретитьИзменениеПрофилей - Булево +// ** ОбновлятьГруппыДоступа - Булево +// ** ОбновлятьГруппыДоступаСУстаревшимиНастройками - Булево +// +Функция ПоставляемыеПрофили() Экспорт + + Возврат Справочники.ПрофилиГруппДоступа.ПоставляемыеПрофили(); + +КонецФункции + +// Смотри заполнение в функции Справочники.ПрофилиГруппДоступа.ПодготовленныеСтандартныеРолиРасширенийСеанса. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ОбщиеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>ОбщиеПрава +// * ПолныеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>ПолныеПрава +// * БазовыеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>БазовыеПрава +// * БазовыеПраваВнешнихПользователей - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>БазовыеПраваВнешнихПользователей +// * АдминистраторСистемы - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>АдминистраторСистемы +// * Все - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка - имя роли расширений, из указанных выше. +// ** Значение - Строка - имя вида ролей (имя свойства структуры). +// * ДополнительныеРолиАдминистратора - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка - имя ролей расширений, которые можно назначить администратору. +// ** Значение - Булево - Истина. +// +Функция СтандартныеРолиРасширений() Экспорт + + Возврат Справочники.ПрофилиГруппДоступа.СтандартныеРолиРасширений(); + +КонецФункции + +#КонецОбласти + +#Область УниверсальноеОграничение + +#Область ОбработчикиПодписокНаСобытия + +// Обработчик подписок ПроверитьДоступПередЗаписью* проверяет доступ к старой версии объекта, проверяет +// изменение полей объектов дополнительных таблиц, присоединенных в ограничениях доступа списков. +// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа +// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередЗаписью. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// +// РежимЗаписи - РежимЗаписиДокумента - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это ДокументОбъект. +// +// РежимПроведения - РежимПроведенияДокумента - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это ДокументОбъект. +// +Процедура ПроверитьДоступПередЗаписью(Источник, Отказ, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, Ложь, Ложь); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПередЗаписьюНабораЗаписей* проверяет доступ к старой версии набора записей, +// проверяет изменение полей наборов записей дополнительных таблиц, присоединенных в ограничениях доступа списков. +// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа +// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. +// +// Параметры: +// Источник - РегистрСведенийНаборЗаписей +// - РегистрНакопленияНаборЗаписей +// - РегистрБухгалтерииНаборЗаписей +// - РегистрРасчетаНаборЗаписей +// - ПерерасчетНаборЗаписей - набор записей, передаваемый в подписку +// на событие ПередЗаписью. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// Замещение - РежимЗамещения, Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// +// ТолькоЗапись - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьФактическогоПериодаДействия - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьПерерасчетов - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +Процедура ПроверитьДоступПередЗаписьюНабораЗаписей(Источник, Отказ, Замещение, + ТолькоЗапись = Неопределено, + ЗаписьФактическогоПериодаДействия = Неопределено, + ЗаписьПерерасчетов = Неопределено) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, Истина, Замещение); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПриЗаписи* проверяет устаревание ключа доступа +// новой версии объекта. Обновляет устаревший ключ доступа и, в этом случае, +// выполняет проверку прав Чтение и Изменение новой версии объекта. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПриЗаписи. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПриЗаписи. +// +Процедура ПроверитьДоступПриЗаписи(Источник, Отказ) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, Ложь, Ложь); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПриЗаписиНабораЗаписей* проверяет устаревание ключей доступа +// новой версии набора записей. Обновляет устаревшие ключи доступа и, в этом случае, +// выполняет проверку прав Чтение и Изменение новой версии набора записей. +// +// Параметры: +// Источник - РегистрСведенийНаборЗаписей +// - РегистрНакопленияНаборЗаписей +// - РегистрБухгалтерииНаборЗаписей +// - РегистрРасчетаНаборЗаписей +// - ПерерасчетНаборЗаписей - набор записей, передаваемый в подписку +// на событие ПриЗаписи. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПриЗаписи. +// Замещение - РежимЗамещения, Булево - параметр, передаваемый в подписку на событие ПриЗаписи. +// +// ТолькоЗапись - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьФактическогоПериодаДействия - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьПерерасчетов - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +Процедура ПроверитьДоступПриЗаписиНабораЗаписей(Источник, Отказ, Замещение, + ТолькоЗапись = Неопределено, + ЗаписьФактическогоПериодаДействия = Неопределено, + ЗаписьПерерасчетов = Неопределено) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, Истина, Замещение); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПередУдалением* проверяет +// изменение полей объектов дополнительных таблиц, присоединенных в ограничениях доступа списков. +// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа +// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередУдалением. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередУдалением. +// +Процедура ПроверитьДоступПередУдалением(Источник, Отказ) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПередУдалениемИсточника(Источник, Отказ); + +КонецПроцедуры + +#КонецОбласти + +#Область УниверсальноеОграничениеДоступа + +// Параметры: +// ОписаниеДанных - см. УправлениеДоступом.ИзменениеРазрешено.ОписаниеДанных +// ПравоИзменение - Булево +// ВызыватьИсключение - Булево +// ПроверитьТолькоСтаруюВерсию - Булево +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - Неопределено - проверить для текущего пользователя. +// +// Возвращаемое значение: +// Булево +// +Функция ДоступРазрешен(ОписаниеДанных, ПравоИзменение, ВызыватьИсключение = Ложь, + ПроверитьТолькоСтаруюВерсию = Ложь, Знач Пользователь = Неопределено) Экспорт + + УчитыватьПривилегированныйРежим = Истина; + ПользовательИБ = Неопределено; + + Если Пользователь <> Неопределено + И Пользователь = Пользователи.АвторизованныйПользователь() Тогда + + Пользователь = Неопределено; + УчитыватьПривилегированныйРежим = Ложь; + ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь(); + КонецЕсли; + + Если Пользователь = Неопределено + И Пользователи.ЭтоПолноправныйПользователь(,, УчитыватьПривилегированныйРежим) Тогда + Возврат Истина; + КонецЕсли; + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ОписаниеДанных)); + Если ОбъектМетаданных = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимое значение параметра %1 в %2. + |Ожидалась ссылка, объект, ключ записи или набор записей. + |Передано значение: %3 (тип %4).'"), + "ОписаниеДанных", + ?(ВызыватьИсключение, + ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", + "УправлениеДоступом.ПроверитьЧтениеРазрешено"), + ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", + "УправлениеДоступом.ЧтениеРазрешено")), + Строка(ОписаниеДанных), + Строка(ТипЗнч(ОписаниеДанных))); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ПроизводительныйВариант = УправлениеДоступом.ПроизводительныйВариант(); + + Если Пользователь <> Неопределено Тогда + ОбщегоНазначенияКлиентСервер.ПроверитьПараметр( + ?(ВызыватьИсключение, + ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", + "УправлениеДоступом.ПроверитьЧтениеРазрешено"), + ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", + "УправлениеДоступом.ЧтениеРазрешено")), + "Пользователь", + Пользователь, + Новый ОписаниеТипов("СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи")); + + Если Не ПроизводительныйВариант Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимое значение параметра %1 в %2. + |В стандартном варианте ограничения доступа поддерживается только %3. + |Передано значение: %4 (тип %5).'"), + "Пользователь", + ?(ВызыватьИсключение, + ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", + "УправлениеДоступом.ПроверитьЧтениеРазрешено"), + ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", + "УправлениеДоступом.ЧтениеРазрешено")), + "Неопределено", + Строка(Пользователь), + Строка(ТипЗнч(Пользователь))); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ВызыватьИсключение Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Вызов исключения поддерживается только для текущего пользователя. + |В %1 + |- либо недопустимое значение параметра %2 + |передано значение: %3 (тип %4), + |- либо недопустимое значение параметра %5 + |передано значение: %6 (тип %7).'"), + "УправлениеДоступом.ДоступРазрешен", + "ВызыватьИсключение", + Строка(ВызыватьИсключение), + Строка(ТипЗнч(ВызыватьИсключение)), + "Пользователь", + Строка(Пользователь), + Строка(ТипЗнч(Пользователь))); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Пользователи.ЭтоПолноправныйПользователь(Пользователь,, УчитыватьПривилегированныйРежим) Тогда + Возврат Истина; + КонецЕсли; + + ИдентификаторПользователяИБ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователь, + "ИдентификаторПользователяИБ"); + + Если ТипЗнч(ИдентификаторПользователяИБ) <> Тип("УникальныйИдентификатор") Тогда + Возврат Ложь; + КонецЕсли; + + ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( + ИдентификаторПользователяИБ); + + Если ПользовательИБ = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + ЛюбойОбъект = ОписаниеДанных; // СправочникОбъект + + Если Не ПравоИзменение Тогда + ИмяПраваДоступа = "Чтение"; + + ИначеЕсли ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ОбъектМетаданных) + И Не ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ЛюбойОбъект)) + И ЛюбойОбъект.ЭтоНовый() Тогда + + ИмяПраваДоступа = "Добавление"; + Иначе + ИмяПраваДоступа = "Изменение"; + КонецЕсли; + + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + СписокПолей = УправлениеДоступомСлужебныйПовтИсп.СписокВсехПолейОграниченияДоступа(ПолноеИмя); + + Если ВызыватьИсключение Тогда + ВыполнитьПроверкуПравДоступа(ИмяПраваДоступа, ОбъектМетаданных); + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей); + + ИначеЕсли ПользовательИБ = Неопределено Тогда + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей); + + ИначеЕсли Пользователь = Неопределено Тогда + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей, ПользовательИБ); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + Иначе + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей, ПользовательИБ); + КонецЕсли; + Если Не ПараметрыДоступа.Доступность Тогда + Возврат Ложь; + ИначеЕсли Не ПараметрыДоступа.ОграничениеУсловием Тогда + Возврат Истина; + КонецЕсли; + + Если УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа(Пользователь) Тогда + Возврат Истина; + КонецЕсли; + + Если Не ПроизводительныйВариант Тогда + Возврат ЧтениеДоступно(ПолноеИмя, ОбъектМетаданных, ОписаниеДанных, ВызыватьИсключение); + КонецЕсли; + + Если ЗначениеЗаполнено(Пользователь) Тогда + ДляВнешнихПользователей = ТипЗнч(Пользователь) = Тип("СправочникСсылка.ВнешниеПользователи"); + Иначе + ДляВнешнихПользователей = Неопределено; + КонецЕсли; + Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + + ИдентификаторТранзакции = Новый УникальныйИдентификатор; + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, ДляВнешнихПользователей); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(); + + Если ПараметрыОграничения.ОграничениеОтключено + Или Не ПравоИзменение + И ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда + + Возврат Истина; + КонецЕсли; + + СтараяВерсия = Истина; + ПравоИзменения = Ложь; + ЭтоНовый = Ложь; + + Если ПараметрыОграничения.ДоступЗапрещен Тогда + ДоступРазрешен = Ложь; + Иначе + Запрос = Новый Запрос; + УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос, Пользователь); + + Запрос.Текст = ?(ПравоИзменение, ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение, + ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение); + + Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда + СсылкаНаОбъект = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеДанных)), + ОписаниеДанных, ОписаниеДанных.Ссылка); + Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект); + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); + КонецЕсли; + Если ОписаниеДанных = СсылкаНаОбъект Или ЗначениеЗаполнено(СсылкаНаОбъект) Тогда + ДоступРазрешен = Не Запрос.Выполнить().Пустой(); + Иначе + ДоступРазрешен = Истина; + КонецЕсли; + + Если Не ДоступРазрешен Тогда + ДанныеДляПредставления = СсылкаНаОбъект; + + ИначеЕсли ОписаниеДанных <> СсылкаНаОбъект И Не ПроверитьТолькоСтаруюВерсию Тогда + СтараяВерсия = Ложь; + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + ПоляЧерезТочку = СтрРазделить(ПараметрыОграничения.ПолеВладельца.Имя, ".", Ложь); + ПолеОбъекта = ПоляЧерезТочку[0]; + ЗначениеПоляОбъекта = ОписаниеДанных[ПолеОбъекта]; + Если ПоляЧерезТочку.Количество() = 1 Тогда + ПараметрИзПамяти = "&Владелец"; + Иначе + ОбъектМетаданныхПоТипу = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеПоляОбъекта)); + Если ОбъектМетаданныхПоТипу = Неопределено Тогда + ПараметрИзПамяти = "&Владелец"; + ЗначениеПоляОбъекта = Null; + Иначе + ПоляЧерезТочку.Удалить(0); + ПараметрИзПамяти = "ВЫРАЗИТЬ(&Владелец КАК " + ОбъектМетаданныхПоТипу.ПолноеИмя() + + ")." + СтрСоединить(ПоляЧерезТочку, "."); // @query-part-1 + КонецЕсли; + КонецЕсли; + Запрос.Текст = СтрЗаменить(Запрос.Текст, + ПараметрыОграничения.ПолеОбъектаВладельцаВЗапросеПроверкиПрав, ПараметрИзПамяти); + Запрос.УстановитьПараметр("Владелец", ЗначениеПоляОбъекта); + Иначе + МодельОбъектовВПамяти = МодельОбъектовВПамяти(ОписаниеДанных, ПараметрыОграничения); + ПараметрыОбновления = Новый Структура(ПараметрыОграничения); + ПараметрыОбновления.Вставить("МодельОбъектовВПамяти", МодельОбъектовВПамяти); + ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); + ПараметрыОбновления.Вставить("ИдентификаторСписка", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); + ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(МодельОбъектовВПамяти.ЭлементыДанных, ПараметрыОбновления); + Запрос.УстановитьПараметр("КлючиДоступаКОбъектам", МодельОбъектовВПамяти.КлючиДоступаКОбъектам); + Запрос.УстановитьПараметр("Объект", МодельОбъектовВПамяти.ЭлементыДанных[0].ТекущаяСсылка); + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК Объект, + | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, + | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей + |ПОМЕСТИТЬ РегистрСведений_КлючиДоступаКОбъектам + |ИЗ + | &КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам"; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "РегистрСведений.КлючиДоступаКОбъектам", + "РегистрСведений_КлючиДоступаКОбъектам"); + Запрос.Текст = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + КонецЕсли; + ПроверкаДобавления = Ложь; + ТекстЗапросаИзменения = Запрос.Текст; + ЭтоНовый = ОписаниеДанных.ЭтоНовый(); + УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления); + ДоступРазрешен = Не Запрос.Выполнить().Пустой(); + Если Не ДоступРазрешен И ПроверкаДобавления Тогда + Запрос.Текст = ТекстЗапросаИзменения; + ПравоИзменения = Не Запрос.Выполнить().Пустой(); + КонецЕсли; + ДанныеДляПредставления = ОписаниеДанных; + КонецЕсли; + Иначе + НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); + ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей); + + Замещение = Неопределено; + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос, Замещение); + ТекстЗапроса = Запрос.Текст; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборПоИзмерениям", ОтборПоИзмерениям); + ДоступРазрешен = Запрос.Выполнить().Пустой(); + + Если ДоступРазрешен + И ТипЗнч(ОписаниеДанных) = ТипЗнч(НаборЗаписей) + И Не ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) + И Не ПроверитьТолькоСтаруюВерсию Тогда + + СтараяВерсия = Ложь; + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + ПолеВладельца = ПараметрыОграничения.ПолеВладельца.Имя; + Комбинации = ОписаниеДанных.Выгрузить(, ПолеВладельца); // ТаблицаЗначений + Комбинации.Свернуть(ПолеВладельца); + Запрос.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", Комбинации); + ТекстЗапросаПодготовкиКомбинаций = "ВЫБРАТЬ ТекущаяТаблица." + ПолеВладельца + " + |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей + |ИЗ &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"; // @query-part-1, @query-part-2 + Иначе + ТекстЗапросаПодготовкиКомбинаций = "ВЫБРАТЬ ТекущаяТаблица." + + СтрСоединить(ПараметрыОграничения.ОпорныеПоля.Используемые, ", + | ТекущаяТаблица.") + " + |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей + |ИЗ &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"; // @query-part-1, @query-part-2, @query-part-3 + ОписаниеДанных.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", + ИдентификаторТранзакции); + ОбновитьКлючиДоступаКНаборуЗаписей(ОписаниеДанных, Ложь, Ложь, + ИдентификаторТранзакции, ПараметрыОграничения, "", Запрос); + ОписаниеДанных.ДополнительныеСвойства.Удалить("УправлениеДоступомИдентификаторТранзакции"); + КонецЕсли; + Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", "ИСТИНА"); + ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(ОписаниеДанных)).ПолноеИмя(); + Запрос.Текст = ТекстЗапросаПодготовкиКомбинаций + ОбщегоНазначения.РазделительПакетаЗапросов() + + СтрЗаменить(Запрос.Текст, ПолноеИмяРегистра + " КАК ТекущаяТаблица", + "КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"); // @query-part-1 @query-part-2 + + ДоступРазрешен = Запрос.Выполнить().Пустой(); + КонецЕсли; + ДанныеДляПредставления = НаборЗаписей; + КонецЕсли; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Если ДоступРазрешен Или Не ВызыватьИсключение Тогда + Возврат ДоступРазрешен; + КонецЕсли; + + Если ПравоИзменение Тогда + ПравоЧтения = ДоступРазрешен(ОписаниеДанных, Ложь); + Иначе + ПравоЧтения = Ложь; + КонецЕсли; + + СообщитьОбОшибкеДоступа(ДанныеДляПредставления, СтараяВерсия, ПравоЧтения, ПравоИзменения, ЭтоНовый); + + Возврат Ложь; + +КонецФункции + +// Для функции ДоступРазрешен. +Функция ЧтениеДоступно(ПолноеИмя, ОбъектМетаданных, ОписаниеДанных, ВызыватьИсключение) + + Запрос = Новый Запрос; + + Если ЭтоСсылочныйТипТаблицы(ПолноеИмя) Тогда + СсылкаНаОбъект = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеДанных)), + ОписаниеДанных, ОписаниеДанных.Ссылка); + + Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект); + ТекстЗапроса = + "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Ссылка = &Ссылка"; + Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя); + Если Не Запрос.Выполнить().Пустой() Тогда + Возврат Истина; + КонецЕсли; + ДанныеДляПредставления = СсылкаНаОбъект; + Иначе + НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); + ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей); + + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос); + ТекстЗапроса = + "ВЫБРАТЬ РАЗРЕШЕННЫЕ + | КОЛИЧЕСТВО(1) КАК КоличествоДанных + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", ОтборПоИзмерениям); + Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя); + + УстановитьПривилегированныйРежим(Истина); + Выборка = Запрос.Выполнить().Выбрать(); + УстановитьПривилегированныйРежим(Ложь); + ВсегоДанных = ?(Выборка.Следующий(), Выборка.КоличествоДанных, 0); + + Выборка = Запрос.Выполнить().Выбрать(); + ДоступноДанных = ?(Выборка.Следующий(), Выборка.КоличествоДанных, 0); + + Если ВсегоДанных = ДоступноДанных Тогда + Возврат Истина; + КонецЕсли; + ДанныеДляПредставления = НаборЗаписей; + КонецЕсли; + + Если Не ВызыватьИсключение Тогда + Возврат Ложь; + КонецЕсли; + + СообщитьОбОшибкеДоступа(ДанныеДляПредставления, Истина, Ложь, Ложь, Ложь); + + Возврат Ложь; + +КонецФункции + +// См. УправлениеДоступом.ПраваДоступаКДанным +Функция ПраваДоступаКДанным(ОписаниеДанных, ДляВнешнихПользователей, СоставПользователей) Экспорт + + Если ТипЗнч(ДляВнешнихПользователей) <> Тип("Булево") Тогда + Результат1 = ПраваДоступаКДанным(ОписаниеДанных, Ложь, СоставПользователей); + Результат2 = ПраваДоступаКДанным(ОписаниеДанных, Истина, СоставПользователей); + Для Каждого СтрокаТЗ Из Результат2 Цикл + ЗаполнитьЗначенияСвойств(Результат1.Добавить(), СтрокаТЗ); + КонецЦикла; + Возврат Результат1; + КонецЕсли; + + Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда + ТекстОшибки = НСтр("ru = 'Недостаточно прав доступа.'"); + ДляАдминистратора = НСтр("ru = 'Нужны полные права или привилегированный режим.'"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа,, ДляАдминистратора); + КонецЕсли; + + Если Не УправлениеДоступом.ПроизводительныйВариант() Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Функция %1 не поддерживается в стандартном варианте ограничения доступа.'"), + "УправлениеДоступом.ПраваДоступаКДанным"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда + ЭлементДанных = ?(ОписаниеДанных.Количество() > 0, ОписаниеДанных[0], + "<" + НСтр("ru = 'Пустой массив'") + ">"); + Иначе + ЭлементДанных = ОписаниеДанных; + КонецЕсли; + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ЭлементДанных)); + Если ОбъектМетаданных = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимое значение параметра %1 в %2. + |Ожидалась ссылка, ключ записи, набор записей или непустой массив ссылок одного типа. + |Передано значение: %3 (тип %4).'"), + "ОписаниеДанных", + "УправлениеДоступом.ПраваДоступаКДанным", + Строка(ЭлементДанных), + Строка(ТипЗнч(ОписаниеДанных))); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, + Новый УникальныйИдентификатор, ДляВнешнихПользователей); + + Если ДляВнешнихПользователей + И Не Константы.ИспользоватьВнешнихПользователей.Получить() Тогда + + Возврат ПодготовленныйРезультат(ПараметрыОграничения); + КонецЕсли; + + Запрос = Новый Запрос; + ДобавитьЗапросПроверяемыхПользователей(Запрос, ДляВнешнихПользователей, СоставПользователей); + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + Запрос.УстановитьПараметр("ИдентификаторОбъектаМетаданных", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных)); + + Если ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ОграничениеОтключено Тогда + + ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, + ?(ПараметрыОграничения.ДоступЗапрещен, "ТолькоПраваБезОграничения", "ПраваСОграничением"), + ?(СоставПользователей = Неопределено, "", "ПроверяемыеПользователи"), + "ПользователиСПравамиНаТаблицу"); + + ТекстЗапросаПравСДанными = Неопределено; + ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, ТекстЗапросаПравСДанными); + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаПравСДанными; + + Возврат ПодготовленныйРезультат(ПараметрыОграничения, Запрос); + КонецЕсли; + + ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, + ?(ПараметрыОграничения.ОграничениеЧтенияОтключено, "ОграничениеЧтенияОтключено", "ТолькоПраваБезОграничения"), + ?(СоставПользователей = Неопределено, "", "ПроверяемыеПользователи"), + "ПользователиСПравамиБезОграниченияНаТаблицу"); + + ТекстЗапросаПравСДанными = ""; + ОтборПоИзмерениям = ""; + ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, + ТекстЗапросаПравСДанными, ОтборПоИзмерениям); + + ТекстЗапроса = ПараметрыОграничения.ТекстЗапросаПравПользователей; + + Если СоставПользователей <> Неопределено Тогда + ОтборПользователей = СтрШаблон( + "ВЫРАЗИТЬ(НаборыПользователей.Пользователь КАК %1) В + | (ВЫБРАТЬ + | ПроверяемыеПользователи.ПользовательСПравом + | ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи)", + ?(ДляВнешнихПользователей, "Справочник.ВнешниеПользователи", "Справочник.Пользователи")); + Иначе + ОтборПользователей = "ИСТИНА"; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПользователей1", + ТекстСОтступом(ОтборПользователей, " ")); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПользователей2", ТекстСОтступом( + СтрЗаменить(ОтборПользователей, "НаборыПользователей.Пользователь", "СоставыГруппПользователей.Пользователь"), + " ")); + + Если Не ПараметрыОграничения.ЭтоСсылочныйТип + И Не ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", + ТекстСОтступом(ОтборПоИзмерениям, " ")); + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + + Запрос.УстановитьПараметр("РазрешенныйПустойНаборГруппДоступа", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); + КонецЕсли; + + ДобавитьЗапросПользователейИзПравНаЭлементыДанных(Запрос, ПараметрыОграничения, СоставПользователей); + + ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, + "ПраваСОграничением", + "ПользователиИзПравНаЭлементыДанных", + "ПользователиСПравамиСОграничениемНаТаблицу"); + + ДобавитьИтоговыйЗапросПравПользователей(Запрос, ПараметрыОграничения, ТекстЗапросаПравСДанными, ОтборПоИзмерениям); + + Возврат ПодготовленныйРезультат(ПараметрыОграничения, Запрос); + +КонецФункции + +// Для функций ДоступРазрешен, ЧтениеРазрешено, ПраваДоступаКДанным. +Функция ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмяРегистра, НовыйПустойНаборЗаписей, + ПраваДоступаКДанным = Ложь) + + Если ТипЗнч(ОписаниеДанных) <> ТипЗнч(НовыйПустойНаборЗаписей) Тогда + // КлючЗаписи. + ОтборЗаписей = Новый Массив; + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + ОтборЗаписей.Добавить(Новый Структура("Имя, Значение, Использование", + ОписаниеПоля.Имя, ОписаниеДанных[ОписаниеПоля.Имя], Истина)); + КонецЦикла; + Возврат ОтборЗаписей; + КонецЕсли; + + Если Не ПраваДоступаКДанным Тогда + Возврат ОписаниеДанных; + КонецЕсли; + + ЕстьОтбор = Ложь; + Для Каждого ЭлементОтбора Из ОписаниеДанных.Отбор Цикл + Если ЭлементОтбора.Использование Тогда + ЕстьОтбор = Истина; + КонецЕсли; + КонецЦикла; + + Возврат ?(ЕстьОтбор, ОписаниеДанных.Отбор, Неопределено); + +КонецФункции + +// Для функции ПраваДоступаКДанным. +Функция ПодготовленныйРезультат(ПараметрыОграничения, Запрос = Неопределено); + + ПолноеИмя = ПараметрыОграничения.Список; + + Если Запрос = Неопределено Тогда + ТипПользователь = Новый ОписаниеТипов("СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи"); + Результат = Новый ТаблицаЗначений; + Результат.Колонки.Добавить("ПользовательСПравом", ТипПользователь); + Результат.Колонки.Добавить("ПравоИзменение", Новый ОписаниеТипов("Булево")); + Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда + ТипСсылки = ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); + Результат.Колонки.Добавить("Ссылка", + Новый ОписаниеТипов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки))); + Иначе + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + Результат.Колонки.Добавить(ОписаниеПоля.Имя, ОписаниеПоля.Тип); + КонецЦикла; + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) КАК ПользовательСПравом, + | ЛОЖЬ КАК ПравоИзменение, + | НЕОПРЕДЕЛЕНО КАК Ссылка + |ГДЕ + | ЛОЖЬ + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка), + | ЛОЖЬ, + | НЕОПРЕДЕЛЕНО КАК Ссылка + |ГДЕ + | ЛОЖЬ"; + Если Не ПараметрыОграничения.ЭтоСсылочныйТип Тогда + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); + ИзмеренияДляВыбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + ИзмеренияДляВыбора.Добавить("НЕОПРЕДЕЛЕНО"); // @query-part-1 + КонецЦикла; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "НЕОПРЕДЕЛЕНО КАК Ссылка", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); // @query-part-1 + КонецЕсли; + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.ТекстОбъединитьВсе() + ТекстЗапроса; + Результат = Запрос.Выполнить().Выгрузить(); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Процедура ДобавитьЗапросПроверяемыхПользователей(Запрос, ДляВнешнихПользователей, СоставПользователей) + + Если СоставПользователей = Неопределено Тогда + Возврат; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПроверяемыеПользователи.Пользователь КАК ПользовательСПравом + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | &ПроверяемыеПользователи КАК ПроверяемыеПользователи + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + + ПроверяемыеПользователи = Новый ТаблицаЗначений; + ТипПользователя = ?(ДляВнешнихПользователей, Тип("СправочникСсылка.ВнешниеПользователи"), + Тип("СправочникСсылка.Пользователи")); + ПроверяемыеПользователи.Колонки.Добавить("Пользователь", Новый ОписаниеТипов( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипПользователя))); + + Для Каждого Пользователь Из СоставПользователей Цикл + Если ТипЗнч(Пользователь) = ТипПользователя И ЗначениеЗаполнено(Пользователь) Тогда + ПроверяемыеПользователи.Добавить().Пользователь = Пользователь; + КонецЕсли; + КонецЦикла; + + Запрос.УстановитьПараметр("ПроверяемыеПользователи", ПроверяемыеПользователи); + Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(Запрос.Текст), + ОбщегоНазначения.РазделительПакетаЗапросов(), "") + ТекстЗапроса; + +КонецПроцедуры + +Процедура ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, ВариантПрав, + ИмяВременнойТаблицыПроверяемыхПользователей = "", ИмяВременнойТаблицыРезультата = "") + + Если ИмяВременнойТаблицыПроверяемыхПользователей = "" Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | СписокПользователей.Ссылка КАК ПользовательСПравом, + | МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение) КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Ссылка = ТаблицыГруппДоступа.ГруппаДоступа) + | И (ТаблицыГруппДоступа.Таблица = &ИдентификаторОбъектаМетаданных) + | И (&ОтборПрав) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей + | ПО (СписокПользователей.Ссылка = СоставыГруппПользователей.Пользователь) + | И (СписокПользователей.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (НЕ СписокПользователей.ПометкаУдаления) + | И (НЕ СписокПользователей.Недействителен) + | И (НЕ СписокПользователей.Служебный) + | + |СГРУППИРОВАТЬ ПО + | СписокПользователей.Ссылка"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПроверяемыеПользователи.ПользовательСПравом КАК ПользовательСПравом, + | МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение) КАК ПравоИзменение + |ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей + | ПО (СписокПользователей.Ссылка = ПроверяемыеПользователи.ПользовательСПравом) + | И (СписокПользователей.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (НЕ СписокПользователей.ПометкаУдаления) + | И (НЕ СписокПользователей.Недействителен) + | И (НЕ СписокПользователей.Служебный) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.Пользователь = СписокПользователей.Ссылка) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ПО (ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступаПользователи.Ссылка) + | И (ТаблицыГруппДоступа.Таблица = &ИдентификаторОбъектаМетаданных) + | И (&ОтборПрав) + | + |СГРУППИРОВАТЬ ПО + | ПроверяемыеПользователи.ПользовательСПравом"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПроверяемыеПользователи КАК", + ИмяВременнойТаблицыПроверяемыхПользователей + " КАК"); // @query-part-1, @query-part-2 + КонецЕсли; + + Если ИмяВременнойТаблицыРезультата <> "" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КАК ПравоИзменение", + "КАК ПравоИзменение + |ПОМЕСТИТЬ " + ИмяВременнойТаблицыРезультата); // @query-part-1, @query-part-2 + КонецЕсли; + + Если ПараметрыОграничения.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СписокПользователей.Недействителен", "ЛОЖЬ"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СписокПользователей.Служебный", "ЛОЖЬ"); + КонецЕсли; + + Если ВариантПрав = "ПраваСОграничением" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", "ИСТИНА"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение)", + "МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменениеБезОграничения)"); // @query-part-1, @query-part-2 + + Если ВариантПрав = "ОграничениеЧтенияОтключено" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", "ИСТИНА"); + Иначе // ТолькоПраваБезОграничения + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", + "ТаблицыГруппДоступа.ПравоЧтениеБезОграничения"); + КонецЕсли; + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(Запрос.Текст), + ОбщегоНазначения.РазделительПакетаЗапросов(), "") + ТекстЗапроса; + +КонецПроцедуры + +Процедура ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, + ТекстЗапросаПравСДанными = Неопределено, ОтборПоИзмерениям = Неопределено) + + ТекущаяТаблица = Новый ТаблицаЗначений; + ПолноеИмя = ПараметрыОграничения.Список; + + Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ТекущаяТаблица + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица"; + + ТипСсылки = ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); + ТекущаяТаблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки))); + + Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда + Для Счетчик = 1 По ОписаниеДанных.Количество() Цикл + ТекущаяТаблица.Добавить(); + КонецЦикла; + ТекущаяТаблица.ЗагрузитьКолонку(ОписаниеДанных, "Ссылка"); + Иначе + ТекущаяТаблица.Добавить().Ссылка = ОписаниеДанных; + КонецЕсли; + Запрос.УстановитьПараметр("ТекущаяТаблица", ТекущаяТаблица); + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + + Если ТекстЗапросаПравСДанными = Неопределено Тогда + ТекстЗапросаПравСДанными = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ПользователиСПравамиНаТаблицу КАК ПраваПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица + | ПО ИСТИНА"; + КонецЕсли; + + Возврат; + + КонецЕсли; + + НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); + ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей, Истина); + + ОтборПоИзмерениям = ?(ОтборЗаписей = Неопределено, "ИСТИНА", + ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос)); + + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); + + Если ЗначениеЗаполнено(ОписаниеДанных) И ОтборЗаписей = Неопределено Тогда + ИзмеренияДляВыбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %1", ОписаниеПоля.Имя)); // @query-part-1 + КонецЦикла; + ТекстЗапросаКлючейЗаписей = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.Поле1 КАК Поле1 + |ПОМЕСТИТЬ КлючиЗаписейРегистра + |ИЗ + | &КлючиЗаписейРегистра КАК ТекущаяТаблица"; + ТекстЗапросаКлючейЗаписей = СтрЗаменить(ТекстЗапросаКлючейЗаписей, + "ТекущаяТаблица.Поле1 КАК Поле1", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); // @query-part-1 + Запрос.УстановитьПараметр("КлючиЗаписейРегистра", + ОписаниеДанных.Выгрузить(, ОписаниеКлючаЗаписи.СписокПолей)); + + ОтборПоИзмерениям = + "ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | КлючиЗаписейРегистра КАК КлючиЗаписейРегистра + | ГДЕ + | КлючиЗаписейРегистра.Поле1 = ТекущаяТаблица.Поле1)"; // @query-part-1 + УсловияОтбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + УсловияОтбора.Добавить(СтрШаблон("КлючиЗаписейРегистра.%1 = ТекущаяТаблица.%1", ОписаниеПоля.Имя)); + КонецЦикла; + ОтборПоИзмерениям = СтрЗаменить(ОтборПоИзмерениям, + "КлючиЗаписейРегистра.Поле1 = ТекущаяТаблица.Поле1", + СтрСоединить(УсловияОтбора, " + | И ")); // @query-part-1, @query-part-2 + КонецЕсли; + + Если ТекстЗапросаПравСДанными = Неопределено Тогда + ТекстЗапросаПравСДанными = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ПользователиСПравамиНаТаблицу КАК ПраваПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаРегистра КАК ТекущаяТаблица + | ПО (&ОтборПоИзмерениям)"; + + ИначеЕсли ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + ОпорноеПолеВладельца = СтрРазделить(ПараметрыОграничения.ПолеВладельца.Имя, ".").Получить(0); + ТекстЗапросаВладельца = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.ОпорноеПолеВладельца КАК Ссылка + |ПОМЕСТИТЬ ТекущаяТаблица + |ИЗ + | &ТаблицаРегистра КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям"; + ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "ОпорноеПолеВладельца", ОпорноеПолеВладельца); + ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "&ТаблицаРегистра", ПолноеИмя); + ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "&ОтборПоИзмерениям", ОтборПоИзмерениям); + + ТекстЗапросаПравСДанными = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ПраваПользователейНаЗаписиРегистраПоВладельцу КАК ПраваПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаРегистра КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.ОпорноеПолеВладельца = ПраваПользователей.Ссылка) + | И (&ОтборПоИзмерениям)"; + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, + "ОпорноеПолеВладельца", ОпорноеПолеВладельца); + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаПравСДанными) Тогда + ИзмеренияДляВыбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + УточненноеИмя = УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ОписаниеПоля.Имя); + ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %2", ОписаниеПоля.Имя, УточненноеИмя)); // @query-part-1 + КонецЦикла; + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, "&ТаблицаРегистра", ПолноеИмя); + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, "&ОтборПоИзмерениям", + ТекстСОтступом(ОтборПоИзмерениям, " ")); + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, + "ТекущаяТаблица.Поле1 КАК Поле1", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); // @query-part-1 + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаКлючейЗаписей) Тогда + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаКлючейЗаписей; + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаВладельца) Тогда + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаВладельца; + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьЗапросПользователейИзПравНаЭлементыДанных(Запрос, ПараметрыОграничения, СоставПользователей) + + Если СоставПользователей = Неопределено Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ВсеПользователиИзПрав.ПользовательСПравом КАК ПользовательСПравом + |ПОМЕСТИТЬ ПользователиИзПравНаЭлементыДанных + |ИЗ + | (ВЫБРАТЬ + | ВЫРАЗИТЬ(ПользователиСПравами.ПользовательСПравом КАК Справочник.Пользователи) КАК ПользовательСПравом + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ГДЕ + | ТИПЗНАЧЕНИЯ(ПользователиСПравами.ПользовательСПравом) = ТИП(Справочник.Пользователи) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СписокПользователей.Ссылка + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей + | ПО (ПользователиСПравами.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ВсеПользователиИзПрав"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ВсеПользователиИзПрав.ПользовательСПравом КАК ПользовательСПравом + |ПОМЕСТИТЬ ПользователиИзПравНаЭлементыДанных + |ИЗ + | (ВЫБРАТЬ + | ВЫРАЗИТЬ(ПользователиСПравами.ПользовательСПравом КАК Справочник.Пользователи) КАК ПользовательСПравом + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ГДЕ + | ТИПЗНАЧЕНИЯ(ПользователиСПравами.ПользовательСПравом) = ТИП(Справочник.Пользователи) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ПроверяемыеПользователи.ПользовательСПравом + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПроверяемыеПользователи КАК ПроверяемыеПользователи + | ПО (ПользователиСПравами.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ВсеПользователиИзПрав"; + КонецЕсли; + + Если ПараметрыОграничения.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + +КонецПроцедуры + +Процедура ДобавитьИтоговыйЗапросПравПользователей(Запрос, ПараметрыОграничения, + ТекстЗапросаПравСДанными, ОтборПоИзмерениям) + + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | МАКСИМУМ(ПраваПользователей.ПравоИзменение) КАК ПравоИзменение, + | ПраваПользователей.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ПраваНаТаблицу.ПользовательСПравом КАК ПользовательСПравом, + | ПраваНаТаблицу.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + | ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиБезОграниченияНаТаблицу КАК ПраваНаТаблицу + | ПО (&ОтборПоИзмерениям) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ПраваНаТаблицу.ПользовательСПравом, + | ПраваНаТаблицу.ПравоИзменение + | И ТекущаяТаблица.ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + | ИЗ + | ПользователиСПравамиСОграничениемНаТаблицу КАК ПраваНаТаблицу + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиНаЭлементыДанных КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.ПользовательСПравом = ПраваНаТаблицу.ПользовательСПравом) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ПраваНаТаблицу.ПользовательСПравом, + | ПраваНаТаблицу.ПравоИзменение + | И ТекущаяТаблица.ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + | ИЗ + | ПользователиСПравамиСОграничениемНаТаблицу КАК ПраваНаТаблицу + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиНаЭлементыДанных КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ПраваПользователей + | + |СГРУППИРОВАТЬ ПО + | ПраваПользователей.Ссылка, + | ПраваПользователей.ПользовательСПравом"; + + Если Не ПараметрыОграничения.ЭтоСсылочныйТип + И ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка КАК Ссылка", + "ПраваПользователей.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПраваПользователейНаЗаписиРегистраПоВладельцу"); // @query-part-1, @query-part-2 + + ТекстЗапроса = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаПравСДанными; + + ИначеЕсли Не ПараметрыОграничения.ЭтоСсылочныйТип Тогда + + УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, ПараметрыОграничения.Список); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекущаяТаблица КАК ТекущаяТаблица", + ПараметрыОграничения.Список + " КАК ТекущаяТаблица"); // @query-part-1, @query-part-2 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", + ТекстСОтступом(ОтборПоИзмерениям, " ")); + КонецЕсли; + + Если ПараметрыОграничения.ЭтоСсылочныйТип + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", "ИСТИНА"); + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + +КонецПроцедуры + +// Требуется, как начальная максимальная дата при планировании начального обновления доступа. +// +// Возвращаемое значение: +// Дата +// +Функция МаксимальнаяДата() Экспорт + + Возврат '39991231235959'; + +КонецФункции + +// Требуется, как начальная максимальная дата при планировании продолжения обновления доступа. +Функция МаксимальнаяДатаПриПродолжении() + + Возврат '39990101000000'; + +КонецФункции + +// Для функции НастройкиВнедрения. +Функция ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Возврат Свойства.ЯзыкАнглийский + "." + СоставИмени[1]; + +КонецФункции + +// Для процедуры ДобавитьТипыТребуемыеВОпределяемомТипе. +Функция ИмяТипаСсылки(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Если Не Свойства.ЭтоСсылочныйТип Тогда + Возврат ""; + КонецЕсли; + + Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда + ИмяТипа = Свойства.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS + Иначе + ИмяТипа = Свойства.ЯзыкАнглийский + "Ref." + СоставИмени[1]; + КонецЕсли; + + Возврат ИмяТипа; + +КонецФункции + +// Для функции НастройкиВнедрения. +Функция ИмяТипаСсылкиXML(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Если Свойства.ЭтоСсылочныйТип Тогда + Возврат Свойства.ЯзыкАнглийский + "Ref." + СоставИмени[1]; + КонецЕсли; + + Возврат ""; + +КонецФункции + +// Для функции ДобавитьТипыТребуемыеВОпределяемомТипе. +Функция ИмяТипаОбъектаИлиНабораЗаписей(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ИмяТипа = ""; + + Если Свойства.ЭтоСсылочныйТип Тогда + Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда + ИмяТипа = Свойства.ЯзыкРусский + "Объект." + СоставИмени[1]; // @Non-NLS + Иначе + ИмяТипа = Свойства.ЯзыкАнглийский + "Object." + СоставИмени[1]; + КонецЕсли; + КонецЕсли; + + Если СтрНачинаетсяС(Свойства.ИмяКоллекции, "Регистры") Тогда + Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда + ИмяТипа = Свойства.ЯзыкРусский + "НаборЗаписей." + СоставИмени[1]; // @Non-NLS + Иначе + ИмяТипа = Свойства.ЯзыкАнглийский + "RecordSet." + СоставИмени[1]; + КонецЕсли; + КонецЕсли; + + Возврат ИмяТипа; + +КонецФункции + +// Для функции НастройкиВнедрения. +Функция ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Если Свойства.ЭтоСсылочныйТип Тогда + Возврат Свойства.ЯзыкАнглийский + "Object." + СоставИмени[1]; + КонецЕсли; + + Если СтрНачинаетсяС(Свойства.ИмяКоллекции, "Регистры") Тогда + Возврат Свойства.ЯзыкАнглийский + "RecordSet." + СоставИмени[1]; + КонецЕсли; + + Возврат ""; + +КонецФункции + +// Для функции НастройкиВнедрения. +Процедура ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа) + + Если СтрНачинаетсяС(ИмяТипаОбъектаXML, "DocumentObject.") Тогда + ВладельцыЗначенийКлючейДоступа.Документы.Добавить(ИмяТипаОбъектаXML); + + ИначеЕсли СтрНачинаетсяС(ИмяТипаОбъектаXML, "CalculationRegisterRecordSet.") Тогда + ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета.Добавить(ИмяТипаОбъектаXML); + + ИначеЕсли СтрНайти(ИмяТипаОбъектаXML, "RecordSet.") > 0 Тогда + ВладельцыЗначенийКлючейДоступа.НаборыЗаписей.Добавить(ИмяТипаОбъектаXML); + + ИначеЕсли СтрНайти(ИмяТипаОбъектаXML, "Object.") > 0 Тогда + ВладельцыЗначенийКлючейДоступа.Объекты.Добавить(ИмяТипаОбъектаXML); + КонецЕсли; + +КонецПроцедуры + +// Для функции НастройкиВнедрения. +Процедура ДобавитьОграниченияВРолях(ПолноеИмяXML, ПолноеИмя, ОграниченияВРолях, СвойстваОграничений, Контекст) + + Свойства = СвойстваОграничений.Получить(ПолноеИмя); + Если Свойства <> Неопределено И Свойства.ДоступЗапрещен Тогда + Возврат; + КонецЕсли; + + ОграничениеВРоли = Новый Структура("ШаблонДляОбъекта, Параметры", Истина, Новый Массив); + ОграниченияВРолях.Вставить(ПолноеИмяXML, ОграничениеВРоли); + + Если Свойства = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Свойства.ПолеВладельца <> Неопределено Тогда + ПолеВладельца = Свойства.ПолеВладельца; // См. НовоеПолеВладельца + ОграничениеВРоли.Параметры.Добавить(ПолеВладельца.Имя); + Возврат; + КонецЕсли; + + Если Свойства.ОпорныеПоля = Неопределено + Или Не ЗначениеЗаполнено(Свойства.ОпорныеПоля) Тогда + Возврат; + КонецЕсли; + + ОграничениеВРоли.ШаблонДляОбъекта = Ложь; + + Если ЗначениеЗаполнено(Свойства.ИмяОтдельногоРегистраКлючей) Тогда + ПервыйПараметр = Свойства.ИмяОтдельногоРегистраКлючей; + + ДобавитьТипыИзмерения(Свойства.ИмяОтдельногоРегистраКлючей, + Свойства.ОпорныеПоля, ПолноеИмя, Контекст); + Иначе + ПервыйПараметр = + УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных(ПолноеИмя); + + ДобавитьТипыИзмерения("КлючиДоступаКРегистрам", + Свойства.ОпорныеПоля, ПолноеИмя, Контекст); + + Контекст.ПредопределенныеИдентификаторы.Вставить(ПервыйПараметр, ПолноеИмя); + КонецЕсли; + + ОграничениеВРоли.Параметры.Добавить(ПервыйПараметр); + + Для Каждого ОпорноеПоле Из Свойства.ОпорныеПоля.Все Цикл + ОграничениеВРоли.Параметры.Добавить(ОпорноеПоле); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьОграниченияВРолях. +Процедура ДобавитьТипыИзмерения(ИмяРегистраКлючей, ОпорныеПоля, ИмяИсходногоРегистра, Контекст) + + Если ОпорныеПоля.Все.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ТипыИзмерений = ТипыИзмеренийРегистраКлючей(Контекст.ТипыИзмеренийРегистровКлючей, ИмяРегистраКлючей); + ТипыТаблицПоИменам = Контекст.ТипыТаблицПоИменам; + + ИменаТипов = ТипыИзмерений.ИменаТипов; + ПоляРегистровПоТипам = ТипыИзмерений.ПоляРегистровПоТипам; + + ПоляРегистра = Новый Массив; + ТипыИзмерений.ПоляРегистров.Вставить(ИмяИсходногоРегистра, ПоляРегистра); + + Для Каждого ИмяПоля Из ОпорныеПоля.Все Цикл + ХранилищеТиповПоля = ОпорныеПоля.ТипыВсех[ОпорныеПоля.Все.Найти(ИмяПоля)]; // ХранилищеЗначения + ТипыПоля = ХранилищеТиповПоля.Получить(); + ПоляРегистра.Добавить(Новый Структура("Поле, Тип", ИмяПоля, ТипыПоля)); + Для Каждого Тип Из ТипыПоля.Типы() Цикл + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + Если ОбъектМетаданных = Неопределено Тогда + СинтаксисЯзыка = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка(); + ИмяТипа = СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(Тип)).ЯзыкАнглийский; + Иначе + ИмяТипа = ИмяТипаСсылкиXML(Метаданные.НайтиПоТипу(Тип).ПолноеИмя(), ТипыТаблицПоИменам); + КонецЕсли; + Если ИменаТипов.Найти(ИмяТипа) = Неопределено Тогда + ИменаТипов.Добавить(ИмяТипа); + КонецЕсли; + ПоляРегистровПоТипу = ПоляРегистровПоТипам.Получить(ИмяТипа); + Если ПоляРегистровПоТипу = Неопределено Тогда + ПоляРегистровПоТипу = Новый Массив; + ПоляРегистровПоТипам.Вставить(ИмяТипа, ПоляРегистровПоТипу); + КонецЕсли; + ПолноеИмяПоля = ИмяИсходногоРегистра + "." + ИмяПоля; + Если ПоляРегистровПоТипу.Найти(ПолноеИмяПоля) = Неопределено Тогда + ПоляРегистровПоТипу.Добавить(ПолноеИмяПоля); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для функции НастройкиВнедрения и процедуры ДобавитьТипыИзмерения. +Функция ТипыИзмеренийРегистраКлючей(ТипыИзмеренийРегистровКлючей, ИмяРегистраКлючей) + + ТипыИзмерений = ТипыИзмеренийРегистровКлючей.Получить(ИмяРегистраКлючей); + Если ТипыИзмерений = Неопределено Тогда + ТипыИзмерений = Новый Структура; + ТипыИзмерений.Вставить("ИменаТипов", Новый Массив); + ТипыИзмерений.Вставить("ПоляРегистров", Новый Соответствие); + ТипыИзмерений.Вставить("ПоляРегистровПоТипам", Новый Соответствие); + ТипыИзмеренийРегистровКлючей.Вставить(ИмяРегистраКлючей, ТипыИзмерений); + ТипыИзмерений.ИменаТипов.Добавить("EnumRef.ДополнительныеЗначенияДоступа"); + КонецЕсли; + + Возврат ТипыИзмерений; + +КонецФункции + +// Для функции ОграничиватьДоступНаУровнеЗаписейУниверсально. +Функция КонстантаПервоеОбновлениеДоступаЗавершилось() + + Возврат Не ВариантВстроенногоЯзыкаРусский() + Или Константы.ПервоеОбновлениеДоступаЗавершилось.Получить(); + +КонецФункции + +#КонецОбласти + +#Область ПроверкаДоступаПриИзменении + +// Для процедур ПроверитьДоступПередЗаписьюИсточника и др. +Процедура ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ() + + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); + Блокировка.Добавить("Справочник.КлючиДоступа"); + Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ГруппыЗначенийДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗначенияГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗначенияГруппДоступаПоУмолчанию"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НастройкиПравОбъектов"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НаследованиеНастроекПравОбъектов"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + Блокировка.Заблокировать(); + +КонецПроцедуры + +// Для процедур ПроверитьДоступПередЗаписьюИсточника и др. +Процедура ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ() + + Если ЭтоСеансФоновогоОбновленияДоступа() Тогда + Возврат; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Константа.КоличествоПотоковОбновленияДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + Блокировка.Заблокировать(); + +КонецПроцедуры + +// Для обработчиков подписок на событие ПередЗаписью. +Процедура ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, ЭтоНаборЗаписей, Замещение) + + Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + Возврат; + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Если Не ЭтоНаборЗаписей И Источник.ЭтоНовый() Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + Иначе + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + КонецЕсли; + + ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь() + Или УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа() + Или Не УправлениеДоступом.ПроизводительныйВариант(); + + Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", + Новый УникальныйИдентификатор); + + ЕстьСтараяВерсия = Не ЭтоНаборЗаписей И Не Источник.ЭтоНовый() + Или ЭтоНаборЗаписей + И Замещение <> Ложь + И Не ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение); + + Если ЕстьСтараяВерсия Тогда + ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, ЭтоНаборЗаписей, Замещение); + ПроверитьДоступКИсточнику(Источник, Истина, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь); + + ИначеЕсли Не ЭтоНаборЗаписей Тогда + УстановитьРазрешенныйКлючДоступаДляНовогоОбъекта(Источник, ЭтоПолноправныйПользователь); + КонецЕсли; + + Если ЭтоНаборЗаписей Тогда + ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью(Источник, Замещение, ЭтоПолноправныйПользователь); + КонецЕсли; + +КонецПроцедуры + +// Для обработчиков подписок на событие ПриЗаписи. +Процедура ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, ЭтоНаборЗаписей, Замещение) + + Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + Возврат; + КонецЕсли; + + ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь() + Или УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа() + Или Не УправлениеДоступом.ПроизводительныйВариант(); + + // Проверка доступа к новой версии. + ПроверитьДоступКИсточнику(Источник, Ложь, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь); + + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, ЭтоНаборЗаписей, Ложь); + +КонецПроцедуры + +// Для обработчиков подписок на событие ПередУдалением. +Процедура ПроверитьДоступПередУдалениемИсточника(Источник, Отказ) + + Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + Возврат; + КонецЕсли; + + Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", + Новый УникальныйИдентификатор); + + ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, Ложь, Ложь); + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, Ложь, Истина); + +КонецПроцедуры + + +// Для процедур ПроверитьДоступПередЗаписьюИсточника, ПроверитьДоступПриЗаписиИсточника. +Функция ПропуститьПроверкуДоступа(Отказ, Источник) + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда + Возврат Истина; + КонецЕсли; + + Если УправлениеДоступомСлужебныйПовтИсп.РазделенныеДанныеНедоступны() Тогда + Возврат Истина; + КонецЕсли; + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь) Тогда + Возврат Истина; + КонецЕсли; + + ОтключениеОбновления = ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа; // См. НовоеОтключениеОбновленияКлючейДоступа + Если ОтключениеОбновления.Полное Тогда + Возврат Истина; + КонецЕсли; + + Если ОтключениеОбновления.Стандартное Тогда + Кэш = УправлениеДоступомСлужебныйПовтИсп.КэшИзмененныхСписковПриОтключенномОбновленииКлючейДоступа(); + ТипИсточника = ТипЗнч(Источник); + Если Кэш.Получить(ТипИсточника) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + ОтключениеОбновления = Новый Структура(ОтключениеОбновления); + ИзмененныеСписки = ОтключениеОбновления.ИзмененныеСписки.Получить(); + ИзмененныеСписки.Вставить(ТипИсточника, Истина); + ОтключениеОбновления.ИзмененныеСписки = Новый ХранилищеЗначения(ИзмененныеСписки); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа = Новый ФиксированнаяСтруктура(ОтключениеОбновления); + УстановитьПривилегированныйРежим(Истина); + УстановитьОтключениеБезопасногоРежима(Истина); + + Кэш.Вставить(ТипИсточника, Истина); + Возврат Истина; + КонецЕсли; + + Если Отказ Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ПроверитьДоступПередЗаписьюИсточника. +Процедура ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, ЭтоНаборЗаписей, Замещение) + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмя, + Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоЗначениямПолей = Неопределено Тогда + + Источник.ДополнительныеСвойства.Вставить( + "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи"); + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + + Если ЭтоНаборЗаписей Тогда + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(Источник, Запрос, Замещение); + Запрос.Текст = СтрЗаменить(СвойстваСпискаКакВедущего.ПоЗначениямПолей.ТекстЗапроса, + "&ОтборПоИзмерениям", ОтборПоИзмерениям); + Иначе + Запрос.Текст = СвойстваСпискаКакВедущего.ПоЗначениямПолей.ТекстЗапроса; + Запрос.УстановитьПараметр("СсылкаНаОбъект", Источник.Ссылка); + КонецЕсли; + + Источник.ДополнительныеСвойства.Вставить( + "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи", + Запрос.ВыполнитьПакет()); + +КонецПроцедуры + +// Для процедур ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа, ОбновитьКлючиДоступаКНаборуЗаписей и +// функций ДоступРазрешен, ЧтениеДоступно. +// +Функция ОтборПоИзмерениямНабораЗаписей(НаборЗаписей, Запрос, Замещение = Неопределено, ЗапросНовыхКомбинаций = Неопределено) + + Параметры = ОбщегоНазначения.НовыеПараметрыОтбораЗаписейНабораИзБазыДанных(); + Параметры.ПрефиксИменПолейВПараметрах = "ЗначениеПоля"; + + ОтборЗаписей = ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение,, Параметры); + + Для Каждого КлючИЗначение Из ОтборЗаписей.ПараметрыЗапроса Цикл + Если Запрос <> Неопределено Тогда + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + Если ЗапросНовыхКомбинаций <> Неопределено Тогда + ЗапросНовыхКомбинаций.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + + Возврат ОтборЗаписей.УсловиеЗапроса; + +КонецФункции + +// Для процедуры ПроверитьДоступПередЗаписьюИсточника. +Процедура УстановитьРазрешенныйКлючДоступаДляНовогоОбъекта(Источник, ЭтоПолноправныйПользователь) + + Если ЭтоПолноправныйПользователь Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + СсылкаНового = ПользователиСлужебный.СсылкаОбъекта(Источник); + РазрешенныйКлючДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа(); + + НаборЗаписей = РегистрыСведений.КлючиДоступаКОбъектам.СоздатьНаборЗаписей(); + НаборЗаписей.Отбор.Объект.Установить(СсылкаНового); + + Запись = НаборЗаписей.Добавить(); + Запись.Объект = СсылкаНового; + Запись.КлючДоступаПользователей = РазрешенныйКлючДоступа; + Запись.КлючДоступаВнешнихПользователей = РазрешенныйКлючДоступа; + + НаборЗаписей.Записать(); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедур ПроверитьДоступПередЗаписьюИсточника, ПроверитьДоступПриЗаписиИсточника. +Процедура ПроверитьДоступКИсточнику(Источник, ПередЗаписью, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь) + + Если ПередЗаписью И ЭтоПолноправныйПользователь Тогда + Возврат; + КонецЕсли; + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + ИдентификаторТранзакции = Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции; + ВсеПараметрыОграничения = ПараметрыОграниченияПриПроверкеДоступа(Источник, ПолноеИмя, ИдентификаторТранзакции); + + Если Пользователи.ЭтоСеансВнешнегоПользователя() Тогда + ПараметрыОграничения = ВсеПараметрыОграничения.ДляВнешнихПользователей; + ПараметрыОграниченияДополнительные = ВсеПараметрыОграничения.ДляПользователей + Иначе + ПараметрыОграничения = ВсеПараметрыОграничения.ДляПользователей; + ПараметрыОграниченияДополнительные = ВсеПараметрыОграничения.ДляВнешнихПользователей + КонецЕсли; + + Если ПараметрыОграничения.ДоступЗапрещен И Не ЭтоПолноправныйПользователь Тогда + Если ПараметрыОграничения.ДляВнешнихПользователей Тогда + ШаблонОшибки = + НСтр("ru = 'Внешним пользователям запрещен доступ к данным списка + |""%1"".'"); + Иначе + ШаблонОшибки = + НСтр("ru = 'Пользователям запрещен доступ к данным списка + |""%1"".'"); + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + Источник.Метаданные().Представление()); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ЭтоНаборЗаписей Тогда + ПроверитьДоступКНаборуЗаписей(Источник, ПередЗаписью, Замещение, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные); + Иначе + ПроверитьДоступКОбъекту(Источник, ПередЗаписью, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКИсточнику. +// +// Возвращаемое значение: +// см. РассчитанныеПараметрыОграничения +// +Функция ПараметрыОграниченияПриПроверкеДоступа(Источник, ПолноеИмя, ИдентификаторТранзакции) + + Возврат ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Null); + +КонецФункции + +// Для процедуры ПроверитьДоступКИсточнику. +Процедура ПроверитьДоступКОбъекту(Источник, ПередЗаписью, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные) + + ЭтоНовый = Не Источник.ДополнительныеСвойства.Свойство( + "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи"); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Не ПередЗаписью Тогда + КлючДоступаОбновлен = Ложь; + + ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, + ПараметрыОграничения, КлючДоступаОбновлен); + + ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, + ПараметрыОграниченияДополнительные); + + Если Не КлючДоступаОбновлен Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + Если ПараметрыОграничения.ОграничениеОтключено Или ЭтоПолноправныйПользователь Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение; + + ПроверкаДобавления = Ложь; + Если Не ПередЗаписью Тогда + УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления); + КонецЕсли; + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(); + + Запрос.УстановитьПараметр("Объект", Источник.Ссылка); + УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос); + + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); + КонецЕсли; + + Если Не РезультатЗапросаПроверкиДоступа(Запрос, Источник).Пустой() Тогда + Возврат; // Доступ разрешен. + КонецЕсли; + + Если ПроверкаДобавления Тогда + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение; + ПравоИзменения = Не Запрос.Выполнить().Пустой(); + Иначе + ПравоИзменения = Ложь; + КонецЕсли; + + Если ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда + ПравоЧтения = Истина; + Иначе + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение; + ПравоЧтения = Не Запрос.Выполнить().Пустой(); + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Данные = ?(ПередЗаписью, Источник.Ссылка, Источник); + СообщитьОбОшибкеДоступа(Данные, ПередЗаписью, ПравоЧтения, ПравоИзменения, ЭтоНовый); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКОбъекту и функции ДоступРазрешен. +Процедура УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления) + + ПроверкаДобавления = ЭтоНовый И Не ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу; + Если Не ПроверкаДобавления Тогда + Возврат; + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "РазрешенныеКлючиДоступа.ПравоИзменение", "РазрешенныеКлючиДоступа.ПравоДобавление"); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКОбъекту. +Процедура ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, + ПараметрыОграничения, КлючДоступаОбновлен = Ложь) + + Если ПараметрыОграничения.ДоступЗапрещен + Или (ПараметрыОграничения.ОграничениеОтключено + И Не ПараметрыОграничения.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей) Тогда + Возврат; + КонецЕсли; + + Если Не ЭтоНовый И Не КлючДоступаИсточникаУстарел(Источник.Ссылка, ПараметрыОграничения, Источник) Тогда + Возврат; + КонецЕсли; + + ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(Источник.Ссылка, + ПараметрыОграничения, ИдентификаторТранзакции,,, Источник); + + КлючДоступаОбновлен = Истина; + +КонецПроцедуры + +// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. +Функция РезультатЗапросаПроверкиДоступа(Запрос, Источник) + + Возврат Запрос.Выполнить(); + +КонецФункции + +// Для процедуры ПроверитьДоступКИсточнику. +Процедура ПроверитьДоступКНаборуЗаписей(Источник, ПередЗаписью, Замещение, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные) + + Если ПередЗаписью + И (Замещение = Ложь + Или ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение)) + Или Не ПередЗаписью + И (Источник.Количество() = 0 + Или ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение)) Тогда + + Возврат; + КонецЕсли; + + ОтборПоИзмерениям = ""; + Запрос = ?(ПараметрыОграничения.ОграничениеОтключено Или ЭтоПолноправныйПользователь, + Неопределено, Новый Запрос); + + ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, + ИдентификаторТранзакции, ПараметрыОграничения, ОтборПоИзмерениям, Запрос); + + ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, + ИдентификаторТранзакции, ПараметрыОграниченияДополнительные, "", Неопределено); + + Если Запрос = Неопределено Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Запрос.Текст = СтрЗаменить(ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение, + "&ОтборПоИзмерениям", ОтборПоИзмерениям); + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(); + УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос); + + Если РезультатЗапросаПроверкиДоступа(Запрос, Источник).Пустой() Тогда + Возврат; // Доступ разрешен. + КонецЕсли; + + Если ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда + ПравоЧтения = Истина; + Иначе + Запрос.Текст = СтрЗаменить(ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение, + "&ОтборПоИзмерениям", ОтборПоИзмерениям); + ПравоЧтения = Запрос.Выполнить().Пустой(); + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + СообщитьОбОшибкеДоступа(Источник, ПередЗаписью, ПравоЧтения, Ложь, Ложь); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКНаборуЗаписей и для функции ДоступРазрешен. +Процедура ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, + ИдентификаторТранзакции, ПараметрыОграничения, ОтборПоИзмерениям, Запрос) + + Если ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу + И Запрос = Неопределено Тогда + + Возврат; + КонецЕсли; + + Если Не ПередЗаписью Тогда + ЗапросНовыхКомбинаций = Новый Запрос; + КонецЕсли; + + Если Замещение <> Ложь + И Не ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение) Тогда + + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(Источник, Запрос, Замещение, ЗапросНовыхКомбинаций); + Иначе + КомбинацииЗначенийОпорныхПолей = КомбинацииЗначенийОпорныхПолей(Источник, + ОтборПоИзмерениям, ПараметрыОграничения); + + Если Запрос <> Неопределено Тогда + Запрос.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", КомбинацииЗначенийОпорныхПолей); + КонецЕсли; + ЗапросНовыхКомбинаций.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", КомбинацииЗначенийОпорныхПолей); + КонецЕсли; + + Если ПередЗаписью Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступПередЗаписьюИсточника. +Процедура ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью(Источник, Замещение, ЭтоПолноправныйПользователь) + + Если ЭтоПолноправныйПользователь + Или Источник.Количество() = 0 + Или ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) Тогда + Возврат; + КонецЕсли; + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + ИдентификаторТранзакции = Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции; + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + + ЗапросНовыхКомбинаций = Новый Запрос; + ОтборПоИзмерениям = ""; + + ЗапросНовыхКомбинаций.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", + КомбинацииЗначенийОпорныхПолей(Источник, ОтборПоИзмерениям, ПараметрыОграничения)); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедур ПроверитьДоступКНаборуЗаписей, +// ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью. +// +Функция КомбинацииЗначенийОпорныхПолей(Источник, ОтборПоИзмерениям, ПараметрыОграничения) + + Поля = СтрСоединить(ПараметрыОграничения.ОпорныеПоля.Используемые, ","); + Поля = УправлениеДоступомСлужебныйПовтИсп.ПоляВРегистреСимволовМетаданных(ПараметрыОграничения.Список, Поля); + КомбинацииЗначенийОпорныхПолей = Источник.Выгрузить(, Поля); + КомбинацииЗначенийОпорныхПолей.Свернуть(Поля); + + ПоляОтбора = ""; + Для Каждого Поле Из ПараметрыОграничения.ОпорныеПоля.Используемые Цикл + ПоляОтбора = ПоляОтбора + ?(ПоляОтбора = "", "", ", ") + "ТекущаяТаблица." + Поле; + КонецЦикла; + ОтборПоИзмерениям = "(" + ПоляОтбора + ") В (&КомбинацииЗначенийОпорныхПолей)"; // @query-part-2 + + Возврат КомбинацииЗначенийОпорныхПолей; + +КонецФункции + +// Для процедур ПроверитьДоступКНаборуЗаписей, +// ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью. +// +Процедура ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения) + + ЭлементыДанных = ЭлементыДанныхНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения); + + Если ЭлементыДанных.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(ЭлементыДанных, ПараметрыОграничения, + Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции,,, Источник); + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей. +Функция ЭлементыДанныхНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения) + + Если ЗапросНовыхКомбинаций.Параметры.Свойство("КомбинацииЗначенийОпорныхПолей") Тогда + ЗапросНовыхКомбинаций.Текст = + ПараметрыОграничения.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей; + Иначе + ЗапросНовыхКомбинаций.Текст = СтрЗаменить( + ПараметрыОграничения.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей, + "&ОтборПоИзмерениям", + ОтборПоИзмерениям); + КонецЕсли; + + РезультатЗапросаНовыхКомбинаций = ЗапросНовыхКомбинаций.Выполнить(); + Если РезультатЗапросаНовыхКомбинаций.Пустой() Тогда + Возврат Новый Массив; + КонецЕсли; + + ЭлементыДанных = РезультатЗапросаНовыхКомбинаций.Выгрузить(); + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов("Число")); + Индекс = 0; + + Если ПараметрыОграничения.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей Тогда + ВсеЭлементыДанных = ЭлементыДанных; + ЭлементыДанных = ВсеЭлементыДанных.Скопировать(Новый Массив); + Для Каждого ЭлементДанных Из ВсеЭлементыДанных Цикл + Если НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОграничения) Тогда + Продолжить; + КонецЕсли; + ЭлементДанных.ТекущаяСсылка = Индекс; + Индекс = Индекс + 1; + ЗаполнитьЗначенияСвойств(ЭлементыДанных.Добавить(), ЭлементДанных); + КонецЦикла; + Иначе + Для Каждого ЭлементДанных Из ЭлементыДанных Цикл + ЭлементДанных.ТекущаяСсылка = Индекс; + Индекс = Индекс + 1; + КонецЦикла; + КонецЕсли; + + Возврат ЭлементыДанных; + +КонецФункции + +// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. +Процедура СообщитьОбОшибкеДоступа(Данные, СтараяВерсия, ЕстьПравоЧтения, ЕстьПравоИзменения, ЭтоНовый) + + Если СтараяВерсия Тогда + Если ЕстьПравоЧтения Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для изменения данных: + |%1'"), ПредставлениеДанных(Данные)); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для чтения данных: + |%1'"), ПредставлениеДанных(Данные)); + КонецЕсли; + Иначе + Если ЕстьПравоЧтения И ЕстьПравоИзменения Тогда + Если ЭтоНовый Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (нет права добавления): + |%1'"), ПредставлениеДанных(Данные)); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (нет права добавления для сделанных изменений): + |%1'"), ПредставлениеДанных(Данные)); + КонецЕсли; + ИначеЕсли ЕстьПравоЧтения Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (невозможно будет изменить): + |%1'"), ПредставлениеДанных(Данные)); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (невозможно будет прочитать): + |%1.'"), ПредставлениеДанных(Данные)); + КонецЕсли; + КонецЕсли; + + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа); + +КонецПроцедуры + +// Для процедуры СообщитьОбОшибкеДоступа. +Функция ПредставлениеДанных(Данные) + + Если ТипЗнч(Данные) = Тип("Строка") Тогда + Возврат СокрЛП(Данные); + КонецЕсли; + + Если ТипЗнч(Данные) = Тип("Структура") Тогда + ЭтоРегистр = Истина; + Если ТипЗнч(Данные.Регистр) = Тип("Строка") Тогда + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Данные.Регистр); + Иначе + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Данные.Регистр)); + КонецЕсли; + Иначе + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Данные)); + ЭтоРегистр = ОбщегоНазначения.ЭтоРегистр(ОбъектМетаданных); + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + Возврат ""; + КонецЕсли; + + Если ЭтоРегистр Тогда + ПредставлениеДанных = ОбъектМетаданных.Представление(); + + КоличествоПолей = 0; + Для каждого ЭлементОтбора Из Данные.Отбор Цикл + Если ЭлементОтбора.Использование Тогда + КоличествоПолей = КоличествоПолей + 1; + КонецЕсли; + КонецЦикла; + + Если КоличествоПолей = 1 Тогда + ПредставлениеДанных = ПредставлениеДанных + + " " + НСтр("ru = 'с полем'") + " " + Строка(Данные.Отбор); + + ИначеЕсли КоличествоПолей > 1 Тогда + ПредставлениеДанных = ПредставлениеДанных + + " " + НСтр("ru = 'с полями'") + " " + Строка(Данные.Отбор); + КонецЕсли; + Иначе + ПредставлениеДанных = Строка(Данные); + ПредставлениеМетаданных = ОбщегоНазначения.ПредставлениеОбъекта(ОбъектМетаданных); + + Если Не СтрЗаканчиваетсяНа(ПредставлениеДанных, "(" + ПредставлениеМетаданных + ")") + И Не СтрНачинаетсяС(ПредставлениеДанных, ПредставлениеМетаданных) Тогда + + ПредставлениеДанных = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 (%2)", + ПредставлениеДанных, ПредставлениеМетаданных); + КонецЕсли; + КонецЕсли; + + Возврат ПредставлениеДанных; + +КонецФункции + +// Для процедуры ПроверитьДоступКОбъекту и формы ОбновлениеДоступаРучноеУправление. +// +// Возвращаемое значение: +// Булево +// +Функция КлючДоступаИсточникаУстарел(СсылкаНаОбъект, ПараметрыОграничения, Источник = Неопределено) Экспорт + + Если ПараметрыОграничения.БезЗаписиКлючейДоступа Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект); + + Если Не ЗначениеЗаполнено(ПараметрыОграничения.СоставПолей) Тогда + Запрос.УстановитьПараметр("Список", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); + КонецЕсли; + + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиКлючаДоступаОбъекта; + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Запрос.Выполнить().Пустой() Тогда + Возврат Ложь; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Возврат Истина; + +КонецФункции + +// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей и формы ОбновлениеДоступаРучноеУправление. +Процедура ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(ОписаниеЭлементовДанных, ПараметрыОграничения, + ИдентификаторТранзакции, ОбновитьПраваНаКлючи = Ложь, ЕстьИзмененияПрав = Ложь, Источник = Неопределено) Экспорт + + Если ПараметрыОграничения.БезЗаписиКлючейДоступа Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ОписаниеЭлементовДанных) = Тип("ТаблицаЗначений") Тогда + ЭлементыДанных = ОписаниеЭлементовДанных; + Иначе + ЭлементыДанных = Новый ТаблицаЗначений; + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка"); + ЭлементыДанных.Добавить().ТекущаяСсылка = ОписаниеЭлементовДанных; + КонецЕсли; + + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПараметрыОграничения.Список, + ИдентификаторТранзакции); + ИмяСвойстваВидаПользователей = ?(ПараметрыОграничения.ДляВнешнихПользователей, + "ДляВнешнихПользователей", "ДляПользователей"); + + ПараметрыОбновления = Новый Структура(ПараметрыОграничения); + ПараметрыОбновления.Вставить("ЕстьИзмененияПрав", ЕстьИзмененияПрав); + ПараметрыОбновления.Вставить("ОбновитьПраваНаКлючи", ОбновитьПраваНаКлючи); + ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); + ПараметрыОбновления.Вставить("ИдентификаторСписка", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей] = Неопределено Тогда + + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", Новый Массив); + Иначе + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", + СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей]); + КонецЕсли; + + ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ЭлементыДанных, ПараметрыОбновления); + + ЕстьИзмененияПрав = ПараметрыОбновления.ЕстьИзмененияПрав; + +КонецПроцедуры + +// Для регистра сведений ГруппыЗначенийДоступа. +Процедура ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами(ЗначенияСИзменениямиПоТипам) Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Возврат; + КонецЕсли; + + ИдентификаторТранзакции = Новый УникальныйИдентификатор; + + СпискиДляОбновления = Новый Соответствие; + Для Каждого ОписаниеЗначений Из ЗначенияСИзменениямиПоТипам Цикл + ПолноеИмяВедущего = Метаданные.НайтиПоТипу(ОписаниеЗначений.Ключ).ПолноеИмя(); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмяВедущего, ИдентификаторТранзакции); + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоЗначениямСГруппами = Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, + СвойстваСпискаКакВедущего.ПоЗначениямСГруппами, "ДляПользователей"); + + ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, + СвойстваСпискаКакВедущего.ПоЗначениямСГруппами, "ДляВнешнихПользователей"); + КонецЦикла; + + ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, + ИдентификаторТранзакции, + "ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами", + ?(ЗначенияСИзменениямиПоТипам.Количество() <> 1 Или ОписаниеЗначений.Значение = Истина, + Неопределено, Новый Структура("ПоЗначениямСГруппами", ОписаниеЗначений.Значение))); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами. +Процедура ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, ПоЗначениямСГруппами, ИмяВидаПользователей) + + ПолныеИмена = ПоЗначениямСГруппами[ИмяВидаПользователей]; + Если ПолныеИмена = Неопределено Тогда + Возврат; + КонецЕсли; + + Для Каждого ПолноеИмя Из ПолныеИмена Цикл + СписокДляОбновления = СпискиДляОбновления.Получить(ПолноеИмя); + Если СписокДляОбновления = Неопределено Тогда + СписокДляОбновления = Новый Структура("ДляПользователей, ДляВнешнихПользователей", Ложь, Ложь); + СпискиДляОбновления.Вставить(ПолноеИмя, СписокДляОбновления); + КонецЕсли; + СписокДляОбновления[ИмяВидаПользователей] = Истина; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа, ЗаписатьКлючиДоступаОбъектов, +// ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами. +// +Процедура ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, ИдентификаторТранзакции, + Описание, ВедущийОбъект = Неопределено, ЭтоПродолжениеОбновления = Ложь) + + Если ТипЗнч(СпискиДляОбновления) = Тип("Соответствие") + И СпискиДляОбновления.Количество() = 0 + Или ТипЗнч(СпискиДляОбновления) = Тип("Структура") + И СпискиДляОбновления.ИменаСписков.Количество() = 0 Тогда + + Возврат; + КонецЕсли; + + Списки = Новый Массив; + СпискиДляПользователей = Новый Массив; + СпискиДляВнешнихПользователей = Новый Массив; + + Если ТипЗнч(СпискиДляОбновления) = Тип("Соответствие") Тогда + Для Каждого ОписаниеСписка Из СпискиДляОбновления Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + Свойства = ОписаниеСписка.Значение; + + Если Свойства.ДляПользователей Тогда + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Ложь); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + Свойства.ДляПользователей = Ложь; + КонецЕсли; + КонецЕсли; + + Если Свойства.ДляВнешнихПользователей Тогда + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Истина); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + Свойства.ДляВнешнихПользователей = Ложь; + КонецЕсли; + КонецЕсли; + + Если Свойства.ДляПользователей И Свойства.ДляВнешнихПользователей Тогда + Списки.Добавить(ПолноеИмя); + + ИначеЕсли Свойства.ДляПользователей Тогда + СпискиДляПользователей.Добавить(ПолноеИмя); + + ИначеЕсли Свойства.ДляВнешнихПользователей Тогда + СпискиДляВнешнихПользователей.Добавить(ПолноеИмя); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого ПолноеИмя Из СпискиДляОбновления.ИменаСписков Цикл + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, + ИдентификаторТранзакции, СпискиДляОбновления.ДляВнешнихПользователей); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + Продолжить; + КонецЕсли; + + Если СпискиДляОбновления.ДляВнешнихПользователей Тогда + СпискиДляВнешнихПользователей.Добавить(ПолноеИмя); + Иначе + СпискиДляПользователей.Добавить(ПолноеИмя); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если Описание = "ЗаполнитьКэшПараметровОграниченияДоступа" Тогда + Возврат; + КонецЕсли; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.Описание = Описание; + ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; + ПараметрыПланирования.ЭтоПродолжениеОбновления = ЭтоПродолжениеОбновления; + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); + + ПараметрыПланирования.ДляПользователей = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступПриЗаписиИсточника, ПроверитьДоступПередУдалениемИсточника. +Процедура ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, ЭтоНаборЗаписей, Удаление) + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмя, + Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоЗначениямПолей = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи") Тогда + РезультатыЗапроса = Источник.ДополнительныеСвойства.УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи; + Иначе + РезультатыЗапроса = Неопределено; + КонецЕсли; + + ИзмененияПоЗначениямПолей = Новый Структура; + ИзмененияПоЗначениямПолей.Вставить("Описание", ?(ЭтоНаборЗаписей, Источник.Отбор, Источник.Ссылка)); + ИзмененияПоЗначениямПолей.Вставить("ИзмененнаяТаблица", ПолноеИмя); + ИзмененияПоЗначениямПолей.Вставить("СоставИзменений"); + + ВедущийОбъект = ОписаниеВедущегоОбъекта(); + ВедущийОбъект.Вставить("ПоЗначениямПолей", ИзмененияПоЗначениямПолей); + + ПоЗначениямПолей = СвойстваСпискаКакВедущего.ПоЗначениямПолей; + ПоляШапки = ПоЗначениямПолей.ПоляШапки; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.Описание = "ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа"; + ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; + + Если ЭтоНаборЗаписей Тогда + Если ЗначениеЗаполнено(ПоляШапки.ВсеПоля) Тогда + РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[0]); + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + Источник, ПоляШапки.НаборыПолей, ПараметрыПланирования); + КонецЕсли; + Иначе + Если ЗначениеЗаполнено(ПоляШапки.ВсеПоля) Тогда + РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[0]); + НовыеЗначения = Новый ТаблицаЗначений; + Для Каждого ИмяПоля Из ПоляШапки.ВсеПоля Цикл + НовыеЗначения.Колонки.Добавить(ИмяПоля, ПоляШапки.ТипыВсехПолей.Получить(ИмяПоля).Получить()); + КонецЦикла; + Если Не Удаление Тогда + ЗаполнитьЗначенияСвойств(НовыеЗначения.Добавить(), Источник); + КонецЕсли; + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + НовыеЗначения, ПоляШапки.НаборыПолей, ПараметрыПланирования); + Индекс = 1; + Иначе + Индекс = 0; + КонецЕсли; + Для Каждого ОписаниеТабличнойЧасти Из ПоЗначениямПолей.ТабличныеЧасти Цикл + РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[Индекс]); + ИзмененияПоЗначениямПолей.ИзмененнаяТаблица = ПолноеИмя + "." + ОписаниеТабличнойЧасти.Имя; + НовыеЗначения = НовыеЗначенияТабличнойЧасти(Источник, ОписаниеТабличнойЧасти, Удаление); + // @skip-check query-in-loop - В вызываемом варианте ветка с запросом не используется + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + НовыеЗначения, ОписаниеТабличнойЧасти.НаборыПолей, ПараметрыПланирования); + Индекс = Индекс + 1; + КонецЦикла; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ПоЗначениямПолей - Структура: +// ** Описание - ЛюбаяСсылка +// - Отбор +// ** ИзмененнаяТаблица - Строка - полное имя списка +// ** СоставИзменений - см. СоставИзмененийТаблицы +// * ПоКлючамДоступа - СправочникСсылка.КлючиДоступа +// * ПоЗначениямСГруппами - ОпределяемыйТип.ЗначениеДоступа - только значения доступа с группами. +// * ПоДаннымКэшаРасчетаПрав - Строка - наименование данных для кэша расчета прав. +// +Функция ОписаниеВедущегоОбъекта() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа. +Функция НовыеЗначенияТабличнойЧасти(Источник, ОписаниеТабличнойЧасти, Удаление) + + Поля = Новый Массив(ОписаниеТабличнойЧасти.ВсеПоля); + + ИмяПоляСсылка = "Ссылка"; // @Non-NLS + Индекс = Поля.Найти(ИмяПоляСсылка); + Если Индекс <> Неопределено Тогда + Поля.Удалить(Индекс); + Иначе + ИмяПоляСсылка = "Ref"; + Индекс = Поля.Найти(ИмяПоляСсылка); + Если Индекс <> Неопределено Тогда + Поля.Удалить(Индекс); + КонецЕсли; + КонецЕсли; + + НовыеЗначения = Источник[ОписаниеТабличнойЧасти.Имя].Выгрузить( + ?(Удаление, Новый Массив, Неопределено), СтрСоединить(Поля, ", ")); // ТаблицаЗначений + + Если Индекс <> Неопределено Тогда + Типы = Новый Массив; + Типы.Добавить(ТипЗнч(Источник.Ссылка)); + НовыеЗначения.Колонки.Добавить(ИмяПоляСсылка, Новый ОписаниеТипов(Типы)); + НовыеЗначения.ЗаполнитьЗначения(Источник.Ссылка, ИмяПоляСсылка); + КонецЕсли; + + Возврат НовыеЗначения; + +КонецФункции + +// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа. +Процедура ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + Источник, НаборыПолейПоВидамПользователей, ПараметрыПланирования) + + ВидыПользователей = Новый Массив; + ВидыПользователей.Добавить("ДляПользователей"); + ВидыПользователей.Добавить("ДляВнешнихПользователей"); + + Для Каждого ВидПользователей Из ВидыПользователей Цикл + НаборыПолей = НаборыПолейПоВидамПользователей[ВидПользователей]; + Если НаборыПолей = Неопределено Тогда + Продолжить; + КонецЕсли; + Если ВидПользователей = "ДляПользователей" Тогда + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ПараметрыПланирования.ДляПользователей = Истина; + Иначе + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ПараметрыПланирования.ДляПользователей = Ложь; + КонецЕсли; + Для Каждого ОписаниеНабораПолей Из НаборыПолей Цикл + СоставИзменений = СоставИзмененийТаблицы(РезультатЗапроса, Источник, ОписаниеНабораПолей.Ключ); + Если СоставИзменений = Null Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеЗависимыхТаблиц Из ОписаниеНабораПолей.Значение Цикл + Если ОписаниеЗависимыхТаблиц.Ключ = ОписаниеНабораПолей.Ключ + Или СоставИзменений = Неопределено Тогда + ТекущийСоставИзменений = СоставИзменений; + Иначе + ТекущийСоставИзменений = СоставИзменений.Скопировать(, ОписаниеЗависимыхТаблиц.Ключ); + ТекущийСоставИзменений.Свернуть(ОписаниеЗависимыхТаблиц.Ключ); + КонецЕсли; + ПараметрыПланирования.ВедущийОбъект.ПоЗначениямПолей.СоставИзменений = ТекущийСоставИзменений; + // @skip-check query-in-loop - В вызываемом варианте ветка с запросом не используется + ЗапланироватьОбновлениеДоступа(ОписаниеЗависимыхТаблиц.Значение, ПараметрыПланирования); + КонецЦикла; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей. +// +// Возвращаемое значение: +// ТаблицаЗначений +// +Функция СоставИзмененийТаблицы(РезультатЗапроса, Источник, Поля) + + МаксимумКомбинаций = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); + Если РезультатЗапроса = Неопределено Тогда + СтарыеКомбинации = Новый ТаблицаЗначений; + Иначе + СтарыеКомбинации = РезультатЗапроса.Выгрузить(); + Если СтрРазделить(Поля, ",").Количество() < СтарыеКомбинации.Колонки.Количество() Тогда + СтарыеКомбинации.Свернуть(Поля); + КонецЕсли; + КонецЕсли; + + Если СтарыеКомбинации.Количество() >= МаксимумКомбинаций Тогда + Возврат Неопределено; + КонецЕсли; + + Если ТипЗнч(Источник) = Тип("ТаблицаЗначений") Тогда + НовыеКомбинации = Источник.Скопировать(, Поля); + Иначе + НовыеКомбинации = Источник.Выгрузить(, Поля); + КонецЕсли; + НовыеКомбинации.Свернуть(Поля); + + Если НовыеКомбинации.Количество() >= МаксимумКомбинаций Тогда + Возврат Неопределено; + КонецЕсли; + + СоставИзменений = НовыеКомбинации.Скопировать(Новый Массив); + + НовыеКомбинации.Колонки.Добавить("ВидИзменения", Новый ОписаниеТипов("Число")); + НовыеКомбинации.ЗаполнитьЗначения(1, "ВидИзменения"); + Для Каждого Строка Из СтарыеКомбинации Цикл + НоваяСтрока = НовыеКомбинации.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); + НоваяСтрока.ВидИзменения = -1; + КонецЦикла; + НовыеКомбинации.Свернуть(Поля, "ВидИзменения"); + + Для Каждого Строка Из НовыеКомбинации Цикл + Если Строка.ВидИзменения <> 0 Тогда + ЗаполнитьЗначенияСвойств(СоставИзменений.Добавить(), Строка); + КонецЕсли; + КонецЦикла; + + Возврат ?(СоставИзменений.Количество() > 0, СоставИзменений, Null); + +КонецФункции + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. +Процедура ПроверитьОбъектыНастроекДоступа() + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + УстановитьРазделяемуюБлокировку("Справочник.ГруппыВнешнихПользователей"); + УстановитьРазделяемуюБлокировку("Справочник.ВнешниеПользователи"); + УстановитьРазделяемуюБлокировку("Справочник.ГруппыПользователей"); + УстановитьРазделяемуюБлокировку("Справочник.Пользователи"); + УстановитьРазделяемуюБлокировку("Справочник.ПрофилиГруппДоступа"); + УстановитьРазделяемуюБлокировку("Справочник.ГруппыДоступа"); + +КонецПроцедуры + +// Для процедуры ПроверитьОбъектыНастроекДоступа. +Процедура УстановитьРазделяемуюБлокировку(ИмяТаблицы) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ИмяТаблицы); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// См. УправлениеДоступом.УстановитьБлокировкуПередЗаписьюВФайловойИБ +Процедура УстановитьБлокировкуПередЗаписьюВФайловойИБ(ПередЗаписьюНовогоОбъекта = Ложь, + ПередЗаписьюНастройкиДоступа = Ложь) Экспорт + + Если ПередЗаписьюНастройкиДоступа Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(,, Истина); + ИначеЕсли ПередЗаписьюНовогоОбъекта Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + Иначе + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + +КонецПроцедуры + +Процедура ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(ЭтоОшибкаБлокировки = Ложь, + ОбновлениеПараметров = Ложь, ЭтоЗаписьОбъектаНастроекДоступа = Ложь) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Константа.КоличествоПотоковОбновленияДоступа"); + Если Не ЭтоСеансФоновогоОбновленияДоступа() Тогда + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + + Если ЭтоЗаписьОбъектаНастроекДоступа Тогда + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); + Если Не ОбновлениеПараметров Тогда + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаПользователей"); + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для вызова и модуля менеджера справочника ГруппыДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа(ГруппыДоступа, + ТипыИзмененныхУчастников, ПриЗагрузке = Ложь) Экспорт + + Если Не ТипыИзмененныхУчастников.Пользователи + И Не ТипыИзмененныхУчастников.ВнешниеПользователи Тогда + Возврат; + КонецЕсли; + + Описание = ?(ПриЗагрузке, + "ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступаПриЗагрузке", + "ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа"); + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "УчастникиГруппДоступа"); + + Запрос = Новый Запрос; + + Если ГруппыДоступа = Неопределено Тогда + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа"; + Иначе + Запрос.УстановитьПараметр("ГруппыДоступа", ГруппыДоступа); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + |ГДЕ + | ТаблицыГруппДоступа.ГруппаДоступа В(&ГруппыДоступа)"; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Таблицы = Запрос.Выполнить().Выгрузить(); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, Описание, + ТипыИзмененныхУчастников.Пользователи, ТипыИзмененныхУчастников.ВнешниеПользователи, Истина); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедуры ПослеОбновленияСоставовГруппПользователей и +// модуля менеджера справочника ГруппыДоступа. +// +Процедура ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(ИзмененныеУчастники, + ПриЗагрузке = Ложь, ПослеУстановкиПользователяИБ = Ложь) + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Описание = ?(ПослеУстановкиПользователяИБ, + "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступаПослеУстановкиПользователяИБ", + ?(ПриЗагрузке, + "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступаПриЗагрузке", + "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа")); + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "СоставыГруппПользователей"); + + Если ИзмененныеУчастники = Неопределено Тогда + ДляПользователей = Истина; + ДляВнешнихПользователей = Истина; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа"; + Иначе + ДляПользователей = Ложь; + ДляВнешнихПользователей = Ложь; + + Для Каждого Участник Из ИзмененныеУчастники Цикл + Если ТипЗнч(Участник) = Тип("СправочникСсылка.Пользователи") + Или ТипЗнч(Участник) = Тип("СправочникСсылка.ГруппыПользователей") Тогда + + ДляПользователей = Истина; + + ИначеЕсли ТипЗнч(Участник) = Тип("СправочникСсылка.ВнешниеПользователи") + Или ТипЗнч(Участник) = Тип("СправочникСсылка.ГруппыВнешнихПользователей") Тогда + + ДляВнешнихПользователей = Истина; + КонецЕсли; + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИзмененныеУчастники", ИзмененныеУчастники); + Если ПослеУстановкиПользователяИБ Тогда + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ПО ТаблицыГруппДоступа.ГруппаДоступа = УчастникиГруппДоступа.Ссылка + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.Пользователь В (&ИзмененныеУчастники)) + | И (СоставыГруппПользователей.ГруппаПользователей = УчастникиГруппДоступа.Пользователь)"; + Иначе + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ПО ТаблицыГруппДоступа.ГруппаДоступа = УчастникиГруппДоступа.Ссылка + | И (УчастникиГруппДоступа.Пользователь В (&ИзмененныеУчастники))"; + КонецЕсли; + КонецЕсли; + + Таблицы = Запрос.Выполнить().Выгрузить(); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, + Описание, ДляПользователей, ДляВнешнихПользователей, Истина); + + ЗапланироватьОбновлениеНаборовГруппДоступа(Описание, ДляПользователей, ДляВнешнихПользователей); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для вызова из модуля менеджера регистра ТаблицыГруппДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа(Таблицы) Экспорт + + Описание = "ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа"; + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ТаблицыГруппДоступа"); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, Описание, Истина, Истина); + +КонецПроцедуры + +// Для вызова из модуля объекта и модуля менеджера справочника ПрофилиГруппДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРолейПрофиля(Описание, ИзмененныеРоли) Экспорт + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "РолиПрофилейГруппДоступа"); + + Если ИзмененныеРоли = Неопределено + Или ИзмененныеРоли.Количество() > 0 Тогда + + ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли); + КонецЕсли; + +КонецПроцедуры + +// Для вызова из модуля объекта и модуля менеджера справочника ГруппыДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииПрофиляГруппыДоступа(Описание, ИзмененныеРоли, ПрофильИзменен) Экспорт + + Если ПрофильИзменен Тогда + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ГруппыДоступаПрофилей"); + КонецЕсли; + + Если ИзмененныеРоли = Неопределено + Или ИзмененныеРоли.Количество() > 0 Тогда + + ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииРолейПрофиля и +// ЗапланироватьОбновлениеДоступаПриИзмененииПрофиляГруппыДоступа. +// +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли) + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + Если Не ЗначениеЗаполнено(ДействующиеПараметры.ВедущиеРоли) Тогда + Возврат; + КонецЕсли; + + Если ИзмененныеРоли <> Неопределено Тогда + МетаданныеРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИзмененныеРоли, Ложь); + ИменаРолей = Новый Соответствие; + Для Каждого КлючИЗначение Из МетаданныеРолей Цикл + Если ТипЗнч(КлючИЗначение.Значение) = Тип("ОбъектМетаданных") Тогда + ИменаРолей.Вставить(КлючИЗначение.Значение.Имя, Истина); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + СпискиДляПользователей = Новый Массив; + СпискиДляВнешнихПользователей = Новый Массив; + ДобавленныеСпискиДляПользователей = Новый Соответствие; + ДобавленныеСпискиДляВнешнихПользователей = Новый Соответствие; + + Для Каждого ОписаниеВедущейРоли Из ДействующиеПараметры.ВедущиеРоли Цикл + Если ИзмененныеРоли <> Неопределено + И ИменаРолей.Получить(ОписаниеВедущейРоли.Ключ) = Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавитьСпискиВедущейРолиДляОбновленияПрав(СпискиДляПользователей, + ОписаниеВедущейРоли.Значение.ДляПользователей, ДобавленныеСпискиДляПользователей); + ДобавитьСпискиВедущейРолиДляОбновленияПрав(СпискиДляВнешнихПользователей, + ОписаниеВедущейРоли.Значение.ДляВнешнихПользователей, ДобавленныеСпискиДляВнешнихПользователей); + КонецЦикла; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.КлючиДоступаКДанным = Ложь; + ПараметрыПланирования.Описание = Описание; + + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); + + ПараметрыПланирования.ДляПользователей = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеДоступаПриИзмененииРолей. +Процедура ДобавитьСпискиВедущейРолиДляОбновленияПрав(Списки, СпискиВедущейРоли, ДобавленныеСписки) + + Если Не ЗначениеЗаполнено(СпискиВедущейРоли) Тогда + Возврат; + КонецЕсли; + + Для Каждого ОписаниеСписка Из СпискиВедущейРоли Цикл + Если ДобавленныеСписки.Получить(ОписаниеСписка.Ключ) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавленныеСписки.Вставить(ОписаниеСписка.Ключ, Истина); + Списки.Добавить(ОписаниеСписка.Ключ); + КонецЦикла; + +КонецПроцедуры + +// Для вызова из модуля менеджера регистра ЗначенияГруппДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений(ГруппыДоступаИТипыЗначений) Экспорт + + Описание = "ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений"; + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ЗначенияГруппДоступа"); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ГруппыДоступаИТипыЗначений", ГруппыДоступаИТипыЗначений); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступаИТипыЗначений.ГруппаДоступа КАК ГруппаДоступа, + | ГруппыДоступаИТипыЗначений.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ПОМЕСТИТЬ ГруппыДоступаИТипыЗначений + |ИЗ + | &ГруппыДоступаИТипыЗначений КАК ГруппыДоступаИТипыЗначений + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица, + | ТИПЗНАЧЕНИЯ(ГруппыДоступаИТипыЗначений.ТипЗначенийДоступа) КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступаИТипыЗначений КАК ГруппыДоступаИТипыЗначений + | ПО ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступаИТипыЗначений.ГруппаДоступа + |ИТОГИ ПО + | Таблица"; + + ТаблицыИТипыЗначенийДоступа = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(ТаблицыИТипыЗначенийДоступа.Строки, + Описание, Истина, Истина); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеДоступа, ЗапланироватьОбновлениеПараметровОграниченияДоступа. +Функция СлужебныйИдентификатор(ПолноеИмя) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПолноеИмя", ПолноеИмя); + Запрос.Текст = + "ВЫБРАТЬ + | ИдентификаторыОбъектовМетаданных.Ссылка КАК Ссылка + |ИЗ + | Справочник.ИдентификаторыОбъектовМетаданных КАК ИдентификаторыОбъектовМетаданных + |ГДЕ + | ИдентификаторыОбъектовМетаданных.ПолноеИмя = &ПолноеИмя + | + |УПОРЯДОЧИТЬ ПО + | ИдентификаторыОбъектовМетаданных.ПометкаУдаления"; + + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + Возврат Выборка.Ссылка; + КонецЕсли; + + Возврат Null; + +КонецФункции + +// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений. +// +Процедура ЗапланироватьОбновлениеПользователейКлючейДоступа(ОписаниеСписков, Описание, ДляПользователей, + ДляВнешнихПользователей, ПриИзмененииУчастниковГруппыДоступа = Ложь, ВедущийОбъект = Неопределено) + + Если ОписаниеСписков.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Контекст = Новый Структура; + Контекст.Вставить("ПриИзмененииУчастниковГруппыДоступа", ПриИзмененииУчастниковГруппыДоступа); + Контекст.Вставить("ИдентификаторТранзакции", Новый УникальныйИдентификатор); + Контекст.Вставить("Список", Неопределено); + Контекст.Вставить("ПолноеИмя", Неопределено); + Контекст.Вставить("ТипыЗначенийДоступа", Неопределено); + + Если ТипЗнч(ОписаниеСписков) = Тип("ФиксированныйМассив") Тогда + ИдентификаторыСписковПоПолнымИменам = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ОписаниеСписков); + Иначе + ПолныеИмена = ОписаниеСписков.ВыгрузитьКолонку("Таблица"); + ОбъектыМетаданныхСписков = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ПолныеИмена, Ложь); + КонецЕсли; + + Списки = Новый Массив; + СпискиДляПользователей = Новый Массив; + СпискиДляВнешнихПользователей = Новый Массив; + + Для Каждого ОписаниеСписка Из ОписаниеСписков Цикл + Если ИдентификаторыСписковПоПолнымИменам <> Неопределено Тогда + Контекст.ПолноеИмя = ОписаниеСписка; + Контекст.Список = ИдентификаторыСписковПоПолнымИменам.Получить(Контекст.ПолноеИмя); + Иначе + ОбъектМетаданных = ОбъектыМетаданныхСписков.Получить(ОписаниеСписка.Таблица); + Контекст.ПолноеИмя = ?(ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных"), ОбъектМетаданных.ПолноеИмя(), ""); + Контекст.Список = ОписаниеСписка.Таблица; + Если ТипЗнч(ОписаниеСписка) = Тип("СтрокаДереваЗначений") Тогда + Контекст.ТипыЗначенийДоступа = ОписаниеСписка.Строки; + КонецЕсли; + КонецЕсли; + Если Не ЗначениеЗаполнено(Контекст.ПолноеИмя) Тогда + Продолжить; + КонецЕсли; + ЗапланироватьДляПользователей = ДляПользователей + И ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, Ложь); + + ЗапланироватьДляВнешнихПользователей = ДляВнешнихПользователей + И ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, Истина); + + Если ЗапланироватьДляПользователей И ЗапланироватьДляВнешнихПользователей Тогда + Списки.Добавить(Контекст.ПолноеИмя); + + ИначеЕсли ЗапланироватьДляПользователей Тогда + СпискиДляПользователей.Добавить(Контекст.ПолноеИмя); + + ИначеЕсли ЗапланироватьДляВнешнихПользователей Тогда + СпискиДляВнешнихПользователей.Добавить(Контекст.ПолноеИмя); + КонецЕсли; + КонецЦикла; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.КлючиДоступаКДанным = Ложь; + ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; + ПараметрыПланирования.Описание = Описание; + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); + + ПараметрыПланирования.ДляПользователей = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеПользователейКлючейДоступа. +Функция ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, ДляВнешнихПользователей) + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Контекст.ИдентификаторТранзакции, Неопределено, Ложь); + Если ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + + Если Не Контекст.ПриИзмененииУчастниковГруппыДоступа + И ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(Контекст.ПолноеИмя) <> Неопределено + И ДополнительныйКонтекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(Контекст.ПолноеИмя) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + + СвойстваОграничения = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Контекст.ПолноеИмя); + + Если ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(Контекст.ПолноеИмя) <> Неопределено + Или СвойстваОграничения = Неопределено + Или СвойстваОграничения.ДоступЗапрещен + Или СвойстваОграничения.ПолеВладельца <> Неопределено + И Не СвойстваОграничения.ПолеВладельца.Отключено + Или Контекст.ПриИзмененииУчастниковГруппыДоступа + И Не СвойстваОграничения.РассчитыватьПраваПользователей Тогда + + Возврат Ложь; + КонецЕсли; + + Если СвойстваОграничения <> Неопределено + И Контекст.ТипыЗначенийДоступа <> Неопределено + И Не Контекст.ПриИзмененииУчастниковГруппыДоступа Тогда + + СредиИзмененныхТиповЗначенийДоступаНетИспользуемых = Истина; + ИспользуемыеТипыЗначенийДоступа = СвойстваОграничения.ИспользуемыеТипыЗначенийДоступа.Получить(); // Массив из Тип + Для Каждого Строка Из Контекст.ТипыЗначенийДоступа Цикл + Если ИспользуемыеТипыЗначенийДоступа.Найти(Строка.ТипЗначенийДоступа) <> Неопределено Тогда + СредиИзмененныхТиповЗначенийДоступаНетИспользуемых = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если СредиИзмененныхТиповЗначенийДоступаНетИспользуемых Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для процедуры ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа и +// модулей менеджера и объекта справочника ГруппыДоступа. +// +Процедура ЗапланироватьОбновлениеНаборовГруппДоступа(Описание, ДляПользователей = Истина, ДляВнешнихПользователей = Истина) Экспорт + + Если Не ДляПользователей И Не ДляВнешнихПользователей Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + + Список = "Справочник.НаборыГруппДоступа"; + КлючУникальности = Новый УникальныйИдентификатор; + ИдентификаторСписка = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Список); + ТекущаяДата = ТекущаяДатаСеанса(); + МаксимальнаяДата = МаксимальнаяДата(); + + // Обновление только по изменениям (не полное). + ПараметрыЗадания = Новый Структура; + УстановитьВидКлючаДанных(ПараметрыЗадания, "НовыеНаборыИзОдногоПользователя"); + ХранилищеПараметровЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); + + Если ДляПользователей Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальности; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Ложь; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = 3; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДата; + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальности; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Истина; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = 3; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДата; + КонецЕсли; + + НаборЗаписей.Записать(Ложь); + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.ДляПользователей = ДляПользователей; + ПараметрыПланирования.ДляВнешнихПользователей = ДляВнешнихПользователей; + ПараметрыПланирования.Описание = Описание; + + СпискиПоИдентификаторам = Новый Соответствие; + СпискиПоИдентификаторам.Вставить(ИдентификаторСписка, Список); + + ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений. +// +Процедура ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, ИмяИзмененныхДанных) + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.КлючиДоступаКДанным = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ПараметрыПланирования.Описание = Описание; + ПараметрыПланирования.ВедущийОбъект = Новый Структура("ПоДаннымКэшаРасчетаПрав", ИмяИзмененныхДанных); + ЗапланироватьОбновлениеДоступа(СписокДляПланированияОбновленияКэшаРасчетаПрав(), ПараметрыПланирования); + +КонецПроцедуры + +// Для процедур ПодготовитьПланОбновления, ЗапланироватьОбновлениеКэшаРасчетаПрав +// и функции ВерсияДанныхДляКэшаРасчетаПрав. +// +Функция СписокДляПланированияОбновленияКэшаРасчетаПрав() + + Возврат "РегистрСведений.ПараметрыРаботыВерсийРасширений"; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ТаблицыГруппДоступа - Строка +// - Неопределено +// * ЗначенияГруппДоступа - Строка +// - Неопределено +// * УчастникиГруппДоступа - Строка +// - Неопределено +// * СоставыГруппПользователей - Строка +// - Неопределено +// * РолиПрофилейГруппДоступа - Строка +// - Неопределено +// * ГруппыДоступаПрофилей - Строка +// - Неопределено +// +Функция НоваяВерсияДанныхДляКэшаРасчетаПрав(Версия = Неопределено) Экспорт + + НоваяВерсияДанных = Новый Структура; + НоваяВерсияДанных.Вставить("ТаблицыГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("ЗначенияГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("УчастникиГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("СоставыГруппПользователей", Версия); + НоваяВерсияДанных.Вставить("РолиПрофилейГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("ГруппыДоступаПрофилей", Версия); + + Возврат НоваяВерсияДанных; + +КонецФункции + +// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. +Функция ИмяПараметраВерсииДанныхДляКэшаРасчетаПрав() + + Возврат "СтандартныеПодсистемы.УправлениеДоступом.ВерсияДанныхДляКэшаРасчетаПрав"; + +КонецФункции + +#КонецОбласти + +#Область ОбновлениеДоступа + +// Для процедуры ЗапуститьОбновлениеДоступа. +Функция ЕстьЗапланированныеТочечныеЗадания() + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("СписокДляПланированияОбновленияКэшаРасчетаПрав", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(СписокДляПланированияОбновленияКэшаРасчетаПрав(), Ложь)); + + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + |ГДЕ + | ОбновлениеКлючейДоступаКДанным.ТочечноеЗадание + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей + |ГДЕ + | ОбновлениеКлючейДоступаПользователей.ТочечноеЗадание + | И ОбновлениеКлючейДоступаПользователей.Список <> &СписокДляПланированияОбновленияКэшаРасчетаПрав"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Запускает фоновое задание обновления доступа вместо регламентного задания. +// +// Параметры: +// ЭтоЗапускВручную - Булево - если передать Ложь, то наименование будет начинаться с "Автозапуск", +// в противном случае, наименование будет начинаться с "Запуск вручную", +// блокировка обновления доступа будет снята, если была установлена, +// выполнение будет продолжаться до полного завершения. +// ЭтоПерезапуск - Булево - если передать Истина, тогда текущий сеанс фонового задания не будет +// считаться незавершенным исполнителем. +// ДляУскорения - Булево - если передать Истина, тогда признак передается в процедуру обновления доступа, +// чтобы прекратить обновление, когда точечных заданий нет и функция +// ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий возвращает Истина. +// +// Возвращаемое значение: +// - Неопределено - обновление доступа не требуется или запрещено. +// - Структура: +// * УжеВыполняется - Булево - если обновление уже выполняется. +// +// * ИдентификаторФоновогоЗадания - Неопределено - если обновление не выполняется или +// выполняется не в фоновом задании. +// - УникальныйИдентификатор - идентификатор фонового задания. +// +// * СвойстваСеанса - Неопределено - если запуска не было или фоновое задание только добавлено в очередь. +// - Структура - со свойствами сеанса, если обновление уже выполняется: +// ** ИмяКомпьютера - Строка - одноименное свойства объекта СеансИнформационнойБазы. +// ** НомерСеанса - Число - одноименное свойства объекта СеансИнформационнойБазы. +// ** НачалоСеанса - Строка - одноименное свойства объекта СеансИнформационнойБазы. +// +// * ТекстПредупреждения - Неопределено - если запуска не было или запущено новое фоновое задание. +// - Строка - описание, что обновление доступа уже запущено. +// +Функция ЗапуститьОбновлениеДоступаНаУровнеЗаписей(ЭтоЗапускВручную = Ложь, ЭтоПерезапуск = Ложь, ДляУскорения = Ложь) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно запустить обновление доступа на уровне записей, так как + |константа %1 выключена.'"), + "ОграничиватьДоступНаУровнеЗаписейУниверсально"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ТранзакцияАктивна() Тогда + ТекстОшибки = + НСтр("ru = 'Невозможно запустить обновление доступа на уровне записей в открытой транзакции.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Не ЭтоЗапускВручную И Не ЗапланированоОбновлениеДоступа() Тогда + Возврат Неопределено; + КонецЕсли; + + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(); + Если Не ЭтоЗапускВручную И ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Возврат Неопределено; + КонецЕсли; + + ИдентификаторИсключаемогоЗадания = Неопределено; + Если ЭтоПерезапуск Тогда + ТекущееФоновоеЗадание = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание(); + Если ТекущееФоновоеЗадание <> Неопределено Тогда + ИдентификаторИсключаемогоЗадания = ТекущееФоновоеЗадание.УникальныйИдентификатор; + КонецЕсли; + КонецЕсли; + Результат = Новый Структура("УжеВыполняется, ТекстПредупреждения, ИдентификаторФоновогоЗадания, СвойстваСеанса", Истина, ""); + Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторИсключаемогоЗадания); + + Если Исполнитель = Неопределено Тогда + Результат.УжеВыполняется = Ложь; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Попытка + // В файловой ИБ перезапуск фонового задания с расширениями базы данных + // выполняется с той же версией динамического поколения конфигурации. + СтандартныеПодсистемыСервер.ПроверитьДинамическоеОбновлениеВерсииПрограммы(); + Исключение + Результат.ТекстПредупреждения = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); + Возврат Результат; + КонецПопытки; + КонецЕсли; + Если ЭтоЗапускВручную Тогда + УстановитьЗапретОбновленияДоступа(Ложь); + ПараметрыЗадания = Новый Массив; + ПараметрыЗадания.Добавить(Истина); + ИначеЕсли ЭтоПерезапуск Или ДляУскорения Тогда + ДополнительныеПараметры = НовыеДополнительныеПараметрыОбновленияДоступа(); + ДополнительныеПараметры.ЭтоПерезапуск = ЭтоПерезапуск; + ДополнительныеПараметры.ДляУскорения = ДляУскорения; + ПараметрыЗадания = Новый Массив; + ПараметрыЗадания.Добавить(Ложь); + ПараметрыЗадания.Добавить(Ложь); + ПараметрыЗадания.Добавить(ДополнительныеПараметры); + Иначе + ПараметрыЗадания = Неопределено; + КонецЕсли; + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + НаименованиеЗадания = + ?(ЭтоЗапускВручную, + НСтр("ru = 'Запуск вручную'", ОбщегоНазначения.КодОсновногоЯзыка()), + НСтр("ru = 'Автозапуск'", ОбщегоНазначения.КодОсновногоЯзыка())) + + ": " + Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.Синоним + " (" + + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'из сеанса %1 от %2'", ОбщегоНазначения.КодОсновногоЯзыка()), + Формат(ТекущийСеанс.НомерСеанса, "ЧГ="), + Формат(ТекущийСеанс.НачалоСеанса, "ДЛФ=DT")) + ")"; + + ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных( + ИмяМетодаЗаданияОбновленияДоступа(), ПараметрыЗадания,, НаименованиеЗадания); + + Результат.ИдентификаторФоновогоЗадания = ФоновоеЗадание.УникальныйИдентификатор; + + ИначеЕсли ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") + И Исполнитель.УникальныйИдентификатор <> ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания Тогда + + Результат.ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже запущено %1 в %2'"), + Формат(Исполнитель.Начало, "ДЛФ=D"), + Формат(Исполнитель.Начало, "ДЛФ=T")); + Иначе + СвойстваСеанса = Новый Структура("ИмяКомпьютера, НомерСеанса, НачалоСеанса"); + Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") Тогда + ЗаполнитьЗначенияСвойств(СвойстваСеанса, ПоследнееОбновлениеДоступа); + Иначе + ЗаполнитьЗначенияСвойств(СвойстваСеанса, Исполнитель); + КонецЕсли; + Результат.СвойстваСеанса = СвойстваСеанса; + Результат.ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обновление доступа уже выполняется + |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), + СвойстваСеанса.ИмяКомпьютера, + СвойстваСеанса.НомерСеанса, + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=D"), + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=T")); + КонецЕсли; + + Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") Тогда + Результат.ИдентификаторФоновогоЗадания = Исполнитель.УникальныйИдентификатор; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Отменить обновление доступа, которое выполняется в фоновом задании. +Процедура ОтменитьОбновлениеДоступаНаУровнеЗаписей() Экспорт + + Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа()); + + Если ТипЗнч(Исполнитель) = Тип("СеансИнформационнойБазы") Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно отменить полное обновление доступа + |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), + Исполнитель.ИмяКомпьютера, + Исполнитель.НомерСеанса, + Формат(Исполнитель.НачалоСеанса, "ДЛФ=D"), + Формат(Исполнитель.НачалоСеанса, "ДЛФ=T")); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Выполняется = ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание"); + + ЗавершитьПотокиОбновленияДоступа(Истина); + УстановитьЗапретОбновленияДоступа(Истина, Выполняется); + + Если Выполняется Тогда + Исполнитель = Исполнитель.ОжидатьЗавершенияВыполнения(СекундОжиданияЗавершенияФоновогоЗадания()); + Если Исполнитель.Состояние = СостояниеФоновогоЗадания.Активно Тогда + Исполнитель.Отменить(); + КонецЕсли; + КонецЕсли; + + Отбор = Новый Структура; + Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно); + Отбор.Вставить("ИмяМетода", ИмяМетодаЗаданияОбновленияДоступа()); + ОсновныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); + + Для Каждого ОсновноеЗадание Из ОсновныеЗадания Цикл + ОсновноеЗадание = ОсновноеЗадание.ОжидатьЗавершенияВыполнения(1); + Если ОсновноеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + ОсновноеЗадание.Отменить(); + КонецЕсли; + КонецЦикла; + + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(); + +КонецПроцедуры + +// Для процедуры УстановитьОбновлениеДоступа. +Процедура ВключитьРегламентноеЗаданиеОбновленияДоступа() Экспорт + + ИзменитьРегламентноеЗаданиеОбновленияДоступа(Истина); + +КонецПроцедуры + +// Для процедуры УстановитьОбновлениеДоступа. +Процедура ОтключитьРегламентноеЗаданиеОбновленияДоступа() Экспорт + + ИзменитьРегламентноеЗаданиеОбновленияДоступа(Ложь); + +КонецПроцедуры + +// Для процедуры УстановитьОбновлениеДоступа. +Процедура ИзменитьРегламентноеЗаданиеОбновленияДоступа(ВключитьЗадание) + + Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); + + ТребуетсяИзменить = Ложь; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ТребуетсяИзменить = Истина; + Иначе + УстановитьПривилегированныйРежим(Истина); + Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); + Для Каждого Задание Из Задания Цикл + Если ВключитьЗадание <> Задание.Использование Тогда + ТребуетсяИзменить = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + УстановитьПривилегированныйРежим(Ложь); + КонецЕсли; + + Если Не ТребуетсяИзменить Тогда + Возврат; + КонецЕсли; + + ЭтоОшибкаБлокировки = Ложь; + НомерПопыткиБлокировки = 0; + Пока Истина Цикл + НомерПопыткиБлокировки = НомерПопыткиБлокировки + 1; + НачатьТранзакцию(); + Попытка + ЭтоОшибкаБлокировки = Истина; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + РегламентныеЗаданияСервер.ЗаблокироватьРегламентноеЗадание(Новый УникальныйИдентификатор); + КонецЕсли; + ЭтоОшибкаБлокировки = Ложь; + УстановитьПривилегированныйРежим(Истина); + Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); + Для Каждого Задание Из Задания Цикл + Если ВключитьЗадание = Задание.Использование Тогда + Продолжить; + КонецЕсли; + РегламентныеЗаданияСервер.ИзменитьЗадание(Задание, + Новый Структура("Использование", ВключитьЗадание)); + КонецЦикла; + УстановитьПривилегированныйРежим(Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + Если ЭтоОшибкаБлокировки + И НомерПопыткиБлокировки <= 3 + И Не ТранзакцияАктивна() Тогда + Продолжить; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + Прервать; + КонецЦикла; + +КонецПроцедуры + +// Включает или отключает запрет обновления доступа при запуске +// с помощью регламентного задания или при программном запуске. +// +// При вызове процедуры ОбновлениеДоступаНаУровнеЗаписей +// с признаком ОбновитьВсе запрет игнорируется. +// +// При вызове процедуры ЗапуститьОбновлениеДоступаНаУровнеЗаписей +// с признаком ЭтоЗапускВручную запрет снимается автоматически. +// +Процедура УстановитьЗапретОбновленияДоступа(Использование, ОтменитьОбновление = Ложь) Экспорт + + БлокировкаДанных = Новый БлокировкаДанных; + БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); + + ЕстьВнешняяТранзакция = ТранзакцияАктивна(); + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + Записать = Ложь; + Если ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено <> Использование Тогда + ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено = Использование; + Записать = Истина; + КонецЕсли; + + Если ОтменитьОбновление + И ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере > ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере + И ( Не ПоследнееОбновлениеДоступа.ОбновлениеОтменено + Или ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения <> "") Тогда + + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Истина; + ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ""; + ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = '00010101'; + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере = ТекущаяДатаНаСервере(); + ПоследнееОбновлениеДоступа.ПоследнееВыполнениеСекунд = + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере + + СекундОжиданияЗавершенияФоновогоЗадания() + 1; + Записать = Истина; + КонецЕсли; + + Если Записать Тогда + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедур ОтменитьОбновлениеДоступаНаУровнеЗаписей, УстановитьЗапретОбновленияДоступа. +Функция СекундОжиданияЗавершенияФоновогоЗадания() + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Возврат 3; + Иначе + Возврат 15; + КонецЕсли; + +КонецФункции + +// Обработчик регламентного задания ОбновлениеДоступаНаУровнеЗаписей. +Процедура ОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе = Ложь, ВызыватьИсключениеВместоРегистрацииОшибки = Ложь, + ДополнительныеПараметры = Неопределено) Экспорт + + // Регламентное задание должно запускаться сразу, как только было запланировано обновление доступа. + // После обработки первой порции по всем таблицам (2 мин на все) можно сделать + // небольшую паузу вместо непрерывного выполнения до конца. + // В данном случае пауза - это перезапуск через 15 секунд. + // В отличие от обычных регламентных заданий это задание самоотключаемое, + // то есть после отработки запланированного обновления, задание выключает само себя и + // запуски полностью прекращаются до того, как будет запланировано новое обновление доступа. + + ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания( + Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); + + ВыполнитьОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе, ВызыватьИсключениеВместоРегистрацииОшибки, + 0, , ДополнительныеПараметры); + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// Структура: +// * ДляУскорения - Булево +// * ЭтоПерезапуск - Булево +// +Функция НовыеДополнительныеПараметрыОбновленияДоступа() + + Результат = Новый Структура; + Результат.Вставить("ДляУскорения", Ложь); + Результат.Вставить("ЭтоПерезапуск", Ложь); + + Возврат Результат; + +КонецФункции + +// Выполняет обновление доступа, если запланировано. +Процедура ВыполнитьОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе, ВызыватьИсключениеВместоРегистрацииОшибки, + СекундНеБолее, ПослеОбновлениеИБ = Ложь, ДополнительныеПараметры = Неопределено) + + Если ОбновитьВсе Тогда + СекундНеБолее = 0; + КонецЕсли; + + НовыеДополнительныеПараметры = НовыеДополнительныеПараметрыОбновленияДоступа(); + Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда + ЗаполнитьЗначенияСвойств(НовыеДополнительныеПараметры, ДополнительныеПараметры); + КонецЕсли; + ДополнительныеПараметры = НовыеДополнительныеПараметры; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + УстановитьЭтоСеансФоновогоОбновленияДоступа(); + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + ОписаниеОсновногоСеанса = ОписаниеОсновногоСеанса(); + ОписаниеОсновногоСеанса.Вставить("НомерСеанса", ТекущийСеанс.НомерСеанса); + ОписаниеОсновногоСеанса.Вставить("НачалоСеанса", ТекущийСеанс.НачалоСеанса); + + Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда + Если ОбновитьВсе Тогда + ИдентификаторФоновогоЗадания = ИдентификаторПроизвольногоСеанса(); + Иначе + ТекстОшибки = НСтр("ru = 'Обновление доступа может выполняться порциями только в фоновом задании.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ИдентификаторОсновногоСеанса = Строка(Новый УникальныйИдентификатор); + Иначе + ТекущееФоновоеЗадание = ТекущийСеанс.ПолучитьФоновоеЗадание(); + Если ТекущееФоновоеЗадание = Неопределено Тогда + ТекстОшибки = НСтр("ru = 'Не удалось получить фоновое задание текущего сеанса.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ИдентификаторФоновогоЗадания = ТекущееФоновоеЗадание.УникальныйИдентификатор; + ОписаниеОсновногоСеанса.ФоновоеЗадание = ТекущееФоновоеЗадание; + ОписаниеОсновногоСеанса.ИдентификаторФоновогоЗадания = ИдентификаторФоновогоЗадания; + ИдентификаторОсновногоСеанса = Строка(ИдентификаторФоновогоЗадания); + КонецЕсли; + ОписаниеОсновногоСеанса.Вставить("Идентификатор", ИдентификаторОсновногоСеанса + + " (" + НСтр("ru = 'Идентификатор основного сеанса'") + ")"); + + БлокировкаДанных = Новый БлокировкаДанных; + БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); + + ЕстьВнешняяТранзакция = ТранзакцияАктивна(); + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + Если ОбновитьВсе Или Не ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторФоновогоЗадания); + + Если Исполнитель = Неопределено Тогда + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Ложь; + ПоследнееОбновлениеДоступа.ДляУскорения = ДополнительныеПараметры.ДляУскорения; + ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере = ТекущаяДатаНаСервере(); + ПоследнееОбновлениеДоступа.НомерСеанса = ТекущийСеанс.НомерСеанса; + ПоследнееОбновлениеДоступа.НачалоСеанса = ТекущийСеанс.НачалоСеанса; + ПоследнееОбновлениеДоступа.ИмяКомпьютера = ТекущийСеанс.ИмяКомпьютера; + ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = ИдентификаторФоновогоЗадания; + + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + КонецЕсли; + + Если ПоследнееОбновлениеДоступа.ДляУскорения И Не ДополнительныеПараметры.ДляУскорения Тогда + ПоследнееОбновлениеДоступа.ДляУскорения = Ложь; + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если Не ОбновитьВсе И ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Если ТекущееФоновоеЗадание.РегламентноеЗадание <> Неопределено Тогда + УстановитьОбновлениеДоступа(Ложь); + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обновление доступа запрещено. + |Чтобы разрешить нужно нажать ""Разрешить"" в форме ""Обновление доступа на уровне записей"". + |Форму можно открыть из панели ""Настройки пользователей и прав"" или перейти по навигационной ссылке: + |%1'"), + "e1cib/app/РегистрСведений.ОбновлениеКлючейДоступаКДанным.Форма.ОбновлениеДоступаНаУровнеЗаписей"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Исполнитель <> Неопределено Тогда + Если Не ОбновитьВсе Или ПослеОбновлениеИБ Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") + И Исполнитель.УникальныйИдентификатор <> ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже запущено %1 в %2'"), + Формат(Исполнитель.Начало, "ДЛФ=D"), + Формат(Исполнитель.Начало, "ДЛФ=T")); + Иначе + СвойстваСеанса = ?(ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание"), + ПоследнееОбновлениеДоступа, Исполнитель); + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже выполняется + |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), + СвойстваСеанса.ИмяКомпьютера, + СвойстваСеанса.НомерСеанса, + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=D"), + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=T")); + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Ложь; + ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ""; + ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор(); + + ПерезапускВозможен = ТекущееФоновоеЗадание <> Неопределено + И Не ОбновитьВсе + И Не ВызыватьИсключениеВместоРегистрацииОшибки + И СекундНеБолее = 0 + И Не ПослеОбновлениеИБ; + + ТекстВсехОшибок = ""; + ДатаПолногоЗавершения = ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения; + + ПараметрыВыполнения = Новый Структура; + ПараметрыВыполнения.Вставить("СекундНеБолее", СекундНеБолее); + ПараметрыВыполнения.Вставить("ТекстОшибкиПланирования", ""); + ПараметрыВыполнения.Вставить("ТекстОшибкиЗавершения", ""); + ПараметрыВыполнения.Вставить("ОписаниеОсновногоСеанса", ОписаниеОсновногоСеанса); + Попытка + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + ВыполнитьОбновлениеДоступа(ОбновитьВсе, ПараметрыВыполнения, ПоследнееОбновлениеДоступа); + Если Не ПерезапускВозможен Тогда + СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(ТекстВсехОшибок); + КонецЕсли; + Иначе + УстановитьОбновлениеДоступа(Ложь); + КонецЕсли; + Исключение + Если ТранзакцияАктивна() Тогда + ВызватьИсключение; + КонецЕсли; + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстВсехОшибок = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + Если ПерезапускВозможен + И СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + ТекстВсехОшибок = ""; + КонецЕсли; + КонецПопытки; + + Попытка + ЗавершитьПотокиОбновленияДоступа(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось завершить потоки обновления доступа по причине: + |%1'"), + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке))); + КонецПопытки; + + Попытка + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(2); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось отменить фоновые задания потоков обновления доступа по причине: + |%1'"), + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке))); + КонецПопытки; + + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, ПараметрыВыполнения.ТекстОшибкиПланирования); + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, ПараметрыВыполнения.ТекстОшибкиЗавершения); + + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере = ТекущаяДатаНаСервере(); + Если ЗначениеЗаполнено(ТекстВсехОшибок) Тогда + ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = '00010101'; + КонецЕсли; + Если Не ЗначениеЗаполнено(ДатаПолногоЗавершения) + Или ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения <> ДатаПолногоЗавершения Тогда + + ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ТекстВсехОшибок; + ПоследнееОбновлениеДоступа.ПоследнееВыполнениеСекунд = + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере; + КонецЕсли; + + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ТекущееПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено = + ТекущееПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено; + + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ПерезапускВозможен И СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + ЗапуститьОбновлениеДоступаНаУровнеЗаписей(, Истина, ПоследнееОбновлениеДоступа.ДляУскорения); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ТекстВсехОшибок) Тогда + Возврат; + КонецЕсли; + + ТекстВсехОшибок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось выполнить обновление доступа по причине: + |%1'"), ТекстВсехОшибок); + + Если ВызыватьИсключениеВместоРегистрацииОшибки Тогда + ВызватьИсключение ТекстВсехОшибок; + Иначе + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстВсехОшибок, + Новый Структура("ОписаниеОсновногоСеанса", ОписаниеОсновногоСеанса)); + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ИдентификаторФоновогоЗадания - УникальныйИдентификатор +// * ФоновоеЗадание - ФоновоеЗадание +// * НомерСеанса - Число +// * НачалоСеанса - Дата +// * Идентификатор - Строка - представление сеанса +// +Функция ОписаниеОсновногоСеанса() + + Возврат Новый Структура("ИдентификаторФоновогоЗадания, ФоновоеЗадание"); + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей. +Функция ЗапланированоОбновлениеДоступа() + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей и +// процедур ОбновлениеДоступаНаУровнеЗаписей, ОтменитьОбновлениеДоступаНаУровнеЗаписей и +// формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Возвращаемое значение: +// Структура: +// * ДатаЗапускаНаСервере - Дата +// * ДатаЗавершенияНаСервере - Дата +// * ОбновлениеОтменено - Булево +// * ПоследнееВыполнениеСекунд - Число +// * ДатаПолногоЗавершения - Дата +// * ТекстОшибкиЗавершения - Строка +// * НомерСеанса - Число +// * ИмяКомпьютера - Строка +// * ОбновлениеДоступаЗапрещено - Булево +// * БалансировкаНагрузкиНаДиск - Булево +// * ИдентификаторФоновогоЗадания - УникальныйИдентификатор +// * ПоследнееПланированиеОбработкиУстаревшихЭлементов - Дата +// +Функция ПоследнееОбновлениеДоступа(ТекущееЗначение = Неопределено) Экспорт + + Если ТекущееЗначение = Неопределено Тогда + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ПоследнееОбновлениеДоступа.Значение КАК Значение + |ИЗ + | Константа.ПоследнееОбновлениеДоступа КАК ПоследнееОбновлениеДоступа"; + + Выборка = Запрос.Выполнить().Выбрать(); + ТекущееЗначение = ?(Выборка.Следующий(), Выборка.Значение, Неопределено); + КонецЕсли; + + Свойства = Новый Структура; + Свойства.Вставить("ДатаЗапускаНаСервере", '00010101'); + Свойства.Вставить("ДатаЗавершенияНаСервере", '00010101'); + Свойства.Вставить("ОбновлениеОтменено", Ложь); + Свойства.Вставить("ПоследнееВыполнениеСекунд", 0); + Свойства.Вставить("ДатаПолногоЗавершения", '00010101'); + Свойства.Вставить("ТекстОшибкиЗавершения", ""); + Свойства.Вставить("НомерСеанса", 0); + Свойства.Вставить("НачалоСеанса", '00010101'); + Свойства.Вставить("ИмяКомпьютера", ""); + Свойства.Вставить("ОбновлениеДоступаЗапрещено", Ложь); + Свойства.Вставить("БалансировкаНагрузкиНаДиск", Истина); + Свойства.Вставить("ИдентификаторДоступа"); + Свойства.Вставить("ИдентификаторФоновогоЗадания", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + Свойства.Вставить("ПоследнееПланированиеОбработкиУстаревшихЭлементов", '00010101'); + Свойства.Вставить("ДляУскорения", Ложь); + + Если ТипЗнч(ТекущееЗначение) <> Тип("ХранилищеЗначения") Тогда + Возврат Свойства; + КонецЕсли; + + ТекущиеСвойства = ТекущееЗначение.Получить(); + + Если ТипЗнч(ТекущиеСвойства) <> Тип("Структура") Тогда + Возврат Свойства; + КонецЕсли; + + ЗаполнитьЗначенияСвойств(Свойства, ТекущиеСвойства); + + Возврат Свойства; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаНаУровнеЗаписей, +// УстановитьЗапретОбновленияДоступа и УстановитьБалансировкуНагрузкиНаДиск. +// +Процедура УстановитьПоследнееОбновлениеДоступа(Свойства, ЕстьВнешняяТранзакция) + + Если Не ЗначениеЗаполнено(Свойства.ИдентификаторДоступа) И Не ЕстьВнешняяТранзакция Тогда + Свойства.ИдентификаторДоступа = Новый УникальныйИдентификатор; + КонецЕсли; + + МенеджерЗначения = СлужебныйМенеджерЗначения(Константы.ПоследнееОбновлениеДоступа); + МенеджерЗначения.Значение = Новый ХранилищеЗначения(Свойства); + МенеджерЗначения.Записать(); + +КонецПроцедуры + +// Для константы ОграничиватьДоступНаУровнеЗаписейУниверсально. +Процедура ОчиститьПоследнееОбновлениеДоступа() Экспорт + + Свойства = ПоследнееОбновлениеДоступа(Null); + ЗаполнитьЗначенияСвойств(Свойства, ПоследнееОбновлениеДоступа(), + "ИдентификаторДоступа, ОбновлениеДоступаЗапрещено, БалансировкаНагрузкиНаДиск"); + + МенеджерЗначения = СлужебныйМенеджерЗначения(Константы.ПоследнееОбновлениеДоступа); + МенеджерЗначения.Значение = Новый ХранилищеЗначения(Свойства); + МенеджерЗначения.Записать(); + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей и +// процедур ОбновлениеДоступаНаУровнеЗаписей, ОтменитьОбновлениеДоступаНаУровнеЗаписей и +// формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Параметры: +// ПоследнееОбновлениеДоступа - см. ПоследнееОбновлениеДоступа +// ИдентификаторИсключаемогоЗадания - УникальныйИдентификатор +// - Неопределено +// +// Возвращаемое значение: +// - ФоновоеЗадание +// - СеансИнформационнойБазы +// - Неопределено +// +Функция ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторИсключаемогоЗадания = Неопределено) Экспорт + + Если ЗначениеЗаполнено(ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания) Тогда + Если ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = ИдентификаторПроизвольногоСеанса() Тогда + Сеансы = ПолучитьСеансыИнформационнойБазы(); + Для Каждого Сеанс Из Сеансы Цикл + Если Сеанс.НомерСеанса = ПоследнееОбновлениеДоступа.НомерСеанса + И Сеанс.НачалоСеанса = ПоследнееОбновлениеДоступа.НачалоСеанса Тогда + Возврат Сеанс; + КонецЕсли; + КонецЦикла; + Иначе + ИсполняющееФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору( + ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания); + + Если ИсполняющееФоновоеЗадание <> Неопределено + И ИсполняющееФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + + Возврат ИсполняющееФоновоеЗадание; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Отбор = Новый Структура("Состояние, ИмяМетода", СостояниеФоновогоЗадания.Активно, + ИмяМетодаЗаданияОбновленияДоступа()); + + НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); + Для Каждого НайденноеЗадание Из НайденныеЗадания Цикл + Если НайденноеЗадание.УникальныйИдентификатор <> ИдентификаторИсключаемогоЗадания Тогда + Возврат НайденноеЗадание; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ОбновлениеДоступаНаУровнеЗаписей, ИсполнительОбновленияДоступа. +Функция ИдентификаторПроизвольногоСеанса() + + Возврат Новый УникальныйИдентификатор("ba4730f7-0493-402d-b5d3-8052c80fb125"); + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступа, ДобавитьЗаданияОбновленияДоступа и +// ОбновитьСоставИспользуемыхВерсийПараметровШаблонов. +// +// Параметры: +// Контекст - см. НовыйКонтекстОбновленияДоступа +// ПриЗапуске - Булево +// +Процедура ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст, ПриЗапуске = Ложь) + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + НачалоПроверки = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(, Истина); + + ДатаОбновленияВерсииРасширений = Справочники.ВерсииРасширений.ПоследняяВерсияРасширений().ДатаОбновления; + + ДатаОбновленияВсехПараметровРаботыПрограммы = + РегистрыСведений.ПараметрыРаботыПрограммы.ДатаОбновленияВсехПараметровРаботыПрограммы(); + + ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений = + РегистрыСведений.ПараметрыРаботыВерсийРасширений.ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений(); + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + ДатаСозданияПараметровОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа.ДатаСоздания; + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; + ДатаПроверкиПараметровОграниченияДоступа = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + Если ТипЗнч(ДатаПроверкиПараметровОграниченияДоступа) <> Тип("Дата") Тогда + ДатаПроверкиПараметровОграниченияДоступа = '00010101'; + КонецЕсли; + + Если ДатаПроверкиПараметровОграниченияДоступа > ДатаСозданияПараметровОграниченияДоступа Тогда + ДатаАктуальностиПараметровОграниченияДоступа = ДатаПроверкиПараметровОграниченияДоступа; + Иначе + ДатаАктуальностиПараметровОграниченияДоступа = ДатаСозданияПараметровОграниченияДоступа; + КонецЕсли; + + Если ДатаАктуальностиПараметровОграниченияДоступа > ТекущаяДатаСеанса() Тогда + ДатаАктуальностиПараметровОграниченияДоступа = '00010101'; + КонецЕсли; + + ИспользованиеВидовДоступаИзменено = ИспользованиеВидовДоступаИзменено(ДействующиеПараметры); + + ВерсияТекстовОграниченияДоступаИзменена = Ложь; + ТекущаяВерсияТекстов = Неопределено; + Если ПриЗапуске Тогда + ТекущаяВерсияТекстов = РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(); + Если ДействующиеПараметры.ВерсияТекстовОграниченияДоступа <> ТекущаяВерсияТекстов Тогда + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; + ПоследняяВерсияТекстов = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + ВерсияТекстовОграниченияДоступаИзменена = ПоследняяВерсияТекстов <> ТекущаяВерсияТекстов; + КонецЕсли; + КонецЕсли; + + Если ДатаОбновленияВерсииРасширений > ДатаАктуальностиПараметровОграниченияДоступа + Или ДатаОбновленияВсехПараметровРаботыПрограммы > ДатаАктуальностиПараметровОграниченияДоступа + Или ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений > ДатаАктуальностиПараметровОграниченияДоступа + Или ИспользованиеВидовДоступаИзменено + Или ВерсияТекстовОграниченияДоступаИзменена + Или ПриЗапуске + И ЗапланированоОбновлениеПараметровОграниченияДоступа(ДатаАктуальностиПараметровОграниченияДоступа) Тогда + + Если Показатели <> Неопределено Тогда + НачалоОбновления = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + // Предварительное кэширование в файловой ИБ вне транзакции для предотвращения конфликтов блокировок. + ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом"); // СтандартныеПодсистемыПовтИсп.ИменаПодсистем + УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписей(); + УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + УправлениеДоступомСлужебныйПовтИсп.ПрофильАдминистратор(); + УправлениеДоступомСлужебныйПовтИсп.ГруппаДоступаАдминистраторы(); + СвойстваВидовДоступа(); + ВозможныеПраваДляНастройкиПравОбъектов(); + КонецЕсли; + + Если ИспользованиеВидовДоступаИзменено Тогда + Попытка + РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); + Исключение + РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); + КонецПопытки; + КонецЕсли; + Попытка + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); + Исключение + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); + КонецПопытки; + Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия > 100000000000000 Тогда + Попытка + УменьшитьНомераВерсийПараметровОграниченияДоступа(); + Исключение + УменьшитьНомераВерсийПараметровОграниченияДоступа(); + КонецПопытки; + КонецЕсли; + НоваяДатаПроверкиПараметровОграниченияДоступа = ТекущаяДатаСеанса(); + Попытка + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Истина); + Исключение + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Истина); + КонецПопытки; + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; + ПоследняяДата = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + ПоследняяДата = ?(ТипЗнч(ПоследняяДата) = Тип("Дата"), ПоследняяДата, '00010101'); + Если ПоследняяДата < НоваяДатаПроверкиПараметровОграниченияДоступа Тогда + Попытка + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + НоваяДатаПроверкиПараметровОграниченияДоступа, Истина); + Исключение + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + НоваяДатаПроверкиПараметровОграниченияДоступа, Истина); + КонецПопытки; + КонецЕсли; + Если ТекущаяВерсияТекстов = Неопределено Тогда + ТекущаяВерсияТекстов = РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(); + КонецЕсли; + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; + ПоследняяВерсияТекстов = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + Если ПоследняяВерсияТекстов <> ТекущаяВерсияТекстов Тогда + Попытка + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + ТекущаяВерсияТекстов, Истина); + Исключение + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + ТекущаяВерсияТекстов, Истина); + КонецПопытки; + КонецЕсли; + Если Показатели <> Неопределено Тогда + Показатели.ВремяОбновленияПараметровОграничения = Показатели.ВремяОбновленияПараметровОграничения + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОбновления); + КонецЕсли; + КонецЕсли; + + // Удаление устаревших параметров ограничения доступа. + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТекущаяВерсия", ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия); + Запрос.УстановитьПараметр("ДатаУстаревания", ТекущаяДатаСеанса() - 2 * 24 * 60 *60); + Запрос.Текст = + "ВЫБРАТЬ + | ПараметрыОграниченияДоступа.Версия КАК Версия, + | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания + |ИЗ + | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа + |ГДЕ + | ПараметрыОграниченияДоступа.Версия < &ТекущаяВерсия + | И ПараметрыОграниченияДоступа.ДатаСоздания <= &ДатаУстаревания + | + |УПОРЯДОЧИТЬ ПО + | Версия УБЫВ, + | ДатаСоздания УБЫВ"; + + // АПК:1328-выкл. См. 648.1.1. Допустимо чтение без предварительной + // управляемой разделяемой блокировки, так как используется только + // для очистки и какой сеанс очистит первым не важно. + // Если установить разделяемую блокировку, то позже будет повышение + // до исключительной, что ведет к взаимоблокировке и недопустимо. + // Если установить исключительную блокировку на таблицу, то + // это вызовет избыточное замедление запуска сеансов при установке + // параметров сеанса из параметров ограничения, что недопустимо. + РезультатЗапроса = Запрос.Выполнить(); + // АПК:1328-вкл. + + Если Не РезультатЗапроса.Пустой() Тогда + НаборЗаписей = РегистрыСведений.ПараметрыОграниченияДоступа.СоздатьНаборЗаписей(); + Выборка = РезультатЗапроса.Выбрать(); + Пока Выборка.Следующий() Цикл + НаборЗаписей.Отбор.Версия.Установить(Выборка.Версия); + Попытка + НаборЗаписей.Записать(); + Исключение + НаборЗаписей.Записать(); + КонецПопытки; + КонецЦикла; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Если Показатели <> Неопределено Тогда + Показатели.ВремяПроверкиИОбновленияПараметровОграничения = Показатели.ВремяПроверкиИОбновленияПараметровОграничения + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоПроверки); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. +Функция ЗапланированоОбновлениеПараметровОграниченияДоступа(ДатаАктуальности) + + Идентификатор = СлужебныйИдентификатор("РегистрСведений.ПараметрыОграниченияДоступа"); + Если Идентификатор = Null Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Список", Идентификатор); + Запрос.УстановитьПараметр("ДатаАктуальности", ДатаАктуальности); + Запрос.Текст = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Список = &Список + | И ТекущаяТаблица.ДатаИзмененияЗаписиРегистра >= &ДатаАктуальности + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ИСТИНА + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Список = &Список + | И ТекущаяТаблица.ДатаИзмененияЗаписиРегистра >= &ДатаАктуальности"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. +Процедура УменьшитьНомераВерсийПараметровОграниченияДоступа() + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + НаборЗаписей = РегистрыСведений.ПараметрыОграниченияДоступа.СоздатьНаборЗаписей(); + НаборЗаписей.Прочитать(); + Выгрузка = НаборЗаписей.Выгрузить(); + Выгрузка.Сортировать("Версия"); + ТекущаяВерсия = 1; + Для Каждого Строка Из Выгрузка Цикл + Строка.Версия = ТекущаяВерсия; + ТекущаяВерсия = ТекущаяВерсия + 1; + КонецЦикла; + НаборЗаписей.Загрузить(Выгрузка); + НаборЗаписей.Записать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. +Функция ИспользованиеВидовДоступаИзменено(ДействующиеПараметры) + + Если ДействующиеПараметры.ВнешниеПользователиВключены + <> Константы.ИспользоватьВнешнихПользователей.Получить() + Или ДействующиеПараметры.ОграничениеДоступаВключено + <> Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() Тогда + Возврат Истина; + КонецЕсли; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ТекущиеИспользуемыеТипыЗначений = ИспользуемыеТипыЗначений(СвойстваВидовДоступа,,, Истина); + + ИспользуемыеТипыЗначений = ДействующиеПараметры.ИспользуемыеТипыЗначений.Получить(); + + Если ТипЗнч(ИспользуемыеТипыЗначений) <> Тип("Структура") + Или Не ИспользуемыеТипыЗначений.Свойство("ХешСумма") + Или ИспользуемыеТипыЗначений.ХешСумма <> ТекущиеИспользуемыеТипыЗначений.ХешСумма Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступа, +// ОтменитьОбновлениеДоступаНаУровнеЗаписей, ЗавершитьОбновлениеДоступа. +// +Процедура ЗавершитьПотокиОбновленияДоступа(ОтменитьОбновление = Ложь) + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + + Если ОтменитьОбновление Тогда + НаборЗаписей.Добавить().ИдентификаторПотока = ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей(); + Иначе + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ОбновлениеКлючейДоступаТекущиеЗадания"; + + Если Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + НаборЗаписей.Записать(); + +КонецПроцедуры + +// Для процедур ОбработатьВыполненныеЗадания, ЗавершитьПотокиОбновленияДоступа. +Функция ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей() + + Возврат Новый УникальныйИдентификатор("06cc4b5f-a2f9-4622-bef0-df4870ab5dd5"); + +КонецФункции + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступа, +// ОтменитьОбновлениеДоступаНаУровнеЗаписей, ЗавершитьОбновлениеДоступа. +// +Процедура ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(СекундОжидания = 5) + + Отбор = Новый Структура; + Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно); + Отбор.Вставить("ИмяМетода", ИмяМетодаПотокаОбновленияДоступа()); + + ФоновыеЗаданияПотоков = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); + Если ФоновыеЗаданияПотоков.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ФоновыеЗаданияПотоков = ФоновыеЗадания.ОжидатьЗавершенияВыполнения(ФоновыеЗаданияПотоков, СекундОжидания); + Для Каждого ФоновоеЗаданиеПотока Из ФоновыеЗаданияПотоков Цикл + Если ФоновоеЗаданиеПотока.Состояние = СостояниеФоновогоЗадания.Активно Тогда + ФоновоеЗаданиеПотока.Отменить(); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Обновляет ключи доступа к данным на основе записей в регистре сведений +// ОбновлениеКлючейДоступаКДанным и ключи доступа пользователей на основе записей +// регистра сведений ОбновлениеКлючейДоступаПользователей. +// +// Обновляется порция данных для каждой таблицы, начиная с самых свежих данных. +// Процедура должна вызываться повторно, пока обработка не будет завершена, +// при этом регламентное задание выключается. +// +// Процедура предназначена для работы в единственном экземпляре, то есть без параллельной +// работы (вызов из процедуры регламентного задания ОбновлениеДоступаНаУровнеЗаписей). +// Параллельность обеспечивает сама процедура путем запуска до двух фоновых заданий +// на каждый список, но не более значения константы КоличествоПотоковОбновленияДоступа. +// +Процедура ВыполнитьОбновлениеДоступа(ОбновитьВсе, ПараметрыВыполнения, ПоследнееОбновлениеДоступа) + + Контекст = НовыйКонтекстОбновленияДоступа(); + Контекст.Вставить("Показатели", ПоказателиОбновленияОсновногоСеанса()); + Контекст.Вставить("ОписаниеОсновногоСеанса", ПараметрыВыполнения.ОписаниеОсновногоСеанса); + Контекст.Вставить("ТекущееФоновоеЗадание", ПараметрыВыполнения.ОписаниеОсновногоСеанса.ФоновоеЗадание); + Контекст.Вставить("Задания", ТаблицаЗаданийОбновления()); + Контекст.Вставить("ЗаданияДляЗапуска", Новый Массив); + Контекст.Вставить("ЗанятыеПотоки", Новый Соответствие); + Контекст.Вставить("СвободныеПотоки", Новый Массив); + Контекст.Вставить("ГраницаОбновленияЗаданий", '00010101'); + Контекст.Вставить("ОбщиеПараметрыОбновления", ОписаниеОбщихПараметровОбновления()); + Контекст.Вставить("ОбновлениеВЭтомСеансе", Ложь); + Контекст.Вставить("КоличествоПотоков", 0); + Контекст.Вставить("ДатаПолногоЗавершения", ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения); + Контекст.Вставить("ТекстОшибкиЗавершения", ""); + Контекст.Вставить("ЕстьОтложенныеЗадания", Ложь); + Контекст.Вставить("ЕстьЗапущенноеЗадание", Истина); + Контекст.Вставить("ОбработкаЗавершена", Ложь); + Контекст.Вставить("ОбновлениеОтменено", Ложь); + Контекст.Вставить("ТребуетсяПерезапускСеанса",Ложь); + Контекст.Вставить("МаксимумПорцийИзИсходной", 0); + Контекст.Вставить("МаксимумМиллисекундОбработкиПорции", 0); + Контекст.Вставить("КоличествоДополнительныхПорций", 0); + Контекст.Вставить("ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных", Ложь); + Контекст.Вставить("МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных", 0); + Контекст.Вставить("ИдентификаторыОтключенныхОбъектовМетаданных", Новый Соответствие); + Контекст.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.НаборыГруппДоступа")); + ПараметрыВыполнения.ОписаниеОсновногоСеанса.Удалить("ФоновоеЗадание"); + + ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст, Истина); + ЗапланироватьОбработкуУстаревшихЭлементов(ПараметрыВыполнения.ТекстОшибкиПланирования, + ПоследнееОбновлениеДоступа.ПоследнееПланированиеОбработкиУстаревшихЭлементов); + + Запрос = Новый Запрос; + Запрос.Текст = ТекстЗапросаЗаданий(); + Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДата()); + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ЗавершитьПотокиОбновленияДоступа(); + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(1); + + Задания = Контекст.Задания; + ЗанятыеПотоки = Контекст.ЗанятыеПотоки; + + Если ПараметрыВыполнения.СекундНеБолее > 0 Тогда + ОкончаниеВыполнения = ТекущаяДатаСеанса() + ПараметрыВыполнения.СекундНеБолее; + Иначе + ОкончаниеВыполнения = ТекущаяДатаСеанса() + + МаксимальноеКоличествоМинутВыполненияФоновогоЗаданияОбновленияДоступа() * 60; + КонецЕсли; + + ЗаполнитьКоличествоПотоков(Контекст); + ДобавитьПоказателиОбновленияУправляющегоПотока(Контекст); + ПовторныйЗапуск = Ложь; + + Пока Истина Цикл + Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск + Или ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + Прервать; + КонецЕсли; + Контекст.ОбработкаЗавершена = Истина; + + ЗаполнитьКоличествоПотоков(Контекст); + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + + Если Контекст.ОбновлениеОтменено Или Контекст.ТребуетсяПерезапускСеанса Тогда + Контекст.ОбработкаЗавершена = Ложь; + Прервать; + КонецЕсли; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + ДобавитьЗаданияОбновленияДоступа(РезультатыЗапроса, Контекст); + + Если Контекст.ТребуетсяПерезапускСеанса Тогда + Контекст.ОбработкаЗавершена = Ложь; + Прервать; + ИначеЕсли Контекст.ОбработкаЗавершена Тогда + ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст); + Если Не Контекст.ОбработкаЗавершена Тогда + Продолжить; + КонецЕсли; + Прервать; + КонецЕсли; + Контекст.ДатаПолногоЗавершения = '00010101'; + + ОкончаниеТекущегоЗапуска = ТекущаяДатаСеанса() + 5; + Контекст.Вставить("ПервыйПроход", Истина); + + Пока Истина Цикл + + Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск + Или ТекущаяДатаСеанса() > ОкончаниеТекущегоЗапуска + Или ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) + Или Задания.Количество() = 0 + Или Контекст.ОбновлениеОтменено + Или Контекст.ТребуетсяПерезапускСеанса Тогда + Прервать; + КонецЕсли; + + ПрерватьПроход = Ложь; + МоментПрерыванияПрохода = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + ЗаполнитьОбщиеПараметрыОбновления(Контекст); + Контекст.ЕстьЗапущенноеЗадание = Ложь; + ЗаданияДляЗапуска = Контекст.ЗаданияДляЗапуска; + + Для Каждого Задание Из ЗаданияДляЗапуска Цикл + + Пока ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Цикл + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + + Если Контекст.ОбновлениеОтменено Или Контекст.ТребуетсяПерезапускСеанса Тогда + ПрерватьПроход = Истина; + Прервать; + КонецЕсли; + + Если ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Тогда + Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск + Или ТекущаяДатаСеанса() > ОкончаниеТекущегоЗапуска Тогда + ПрерватьПроход = Истина; + Прервать; + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + ПодождатьОсвобожденияПотока(Контекст, Истина); + Если Не Контекст.ПервыйПроход + И ТекущаяУниверсальнаяДатаВМиллисекундах() > МоментПрерыванияПрохода Тогда + ПрерватьПроход = Истина; + Прервать; + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если ПрерватьПроход Тогда + Прервать; + КонецЕсли; + Если ЗанятыеПотоки.Количество() < Контекст.КоличествоПотоков Тогда + // @skip-check query-in-loop - Порционная обработка данных + ЗапуститьОбновлениеДоступаСписка(Задание, Контекст); + ПовторныйЗапуск = Истина; + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) + Или Контекст.ОбновлениеОтменено + Или Контекст.ТребуетсяПерезапускСеанса Тогда + Прервать; + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Не Контекст.ЕстьЗапущенноеЗадание + И (ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков + Или Не Контекст.ЕстьОтложенныеЗадания) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ПодождатьОсвобожденияПотока(Контекст, Истина); + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + Контекст.ПервыйПроход = Ложь; + КонецЦикла; + + Если Не ОбновитьВсе + И ПоследнееОбновлениеДоступа.ДляУскорения + И ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(Ложь) + И Задания.Найти(Истина, "ЕстьТочечноеЗадание") = Неопределено Тогда + + Если ПоследнееОбновлениеДоступа().ДляУскорения Тогда + Прервать; + Иначе + ПоследнееОбновлениеДоступа.ДляУскорения = Ложь; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если Не Контекст.ОбработкаЗавершена + И Не ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) + И Не Контекст.ОбновлениеОтменено + И Не Контекст.ТребуетсяПерезапускСеанса Тогда + + ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст); + КонецЕсли; + + ЗавершитьОбновлениеДоступа(Контекст); + + ПараметрыВыполнения.ТекстОшибкиЗавершения = Контекст.ТекстОшибкиЗавершения; + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Контекст.ОбновлениеОтменено; + ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = Контекст.ДатаПолногоЗавершения; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ОписаниеОсновногоСеанса - см. ОписаниеОсновногоСеанса +// * ТекущееФоновоеЗадание - ФоновоеЗадание +// * Задания - см. ТаблицаЗаданийОбновления +// * ЗаданияДляЗапуска - Массив из СтрокаТаблицыЗначений: см. ТаблицаЗаданийОбновления +// * ЗанятыеПотоки - Соответствие из КлючИЗначение: +// ** Ключ - УникальныйИдентификатор +// ** Значение - см. НовыйПоток +// * СвободныеПотоки - Массив из см. НовыйПоток +// * ГраницаОбновленияЗаданий - Дата +// * ОбщиеПараметрыОбновления - см. ОписаниеОбщихПараметровОбновления +// * ОбновлениеВЭтомСеансе - Булево +// * КоличествоПотоков - Число +// * ДатаПолногоЗавершения - Дата +// * ТекстОшибкиЗавершения - Строка +// * ЕстьОтложенныеЗадания - Булево +// * ЕстьЗапущенноеЗадание - Булево +// * ОбработкаЗавершена - Булево +// * ОбновлениеОтменено - Булево +// * ТребуетсяПерезапускСеанса - Булево +// * МаксимумПорцийИзИсходной - Число +// * КоличествоДополнительныхПорций - Число +// * ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных - Булево +// * МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных - Число +// * ИдентификаторыОтключенныхОбъектовМетаданных - Соответствие +// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// +Функция НовыйКонтекстОбновленияДоступа() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗапланироватьОбработкуУстаревшихЭлементов(ТекстОшибкиПланирования, + ПоследнееПланированиеОбработкиУстаревшихЭлементов) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | ГДЕ ОбновлениеКлючейДоступаКДанным.РазмерЗадания = 2 + | И КлючУникальности <> &ПустойИдентификатор"; + + Если Не Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПоследнееПланированиеОбработкиУстаревшихЭлементов) Тогда + ПоследнееПланированиеОбработкиУстаревшихЭлементов = ТекущаяДатаСеанса(); + КонецЕсли; + Попытка + ГраницаОжидания = ТекущаяДатаСеанса() - КоличествоЧасовМеждуПланированиемОбработкиУстаревшихЭлементов() * 60 * 60; + Если ПоследнееПланированиеОбработкиУстаревшихЭлементов < ГраницаОжидания Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ПараметрыПланирования.Описание = "ОбновлениеДоступаНаУровнеЗаписей"; + ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); + ПоследнееПланированиеОбработкиУстаревшихЭлементов = ТекущаяДатаСеанса(); + КонецЕсли; + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибкиПланирования = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось запланировать обработку устаревших элементов ограничения доступа по причине: + |%1'"), + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ЗапуститьОбновлениеДоступаСписка. +Функция МаксимумМиллисекундПолученияПорций(Контекст) + + Если Не ЗначениеЗаполнено(Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных) Тогда + Результат = 3000; + + ИначеЕсли Не Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных Тогда + Результат = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000 - 1000; + Иначе + Результат = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000 / 2; + КонецЕсли; + + Если Результат < 1000 Тогда + Результат = 1000; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Для процедуры ЗаполнитьКоличествоПотоков и формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Возвращаемое значение: +// Булево +// +Функция ДоступнаБалансировкаНагрузкиНаДиск() Экспорт + + Возврат МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных() > 0 + И УправлениеДоступомСлужебныйПовтИсп.ДоступнаБалансировкаНагрузкиНаДиск(); + +КонецФункции + +// Для процедуры ЗаполнитьКоличествоПотоков и формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Возвращаемое значение: +// Булево +// +Функция БалансировкаНагрузкиНаДиск() Экспорт + + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + Возврат ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск; + +КонецФункции + +// Для формы ОбновлениеДоступаНаУровнеЗаписей. +Процедура УстановитьБалансировкуНагрузкиНаДиск(Использование) Экспорт + + БлокировкаДанных = Новый БлокировкаДанных; + БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); + + ЕстьВнешняяТранзакция = ТранзакцияАктивна(); + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + Если ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск <> Использование Тогда + ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск = Использование; + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +// Возвращаемое значение: +// ТаблицаЗначений: +// * ЕстьТочечноеЗадание - Булево +// * ЕстьНачальноеОбновлениеТочечногоЗадания - Дата +// * ДатаПоследнегоЗапускаТочечногоЗадания - Дата +// * ДатаДобавленияТочечногоЗадания - Дата +// * УровеньЗависимости - Число +// * ЗависимыеСписки - Массив +// - Строка +// * ЕстьНачальноеОбновление - Булево +// * ЕстьПерезапуск - Булево +// * ДатаПоследнегоЗапускаОбщегоЗадания - Дата +// * ЕстьДатаПоследнегоОбновленногоЭлемента - Булево +// * ДатаПоследнегоОбновленногоЭлемента - Дата +// * ДатаДобавленияОбщегоЗадания - Дата +// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ДляВнешнихПользователей - Булево +// * ЭтоОбновлениеПрав - Булево +// * Запускать - Булево +// * ЗанятыеПотоки - Соответствие из КлючИЗначение: +// ** Ключ - УникальныйИдентификатор +// ** Значение - см. НовыйПоток +// * НаборПорций - Массив из см. ПорцияИзНабора +// * КоличествоПорцийДляОбработки - Число +// * ИндексСледующейПорцииДляОбработки - Число +// * Пропустить - Булево +// * Удалить - Булево +// * ПорядокВидаКлючаДанных - Число +// * ЭтоОбработкаУстаревшихЭлементов - Булево +// * ОбновитьУровеньЗависимости - Булево +// +Функция ТаблицаЗаданийОбновления() + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + Задания = Новый ТаблицаЗначений; + Задания.Колонки.Добавить("ЕстьТочечноеЗадание", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЕстьНачальноеОбновлениеТочечногоЗадания",Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ДатаПоследнегоЗапускаТочечногоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ДатаДобавленияТочечногоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("УровеньЗависимости", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("ЗависимыеСписки", Новый ОписаниеТипов("Массив,Строка")); + Задания.Колонки.Добавить("ЕстьНачальноеОбновление", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЕстьПерезапуск", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ДатаПоследнегоЗапускаОбщегоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ЕстьДатаПоследнегоОбновленногоЭлемента", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ДатаПоследнегоОбновленногоЭлемента", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ДатаДобавленияОбщегоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); + Задания.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЭтоОбновлениеПрав", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("Запускать", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЗанятыеПотоки", Новый ОписаниеТипов("Соответствие")); + Задания.Колонки.Добавить("НаборПорций", Новый ОписаниеТипов("Массив")); + Задания.Колонки.Добавить("КоличествоПорцийДляОбработки", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("ИндексСледующейПорцииДляОбработки", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("Пропустить", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("Удалить", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ПорядокВидаКлючаДанных", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("ЭтоОбработкаУстаревшихЭлементов", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("РазрешенаОбработкаУстаревшихЭлементов", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ОбновитьУровеньЗависимости", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("БылаОшибка", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ТекстОшибки", Новый ОписаниеТипов("Строка")); + Задания.Колонки.Добавить("ДлительноеЗаданиеПолученияПорцийДо", Новый ОписаниеТипов("Дата")); + + Задания.Индексы.Добавить( + "ЕстьТочечноеЗадание, + |ЕстьНачальноеОбновлениеТочечногоЗадания, + |ДатаПоследнегоЗапускаТочечногоЗадания, + |ДатаДобавленияТочечногоЗадания, + |ЕстьНачальноеОбновление, + |ДатаПоследнегоЗапускаОбщегоЗадания, + |ЕстьДатаПоследнегоОбновленногоЭлемента, + |ДатаПоследнегоОбновленногоЭлемента, + |ДатаДобавленияОбщегоЗадания"); + + Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав, ЭтоОбработкаУстаревшихЭлементов"); + Задания.Индексы.Добавить("Удалить, ЭтоОбработкаУстаревшихЭлементов"); + Задания.Индексы.Добавить("УровеньЗависимости"); + + Возврат Задания; + +КонецФункции + +// Для процедуры ДобавитьЗаданияОбновленияДоступа. +Функция ТаблицаКлючейЗаданий() + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + Задания = Новый ТаблицаЗначений; + Задания.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); + Задания.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЭтоОбновлениеПрав", Новый ОписаниеТипов("Булево")); + + Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + + Возврат Задания; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +// +// Возвращаемое значение: +// Структура: +// * ИдентификаторПотока - УникальныйИдентификатор +// * ФоновоеЗадание - ФоновоеЗадание +// * Задание - СтрокаТаблицыЗначений из см. ТаблицаЗаданийОбновления +// * ОтменитьЗадание - Булево +// * МоментЗапускаЗадания - Число +// * ПорцияИзНабора - см. ПорцияИзНабора +// * ПолучитьПорции - Число +// * ДатаОсвобождения - Дата +// +Функция НовыйПоток() + + Поток = Новый Структура; + Поток.Вставить("ИдентификаторПотока"); + Поток.Вставить("ФоновоеЗадание"); + Поток.Вставить("Задание"); + Поток.Вставить("ОтменитьЗадание", Ложь); + Поток.Вставить("МоментЗапускаЗадания", 0); + Поток.Вставить("ПорцияИзНабора"); + Поток.Вставить("ПолучитьПорции", 0); + Поток.Вставить("ДатаОсвобождения", '00010101'); + + Возврат Поток; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +// +// Возвращаемое значение: +// Структура: +// * ЭтоОбновлениеПрав - Булево +// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ДляВнешнихПользователей - Булево +// * ЭтоОбработкаУстаревшихЭлементов - Булево +// * РазрешенаОбработкаУстаревшихЭлементов - Булево +// * ДатаНачала - Дата +// * ДатаОкончания - Дата +// * НачальноеОбновление - Булево +// * ОбработкаЗавершена - Булево +// * МаксимумМиллисекундОбработки - Число +// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// * Кэш - см. НовыйКэшКонтекста +// * МаксимумПорцийИзИсходной - Число +// +Функция ОписаниеОбщихПараметровОбновления(Контекст = Неопределено) + + ОбщиеПараметрыОбновления = Новый Структура; + ОбщиеПараметрыОбновления.Вставить("ЭтоОбновлениеПрав", Ложь); + ОбщиеПараметрыОбновления.Вставить("ИдентификаторСписка", Неопределено); + ОбщиеПараметрыОбновления.Вставить("ДляВнешнихПользователей", Ложь); + ОбщиеПараметрыОбновления.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); + ОбщиеПараметрыОбновления.Вставить("РазрешенаОбработкаУстаревшихЭлементов", Ложь); + ОбщиеПараметрыОбновления.Вставить("ДатаНачала", '00010101'); + ОбщиеПараметрыОбновления.Вставить("ДатаОкончания", '00010101'); + ОбщиеПараметрыОбновления.Вставить("НачальноеОбновление", Ложь); + ОбщиеПараметрыОбновления.Вставить("ОбработкаЗавершена", Истина); + ОбщиеПараметрыОбновления.Вставить("МаксимумМиллисекундОбработки", 1000); + + Если Контекст = Неопределено Тогда + ОбщиеПараметрыОбновления.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.НаборыГруппДоступа")); + Иначе + ОбщиеПараметрыОбновления.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", + Контекст.ИдентификаторСправочникаНаборыГруппДоступа); + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + ОбщиеПараметрыОбновления.Вставить("Кэш", Контекст.Кэш); + КонецЕсли; + ОбщиеПараметрыОбновления.Вставить("МаксимумПорцийИзИсходной", Контекст.МаксимумПорцийИзИсходной); + КонецЕсли; + + Возврат ОбщиеПараметрыОбновления; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Функция ТекстЗапросаЗаданий() + + Возврат + "ВЫБРАТЬ + | ЛОЖЬ КАК ЭтоОбновлениеПрав, + | Списки.Список КАК ИдентификаторСписка, + | Списки.ДляВнешнихПользователей КАК ДляВнешнихПользователей, + | МАКСИМУМ(Списки.ТочечноеЗадание) КАК ЕстьТочечноеЗадание, + | МАКСИМУМ(Списки.ТочечноеЗадание + | И Списки.ДатаПоследнегоОбновленногоЭлемента = &МаксимальнаяДата) КАК ЕстьНачальноеОбновлениеТочечногоЗадания, + | МАКСИМУМ(ВЫБОР + | КОГДА Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) КАК ДатаДобавленияТочечногоЗадания, + | МАКСИМУМ(Списки.РазмерЗадания = 2) КАК ЕстьОбработкаУстаревших, + | МАКСИМУМ(Списки.РазмерЗадания = 3) КАК ЕстьПолноеОбновление, + | МАКСИМУМ(Списки.РазмерЗадания = 3 + | И Списки.ДатаПоследнегоОбновленногоЭлемента = &МаксимальнаяДата) КАК ЕстьНачальноеОбновление, + | МАКСИМУМ(НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор) КАК ЕстьПерезапуск, + | МАКСИМУМ(ВЫБОР + | КОГДА НЕ Списки.ТочечноеЗадание + | ИЛИ Списки.КлючУникальности = &ПустойИдентификатор + | ТОГДА Списки.ДатаПоследнегоОбновленногоЭлемента + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) КАК ДатаПоследнегоОбновленногоЭлемента, + | МАКСИМУМ(ВЫБОР + | КОГДА НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) КАК ДатаДобавленияОбщегоЗадания + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК Списки + | + |СГРУППИРОВАТЬ ПО + | Списки.Список, + | Списки.ДляВнешнихПользователей + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ИСТИНА, + | Списки.Список, + | Списки.ДляВнешнихПользователей, + | МАКСИМУМ(Списки.ТочечноеЗадание), + | ЛОЖЬ, + | МАКСИМУМ(ВЫБОР + | КОГДА Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ), + | МАКСИМУМ(Списки.РазмерЗадания = 2), + | МАКСИМУМ(Списки.РазмерЗадания = 3), + | ЛОЖЬ, + | МАКСИМУМ(НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор), + | ДАТАВРЕМЯ(1, 1, 1), + | МАКСИМУМ(ВЫБОР + | КОГДА НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК Списки + | + |СГРУППИРОВАТЬ ПО + | Списки.Список, + | Списки.ДляВнешнихПользователей"; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗаполнитьКоличествоПотоков(Контекст) + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Возврат; + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + КоличествоПотоков = 1; + Контекст.МаксимумПорцийИзИсходной = 5; + Иначе + КоличествоПотоков = Константы.КоличествоПотоковОбновленияДоступа.Получить(); + Контекст.МаксимумПорцийИзИсходной = 5 + (КоличествоПотоков - 1) * 2; + КонецЕсли; + + Если КоличествоПотоков < 1 Тогда + КоличествоПотоков = 1; + КонецЕсли; + + Если Контекст.КоличествоПотоков = 0 Тогда + Контекст.ОбновлениеВЭтомСеансе = КоличествоПотоков = 1; + КонецЕсли; + + Контекст.КоличествоПотоков = КоличествоПотоков; + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Возврат; + КонецЕсли; + + Если ДоступнаБалансировкаНагрузкиНаДиск() И БалансировкаНагрузкиНаДиск() Тогда + Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных = + МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных(); + Иначе + Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных = 0; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ДобавитьЗаданияОбновленияДоступа(РезультатыЗапроса, Контекст) + + Если Контекст.Свойство("Кэш") Тогда + Кэш = Контекст.Кэш; // см. НовыйКэшКонтекста + Иначе + Кэш = НовыйКэшКонтекста(); + Контекст.Вставить("Кэш", Кэш); + Контекст.Вставить("ИдентификаторыПоПолнымИменам", Новый Соответствие); + Контекст.Вставить("ВерсияПараметровОграничения"); + Контекст.Вставить("ХешСуммаПараметровОграничения"); + КонецЕсли; + Если Не Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда + Кэш.Вставить("ОбъектыМетаданныхПоИдентификаторам", Новый Соответствие); + КонецЕсли; + + Попытка + ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст); + Исключение + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + Возврат; + КонецЕсли; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + Задания = Контекст.Задания; + ИдентификаторыСписков = Новый Массив; + + Если Контекст.ВерсияПараметровОграничения <> ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия + Или Контекст.ХешСуммаПараметровОграничения <> ПараметрыСеанса.ПараметрыОграниченияДоступа.ХешСумма Тогда + + Задания.ЗаполнитьЗначения(-1, "УровеньЗависимости"); + Задания.ЗаполнитьЗначения(Неопределено, "ЗависимыеСписки"); + Контекст.Вставить("ИдентификаторыПоПолнымИменам", Новый Соответствие); + Контекст.Вставить("ВедущиеСпискиПоЗависимым", ТаблицаКлючейЗаданий()); + Контекст.ВедущиеСпискиПоЗависимым.Колонки.Добавить("ВедущиеСписки"); + + ТекущиеИдентификаторыСписка = Задания.Скопировать(, "ИдентификаторСписка"); + ТекущиеИдентификаторыСписка.Свернуть("ИдентификаторСписка"); + ИдентификаторыСписков = ТекущиеИдентификаторыСписка.ВыгрузитьКолонку("ИдентификаторСписка"); + + Контекст.ВерсияПараметровОграничения = ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия; + Контекст.ХешСуммаПараметровОграничения = ПараметрыСеанса.ПараметрыОграниченияДоступа.ХешСумма; + КонецЕсли; + + Задания.ЗаполнитьЗначения(Истина, "Удалить"); + Отбор = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + + Выгрузка = РезультатыЗапроса[0].Выгрузить(); + + Для Каждого Строка Из Выгрузка Цикл + Если Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Получить(Строка.ИдентификаторСписка) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Строки = Задания.НайтиСтроки(Отбор); + Если Строки.Количество() = 0 Тогда + Задание = Задания.Добавить(); + Задание.УровеньЗависимости = -1; // Не заполнен. + Если Строка.ИдентификаторСписка <> Неопределено + И Кэш.ОбъектыМетаданныхПоИдентификаторам.Получить(Строка.ИдентификаторСписка) = Неопределено Тогда + ИдентификаторыСписков.Добавить(Строка.ИдентификаторСписка); + КонецЕсли; + Если Строка.ЕстьОбработкаУстаревших И Не Строка.ЕстьТочечноеЗадание И Не Строка.ЕстьПолноеОбновление Тогда + Задание.ПорядокВидаКлючаДанных = ПорядокВидаКлючаДанных("УстаревшиеЭлементы"); + КонецЕсли; + Иначе + Задание = Строки[0]; + КонецЕсли; + ЗаполнитьЗначенияСвойств(Задание, Строка); + Задание.Удалить = Ложь; + ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание, Ложь); + Если Строка.ЕстьПолноеОбновление Тогда + Задание.ЭтоОбработкаУстаревшихЭлементов = Ложь; + КонецЕсли; + Задание.ЕстьДатаПоследнегоОбновленногоЭлемента + = ЗначениеЗаполнено(Задание.ДатаПоследнегоОбновленногоЭлемента); + + Если Задание.ЕстьПерезапуск Тогда + ОтменитьЗадание(Задание); + КонецЕсли; + КонецЦикла; + + Если ИдентификаторыСписков.Количество() > 0 Тогда + ОбъектыМетаданныхПоИдентификаторам = + ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИдентификаторыСписков, Ложь); + Для Каждого КлючИЗначение Из ОбъектыМетаданныхПоИдентификаторам Цикл + Кэш.ОбъектыМетаданныхПоИдентификаторам.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + Если ТипЗнч(КлючИЗначение.Значение) = Тип("ОбъектМетаданных") Тогда + Контекст.ИдентификаторыПоПолнымИменам.Вставить(КлючИЗначение.Значение.ПолноеИмя(), КлючИЗначение.Ключ); + ИначеЕсли КлючИЗначение.Значение = Неопределено Тогда + Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Вставить(КлючИЗначение.Ключ, Истина); + Строки = Задания.НайтиСтроки(Новый Структура("ИдентификаторСписка", КлючИЗначение.Ключ)); + Для Каждого Строка Из Строки Цикл + Задания.Удалить(Строка); + КонецЦикла; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если Задания.Количество() > 0 Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + + ЗаполнитьУровниЗависимостиЗаданий(Контекст, ДействующиеПараметры.ВедущиеСписки); + +КонецПроцедуры + +// Для функции ДобавитьЗаданияОбновленияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ОбъектыМетаданныхПоИдентификаторам - Соответствие +// +Функция НовыйКэшКонтекста() + + Возврат Новый Структура; + +КонецФункции + +// Для процедур ДобавитьЗаданияОбновленияДоступа, ОбновитьСвойстваЗадания и +// функции ЗапуститьОбновлениеДоступаСписка. +// +Процедура ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание, ТребуетсяОбновитьУровеньЗависимостиПриИзменении = Истина) + + ЭтоОбработкаУстаревшихЭлементов = Не Задание.ЕстьТочечноеЗадание + И Задание.ПорядокВидаКлючаДанных >= ПорядокВидаКлючаДанных("УстаревшиеЭлементы") + И Задание.ПорядокВидаКлючаДанных < ПорядокВидаКлючаДанных("НетДанных"); + + Если Задание.ЭтоОбработкаУстаревшихЭлементов <> ЭтоОбработкаУстаревшихЭлементов Тогда + Задание.ЭтоОбработкаУстаревшихЭлементов = ЭтоОбработкаУстаревшихЭлементов; + Задание.ОбновитьУровеньЗависимости = ТребуетсяОбновитьУровеньЗависимостиПриИзменении; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОбщиеПараметрыОбновления. +Функция ЭтоОбновлениеСоставаНаборовГруппДоступа(Задание, Контекст) + + Возврат Задание.ИдентификаторСписка = Контекст.ИдентификаторСправочникаНаборыГруппДоступа + И Задание.ПорядокВидаКлючаДанных <= ПорядокВидаКлючаДанных("НаборыГруппРазрешенныеПользователям"); + +КонецФункции + +// Для процедуры ДобавитьЗаданияОбновленияДоступа. +Процедура ЗаполнитьУровниЗависимостиЗаданий(Контекст, СвойстваВедущихСписков) + + Задания = Контекст.Задания; + ОбъектыМетаданныхПоИдентификаторам = Контекст.Кэш.ОбъектыМетаданныхПоИдентификаторам; + ИдентификаторыПоПолнымИменам = Контекст.ИдентификаторыПоПолнымИменам; + + ЗаданияДляЗаполнения = Задания.НайтиСтроки(Новый Структура("УровеньЗависимости", -1)); + ВедущиеСпискиПоЗависимым = Контекст.ВедущиеСпискиПоЗависимым; + ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + + Для Каждого Задание Из ЗаданияДляЗаполнения Цикл + УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, ВедущиеСпискиПоЗависимым); + + ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(Задание.ИдентификаторСписка); + Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда + Продолжить; + КонецЕсли; + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + СвойстваВедущегоСписка = СвойстваВедущихСписков.Получить(ПолноеИмя); + Если СвойстваВедущегоСписка = Неопределено + Или СвойстваВедущегоСписка.ПоКлючамДоступа = Неопределено Тогда + Продолжить; + КонецЕсли; + Если Задание.ДляВнешнихПользователей Тогда + ЗависимыеСписки = СвойстваВедущегоСписка.ПоКлючамДоступа.ДляВнешнихПользователей; + Иначе + ЗависимыеСписки = СвойстваВедущегоСписка.ПоКлючамДоступа.ДляПользователей; + КонецЕсли; + Если ЗависимыеСписки = Неопределено Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(ОтборЗадания, Задание); + Для Каждого ЗависимыйСписок Из ЗависимыеСписки Цикл + ИдентификаторЗависимого = ИдентификаторыПоПолнымИменам.Получить(ЗависимыйСписок); + Если Задание.ЗависимыеСписки = Неопределено Тогда + Задание.ЗависимыеСписки = Новый Массив; + КонецЕсли; + ЗаданиеЗависимыеСписки = Задание.ЗависимыеСписки; + ЗаданиеЗависимыеСписки.Добавить(ИдентификаторЗависимого); + ОтборЗадания.ИдентификаторСписка = ИдентификаторЗависимого; + Найденные = ВедущиеСпискиПоЗависимым.НайтиСтроки(ОтборЗадания); + Если Найденные.Количество() = 0 Тогда + ВедущиеСписки = Новый Соответствие; + НоваяСтрока = ВедущиеСпискиПоЗависимым.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ОтборЗадания); + НоваяСтрока.ВедущиеСписки = ВедущиеСписки; + Иначе + ВедущиеСписки = Найденные[0].ВедущиеСписки; + КонецЕсли; + ВедущиеСписки.Вставить(Задание.ИдентификаторСписка, Истина); + ЗависимыеЗадания = Задания.НайтиСтроки(ОтборЗадания); + Если ЗависимыеЗадания.Количество() > 0 Тогда + УстановитьУровеньЗависимостиПоВедущим(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗаполнитьУровниЗависимостиЗаданий, ОбновитьУровеньЗависимости. +Процедура УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, ВедущиеСпискиПоЗависимым) + + Задание.УровеньЗависимости = 0; + Если Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Возврат; + КонецЕсли; + + ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав", + Задание.ИдентификаторСписка, Задание.ДляВнешнихПользователей, Задание.ЭтоОбновлениеПрав); + + Найденные = ВедущиеСпискиПоЗависимым.НайтиСтроки(ОтборЗадания); + Если Найденные.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ОтборЗадания.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); + + Для Каждого ОписаниеВедущегоСписка Из Найденные[0].ВедущиеСписки Цикл + ОтборЗадания.ИдентификаторСписка = ОписаниеВедущегоСписка.Ключ; + ВедущиеЗадания = Задания.НайтиСтроки(ОтборЗадания); + Если ВедущиеЗадания.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + Если Задание.УровеньЗависимости < ВедущиеЗадания[0].УровеньЗависимости + 1 Тогда + Задание.УровеньЗависимости = ВедущиеЗадания[0].УровеньЗависимости + 1; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОбщиеПараметрыОбновления. +Процедура ОбновитьУровеньЗависимости(СвойстваЗадания, Задания, ВедущиеСпискиПоЗависимым) + + Если Не ЗначениеЗаполнено(СвойстваЗадания.ЗависимыеСписки) Тогда + Возврат; + КонецЕсли; + ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + ЗаполнитьЗначенияСвойств(ОтборЗадания, СвойстваЗадания); + + Для Каждого ЗависимыйСписок Из СвойстваЗадания.ЗависимыеСписки Цикл + ОтборЗадания.ИдентификаторСписка = ЗависимыйСписок; + ЗависимыеЗадания = Задания.НайтиСтроки(ОтборЗадания); + Если ЗависимыеЗадания.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + УстановитьУровеньЗависимостиПоВедущим(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); + ОбновитьУровеньЗависимости(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗаполнитьОбщиеПараметрыОбновления(Контекст) + + Задания = Контекст.Задания; + Задания.Сортировать( + "ЕстьТочечноеЗадание Убыв, + |ЕстьНачальноеОбновлениеТочечногоЗадания Убыв, + |ДатаПоследнегоЗапускаТочечногоЗадания Возр, + |ДатаДобавленияТочечногоЗадания Убыв, + |ЕстьНачальноеОбновление Убыв, + |ДатаПоследнегоЗапускаОбщегоЗадания Возр, + |ЕстьДатаПоследнегоОбновленногоЭлемента Возр, + |ДатаПоследнегоОбновленногоЭлемента Убыв, + |ДатаДобавленияОбщегоЗадания Убыв"); + + ЗаданияДляУдаления = Задания.НайтиСтроки(Новый Структура("Удалить", Истина)); + Для Каждого Задание Из ЗаданияДляУдаления Цикл + Если Не Задание.Удалить Или Задание.ЗанятыеПотоки.Количество() > 0 Тогда + Продолжить; + КонецЕсли; + СвойстваЗадания = Новый Структура("ИдентификаторСписка, + |ДляВнешнихПользователей, ЭтоОбновлениеПрав, ЗависимыеСписки"); + ЗаполнитьЗначенияСвойств(СвойстваЗадания, Задание); + Задания.Удалить(Задание); + ОбновитьУровеньЗависимости(СвойстваЗадания, Задания, Контекст.ВедущиеСпискиПоЗависимым); + КонецЦикла; + ЗаданияДляОбновленияУровня = Задания.НайтиСтроки(Новый Структура("ОбновитьУровеньЗависимости", Истина)); + Для Каждого Задание Из ЗаданияДляОбновленияУровня Цикл + УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, Контекст.ВедущиеСпискиПоЗависимым); + ОбновитьУровеньЗависимости(Задание, Задания, Контекст.ВедущиеСпискиПоЗависимым); + Задание.ОбновитьУровеньЗависимости = Ложь; + КонецЦикла; + + ОтборУровней = Новый Структура("Удалить, ЭтоОбработкаУстаревшихЭлементов", Ложь, Ложь); + Уровни = Задания.Скопировать(ОтборУровней, "УровеньЗависимости"); + Уровни.Свернуть("УровеньЗависимости"); + Уровни.Сортировать("УровеньЗависимости"); + НаименьшийУровеньЗависимости = ?(Уровни.Количество() > 0, Уровни[0].УровеньЗависимости, 0); + ЭтоОбработкаУстаревшихЭлементов = Уровни.Количество() = 0; + ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания = '00010101'; + Если Уровни.Количество() > 1 Или Не ЭтоОбработкаУстаревшихЭлементов Тогда + Для Каждого Задание Из Задания Цикл + Если Задание.Удалить + Или Задание.ЕстьТочечноеЗадание Тогда + Продолжить; + КонецЕсли; + Если Задание.УровеньЗависимости > НаименьшийУровеньЗависимости + И ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания < Задание.ДатаПоследнегоЗапускаОбщегоЗадания Тогда + ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания = Задание.ДатаПоследнегоЗапускаОбщегоЗадания; + КонецЕсли; + КонецЦикла; + КонецЕсли; + ЗапускаемоеЗависимоеОбщееЗадание = + ?(ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания > ТекущаяДатаСеанса() - 10, Null, Неопределено); + + ОбщиеПараметрыОбновления = Контекст.ОбщиеПараметрыОбновления; + ОбщиеПараметрыОбновления.ЭтоОбработкаУстаревшихЭлементов = ЭтоОбработкаУстаревшихЭлементов; + ОбщиеПараметрыОбновления.НачальноеОбновление = Ложь; + ПоследняяДата = '00010101'; + ЗаданиеСправочникаНаборыГруппДоступа = Неопределено; + ГраницаОжиданияДляЗависимыхЗаданий = ТекущаяДатаСеанса() - 3; + МаксимальнаяДатаПриПродолжении = МаксимальнаяДатаПриПродолжении(); + ЕстьСписокБезПериода = Ложь; + + Для Каждого Задание Из Задания Цикл + Если Задание.Удалить Тогда + Продолжить; + КонецЕсли; + Если ЭтоОбновлениеСоставаНаборовГруппДоступа(Задание, Контекст) Тогда + ЗаданиеСправочникаНаборыГруппДоступа = Задание; + КонецЕсли; + Если Задание.БылаОшибка Тогда + Задание.Пропустить = Истина; + Продолжить; + КонецЕсли; + Задание.Пропустить = Ложь; + + Если Задание.ЕстьНачальноеОбновление Тогда + ОбщиеПараметрыОбновления.НачальноеОбновление = Истина; + + ИначеЕсли Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Задание.Пропустить = Не ЭтоОбработкаУстаревшихЭлементов + И ЭтоДлительноеЗаданиеПолученияПорций(Задание); + Продолжить; + + ИначеЕсли Не Задание.ЕстьПерезапуск Тогда + + Если Задание.УровеньЗависимости > НаименьшийУровеньЗависимости Тогда + Если Задание.ЕстьТочечноеЗадание Тогда + Если Задание.ДатаПоследнегоЗапускаТочечногоЗадания > ГраницаОжиданияДляЗависимыхЗаданий Тогда + Задание.Пропустить = Истина; + Продолжить; + КонецЕсли; + ИначеЕсли ЗапускаемоеЗависимоеОбщееЗадание <> Неопределено Тогда + Задание.Пропустить = Истина; + Продолжить; + Иначе + ЗапускаемоеЗависимоеОбщееЗадание = Задание; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если Задание.ЭтоОбновлениеПрав Тогда + Продолжить; + КонецЕсли; + Если Задание.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДатаПриПродолжении Тогда + ЕстьСписокБезПериода = Истина; + ИначеЕсли Задание.ДатаПоследнегоОбновленногоЭлемента > ПоследняяДата Тогда + ПоследняяДата = Задание.ДатаПоследнегоОбновленногоЭлемента; + КонецЕсли; + КонецЦикла; + + Если ОбщиеПараметрыОбновления.НачальноеОбновление Тогда + // Начало обновления. + ОбщиеПараметрыОбновления.ДатаНачала = НачалоДня(ТекущаяДатаСеанса()) - 7 * (60 * 60 * 24); // 7 Дней. + Иначе + // Продолжение обновления. + МаксимальныйПериод = МаксимальныйПериодПолученияПорцийЗапросом(); + + Если МаксимальныйПериод = "Неделя" Тогда + ДатаНачала = НачалоНедели(ПоследняяДата); + + ИначеЕсли МаксимальныйПериод = "Месяц" Тогда + ДатаНачала = НачалоМесяца(ПоследняяДата); + Иначе + ЭтотГод = Год(ТекущаяДатаСеанса()) - Год(ПоследняяДата) = 0; + СмещениеМесяца = Месяц(ТекущаяДатаСеанса()) - Месяц(ПоследняяДата); + + Если ЭтотГод И СмещениеМесяца = 0 Тогда + ДатаНачала = НачалоМесяца(ПоследняяДата); + + ИначеЕсли ЭтотГод И СмещениеМесяца < 3 Или МаксимальныйПериод = "Квартал" Тогда + ДатаНачала = НачалоКвартала(ПоследняяДата); + Иначе + ДатаНачала = НачалоГода(ПоследняяДата); + КонецЕсли; + КонецЕсли; + + ОбщиеПараметрыОбновления.ДатаНачала = ДатаНачала; + КонецЕсли; + ОбщиеПараметрыОбновления.ДатаОкончания = ПоследняяДата; + + ЗаданияДляЗапуска = Новый Массив; + Контекст.ЗаданияДляЗапуска = ЗаданияДляЗапуска; + Контекст.ЕстьОтложенныеЗадания = Ложь; + ЗаданийДляЗапускаСУчетомПорций = 0; + СпискиСОбработкойНеТолькоУстаревшихЭлементов = Новый Соответствие; + + Для Каждого Задание Из Задания Цикл + Задание.Запускать = Ложь; + Задание.РазрешенаОбработкаУстаревшихЭлементов = Ложь; + + Если Задание.Удалить Или Задание.Пропустить Тогда + Продолжить; + + ИначеЕсли Задание.ЕстьПерезапуск + Или Задание.ЕстьНачальноеОбновление + Или Задание.ЕстьТочечноеЗадание Тогда + + Задание.Запускать = Истина; + + ИначеЕсли Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Задание.Запускать = ЭтоОбработкаУстаревшихЭлементов; + Задание.РазрешенаОбработкаУстаревшихЭлементов = Истина; + + ИначеЕсли Задание = ЗаданиеСправочникаНаборыГруппДоступа + Или Задание.ЭтоОбновлениеПрав + Или Задание.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДатаПриПродолжении Тогда // Список без периода. + + Задание.Запускать = Истина; + Иначе + Запускать = Не ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + Задание.ДатаПоследнегоОбновленногоЭлемента); + Задание.Пропустить = Не Запускать; // Нет смысла запускать, так как в исполняющем потоке будет возврат. + Задание.Запускать = Запускать И Не ЕстьСписокБезПериода; + КонецЕсли; + + Если Задание.Запускать Тогда + ЗаданияДляЗапуска.Добавить(Задание); + ЗаданийДляЗапускаСУчетомПорций = ЗаданийДляЗапускаСУчетомПорций + ?(Не Задание.ЕстьПерезапуск + И ЗначениеЗаполнено(Задание.НаборПорций), Задание.НаборПорций.Количество(), 1); + ИначеЕсли Не Задание.Пропустить Тогда + Контекст.ЕстьОтложенныеЗадания = Истина; + КонецЕсли; + Если Не Задание.РазрешенаОбработкаУстаревшихЭлементов Тогда + СпискиСОбработкойНеТолькоУстаревшихЭлементов.Вставить(Задание.ИдентификаторСписка, Истина); + КонецЕсли; + КонецЦикла; + + Если ЗаданийДляЗапускаСУчетомПорций >= Контекст.КоличествоПотоков + Или Не ЗагружатьСвободныеПотокиСледующимиЗаданиямиПриДлительныхЗапросах() Тогда + Контекст.ЕстьОтложенныеЗадания = Ложь; + КонецЕсли; + + Если Не Контекст.ЕстьЗапущенноеЗадание + И Контекст.ЕстьОтложенныеЗадания + И Контекст.ЗанятыеПотоки.Количество() < Контекст.КоличествоПотоков Тогда + + Контекст.ЕстьОтложенныеЗадания = Ложь; + КоличествоСвободныхПотоков = Контекст.КоличествоПотоков - Контекст.ЗанятыеПотоки.Количество(); + КоличествоДополнительныхЗаданий = 0; + + Для ДобавитьОбработкуУстаревшихЭлементов = 0 По 1 Цикл + Для Каждого Задание Из Задания Цикл + Если Задание.Удалить + Или Задание.Запускать + Или Задание.Пропустить + Или Задание.ЭтоОбработкаУстаревшихЭлементов + И (СпискиСОбработкойНеТолькоУстаревшихЭлементов.Получить(Задание.ИдентификаторСписка) <> Неопределено + Или ДобавитьОбработкуУстаревшихЭлементов = 0 + И Не ЭтоОбработкаУстаревшихЭлементов) Тогда + Продолжить; + КонецЕсли; + Если КоличествоДополнительныхЗаданий >= КоличествоСвободныхПотоков Тогда + Контекст.ЕстьОтложенныеЗадания = Истина; + Прервать; + КонецЕсли; + Задание.Запускать = Истина; + ЗаданияДляЗапуска.Добавить(Задание); + КоличествоДополнительныхЗаданий = КоличествоДополнительныхЗаданий + 1; + КонецЦикла; + Если КоличествоДополнительныхЗаданий >= КоличествоСвободныхПотоков Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + КоличествоОсновныхЗаданий = ЗаданияДляЗапуска.Количество(); + Если КоличествоОсновныхЗаданий > 0 Тогда + Контекст.КоличествоДополнительныхПорций = Цел(Контекст.КоличествоПотоков / КоличествоОсновныхЗаданий); + Иначе + Контекст.КоличествоДополнительныхПорций = 0; + КонецЕсли; + + КоличествоЗаданий = Задания.Количество(); + Если КоличествоЗаданий = 0 Тогда + ДостаточностьПотоков = 0; + ИначеЕсли Контекст.КоличествоПотоков > КоличествоЗаданий Тогда + ДостаточностьПотоков = 1; + Иначе + ДостаточностьПотоков = Контекст.КоличествоПотоков / КоличествоЗаданий; + КонецЕсли; + НагруженностьОтПотоков = Контекст.КоличествоПотоков * 0.025; + Если НагруженностьОтПотоков > 1 Тогда + НагруженностьОтПотоков = 1; + КонецЕсли; + Контекст.МаксимумМиллисекундОбработкиПорции = + Цел(МинимальноеКоличествоСекундОбработкиПорцииВОтдельномПотоке() * 1000 + * (1 + НагруженностьОтПотоков) * (1 + ДостаточностьПотоков)); + + Если КоличествоОсновныхЗаданий = 0 + И КоличествоЗаданий > 0 + И Не ЗначениеЗаполнено(Контекст.ЗанятыеПотоки) Тогда + + ОбработатьЗаданияСОшибками(Контекст); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ДобавитьЗаданияОбновленияДоступа, ЗапуститьОбновлениеДоступаСписка, +// ВыполнитьОбновлениеДоступаСписка. +// +Функция ПериодОбновленияДоПериодаДанных(ДатаНачала, ДатаПоследнегоОбновленногоЭлемента) + + // ДатаНачала - например, 01.01.2012, а дата окончания 31.12.2012, + // при этом ДатаПоследнегоОбновленногоЭлемента, например, 03.01.2013. + // В таком случае данные для обновления старее, чем период обновления. + Возврат ЗначениеЗаполнено(ДатаПоследнегоОбновленногоЭлемента) + И ДатаНачала > ДатаПоследнегоОбновленногоЭлемента; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ОбработатьЗаданияСОшибками(Контекст) + + Отбор = Новый Структура("БылаОшибка", Истина); + ЗаданияСОшибками = Контекст.Задания.НайтиСтроки(Отбор); + Если Не ЗначениеЗаполнено(ЗаданияСОшибками) Тогда + Возврат; + КонецЕсли; + Контекст.ОбработкаЗавершена = Ложь; + + ТекстыОшибок = Новый Массив; + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + ТекстыОшибок.Добавить(Контекст.ТекстОшибкиЗавершения); + КонецЕсли; + + Для Каждого Задание Из ЗаданияСОшибками Цикл + Контекст.ОбработкаЗавершена = Ложь; + ТекстыОшибок.Добавить(Задание.ТекстОшибки); + КонецЦикла; + Контекст.ТекстОшибкиЗавершения = СтрСоединить(ТекстыОшибок, Символы.ПС + Символы.ПС); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст) + + Если Не Контекст.ОбработкаЗавершена + И ПараметрыСеанса.ПараметрыОграниченияДоступа.ДатаСоздания > ТекущаяДатаСеанса() - 5 * 60 Тогда + + Возврат; + КонецЕсли; + + Попытка + ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст); + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + Исключение + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + Возврат; + КонецЕсли; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст; + + Если ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст.ДляПользователей) + И ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст.ДляВнешнихПользователей) Тогда + + Возврат; + КонецЕсли; + + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); + ОбщийКонтекст.Вставить("СпискиСУстаревшимиВариантамиДоступа", Новый Массив); + + Попытка + ДействующиеПараметрыОграниченияДоступа(Неопределено, ОбщийКонтекст, Истина); + Исключение + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + Возврат; + КонецЕсли; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + + Если ЗначениеЗаполнено(ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа) Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗавершитьОбновлениеДоступа(Контекст) + + Если Не Контекст.ОбновлениеОтменено И Не Контекст.ТребуетсяПерезапускСеанса Тогда + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + ГраницаОжидания = ТекущаяДатаСеанса() + 3; + Иначе + ГраницаОжидания = ТекущаяДатаСеанса() + 15; + КонецЕсли; + Пока Контекст.ЗанятыеПотоки.Количество() > 0 Цикл + // @skip-check query-in-loop - Порционная обработка данных + ПодождатьОсвобожденияПотока(Контекст); + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + Если ТекущаяДатаСеанса() > ГраницаОжидания Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ЗавершитьПотокиОбновленияДоступа(); + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(); + + Попытка + Если Контекст.ОбработкаЗавершена Тогда + Контекст.Вставить("ОшибкаОжиданияБлокировкиДанных", Ложь); + Попытка + ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий(Контекст); + Исключение + Если Не Контекст.ОшибкаОжиданияБлокировкиДанных Тогда + ВызватьИсключение; + КонецЕсли; + КонецПопытки; + Если Не Константы.ПервоеОбновлениеДоступаЗавершилось.Получить() Тогда + Константы.ПервоеОбновлениеДоступаЗавершилось.Установить(Истина); + КонецЕсли; + КонецЕсли; + Исключение + ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст); + ВызватьИсключение; + КонецПопытки; + + ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст); + +КонецПроцедуры + +// Для процедуры ОбновитьСоставИспользуемыхВерсийПараметровШаблонов. +Функция ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст) + + ИспользуетсяНесколькоВариантов = Ложь; + + Для Каждого КлючИЗначение Из ДополнительныйКонтекст.ОсновныеВариантыДоступа Цикл + Если КлючИЗначение.Значение.Количество() > 1 Тогда + ИспользуетсяНесколькоВариантов = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Не ИспользуетсяНесколькоВариантов; + +КонецФункции + +// Для процедуры ЗавершитьОбновлениеДоступа. +Процедура ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий(Контекст) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("НедоступныеСпискиДляОбновленияКлючейДоступаКДанным", Новый Массив); + Запрос.УстановитьПараметр("НедоступныеСпискиДляОбновленияКлючейДоступаПользователей", Новый Массив); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаКДанным.Список КАК Список + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + |ГДЕ + | НЕ ОбновлениеКлючейДоступаКДанным.Список В (&НедоступныеСпискиДляОбновленияКлючейДоступаКДанным) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаПользователей.Список КАК Список + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей + |ГДЕ + | НЕ ОбновлениеКлючейДоступаПользователей.Список В (&НедоступныеСпискиДляОбновленияКлючейДоступаПользователей)"; + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Если Не РезультатыЗапроса[0].Пустой() Тогда + УстановитьНедоступныеСписки(РезультатыЗапроса[0], + Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным); + КонецЕсли; + + Если Не РезультатыЗапроса[1].Пустой() Тогда + УстановитьНедоступныеСписки(РезультатыЗапроса[1], + Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным); + КонецЕсли; + + Если Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным.Количество() > 0 + Или Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаПользователей.Количество() > 0 Тогда + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + КонецЕсли; + + Если РезультатыЗапроса[0].Пустой() + И РезультатыЗапроса[1].Пустой() Тогда + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаПользователей"); + НачатьТранзакцию(); + Попытка + Контекст.ОшибкаОжиданияБлокировкиДанных = Истина; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + РегламентныеЗаданияСервер.ЗаблокироватьРегламентноеЗадание(Новый УникальныйИдентификатор); + КонецЕсли; + Блокировка.Заблокировать(); + Контекст.ОшибкаОжиданияБлокировкиДанных = Ложь; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Если РезультатыЗапроса[0].Пустой() + И РезультатыЗапроса[1].Пустой() Тогда + + Если ЗначениеЗаполнено(Контекст.ДатаПолногоЗавершения) Тогда + ГраницаОтключения = ТекущаяДатаСеанса() + - КоличествоСекундПередОтключениемРегламентногоЗаданияПослеПолногоЗавершенияОбновления(); + Если Контекст.ДатаПолногоЗавершения < ГраницаОтключения Тогда + УстановитьОбновлениеДоступа(Ложь); + КонецЕсли; + Иначе + Контекст.ДатаПолногоЗавершения = ТекущаяДатаСеанса(); + КонецЕсли; + Иначе + Контекст.ОбработкаЗавершена = Ложь; + Контекст.ДатаПолногоЗавершения = '00010101'; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + Контекст.ОбработкаЗавершена = Ложь; + ВызватьИсключение; + КонецПопытки; + Иначе + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий. +// +// Параметры: +// РезультатЗапроса - РезультатЗапроса +// НедоступныеСписки - Массив +// +Процедура УстановитьНедоступныеСписки(РезультатЗапроса, НедоступныеСписки) + + ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( + РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Список"), Ложь); + + Для Каждого КлючИЗначение Из ОбъектыМетаданныхПоИдентификаторам Цикл + Если КлючИЗначение.Значение = Неопределено Тогда + НедоступныеСписки.Добавить(КлючИЗначение.Ключ); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Функция ЗапуститьОбновлениеДоступаСписка(Задание, Контекст) + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + Показатели.НачалоВыдачиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + ОбработатьВыполненныеЗадания(Контекст, Задание.ЗанятыеПотоки); + + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + Возврат Ложь; + КонецЕсли; + + Если Задание.ЗанятыеПотоки.Количество() > 0 И Контекст.ПервыйПроход Тогда + Возврат Истина; // Уже запущено. + КонецЕсли; + + Если ОбщееЗаданиеВыполняется(Задание) + И Не ЗапускатьОбновлениеПолученныхПорцийПриПолученииНовыхПорций() Тогда + Возврат Истина; + КонецЕсли; + + ОбщиеПараметрыОбновления = ОписаниеОбщихПараметровОбновления(Контекст); + ЗаполнитьЗначенияСвойств(ОбщиеПараметрыОбновления, Контекст.ОбщиеПараметрыОбновления); + ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав = Задание.ЭтоОбновлениеПрав; + ОбщиеПараметрыОбновления.ИдентификаторСписка = Задание.ИдентификаторСписка; + ОбщиеПараметрыОбновления.ДляВнешнихПользователей = Задание.ДляВнешнихПользователей; + ОбщиеПараметрыОбновления.РазрешенаОбработкаУстаревшихЭлементов = Задание.РазрешенаОбработкаУстаревшихЭлементов; + + НаборПорций = Задание.НаборПорций; + ПоследнийИндекс = НаборПорций.Количество() - 1; + + ИндексСледующейПорцииДляОбработки = Задание.ИндексСледующейПорцииДляОбработки; + ПорцияДляОбработки = Неопределено; + Для Индекс = ИндексСледующейПорцииДляОбработки По ПоследнийИндекс Цикл + ПорцияЭлементов = НаборПорций.Получить(Индекс); + Если Не ПорцияЭлементов.Обработана И Не ПорцияЭлементов.Обрабатывается Тогда + ПорцияДляОбработки = ПорцияЭлементов; + Задание.ИндексСледующейПорцииДляОбработки = Индекс; + ИндексСледующейПорцииДляОбработки = Индекс + 1; + Прервать; + КонецЕсли; + КонецЦикла; + + Если ПорцияДляОбработки = Неопределено Тогда + Задание.ИндексСледующейПорцииДляОбработки = ПоследнийИндекс + 1; + ПредыдущаяПорция = Неопределено; + + ИначеЕсли Индекс > 0 Тогда + ПредыдущаяПорция = НаборПорций.Получить(Индекс - 1); + Иначе + ПредыдущаяПорция = Неопределено; + КонецЕсли; + + Если Не Задание.ЕстьТочечноеЗадание И ПорцияДляОбработки <> Неопределено Тогда + Если ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + ?(ПредыдущаяПорция = Неопределено, Задание.ДатаПоследнегоОбновленногоЭлемента, + ПредыдущаяПорция.ДатаПоследнегоЭлементаПорции)) Тогда + Возврат Истина; + КонецЕсли; + ОбщиеПараметрыОбновления.Вставить("ПорцияИзНабора", ПорцияДляОбработки); + ПорцияДляОбработки.Обрабатывается = Истина; + Задание.ИндексСледующейПорцииДляОбработки = ИндексСледующейПорцииДляОбработки; + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки = Контекст.МаксимумМиллисекундОбработкиПорции; + Иначе + ПоследняяПорция = ?(ПоследнийИндекс > -1, НаборПорций[ПоследнийИндекс], Неопределено); + + Если ПоследняяПорция <> Неопределено + И (ПоследняяПорция.ПоследнийЭлементПорции.ВидКлючаДанных + <> ПоследняяПорция.НовыйПоследнийЭлементПорции.ВидКлючаДанных + Или ПоследняяПорция.НовыйПоследнийЭлементПорции.КлючДанных = Null + Или Не ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав + И ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + ПоследняяПорция.ДатаПоследнегоЭлементаПорции)) Тогда + + ПолучитьПорции = 0; + Иначе + КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки; + ПолучитьПорции = (Контекст.КоличествоДополнительныхПорций + 2) * 2; + Если Задание.ЕстьТочечноеЗадание Тогда + ПолучитьПорции = ПолучитьПорции - КоличествоПорцийДляОбработки; + Если ПолучитьПорции - КоличествоПорцийДляОбработки < Цел(ПолучитьПорции / 3) Тогда + ПолучитьПорции = Цел(ПолучитьПорции / 3); + Иначе + ПолучитьПорции = ПолучитьПорции - КоличествоПорцийДляОбработки; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если Не Задание.ЕстьТочечноеЗадание И ПолучитьПорции = 0 Тогда + Возврат Истина; + КонецЕсли; + + ОбщиеПараметрыОбновления.Вставить("ПолучитьПорции", ПолучитьПорции); + Если ПоследняяПорция <> Неопределено Тогда + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийЭлементПорции", + ПоследняяПорция.НовыйПоследнийЭлементПорции); + КонецЕсли; + Если ПолучитьПорции > 0 Тогда + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки = МаксимумМиллисекундПолученияПорций(Контекст); + КонецЕсли; + КонецЕсли; + + Если Не ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") И ОбщееЗаданиеВыполняется(Задание) Тогда + Возврат Истина; + КонецЕсли; + + Если Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных + И Не Задание.ЭтоОбновлениеПрав + И ОбщиеПараметрыОбновления.Свойство("ПолучитьПорции") + И ОбщиеПараметрыОбновления.ПолучитьПорции > 0 Тогда + + Если Задание.ЕстьТочечноеЗадание Тогда + ОбщиеПараметрыОбновления.ПолучитьПорции = 0; + ИначеЕсли ЭтоДлительноеЗаданиеПолученияПорций(Задание) Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Если Задание.ЕстьТочечноеЗадание Тогда + Задание.ЕстьТочечноеЗадание = Ложь; + ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание); + Задание.ДатаПоследнегоЗапускаТочечногоЗадания = ТекущаяДатаСеанса(); + Иначе + Задание.ДатаПоследнегоЗапускаОбщегоЗадания = ТекущаяДатаСеанса(); + КонецЕсли; + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст); + ОбработатьРезультатЗадания(Контекст, ОбщиеПараметрыОбновления, Задание); + Иначе + Для Каждого СвободныйПоток Из Контекст.СвободныеПотоки Цикл + Прервать; + КонецЦикла; + Если СвободныйПоток = Неопределено Тогда + Если Контекст.ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Тогда + Возврат Истина; + КонецЕсли; + СвободныйПоток = НовыйПоток(); + Параметры = Новый Массив; + Параметры.Добавить(Контекст.ОписаниеОсновногоСеанса); + СвободныйПоток.ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяМетодаПотокаОбновленияДоступа(), Параметры,, + НСтр("ru = 'Управление доступом: Поток обновления доступа на уровне записей'", + ОбщегоНазначения.КодОсновногоЯзыка())); + СвободныйПоток.ИдентификаторПотока = СвободныйПоток.ФоновоеЗадание.УникальныйИдентификатор; + Контекст.СвободныеПотоки.Добавить(СвободныйПоток); + КонецЕсли; + + ИдентификаторПотока = СвободныйПоток.ИдентификаторПотока; + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока); + ЗаписьНабора = НаборЗаписей.Добавить(); + ЗаписьНабора.ИдентификаторПотока = ИдентификаторПотока; + ЗаписьНабора.ЭтоЗапуск = Истина; + ЗаписьНабора.Параметры = Новый ХранилищеЗначения(ОбщиеПараметрыОбновления); + ЗаписьНабора.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + + НаборЗаписей.Записать(); + + СвободныйПоток.Задание = Задание; + СвободныйПоток.МоментЗапускаЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + СвободныйПоток.ПорцияИзНабора = ?(ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора"), + ОбщиеПараметрыОбновления.ПорцияИзНабора, Неопределено); + СвободныйПоток.ПолучитьПорции = ?(ОбщиеПараметрыОбновления.Свойство("ПолучитьПорции"), + ОбщиеПараметрыОбновления.ПолучитьПорции, 0); + Задание.ЗанятыеПотоки.Вставить(ИдентификаторПотока, СвободныйПоток); + Контекст.ЗанятыеПотоки.Вставить(ИдентификаторПотока, СвободныйПоток); + Контекст.СвободныеПотоки.Удалить(0); + Если Показатели <> Неопределено Тогда + СнятьПоказателиВыдачиЗаданий(Показатели); + КонецЕсли; + Контекст.ЕстьЗапущенноеЗадание = Истина; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ОбработатьРезультатЗадания. +Функция ОбщееЗаданиеВыполняется(Задание) + + Для Каждого ОписаниеЗанятогоПотока Из Задание.ЗанятыеПотоки Цикл + Если ОписаниеЗанятогоПотока.Значение.ПорцияИзНабора = Неопределено Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ОтменитьФоновыеЗаданияПотоковОбновленияДоступа. +Функция ИмяМетодаПотокаОбновленияДоступа() + + Возврат "УправлениеДоступомСлужебный.ВыполнитьОбновлениеДоступаСпискаВФоне"; + +КонецФункции + +// Для процедур УстановитьОбновлениеДоступа, ЗапуститьОбновлениеДоступаНаУровнеЗаписей, +// ОтменитьОбновлениеДоступаНаУровнеЗаписей и функции ИсполнительОбновленияДоступа. +// +Функция ИмяМетодаЗаданияОбновленияДоступа() + + Возврат Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.ИмяМетода; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа, ЗавершитьОбновлениеДоступа. +Процедура ПодождатьОсвобожденияПотока(Контекст, ЖдатьЗавершенияЗадания = Ложь) + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Возврат; + КонецЕсли; + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + НачалоОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Выполнять = Истина; + + Если ЖдатьЗавершенияЗадания Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторыПотоков", ИдентификаторыПотоков(Контекст.ЗанятыеПотоки)); + Запрос.УстановитьПараметр("КоличествоПотоков", Контекст.КоличествоПотоков); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | ТекущиеЗадания.ИдентификаторПотока В(&ИдентификаторыПотоков) + | + |СГРУППИРОВАТЬ ПО + | ТекущиеЗадания.ИдентификаторПотока + | + |ИМЕЮЩИЕ + | (МИНИМУМ(ТекущиеЗадания.ЭтоЗапуск) = ЛОЖЬ + | ИЛИ КОЛИЧЕСТВО(ТекущиеЗадания.ЭтоЗапуск) < &КоличествоПотоков)"; + Если Не Запрос.Выполнить().Пустой() Тогда + Выполнять = Ложь; + КонецЕсли; + ГраницаОжидания = ТекущаяДатаСеанса() + 5; + КонецЕсли; + + Пока Выполнять Цикл + Если Контекст.ТекущееФоновоеЗадание <> Неопределено Тогда + ФоновоеЗадание = Контекст.ТекущееФоновоеЗадание; + Иначе + ФоновоеЗадание = Неопределено; + Для Каждого ОписаниеПотока Из Контекст.ЗанятыеПотоки Цикл + Поток = ОписаниеПотока.Значение; + ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); + Если Поток.ФоновоеЗадание <> Неопределено + И Поток.ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + + ФоновоеЗадание = Поток.ФоновоеЗадание; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ФоновоеЗадание = Неопределено Тогда + Прервать; + КонецЕсли; + ФоновоеЗадание.ОжидатьЗавершенияВыполнения(0.025); + Если Не ЖдатьЗавершенияЗадания + Или ТекущаяДатаСеанса() > ГраницаОжидания + Или Контекст.ЗанятыеПотоки.Количество() = 0 Тогда + Прервать; + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + Если Не Запрос.Выполнить().Пустой() Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + Если Показатели <> Неопределено Тогда + Показатели.ВремяОжиданийСвободногоПотока = Показатели.ВремяОжиданийСвободногоПотока + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОжидания); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПодождатьОсвобожденияПотока, ОбработатьВыполненныеЗадания. +Функция ИдентификаторыПотоков(ЗанятыеПотоки) + + ИдентификаторыПотоков = Новый Массив; + + Для Каждого ОписаниеПотока Из ЗанятыеПотоки Цикл + ИдентификаторыПотоков.Добавить(ОписаниеПотока.Ключ); + КонецЦикла; + + Возврат ИдентификаторыПотоков; + +КонецФункции + +// Для процедур ПодождатьОсвобожденияПотока, УдалитьОстановленныеПотоки. +Процедура ОбновитьСвойстваФоновогоЗадания(Поток, Контекст) + + ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Поток.ИдентификаторПотока); + + Если ФоновоеЗадание = Неопределено Тогда + Если РегистрироватьПоказателиОбновленияДоступа() Тогда + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( + НСтр("ru = 'Не удалось найти запущенное фоновое задание.'"), Поток.Задание, Истина), Контекст); + КонецЕсли; + Контекст.ОбработкаЗавершена = Ложь; + Возврат; + КонецЕсли; + Поток.ФоновоеЗадание = ФоновоеЗадание; + +КонецПроцедуры + +// Для процедуры ОбработатьВыполненныеЗадания. +Процедура ОтменитьФоновоеЗаданиеПотока(Поток, Контекст) + + ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); + ФоновоеЗадание = Поток.ФоновоеЗадание; + + Если ФоновоеЗадание = Неопределено + Или ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Активно Тогда + + Возврат; + КонецЕсли; + + Попытка + ФоновоеЗадание.Отменить(); + Исключение + ПредставлениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось отменить фоновое задание потока по причине: + |%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( + ПредставлениеОшибки, Поток.Задание, Истина), Контекст); + КонецПопытки; + + Контекст.ОбработкаЗавершена = Ложь; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа, ОбработатьРезультатЗадания. +Процедура ОбработатьВыполненныеЗадания(Контекст, ЗанятыеПотоки = Неопределено) + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Если ОбновлениеДоступаОтменено() Тогда + Контекст.ОбновлениеОтменено = Истина; + КонецЕсли; + Возврат; + КонецЕсли; + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + НачалоОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Если ЗанятыеПотоки = Неопределено Тогда + ЗанятыеПотоки = Контекст.ЗанятыеПотоки; + КонецЕсли; + ОписаниеПотоков = Новый Соответствие(Новый ФиксированноеСоответствие(ЗанятыеПотоки)); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторОтмены", ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей()); + Запрос.УстановитьПараметр("ИдентификаторыПотоков", ИдентификаторыПотоков(ОписаниеПотоков)); + Запрос.УстановитьПараметр("ГраницаОжиданияВыполнения", ТекущаяДатаСеанса() + - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()); + + Запрос.Текст = + "ВЫБРАТЬ + | ТекущиеЗадания.ИдентификаторПотока КАК ИдентификаторПотока, + | ТекущиеЗадания.Результат КАК Результат, + | ТекущиеЗадания.ЭтоЗапуск + | И &ГраницаОжиданияВыполнения > ТекущиеЗадания.ДатаИзмененияЗаписиРегистра + | ИЛИ ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторОтмены КАК ПревышеноВремяВыполнения, + | ТекущиеЗадания.ДатаИзмененияЗаписиРегистра КАК ДатаИзмененияЗаписиРегистра + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | (НЕ ТекущиеЗадания.ЭтоЗапуск + | И ТекущиеЗадания.ИдентификаторПотока В (&ИдентификаторыПотоков) + | ИЛИ ТекущиеЗадания.ЭтоЗапуск + | И &ГраницаОжиданияВыполнения > ТекущиеЗадания.ДатаИзмененияЗаписиРегистра + | ИЛИ ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторОтмены)"; + + ОписаниеРезультатов = Новый Соответствие; + Выборка = Запрос.Выполнить().Выбрать(); + + Пока Выборка.Следующий() Цикл + Если Выборка.ПревышеноВремяВыполнения = Истина Тогда + Если Выборка.ИдентификаторПотока = ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей() Тогда + Контекст.ОбновлениеОтменено = Истина; + Возврат; + КонецЕсли; + Поток = Контекст.ЗанятыеПотоки.Получить(Выборка.ИдентификаторПотока); + Если Поток = Неопределено Тогда + Для Каждого СвободныйПоток Из Контекст.СвободныеПотоки Цикл + Если СвободныйПоток.ИдентификаторПотока = Выборка.ИдентификаторПотока Тогда + Поток = СвободныйПоток; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если Поток = Неопределено Тогда + Продолжить; + КонецЕсли; + Если Поток.Задание.ИдентификаторСписка = Контекст.ИдентификаторСправочникаНаборыГруппДоступа + И Выборка.ДатаИзмененияЗаписиРегистра > (Запрос.Параметры.ГраницаОжиданияВыполнения + - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()) Тогда + Продолжить; + КонецЕсли; + + ПредставлениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Превышено время выполнения задания в потоке (%1 сек). + |Рекомендуется реиндексация и обновление статистик таблиц базы данных. + |В некоторых случаях, достаточно запустить обновление доступа еще раз. + |См. также режим ""Медленный диск"" в панели настройки количества потоков.'"), + МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()); + + Поток.Задание.БылаОшибка = Истина; + Поток.Задание.ТекстОшибки = ТекстОшибкиОбновленияСКонтекстом(ПредставлениеОшибки, Поток.Задание); + + ОтменитьФоновоеЗаданиеПотока(Поток, Контекст); + УдалитьПоток(Поток, Контекст); + ОписаниеПотоков.Удалить(Поток.ИдентификаторПотока); + + Если Показатели <> Неопределено Тогда + Показатели.КоличествоПотоковСПревышениемВремениВыполнения = + Показатели.КоличествоПотоковСПревышениемВремениВыполнения + 1; + КонецЕсли; + + ИначеЕсли ТипЗнч(Выборка.Результат) = Тип("ХранилищеЗначения") Тогда + ОписаниеРезультата = Новый Структура; + ОписаниеРезультата.Вставить("ДатаЗавершения", Выборка.ДатаИзмененияЗаписиРегистра); + ОписаниеРезультата.Вставить("Результат", Выборка.Результат.Получить()); + ОписаниеРезультатов.Вставить(Выборка.ИдентификаторПотока, ОписаниеРезультата); + КонецЕсли; + КонецЦикла; + + ЗадержкаЗапроса = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000; + Для Каждого ОписаниеПотока Из ОписаниеПотоков Цикл + Поток = ОписаниеПотока.Значение; + ОписаниеРезультата = ОписаниеРезультатов.Получить(Поток.ИдентификаторПотока); + ОбработатьРезультатВыполненногоЗадания(Поток, ОписаниеРезультата, Контекст, ЗадержкаЗапроса); + КонецЦикла; + + КоличествоПотоков = Контекст.ЗанятыеПотоки.Количество() + Контекст.СвободныеПотоки.Количество(); + Если КоличествоПотоков > Контекст.КоличествоПотоков Тогда + Индекс = Контекст.СвободныеПотоки.Количество() - 1; + Пока Индекс >= 0 Цикл + СвободныйПоток = Контекст.СвободныеПотоки.Получить(Индекс); + УдалитьПоток(СвободныйПоток, Контекст); + Индекс = Индекс - 1; + КоличествоПотоков = КоличествоПотоков - 1; + Если КоличествоПотоков <= Контекст.КоличествоПотоков Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Ложь; + Если ЗадержкаЗапроса > 0 Тогда + ЭтоОбработкаУстаревшихЭлементов = Контекст.ОбщиеПараметрыОбновления.ЭтоОбработкаУстаревшихЭлементов; + ТекущиеЗанятыеПотоки = Новый Соответствие(Новый ФиксированноеСоответствие(Контекст.ЗанятыеПотоки)); + ТекущийМомент = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ДлительныеПотоки = Новый СписокЗначений; + ЕстьДлительноеЗаданиеПолученияПорций = Ложь; + Для Каждого ОписаниеПотока Из ТекущиеЗанятыеПотоки Цикл + Поток = ОписаниеПотока.Значение; // см. НовыйПоток + Если Поток.ПорцияИзНабора <> Неопределено + Или Поток.Задание.ЭтоОбновлениеПрав + Или Поток.ПолучитьПорции = 0 Тогда + Продолжить; + КонецЕсли; + Если ЭтоДлительноеЗаданиеПолученияПорций(Поток.Задание) Тогда + ЕстьДлительноеЗаданиеПолученияПорций = Истина; + КонецЕсли; + Если ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса / 2 Тогда + Продолжить; + КонецЕсли; + ДлительныеПотоки.Добавить(Поток, Формат(Поток.МоментЗапускаЗадания, "ЧЦ=23; ЧВН=")); + Если ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда + Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Истина; + КонецЕсли; + КонецЦикла; + Если Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных Тогда + ДлительныеПотоки.СортироватьПоПредставлению(); + Поток = ДлительныеПотоки.Получить(0).Значение; // см. НовыйПоток + Граница1 = ТекущаяДатаСеанса() + ЗадержкаЗапроса + 5; + Граница2 = ТекущаяДатаСеанса() + ЗадержкаЗапроса * 10; + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница1; + ДлительныеПотоки.Удалить(0); + Для Каждого ОписаниеПотока Из ДлительныеПотоки Цикл + Поток = ОписаниеПотока.Значение; // см. НовыйПоток + Если Не ЭтоОбработкаУстаревшихЭлементов И Поток.Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Граница2 = Граница2 + ЗадержкаЗапроса * 2; + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница2; + ИначеЕсли ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда + Продолжить; + Иначе + Граница1 = Граница1 + 10; + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница1; + КонецЕсли; + ОтменитьФоновоеЗаданиеПотока(Поток, Контекст); + УдалитьПоток(Поток, Контекст); + Контекст.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); + КонецЦикла; + КонецЕсли; + Если ЕстьДлительноеЗаданиеПолученияПорций Тогда + Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Истина; + КонецЕсли; + КонецЕсли; + + Если ТекущаяДатаСеанса() > Контекст.ГраницаОбновленияЗаданий Тогда + Контекст.ГраницаОбновленияЗаданий = ТекущаяДатаСеанса() + 2; + УдалитьОстановленныеПотоки(Контекст, Контекст.ЗанятыеПотоки); + УдалитьОстановленныеПотоки(Контекст, Контекст.СвободныеПотоки); + УдалитьНеиспользуемыеСвободныеПотоки(Контекст); + КонецЕсли; + + Если Показатели <> Неопределено Тогда + Показатели.ВремяОбработкиРезультатовЗаданий = Показатели.ВремяОбработкиРезультатовЗаданий + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОбработки); + КонецЕсли; + +КонецПроцедуры + +// Параметры: +// Задание - СтрокаТаблицыЗначений из см. ТаблицаЗаданийОбновления +// +// Возвращаемое значение: +// Булево +// +Функция ЭтоДлительноеЗаданиеПолученияПорций(Задание) + + Возврат Задание.ДлительноеЗаданиеПолученияПорцийДо > ТекущаяДатаСеанса(); + +КонецФункции + +// Для процедур ОбработатьВыполненныеЗадания, ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора. +Функция ОбновлениеДоступаОтменено() + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторПотока", ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей()); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторПотока"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Для процедуры ОбработатьВыполненныеЗадания. +Процедура ОбработатьРезультатВыполненногоЗадания(Поток, ОписаниеРезультата, Контекст, ЗадержкаЗапроса) + + Если Не Поток.ОтменитьЗадание + И Не Поток.Задание.Удалить Тогда + + Если ОписаниеРезультата = Неопределено Тогда + Возврат; + ИначеЕсли ТипЗнч(ОписаниеРезультата.Результат) <> Тип("Структура") Тогда + Контекст.ОбработкаЗавершена = Ложь; + Иначе + Результат = ОписаниеРезультата.Результат; + Если Результат.Свойство("ПорцияИзНабора") Тогда + Результат.ПорцияИзНабора = Поток.ПорцияИзНабора; + КонецЕсли; + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + Показатели.НачалоОбработкиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + Если ЗадержкаЗапроса > 0 + И ЭтоДлительноеЗаданиеПолученияПорций(Поток.Задание) + И Результат.Свойство("НаборПорций") + И ТекущаяУниверсальнаяДатаВМиллисекундах() - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = '00010101'; + КонецЕсли; + ОбработатьРезультатЗадания(Контекст, Результат, Поток.Задание); + Если Показатели <> Неопределено Тогда + СнятьПоказателиОбработкиРезультатаЗадания(Показатели); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если ОписаниеРезультата = Неопределено Тогда + ДатаЗавершения = Неопределено; + Иначе + ДатаЗавершения = ОписаниеРезультата.ДатаЗавершения; + КонецЕсли; + + ОсвободитьПоток(Поток, Контекст, ДатаЗавершения); + +КонецПроцедуры + +// Для процедур ОбработатьРезультатВыполненногоЗадания, УдалитьПоток. +Процедура ОсвободитьПоток(Поток, Контекст, ДатаЗавершения = Неопределено) + + ПозицияВставки = 0; + Если ДатаЗавершения = Неопределено Тогда + Поток.ДатаОсвобождения = ТекущаяДатаСеанса(); + Иначе + Поток.ДатаОсвобождения = ДатаЗавершения; + Количество = Контекст.СвободныеПотоки.Количество(); + Пока ПозицияВставки < Количество Цикл + ТекущийПоток = Контекст.СвободныеПотоки.Получить(ПозицияВставки); + Если ТекущийПоток.ДатаОсвобождения <= ДатаЗавершения Тогда + Прервать; + КонецЕсли; + ПозицияВставки = ПозицияВставки + 1; + КонецЦикла; + КонецЕсли; + + Контекст.СвободныеПотоки.Вставить(ПозицияВставки, Поток); + Контекст.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); + Поток.Задание.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); + Если Поток.ПорцияИзНабора <> Неопределено Тогда + СнятьПризнакОбрабатываетсяДляПорции(Поток, Поток.Задание); + Поток.ПорцияИзНабора = Неопределено; + КонецЕсли; + Поток.МоментЗапускаЗадания = 0; + Поток.ПолучитьПорции = 0; + Поток.Задание = Неопределено; + Поток.ОтменитьЗадание = Ложь; + +КонецПроцедуры + +// Для процедур ЗапуститьОбновлениеДоступаСписка, ОбработатьРезультатВыполненногоЗадания, ОсвободитьПоток. +Процедура СнятьПризнакОбрабатываетсяДляПорции(ПотокИлиРезультат, Задание) + + ПорцияИзНабора = Неопределено; + + Если Не ПотокИлиРезультат.Свойство("ПорцияИзНабора", ПорцияИзНабора) + Или ПорцияИзНабора = Неопределено + Или Не ПорцияИзНабора.Обрабатывается Тогда + Возврат; + КонецЕсли; + + Если Не ПорцияИзНабора.Обработана Тогда + ИндексПорции = Задание.НаборПорций.Найти(ПорцияИзНабора); + + Если ИндексПорции = Неопределено Тогда + Задание.ИндексСледующейПорцииДляОбработки = 0; + + ИначеЕсли Задание.ИндексСледующейПорцииДляОбработки > ИндексПорции Тогда + Задание.ИндексСледующейПорцииДляОбработки = ИндексПорции; + КонецЕсли; + КонецЕсли; + + ПорцияИзНабора.Обрабатывается = Ложь; + +КонецПроцедуры + +// Для процедуры ОбработатьРезультатВыполненногоЗадания, ЗавершитьОбновлениеДоступа. +Процедура УдалитьПоток(Поток, Контекст) + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + НаборЗаписей.Отбор.ИдентификаторПотока.Установить(Поток.ИдентификаторПотока); + НаборЗаписей.Записать(); + + Если Контекст.ЗанятыеПотоки.Получить(Поток.ИдентификаторПотока) <> Неопределено Тогда + ОсвободитьПоток(Поток, Контекст); + КонецЕсли; + + Индекс = Контекст.СвободныеПотоки.Найти(Поток); + Если Индекс <> Неопределено Тогда + Контекст.СвободныеПотоки.Удалить(Индекс); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбработатьРезультатВыполненногоЗадания, ЗавершитьОбновлениеДоступа. +Процедура УдалитьОстановленныеПотоки(Контекст, ОписаниеПотоков) + + Если ТипЗнч(ОписаниеПотоков) = Тип("Соответствие") Тогда + ИсходноеОписаниеПотоков = Новый ФиксированноеСоответствие(ОписаниеПотоков); + Иначе + ИсходноеОписаниеПотоков = Новый ФиксированныйМассив(ОписаниеПотоков); + КонецЕсли; + + Для Каждого ОписаниеПотока Из ИсходноеОписаниеПотоков Цикл + Если ТипЗнч(ОписаниеПотока) = Тип("КлючИЗначение") Тогда + Поток = ОписаниеПотока.Значение; + Иначе + Поток = ОписаниеПотока; + КонецЕсли; + ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); + ФоновоеЗадание = Поток.ФоновоеЗадание; + + Если ФоновоеЗадание <> Неопределено + И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + Продолжить; + КонецЕсли; + Контекст.ОбработкаЗавершена = Ложь; + + УдалитьПоток(Поток, Контекст); + + Если ФоновоеЗадание <> Неопределено + И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда + + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( + ФоновоеЗадание.ИнформацияОбОшибке, Поток.Задание, Истина), Контекст); + + Если Контекст.Показатели <> Неопределено Тогда + Контекст.Показатели.КоличествоПотоковСНештатнымЗавершением = + Контекст.Показатели.КоличествоПотоковСНештатнымЗавершением + 1; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбработатьВыполненныеЗадания. +Процедура УдалитьНеиспользуемыеСвободныеПотоки(Контекст) + + Количество = Контекст.СвободныеПотоки.Количество(); + Если Количество = 0 Тогда + Возврат; + КонецЕсли; + + СвободныеПотоки = Контекст.СвободныеПотоки; + Индекс = Количество - 1; + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + + Пока Индекс >= 0 Цикл + Поток = СвободныеПотоки.Получить(Индекс); + Если ТекущаяДатаСеанса > Поток.ДатаОсвобождения + 15 Тогда + УдалитьПоток(Поток, Контекст); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ДобавитьЗаданияОбновленияДоступа и ОбработатьРезультатЗадания. +Процедура ОтменитьЗадание(Задание) + + Задание.НаборПорций = Новый Массив; + Задание.КоличествоПорцийДляОбработки = 0; + Задание.ИндексСледующейПорцииДляОбработки = 0; + + Для Каждого ОписаниеПотока Из Задание.ЗанятыеПотоки Цикл + ОписаниеПотока.Значение.ОтменитьЗадание = Истина; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗапуститьОбновлениеДоступаСписка, ОбработатьРезультатВыполненногоЗадания. +Процедура ОбработатьРезультатЗадания(Контекст, Результат, Задание) + + Если Результат.Свойство("НетЗаданий") Или Результат.Свойство("ПерезапускОбновления") Тогда + Если Результат.Свойство("ПерезапускОбновления") Тогда + Задание.ЕстьПерезапуск = Истина; + Если Результат.Свойство("ПерезапускОбновленияСНачала") Тогда + Задание.ЕстьНачальноеОбновление = Истина; + КонецЕсли; + КонецЕсли; + ОтменитьЗадание(Задание); + Если Результат.Свойство("НетЗаданий") Тогда + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + ОбновитьСвойстваЗадания(Задание, Новый Структура("КлючДанных", Null)); + Если Результат.НетЗаданий = "ОбъектМетаданныхОтключен" Тогда + Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Вставить(Задание.ИдентификаторСписка, Истина); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если Результат.Свойство("ТребуетсяПерезапускСеанса") Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Контекст.ОбработкаЗавершена = Ложь; + СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(Результат.ТребуетсяПерезапускСеанса); + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + Возврат; + КонецЕсли; + + Если Результат.Свойство("ТекстОшибкиЗавершения") Тогда + Если Не Результат.ОбработкаЗавершена Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + Если ЗначениеЗаполнено(Результат.ТекстОшибкиЗавершения) Тогда + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + ДобавитьТекстОшибкиЗавершения(Контекст.ТекстОшибкиЗавершения, Результат.ТекстОшибкиЗавершения); + Возврат; + КонецЕсли; + КонецЕсли; + + Если Результат.Свойство("НетЗаданий") Тогда + Возврат; + КонецЕсли; + + Если Результат.Свойство("НачальноеОбновлениеЗавершено") Тогда + Задание.ЕстьНачальноеОбновление = Ложь; + Задание.ЕстьПерезапуск = Ложь; + КонецЕсли; + + Если Результат.Свойство("ПорцияИзНабора") Тогда + ИсходнаяПорцияИзНабора = Результат.ПорцияИзНабора; + Если Результат.Свойство("НаборПорций") Тогда + Индекс = Задание.НаборПорций.Найти(ИсходнаяПорцияИзНабора); + Если Задание.ИндексСледующейПорцииДляОбработки > Индекс Тогда + Задание.ИндексСледующейПорцииДляОбработки = Индекс + 1; + КонецЕсли; + Для Каждого НоваяПорцияИзИсходной Из Результат.НаборПорций Цикл + Индекс = Индекс + 1; + Задание.НаборПорций.Вставить(Индекс, НоваяПорцияИзИсходной); + КонецЦикла; + Задание.КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки + + Результат.НаборПорций.Количество(); + ИсходнаяПорцияИзНабора.ПоследнийЭлементПорции = Результат.НовыйПоследнийОбновленныйЭлемент; + ИсходнаяПорцияИзНабора.НовыйПоследнийЭлементПорции = Результат.НовыйПоследнийОбновленныйЭлемент; + КонецЕсли; + ИсходнаяПорцияИзНабора.Обработана = Истина; + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + + ИначеЕсли Результат.Свойство("НаборПорций") Тогда + Для Каждого НоваяПорция Из Результат.НаборПорций Цикл + Задание.НаборПорций.Добавить(НоваяПорция); + КонецЦикла; + Задание.КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки + + Результат.НаборПорций.Количество(); + + ИначеЕсли Результат.Свойство("НовыйПоследнийОбновленныйЭлемент") Тогда + ОбновитьСвойстваЗадания(Задание, Результат.НовыйПоследнийОбновленныйЭлемент); + КонецЕсли; + + Если Результат.Свойство("ПорцияИзНабора") И ОбщееЗаданиеВыполняется(Задание) Тогда + Возврат; + КонецЕсли; + + Зафиксировать = Ложь; + Пока Задание.НаборПорций.Количество() > 0 Цикл + ПорцияИзНабора = Задание.НаборПорций[0]; + Если Не ПорцияИзНабора.Обработана Тогда + Прервать; + КонецЕсли; + Зафиксировать = Истина; + НовыйПоследнийОбновленныйЭлемент = ПорцияИзНабора.НовыйПоследнийЭлементПорции; + Задание.НаборПорций.Удалить(0); + Если Задание.ИндексСледующейПорцииДляОбработки > 0 Тогда + Задание.ИндексСледующейПорцииДляОбработки = Задание.ИндексСледующейПорцииДляОбработки - 1; + КонецЕсли; + КонецЦикла; + + Если Зафиксировать Тогда + ЗаписатьПоследнийОбновленныйЭлемент(Результат, НовыйПоследнийОбновленныйЭлемент); + ОбновитьСвойстваЗадания(Задание, НовыйПоследнийОбновленныйЭлемент); + Если Не Результат.ОбработкаЗавершена Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбработатьРезультатЗадания. +Процедура ОбновитьСвойстваЗадания(Задание, НовыйПоследнийОбновленныйЭлемент) + + Если НовыйПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда + Задание.Удалить = Истина; + Иначе + Если НовыйПоследнийОбновленныйЭлемент.Свойство("Дата") Тогда + Задание.ДатаПоследнегоОбновленногоЭлемента = НовыйПоследнийОбновленныйЭлемент.Дата; + Иначе + Задание.ДатаПоследнегоОбновленногоЭлемента = '00010101'; + КонецЕсли; + Задание.ЕстьДатаПоследнегоОбновленногоЭлемента + = ЗначениеЗаполнено(Задание.ДатаПоследнегоОбновленногоЭлемента); + + Задание.ПорядокВидаКлючаДанных = НовыйПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных; + ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание); + КонецЕсли; + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка. +Процедура ВыполнитьОбновлениеДоступаСпискаВФоне(ОписаниеРодительскогоСеанса) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Контекст = Новый Структура; + Контекст.Вставить("Показатели", ПоказателиОбновленияИсполняющегоПотока()); + Контекст.Вставить("ОписаниеРодительскогоСеанса", ОписаниеРодительскогоСеанса); + + Если Не ИсполняющийПотокЗапущен(Контекст) Тогда + Возврат; + КонецЕсли; + Кэш = Новый Структура; + УстановитьЭтоСеансФоновогоОбновленияДоступа(); + + Пока Истина Цикл + Запрос = Контекст.Запрос; // Запрос + Выборка = Запрос.Выполнить().Выбрать(); + Если Не Выборка.Следующий() Тогда + Прервать; + КонецЕсли; + Если ТипЗнч(Выборка.Параметры) <> Тип("ХранилищеЗначения") Тогда + Если ПродолжитьОжиданиеНовогоЗадания(Контекст) Тогда + Продолжить; + Иначе + Прервать; + КонецЕсли; + КонецЕсли; + Результат = ОписаниеОбщихПараметровОбновления(); + Результат.Вставить("ОбработкаЗавершена", Ложь); + Результат.Вставить("ТекстОшибкиЗавершения", ""); + Попытка + ОбщиеПараметрыОбновления = Выборка.Параметры.Получить(); // см. ОписаниеОбщихПараметровОбновления + ЗаполнитьЗначенияСвойств(Результат, ОбщиеПараметрыОбновления); + ОбщиеПараметрыОбновления.Вставить("Кэш", Кэш); + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания = + Цел(0.025 * Результат.МаксимумМиллисекундОбработки) / 1000; + + ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст); + Результат.ОбработкаЗавершена = ОбщиеПараметрыОбновления.ОбработкаЗавершена; + + ВозвращаемыеСвойства = "НетЗаданий, ПерезапускОбновления, ПерезапускОбновленияСНачала, + |НаборПорций, НовыйПоследнийОбновленныйЭлемент, НачальноеОбновлениеЗавершено, + |ТекстОшибкиЗавершения, ТребуетсяПерезапускСеанса"; + Для Каждого КлючИЗначение Из Новый Структура(ВозвращаемыеСвойства) Цикл + Если ОбщиеПараметрыОбновления.Свойство(КлючИЗначение.Ключ) Тогда + Результат.Вставить(КлючИЗначение.Ключ, ОбщиеПараметрыОбновления[КлючИЗначение.Ключ]); + КонецЕсли; + КонецЦикла; + Если ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") Тогда + Результат.Вставить("ПорцияИзНабора"); + КонецЕсли; + Исключение + ДобавитьТекстОшибкиЗавершения(Результат.ТекстОшибкиЗавершения, ТекстОшибкиОбновленияСКонтекстом( + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()), Результат)); + КонецПопытки; + ЗаписатьРезультатОбновленияДоступаСпискаВФоне(Результат, Выборка.Параметры, Контекст); + КонецЦикла; + + ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока(Контекст); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Функция ИсполняющийПотокЗапущен(Контекст) + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + Контекст.Вставить("ТекущийСеанс", ТекущийСеанс); + + Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда + ТекстОшибки = НСтр("ru = 'Порция обновления доступа может обрабатываться только в фоновом задании.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Контекст.Вставить("ТекущееФоновоеЗадание", ТекущийСеанс.ПолучитьФоновоеЗадание()); + ИдентификаторПотока = Контекст.ТекущееФоновоеЗадание.УникальныйИдентификатор; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторПотока", ИдентификаторПотока); + Запрос.Текст = + "ВЫБРАТЬ + | ВЫБОР + | КОГДА ТекущиеЗадания.ЭтоЗапуск + | ТОГДА ТекущиеЗадания.Параметры + | ИНАЧЕ НЕОПРЕДЕЛЕНО + | КОНЕЦ КАК Параметры + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторПотока"; + Контекст.Вставить("Запрос", Запрос); + + Блокировка = Новый("БлокировкаДанных"); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания"); + ЭлементБлокировки.УстановитьЗначение("ИдентификаторПотока", ИдентификаторПотока); + Контекст.Вставить("Блокировка", Блокировка); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока); + Контекст.Вставить("НаборЗаписей", НаборЗаписей); + + ЗаписьНабора = НаборЗаписей.Добавить(); + ЗаписьНабора.ИдентификаторПотока = ИдентификаторПотока; + ЗаписьНабора.ЭтоЗапуск = Ложь; + Контекст.Вставить("ЗаписьНабора", ЗаписьНабора); + + // Ожидание признака запуска. + ГраницаОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + Пока Истина Цикл + Если Не Запрос.Выполнить().Пустой() Тогда + Прервать; + КонецЕсли; + Если ТекущаяУниверсальнаяДатаВМиллисекундах() > ГраницаОжидания Тогда + Возврат Ложь; + КонецЕсли; + Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения(0.025); + КонецЦикла; + + Контекст.Вставить("ГраницаПроверкиРодительскогоСеанса", ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000); + Контекст.Вставить("КоличествоСекундОжиданияДоПоискаНовогоЗадания", 0.025); + + Возврат Истина; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Функция ПродолжитьОжиданиеНовогоЗадания(Контекст) + + Если ТекущаяУниверсальнаяДатаВМиллисекундах() > Контекст.ГраницаПроверкиРодительскогоСеанса Тогда + Если ОбновлениеДоступаОтменено() Тогда + Возврат Ложь; + КонецЕсли; + Контекст.ГраницаПроверкиРодительскогоСеанса = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + Если Не СеансСуществует(Контекст.ОписаниеРодительскогоСеанса) Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + Показатели.КоличествоОжиданийНовыхЗаданий = Показатели.КоличествоОжиданийНовыхЗаданий + 1; + КонецЕсли; + + НачалоОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + + Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения( + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания); + + Если Показатели <> Неопределено Тогда + Показатели.ВремяОжиданияНовыхЗаданий = Показатели.ВремяОжиданияНовыхЗаданий + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОжидания); + КонецЕсли; + Если Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания < 1 Тогда + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания = + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания + 0.010; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для функции ПродолжитьОжиданиеНовогоЗадания. +Функция СеансСуществует(ОписаниеСеанса) + + Если ЗначениеЗаполнено(ОписаниеСеанса.ИдентификаторФоновогоЗадания) Тогда + ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору( + ОписаниеСеанса.ИдентификаторФоновогоЗадания); + + Возврат ФоновоеЗадание <> Неопределено + И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно; + КонецЕсли; + + ОсновнойСеансНайден = Ложь; + Сеансы = ПолучитьСеансыИнформационнойБазы(); + + Для Каждого Сеанс Из Сеансы Цикл + + Если Сеанс.НачалоСеанса = ОписаниеСеанса.НачалоСеанса + И Сеанс.НомерСеанса = ОписаниеСеанса.НомерСеанса Тогда + + ОсновнойСеансНайден = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат ОсновнойСеансНайден; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура ЗаписатьРезультатОбновленияДоступаСпискаВФоне(Результат, ИсходныеПараметры, Контекст) + + НачатьТранзакцию(); + Попытка + Контекст.Блокировка.Заблокировать(); + Запрос = Контекст.Запрос; // Запрос - + Выборка = Запрос.Выполнить().Выбрать(); + + Если Выборка.Следующий() + И XMLСтрока(Выборка.Параметры) = XMLСтрока(ИсходныеПараметры) Тогда + + Контекст.ЗаписьНабора.Параметры = ИсходныеПараметры; + Контекст.ЗаписьНабора.Результат = Новый ХранилищеЗначения(Результат); + Контекст.ЗаписьНабора.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + НаборЗаписей = Контекст.НаборЗаписей; // РегистрСведенийНаборЗаписей - + НаборЗаписей.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Функция ПоказателиОбновленияОсновногоСеанса() + + Если Не РегистрироватьПоказателиОбновленияДоступа() + Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда + Возврат Неопределено; + КонецЕсли; + + Показатели = Новый Структура; + Показатели.Вставить("ВремяПроверкиИОбновленияПараметровОграничения", 0); + Показатели.Вставить("ВремяОбновленияПараметровОграничения", 0); + + // Переменные. + Показатели.Вставить("НачалоРаботыВМиллисекундах", ТекущаяУниверсальнаяДатаВМиллисекундах()); + Показатели.Вставить("НачалоВыдачиЗадания"); + + Возврат Показатели; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ДобавитьПоказателиОбновленияУправляющегоПотока(Контекст) + + Показатели = Контекст.Показатели; + Если Показатели = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + ДобавитьПоказателиВыполненияЗаданий(Показатели); + Иначе + Показатели.Вставить("ВремяОжиданийСвободногоПотока", 0); + + Показатели.Вставить("КоличествоВыданныхЗаданий", 0); + Показатели.Вставить("ВремяВыдачиЗаданий", 0); + Показатели.Вставить("МинимальноеВремяВыдачиЗадания", 0); + Показатели.Вставить("МаксимальноеВремяВыдачиЗадания", 0); + + Показатели.Вставить("ВремяОбработкиРезультатовЗаданий", 0); + Показатели.Вставить("МинимальноеВремяОбработкиРезультатаЗадания", 0); + Показатели.Вставить("МаксимальноеВремяОбработкиРезультатаЗадания", 0); + + Показатели.Вставить("КоличествоПотоковСПревышениемВремениВыполнения", 0); + Показатели.Вставить("КоличествоПотоковСНештатнымЗавершением", 0); + + // Переменные. + Показатели.Вставить("НачалоОбработкиЗадания", 0); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Функция ПоказателиОбновленияИсполняющегоПотока() + + Если Не РегистрироватьПоказателиОбновленияДоступа() + Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда + Возврат Неопределено; + КонецЕсли; + + Показатели = Новый Структура; + + Показатели.Вставить("НачалоРаботыВМиллисекундах", ТекущаяУниверсальнаяДатаВМиллисекундах()); + Показатели.Вставить("КоличествоОжиданийНовыхЗаданий", 0); + Показатели.Вставить("ВремяОжиданияНовыхЗаданий", 0); + + ДобавитьПоказателиВыполненияЗаданий(Показатели); + + Возврат Показатели; + +КонецФункции + +// Для функций ПоказателиОбновленияУправляющегоПотока, ПоказателиОбновленияИсполняющегоПотока. +Процедура ДобавитьПоказателиВыполненияЗаданий(Показатели) + + // Переменные. + Показатели.Вставить("ЗаданиеСПолучениемПорций", Истина); + Показатели.Вставить("НачалоПервойПопыткиВыполненияЗадания", 0); + Показатели.Вставить("НачалоВыполненияЗадания", 0); + + // Общие показатели. + Показатели.Вставить("КоличествоЗаданийСПовторамиИзЗаОшибок", 0); + Показатели.Вставить("ВремяВыполненияЗаданийСПовторамиИзЗаОшибок", 0); + Показатели.Вставить("КоличествоПовторовЗаданийИзЗаОшибок", 0); + Показатели.Вставить("МаксимальноеКоличествоПовторовЗаданияПриОшибке", 0); + Показатели.Вставить("ТекстОшибокПриПопыткахПовтора", ""); + + // Получение порций или сразу обработка маленькой порции. + Показатели.Вставить("КоличествоВыполненныхЗаданийСПолучениемПорций", 0); + Показатели.Вставить("ВремяВыполненияЗаданийСПолучениемПорций", 0); + Показатели.Вставить("МинимальноеВремяВыполненияЗаданийСПолучениемПорций", 0); + Показатели.Вставить("МаксимальноеВремяВыполненияЗаданийСПолучениемПорций", 0); + + // Только обработки порции. + Показатели.Вставить("КоличествоВыполненныхЗаданийБезПолученияПорций", 0); + Показатели.Вставить("ВремяВыполненияЗаданийБезПолученияПорций", 0); + Показатели.Вставить("МинимальноеВремяВыполненияЗаданийБезПолученияПорций", 0); + Показатели.Вставить("МаксимальноеВремяВыполненияЗаданийБезПолученияПорций", 0); + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка. +Процедура СнятьПоказателиВыдачиЗаданий(Показатели) + + ВремяВыдачиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоВыдачиЗадания; + + Показатели.КоличествоВыданныхЗаданий = Показатели.КоличествоВыданныхЗаданий + 1; + Показатели.ВремяВыдачиЗаданий = Показатели.ВремяВыдачиЗаданий + ВремяВыдачиЗадания; + + Если Показатели.МинимальноеВремяВыдачиЗадания = 0 Тогда + Показатели.МинимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; + КонецЕсли; + Если ВремяВыдачиЗадания < Показатели.МинимальноеВремяВыдачиЗадания Тогда + Показатели.МинимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; + КонецЕсли; + + Если ВремяВыдачиЗадания > Показатели.МаксимальноеВремяВыдачиЗадания Тогда + Показатели.МаксимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; + КонецЕсли; + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка. +Процедура СнятьПоказателиОбработкиРезультатаЗадания(Показатели) + + ВремяОбработкиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоОбработкиЗадания; + + Показатели.ВремяОбработкиРезультатовЗаданий = + Показатели.ВремяОбработкиРезультатовЗаданий + ВремяОбработкиЗадания; + + Если Показатели.МинимальноеВремяОбработкиРезультатаЗадания = 0 Тогда + Показатели.МинимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; + КонецЕсли; + Если ВремяОбработкиЗадания < Показатели.МинимальноеВремяОбработкиРезультатаЗадания Тогда + Показатели.МинимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; + КонецЕсли; + + Если ВремяОбработкиЗадания > Показатели.МаксимальноеВремяОбработкиРезультатаЗадания Тогда + Показатели.МаксимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура СнятьПоказателиВыполненияЗадания(Показатели) + + ВремяВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоВыполненияЗадания; + + Если Показатели.ЗаданиеСПолучениемПорций Тогда + Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций = + Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций + 1; + + Показатели.ВремяВыполненияЗаданийСПолучениемПорций = + Показатели.ВремяВыполненияЗаданийСПолучениемПорций + ВремяВыполненияЗадания; + + Если Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = 0 Тогда + Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; + КонецЕсли; + Если ВремяВыполненияЗадания < Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций Тогда + Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; + КонецЕсли; + + Если ВремяВыполненияЗадания > Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций Тогда + Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; + КонецЕсли; + Иначе + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций = + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций + 1; + + Показатели.ВремяВыполненияЗаданийБезПолученияПорций = + Показатели.ВремяВыполненияЗаданийБезПолученияПорций + ВремяВыполненияЗадания; + + Если Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = 0 Тогда + Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; + КонецЕсли; + Если ВремяВыполненияЗадания < Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций Тогда + Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; + КонецЕсли; + + Если ВремяВыполненияЗадания > Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций Тогда + Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура СнятьПоказателиОшибокВыполненияЗадания(Показатели, ТекстОшибок, КоличествоОшибок); + + Если КоличествоОшибок = 0 Тогда + Возврат; + КонецЕсли; + + Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок = Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок + 1; + + Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок = Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоПервойПопыткиВыполненияЗадания); + + Показатели.КоличествоПовторовЗаданийИзЗаОшибок = + Показатели.КоличествоПовторовЗаданийИзЗаОшибок + КоличествоОшибок; + + Если КоличествоОшибок > Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке Тогда + Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке = КоличествоОшибок; + КонецЕсли; + + ДобавитьТекстОшибкиЗавершения(Показатели.ТекстОшибокПриПопыткахПовтора, ТекстОшибок); + +КонецПроцедуры + +// Для процедур ЗарегистрироватьПоказателиОбновленияОсновногоПотока, +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока, +// ДобавитьЗначенияПоказателейРаботыСеанса, +// ДобавитьЗначенияПоказателейВыполненияЗаданий. +// +Функция ФорматСекунд(ЧислоСекунд) + + Если ЧислоСекунд = 0 Тогда + Возврат СтрЗаменить(Формат(1.111), "1", "0"); + КонецЕсли; + + Возврат Формат(ЧислоСекунд, "ЧДЦ=3; ЧГ="); + +КонецФункции + +// Для процедур ЗарегистрироватьПоказателиОбновленияОсновногоПотока, +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока, +// ДобавитьЗначенияПоказателейВыполненияЗаданий. +// +Функция ФорматКоличества(ЧислоКоличества) + + Возврат Формат(ЧислоКоличества, "ЧН=0; ЧГ="); + +КонецФункции + +// Для процедуры ЗавершитьОбновлениеДоступа. +Процедура ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст) + + Показатели = Контекст.Показатели; + Если Показатели = Неопределено Тогда + Возврат; + КонецЕсли; + + ОписаниеСеанса = Контекст.ОписаниеОсновногоСеанса; // См. ОписаниеОсновногоСеанса + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Комментарий = НСтр("ru = 'Завершен сеанс обновления доступа.'"); + ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса); + ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели); + Иначе + ВремяОжиданийСвободногоПотока = Показатели.ВремяОжиданийСвободногоПотока / 1000; + + ВремяВыдачиЗаданий = Показатели.ВремяВыдачиЗаданий / 1000; + МинимальноеВремяВыдачиЗадания = Показатели.МинимальноеВремяВыдачиЗадания / 1000; + МаксимальноеВремяВыдачиЗадания = Показатели.МаксимальноеВремяВыдачиЗадания / 1000; + + ВремяОбработкиРезультатовЗаданий = Показатели.ВремяОбработкиРезультатовЗаданий / 1000; + МинимальноеВремяОбработкиРезультатаЗадания = Показатели.МинимальноеВремяОбработкиРезультатаЗадания / 1000; + МаксимальноеВремяОбработкиРезультатаЗадания = Показатели.МаксимальноеВремяОбработкиРезультатаЗадания / 1000; + + Комментарий = НСтр("ru = 'Завершен сеанс управляющего потока обновления доступа.'"); + ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса); + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Время ожиданий свободного потока: %1 сек + | + |Количество выданных заданий: %2 + |Время выдачи заданий: %3 сек + |Минимальное время выдачи заданий: %4 сек + |Максимальное время выдачи заданий: %5 сек'"), + ФорматСекунд(ВремяОжиданийСвободногоПотока), + ФорматКоличества(Показатели.КоличествоВыданныхЗаданий), + ФорматСекунд(ВремяВыдачиЗаданий), + ФорматСекунд(МинимальноеВремяВыдачиЗадания), + ФорматСекунд(МаксимальноеВремяВыдачиЗадания)); + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Время обработки результатов заданий: %1 сек + |Минимальное время обработки результатов заданий: %2 сек + |Максимальное время обработки результатов заданий: %3 сек + | + |Количество потоков с превышением времени выполнения: %4 + |Количество потоков с нештатным завершением: %5'"), + ФорматСекунд(ВремяОбработкиРезультатовЗаданий), + ФорматСекунд(МинимальноеВремяОбработкиРезультатаЗадания), + ФорматСекунд(МаксимальноеВремяОбработкиРезультатаЗадания), + ФорматКоличества(Показатели.КоличествоПотоковСПревышениемВремениВыполнения), + ФорматКоличества(Показатели.КоличествоПотоковСНештатнымЗавершением)); + КонецЕсли; + Данные = ОписаниеСеанса.Идентификатор; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Показатели.Обновление доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, , Данные, Комментарий); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока(Контекст) + + Показатели = Контекст.Показатели; + Если Показатели = Неопределено Тогда + Возврат; + КонецЕсли; + + ВремяОжиданияНовыхЗаданий = Показатели.ВремяОжиданияНовыхЗаданий / 1000; + + Комментарий = НСтр("ru = 'Завершен сеанс исполняющего потока обновления доступа.'"); + ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, Контекст.ТекущийСеанс, Истина); + + ОписаниеСеанса = Контекст.ОписаниеРодительскогоСеанса; // См. ОписаниеОсновногоСеанса + + Комментарий = Комментарий + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Номер сеанса управляющего потока: %1 + |Начало сеанса управляющего потока: %2 + | + |Количество ожиданий новых заданий: %3 + |Время ожидания новых заданий: %4 сек'"), + ОписаниеСеанса.НомерСеанса, + ОписаниеСеанса.НачалоСеанса, + ФорматКоличества(Показатели.КоличествоОжиданийНовыхЗаданий), + ФорматСекунд(ВремяОжиданияНовыхЗаданий)); + + ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели); + Данные = ОписаниеСеанса.Идентификатор; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Показатели.Обновление доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, , Данные, Комментарий); + +КонецПроцедуры + +// Для процедур ЗарегистрироватьПоказателиОбновленияУправляющегоПотока и +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока. +// +Процедура ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса, ЭтоИсполняющийПоток = Ложь) + + ВремяРаботы = (ТекущаяУниверсальнаяДатаВМиллисекундах() + - Показатели.НачалоРаботыВМиллисекундах) / 1000; + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Номер сеанса: %1 + |Начало сеанса: %2 + |Время работы: %3 сек'"), + ОписаниеСеанса.НомерСеанса, + ОписаниеСеанса.НачалоСеанса, + ФорматСекунд(ВремяРаботы)); + + Если ЭтоИсполняющийПоток Тогда + Возврат; + КонецЕсли; + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Время проверки и обновления параметров ограничения: %1 сек + |Время обновления параметров ограничения: %2 сек'"), + ФорматСекунд(Показатели.ВремяПроверкиИОбновленияПараметровОграничения / 1000), + ФорматСекунд(Показатели.ВремяОбновленияПараметровОграничения / 1000)); + +КонецПроцедуры + +// Для процедур ЗарегистрироватьПоказателиОбновленияУправляющегоПотока и +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока. +// +Процедура ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели) + + ВремяВыполненияЗаданийСПолучениемПорций = Показатели.ВремяВыполненияЗаданийСПолучениемПорций / 1000; + МаксимальноеВремяВыполненияЗаданийСПолучениемПорций = Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций / 1000; + МинимальноеВремяВыполненияЗаданийСПолучениемПорций = Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций / 1000; + + ВремяВыполненияЗаданийБезПолученияПорций = Показатели.ВремяВыполненияЗаданийБезПолученияПорций / 1000; + МаксимальноеВремяВыполненияЗаданийБезПолученияПорций = Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций / 1000; + МинимальноеВремяВыполненияЗаданийБезПолученияПорций = Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций / 1000; + + КоличествоВыполненныхЗаданий = Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций + + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций; + + ВремяВыполненияЗаданий = ВремяВыполненияЗаданийСПолучениемПорций + ВремяВыполненияЗаданийБезПолученияПорций; + ВремяВыполненияЗаданийСПовторамиИзЗаОшибок = Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок / 1000; + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Количество выполненных заданий: %1 + |Время выполнения заданий: %2 сек + | + |Количество заданий с повторами из-за ошибок: %3 + |Время выполнения заданий с повторами из-за ошибок: %4 сек + |Количество повторов заданий из-за ошибок: %5 + |Максимум повторов отдельного задания из-за ошибок: %6'"), + ФорматКоличества(КоличествоВыполненныхЗаданий), + ФорматСекунд(ВремяВыполненияЗаданий), + ФорматКоличества(Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок), + ФорматСекунд(ВремяВыполненияЗаданийСПовторамиИзЗаОшибок), + ФорматКоличества(Показатели.КоличествоПовторовЗаданийИзЗаОшибок), + ФорматКоличества(Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке)); + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Задания получения порций и/или обработки маленькой порции: + |- количество выполненных заданий: %1 + |- время выполнения заданий: %2 сек + |- минимальное время выполнения задания: %3 сек + |- максимальное время выполнения задания: %4 сек + | + |Задания обработки порций: + |- количество выполненных заданий: %5 + |- время выполнения заданий: %6 сек + |- минимальное время выполнения задания: %7 сек + |- максимальное время выполнения задания: %8 сек'"), + ФорматКоличества(Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций), + ФорматСекунд(ВремяВыполненияЗаданийСПолучениемПорций), + ФорматСекунд(МинимальноеВремяВыполненияЗаданийСПолучениемПорций), + ФорматСекунд(МаксимальноеВремяВыполненияЗаданийСПолучениемПорций), + ФорматКоличества(Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций), + ФорматСекунд(ВремяВыполненияЗаданийБезПолученияПорций), + ФорматСекунд(МинимальноеВремяВыполненияЗаданийБезПолученияПорций), + ФорматСекунд(МаксимальноеВремяВыполненияЗаданийБезПолученияПорций)); + + Если ЗначениеЗаполнено(Показатели.ТекстОшибокПриПопыткахПовтора) Тогда + Комментарий = Комментарий + Символы.ПС + Символы.ПС + + НСтр("ru = 'Тексты ошибок при попытках повторного выполнения:'") + + Символы.ПС + Символы.ПС + Показатели.ТекстОшибокПриПопыткахПовтора; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ОбработатьРезультатЗадания, ЗарегистрироватьОшибкуОбновленияДоступа. +Процедура ДобавитьТекстОшибкиЗавершения(ТекстОшибкиЗавершения, ТекстОшибки) + + Если Не ЗначениеЗаполнено(ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстОшибкиЗавершения) Тогда + Если СтрНайти(ТекстОшибкиЗавершения, ТекстОшибки) > 0 Тогда + Возврат; + КонецЕсли; + ТекстОшибкиЗавершения = ТекстОшибкиЗавершения + Символы.ПС + Символы.ПС; + КонецЕсли; + + ТекстОшибкиЗавершения = ТекстОшибкиЗавершения + ТекстОшибки; + +КонецПроцедуры + +// Для процедур ОбновитьСвойстваФоновогоЗадания, ОтменитьФоновоеЗаданиеПотока, ОбработатьВыполненныеЗадания, +// УдалитьОстановленныеПотоки, ВыполнитьОбновлениеДоступаСпискаВФоне. +// +Функция ТекстОшибкиОбновленияСКонтекстом(ИнформацияОбОшибке, ОбщиеПараметрыОбновления, УстранимаяОшибка = Ложь) + + Если ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда + ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + Иначе + ПредставлениеОшибки = Строка(ИнформацияОбОшибке); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда + Возврат ""; + КонецЕсли; + + Если ОбщиеПараметрыОбновления = Неопределено Тогда + ТекстОшибки = ПредставлениеОшибки; + + ИначеЕсли Не ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав Тогда + + Если ОбщиеПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа к элементам данных списка + |""%1"" (для внешних пользователей) + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа к элементам данных списка + |""%1"" (для пользователей) + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + КонецЕсли; + + Иначе // ОбновлениеКлючейДоступаПользователей. + + Если ОбщиеПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа внешних пользователей списка + |""%1"" + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа пользователей списка + |""%1"" + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + КонецЕсли; + КонецЕсли; + + Если УстранимаяОшибка Тогда + ТекстОшибки = НСтр("ru = 'Возникла устранимая ошибка (обновление продолжается автоматически).'") + + Символы.ПС + ТекстОшибки; + КонецЕсли; + + Возврат ТекстОшибки; + +КонецФункции + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ЗавершитьФоновыеЗадания, +// ОбработатьРезультатВыполненногоЗадания, ОбновитьСвойстваФоновогоЗадания, +// ВыполнитьОбновлениеДоступаСпискаВФоне. +// +Процедура ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибки, Контекст) + + Если Контекст.Свойство("ОписаниеРодительскогоСеанса") Тогда + ОписаниеСеанса = Контекст.ОписаниеРодительскогоСеанса; // См. ОписаниеОсновногоСеанса + Иначе + ОписаниеСеанса = Контекст.ОписаниеОсновногоСеанса; // См. ОписаниеОсновногоСеанса + КонецЕсли; + + Данные = ОписаниеСеанса.Идентификатор; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Обновление доступа на уровне записей'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка, , Данные, ТекстОшибки); + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст) + + Показатели = Контекст.Показатели; + + Если Показатели <> Неопределено Тогда + Показатели.НачалоПервойПопыткиВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + ПопыткаВыполнения = 1; + ОшибкиПопытокВыполнения = Новый Массив; + Пока Истина Цикл + ТекстОшибкиТекущейПопытки = ""; + Если Показатели <> Неопределено Тогда + Показатели.ЗаданиеСПолучениемПорций = Не ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора"); + Показатели.НачалоВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + Попытка + ВыполнитьОбновлениеДоступаСписка(ОбщиеПараметрыОбновления); + Исключение + Если ТранзакцияАктивна() Тогда + ВызватьИсключение; + КонецЕсли; + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибкиТекущейПопытки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Если Показатели <> Неопределено И Не ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда + СнятьПоказателиВыполненияЗадания(Показатели); + КонецЕсли; + ТекстОшибкиТребуетсяПерезапуск = ""; + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(ТекстОшибкиТребуетсяПерезапуск) Тогда + ОбщиеПараметрыОбновления.Вставить("ТребуетсяПерезапускСеанса", ТекстОшибкиТребуетсяПерезапуск); + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + ТекстОшибкиТекущейПопытки = ""; + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда + ВремяОшибкиТекущейПопытки = Формат(ТекущаяДатаСеанса(), "ДЛФ=DT"); + ОшибкиПопытокВыполнения.Добавить(ВремяОшибкиТекущейПопытки + " " + ТекстОшибкиТекущейПопытки); + ПопыткаВыполнения = ПопыткаВыполнения + 1; + Если ПопыткаВыполнения < 9 И Не ЗначениеЗаполнено(ТекстОшибкиТребуетсяПерезапуск) Тогда + Для Счетчик = 1 По ПопыткаВыполнения Цикл + // @skip-check query-in-loop - Порционная обработка данных + Если ОбновлениеДоступаОтменено() Тогда + Прервать; + КонецЕсли; + Если Контекст.ТекущееФоновоеЗадание <> Неопределено Тогда + Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения(1); + Иначе + ГраницаОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + Пока ГраницаОжидания > ТекущаяУниверсальнаяДатаВМиллисекундах() Цикл + Продолжить; + КонецЦикла; + КонецЕсли; + КонецЦикла; + // @skip-check query-in-loop - Порционная обработка данных + Если Не ОбновлениеДоступаОтменено() Тогда + Продолжить; + КонецЕсли; + КонецЕсли; + КонецЕсли; + ТекстОшибки = СтрСоединить(ОшибкиПопытокВыполнения, Символы.ПС + "---" + Символы.ПС); + ТекстОшибки = ТекстОшибкиОбновленияСКонтекстом(ТекстОшибки, ОбщиеПараметрыОбновления); + + Если ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда + ОбщиеПараметрыОбновления.Вставить("ТекстОшибкиЗавершения", ""); + ДобавитьТекстОшибкиЗавершения(ОбщиеПараметрыОбновления.ТекстОшибкиЗавершения, ТекстОшибки); + КонецЕсли; + Если Показатели <> Неопределено Тогда + СнятьПоказателиОшибокВыполненияЗадания(Показатели, ТекстОшибки, ОшибкиПопытокВыполнения.Количество()); + КонецЕсли; + Прервать; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора. +Процедура ВыполнитьОбновлениеДоступаСписка(ОбщиеПараметрыОбновления) + + Если Не ОбщиеПараметрыОбновления.Свойство("Кэш") Тогда + ОбщиеПараметрыОбновления.Вставить("Кэш", Новый Структура); + КонецЕсли; + + Если ОбщиеПараметрыОбновления.ИдентификаторСписка = Неопределено Тогда + ОбъектМетаданных = Null; + ИначеЕсли ОбщиеПараметрыОбновления.Свойство("Кэш") + И ОбщиеПараметрыОбновления.Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда + + ОбъектМетаданных = ОбщиеПараметрыОбновления.Кэш.ОбъектыМетаданныхПоИдентификаторам.Получить( + ОбщиеПараметрыОбновления.ИдентификаторСписка); + Иначе + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору( + ОбщиеПараметрыОбновления.ИдентификаторСписка, Ложь); + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + // Если расширение конфигурации отключено, тогда обновление невозможно, + // но нельзя очищать регистрацию к обновлению. + ОбщиеПараметрыОбновления.Вставить("НетЗаданий", "ОбъектМетаданныхОтключен"); + Возврат; + КонецЕсли; + + ЭтоОбновлениеПрав = ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав; + + Если Не ОбщиеПараметрыОбновления.ДляВнешнихПользователей + И ОбщиеПараметрыОбновления.ИдентификаторСписка + = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка() Тогда + УдалитьОбъектыНедопустимыхТиповВРегистреКлючиДоступаКОбъектам(); + КонецЕсли; + + ПараметрыОбновления = ПараметрыОбновления(ОбщиеПараметрыОбновления, ОбъектМетаданных); + + // Обработка ранее подготовленной порции для обработки. + Если ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") Тогда + ПорцияИзНабора = ОбщиеПараметрыОбновления.ПорцияИзНабора; // См. ПорцияИзНабора + ЭлементыПорции = ПорцияИзНабора.Элементы.Получить(); + ПараметрыОбновления.Вставить("ПоследнийОбновленныйЭлемент", + ПорцияИзНабора.ПоследнийЭлементПорции); + + ОбновитьПорциюЭлементов(ЭлементыПорции, ПараметрыОбновления); + + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); + + Если ЭлементыПорции <> Неопределено Тогда + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + ВыбраныВсеЭлементы = ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; + ОбщиеПараметрыОбновления.Вставить("НаборПорций", НаборПорцийЭлементов( + ПараметрыОбновления, ЭлементыПорции, ВыбраныВсеЭлементы)); + КонецЕсли; + Возврат; + КонецЕсли; + + // Подготовка плана обработки элементов данных. + ПодготовкаЗавершена = Ложь; + ПараметрыОбновления.Вставить("ПерезапускОбновления", Ложь); + + Пока Не ПодготовкаЗавершена Цикл + ПодготовкаЗавершена = Истина; + ПараметрыОбновления.Вставить("ЕстьЗадания", Истина); + ПараметрыОбновления.Вставить("ТочечноеЗадание", Неопределено); + ПараметрыОбновления.Вставить("ПоследнийОбновленныйЭлемент", НачальныйЭлемент(ПараметрыОбновления)); + // @skip-check query-in-loop - Порционная обработка данных + ПодготовитьПланОбновления(ПараметрыОбновления, ПодготовкаЗавершена); + КонецЦикла; + + Если Не ПараметрыОбновления.ЕстьЗадания Тогда + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + Если Не ПараметрыОбновления.ЭтоОбновлениеПрав + И ПараметрыОбновления.БезОбновленияКлючейДоступаКОбъектам Тогда + + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Null; + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ТочечноеЗадание <> Неопределено Тогда + ВыбраныВсеЭлементы = Ложь; + Элементы = ЭлементыТочечногоЗаданияДляОбновления(ПараметрыОбновления, + КоличествоЭлементовВЗапросе(ЭтоОбновлениеПрав), ВыбраныВсеЭлементы); + + Если Элементы <> Неопределено Тогда + МаксимумМиллисекунд = МинимальноеКоличествоСекундВыполненияТочечногоЗадания() * 1000; + Если ПараметрыОбновления.ГраницаВремениОбработки - ТекущаяУниверсальнаяДатаВМиллисекундах() < МаксимумМиллисекунд Тогда + ПараметрыОбновления.ГраницаВремениОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах() + МаксимумМиллисекунд; + КонецЕсли; + ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления, Истина); + КонецЕсли; + Если Элементы <> Неопределено Или Не ВыбраныВсеЭлементы Тогда + ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении(ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + + УточнитьПоследнийОбновленныйЭлемент(ПараметрыОбновления); + + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Null; + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ТочечноеЗадание <> Неопределено Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Вставить("ОчиститьТочечноеЗадание"); + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Удалить("ОчиститьТочечноеЗадание"); + КонецЕсли; + + Если ПараметрыОбновления.ПерезапускОбновления Тогда + ОбщиеПараметрыОбновления.Вставить("ПерезапускОбновления"); + Если ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") Тогда + ОбщиеПараметрыОбновления.Удалить("НовыйПоследнийЭлементПорции"); + КонецЕсли; + КонецЕсли; + + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) + И Не ОбщиеПараметрыОбновления.РазрешенаОбработкаУстаревшихЭлементов Тогда + + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НачальноеОбновлениеЗавершено"); + Возврат; + КонецЕсли; + + Если ОбщиеПараметрыОбновления.ПолучитьПорции > 0 + И ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") Тогда + + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); + ЗаполнитьЗначенияСвойств(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + ОбщиеПараметрыОбновления.НовыйПоследнийЭлементПорции); + КонецЕсли; + + Если Не ЭтоОбновлениеПрав + И ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата) Тогда + + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + Возврат; + КонецЕсли; + + // Однопоточное обновление некоторых наборов групп доступа. + Если Не ЭтоОбновлениеПрав + И ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + И ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Неопределено Тогда + + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + УстранитьДублиНаборовИзОдногоПользователяВСправочнике(ПараметрыОбновления); + + ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + ЗаполнитьПустыеХешиНаборовГрупп(ПараметрыОбновления); + + ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + ОбновитьПраваНаРазрешенныйКлючДоступа(); + КонецЕсли; + ОчиститьПраваПустогоНабораГруппДоступа(ПараметрыОбновления); + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ОчиститьПраваНесуществующихНаборовГруппДоступа(ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + + // Запрос элементов для обработки. + ВыбраныВсеЭлементы = Ложь; + + Если ОбщиеПараметрыОбновления.ПолучитьПорции > 0 Тогда + КоличествоВПорции = КоличествоЭлементовВПорции(ПараметрыОбновления); + КоличествоВЗапросе = КоличествоВПорции * ОбщиеПараметрыОбновления.ПолучитьПорции; + Элементы = ЭлементыДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы); + + Если ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") + Или Элементы <> Неопределено + И Элементы.Количество() > КоличествоВПорции * 2 + Или КоличествоВЗапросе = Null Тогда + + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + ОбщиеПараметрыОбновления.Вставить("НаборПорций", НаборПорцийЭлементов( + ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы, КоличествоВПорции)); + Если КоличествоВЗапросе = Null Тогда + ОбщиеПараметрыОбновления.НаборПорций[0].Обработана = Истина; + КонецЕсли; + Возврат; + КонецЕсли; + Иначе + Возврат; + КонецЕсли; + + // Обработка элементов данных. + ПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + НачальныйЭлемент(ПараметрыОбновления, , Истина)); + + ОбщиеПараметрыОбновления.Вставить("НачальноеОбновлениеЗавершено"); + + Если Элементы <> Неопределено Тогда + ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления); + КонецЕсли; + + // Уточнение нового последнего элемента. + Если Элементы = Неопределено И ВыбраныВсеЭлементы Тогда + УстановитьПустойПоследнийЭлемент(ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент, + ПараметрыОбновления); + КонецЕсли; + + // Запись нового последнего элемента. + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); + + Если ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); + + // Подготовка оставшихся элементов к продолжению обновления. + Если Элементы <> Неопределено Тогда + ОбщиеПараметрыОбновления.Вставить("НаборПорций", + НаборПорцийЭлементов(ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы)); + КонецЕсли; + +КонецПроцедуры + +Функция ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + + Если ПараметрыОбновления.Свойство("Список") Тогда + Возврат ПараметрыОбновления.Список = "Справочник.НаборыГруппДоступа"; + КонецЕсли; + + Возврат ПараметрыОбновления.ИдентификаторСписка + = ПараметрыОбновления.ИдентификаторСправочникаНаборыГруппДоступа; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +// +// Возвращаемое значение: +// Структура: +// * ЭтоОбновлениеПрав - Булево +// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ДляВнешнихПользователей - Булево +// * Кэш - см. НовыйКэшКонтекста +// * ДатаНачала - Дата +// * ДатаОкончания - Дата +// * МаксимумПорцийИзИсходной - Число +// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// * ГраницаВремениОбработки - Дата +// +// Свойства, если ЭтоСправочникНаборыГруппДоступа. +// * СписокСДатой - Булево +// * СписокСПериодом - Булево +// * ЭтоСсылочныйТип - Булево +// * ПустойНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа +// +// Свойства, если не ЭтоСправочникНаборыГруппДоступа. +// * ИдентификаторТранзакции - УникальныйИдентификатор +// * ЗависимыеСпискиПоКлючамДоступа - Массив из Строка - полные имена списков +// +// Свойства добавляемые в процессе работы. +// * ЕстьИзмененияПрав - Булево +// * ОбновитьПраваНаКлючи - Булево +// * ПоследнийОбновленныйЭлемент - см. НачальныйЭлемент +// * НовыйПоследнийОбновленныйЭлемент - см. НачальныйЭлемент +// * ПерезапускОбновления - Булево +// * ЕстьЗадания - Булево +// * ТочечноеЗадание - см. ПодготовленноеТочечноеЗадание +// * НаборПорций - Массив из см. ПорцияИзНабора +// * ТипПользователя - Тип +// * ТипГруппыПользователей - Тип +// * ТипГруппыДоступа - Тип +// * ПустаяГруппаДоступа - СправочникСсылка.ГруппыДоступа +// * ПраваГруппДоступаСписка - см. НовыеПраваГруппДоступаСписка +// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей +// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа +// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа +// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа +// * ЗначенияГруппДоступа - см. НовыеЗначенияГруппДоступа +// * РолиПрофилейГруппДоступа - см. НовыеРолиПрофилейГруппДоступа +// * ГруппыДоступаПрофилей - см. НовыеГруппыДоступаПрофилей +// * ПраваНаСпискиВедущихКлючейДоступа - см. НовыеПраваНаСпискиВедущихКлючейДоступа +// * ПраваНаВедущиеКлючиДоступа - см. НовыеПраваНаВедущиеКлючиДоступа +// * ПраваНаВедущиеСписки - см. НовыеПраваНаВедущиеСписки +// * ПраваПоВладельцамНастроекПрав - см. НовыеПраваПоВладельцамНастроекПрав +// * МодельОбъектовВПамяти - см. МодельОбъектовВПамяти +// +// Копия свойств из ПараметрыОграниченияПоСтруктуреОграничения. +// * Список - Строка +// * ДляВнешнихПользователей - Булево +// * Версия - Строка +// * ВедущиеСписки - см. НовыеВедущиеСписки +// * ДоступЗапрещен - Булево +// * ОграничениеОтключено - Булево +// * ОграничениеЧтенияОтключено - Булево +// * ПолеВладельца - см. НовоеПолеВладельца +// * ТребуетсяОграничениеПоВладельцу - Булево +// * ИспользуетсяОграничениеПоВладельцу - Булево +// * РассчитыватьПраваПользователей - Булево +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа +// * ЧтениеРазрешеноДляВсехПользователей - Булево +// * ИзменениеРазрешеноДляВсехПользователей - Булево +// * ЕстьВедущиеКлючиДоступа - Булево +// * ЕстьВедущиеСпискиПоПравам - Булево +// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ИдентификаторТаблицыНастроекПрав - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// * ЕстьВладельцыНастроекПрав - Булево +// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип +// * ВсеВидыОграниченийПрав - Соответствие +// * ПоляТаблицОбъекта - Массив из см. НовыеПоляТаблицыОбъекта +// * ИмяОтдельногоРегистраКлючей - Строка +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ВариантДоступа - Число +// * СоставПолей - Число +// * ЕстьОграничениеЧтения - Булево +// * ЕстьОграничениеИзменения - Булево +// * ЕстьОграничениеПоПользователям - Булево +// * СтруктураРасчетаПраваЧтение - см. СтруктураРасчетаПрава +// * СтруктураРасчетаПраваИзменение - см. СтруктураРасчетаПрава +// * Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +// Свойства, добавляемые в процедуре ДобавитьТекстыЗапросовВПараметрыОграничения. +// * ТекстЗапросаПроверкиПравЧтениеИзменение - Строка +// * ТекстЗапросаПроверкиПраваЧтение - Строка +// * ПолеОбъектаВладельцаВЗапросеПроверкиПрав - Строка +// * ТекстЗапросаУстаревшихЭлементовДанных - Строка +// * ТекстЗапросаПроверкиУстаревшихЭлементовДанных - Строка +// * ТекстЗапросаНекорректныхЭлементовДанных - Строка +// * ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра - Строка +// * ТаблицыКлюча - Массив из Строка +// * РеквизитыТаблицКлюча - см. НовыеРеквизитыТаблицКлюча +// * ТекстЗапросаДиапазонаЭлементовДанных - Строка +// * ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами - Строка +// * ТекстЗапросаПроверкиКлючаДоступаОбъекта - Строка +// * ТекстЗапросаЭлементовДанныхБезКлючейДоступа - Строка +// * ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей - Строка +// * ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей - Строка +// * ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам - Соответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - Соответствие из КлючИЗначение: +// *** Ключ - Строка +// *** Значение - Соответствие +// - Структура: +// *** ТипСсылки - ХранилищеЗначения +// *** КлючиЗапросовПоТипам - Соответствие +// *** ТекстыЗапросовПоКлючам - Соответствие +// *** ТекстЗапросаПараметров - Строка +// - Строка +// * ТекстЗапросаТекущихКлючейДоступаРегистра - Строка +// * ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа - Строка +// * ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа - Строка +// * ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения - Строка +// * ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения - Строка +// * ТекстЗапросаСуществованияКлючейДляСравнения - Строка +// * ТекстЗапросаКлючейДоступаДляОбновленияПрав - Строка +// * ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав - Строка +// * ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав - Строка +// * ТекстЗапросаУстаревшихКлючейДоступа - Строка +// +Функция ПараметрыОбновления(ОбщиеПараметрыОбновления, ОбъектМетаданных) + + ПараметрыОбновления = Новый Структура("ЭтоОбновлениеПрав, + |ИдентификаторСписка, ДляВнешнихПользователей, Кэш, + |ДатаНачала, ДатаОкончания, МаксимумПорцийИзИсходной, + |ЭтоФоновоеОбновлениеДоступа, ИдентификаторСправочникаНаборыГруппДоступа"); + + ЗаполнитьЗначенияСвойств(ПараметрыОбновления, ОбщиеПараметрыОбновления); + + Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда + ПараметрыОбновления.Вставить("Список", ОбъектМетаданных.ПолноеИмя()); + КонецЕсли; + + ПараметрыОбновления.Вставить("ГраницаВремениОбработки", + ТекущаяУниверсальнаяДатаВМиллисекундах() + + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки); + + ДобавитьПараметрыОграничения(ПараметрыОбновления); + + Возврат ПараметрыОбновления; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Процедура ДобавитьПараметрыОграничения(ПараметрыОбновления) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + ПараметрыОбновления.Вставить("СписокСДатой", Ложь); + ПараметрыОбновления.Вставить("СписокСПериодом", Ложь); + ПараметрыОбновления.Вставить("ЭтоСсылочныйТип", Истина); + ПараметрыОбновления.Вставить("ПустойНаборГруппДоступа", Справочники.НаборыГруппДоступа.ПустаяСсылка()); + ПараметрыОбновления.Вставить("БезОбновленияКлючейДоступаКОбъектам", Ложь); + Возврат; + КонецЕсли; + + ИдентификаторТранзакции = Новый УникальныйИдентификатор; + Список = ?(ПараметрыОбновления.Свойство("Список"), ПараметрыОбновления.Список, ""); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(Список, ИдентификаторТранзакции); + ПараметрыОграничения = ПараметрыОграничения(Список, + ИдентификаторТранзакции, ПараметрыОбновления.ДляВнешнихПользователей); + + ПараметрыОграничения = Новый Структура(ПараметрыОграничения); + Для Каждого КлючИЗначение Из ПараметрыОбновления Цикл + ПараметрыОграничения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + ПараметрыОбновления = ПараметрыОграничения; + ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); + + ИмяСвойстваВидаПользователей = ?(ПараметрыОбновления.ДляВнешнихПользователей, + "ДляВнешнихПользователей", "ДляПользователей"); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей] = Неопределено Тогда + + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", Новый Массив); + Иначе + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", + СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей]); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ПодготовитьПланОбновления. +// +// Возвращаемое значение: +// Структура: +// * КлючДанных - ЛюбаяСсылка +// - Null +// - Структура +// * ОбработатьУстаревшиеЭлементы - Булево +// * ОбработатьНаборыГруппСУстаревшимиПравами - Булево +// * Дата - Дата +// +Функция НачальныйЭлемент(ПараметрыОбновления, ВидКлючаДанных = Неопределено, + СохранитьВидКлючаДанных = Ложь, ПерезапускОбновленияСНачала = Ложь) + + НачальныйЭлемент = Новый Структура; + НачальныйЭлемент.Вставить("КлючДанных"); + НачальныйЭлемент.Вставить("ОбработатьУстаревшиеЭлементы", Ложь); + НачальныйЭлемент.Вставить("ОбработатьНаборыГруппСУстаревшимиПравами", Ложь); + СохранитьСвойства = Ложь; + + Если ВидКлючаДанных = Неопределено Тогда + Если СохранитьВидКлючаДанных Тогда + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + СохранитьСвойства = Истина; + + ИначеЕсли ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя"; + + ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ВидКлючаДанных = "ЭлементыСУстаревшимиПравами"; + Иначе + ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами"; + КонецЕсли; + ИначеЕсли ВидКлючаДанных <> "НетДанных" + И ПараметрыОбновления.Свойство("ПоследнийОбновленныйЭлемент") Тогда + СохранитьСвойства = Истина; + КонецЕсли; + Если СохранитьСвойства Тогда + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы Тогда + НачальныйЭлемент.ОбработатьУстаревшиеЭлементы = Истина; + КонецЕсли; + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами Тогда + НачальныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + КонецЕсли; + УстановитьВидКлючаДанных(НачальныйЭлемент, ВидКлючаДанных); + + Если Не ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + НачальныйЭлемент.Вставить("Дата", ?(ПерезапускОбновленияСНачала, + МаксимальнаяДата(), МаксимальнаяДатаПриПродолжении())); + КонецЕсли; + + Возврат НачальныйЭлемент; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Процедура ПодготовитьПланОбновления(ПараметрыОбновления, ПодготовкаЗавершена) + + ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; + ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + ЭтоОбновлениеПрав = ПараметрыОбновления.ЭтоОбновлениеПрав; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Список", ИдентификаторСписка); + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); + + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | КлючиУникальности.КлючУникальности КАК КлючУникальности, + | КлючиУникальности.ПараметрыЗадания КАК ПараметрыЗадания, + | КлючиУникальности.ДатаПоследнегоОбновленногоЭлемента КАК ДатаПоследнегоОбновленногоЭлемента + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК КлючиУникальности + |ГДЕ + | КлючиУникальности.Список = &Список + | И КлючиУникальности.ДляВнешнихПользователей = &ДляВнешнихПользователей + | + |УПОРЯДОЧИТЬ ПО + | КлючиУникальности.Список, + | КлючиУникальности.ДляВнешнихПользователей, + | КлючиУникальности.КлючУникальности"; + + Если ЭтоОбновлениеПрав Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "РегистрСведений.ОбновлениеКлючейДоступаКДанным", + "РегистрСведений.ОбновлениеКлючейДоступаПользователей"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, ", + | КлючиУникальности.ДатаПоследнегоОбновленногоЭлемента КАК ДатаПоследнегоОбновленногоЭлемента", + ""); // @query-part-1 + КонецЕсли; + + РезультатЗапроса = Запрос.Выполнить(); + + Если РезультатЗапроса.Пустой() Тогда + ПараметрыОбновления.ЕстьЗадания = Ложь; + Возврат; + КонецЕсли; + + Выгрузка = РезультатЗапроса.Выгрузить(); + + Если Выгрузка.Количество() = 1000 Тогда + ПодготовкаЗавершена = Ложь; + КонецЕсли; + + Если ЭтоОбновлениеПрав Тогда + ПланОбновления = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаПользователей); + Иначе + ПланОбновления = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + КонецЕсли; + ПланОбновления.Отбор.Список.Установить(ИдентификаторСписка); + ПланОбновления.Отбор.ДляВнешнихПользователей.Установить(ДляВнешнихПользователей); + + Если ПараметрыОбновления.Список = СписокДляПланированияОбновленияКэшаРасчетаПрав() Тогда + ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка); + ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка); + ПараметрыОбновления.ЕстьЗадания = Ложь; + Возврат; + КонецЕсли; + + ПерезапускОбновления = Ложь; + ПерезапускОбновленияСНачала = Ложь; + СохраняемыеПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ПараметрыОбновления); + + Если Не ЗначениеЗаполнено(Выгрузка[0].КлючУникальности) Тогда + ТекущийИтог = Выгрузка[0]; + ПараметрыЗадания = ТекущийИтог.ПараметрыЗадания.Получить(); + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") Тогда + СохраняемыеПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, + ПараметрыОбновления, ПараметрыЗадания, ПерезапускОбновления); + Иначе + ПерезапускОбновления = Истина; + КонецЕсли; + Если Не ПерезапускОбновления И Не ЭтоОбновлениеПрав Тогда + СохраненнаяДата = ТекущийИтог.ДатаПоследнегоОбновленногоЭлемента; + Если ТипЗнч(СохраненнаяДата) = Тип("Дата") Тогда + СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент.Дата = СохраненнаяДата; + Иначе + ПерезапускОбновления = Истина; + КонецЕсли; + КонецЕсли; + Выгрузка.Удалить(0); + Если Не ПерезапускОбновления Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = + СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент; + КонецЕсли; + КонецЕсли; + + Если Не ПерезапускОбновления + И ТекущийИтог <> Неопределено + И Выгрузка.Количество() = 0 Тогда + + ПараметрыОбновления.ТочечноеЗадание = ПодготовленноеТочечноеЗадание( + ЭтоОбновлениеПрав, СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); + Если Не ПерезапускОбновления Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + ПустойИдентификатор = ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор(); + ПолноеИмяРегистра = ?(ЭтоОбновлениеПрав, "РегистрСведений.ОбновлениеКлючейДоступаПользователей", + "РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); + ЭлементБлокировки.УстановитьЗначение("КлючУникальности", ПустойИдентификатор); + + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); + ЭлементБлокировки.ИсточникДанных = Выгрузка; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючУникальности", "КлючУникальности"); + + МаксимальнаяДата = МаксимальнаяДата(); + СвойстваКлючаДанных = НачальныйЭлемент(ПараметрыОбновления, "НетДанных"); + ВидКлючаДанныхУстановлен = Истина; + Для Каждого Строка Из Выгрузка Цикл + ПараметрыЗадания = Строка.ПараметрыЗадания.Получить(); + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") И ПараметрыЗадания.Свойство("ТочечноеЗадание") Тогда + ДобавитьВедущийОбъектКТочечномуЗаданию(ПараметрыЗадания.ТочечноеЗадание, + СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); + Иначе + ПерезапускОбновления = Истина; + Если Не ЭтоОбновлениеПрав И Строка.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата Тогда + ПерезапускОбновленияСНачала = Истина; + КонецЕсли; + Если ЕстьСвойстваКлючаДанных(ПараметрыЗадания) Тогда + Если СвойстваКлючаДанных.ПорядокВидаКлючаДанных > ПараметрыЗадания.ПорядокВидаКлючаДанных Тогда + СвойстваКлючаДанных.ПорядокВидаКлючаДанных = ПараметрыЗадания.ПорядокВидаКлючаДанных; + СвойстваКлючаДанных.ВидКлючаДанных = ПараметрыЗадания.ВидКлючаДанных; + КонецЕсли; + Если ЭтоОбработкаУстаревшихЭлементов(Новый Структура("ПоследнийОбновленныйЭлемент", ПараметрыЗадания)) Тогда + СвойстваКлючаДанных.ОбработатьУстаревшиеЭлементы = Истина; + КонецЕсли; + Если ПараметрыЗадания.Свойство("ОбработатьНаборыГруппСУстаревшимиПравами") + И ПараметрыЗадания.ОбработатьНаборыГруппСУстаревшимиПравами = Истина Тогда + СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + Иначе + ВидКлючаДанныхУстановлен = Ложь; + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + Если ЭтоОбновлениеПрав Или ПерезапускОбновленияСНачала Тогда + Прервать; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + ПараметрыОбновления.ТочечноеЗадание = ПодготовленноеТочечноеЗадание( + ЭтоОбновлениеПрав, СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); + + Если ПерезапускОбновления Тогда + ПараметрыОбновления.ПерезапускОбновления = Истина; + Если ПерезапускОбновленияСНачала Тогда + ПараметрыОбновления.Вставить("ПерезапускОбновленияСНачала"); + КонецЕсли; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = + НачальныйЭлемент(ПараметрыОбновления, , , ПерезапускОбновленияСНачала); + КонецЕсли; + + ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; + Если ВидКлючаДанныхУстановлен Тогда + Если ТекущийИтог = Неопределено Тогда + УстановитьВидКлючаДанных(ПоследнийОбновленныйЭлемент, СвойстваКлючаДанных.ВидКлючаДанных); + + ИначеЕсли ПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных > СвойстваКлючаДанных.ПорядокВидаКлючаДанных Тогда + ПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных = СвойстваКлючаДанных.ПорядокВидаКлючаДанных; + ПоследнийОбновленныйЭлемент.ВидКлючаДанных = СвойстваКлючаДанных.ВидКлючаДанных; + КонецЕсли; + КонецЕсли; + Если СвойстваКлючаДанных.ОбработатьУстаревшиеЭлементы Тогда + ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы = Истина; + КонецЕсли; + Если СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами Тогда + ПоследнийОбновленныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент = ПоследнийОбновленныйЭлемент; + + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда + РазмерЗадания = 1; + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(Новый Структура("ПоследнийОбновленныйЭлемент", + ПоследнийОбновленныйЭлемент)) Тогда + РазмерЗадания = 2; + Иначе + РазмерЗадания = 3; + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "ВЫБРАТЬ ПЕРВЫЕ 1000", "ВЫБРАТЬ ПЕРВЫЕ 1"); // @query-part-1, @query-part-2 + ЗаданияУдалены = Ложь; + + ПланОбновления.Отбор.КлючУникальности.Установить(ПустойИдентификатор); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + РезультатЗапроса = Запрос.Выполнить(); + Если РезультатЗапроса.Пустой() Тогда + ЗаданияУдалены = Истина; + Иначе + Запись = ПланОбновления.Добавить(); + Запись.Список = ИдентификаторСписка; + Запись.ДляВнешнихПользователей = ДляВнешнихПользователей; + Запись.ТочечноеЗадание = ПараметрыОбновления.ТочечноеЗадание <> Неопределено; + Запись.ПараметрыЗадания = Новый ХранилищеЗначения(СохраняемыеПараметрыЗадания); + Запись.РазмерЗадания = РазмерЗадания; + Если Не ЭтоОбновлениеПрав Тогда + Запись.ДатаПоследнегоОбновленногоЭлемента = + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата; + КонецЕсли; + Запись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + ПланОбновления.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЗаданияУдалены Тогда + ПараметрыОбновления.ЕстьЗадания = Ложь; + ПараметрыОбновления.ТочечноеЗадание = Неопределено; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); + Возврат; + КонецЕсли; + + ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка) + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Процедура ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка) + + Если Не ЗначениеЗаполнено(Выгрузка) Тогда + Возврат; + КонецЕсли; + + ПланОбновления.Очистить(); + + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено; + + Если ПакетныйРежим Тогда + Выгрузка.Колонки.Добавить("Список"); + Выгрузка.Колонки.Добавить("ДляВнешнихПользователей"); + Выгрузка.ЗаполнитьЗначения(ПланОбновления.Отбор.Список.Значение, "Список"); + Выгрузка.ЗаполнитьЗначения(ПланОбновления.Отбор.ДляВнешнихПользователей.Значение, "ДляВнешнихПользователей"); + ПланОбновления.Загрузить(Выгрузка); + ПланОбновления.Отбор.Список.Использование = Ложь; + ПланОбновления.Отбор.ДляВнешнихПользователей.Использование = Ложь; + ПланОбновления.Отбор.КлючУникальности.Использование = Ложь; + ПланОбновления.Записать(РежимУдаления); + Иначе + Для Каждого Строка Из Выгрузка Цикл + ПланОбновления.Отбор.КлючУникальности.Установить(Строка.КлючУникальности); + ПланОбновления.Записать(); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Процедура ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка, НоваяВерсияДанныхДляКэша = Неопределено) + + ВерсияДанныхДляКэша = НоваяВерсияДанныхДляКэшаРасчетаПрав(); + + Для Каждого Строка Из Выгрузка Цикл + ПараметрыЗадания = Строка.ПараметрыЗадания.Получить(); + Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") + Или Не ПараметрыЗадания.Свойство("ТочечноеЗадание") + Или ТипЗнч(ПараметрыЗадания.ТочечноеЗадание) <> Тип("Структура") + Или Не ПараметрыЗадания.ТочечноеЗадание.Свойство("ПоДаннымКэшаРасчетаПрав") Тогда + Продолжить; + КонецЕсли; + ИмяИзмененныхДанных = ПараметрыЗадания.ТочечноеЗадание.ПоДаннымКэшаРасчетаПрав; + ОбработатьЗаданиеОбновленияКэшаРасчетаПрав(ВерсияДанныхДляКэша, + ИмяИзмененныхДанных, Строка.КлючУникальности); + КонецЦикла; + + ИмяПараметра = ИмяПараметраВерсииДанныхДляКэшаРасчетаПрав(); + + Если НоваяВерсияДанныхДляКэша = Неопределено Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ТекущееЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + НовоеЗначение = НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша); + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + Иначе + ТекущееЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + НоваяВерсияДанныхДляКэша = НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша, Ложь); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. +Процедура ОбработатьЗаданиеОбновленияКэшаРасчетаПрав(ВерсияДанныхДляКэша, ИмяИзмененныхДанных, КлючУникальности) + + Если ТипЗнч(ИмяИзмененныхДанных) <> Тип("Строка") + Или Не ВерсияДанныхДляКэша.Свойство(ИмяИзмененныхДанных) Тогда + + Для Каждого КлючИЗначение Из ВерсияДанныхДляКэша Цикл + ВерсияДанныхДляКэша[КлючИЗначение.Ключ] = Строка(Новый УникальныйИдентификатор); + КонецЦикла; + Возврат; + КонецЕсли; + + Если ТипЗнч(ВерсияДанныхДляКэша[ИмяИзмененныхДанных]) = Тип("Строка") Тогда + Возврат; + КонецЕсли; + + Если ВерсияДанныхДляКэша[ИмяИзмененныхДанных] = Неопределено Тогда + ВерсияДанныхДляКэша[ИмяИзмененныхДанных] = Новый ХешированиеДанных(ХешФункция.SHA256); + КонецЕсли; + + ХешированиеДанных = ВерсияДанныхДляКэша[ИмяИзмененныхДанных]; // ХешированиеДанных + ХешированиеДанных.Добавить(Строка(КлючУникальности)); + +КонецПроцедуры + +// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. +Функция НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша, ДляЗаписи = Истина) + + НовоеЗначение = НоваяВерсияДанныхДляКэшаРасчетаПрав(); + + Если ТипЗнч(ТекущееЗначение) = Тип("Структура") Тогда + ЗаполнитьЗначенияСвойств(НовоеЗначение, ТекущееЗначение); + КонецЕсли; + + Для Каждого КлючИЗначение Из ВерсияДанныхДляКэша Цикл + Если КлючИЗначение.Значение = Неопределено Тогда + Продолжить; + КонецЕсли; + Если ТипЗнч(КлючИЗначение.Значение) = Тип("ХешированиеДанных") Тогда + НовоеЗначение[КлючИЗначение.Ключ] = Base64Строка(КлючИЗначение.Значение.ХешСумма); + Иначе + НовоеЗначение[КлючИЗначение.Ключ] = КлючИЗначение.Значение; + КонецЕсли; + КонецЦикла; + + Для Каждого КлючИЗначение Из НовоеЗначение Цикл + Если КлючИЗначение.Значение <> Неопределено Тогда + Продолжить; + КонецЕсли; + НовоеЗначение[КлючИЗначение.Ключ] = ?(ДляЗаписи, + Строка(Новый УникальныйИдентификатор), "00000000-0000-0000-0000-000000000000"); + КонецЦикла; + + Возврат НовоеЗначение; + +КонецФункции + +// Для функции КэшРасчетаПравДляВидаПользователей. +Функция ВерсияДанныхДляКэшаРасчетаПрав() + + ИдентификаторСпискаПланирования = ОбщегоНазначения.ИдентификаторОбъектаМетаданных( + СписокДляПланированияОбновленияКэшаРасчетаПрав()); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Список", ИдентификаторСпискаПланирования); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | КлючиУникальности.КлючУникальности КАК КлючУникальности, + | КлючиУникальности.ПараметрыЗадания КАК ПараметрыЗадания + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК КлючиУникальности + |ГДЕ + | КлючиУникальности.Список = &Список + | И КлючиУникальности.ДляВнешнихПользователей = ЛОЖЬ + | + |УПОРЯДОЧИТЬ ПО + | КлючиУникальности.Список, + | КлючиУникальности.ДляВнешнихПользователей, + | КлючиУникальности.КлючУникальности"; + + Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + + Выгрузка = Запрос.Выполнить().Выгрузить(); + + ВерсияДанныхДляКэша = Новый Структура; + ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка, ВерсияДанныхДляКэша); + + Возврат ВерсияДанныхДляКэша; + +КонецФункции + +// Для процедуры ПодготовитьПланОбновления, ЗаписатьПоследнийОбновленныйЭлемент. +// +// Возвращаемое значение: +// Структура: +// * ПоследнийОбновленныйЭлемент - см. НачальныйЭлемент +// * ТочечноеЗадание - Структура: +// ** ПоКлючамДоступа - Соответствие +// ** ПоЗначениямПолей - Соответствие +// ** ПоЗначениямСГруппами - Соответствие +// +Функция СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ПараметрыОбновления, ПараметрыЗадания = Неопределено, + ПерезапускОбновления = Ложь, ОчиститьТочечноеЗадание = Ложь) + + ТочечноеЗадание = Новый Структура; + ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый Соответствие); + Если Не ЭтоОбновлениеПрав Тогда + ТочечноеЗадание.Вставить("ПоЗначениямПолей", Новый Соответствие); + ТочечноеЗадание.Вставить("ПоЗначениямСГруппами", Новый Соответствие); + КонецЕсли; + + СохраняемыеПараметры = Новый Структура; + СохраняемыеПараметры.Вставить("ТочечноеЗадание", ТочечноеЗадание); + СохраняемыеПараметры.Вставить("ПоследнийОбновленныйЭлемент", НачальныйЭлемент(ПараметрыОбновления)); + + Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") Тогда + Возврат СохраняемыеПараметры; + КонецЕсли; + + Если ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") Тогда + Порядок = ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных); + Если Порядок <> Неопределено Тогда + ЗаполнитьЗначенияСвойств(СохраняемыеПараметры.ПоследнийОбновленныйЭлемент, + ПараметрыЗадания.ПоследнийОбновленныйЭлемент); + КонецЕсли; + КонецЕсли; + + Если ОчиститьТочечноеЗадание Или Не ПараметрыЗадания.Свойство("ТочечноеЗадание") Тогда + Возврат СохраняемыеПараметры; + КонецЕсли; + + ТекущееТочечноеЗадание = ПараметрыЗадания.ТочечноеЗадание; + Если ТипЗнч(ТекущееТочечноеЗадание) <> Тип("Структура") Тогда + ПерезапускОбновления = Истина; + Возврат СохраняемыеПараметры; + КонецЕсли; + + Для Каждого ВариантЗадания Из ТочечноеЗадание Цикл + Если Не ТекущееТочечноеЗадание.Свойство(ВариантЗадания.Ключ) + Или ТипЗнч(ТекущееТочечноеЗадание[ВариантЗадания.Ключ]) <> Тип("Соответствие") Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + ТочечноеЗадание[ВариантЗадания.Ключ] = ТекущееТочечноеЗадание[ВариантЗадания.Ключ]; + КонецЦикла; + + Возврат СохраняемыеПараметры; + +КонецФункции + +// Для процедуры ПодготовитьПланОбновления. +Процедура ДобавитьВедущийОбъектКТочечномуЗаданию(ТочечноеЗадание, СохраняемоеТочечноеЗадание, + ПерезапускОбновления) + + Если ТипЗнч(ТочечноеЗадание) <> Тип("Структура") Тогда + ПерезапускОбновления = Истина; + Возврат; + КонецЕсли; + МаксимальноеКоличество = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); + + Для Каждого ВариантЗадания Из ТочечноеЗадание Цикл + Если Не СохраняемоеТочечноеЗадание.Свойство(ВариантЗадания.Ключ) Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + Если ВариантЗадания.Ключ <> "ПоЗначениямПолей" Тогда + Ссылки = ?(ТипЗнч(ВариантЗадания.Значение) = Тип("Массив"), ВариантЗадания.Значение, + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ВариантЗадания.Значение)); + СохраняемыеСсылки = СохраняемоеТочечноеЗадание[ВариантЗадания.Ключ]; + Для Каждого Ссылка Из Ссылки Цикл + СохраняемыеСсылки.Вставить(Ссылка, Истина); + Если СохраняемыеСсылки.Количество() >= МаксимальноеКоличество Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + КонецЦикла; + Иначе + Свойства = ВариантЗадания.Значение; + СохраняемыеТаблицы = СохраняемоеТочечноеЗадание[ВариантЗадания.Ключ]; + + Если Не Свойства.Свойство("ИзмененнаяТаблица") + Или Не Свойства.Свойство("СоставИзменений") + Или ТипЗнч(Свойства.СоставИзменений) <> Тип("ТаблицаЗначений") + Или ТипЗнч(СохраняемыеТаблицы) <> Тип("Соответствие") Тогда + + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + СохраняемаяТаблица = СохраняемыеТаблицы.Получить(Свойства.ИзмененнаяТаблица); + СоставИзменений = Свойства.СоставИзменений; + Если СохраняемаяТаблица = Неопределено Тогда + СохраняемыеТаблицы.Вставить(Свойства.ИзмененнаяТаблица, СоставИзменений); + + ИначеЕсли ТипЗнч(СохраняемаяТаблица) <> Тип("ТаблицаЗначений") + Или СоставИзменений.Колонки.Количество() <> СохраняемаяТаблица.Колонки.Количество() Тогда + + ПерезапускОбновления = Истина; + Продолжить; + Иначе + ИменаКолонок = Новый Массив; + Для Каждого Колонка Из СохраняемаяТаблица.Колонки Цикл + Если СоставИзменений.Колонки.Найти(Колонка.Имя) = Неопределено Тогда + ИменаКолонок = Неопределено; + Прервать; + КонецЕсли; + ИменаКолонок.Добавить(Колонка.Имя); + КонецЦикла; + Если ИменаКолонок = Неопределено Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + СписокИменКолонок = СтрСоединить(ИменаКолонок, ","); + Отбор = Новый Структура(СписокИменКолонок); + Если СохраняемаяТаблица.Индексы.Количество() = 0 Тогда + СохраняемаяТаблица.Индексы.Добавить(СписокИменКолонок); + КонецЕсли; + Для Каждого Строка Из СоставИзменений Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Если СохраняемаяТаблица.НайтиСтроки(Отбор).Количество() = 0 Тогда + Если СохраняемаяТаблица.Количество() >= МаксимальноеКоличество Тогда + ПерезапускОбновления = Истина; + Прервать; + КонецЕсли; + ЗаполнитьЗначенияСвойств(СохраняемаяТаблица.Добавить(), Строка); + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Функция ЕстьСвойстваКлючаДанных(ПараметрыЗадания) + + Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") + Или Не ПараметрыЗадания.Свойство("ВидКлючаДанных") + Или Не ПараметрыЗадания.Свойство("ПорядокВидаКлючаДанных") Тогда + Возврат Ложь; + КонецЕсли; + + Порядок = ПорядокВидаКлючаДанных(ПараметрыЗадания.ВидКлючаДанных); + + Возврат Порядок <> Неопределено И Порядок = ПараметрыЗадания.ПорядокВидаКлючаДанных; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ОбновитьПорциюЭлементов, +// УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных, ОбновитьНаборыГруппДоступа и +// функций ЭлементыДляОбновления, ПоследнийЭлемент, КлючДанных, НаборыГруппДоступаДляОбновления. +// +Функция ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) + + Порядок = ПорядокВидаКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных); + + Возврат Порядок >= ПорядокВидаКлючаДанных("УстаревшиеЭлементы") + И Порядок < ПорядокВидаКлючаДанных("НетДанных"); + +КонецФункции + +// Для функций СохраняемыеПараметрыЗадания, ЕстьСвойстваКлючаДанных и +// процедур ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов, УстановитьВидКлючаДанных. +// +Функция ПорядокВидаКлючаДанных(ВидКлючаДанных) + + ВидыКлючейДанных = Новый Соответствие; + ВидыКлючейДанных.Вставить("ЭлементыСУстаревшимиКлючами", 0); + ВидыКлючейДанных.Вставить("ЭлементыБезКлючейПоЗначениямПолей", 1); + ВидыКлючейДанных.Вставить("ЭлементыБезКлючейПоПериоду", 1); + + ВидыКлючейДанных.Вставить("ЭлементыСУстаревшимиПравами", 0); + + ВидыКлючейДанных.Вставить("НовыеНаборыИзОдногоПользователя", 0); + ВидыКлючейДанных.Вставить("НаборыГруппДоступаНазначенныеПользователям", 1); + ВидыКлючейДанных.Вставить("НаборыГруппПользователейНазначенныеПользователям", 2); + ВидыКлючейДанных.Вставить("НовыеНаборыГруппСУстаревшимиПравами", 3); + ВидыКлючейДанных.Вставить("НаборыГруппРазрешенныеПользователям", 4); + ВидыКлючейДанных.Вставить("НаборыГруппСУстаревшимиПравами", 5); + + ВидыКлючейДанных.Вставить("УстаревшиеЭлементы", 10); + ВидыКлючейДанных.Вставить("НекорректныеЭлементы", 11); + ВидыКлючейДанных.Вставить("НекорректныеЭлементыОбщегоРегистра", 12); + + ВидыКлючейДанных.Вставить("НетДанных", 99); + + Возврат ВидыКлючейДанных.Получить(ВидКлючаДанных); + +КонецФункции + +// Для процедур ЗапланироватьОбновлениеДоступа, ЗапланироватьОбновлениеНаборовГруппДоступа, +// УточнитьПустойПоследнийЭлемент и функции НачальныйЭлемент. +// +Процедура УстановитьВидКлючаДанных(Элемент, ВидКлючаДанных) + + Порядок = ПорядокВидаКлючаДанных(ВидКлючаДанных); + Если Порядок = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректный имя вида порядка ключа данных ""%1""'"), ВидКлючаДанных); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Элемент.Вставить("ВидКлючаДанных", ВидКлючаДанных); + Элемент.Вставить("ПорядокВидаКлючаДанных", Порядок); + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Функция ПодготовленноеТочечноеЗадание(ЭтоОбновлениеПрав, СохраняемоеТочечноеЗадание, ПерезапускОбновления) + + ТочечноеЗадание = Новый Структура; + Если ЭтоОбновлениеПрав Тогда + ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый Массив); + Иначе + ТочечноеЗадание.Вставить("ПоЗначениямПолей", Новый Соответствие); + ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый ТаблицаЗначений); + ТочечноеЗадание.Вставить("ПоЗначениямСГруппами", Новый ТаблицаЗначений); + КонецЕсли; + + ЭтоПустоеЗадание = Истина; + МаксимальноеКоличество = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); + ТипыВедущихОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТиповСсылокВедущихОбъектов(); + + Для Каждого ВариантЗадания Из СохраняемоеТочечноеЗадание Цикл + Если ВариантЗадания.Ключ = "ПоЗначениямПолей" Тогда + Если ЗначениеЗаполнено(ВариантЗадания.Значение) Тогда + ЭтоПустоеЗадание = Ложь; + ТочечноеЗадание.ПоЗначениямПолей = ВариантЗадания.Значение; + КонецЕсли; + Продолжить; + КонецЕсли; + + УдаляемыеСсылки = Новый Массив; + ОписаниеСсылок = ВариантЗадания.Значение; + Если ЭтоОбновлениеПрав Тогда + Ссылки = ТочечноеЗадание[ВариантЗадания.Ключ]; + Иначе + Ссылки = Новый Массив; + Типы = Новый Соответствие; + Таблица = ТочечноеЗадание[ВариантЗадания.Ключ]; // ТаблицаЗначений + КонецЕсли; + Для Каждого ОписаниеСсылки Из ОписаниеСсылок Цикл + Ссылка = ОписаниеСсылки.Ключ; + Тип = ТипЗнч(Ссылка); + Если ТипыВедущихОбъектов.Получить(Тип) = Неопределено Тогда + ПерезапускОбновления = Истина; + УдаляемыеСсылки.Добавить(Ссылка); + Продолжить; + КонецЕсли; + Ссылки.Добавить(Ссылка); + Если Не ЭтоОбновлениеПрав Тогда + Типы.Вставить(Тип, Истина); + Таблица.Добавить(); + КонецЕсли; + Если Ссылки.Количество() >= МаксимальноеКоличество Тогда + ПерезапускОбновления = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Ссылка Из УдаляемыеСсылки Цикл + ОписаниеСсылок.Удалить(Ссылка); + КонецЦикла; + Если Ссылки.Количество() > 0 Тогда + ЭтоПустоеЗадание = Ложь; + Иначе + Продолжить; + КонецЕсли; + Если Не ЭтоОбновлениеПрав Тогда + ТипыКолонки = Новый Массив; + Для Каждого КлючИЗначение Из Типы Цикл + ТипыКолонки.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + Таблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов(ТипыКолонки)); + Таблица.ЗагрузитьКолонку(Ссылки, "Ссылка"); + КонецЕсли; + КонецЦикла; + + Если ЭтоПустоеЗадание Тогда + Возврат Неопределено; + КонецЕсли; + + Возврат ТочечноеЗадание; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Функция КоличествоЭлементовВПорции(ПараметрыОбновления) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + Возврат 25; + ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Возврат КоличествоКлючейДоступаВПорции(); + Иначе + Возврат КоличествоЭлементовДанныхВПорции(); + КонецЕсли; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Функция КоличествоЭлементовВЗапросе(ЭтоОбновлениеПрав) + + Если ЭтоОбновлениеПрав Тогда + Возврат КоличествоКлючейДоступаВЗапросе(); + Иначе + Возврат КоличествоЭлементовДанныхВЗапросе(); + КонецЕсли; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления, ЭтоТочечноеЗадание = Ложь) + + ПараметрыОбновления.Вставить("КоличествоОбработанныхЭлементов", 0); + + Если ЭтоТочечноеЗадание Тогда + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ОбновитьПраваПорцииКлючейДоступаСписка(Элементы, ПараметрыОбновления); + Иначе + ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(Элементы, ПараметрыОбновления); + КонецЕсли; + + ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ОбработатьУстаревшиеКлючиДоступаСписка(Элементы, ПараметрыОбновления); + Иначе + ОбновитьПраваПорцииКлючейДоступаСписка(Элементы, ПараметрыОбновления); + КонецЕсли; + + ИначеЕсли ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + ОбновитьНаборыГруппДоступа(Элементы, ПараметрыОбновления); + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + УдалитьУстаревшиеЭлементыДанныхСписка(Элементы, ПараметрыОбновления); + Иначе + ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(Элементы, ПараметрыОбновления); + КонецЕсли; + + Если Не ЭтоТочечноеЗадание И Элементы.Количество() > 0 Тогда + ПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПоследнийЭлемент(Элементы, ПараметрыОбновления, Истина)); + КонецЕсли; + + Если Элементы.Количество() = ПараметрыОбновления.КоличествоОбработанныхЭлементов Тогда + Элементы = Неопределено; + Иначе + Для Счетчик = 1 По ПараметрыОбновления.КоличествоОбработанныхЭлементов Цикл + Элементы.Удалить(0); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьНаборыГруппДоступа, УдалитьУстаревшиеЭлементыДанныхСписка, +// ЗаписатьКлючиДоступаОбъектов, ЗаписатьКлючиДоступаРегистров, +// ОбновитьПраваПорцииКлючейДоступаСписка, УдалитьПорциюКлючейДоступаСписка, +// УдалитьТекущуюПорциюКлючейДоступаСписка. +// +Функция ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанныхНаШаге = 1) + + Если Не ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") + Или Не ПараметрыОбновления.Свойство("ГраницаВремениОбработки") Тогда + Возврат Ложь; + КонецЕсли; + + ПараметрыОбновления.КоличествоОбработанныхЭлементов = + ПараметрыОбновления.КоличествоОбработанныхЭлементов + КоличествоОбработанныхНаШаге; + + Если ТекущаяУниверсальнаяДатаВМиллисекундах() > ПараметрыОбновления.ГраницаВремениОбработки Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ПроверитьЗавершитьОбновлениеПоПорциям. +Процедура ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, ПоследнийОбновленныйЭлемент) + + ЭтоОбновлениеПрав = ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав; + ДляВнешнихПользователей = ОбщиеПараметрыОбновления.ДляВнешнихПользователей; + ИдентификаторСписка = ОбщиеПараметрыОбновления.ИдентификаторСписка; + + МенеджерРегистра = ?(ЭтоОбновлениеПрав, РегистрыСведений.ОбновлениеКлючейДоступаПользователей, + РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + + ПланОбновления = СлужебныйНаборЗаписей(МенеджерРегистра); + ПланОбновления.Отбор.Список.Установить(ИдентификаторСписка); + ПланОбновления.Отбор.ДляВнешнихПользователей.Установить(ДляВнешнихПользователей); + ПланОбновления.Отбор.КлючУникальности.Установить( + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ПолноеИмяРегистра = ?(ЭтоОбновлениеПрав, "РегистрСведений.ОбновлениеКлючейДоступаПользователей", + "РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); + ЭлементБлокировки.УстановитьЗначение("КлючУникальности", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПланОбновления.Прочитать(); + Если ПланОбновления.Количество() > 0 Тогда + Если ПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда + ПланОбновления.Очистить(); + Иначе + Запись = ПланОбновления[0]; + Если ПоследнийОбновленныйЭлемент.Свойство("ОчиститьТочечноеЗадание") Тогда + Запись.ТочечноеЗадание = Ложь; + КонецЕсли; + + ТекущиеПараметрыЗадания = Запись.ПараметрыЗадания.Получить(); + ПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ОбщиеПараметрыОбновления, + ТекущиеПараметрыЗадания, , ПоследнийОбновленныйЭлемент.Свойство("ОчиститьТочечноеЗадание")); + + ЗаполнитьЗначенияСвойств(ПараметрыЗадания.ПоследнийОбновленныйЭлемент, ПоследнийОбновленныйЭлемент); + + Если Не ЭтоОбновлениеПрав И ПоследнийОбновленныйЭлемент.Свойство("Дата") Тогда + Запись.ДатаПоследнегоОбновленногоЭлемента = ПоследнийОбновленныйЭлемент.Дата; + КонецЕсли; + + Запись.ПараметрыЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); + Запись.РазмерЗадания = ?(ЭтоОбработкаУстаревшихЭлементов( + Новый Структура("ПоследнийОбновленныйЭлемент", ПоследнийОбновленныйЭлемент)), 2, 3); + + Запись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + КонецЕсли; + ПланОбновления.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Функция ЭлементыДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ВыбраныВсеЭлементы = Истина; + Возврат Неопределено; + КонецЕсли; + Элементы = НаборыГруппДоступаДляОбновления(ПараметрыОбновления, КоличествоВЗапросе); + Иначе + Запрос = Новый Запрос; + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + + ПоследнийКлючДоступа = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных; + Если ТипЗнч(ПоследнийКлючДоступа) <> Тип("СправочникСсылка.КлючиДоступа") Тогда + ПоследнийКлючДоступа = Неопределено; + КонецЕсли; + Запрос.УстановитьПараметр("ПоследнийКлючДоступа", ПоследнийКлючДоступа); + + Если ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда + // Для режима ЭтоОчисткаВыбранныхКлючей в процедуре ОбработатьУстаревшиеКлючиДоступаСписка. + // Переключение на шаг УстаревшиеЭлементы выполняется в процедуре УточнитьПоследнийОбновленныйЭлемент. + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей Тогда + // Для режима ЭтоОчисткаВыбранныхКлючей в процедуре ОбработатьУстаревшиеКлючиДоступаСписка. + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.СоставПолей > 0 + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + Иначе + Запрос.УстановитьПараметр("ДатаУстаревания", ДатаУстаревания()); + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаУстаревшихКлючейДоступа; + КонецЕсли; + Иначе + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаКлючейДоступаДляОбновленияПрав; + КонецЕсли; + Иначе + УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных(Запрос, ПараметрыОбновления); + КонецЕсли; + + Если Запрос.Текст = ПризнакПустогоЗапроса() Тогда + ВыбраныВсеЭлементы = Истина; + Возврат Неопределено; + + ИначеЕсли Запрос.Текст = ПризнакИтерационногоЗапроса() Тогда + Возврат ИтерационнаяВыборкаЭлементовДляОбновления(Запрос, + ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы, Неопределено); + Иначе + КоличествоВЗапросе = ?(КоличествоВЗапросе < 1000, 1000, ?(КоличествоВЗапросе > 10000, 10000, КоличествоВЗапросе)); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + Элементы = Запрос.Выполнить().Выгрузить(); + КонецЕсли; + КонецЕсли; + + Если Элементы.Количество() = 0 Тогда + ВыбраныВсеЭлементы = Истина; + Возврат Неопределено; + КонецЕсли; + + ВыбраныВсеЭлементы = Элементы.Количество() < КоличествоВЗапросе; + + Возврат Элементы; + +КонецФункции + +// Для функции ЭлементыДляОбновления и процедур +// УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных, +// УстановитьОбработкуУстаревшихДанных, +// ДобавитьТекстЗапросаУстаревшихЭлементовДанных. +// +Функция ПризнакПустогоЗапроса() + Возврат "НетЭлементов"; +КонецФункции + +// Для функции ЭлементыДляОбновления и +// процедуры УстановитьПустойПоследнийЭлемент. +// +Функция ПризнакИтерационногоЗапроса() + Возврат "*"; +КонецФункции + +// Для функции ЭлементыДляОбновления. +Функция ИтерационнаяВыборкаЭлементовДляОбновления(Запрос, ПараметрыОбновления, КоличествоВЗапросе, + ВыбраныВсеЭлементы, КоличествоЗапрошенныхЭлементов) + + КоличествоЭлементов = 500; // Начальное количество элементов данных в диапазоне. + ТекстЗапросаДиапазона = ПараметрыОбновления.ТекстЗапросаДиапазонаЭлементовДанных; + ТекстЗапросаЭлементовДанных = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами; + + // Подготовка запроса получения первой границы диапазона. + Если ПараметрыОбновления.СписокСДатой Тогда + Запрос.УстановитьПараметр("ДатаОкончанияДиапазона", Запрос.Параметры.ДатаОкончания); + ТекстЗапросаДиапазона = СтрЗаменить(ТекстЗапросаДиапазона, + "ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона", "ИСТИНА"); // @query-part-1 + ТекстЗапросаЭлементовДанных = СтрЗаменить(ТекстЗапросаЭлементовДанных, + "ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона", "ИСТИНА"); // @query-part-1 + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Запрос.УстановитьПараметр("СсылкаНачалаДиапазона", Запрос.Параметры.ПоследняяОбработаннаяСсылка); + Иначе + Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл + НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); + ИмяПоля = СтрШаблон("Поле%1НачалаДиапазона", НомерПоля); + Если КлючИЗначение.Значение = Неопределено Тогда + ТекстЗапросаДиапазона = СтрЗаменить(ТекстЗапросаДиапазона, + " > &" + ИмяПоля, " >= &" + ИмяПоля); + ТекстЗапросаЭлементовДанных = СтрЗаменить(ТекстЗапросаЭлементовДанных, + " > &" + ИмяПоля, " >= &" + ИмяПоля); + КонецЕсли; + Запрос.УстановитьПараметр(ИмяПоля, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + Элементы = Неопределено; + + Пока Истина Цикл + // Получение очередной границы диапазона. + Запрос.Текст = СтрЗаменить(ТекстЗапросаДиапазона, "993", Формат(КоличествоЭлементов, "ЧГ=")); + ТекущийТекстЗапросаДиапазона = Запрос.Текст; + Выгрузка = Запрос.Выполнить().Выгрузить(); + Если Не ЗначениеЗаполнено(Выгрузка) Тогда + ВыбраныВсеЭлементы = Истина; + Прервать; + КонецЕсли; + Если КоличествоЗапрошенныхЭлементов <> Неопределено Тогда + КоличествоЗапрошенныхЭлементов.Добавить(КоличествоЭлементов); + КонецЕсли; + Для Каждого Колонка Из Выгрузка.Колонки Цикл + Запрос.УстановитьПараметр(Колонка.Имя, Выгрузка[0][Колонка.Имя]); + КонецЦикла; + + // Получение элементов с устаревшими ключами из диапазона. + Запрос.Текст = СтрЗаменить(ТекстЗапросаЭлементовДанных, "993", Формат(КоличествоЭлементов, "ЧГ=")); + + МоментНачала = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ТекущиеЭлементы = Запрос.Выполнить().Выгрузить(); + ВремяЗапроса = ТекущаяУниверсальнаяДатаВМиллисекундах() - МоментНачала; + + // Перерасчет количества элементов в диапазоне. + Если ВремяЗапроса < 1000 Тогда + КоличествоЭлементов = КоличествоЭлементов * Цел((1050 - ВремяЗапроса) / 50); + ИначеЕсли ВремяЗапроса > 2000 Тогда + КоличествоЭлементов = КоличествоЭлементов / 2; + КонецЕсли; + КоличествоЭлементов = (1 + Цел((КоличествоЭлементов - 1) / 500)) * 500; + Если КоличествоЭлементов > 10000 Тогда + КоличествоЭлементов = 10000; + КонецЕсли; + Если КоличествоЭлементов < 500 Тогда + КоличествоЭлементов = 500; + КонецЕсли; + + // Проверка неизменности текущего диапазона. + Запрос.Текст = ТекущийТекстЗапросаДиапазона; + Выгрузка = Запрос.Выполнить().Выгрузить(); + ДиапазонИзменился = Ложь; + Для Каждого Колонка Из Выгрузка.Колонки Цикл + Если Запрос.Параметры[Колонка.Имя] <> Выгрузка[0][Колонка.Имя] Тогда + ДиапазонИзменился = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Если ДиапазонИзменился Тогда + Запрос.Текст = СтрЗаменить(ТекстЗапросаЭлементовДанных, "ПЕРВЫЕ 993", ""); + ТекущиеЭлементы = Запрос.Выполнить().Выгрузить(); + КонецЕсли; + + ПоследнийТекущийЭлемент = Неопределено; + Если ЗначениеЗаполнено(ТекущиеЭлементы) Тогда + Если Элементы = Неопределено Тогда + Элементы = ТекущиеЭлементы; + Иначе + Для Каждого ТекущийЭлемент Из ТекущиеЭлементы Цикл + ЗаполнитьЗначенияСвойств(Элементы.Добавить(), ТекущийЭлемент); + КонецЦикла; + КонецЕсли; + ПоследнийТекущийЭлемент = ТекущиеЭлементы[ТекущиеЭлементы.Количество() - 1]; + КонецЕсли; + + Если Элементы <> Неопределено + И Элементы.Количество() >= КоличествоВЗапросе + Или ТекущаяУниверсальнаяДатаВМиллисекундах() > ПараметрыОбновления.ГраницаВремениОбработки + И (ЗначениеЗаполнено(Элементы) + Или Не ПараметрыОбновления.СписокСДатой + Или Запрос.Параметры.ДатаОкончания > Запрос.Параметры.ДатаНачалаДиапазона) Тогда + + Прервать; + КонецЕсли; + + // Подготовка запроса следующей границы диапазона. + ТекстЗапросаДиапазона = ПараметрыОбновления.ТекстЗапросаДиапазонаЭлементовДанных; + ТекстЗапросаЭлементовДанных = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами; + + Если ПараметрыОбновления.СписокСДатой Тогда + Запрос.УстановитьПараметр("ДатаОкончанияДиапазона", Запрос.Параметры.ДатаНачалаДиапазона); + Запрос.УстановитьПараметр("СсылкаДатыОкончанияДиапазона", Запрос.Параметры.СсылкаДатыНачалаДиапазона); + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Запрос.УстановитьПараметр("СсылкаНачалаДиапазона", Запрос.Параметры.СсылкаОкончанияДиапазона); + Иначе + Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл + НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); + ИмяПоляНачала = СтрШаблон("Поле%1НачалаДиапазона", НомерПоля); + ИмяПоляОкончания = СтрШаблон("Поле%1ОкончанияДиапазона", НомерПоля); + ЗначениеПоляОкончания = Запрос.Параметры[ИмяПоляОкончания]; + Запрос.УстановитьПараметр(ИмяПоляНачала, ЗначениеПоляОкончания); + КонецЦикла; + КонецЕсли; + КонецЦикла; + + Если ВыбраныВсеЭлементы Или ЗначениеЗаполнено(Элементы) Тогда + Возврат Элементы; + КонецЕсли; + + КоличествоВЗапросе = Null; + + // Подготовка обработанного элемента для продвижения указателя. + Элементы = ТекущиеЭлементы; + Элемент = Элементы.Добавить(); + + Если ПараметрыОбновления.СписокСДатой Тогда + Элемент.Дата = Запрос.Параметры.ДатаНачалаДиапазона; + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Элемент.ТекущаяСсылка = Запрос.Параметры.СсылкаОкончанияДиапазона; + Иначе + Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл + НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); + ИмяПоляОкончания = СтрШаблон("Поле%1ОкончанияДиапазона", НомерПоля); + Элемент[КлючИЗначение.Ключ] = Запрос.Параметры[ИмяПоляОкончания]; + КонецЦикла; + КонецЕсли; + + Возврат Элементы; + +КонецФункции + +// Для процедур выполнения запросов. +Процедура УстановитьУточнениеПланаЗапроса(ТекстЗапроса, УникальныйПлан = Ложь) + + Если УправлениеДоступомСлужебныйПовтИсп.ТребуетсяУточнениеПланаЗапроса() Тогда + Если УникальныйПлан Тогда + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + ВсегоМинут = Цел((ТекущаяДатаСеанса - '00010101') / 60); + ОстатокМинут = ВсегоМинут - Цел(ВсегоМинут / 2048) * 2048; + УточнениеПланаЗапроса = УправлениеДоступомСлужебныйПовтИсп.УточнениеПланаЗапроса(ОстатокМинут, 11); + Иначе + ТочноеВремя = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ВсегоДесятыхСекунд = Цел(ТочноеВремя / 100); + ОстатокДесятыхСекунд = ВсегоДесятыхСекунд - Цел(ВсегоДесятыхСекунд / 1048576) * 1048576; + УточнениеПланаЗапроса = УправлениеДоступомСлужебныйПовтИсп.УточнениеПланаЗапроса(ОстатокДесятыхСекунд, 20); + КонецЕсли; + Иначе + УточнениеПланаЗапроса = "ИСТИНА"; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УточнениеПланаЗапроса", УточнениеПланаЗапроса); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Функция ЭлементыТочечногоЗаданияДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + Или ПараметрыОбновления.БезЗаписиКлючейДоступа + Или ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей Тогда + + Возврат Неопределено; + КонецЕсли; + + Запрос = Новый Запрос; + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав; + Если Не ЗначениеЗаполнено(Запрос.Текст) Тогда + Возврат Неопределено; + КонецЕсли; + Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + Запрос.УстановитьПараметр("ВедущиеКлючиДоступа", ПараметрыОбновления.ТочечноеЗадание.ПоКлючамДоступа); + Иначе + Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + ОписаниеЗапросов = ПараметрыОбновления.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам; + ЗапросыПакета = Новый Массив; + ЗапросыДанных = Новый Массив; + Если ЗначениеЗаполнено(ПараметрыОбновления.ТочечноеЗадание.ПоЗначениямПолей) Тогда + ОписаниеЗапросовПоЗначениямПолей = ОписаниеЗапросов.Получить("ПоЗначениямПолей"); + Если ОписаниеЗапросовПоЗначениямПолей = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + Для Каждого ОписаниеИзменений Из ПараметрыОбновления.ТочечноеЗадание.ПоЗначениямПолей Цикл + ОписаниеЗапроса = ОписаниеЗапросовПоЗначениямПолей.Получить(ОписаниеИзменений.Ключ); + Если ОписаниеЗапроса = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + СоставИзменений = ОписаниеИзменений.Значение; // ТаблицаЗначений + Если ОписаниеЗапроса.ТипыПолей.Количество() <> СоставИзменений.Колонки.Количество() Тогда + Возврат Неопределено; + КонецЕсли; + Для Каждого Колонка Из СоставИзменений.Колонки Цикл + ТипыПоля = ОписаниеЗапроса.ТипыПолей.Получить(Колонка.Имя); + Если ТипЗнч(ТипыПоля) <> Тип("ХранилищеЗначения") Тогда + Возврат Неопределено; + КонецЕсли; + ТипКолонки = Новый ОписаниеТипов(Колонка.ТипЗначения,, "Null"); + Если ТипыПоля.Получить() <> ТипКолонки + Или СтрокаДанныхДляХеширования(Колонка.ТипЗначения) + <> СтрокаДанныхДляХеширования(Новый ОписаниеТипов(Колонка.ТипЗначения.Типы())) Тогда + Возврат Неопределено; + КонецЕсли; + КонецЦикла; + ИмяВременнойТаблицыИПараметра = СтрЗаменить(ОписаниеИзменений.Ключ, ".", "_"); + Запрос.УстановитьПараметр(ИмяВременнойТаблицыИПараметра, СоставИзменений); + ЗапросыПакета.Добавить(ОписаниеЗапроса.ТекстЗапросаПараметров); + Для Каждого ТекстЗапросаДанных Из ОписаниеЗапроса.ТекстыЗапросовДанных Цикл + ЗапросыДанных.Добавить(ТекстЗапросаДанных); + КонецЦикла; + КонецЦикла; + КонецЕсли; + Если Не ДобавитьЗапросыТочечногоЗадания("ПоКлючамДоступа", + Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) + Или Не ДобавитьЗапросыТочечногоЗадания("ПоЗначениямСГруппами", + Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) + Или ЗапросыДанных.Количество() = 0 Тогда + Возврат Неопределено; + КонецЕсли; + Если ЗапросыДанных.Количество() = 1 Тогда + ЗапросыПакета.Добавить(СтрЗаменить(ЗапросыДанных[0], + " + |ИЗ + | ", + " + |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам + |ИЗ + | ")); // @query-part-1, @query-part-2 + Иначе + ТекстыЗапросов = СтрСоединить(ЗапросыДанных, + " + | + |ОБЪЕДИНИТЬ ВСЕ + | + |"); // @query-part-1 + ЗапросыПакета.Добавить(СтрЗаменить(ОписаниеЗапросов.Получить("ТекстЗапросаОберткиВыбораДанных"), + "#ЗапросыВыбораДанных", "(" + ТекстСОтступом(ТекстыЗапросов, " ") + ")")); + КонецЕсли; + ЗапросыПакета.Добавить(ОписаниеЗапросов.Получить("ТекстЗапросаТочечнойПроверки")); + Запрос.Текст = СтрСоединить(ЗапросыПакета, ОбщегоНазначения.РазделительПакетаЗапросов()); + КонецЕсли; + + КоличествоВЗапросе = ?(КоличествоВЗапросе < 1000, 1000, ?(КоличествоВЗапросе > 4000, 4000, КоличествоВЗапросе)); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Элементы = Запрос.Выполнить().Выгрузить(); + КоличествоВыбранных = Элементы.Количество(); + Иначе + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + КоличествоВыбранных = РезультатыЗапроса[ЗапросыПакета.Количество() - 2].Выгрузить()[0].Количество; + Элементы = РезультатыЗапроса[ЗапросыПакета.Количество() - 1].Выгрузить(); + КонецЕсли; + + ВыбраныВсеЭлементы = КоличествоВыбранных < КоличествоВЗапросе; + + Если Элементы.Количество() = 0 Тогда + Возврат Неопределено; + КонецЕсли; + + Возврат Элементы; + +КонецФункции + +// Для функции ЭлементыТочечногоЗаданияДляОбновления. +Функция ДобавитьЗапросыТочечногоЗадания(ВидЗадания, Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) + + Данные = ТаблицаТочечногоЗадания(); + Данные = ПараметрыОбновления.ТочечноеЗадание[ВидЗадания]; // см. ТаблицаТочечногоЗадания + Если Не ЗначениеЗаполнено(Данные) Тогда + Возврат Истина; + КонецЕсли; + + ОписаниеЗапросов = + ПараметрыОбновления.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам.Получить(ВидЗадания); + + Если ОписаниеЗапросов = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ТипКолонки = Данные.Колонки.Ссылка.ТипЗначения; + НедостающиеТипы = Новый ОписаниеТипов(ТипКолонки, , ОписаниеЗапросов.ТипСсылки.Получить().Типы()); + Если НедостающиеТипы.Типы().Количество() > 0 Тогда + Возврат Ложь; + КонецЕсли; + + Запрос.УстановитьПараметр(ВидЗадания, Данные); + ЗапросыПакета.Добавить(ОписаниеЗапросов.ТекстЗапросаПараметров); + + КлючиЗапросов = Новый Соответствие; + Для Каждого Тип Из ТипКолонки.Типы() Цикл + ТекущиеКлючи = ОписаниеЗапросов.КлючиЗапросовПоТипам.Получить(Тип); + Если ТекущиеКлючи = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + Для Каждого Ключ Из ТекущиеКлючи Цикл + КлючиЗапросов.Вставить(Ключ, Истина); + КонецЦикла; + КонецЦикла; + + Для Каждого КлючИЗначение Из КлючиЗапросов Цикл + ТекстЗапроса = ОписаниеЗапросов.ТекстыЗапросовПоКлючам.Получить(КлючИЗначение.Ключ); + Если ТекстЗапроса = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + ЗапросыДанных.Добавить(ТекстЗапроса); + КонецЦикла; + + Возврат Истина; + +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Ссылка - ЛюбаяСсылка +// +Функция ТаблицаТочечногоЗадания() + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении(ПараметрыОбновления) + + ПараметрыОбновления.ПерезапускОбновления = Истина; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); + + // Регистрация косвенного планирования обновления доступа. + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = ПараметрыОбновления.ЭтоОбновлениеПрав; + ПараметрыПланирования.ДляПользователей = Не ПараметрыОбновления.ДляВнешнихПользователей; + ПараметрыПланирования.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + ПараметрыПланирования.Описание = "ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении"; + + СпискиПоИдентификаторам = Новый Соответствие; + СпискиПоИдентификаторам.Вставить(ПараметрыОбновления.ИдентификаторСписка, ПараметрыОбновления.Список); + + ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Функция НаборПорцийЭлементов(ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы, РазмерПорции = Неопределено) + + НаборПорций = Новый Массив; + + Если Элементы = Неопределено Тогда + ПорцияИзНабора = ПорцияИзНабора(); + ПорцияИзНабора.Вставить("Обработана", Истина); + ПорцияИзНабора.Вставить("Обрабатывается", Ложь); + ПорцияИзНабора.Вставить("Элементы", Новый ХранилищеЗначения(Новый ТаблицаЗначений)); + ПорцияИзНабора.Вставить("ДатаПоследнегоЭлементаПорции", '00010101'); + ПорцияИзНабора.Вставить("ПоследнийЭлементПорции", НачальныйЭлемент(ПараметрыОбновления,, Истина)); + ПорцияИзНабора.Вставить("НовыйПоследнийЭлементПорции"); + НаборПорций.Добавить(ПорцияИзНабора); + ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; + Если ПорцияИзНабора.ПоследнийЭлементПорции.Свойство("Дата") Тогда + ПорцияИзНабора.ПоследнийЭлементПорции.Дата = '00010101'; + КонецЕсли; + УстановитьПустойПоследнийЭлемент(ПорцияИзНабора.НовыйПоследнийЭлементПорции, + ПараметрыОбновления, '00010101'); + Возврат НаборПорций; + КонецЕсли; + + Если РазмерПорции = Неопределено Тогда + РазмерПорции = ПараметрыОбновления.КоличествоОбработанныхЭлементов; + МаксимумНовыхПорций = ПараметрыОбновления.МаксимумПорцийИзИсходной; + Если Элементы.Количество() / РазмерПорции > МаксимумНовыхПорций Тогда + РазмерПорции = Элементы.Количество() / МаксимумНовыхПорций; + Если РазмерПорции <> Цел(РазмерПорции) Тогда + РазмерПорции = Цел(РазмерПорции) + 1; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ПараметрыОбновления.Вставить("НаборПорций", НаборПорций); + Индекс = 0; + Для Каждого Элемент Из Элементы Цикл + Если Индекс / РазмерПорции = Цел(Индекс / РазмерПорции) Тогда + ПорцияИзНабора = Новый Массив; + НаборПорций.Добавить(ПорцияИзНабора); + КонецЕсли; + ПорцияИзНабора.Добавить(Элемент); + Индекс = Индекс + 1; + КонецЦикла; + + Для Индекс = 0 По НаборПорций.Количество() - 1 Цикл + ЭлементыПорции = Элементы.Скопировать(НаборПорций[Индекс]); + ПорцияИзНабора = ПорцияИзНабора(); + ПорцияИзНабора.Вставить("Обработана", Ложь); + ПорцияИзНабора.Вставить("Обрабатывается", Ложь); + НаборПорций[Индекс] = ПорцияИзНабора; + ПорцияИзНабора.Вставить("Элементы", Новый ХранилищеЗначения(ЭлементыПорции)); + ПорцияИзНабора.Вставить("ПоследнийЭлементПорции", + ПоследнийЭлемент(ЭлементыПорции, ПараметрыОбновления)); + ПорцияИзНабора.Вставить("ДатаПоследнегоЭлементаПорции", + ?(ПорцияИзНабора.ПоследнийЭлементПорции.Свойство("Дата"), + ПорцияИзНабора.ПоследнийЭлементПорции.Дата, '00010101')); + ПорцияИзНабора.Вставить("НовыйПоследнийЭлементПорции", + ПоследнийЭлемент(ЭлементыПорции, ПараметрыОбновления)); + КонецЦикла; + + Если ВыбраныВсеЭлементы Тогда + ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; + УстановитьПустойПоследнийЭлемент(ПорцияИзНабора.НовыйПоследнийЭлементПорции, + ПараметрыОбновления, '00010101'); + КонецЕсли; + + Возврат НаборПорций; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Обработана - Булево +// * Обрабатывается - Булево +// * Элементы - ХранилищеЗначения +// * ДатаПоследнегоЭлементаПорции - Дата +// * ПоследнийЭлементПорции - см. НачальныйЭлемент +// * НовыйПоследнийЭлементПорции - см. НачальныйЭлемент +// +Функция ПорцияИзНабора() + + Возврат Новый Структура; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ОбновитьПорциюЭлементов, НаборПорцийЭлементов. +Функция ПоследнийЭлемент(Элементы, ПараметрыОбновления, ПоследнийОбработанный = Ложь) + + НомерПоследнего = ?(ПоследнийОбработанный, + ПараметрыОбновления.КоличествоОбработанныхЭлементов, Элементы.Количество()); + + ПоследнийЭлемент = Элементы[НомерПоследнего - 1]; + + ЭлементДанных = НачальныйЭлемент(ПараметрыОбновления, , Истина); + + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ЭлементДанных.КлючДанных = ПоследнийЭлемент.Ссылка; + Возврат ЭлементДанных; + КонецЕсли; + + Если ПараметрыОбновления.СписокСДатой + И Не ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + + ЭлементДанных.Дата = ПоследнийЭлемент.Дата; + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + ЭлементДанных.КлючДанных = ПоследнийЭлемент.ТекущаяСсылка; + Иначе + ЭлементДанных.КлючДанных = КлючДанных(ПараметрыОбновления); + ЗаполнитьЗначенияСвойств(ЭлементДанных.КлючДанных, ПоследнийЭлемент); + + Если ПараметрыОбновления.СписокСПериодом + И ЭлементДанных.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + + ЭлементДанных.Дата = ПоследнийЭлемент.Период; + КонецЕсли; + КонецЕсли; + + Возврат ЭлементДанных; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура УточнитьПоследнийОбновленныйЭлемент(ПараметрыОбновления) + + Если ПараметрыОбновления.Список = "Справочник.НаборыГруппДоступа" + Или ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда + Если Не ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = + НачальныйЭлемент(ПараметрыОбновления, "НетДанных"); + + ИначеЕсли Не ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + УстановитьОбработкуУстаревшихДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + ПараметрыОбновления, "НетДанных"); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ВыполнитьОбновлениеДоступаСписка, НаборПорцийЭлементов. +Процедура УстановитьПустойПоследнийЭлемент(Элемент, ПараметрыОбновления, ДатаЭлемента = '00010101') + + ДатаЭлемента = '00010101'; + Элемент = НачальныйЭлемент(ПараметрыОбновления, , Истина); + Элемент.КлючДанных = Null; + + // Уточнение нового последнего элемента. + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Возврат; + КонецЕсли; + НовыйВидКлючаДанных = ""; + Если Элемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + НовыйВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + НовыйВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + НовыйВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + НовыйВидКлючаДанных = "НаборыГруппРазрешенныеПользователям"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" + И Элемент.ОбработатьНаборыГруппСУстаревшимиПравами Тогда + + НовыйВидКлючаДанных = "НаборыГруппСУстаревшимиПравами"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" + Или Элемент.ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Если ЗначениеЗаполнено(НовыйВидКлючаДанных) Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, НовыйВидКлючаДанных); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиПравами" Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "НекорректныеЭлементыОбщегоРегистра" Тогда + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда + Если ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных <> ПризнакПустогоЗапроса() Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементы"); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "НекорректныеЭлементы" Тогда + Если Не ПараметрыОбновления.ЭтоСсылочныйТип + И ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + + Элемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементыОбщегоРегистра"); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.СписокСДатой Тогда + УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента); + Если Элемент.КлючДанных = Null Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ЭтоСсылочныйТип + Или ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента); + Если Элемент.КлючДанных = Null Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Не ПараметрыОбновления.СписокСПериодом Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, "ЭлементыБезКлючейПоЗначениямПолей"); + Возврат; + КонецЕсли; + + Элемент = НачальныйЭлемент(ПараметрыОбновления, "ЭлементыБезКлючейПоПериоду"); + ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = Элемент; + УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента, МаксимальнаяДата()); + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = ПоследнийОбновленныйЭлемент; + + Если Элемент.КлючДанных = Null Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + +КонецПроцедуры + +// Для процедур УточнитьПоследнийОбновленныйЭлемент, УстановитьПустойПоследнийЭлемент. +Процедура УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления, ВидКлючаДанныхЗавершения = Неопределено) + + НовыйЭлемент = Неопределено; + Если Элемент.ОбработатьУстаревшиеЭлементы Тогда + + Если ПараметрыОбновления.ЭтоОбновлениеПрав + Или ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + Или ПараметрыОбновления.ТекстЗапросаУстаревшихЭлементовДанных <> ПризнакПустогоЗапроса() Тогда + + НовыйЭлемент = НачальныйЭлемент(ПараметрыОбновления, "УстаревшиеЭлементы"); + + ИначеЕсли ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных <> ПризнакПустогоЗапроса() Тогда + НовыйЭлемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементы"); + КонецЕсли; + КонецЕсли; + + Если НовыйЭлемент <> Неопределено Тогда + Элемент = НовыйЭлемент; + + ИначеЕсли ВидКлючаДанныхЗавершения <> Неопределено Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, ВидКлючаДанныхЗавершения); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры УточнитьПустойПоследнийЭлемент. +Процедура УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента, + ДатаНачалаТекущегоПериода = Неопределено) + + Если ДатаНачалаТекущегоПериода = Неопределено Тогда + ДатаНачалаТекущегоПериода = ПараметрыОбновления.ДатаНачала; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДатаНачала", ДатаНачалаТекущегоПериода); + + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаДатыСледующегоЭлементаДанных; + + РезультатЗапроса = Запрос.Выполнить(); + + Если РезультатЗапроса.Пустой() Тогда + Элемент.КлючДанных = Null; + Возврат; + КонецЕсли; + + Элемент = ПоследнийЭлемент(РезультатЗапроса.Выгрузить(), ПараметрыОбновления); + ДатаЭлемента = ?(Элемент.Свойство("Дата"), Элемент.Дата, '00010101'); + +КонецПроцедуры + +// Для функции ЭлементыДляОбновления. +Процедура УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных(Запрос, ПараметрыОбновления) + + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаУстаревшихЭлементовДанных; + ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НекорректныеЭлементы" Тогда + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных; + Иначе + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра; + КонецЕсли; + Иначе + // ТекстЗапросаДиапазонаЭлементовДанных, ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами. + Запрос.Текст = ПризнакИтерационногоЗапроса(); + Если Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда + Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + Если ПараметрыОбновления.СписокСДатой Тогда + Запрос.УстановитьПараметр("ДатаНачала", ПараметрыОбновления.ДатаНачала); + Запрос.УстановитьПараметр("ДатаОкончания", ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата); + Возврат; + КонецЕсли; + КонецЕсли; + + КлючДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных; + + Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда + УстановленныйКлючДанных = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(КлючДанных)), КлючДанных, Неопределено); + Запрос.УстановитьПараметр("ПоследняяОбработаннаяСсылка", УстановленныйКлючДанных); + Возврат; + КонецЕсли; + + Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); + УстановленныйКлючДанных = КлючДанных(ПараметрыОбновления, КлючДанных); + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + + ЭлементыБезКлючей = ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" + Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей"; + + Если ЭлементыБезКлючей И ПараметрыОбновления.СписокСПериодом Тогда + Если ВидКлючаДанных <> "ЭлементыБезКлючейПоПериоду" Тогда + УстановитьВидКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + "ЭлементыБезКлючейПоПериоду"); + КонецЕсли; + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхБезКлючейДоступа; + Запрос.УстановитьПараметр("ДатаНачала", ПараметрыОбновления.ДатаНачала); + Запрос.УстановитьПараметр("ДатаОкончания", ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата); + + ИначеЕсли ЭлементыБезКлючей Тогда + Если ВидКлючаДанных <> "ЭлементыБезКлючейПоЗначениямПолей" Тогда + УстановитьВидКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + "ЭлементыБезКлючейПоЗначениямПолей"); + КонецЕсли; + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхБезКлючейДоступа; + КонецЕсли; + + Если Запрос.Текст = ПризнакИтерационногоЗапроса() Тогда + Запрос.УстановитьПараметр("УстановленныйКлючДанных", УстановленныйКлючДанных); + Возврат; + КонецЕсли; + + Для Каждого КлючИЗначение Из УстановленныйКлючДанных Цикл + Если КлючИЗначение.Значение = Неопределено Тогда + ИмяПоля = КлючИЗначение.Ключ; + Запрос.Текст = СтрЗаменить(Запрос.Текст, " > &" + ИмяПоля, " >= &" + ИмяПоля); + КонецЕсли; + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для процедур ПоследнийЭлемент, УстановитьПараметрыПоследнегоОбновленногоЭлемента и +// функции ТекстЗапросаКоличестваОставшихсяЭлементовРегистра. +// +// Возвращаемое значение: +// Структура: +// * Поле1 - ЛюбаяСсылка +// * Поле2 - ЛюбаяСсылка +// * Поле3 - ЛюбаяСсылка +// * Поле4 - ЛюбаяСсылка +// * Поле5 - ЛюбаяСсылка +// +Функция КлючДанных(ПараметрыОбновления, ИсходныйКлючДанных = Неопределено) + + КоличествоПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); + + Если КоличествоПолей = 0 + Или ПараметрыОбновления.ИспользуетсяОграничениеПоВладельцу + Или ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + + КоличествоПолей = ПараметрыОбновления.ОпорныеПоля.МаксимальноеКоличество; + КонецЕсли; + ПолеВариантДоступа = ?(ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления), 1, 0); + + Если ТипЗнч(ИсходныйКлючДанных) = Тип("Структура") + И ИсходныйКлючДанных.Количество() = КоличествоПолей + ПолеВариантДоступа Тогда + + ЗначенияПолей = ИсходныйКлючДанных; + Иначе + ЗначенияПолей = Новый Структура; + КонецЕсли; + + НовыеЗначенияПолей = Новый Структура; + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ИмяПоля = "ВариантДоступа"; + Если ЗначенияПолей.Свойство(ИмяПоля) Тогда + НовыеЗначенияПолей.Вставить(ИмяПоля, ЗначенияПолей[ИмяПоля]); + Иначе + НовыеЗначенияПолей.Вставить(ИмяПоля, Неопределено); + КонецЕсли; + КонецЕсли; + + Для Номер = 1 По КоличествоПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", Номер); + Если ЗначенияПолей.Свойство(ИмяПоля) Тогда + НовыеЗначенияПолей.Вставить(ИмяПоля, ЗначенияПолей[ИмяПоля]); + Иначе + НовыеЗначенияПолей.Вставить(ИмяПоля, Неопределено); + КонецЕсли; + КонецЦикла; + + Возврат НовыеЗначенияПолей; + +КонецФункции + +// Для процедуры ЭлементыДляОбновления. +Функция НаборыГруппДоступаДляОбновления(ПараметрыОбновления, КоличествоВЗапросе) + + ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; + ВидКлючаДанных = ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ПоследняяОбработаннаяСсылка", ПоследнийОбновленныйЭлемент.КлючДанных); + + Если ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК ТекущаяСсылка, + | ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) КАК ЭтоНаборГруппДоступа + |ИЗ + | Справочник.НаборыГруппДоступа КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТекущийСписок.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) + | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | СоставыГруппПользователей.Пользователь КАК ТекущаяСсылка, + | СоставыГруппПользователей.Пользователь.Наименование КАК Наименование, + | СоставыГруппПользователей.Используется + | И ЕСТЬNULL(ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ, &ПустойУникальныйИдентификатор) <> &ПустойУникальныйИдентификатор КАК Используется, + | НаборыГруппДоступа.НеИспользуетсяС КАК НеИспользуетсяС + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ПО (НаборыГруппДоступа.Пользователь = СоставыГруппПользователей.Пользователь) + | И (НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей) + | И (НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) + | И (НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов + | ГДЕ + | ГруппыНаборов.Ссылка = НаборыГруппДоступа.Ссылка)) + |ГДЕ + | ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.Пользователи) + | И ВЫБОР + | КОГДА СоставыГруппПользователей.Используется + | И ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор + | ТОГДА НаборыГруппДоступа.Пользователь ЕСТЬ NULL + | ИЛИ НаборыГруппДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(1, 1, 1) + | ИНАЧЕ НаборыГруппДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ + | И СоставыГруппПользователей.Пользователь > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | СоставыГруппПользователей.Пользователь"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + ИначеЕсли ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + Возврат НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа( + ПараметрыОбновления, КоличествоВЗапросе); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + Возврат НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей( + ПараметрыОбновления, КоличествоВЗапросе); + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК ТекущаяСсылка, + | ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) КАК ЭтоНаборГруппДоступа + |ИЗ + | Справочник.НаборыГруппДоступа КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТекущийСписок.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.НовыйНаборГруппДоступа = ТекущийСписок.Ссылка) + | ИЛИ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.НовыйНаборГруппПользователей = ТекущийСписок.Ссылка)) + | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ИначеЕсли ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | Справочник.НаборыГруппДоступа КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И (ТекущийСписок.НовыйНаборГруппДоступа <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.Ссылка = ТекущийСписок.НовыйНаборГруппДоступа + | И НаборыГруппДоступа.НовыйНаборГруппДоступа = ТекущийСписок.НовыйНаборГруппДоступа) + | ИЛИ ТекущийСписок.НовыйНаборГруппПользователей <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.Ссылка = ТекущийСписок.НовыйНаборГруппПользователей + | И НаборыГруппДоступа.НовыйНаборГруппПользователей = ТекущийСписок.НовыйНаборГруппПользователей)) + | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + Возврат УстаревшиеНаборыГруппДоступаВСправочнике(ПараметрыОбновления, КоличествоВЗапросе); + КонецЕсли; + + КоличествоВЗапросе = ?(КоличествоВЗапросе < 25, 25, ?(КоличествоВЗапросе > 10000, 10000, КоличествоВЗапросе)); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + ЭлементыДанных = Запрос.Выполнить().Выгрузить(); + + Возврат ЭлементыДанных; + +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбновитьНаборыГруппДоступа(ЭлементыДанных, ПараметрыОбновления) + + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + + Если ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления); + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + ОбновитьНаборыИзОдногоПользователяВСправочнике(ЭлементыДанных, ПараметрыОбновления); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления, Истина); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления, Ложь); + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления, Истина); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда + ОбновитьНаборыГруппРазрешенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления); + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ОбработатьУстаревшиеНаборыВСправочнике(ЭлементыДанных, ПараметрыОбновления); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОчиститьПраваПустогоНабораГруппДоступа(ПараметрыОбновления) + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборовГруппДоступа + |ГДЕ + | КлючиДоступаНаборовГруппДоступа.НаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей + |ГДЕ + | КлючиДоступаПользователей.Пользователь = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей + |ГДЕ + | КлючиДоступаВнешнихПользователей.ВнешнийПользователь = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка)"; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Если Не РезультатыЗапроса[0].Пустой() Тогда + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + НаборЗаписей.Отбор.НаборГруппДоступа.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); + НаборЗаписей.Записать(); + КонецЕсли; + + Если Не РезультатыЗапроса[1].Пустой() Тогда + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); + НаборЗаписей.Отбор.Пользователь.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); + НаборЗаписей.Записать(); + КонецЕсли; + + Если Не РезультатыЗапроса[2].Пустой() Тогда + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); + НаборЗаписей.Отбор.ВнешнийПользователь.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); + НаборЗаписей.Записать(); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления, ЭтоНовыеНаборы = Ложь) + + Если ЭтоНовыеНаборы Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + КонецЕсли; + + Для Каждого ЭлементДанных Из ЭлементыДанных Цикл + Если ЭлементДанных.ЭтоНаборГруппДоступа Тогда + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, + "КлючиДоступаНаборовГруппДоступа", "ГруппыДоступа", "НаборГруппДоступа"); + + ИначеЕсли Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, + "КлючиДоступаПользователей", "ГруппыПользователей", "Пользователь"); + Иначе + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, + "КлючиДоступаВнешнихПользователей", "ГруппыВнешнихПользователей", "ВнешнийПользователь"); + КонецЕсли; + + Если ЭтоНовыеНаборы Тогда + ЭлементБлокировки.УстановитьЗначение("Ссылка", ЭлементДанных.ТекущаяСсылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, ЭлементДанных.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + ИмяРеквизита = ?(ЭлементДанных.ЭтоНаборГруппДоступа, + "НовыйНаборГруппДоступа", "НовыйНаборГруппПользователей"); + Если ЗначениеЗаполнено(Объект[ИмяРеквизита]) Тогда + Объект[ИмяРеквизита] = ПараметрыОбновления.ПустойНаборГруппДоступа; + Объект.Записать(); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппСУстаревшимиПравами. +Процедура ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, НаборГруппДоступа, ИмяРегистраПрав, + ИмяСправочникаГрупп, ИмяПоляНабораГрупп) + + Если НаборГруппДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа() Тогда + ТекстЗапросаВыбораПорцииДляБлокировки = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки, + | ВсеСтроки.КлючДоступа КАК КлючДоступа + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ГДЕ + | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И &УточнениеПланаЗапроса + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки, + | КлючДоступа"; + + ТекстЗапросаВыбораПорцииДляОбновления = + "ВЫБРАТЬ ПЕРВЫЕ 100 + | ВсеСтроки.КлючДоступа КАК КлючДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ГДЕ + | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И КлючиДоступаГруппДоступа.КлючДоступа В(&КлючиДоступа) + | И &УточнениеПланаЗапроса + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа + | И СтарыеДанные.КлючДоступа В(&КлючиДоступа)) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + Иначе + ТекстЗапросаВыбораПорцииДляБлокировки = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки, + | ВсеСтроки.КлючДоступа КАК КлючДоступа + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) + | И (ГруппыВходящиеВНаборы.Ссылка = &НаборГруппДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | КлючиДоступаГруппДоступа.КлючДоступа + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки, + | КлючДоступа"; + + ТекстЗапросаВыбораПорцииДляОбновления = + "ВЫБРАТЬ ПЕРВЫЕ 100 + | ВсеСтроки.КлючДоступа КАК КлючДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) + | И (ГруппыВходящиеВНаборы.Ссылка = &НаборГруппДоступа) + | И (КлючиДоступаГруппДоступа.КлючДоступа В (&КлючиДоступа)) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | КлючиДоступаГруппДоступа.КлючДоступа + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа + | И СтарыеДанные.КлючДоступа В(&КлючиДоступа)) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + КонецЕсли; + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "ТИП(Справочник.ГруппыДоступа)", "ТИП(Справочник." + ИмяСправочникаГрупп + ")"); // @query-part-1, @query-part-2 + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "ТИП(Справочник.ГруппыДоступа)", "ТИП(Справочник." + ИмяСправочникаГрупп + ")"); // @query-part-1, @query-part-2 + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "СтарыеДанные.НаборГруппДоступа", "СтарыеДанные." + ИмяПоляНабораГрупп); + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "СтарыеДанные.НаборГруппДоступа", "СтарыеДанные." + ИмяПоляНабораГрупп); + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "РегистрСведений.КлючиДоступаНаборовГруппДоступа", "РегистрСведений." + ИмяРегистраПрав); + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "РегистрСведений.КлючиДоступаНаборовГруппДоступа", "РегистрСведений." + ИмяРегистраПрав); + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "&УсловиеОтбораПравГрупп", ?(ИмяСправочникаГрупп = "ГруппыДоступа", "ИСТИНА", "СтарыеДанные.ЭтоПраваНабораГрупп")); + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "&УсловиеОтбораПравГрупп", ?(ИмяСправочникаГрупп = "ГруппыДоступа", "ИСТИНА", "СтарыеДанные.ЭтоПраваНабораГрупп")); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + Пока Истина Цикл + Запрос = Новый Запрос; + Запрос.Текст = ТекстЗапросаВыбораПорцииДляБлокировки; + УстановитьУточнениеПланаЗапроса(Запрос.Текст, Истина); + Запрос.УстановитьПараметр("НаборГруппДоступа", НаборГруппДоступа); + + Выгрузка = Запрос.Выполнить().Выгрузить(); + Если Выгрузка.Количество() = 0 Тогда + Прервать; + КонецЕсли; + + КлючиДоступа = Выгрузка.Скопировать(Новый Массив, "КлючДоступа"); + ПорцииКлючейДоступа = Новый Массив; + Для Каждого Строка Из Выгрузка Цикл + Если КлючиДоступа.Количество() > 100 Тогда + ПорцииКлючейДоступа.Добавить(КлючиДоступа); + КлючиДоступа = Выгрузка.Скопировать(Новый Массив, "КлючДоступа"); + КонецЕсли; + КлючиДоступа.Добавить().КлючДоступа = Строка.КлючДоступа; + КонецЦикла; + ПорцииКлючейДоступа.Добавить(КлючиДоступа); + + Для Каждого КлючиДоступа Из ПорцииКлючейДоступа Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраПрав); + ЭлементБлокировки.УстановитьЗначение(ИмяПоляНабораГрупп, НаборГруппДоступа); + ЭлементБлокировки.ИсточникДанных = КлючиДоступа; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючДоступа", "КлючДоступа"); + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = ТекстЗапросаВыбораПорцииДляОбновления; + УстановитьУточнениеПланаЗапроса(Запрос.Текст, Истина); + Запрос.УстановитьПараметр("НаборГруппДоступа", НаборГруппДоступа); + Запрос.УстановитьПараметр("КлючиДоступа", КлючиДоступа.ВыгрузитьКолонку("КлючДоступа")); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраПрав]); + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляНабораГрупп]; // ЭлементОтбора + ЭлементОтбора.Установить(НаборГруппДоступа); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + // @skip-check query-in-loop - Порционная обработка данных + Выборка = Запрос.Выполнить().Выбрать(); + + УдалениеЗавершено = Ложь; + Пока Выборка.Следующий() Цикл + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.КлючДоступа.Установить(Выборка.КлючДоступа); + КонецЕсли; + Если Не УдалениеЗавершено И Выборка.ВидИзмененияСтроки = 1 Тогда + УдалениеЗавершено = Истина; + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись[ИмяПоляНабораГрупп] = НаборГруппДоступа; + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + Если УдалениеЗавершено Тогда + ЗаполнитьЗначенияСвойств(ОднаЗапись, Выборка); + КонецЕсли; + НаборЗаписей.Записать(); + Иначе + Запись = НаборЗаписей.Добавить(); + Запись[ИмяПоляНабораГрупп] = НаборГруппДоступа; + ЗаполнитьЗначенияСвойств(Запись, Выборка); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(?(УдалениеЗавершено, РежимСлияния, РежимУдаления)); + КонецЕсли; + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура УстранитьДублиНаборовИзОдногоПользователяВСправочнике(ПараметрыОбновления) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.Пользователь КАК Пользователь, + | НаборыГруппДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И НаборыГруппДоступа.Пользователь В + | (ВЫБРАТЬ + | ВЫРАЗИТЬ(НаборыГруппДоступа.Пользователь КАК Справочник.Пользователи) КАК Пользователь + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | СГРУППИРОВАТЬ ПО + | НаборыГруппДоступа.Пользователь + | ИМЕЮЩИЕ + | КОЛИЧЕСТВО(НаборыГруппДоступа.Пользователь) > 1)"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + Если Выборка.Ссылка.УникальныйИдентификатор() = Выборка.Пользователь.УникальныйИдентификатор() Тогда + Продолжить; + КонецЕсли; + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Выборка.Ссылка); + Если Объект <> Неопределено Тогда + Объект.ТипЭлементовНабора = Неопределено; + Объект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыИзОдногоПользователяВСправочнике(ЭлементыДанных, ПараметрыОбновления) + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ТипЭлементовНабора = Справочники.ВнешниеПользователи.ПустаяСсылка(); + ПредставлениеЭлемента = НСтр("ru = 'Внешний пользователь'", ОбщегоНазначения.КодОсновногоЯзыка()); + Иначе + ТипЭлементовНабора = Справочники.Пользователи.ПустаяСсылка(); + ПредставлениеЭлемента = НСтр("ru = 'Пользователь'", ОбщегоНазначения.КодОсновногоЯзыка()); + КонецЕсли; + + Для Каждого Строка Из ЭлементыДанных Цикл + СсылкаНабора = Справочники.НаборыГруппДоступа.ПолучитьСсылку(Строка.ТекущаяСсылка.УникальныйИдентификатор()); + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНабора); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + Объект = СлужебныйЭлемент(Неопределено, СсылкаНабора); + Если Объект = Неопределено Тогда + Объект = СлужебныйЭлемент(Справочники.НаборыГруппДоступа); + Объект.УстановитьСсылкуНового(СсылкаНабора); + Иначе + Объект.Группы.Очистить(); + КонецЕсли; + Если Строка.Используется Тогда + Объект.НеИспользуетсяС = '00010101'; + ИначеЕсли Не ЗначениеЗаполнено(Строка.НеИспользуетсяС) Тогда + Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); + КонецЕсли; + Объект.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + Объект.ТипЭлементовНабора = ТипЭлементовНабора; + Объект.Пользователь = Строка.ТекущаяСсылка; + ОписаниеОбъекта = Строка; // СправочникОбъект.Пользователи + Объект.Наименование = Строка(ОписаниеОбъекта.Наименование) + " (" + ПредставлениеЭлемента + ")"; + Объект.Записать(); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ЗаполнитьПустыеХешиНаборовГрупп(ПараметрыОбновления) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("РазрешенныйПустойНабор", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) + | И НаборыГруппДоступа.Хеш = 0 + | И НаборыГруппДоступа.Ссылка <> &РазрешенныйПустойНабор"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Выборка.Ссылка); + Если Объект <> Неопределено Тогда + ЗаполнитьХешНабораГрупп(Объект); + Объект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Для функции НаборыГруппДоступаДляОбновления. +Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа(ПараметрыОбновления, + КоличествоВЗапросе) + + Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстЗапросаГрупп = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Группа + |ПОМЕСТИТЬ АктивныеГруппы + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль <> &ПрофильАдминистратор + | И НЕ ГруппыДоступа.ПометкаУдаления + | И НЕ ГруппыДоступа.Профиль.ПометкаУдаления + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа + | ГДЕ + | ПользователиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка) + | И ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение + | ГДЕ + | Назначение.Ссылка = ГруппыДоступа.Профиль + | И ТИПЗНАЧЕНИЯ(Назначение.ТипПользователей) = ТИП(Справочник.Пользователи)) + | ТОГДА ИСТИНА + | КОГДА НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение + | ГДЕ + | Назначение.Ссылка = ГруппыДоступа.Профиль) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ + | + |ИНДЕКСИРОВАТЬ ПО + | ГруппыДоступа.Ссылка"; + Иначе + ТекстЗапросаГрупп = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Группа + |ПОМЕСТИТЬ АктивныеГруппы + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль <> &ПрофильАдминистратор + | И НЕ ГруппыДоступа.ПометкаУдаления + | И НЕ ГруппыДоступа.Профиль.ПометкаУдаления + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа + | ГДЕ + | ПользователиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка) + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение + | ГДЕ + | Назначение.Ссылка = ГруппыДоступа.Профиль + | И Назначение.ТипПользователей <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(Назначение.ТипПользователей) <> ТИП(Справочник.Пользователи)) + | + |ИНДЕКСИРОВАТЬ ПО + | ГруппыДоступа.Ссылка"; + КонецЕсли; + + ТекстЗапросаНовыхНаборовГрупп = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | СоставыГруппПользователей.Пользователь КАК Пользователь, + | ПользователиГруппДоступа.Ссылка КАК Группа + |ПОМЕСТИТЬ НовыеНаборыГрупп + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа + | ПО СоставыГруппПользователей.ГруппаПользователей = ПользователиГруппДоступа.Пользователь + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы + | ПО (ПользователиГруппДоступа.Ссылка = АктивныеГруппы.Группа) + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь, + | Группа"; + + ЭлементыДанных = НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, + ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, "НаборГруппДоступа", "ГруппыДоступа"); + + КоличествоВЗапросе = ЭлементыДанных.Количество() + 1; + Возврат ЭлементыДанных; + +КонецФункции + +// Для функции НаборыГруппДоступаДляОбновления. +Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей(ПараметрыОбновления, + КоличествоВЗапросе) + + ТекстЗапросаГрупп = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | СоставыГруппПользователей.ГруппаПользователей КАК Группа + |ПОМЕСТИТЬ АктивныеГруппы + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + |ГДЕ + | СоставыГруппПользователей.Используется + | И ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей) + | + |ИНДЕКСИРОВАТЬ ПО + | СоставыГруппПользователей.ГруппаПользователей"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстЗапросаГрупп = СтрЗаменить(ТекстЗапросаГрупп, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ТекстЗапросаНовыхНаборовГрупп = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | СоставыГруппПользователей.Пользователь КАК Пользователь, + | СоставыГруппПользователей.ГруппаПользователей КАК Группа + |ПОМЕСТИТЬ НовыеНаборыГрупп + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы + | ПО СоставыГруппПользователей.ГруппаПользователей = АктивныеГруппы.Группа + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА) + | И (СоставыГруппПользователей.Используется) + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь, + | Группа"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ИмяСправочникаГрупп = "ГруппыВнешнихПользователей"; + Иначе + ИмяСправочникаГрупп = "ГруппыПользователей"; + КонецЕсли; + + ЭлементыДанных = НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, + ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, "НаборГруппПользователей", ИмяСправочникаГрупп); + + КоличествоВЗапросе = ЭлементыДанных.Количество() + 1; + Возврат ЭлементыДанных; + +КонецФункции + +// Для функций НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа, +// НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей. +// +Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, + ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, ИмяПоляНабора, ИмяСправочникаГрупп) + + ЧастиЗапроса = Новый Массив; + ЧастиЗапроса.Добавить(ТекстЗапросаГрупп); + ЧастиЗапроса.Добавить(ТекстЗапросаНовыхНаборовГрупп); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | НовыеНаборыГрупп.Пользователь КАК Пользователь, + | НовыеНаборыГрупп.Группа КАК Группа + |ИЗ + | НовыеНаборыГрупп КАК НовыеНаборыГрупп + | + |УПОРЯДОЧИТЬ ПО + | Пользователь, + | Группа + |ИТОГИ ПО + | Пользователь + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НаборыГрупп.Ссылка КАК ТекущаяСсылка, + | НаборыГрупп.Пользователь КАК Пользователь, + | ВЫБОР + | КОГДА НаборыГрупп.НовыйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | ТОГДА НаборыГрупп.РазрешенныйНаборГруппДоступа + | ИНАЧЕ НаборыГрупп.НовыйНаборГруппДоступа + | КОНЕЦ КАК ТекущийНаборГрупп + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГрупп + |ГДЕ + | НаборыГрупп.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГрупп.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И НаборыГрупп.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И НЕ(НаборыГрупп.РазрешенныйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НаборыГрупп.НовыйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | НовыеНаборыГрупп КАК НовыеНаборыГрупп + | ГДЕ + | НовыеНаборыГрупп.Пользователь = НаборыГрупп.Пользователь)) + | И &УточнениеПланаЗапроса + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НаборыГрупп.Ссылка КАК Ссылка + |ПОМЕСТИТЬ НаборыСАктивнымиГруппами + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГрупп + |ГДЕ + | НаборыГрупп.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГрупп.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов + | ЛЕВОЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы + | ПО + | ГруппыНаборов.Группа = АктивныеГруппы.Группа + | ГДЕ + | ГруппыНаборов.Ссылка = НаборыГрупп.Ссылка + | И АктивныеГруппы.Группа ЕСТЬ NULL) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НаборыГрупп.Ссылка КАК НаборГрупп, + | ГруппыНаборов.Группа КАК Группа + |ИЗ + | НаборыСАктивнымиГруппами КАК НаборыГрупп + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов + | ПО (ГруппыНаборов.Ссылка = НаборыГрупп.Ссылка) + | + |УПОРЯДОЧИТЬ ПО + | НаборГрупп, + | Группа + |ИТОГИ ПО + | НаборГрупп + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаборыГруппДоступа.НовыйНаборГруппДоступа КАК НовыйНабор + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.НовыйНаборГруппДоступа <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка)"; + + ЧастиЗапроса.Добавить(ТекстЗапроса); + Запрос.Текст = СтрСоединить(ЧастиЗапроса, ОбщегоНазначения.РазделительПакетаЗапросов()); + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА", "ИСТИНА"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка)", + "ЗНАЧЕНИЕ(Справочник." + ИмяСправочникаГрупп + ".ПустаяСсылка)"); // @query-part-1, @query-part-2 + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "НовыйНаборГруппДоступа", "Новый" + ИмяПоляНабора); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "РазрешенныйНаборГруппДоступа", "Разрешенный" + ИмяПоляНабора); + + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + НовыеНаборы = РезультатыЗапроса[6].Выгрузить(); + РезультатыЗапроса[6] = Неопределено; + НовыеНаборы.Индексы.Добавить("НовыйНабор"); + + СуществующиеНаборыГрупп = Новый Соответствие; + Выгрузка = РезультатыЗапроса[5].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + РезультатыЗапроса[5] = Неопределено; + Для Каждого СтрокаДЗ Из Выгрузка.Строки Цикл + ГруппыНабора = СтрокаДЗ.Строки.ВыгрузитьКолонку("Группа"); + СуществующиеНаборыГрупп.Вставить(СтрокаДанныхДляХеширования(ГруппыНабора), + Новый Структура("НаборГрупп, НаборГруппНовый", СтрокаДЗ.НаборГрупп, + НовыеНаборы.Найти(СтрокаДЗ.НаборГрупп, "НовыйНабор") <> Неопределено)); + КонецЦикла; + Выгрузка.Строки.Очистить(); + НовыеНаборы.Очистить(); + + НовыеНаборыГрупп = Новый Соответствие; + Выгрузка = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + РезультатыЗапроса[2] = Неопределено; + Для Каждого СтрокаДЗ Из Выгрузка.Строки Цикл + ГруппыНабора = СтрокаДЗ.Строки.ВыгрузитьКолонку("Группа"); + СуществующийНаборГрупп = СуществующиеНаборыГрупп.Получить(СтрокаДанныхДляХеширования(ГруппыНабора)); + Свойства = Новый Структура("НаборГрупп, НаборГруппНовый, ГруппыНабора, ИдентификаторГрупп"); + Если СуществующийНаборГрупп = Неопределено Тогда + Свойства.ГруппыНабора = ГруппыНабора; + Свойства.ИдентификаторГрупп = Новый УникальныйИдентификатор; + Иначе + Свойства.НаборГрупп = СуществующийНаборГрупп.НаборГрупп; + Свойства.НаборГруппНовый = СуществующийНаборГрупп.НаборГруппНовый; + КонецЕсли; + НовыеНаборыГрупп.Вставить(СтрокаДЗ.Пользователь, Свойства); + КонецЦикла; + Выгрузка.Строки.Очистить(); + СуществующиеНаборыГрупп.Очистить(); + + Выборка = РезультатыЗапроса[3].Выбрать(); + РезультатыЗапроса.Очистить(); + + ЭлементыДанных = Новый ТаблицаЗначений; + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка"); + ЭлементыДанных.Колонки.Добавить("НаборГрупп"); + ЭлементыДанных.Колонки.Добавить("НаборГруппНовый", Новый ОписаниеТипов("Булево")); + ЭлементыДанных.Колонки.Добавить("ГруппыНабора"); + ЭлементыДанных.Колонки.Добавить("ИдентификаторГрупп"); + ПустойНабор = ПредопределенноеЗначение("Справочник.НаборыГруппДоступа.ПустаяСсылка"); + + Пока Выборка.Следующий() Цикл + НовыйНаборГрупп = НовыеНаборыГрупп.Получить(Выборка.Пользователь); + Если НовыйНаборГрупп <> Неопределено + И НовыйНаборГрупп.НаборГрупп = Выборка.ТекущийНаборГрупп Тогда + Продолжить; + КонецЕсли; + СтрокаТЗ = ЭлементыДанных.Добавить(); + СтрокаТЗ.ТекущаяСсылка = Выборка.ТекущаяСсылка; + Если НовыйНаборГрупп = Неопределено Тогда + СтрокаТЗ.НаборГрупп = ПустойНабор; + Продолжить; + ИначеЕсли НовыйНаборГрупп.НаборГрупп <> Неопределено Тогда + СтрокаТЗ.НаборГрупп = НовыйНаборГрупп.НаборГрупп; + СтрокаТЗ.НаборГруппНовый = НовыйНаборГрупп.НаборГруппНовый; + Продолжить; + КонецЕсли; + СтрокаТЗ.ГруппыНабора = НовыйНаборГрупп.ГруппыНабора; + СтрокаТЗ.ИдентификаторГрупп = НовыйНаборГрупп.ИдентификаторГрупп; + КонецЦикла; + + Возврат ЭлементыДанных; + +КонецФункции + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, + ПараметрыОбновления, ЭтоОбновлениеНазначенныхНаборовГруппДоступа) + + ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + + Если ЭтоОбновлениеНазначенныхНаборовГруппДоступа Тогда + ИмяПоляНабора = "НаборГруппДоступа"; + ТипЭлементовНабора = Справочники.ГруппыДоступа.ПустаяСсылка(); + ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()); + + Иначе + ИмяПоляНабора = "НаборГруппПользователей"; + Если Не ДляВнешнихПользователей Тогда + ТипЭлементовНабора = Справочники.ГруппыПользователей.ПустаяСсылка(); + ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы пользователей'", + ОбщегоНазначения.КодОсновногоЯзыка()); + Иначе + ТипЭлементовНабора = Справочники.ГруппыВнешнихПользователей.ПустаяСсылка(); + ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы внешних пользователей'", + ОбщегоНазначения.КодОсновногоЯзыка()); + КонецЕсли; + КонецЕсли; + + НовыеНаборыГрупп = Новый Соответствие; + + Для Каждого Строка Из ЭлементыДанных Цикл + Если Строка.НаборГрупп = Неопределено Тогда + ОписаниеНабораГрупп = НовыеНаборыГрупп.Получить(Строка.ИдентификаторГрупп); + Если ОписаниеНабораГрупп = Неопределено Тогда + ОписаниеНабораГрупп = Новый Структура("НаборГрупп, НаборГруппНовый",, Ложь); + // @skip-check query-in-loop - Порционная обработка данных + ОписаниеНабораГрупп.НаборГрупп = НовыйНаборГрупп(Строка.ГруппыНабора, + ПараметрыОбновления.ДляВнешнихПользователей, + ТипЭлементовНабора, + ИмяПоляНабора, + ПредставлениеЭлементовГрупп, + ОписаниеНабораГрупп.НаборГруппНовый); + НовыеНаборыГрупп.Вставить(Строка.ИдентификаторГрупп, ОписаниеНабораГрупп); + КонецЕсли; + Строка.НаборГрупп = ОписаниеНабораГрупп.НаборГрупп; + Строка.НаборГруппНовый = ОписаниеНабораГрупп.НаборГруппНовый; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Строка.НаборГруппНовый Тогда + Объект["Новый" + ИмяПоляНабора] = Строка.НаборГрупп; + Иначе + Объект["Разрешенный" + ИмяПоляНабора] = Строка.НаборГрупп; + Объект["Новый" + ИмяПоляНабора] = ПараметрыОбновления.ПустойНаборГруппДоступа; + КонецЕсли; + Объект.Записать(); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппНазначенныеПользователямВСправочнике. +Функция НовыйНаборГрупп(ГруппыНабора, ДляВнешнихПользователей, ТипЭлементовНабора, + ИмяПоляНабора, ПредставлениеЭлементовГрупп, НаборГруппНовый) + + НоваяСсылка = Справочники.НаборыГруппДоступа.ПолучитьСсылку(); + Объект = СлужебныйЭлемент(Справочники.НаборыГруппДоступа); + Объект.УстановитьСсылкуНового(НоваяСсылка); + Объект.ДляВнешнихПользователей = ДляВнешнихПользователей; + Объект.ТипЭлементовНабора = ТипЭлементовНабора; + Объект.Наименование = Строка(НоваяСсылка.УникальныйИдентификатор()) + " (" + ПредставлениеЭлементовГрупп + ")"; + + Для Каждого ГруппаНабора Из ГруппыНабора Цикл + Объект.Группы.Добавить().Группа = ГруппаНабора; + КонецЦикла; + + ЗаполнитьХешНабораГрупп(Объект); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("ТипЭлементовНабора", Объект.ТипЭлементовНабора); + ЭлементБлокировки.УстановитьЗначение("Хеш", Объект.Хеш); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Если НаборГруппСуществует(Объект) Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); + Запрос.УстановитьПараметр("СуществующийНабор", Объект.Ссылка); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.НаборыГруппДоступа КАК ВсеНаборы + |ГДЕ + | ВсеНаборы.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ВсеНаборы.НовыйНаборГруппДоступа = &СуществующийНабор"; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "НовыйНаборГруппДоступа", "Новый" + ИмяПоляНабора); + + Если Не Запрос.Выполнить().Пустой() Тогда + НаборГруппНовый = Истина; + КонецЕсли; + Иначе + Объект["Новый" + ИмяПоляНабора] = НоваяСсылка; + Объект.Записать(); + НаборГруппНовый = Истина; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Возврат Объект.Ссылка; + +КонецФункции + +// Для функции НовыйНаборГрупп и процедуры ЗаполнитьПустыеХешиНаборовГрупп. +Процедура ЗаполнитьХешНабораГрупп(Объект) + + Объект.Группы.Сортировать("Группа", Новый СравнениеЗначений); + + ДанныеДляХеша = Объект.Группы.ВыгрузитьКолонку("Группа"); + СтрокаДляХеша = СтрокаДанныхДляХеширования(ДанныеДляХеша); + Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); + Хеширование.Добавить(СтрокаДляХеша); + Объект.Хеш = Хеширование.ХешСумма; + +КонецПроцедуры + +// Для функции НовыйНаборГрупп. +Функция НаборГруппСуществует(Объект) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТипЭлементовНабора", Объект.ТипЭлементовНабора); + Запрос.УстановитьПараметр("Хеш", Объект.Хеш); + Запрос.Текст = + "ВЫБРАТЬ + | СуществующиеНаборы.Ссылка КАК СсылкаНабора, + | СуществующиеНаборы.Группы.( + | Группы.Группа КАК Группа + | ) КАК ГруппыНабора + |ИЗ + | Справочник.НаборыГруппДоступа КАК СуществующиеНаборы + |ГДЕ + | СуществующиеНаборы.ТипЭлементовНабора = &ТипЭлементовНабора + | И СуществующиеНаборы.Хеш = &Хеш + | + |УПОРЯДОЧИТЬ ПО + | Ссылка"; + + ГруппыОбъекта = Объект.Группы.Выгрузить(, "Группа"); + ГруппыОбъекта.Индексы.Добавить("Группа"); + + Выгрузка = Запрос.Выполнить().Выгрузить(); + Для Каждого Строка Из Выгрузка Цикл + Если ГруппыОбъекта.Количество() <> Строка.ГруппыНабора.Количество() Тогда + Продолжить; + КонецЕсли; + ГруппыСовпадают = Истина; + Для Каждого Подстрока Из Строка.ГруппыНабора Цикл + Если ГруппыОбъекта.Найти(Подстрока.Группа, "Группа") = Неопределено Тогда + ГруппыСовпадают = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если ГруппыСовпадают Тогда + Объект = Новый Структура("Ссылка", Строка.СсылкаНабора); + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыГруппРазрешенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + + Для Каждого Строка Из ЭлементыДанных Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + Если ЗначениеЗаполнено(Объект.НовыйНаборГруппДоступа) Тогда + Объект.РазрешенныйНаборГруппДоступа = Объект.НовыйНаборГруппДоступа; + Объект.НовыйНаборГруппДоступа = ПараметрыОбновления.ПустойНаборГруппДоступа; + КонецЕсли; + Если ЗначениеЗаполнено(Объект.НовыйНаборГруппПользователей) Тогда + Объект.РазрешенныйНаборГруппПользователей = Объект.НовыйНаборГруппПользователей; + Объект.НовыйНаборГруппПользователей = ПараметрыОбновления.ПустойНаборГруппДоступа; + КонецЕсли; + Если Объект.Модифицированность() Тогда + Объект.Записать(); + КонецЕсли; + КонецЕсли; + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОчиститьПраваНесуществующихНаборовГруппДоступа(ПараметрыОбновления) + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаНаборов.НаборГруппДоступа КАК Набор + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.НаборГруппДоступа.Ссылка ЕСТЬ NULL + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаНаборов.Пользователь КАК Набор + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.Пользователь.Ссылка ЕСТЬ NULL + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаНаборов.ВнешнийПользователь КАК Набор + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.ВнешнийПользователь.Ссылка ЕСТЬ NULL"; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Выборка = РезультатыЗапроса[0].Выбрать(); + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Выборка.Набор, + "КлючиДоступаНаборовГруппДоступа", "НаборГруппДоступа"); + КонецЦикла; + + Выборка = РезультатыЗапроса[1].Выбрать(); + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Выборка.Набор, + "КлючиДоступаПользователей", "Пользователь"); + КонецЦикла; + + Выборка = РезультатыЗапроса[2].Выбрать(); + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Выборка.Набор, + "КлючиДоступаВнешнихПользователей", "ВнешнийПользователь"); + КонецЦикла; + +КонецПроцедуры + +// Для функции НаборыГруппДоступаДляОбновления. +Функция УстаревшиеНаборыГруппДоступаВСправочнике(ПараметрыОбновления, КоличествоВЗапросе) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ДатаУстаревания", ДатаУстаревания()); + Запрос.УстановитьПараметр("РазрешенныйПустойНабор", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.Ссылка КАК ТекущаяСсылка, + | НаборыГруппДоступа.ТипЭлементовНабора КАК ТипЭлементовНабора, + | ЛОЖЬ КАК Используется, + | ИСТИНА КАК Удалить + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ТипЭлементовНабора = НЕОПРЕДЕЛЕНО + | И &УточнениеПланаЗапроса + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | НаборыГруппДоступа.Ссылка, + | НаборыГруппДоступа.ТипЭлементовНабора, + | ЛОЖЬ, + | ИСТИНА + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И (ВЫРАЗИТЬ(НаборыГруппДоступа.Пользователь КАК Справочник.Пользователи).Ссылка ЕСТЬ NULL + | ИЛИ НаборыГруппДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(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) + | ИЛИ НаборыГруппПользователей.НеИспользуетсяС < &ДатаУстаревания + | КОНЕЦ"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + ЭлементыДанных = Запрос.Выполнить().Выгрузить(); + + КоличествоВЗапросе = ЭлементыДанных.Количество(); + Возврат ЭлементыДанных; + +КонецФункции + +// Для функций УстаревшиеНаборыГруппДоступаВСправочнике, ЭлементыДляОбновления. +Функция ДатаУстаревания() + + Возврат ТекущаяДатаСеанса() - КоличествоЧасовУстареванияНеиспользуемыхЭлементов() * 60 * 60; + +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбработатьУстаревшиеНаборыВСправочнике(ЭлементыДанных, ПараметрыОбновления) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + + Для Каждого Строка Из ЭлементыДанных Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + Если Строка.Используется Тогда + Объект.НеИспользуетсяС = '00010101'; + ИначеЕсли Не Строка.Удалить Тогда + Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); + Иначе + Объект.ТипЭлементовНабора = Неопределено; + Объект.Хеш = 0; + Объект.Группы.Очистить(); + КонецЕсли; + Объект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если Не Строка.Используется И Строка.Удалить Тогда + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаНаборовГруппДоступа", "НаборГруппДоступа"); + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаПользователей", "Пользователь"); + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаВнешнихПользователей", "ВнешнийПользователь"); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + Объект.Удалить(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры УдалитьУстаревшиеНаборыВСправочнике, ОчиститьПраваНесуществующихНаборовГруппДоступа. +Процедура УдалитьЗаписиРегистраДляНабора(Набор, ИмяРегистраСведений, ИмяПоляНабора) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Набор", Набор); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | КлючиДоступаНаборов.КлючДоступа КАК КлючДоступа + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.НаборГруппДоступа = &Набор"; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "КлючиДоступаНаборовГруппДоступа", ИмяРегистраСведений); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "НаборГруппДоступа", ИмяПоляНабора); + + ПолноеИмяРегистраСведений = "РегистрСведений." + ИмяРегистраСведений; + + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено; + + Пока Истина Цикл + Выгрузка = Запрос.Выполнить().Выгрузить(); + Если Выгрузка.Количество() = 0 Тогда + Прервать; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистраСведений); + ЭлементБлокировки.УстановитьЗначение(ИмяПоляНабора, Набор); + ЭлементБлокировки.ИсточникДанных = Выгрузка; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючДоступа", "КлючДоступа"); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраСведений]); + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляНабора]; // ЭлементОтбора + ЭлементОтбора.Установить(Набор); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Для Каждого Строка Из Выгрузка Цикл + Если ПакетныйРежим Тогда + СтараяЗапись = НаборЗаписей.Добавить(); + СтараяЗапись[ИмяПоляНабора] = Набор; + СтараяЗапись.КлючДоступа = Строка.КлючДоступа; + Иначе + НаборЗаписей.Отбор.КлючДоступа.Установить(Строка.КлючДоступа); + НаборЗаписей.Записать(); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОбновитьПраваНаРазрешенныйКлючДоступа(ЕстьИзменения = Ложь) + + ОбновитьГруппыДоступаРазрешенногоКлючаДоступа( , ЕстьИзменения); + +КонецПроцедуры + +// Для процедуры ОбновитьПраваНаРазрешенныйКлючДоступа. +Процедура ОбновитьГруппыДоступаРазрешенногоКлючаДоступа(ГруппыДоступа = Неопределено, ЕстьИзменения = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + РазрешенныйКлючДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа(); + РазрешенныйПустойНабор = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа(); + + Блокировка = Новый БлокировкаДанных; + + // Обновление групп доступа в регистре КлючиДоступаГруппДоступа. + ЗапросГрупп = Новый Запрос; + ЗапросГрупп.УстановитьПараметр("КлючДоступа", РазрешенныйКлючДоступа); + ЗапросГрупп.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); + ЗапросГрупп.Текст = ТекстЗапросаВыбораРазличийГруппДоступаРазрешенногоКлюча(); + УстановитьУсловиеОтбораВЗапросе(ЗапросГрупп, ГруппыДоступа, "ГруппыДоступа", + "&УсловиеОтбораГруппДоступа1:ГруппыДоступа.Ссылка + |&УсловиеОтбораГруппДоступа2:СтарыеДанные.ГруппаДоступа"); // @query-part-2 + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + ЭлементБлокировкиГрупп = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировкиГрупп.УстановитьЗначение("КлючДоступа", РазрешенныйКлючДоступа); + НаборЗаписейГрупп = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписейГрупп.Отбор.КлючДоступа.Установить(РазрешенныйКлючДоступа); + КонецЕсли; + + // Обновление наборов групп доступа в регистре КлючиДоступаНаборовГруппДоступа. + ЗапросПравДляГруппДоступа = Новый Запрос; + ЗапросПравДляГруппДоступа.УстановитьПараметр("КлючДоступа", РазрешенныйКлючДоступа); + ЗапросПравДляГруппДоступа.УстановитьПараметр("РазрешенныйПустойНабор", РазрешенныйПустойНабор); + ЗапросПравДляГруппДоступа.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа(); + + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", РазрешенныйКлючДоступа); + ПраваДляГруппДоступа = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + Если Не ПакетныйРежим Тогда + ПраваДляГруппДоступа.Отбор.КлючДоступа.Установить(РазрешенныйКлючДоступа); + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + РезультатЗапросаГрупп = ЗапросГрупп.Выполнить(); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаГрупп, + НаборЗаписейГрупп, "ГруппаДоступа", РазрешенныйКлючДоступа, ЕстьИзменения); + + РезультатЗапросаПравДляГруппДоступа = ЗапросПравДляГруппДоступа.Выполнить(); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаПравДляГруппДоступа, + ПраваДляГруппДоступа, "НаборГруппДоступа", РазрешенныйКлючДоступа, ЕстьИзменения); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ОбновитьГруппыРазрешенногоКлючаДоступа. +Функция ТекстЗапросаВыбораРазличийГруппДоступаРазрешенногоКлюча() + + ТекстЗапроса = + "ВЫБРАТЬ + | ВсеСтроки.ГруппаДоступа КАК ГруппаДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК ГруппаДоступа, + | ИСТИНА КАК ПравоИзменение, + | ИСТИНА КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + | ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка + | И (ГруппыДоступа.Профиль <> &ПрофильАдминистратор) + | И (НЕ ГруппыДоступа.ПометкаУдаления) + | И (НЕ ПрофилиГруппДоступа.ПометкаУдаления) + | И (&УсловиеОтбораГруппДоступа1) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ГДЕ + | УчастникиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка)) + | И (&УточнениеПланаЗапроса) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.ГруппаДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.КлючДоступа = &КлючДоступа + | И &УсловиеОтбораГруппДоступа2) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.ГруппаДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура УдалитьУстаревшиеЭлементыДанныхСписка(ЭлементыДанных, ПараметрыОбновления) + + Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда + УдалитьУстаревшиеЭлементыДанныхСсылочногоТипа(ЭлементыДанных, ПараметрыОбновления) + Иначе + УдалитьУстаревшиеЭлементыДанныхРегистров(ЭлементыДанных, ПараметрыОбновления) + КонецЕсли; + +КонецПроцедуры + +// Для процедуры УдалитьУстаревшиеЭлементыДанныхСписка. +Процедура УдалитьУстаревшиеЭлементыДанныхСсылочногоТипа(ЭлементыДанных, ПараметрыОбновления) + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + Если ПакетныйРежим Тогда + РазмерПорции = 1000; // Удаление N элементов данных по 1000 за раз. + Иначе + РазмерПорции = 100; // Удаление N элементов данных по 100 за раз. + КонецЕсли; + ПорцияЭлементовДанных = Неопределено; + КоличествоЭлементов = ЭлементыДанных.Количество(); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + НаборЗаписейДляУдаления = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + + Индекс = 0; + Пока Индекс < КоличествоЭлементов Цикл + Если ПорцияЭлементовДанных = Неопределено Тогда + ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); + ПорцияДляОбновления = ПорцияЭлементовДанных.Скопировать(); + ПорцияДляПроверки = ПорцияЭлементовДанных.Скопировать(); + КонецЕсли; + ЭлементДанных = ЭлементыДанных[Индекс]; + ЗаполнитьЗначенияСвойств(ПорцияЭлементовДанных.Добавить(), ЭлементДанных); + Если ЭлементДанных.Обновить Тогда + ЗаполнитьЗначенияСвойств(ПорцияДляОбновления.Добавить(), ЭлементДанных); + ИначеЕсли Не ЭлементДанных.Удалить Тогда // Не Обновить И Не Удалить. + ЗаполнитьЗначенияСвойств(ПорцияДляПроверки.Добавить(), ЭлементДанных); + КонецЕсли; + + Индекс = Индекс + 1; + Если ПорцияЭлементовДанных.Количество() < РазмерПорции И Индекс < КоличествоЭлементов Тогда + Продолжить; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); + ЭлементБлокировки.ИсточникДанных = ПорцияЭлементовДанных; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Объект", "ТекущаяСсылка"); + + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + ЗапросДляОбновления = Новый Запрос; + ЗапросДляОбновления.Текст = ПараметрыОбновления.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных; + ЗапросДляОбновления.УстановитьПараметр("ЭлементыДанных", ПорцияДляОбновления); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "ТекущаяСсылка"); + ЗапросДляПроверки = Новый Запрос; + ЗапросДляПроверки.Текст = ПараметрыОбновления.ТекстЗапросаПроверкиУстаревшихЭлементовДанных; + ЗапросДляПроверки.УстановитьПараметр("ЭлементыДанных", ПорцияДляПроверки); + УстановитьУточнениеПланаЗапроса(ЗапросДляПроверки.Текст); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляОбновления = ЗапросДляОбновления.Выполнить().Выгрузить(); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляУдаления = ЗапросДляПроверки.Выполнить().Выгрузить(); + КонецЕсли; + Для Каждого Строка Из ПорцияЭлементовДанных Цикл + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.Объект.Установить(Строка.ТекущаяСсылка); + КонецЕсли; + Если Строка.Обновить Тогда + Если Не ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + КонецЕсли; + НайденнаяСтрока = ДанныеДляОбновления.Найти(Строка.ТекущаяСсылка, "Объект"); + Если НайденнаяСтрока <> Неопределено Тогда + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + НайденнаяСтрока.КлючДоступаПользователей = Неопределено; + Иначе + НайденнаяСтрока.КлючДоступаВнешнихПользователей = Неопределено; + КонецЕсли; + Если ЗначениеЗаполнено(НайденнаяСтрока.КлючДоступаВнешнихПользователей) + Или ЗначениеЗаполнено(НайденнаяСтрока.КлючДоступаПользователей) Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НайденнаяСтрока); + ИначеЕсли ПакетныйРежим Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), НайденнаяСтрока); + КонецЕсли; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + КонецЕсли; + КонецЕсли; + ИначеЕсли Строка.Удалить + Или ЗначениеЗаполнено(ПорцияДляПроверки) + И ДанныеДляУдаления.Найти(Строка.ТекущаяСсылка, "ТекущаяСсылка") <> Неопределено Тогда + + Если ПакетныйРежим Тогда + НаборЗаписейДляУдаления.Добавить().Объект = Строка.ТекущаяСсылка; + Иначе + НаборЗаписей.Очистить(); + НаборЗаписей.Записать(); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим Тогда + Если ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + Если ЗначениеЗаполнено(НаборЗаписейДляУдаления) Тогда + НаборЗаписейДляУдаления.Записать(РежимУдаления); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + Если ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + НаборЗаписейДляУдаления.Очистить(); + КонецЕсли; + КоличествоОбработанных = ПорцияЭлементовДанных.Количество(); + ПорцияЭлементовДанных = Неопределено; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры УдалитьУстаревшиеЭлементыДанныхСписка. +Процедура УдалитьУстаревшиеЭлементыДанныхРегистров(ЭлементыДанных, ПараметрыОбновления) + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + Если ПакетныйРежим Тогда + РазмерПорции = 1000; // Удаление N элементов данных по 1000 за раз. + Иначе + РазмерПорции = 100; // Удаление N элементов данных по 100 за раз. + КонецЕсли; + + Если ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) + И ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных <> "НекорректныеЭлементыОбщегоРегистра" Тогда + + ИмяРегистра = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; + Иначе + ИмяРегистра = "КлючиДоступаКРегистрам"; + КонецЕсли; + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистра]); + НаборЗаписейДляУдаления = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистра]); + + ИзмеренияСпискаДляБлокировки = Новый Массив; + ОпорныеПоля = ПараметрыОбновления.ОпорныеПоля; + Если ОпорныеПоля = Неопределено Тогда + КоличествоИспользуемыхОпорныхПолей = 0; + МаксимальноеКоличествоОпорныхПолей = + УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистра); + Иначе + КоличествоИспользуемыхОпорныхПолей = ОпорныеПоля.Используемые.Количество(); + МаксимальноеКоличествоОпорныхПолей = ОпорныеПоля.МаксимальноеКоличество; + ОписаниеПолейБлокировки = УправлениеДоступомСлужебныйПовтИсп.ОписаниеПолейБлокировкиРегистра( + ПараметрыОбновления.Список); + ПоляБлокировкиСписка = СтрРазделить(ОписаниеПолейБлокировки.СписокПолей, ","); + БлокироватьСписокПоРегистратору = Ложь; + Номер = 1; + Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл + ИндексПоля = ПоляБлокировкиСписка.Найти(ИмяОпорногоПоля); + Если ИндексПоля <> Неопределено Тогда + ОписаниеПоля = ОписаниеПолейБлокировки.ОписаниеПолей.Получить(ИндексПоля); + ИзмерениеСписка = Новый Структура; + ИзмерениеСписка.Вставить("ИмяОпорногоПоля", ОписаниеПоля.Имя); + ИзмерениеСписка.Вставить("Тип", ОписаниеПоля.Тип); + ИзмерениеСписка.Вставить("ИмяПоля", СтрШаблон("Поле%1", Номер)); + ИзмеренияСпискаДляБлокировки.Добавить(ИзмерениеСписка); + Если ОписаниеПоля.Имя = "Регистратор" + И ОписаниеПолейБлокировки.БлокироватьПоРегистратору Тогда + БлокироватьСписокПоРегистратору = Истина; + КонецЕсли; + КонецЕсли; + Номер = Номер + 1; + КонецЦикла; + КонецЕсли; + ИменаИзмерений = Новый Массив; + Если ИмяРегистра = "КлючиДоступаКРегистрам" Тогда + ИменаИзмерений.Добавить("Регистр"); + КонецЕсли; + ИменаИзмерений.Добавить("ВариантДоступа"); + Для Номер = 1 По КоличествоИспользуемыхОпорныхПолей Цикл + ИменаИзмерений.Добавить(СтрШаблон("Поле%1", Номер)); + КонецЦикла; + + ОтборДанных = Новый Структура; + ТочныйОтборДанных = Новый Структура; + Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл + ОтборДанных.Вставить(ИмяИзмерения); + ТочныйОтборДанных.Вставить(ИмяИзмерения); + КонецЦикла; + Для Счетчик = Номер По МаксимальноеКоличествоОпорныхПолей Цикл + ТочныйОтборДанных.Вставить(СтрШаблон("Поле%1", Счетчик), + Перечисления.ДополнительныеЗначенияДоступа.Null); + КонецЦикла; + + ПорцияЭлементовДанных = Неопределено; + КоличествоЭлементов = ЭлементыДанных.Количество(); + + Индекс = 0; + Пока Индекс < КоличествоЭлементов Цикл + Если ПорцияЭлементовДанных = Неопределено Тогда + ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); + ПорцияДляОбновления = ПорцияЭлементовДанных.Скопировать(); + ПорцияДляПроверки = ПорцияЭлементовДанных.Скопировать(); + КонецЕсли; + ЭлементДанных = ЭлементыДанных[Индекс]; + ЗаполнитьЗначенияСвойств(ПорцияЭлементовДанных.Добавить(), ЭлементДанных); + Если ЭлементДанных.Обновить Тогда + ЗаполнитьЗначенияСвойств(ПорцияДляОбновления.Добавить(), ЭлементДанных); + ИначеЕсли Не ЭлементДанных.Удалить Тогда // Не Обновить И Не Удалить. + Для Каждого ИзмерениеСписка Из ИзмеренияСпискаДляБлокировки Цикл + Если Не ИзмерениеСписка.Тип.СодержитТип(ТипЗнч(ЭлементДанных[ИзмерениеСписка.ИмяПоля])) Тогда + ЭлементДанных.Удалить = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Если Не ЭлементДанных.Удалить Тогда + ЗаполнитьЗначенияСвойств(ПорцияДляПроверки.Добавить(), ЭлементДанных); + КонецЕсли; + КонецЕсли; + + Индекс = Индекс + 1; + Если ПорцияЭлементовДанных.Количество() < РазмерПорции И Индекс < КоличествоЭлементов Тогда + Продолжить; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистра); + ЭлементБлокировки.ИсточникДанных = ПорцияЭлементовДанных; + Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл + ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ИмяИзмерения, ИмяИзмерения); + КонецЦикла; + + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + ЗапросДляОбновления = Новый Запрос; + ЗапросДляОбновления.Текст = ПараметрыОбновления.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных; + ЗапросДляОбновления.УстановитьПараметр("ЭлементыДанных", ПорцияДляОбновления); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + Если БлокироватьСписокПоРегистратору Тогда + ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список + ".НаборЗаписей"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных( + ИзмеренияСпискаДляБлокировки[0].ИмяОпорногоПоля, + ИзмеренияСпискаДляБлокировки[0].ИмяПоля); + Иначе + ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + Если ЗначениеЗаполнено(ИзмеренияСпискаДляБлокировки) Тогда + ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; + Для Каждого ИзмерениеСписка Из ИзмеренияСпискаДляБлокировки Цикл + ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ИзмерениеСписка.ИмяОпорногоПоля, + ИзмерениеСписка.ИмяПоля); + КонецЦикла; + КонецЕсли; + КонецЕсли; + ЗапросДляПроверки = Новый Запрос; + ЗапросДляПроверки.Текст = ПараметрыОбновления.ТекстЗапросаПроверкиУстаревшихЭлементовДанных; + ЗапросДляПроверки.УстановитьПараметр("КлючиДоступаКРегистрам", ПорцияДляПроверки); + УстановитьУточнениеПланаЗапроса(ЗапросДляПроверки.Текст); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляОбновления = ЗапросДляОбновления.Выполнить().Выгрузить(); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляУдаления = ЗапросДляПроверки.Выполнить().Выгрузить(); + КонецЕсли; + Для Каждого Строка Из ПорцияЭлементовДанных Цикл + Если Не ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл + ЭлементОтбора = НаборЗаписей.Отбор[ИмяИзмерения]; // ЭлементОтбора + Если Строка[ИмяИзмерения] = Неопределено Тогда + ЭлементОтбора.Значение = Неопределено; + ЭлементОтбора.Использование = Истина; + Иначе + ЭлементОтбора.Установить(Строка[ИмяИзмерения]); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если Строка.Обновить Тогда + ЗаполнитьЗначенияСвойств(ОтборДанных, Строка); + НайденныеСтроки = ДанныеДляОбновления.НайтиСтроки(ОтборДанных); + Если Не ЗначениеЗаполнено(НайденныеСтроки) Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(ТочныйОтборДанных, ОтборДанных); + ТочноНайденныеСтроки = ДанныеДляОбновления.НайтиСтроки(ТочныйОтборДанных); + Если ТочноНайденныеСтроки.Количество() > 0 Тогда + НайденнаяСтрока = ТочноНайденныеСтроки.Получить(0); + Если Не ПакетныйРежим Тогда + Если НайденныеСтроки.Количество() = 1 Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НайденнаяСтрока); + КонецЕсли; + Иначе + НайденнаяСтрока = Неопределено; + НоваяЗапись = НаборЗаписей.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяЗапись, НайденныеСтроки[0]); + ЗаполнитьЗначенияСвойств(НоваяЗапись, ТочныйОтборДанных); + КонецЕсли; + Если ПакетныйРежим Тогда + Для Каждого УдаляемаяСтрока Из НайденныеСтроки Цикл + Если УдаляемаяСтрока <> НайденнаяСтрока Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), УдаляемаяСтрока); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ИначеЕсли Не Строка.Удалить И ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + ЗаполнитьЗначенияСвойств(ОтборДанных, Строка); + Если ДанныеДляУдаления.НайтиСтроки(ОтборДанных).Количество() = 0 Тогда + Продолжить; + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + ИначеЕсли Не Строка.Обновить Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), Строка); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим Тогда + Если ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + Если ЗначениеЗаполнено(НаборЗаписейДляУдаления) Тогда + НаборЗаписейДляУдаления.Записать(РежимУдаления); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + Если ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + НаборЗаписейДляУдаления.Очистить(); + КонецЕсли; + КоличествоОбработанных = ПорцияЭлементовДанных.Количество(); + ПорцияЭлементовДанных = Неопределено; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура УдалитьОбъектыНедопустимыхТиповВРегистреКлючиДоступаКОбъектам() + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) КАК ТипСсылки + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным"; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповСсылокДопустимыхОбъектов(); + Выборка = Запрос.Выполнить().Выбрать(); + + Запрос.Текст = + "ВЫБРАТЬ + | КлючиДоступаКДанным.Объект КАК Объект + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) = &Тип"; + + Пока Выборка.Следующий() Цикл + Если Выборка.ТипСсылки = Тип("Неопределено") Тогда + НаборЗаписей.Отбор.Объект.Установить(Неопределено); + НаборЗаписей.Записать(); + Продолжить; + ИначеЕсли ДопустимыеТипы.СодержитТип(Выборка.ТипСсылки) Тогда + Продолжить; + КонецЕсли; + Запрос.УстановитьПараметр("Тип", Выборка.ТипСсылки); + // @skip-check query-in-loop - Порционная обработка данных + Объекты = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Объект"); + Для Каждого Объект Из Объекты Цикл + НаборЗаписей.Отбор.Объект.Установить(Объект); + НаборЗаписей.Записать(); + КонецЦикла; + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = НЕОПРЕДЕЛЕНО"; + + Если Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКРегистрам); + НаборЗаписей.Отбор.Регистр.Установить(Неопределено); + НаборЗаписей.Записать(); + +КонецПроцедуры + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(ЭлементыДанных, ПараметрыОбновления) + + РазмерПорции = 100; // Загрузка N элементов данных по 100 за раз. + + Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда + ЭтоОбработкаСуществующихКомбинаций = Ложь; + ЭтоОбработкаНовыхКомбинаций = Ложь; + Иначе + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + ЭтоОбработкаСуществующихКомбинаций = ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами"; + ЭтоОбработкаНовыхКомбинаций = ПараметрыОбновления.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей + И ( ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" + Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей"); + КонецЕсли; + + Индекс = 0; + Пока Индекс < ЭлементыДанных.Количество() Цикл + + ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); + Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда + ПорцияЭлементовДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов("Число")); + ПорцияУдаляемыхЭлементовДанных = Новый Массив; + КонецЕсли; + КоличествоПропущенных = 0; + + Пока Индекс < ЭлементыДанных.Количество() + И ПорцияЭлементовДанных.Количество() < РазмерПорции + И (ПараметрыОбновления.ЭтоСсылочныйТип + Или ПорцияУдаляемыхЭлементовДанных.Количество() < РазмерПорции) Цикл + + ЭлементДанных = ЭлементыДанных[Индекс]; + + Если ЭтоОбработкаСуществующихКомбинаций + И НекорректнаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) Тогда + + Если ПорцияЭлементовДанных.Количество() > 0 Тогда + Прервать; + КонецЕсли; + ПорцияУдаляемыхЭлементовДанных.Добавить(ЭлементДанных); + + ИначеЕсли ЭтоОбработкаСуществующихКомбинаций + И ПорцияУдаляемыхЭлементовДанных.Количество() > 0 Тогда + Прервать; + + ИначеЕсли ЭтоОбработкаНовыхКомбинаций + И НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) Тогда + + КоличествоПропущенных = КоличествоПропущенных + 1; + Иначе + НоваяСтрока = ПорцияЭлементовДанных.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭлементДанных); + Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда + НоваяСтрока.ТекущаяСсылка = ПорцияЭлементовДанных.Индекс(НоваяСтрока) + 1; + КонецЕсли; + КонецЕсли; + Индекс = Индекс + 1; + КонецЦикла; + + Если ЭтоОбработкаСуществующихКомбинаций + И ПорцияУдаляемыхЭлементовДанных.Количество() > 0 Тогда + + УдалитьНекорректныеКомбинацииЗначенийОпорныхПолей(ПорцияУдаляемыхЭлементовДанных, ПараметрыОбновления); + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, ПорцияУдаляемыхЭлементовДанных.Количество()) Тогда + Прервать; + КонецЕсли; + КонецЕсли; + + Если ПорцияЭлементовДанных.Количество() > 0 Тогда + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ПорцияЭлементовДанных, ПараметрыОбновления); + КонецЕсли; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоПропущенных) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. +Функция НекорректнаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) + + Номер = 1; + Для Каждого ХранилищеТиповПоля Из ПараметрыОбновления.ОпорныеПоля.ТипыИспользуемых Цикл + ТипыПоля = ХранилищеТиповПоля.Получить(); + ИмяПоля = СтрШаблон("Поле%1", Номер); + + Если Не ТипыПоля.СодержитТип(ТипЗнч(ЭлементДанных[ИмяПоля])) + И ЭлементДанных[ИмяПоля] <> Неопределено Тогда + + Возврат Истина; + КонецЕсли; + + Номер = Номер + 1; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. +Функция НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) + + ТипыПолей = УправлениеДоступомСлужебныйПовтИсп.ТипыОпорныхПолейРегистра( + ПараметрыОбновления.ИмяОтдельногоРегистраКлючей); + + Для Номер = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл + ИмяПоля = СтрШаблон("Поле%1", Номер); + + Если Не ТипыПолей[ИмяПоля].СодержитТип(ТипЗнч(ЭлементДанных[ИмяПоля])) + И ЭлементДанных[ИмяПоля] <> Неопределено Тогда + + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции ДоступРазрешен. +Функция МодельОбъектовВПамяти(ОписаниеДанных, ПараметрыОграничения) + + Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда + Объекты = ОписаниеДанных; + Иначе + Объекты = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ОписаниеДанных); + КонецЕсли; + Объект = Объекты[0]; // СправочникОбъект + + ЭлементыДанных = Новый ТаблицаЗначений; + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипЗнч(Объект.Ссылка)))); + + Модель = Новый Структура; + Модель.Вставить("ЭлементыДанных", ЭлементыДанных); + Модель.Вставить("Таблицы", Новый Соответствие); + Модель.Вставить("КлючиДоступаКОбъектам", + РегистрыСведений.КлючиДоступаКОбъектам.СоздатьНаборЗаписей().Выгрузить()); + + ПоляТаблицОбъекта = ПараметрыОграничения.ПоляТаблицОбъекта; + + Для Каждого Объект Из Объекты Цикл + Объект = Объект; // СправочникОбъект + ТекущаяСсылка = ПользователиСлужебный.СсылкаОбъекта(ОписаниеДанных); + ЭлементыДанных.Добавить().ТекущаяСсылка = ТекущаяСсылка; + Для Каждого ОписаниеТаблицы Из ПоляТаблицОбъекта Цикл + ОписаниеТаблицы = ОписаниеТаблицы; // см. НовыеПоляТаблицыОбъекта + Таблица = Модель.Таблицы.Получить(ОписаниеТаблицы.ПолноеИмяТаблицы); // ТаблицаЗначений + СписокПолей = ОписаниеТаблицы.СписокПолей; + Если Таблица = Неопределено Тогда + Таблица = ОписаниеТаблицы.ТаблицаСПолями.Получить(); + Модель.Таблицы.Вставить(ОписаниеТаблицы.ПолноеИмяТаблицы, Таблица); + КонецЕсли; + Если ЗначениеЗаполнено(ОписаниеТаблицы.ТабличнаяЧасть) Тогда + Выгрузка = Объект[ОписаниеТаблицы.ТабличнаяЧасть].Выгрузить(, СписокПолей); // ТаблицаЗначений + Выгрузка.Свернуть(СписокПолей); + Для Каждого Строка Из Выгрузка Цикл + НоваяСтрока = Таблица.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка, СписокПолей); + НоваяСтрока.Ссылка = ТекущаяСсылка; + КонецЦикла; + Иначе + НоваяСтрока = Таблица.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Объект, СписокПолей); + НоваяСтрока.Ссылка = ТекущаяСсылка; + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Возврат Модель; + +КонецФункции + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами, ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи. +Процедура ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ПорцияЭлементовДанных, ПараметрыОбновления) + + ЭтоСсылочныйТип = ПараметрыОбновления.ЭтоСсылочныйТип; + ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; + + Контекст = Новый Структура; + Контекст.Вставить("ПорцияЭлементовДанных", ПорцияЭлементовДанных); + + ЗапросЗначенийЭлементовДанных = Новый Запрос; + Если ЭтоСсылочныйТип Тогда + Контекст.Вставить("СсылкиНаОбъекты", ПорцияЭлементовДанных.ВыгрузитьКолонку("ТекущаяСсылка")); + КонецЕсли; + Если ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда + Если ЭтоСсылочныйТип Тогда + ЗапросЗначенийЭлементовДанных.УстановитьПараметр("СсылкиНаОбъекты", Контекст.СсылкиНаОбъекты); + ИндексТаблицы = 0; + КонецЕсли; + Если ПараметрыОбновления.Свойство("МодельОбъектовВПамяти") Тогда + ЗапросЗначенийЭлементовДанных.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа; + Для Каждого Таблица Из ПараметрыОбновления.МодельОбъектовВПамяти.Таблицы Цикл + ЗапросЗначенийЭлементовДанных.УстановитьПараметр(Таблица.Ключ, Таблица.Значение); + КонецЦикла; + ИндексТаблицы = ПараметрыОбновления.МодельОбъектовВПамяти.Таблицы.Количество(); + Иначе + ЗапросЗначенийЭлементовДанных.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа; + Если Не ЭтоСсылочныйТип Тогда + ЗапросЗначенийЭлементовДанных.УстановитьПараметр("ИдентификаторРегистра", ИдентификаторСписка); + ЗапросЗначенийЭлементовДанных.УстановитьПараметр("ЗначенияОпорныхПолей", ПорцияЭлементовДанных); + ИндексТаблицы = 1; + КонецЕсли; + КонецЕсли; + УстановитьУточнениеПланаЗапроса(ЗапросЗначенийЭлементовДанных.Текст); + РезультатыЗапросаЗначенийЭлементов = ЗапросЗначенийЭлементовДанных.ВыполнитьПакет(); + Иначе + РезультатыЗапросаЗначенийЭлементов = Новый Массив; + КонецЕсли; + + ДанныеСтроковыхКлючейДоступа = Новый Соответствие; + ТаблицыКлюча = ПараметрыОбновления.ТаблицыКлюча; + + ЗначенияСтрокТаблиц = Новый Соответствие; + КлючиЗначенийСтрокОбъектов = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийЭлементов, + ИндексТаблицы, ТаблицыКлюча, ЗначенияСтрокТаблиц); + + ТребуемыеКлючиДоступа = Новый Массив; + ХешиТребуемыхКлючейДоступа = Новый Массив; + ОписаниеКлючейДоступаОбъектов = Новый Массив; + Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл + ОписаниеКлючейЗначений = КлючиЗначенийСтрокОбъектов.Получить(ЭлементДанных.ТекущаяСсылка); + СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); + Свойства = ДанныеСтроковыхКлючейДоступа.Получить(СтрокаДляХеша); + Если Свойства = Неопределено Тогда + Свойства = Новый Структура("ЗначенияТаблиц, СтрокаДляХеша, Хеш, КлючДоступа, ЗначенияКолонокТаблиц"); + ДанныеСтроковыхКлючейДоступа.Вставить(СтрокаДляХеша, Свойства); + ЗначенияТаблиц = Новый Массив; + Для Каждого ИмяТаблицы Из ТаблицыКлюча Цикл + КлючЗначений = ОписаниеКлючейЗначений.КлючиЗначений[ТаблицыКлюча.Найти(ИмяТаблицы)]; + ЗначенияСтрок = ЗначенияСтрокТаблиц.Получить(ИмяТаблицы).Получить(КлючЗначений); + Если ЗначенияСтрок = Неопределено Тогда + ЗначенияСтрок = Новый Массив; + КонецЕсли; + ЗначенияТаблиц.Добавить(Новый Структура("ИмяТаблицы, Таблица", ИмяТаблицы, ЗначенияСтрок)); + КонецЦикла; + Свойства.ЗначенияТаблиц = ЗначенияТаблиц; + Свойства.СтрокаДляХеша = СтрокаДляХеша; + Свойства.ЗначенияКолонокТаблиц = ОписаниеКлючейЗначений.ЗначенияКолонокТаблиц; + Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); + Хеширование.Добавить(СтрокаДляХеша); + Свойства.Хеш = Хеширование.ХешСумма; + ТребуемыеКлючиДоступа.Добавить(Свойства); + ХешиТребуемыхКлючейДоступа.Добавить(Свойства.Хеш); + КонецЕсли; + ОписаниеКлючейДоступаОбъектов.Добавить( + Новый Структура("ТекущаяСсылка, СвойстваКлюча", ЭлементДанных.ТекущаяСсылка, Свойства)); + КонецЦикла; + Контекст.Вставить("ОписаниеКлючейДоступаОбъектов", ОписаниеКлючейДоступаОбъектов); + + // Получение данных существующих ключей доступа по хешам требуемых ключей доступа. + ЗапросЗначенийКлючей = Новый Запрос; + ЗапросЗначенийКлючей.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения; + ЗапросЗначенийКлючей.УстановитьПараметр("Хеши", ХешиТребуемыхКлючейДоступа); + ЗапросЗначенийКлючей.УстановитьПараметр("Список", ИдентификаторСписка); + УстановитьУточнениеПланаЗапроса(ЗапросЗначенийКлючей.Текст); + РезультатыЗапросаЗначенийКлючей = ЗапросЗначенийКлючей.ВыполнитьПакет(); + + КлючиЗначенийСтрокКлючей = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийКлючей, + ?(Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) + Или СтрНачинаетсяС(ТаблицыКлюча[0], "Шапка"), 0, 1), + ТаблицыКлюча); + Выборка = РезультатыЗапросаЗначенийКлючей[0].Выбрать(); + + Пока Выборка.Следующий() Цикл + ОписаниеКлючейЗначений = КлючиЗначенийСтрокКлючей.Получить(Выборка.ТекущаяСсылка); + СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); + Свойства = ДанныеСтроковыхКлючейДоступа.Получить(СтрокаДляХеша); + Если Свойства <> Неопределено И Свойства.КлючДоступа = Неопределено Тогда + Свойства.КлючДоступа = Выборка.ТекущаяСсылка; + КонецЕсли; + КонецЦикла; + + // Создание недостающих ключей доступа. + ОписаниеНовыхКлючей = Новый Массив; + Для Каждого ОписаниеКлюча Из ТребуемыеКлючиДоступа Цикл + Если ОписаниеКлюча.КлючДоступа <> Неопределено Тогда + Продолжить; + КонецЕсли; + ОписаниеНовыхКлючей.Добавить(ОписаниеКлюча); + КонецЦикла; + Если ОписаниеНовыхКлючей.Количество() > 0 Тогда + ОбновитьПраваНаКлючиДоступа(ОписаниеНовыхКлючей, ПараметрыОбновления, Истина, Контекст); + Для Каждого ОписаниеКлюча Из ОписаниеНовыхКлючей Цикл + КлючДоступаОбъект = ОписаниеКлюча.КлючДоступаОбъект; // СправочникОбъект.КлючиДоступа + Если ЗначениеЗаполнено(КлючДоступаОбъект.Ссылка) Тогда + ОписаниеКлюча.КлючДоступа = КлючДоступаОбъект.Ссылка; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + // Обновление ключей доступа элементов данных. + Если ЭтоСсылочныйТип Тогда + Если ПараметрыОбновления.Свойство("МодельОбъектовВПамяти") Тогда + ИмяПоляКлюча = ?(ПараметрыОбновления.ДляВнешнихПользователей, + "КлючДоступаВнешнихПользователей", "КлючДоступаПользователей"); + КлючиДоступаКОбъектам = ПараметрыОбновления.МодельОбъектовВПамяти.КлючиДоступаКОбъектам; // РегистрСведенийНаборЗаписей + Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл + НоваяСтрока = КлючиДоступаКОбъектам.Добавить(); + НоваяСтрока.Объект = ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка; + НоваяСтрока[ИмяПоляКлюча] = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + КонецЦикла; + Иначе + ЗаписатьКлючиДоступаОбъектов(ПараметрыОбновления, Контекст); + КонецЕсли; + Иначе + ЗаписатьКлючиДоступаРегистров(ПараметрыОбновления, Контекст); + КонецЕсли; + + // Принудительное обновление прав вручную. + Если ПараметрыОбновления.Свойство("ОбновитьПраваНаКлючи") + И ПараметрыОбновления.ОбновитьПраваНаКлючи Тогда + + СуществующиеКлючиДоступа = Новый Массив; + Для Каждого ОписаниеКлюча Из ТребуемыеКлючиДоступа Цикл + Если ОписаниеНовыхКлючей.Найти(ОписаниеКлюча) <> Неопределено Тогда + Продолжить; + КонецЕсли; + СуществующиеКлючиДоступа.Добавить(ОписаниеКлюча.КлючДоступа); + КонецЦикла; + Если СуществующиеКлючиДоступа.Количество() > 0 Тогда + ОбновитьПраваНаКлючиДоступа(СуществующиеКлючиДоступа, ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка. +Процедура ОбновитьПраваНаКлючиДоступа(ОписаниеКлючей, ПараметрыОбновления, ЭтоНовыеКлючи = Ложь, Контекст = Неопределено) + + Если ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") Тогда + КоличествоОбработанных = ПараметрыОбновления.КоличествоОбработанныхЭлементов; + ПараметрыОбновления.КоличествоОбработанныхЭлементов = 0; + КонецЕсли; + + Если ЭтоНовыеКлючи Тогда + КлючиДоступа = Новый ТаблицаЗначений; + КлючиДоступа.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); + + ЗапросЗначенийКлючей = Новый Запрос; + ЗапросЗначенийКлючей.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения; + ЗапросЗначенийКлючей.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + УстановитьУточнениеПланаЗапроса(ЗапросЗначенийКлючей.Текст); + + ЗапросСуществованияКлючей = Новый Запрос; + ЗапросСуществованияКлючей.Текст = ПараметрыОбновления.ТекстЗапросаСуществованияКлючейДляСравнения; + ЗапросСуществованияКлючей.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + УстановитьУточнениеПланаЗапроса(ЗапросСуществованияКлючей.Текст); + + ОписаниеНовыхКлючей = Новый Структура; + ОписаниеНовыхКлючей.Вставить("ОписаниеКлючей", ОписаниеКлючей); + ОписаниеНовыхКлючей.Вставить("КлючиДоступа", КлючиДоступа); + ОписаниеНовыхКлючей.Вставить("ЗначенияТаблиц", Новый Структура); + ОписаниеНовыхКлючей.Вставить("ОписанияКлючейПоСсылке", Новый Соответствие); + ОписаниеНовыхКлючей.Вставить("ЗапросЗначенийКлючей", ЗапросЗначенийКлючей); + ОписаниеНовыхКлючей.Вставить("ЗапросСуществованияКлючей", ЗапросСуществованияКлючей); + + ДопустимыеТипыЗначений = УправлениеДоступомСлужебныйПовтИсп.ДопустимыеТипыЗначенийКлючейДоступа(); + ЗначенияТаблиц = ОписаниеНовыхКлючей.ЗначенияТаблиц; + + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + ТаблицаЗначений = ЗначенияТаблицыКлюча(); + ТаблицаЗначений.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); + ПоляТаблицы = ПараметрыОбновления.РеквизитыТаблицКлюча.Получить(ТаблицаКлюча); + Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") И ТаблицаКлюча <> "Шапка0" Тогда + ТаблицаЗначений.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число")); + КонецЕсли; + Для Каждого Поле Из ПоляТаблицы Цикл + ТаблицаЗначений.Колонки.Добавить(Поле, ДопустимыеТипыЗначений); + КонецЦикла; + ЗначенияТаблиц.Вставить(ТаблицаКлюча, ТаблицаЗначений); + КонецЦикла; + + Для Каждого ОписаниеКлюча Из ОписаниеКлючей Цикл + ПроверитьТипЗначенийКлючаДоступа(ОписаниеКлюча, ДопустимыеТипыЗначений, ПараметрыОбновления); + ПодготовитьНовыйКлючДоступа(ОписаниеКлюча, ОписаниеНовыхКлючей, ПараметрыОбновления); + КонецЦикла; + ОписаниеКлючейДоступа = ОписаниеНовыхКлючей; + Иначе + ОписаниеКлючейДоступа = Новый ТаблицаЗначений; + ОписаниеКлючейДоступа.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); + Для Каждого КлючДоступаСсылка Из ОписаниеКлючей Цикл + ОписаниеКлючейДоступа.Добавить().Ссылка = КлючДоступаСсылка; + КонецЦикла; + КонецЕсли; + + ОбновитьПраваПорцииКлючейДоступаСписка(ОписаниеКлючейДоступа, ПараметрыОбновления, ЭтоНовыеКлючи); + + Если ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") Тогда + ПараметрыОбновления.КоличествоОбработанныхЭлементов = КоличествоОбработанных; + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Ссылка - СправочникСсылка.КлючиДоступа +// * НомерСтроки - Число - номер строки табличной части +// +Функция ЗначенияТаблицыКлюча() + + Возврат Новый ТаблицаЗначений; + +КонецФункции + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка. +Функция СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча) + + Если ОписаниеКлючейЗначений = Неопределено Тогда + ОписаниеКлючейЗначений = Новый Структура( + "КлючиЗначений, ИменаТаблиц, ЗначенияКолонокТаблиц", + Новый Массив, Новый Массив, Новый Массив); + КонецЕсли; + + КлючиЗначений = ОписаниеКлючейЗначений.КлючиЗначений; + ИменаТаблиц = ОписаниеКлючейЗначений.ИменаТаблиц; + + Если ИменаТаблиц.Количество() <> ТаблицыКлюча.Количество() Тогда + // В ключе доступа используются табличные части и некоторые пустые. + Для Индекс = 0 По ТаблицыКлюча.Количество() - 1 Цикл + + Если Индекс >= ИменаТаблиц.Количество() + Или ИменаТаблиц[Индекс] <> ТаблицыКлюча[Индекс] Тогда + + ИменаТаблиц.Вставить(Индекс, ТаблицыКлюча[Индекс]); + КлючиЗначений.Вставить(Индекс, "6ab8db6a-4878-483a-b9d5-ef905ff1537e"); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат СтрСоединить(КлючиЗначений); + +КонецФункции + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ЗаписатьКлючиДоступаОбъектов(ПараметрыОбновления, Контекст) + + ЗаписыватьТолькоИзмененные = ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных(); + + Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей + Или ЗаписыватьТолькоИзмененные Тогда + + ЗапросТекущихКлючей = Новый Запрос; + ЗапросТекущихКлючей.Текст = + "ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК Объект, + | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, + | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | КлючиДоступаКОбъектам.Объект В (&СсылкиНаОбъекты)"; + ЗапросТекущихКлючей.УстановитьПараметр("СсылкиНаОбъекты", Контекст.СсылкиНаОбъекты); + КонецЕсли; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ИмяРеквизитаСохраняемогоКлюча = "КлючДоступаПользователей"; + ИмяРеквизитаОбновляемогоКлюча = "КлючДоступаВнешнихПользователей"; + Иначе + ИмяРеквизитаСохраняемогоКлюча = "КлючДоступаВнешнихПользователей"; + ИмяРеквизитаОбновляемогоКлюча = "КлючДоступаПользователей"; + КонецЕсли; + + ОбъектТип = Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект.Тип; + Если Не ОбъектТип.СодержитТип(ТипЗнч(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка)) Тогда + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно обновить ключ доступа объекта ""%1"" типа ""%2"", + |так как тип ""%3"" не указан в определяемом типе ""%4"".'"), + Строка(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка), + Строка(ТипЗнч(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка)), + ИмяТипаСсылки(ПараметрыОбновления.Список, ТипыТаблицПоИменам), + "ВладелецЗначенийКлючейДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ЗаписыватьТолькоИзмененные Тогда + ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); + ТекущиеКлючиДоБлокировки = ЗапросТекущихКлючей.Выполнить().Выгрузить(); + ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); + КонецЕсли; + + КоличествоОбработанных = 0; + ОписаниеКлючейДоступаОбъектов = Новый Массив; + + Блокировка = Новый БлокировкаДанных; + Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл + КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + Если КлючДоступа = Неопределено Тогда + Прервать; + КонецЕсли; + Если ЗаписыватьТолькоИзмененные Тогда + Строка = ТекущиеКлючиДоБлокировки.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "Объект"); + Если Строка <> Неопределено И Строка[ИмяРеквизитаОбновляемогоКлюча] = КлючДоступа Тогда + КоличествоОбработанных = КоличествоОбработанных + 1; + Продолжить; + КонецЕсли; + КонецЕсли; + ОписаниеКлючейДоступаОбъектов.Добавить(ОписаниеКлючаДоступаОбъекта); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); + ЭлементБлокировки.УстановитьЗначение("Объект", ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); + КонецЦикла; + + Если ОписаниеКлючейДоступаОбъектов.Количество() = 0 Тогда + ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных); + Возврат; + КонецЕсли; + + СпискиДляОбновления = Новый Структура("ИменаСписков, ДляВнешнихПользователей", + ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа, + ПараметрыОбновления.ДляВнешнихПользователей); + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, + ПараметрыОбновления.ИдентификаторТранзакции, "ЗаполнитьКэшПараметровОграниченияДоступа"); + КонецЕсли; + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + ПакетныйРежим = РежимСлияния <> Неопределено; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + Если Не ПакетныйРежим Тогда + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + ПередБлокировкойДанных(ПараметрыОбновления); + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + Блокировка.Заблокировать(); + ПослеБлокировкиДанных(ПараметрыОбновления); + + Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей Тогда + ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); + ТекущиеКлючи = ЗапросТекущихКлючей.Выполнить().Выгрузить(); + ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); + КонецЕсли; + + ПередЗаписьюСтрок(ПараметрыОбновления); + СсылкиНаОбъекты = Новый Массив; + Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл + СсылкиНаОбъекты.Добавить(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.Объект.Установить(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); + Иначе + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + Запись.Объект = ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка; + Запись[ИмяРеквизитаОбновляемогоКлюча] = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + + Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей Тогда + Строка = ТекущиеКлючи.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "Объект"); + Если Строка <> Неопределено Тогда + Запись[ИмяРеквизитаСохраняемогоКлюча] = Строка[ИмяРеквизитаСохраняемогоКлюча]; + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + ПослеЗаписиСтрок(ПараметрыОбновления, ОписаниеКлючейДоступаОбъектов.Количество()); + + ПередПланированиемОбновления(ПараметрыОбновления); + ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, + ПараметрыОбновления.ИдентификаторТранзакции, + "ЗаписатьКлючиДоступаОбъектов", + ?(СсылкиНаОбъекты.Количество() > 25, Неопределено, + Новый Структура("ПоКлючамДоступа", СсылкиНаОбъекты)), + ПараметрыОбновления.Свойство("ЭтоФоновоеОбновлениеДоступа")); + ПослеПланированияОбновления(ПараметрыОбновления); + + // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, + // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), + // а в режиме анализа производительности последствия учитываются и не являются критичными. + ПередФиксациейТранзакции(ПараметрыОбновления); + ЗафиксироватьТранзакцию(); + ПослеФиксацииТранзакции(ПараметрыОбновления); + // АПК:330-вкл. + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + КоличествоОбработанных = КоличествоОбработанных + ОписаниеКлючейДоступаОбъектов.Количество(); + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Возврат; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ЗаписатьКлючиДоступаРегистров(ПараметрыОбновления, Контекст) + + ПорцияЭлементовДанных = Контекст.ПорцияЭлементовДанных; + + ЗаписыватьТолькоИзмененные = ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных(); + Если ЗаписыватьТолькоИзмененные Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); + ТекстЗапроса = ПараметрыОбновления.ТекстЗапросаТекущихКлючейДоступаРегистра; + ТекстыПакета = Новый Массив; + НомерСтроки = 1; + Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл + ТекущийНомер = "_" + Формат(НомерСтроки, "ЧГ="); + ТекстыПакета.Добавить(СтрЗаменить(ТекстЗапроса, "_%1", ТекущийНомер)); + Для НомерПоля = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); + Запрос.УстановитьПараметр(ИмяПоля + ТекущийНомер, ЭлементДанных[ИмяПоля]); + КонецЦикла; + НомерСтроки = НомерСтроки + 1; + КонецЦикла; + Запрос.Текст = СтрСоединить(ТекстыПакета, ОбщегоНазначения.РазделительПакетаЗапросов()); + ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); + Если ТекстыПакета.Количество() > 1 Тогда + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Иначе + РезультатыЗапроса = Новый Массив; + РезультатыЗапроса.Добавить(Запрос.Выполнить()); + КонецЕсли; + ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; + Иначе + ИмяРегистраКлючей = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; + КонецЕсли; + + КоличествоОбработанных = 0; + ОписаниеКлючейДоступаОбъектов = Новый Массив; + + ИндексРезультата = -1; + Блокировка = Новый БлокировкаДанных; + Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл + ИндексРезультата = ИндексРезультата + 1; + КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + Если КлючДоступа = Неопределено Тогда + Прервать; + КонецЕсли; + Если ЗаписыватьТолькоИзмененные Тогда + РезультатЗапроса = РезультатыЗапроса[ИндексРезультата]; + Если Не РезультатЗапроса.Пустой() Тогда + Выгрузка = РезультатЗапроса.Выгрузить(); + Если Выгрузка.Количество() = 1 И Выгрузка[0].КлючДоступа = КлючДоступа Тогда + КоличествоОбработанных = КоличествоОбработанных + 1; + Продолжить; + КонецЕсли; + КонецЕсли; + КонецЕсли; + ОписаниеКлючейДоступаОбъектов.Добавить(ОписаниеКлючаДоступаОбъекта); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраКлючей); + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ЭлементБлокировки.УстановитьЗначение("Регистр", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + ЭлементБлокировки.УстановитьЗначение("ВариантДоступа", ПараметрыОбновления.ВариантДоступа); + ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); + Для НомерПоля = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементБлокировки.УстановитьЗначение(ИмяПоля, ЭлементДанных[ИмяПоля]); + КонецЦикла; + КонецЦикла; + + Если ОписаниеКлючейДоступаОбъектов.Количество() = 0 Тогда + ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных); + Возврат; + КонецЕсли; + + ПустыеЗначенияОпорныхПолей = УправлениеДоступомСлужебныйПовтИсп.ПустыеЗначенияОпорныхПолей( + ПараметрыОбновления.ОпорныеПоля.МаксимальноеКоличество); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + ПакетныйРежим = РежимСлияния <> Неопределено; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраКлючей]); + Если Не ПакетныйРежим Тогда + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + + Если Не ПакетныйРежим Тогда + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + НаборЗаписей.Отбор.Регистр.Установить(ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + НаборЗаписей.Отбор.ВариантДоступа.Установить(ПараметрыОбновления.ВариантДоступа); + КонецЕсли; + КоличествоИспользуемыхПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); + + НачатьТранзакцию(); + Попытка + ПередБлокировкойДанных(ПараметрыОбновления); + Блокировка.Заблокировать(); + ПослеБлокировкиДанных(ПараметрыОбновления); + + ПередЗаписьюСтрок(ПараметрыОбновления); + Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл + Если ПакетныйРежим Тогда + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + Запись.Регистр = ПараметрыОбновления.ИдентификаторСписка; + КонецЕсли; + Запись.ВариантДоступа = ПараметрыОбновления.ВариантДоступа; + + ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); + ЗаполнитьЗначенияСвойств(Запись, ПустыеЗначенияОпорныхПолей); + Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоля]; // ЭлементОтбора + Если ЭлементДанных[ИмяПоля] = Неопределено Тогда + ЭлементОтбора.Значение = Неопределено; + ЭлементОтбора.Использование = Истина; + Иначе + ЭлементОтбора.Установить(ЭлементДанных[ИмяПоля]); + КонецЕсли; + КонецЕсли; + Запись[ИмяПоля] = ЭлементДанных[ИмяПоля]; + КонецЦикла; + + Запись.КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + ПослеЗаписиСтрок(ПараметрыОбновления, ОписаниеКлючейДоступаОбъектов.Количество()); + + // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, + // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), + // а в режиме анализа производительности последствия учитываются и не являются критичными. + ПередФиксациейТранзакции(ПараметрыОбновления); + ЗафиксироватьТранзакцию(); + ПослеФиксацииТранзакции(ПараметрыОбновления); + // АПК:330-вкл. + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + КоличествоОбработанных = КоличествоОбработанных + ОписаниеКлючейДоступаОбъектов.Количество(); + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Возврат; + КонецЕсли; + +КонецПроцедуры + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. +Процедура УдалитьНекорректныеКомбинацииЗначенийОпорныхПолей(ПорцияЭлементовДанных, ПараметрыОбновления) + + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; + Иначе + ИмяРегистраКлючей = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; + КонецЕсли; + НаборИзОднойЗаписи = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраКлючей]); + КоличествоИспользуемыхПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); + + Блокировка = Новый БлокировкаДанных; + Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраКлючей); + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ЭлементБлокировки.УстановитьЗначение("Регистр", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + ЭлементБлокировки.УстановитьЗначение("ВариантДоступа", ПараметрыОбновления.ВариантДоступа); + Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементБлокировки.УстановитьЗначение(ИмяПоля, ЭлементДанных[ИмяПоля]); + КонецЦикла; + КонецЦикла; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + НаборИзОднойЗаписи.Отбор.Регистр.Установить(ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + НаборИзОднойЗаписи.Отбор.ВариантДоступа.Установить(ПараметрыОбновления.ВариантДоступа); + Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементОтбора = НаборИзОднойЗаписи.Отбор[ИмяПоля]; // ЭлементОтбора + Если ЭлементДанных[ИмяПоля] = Неопределено Тогда + ЭлементОтбора.Значение = Неопределено; + ЭлементОтбора.Использование = Истина; + Иначе + ЭлементОтбора.Установить(ЭлементДанных[ИмяПоля]); + КонецЕсли; + КонецЦикла; + НаборИзОднойЗаписи.Записать(); + КонецЦикла; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Функция КлючиЗначенийСтрокОбъектов(РезультатыЗапроса, Индекс, ТаблицыКлюча, ЗначенияСтрокТаблиц = Неопределено) + + КлючиЗначенийСтрокОбъектов = Новый Соответствие; + + Если ЗначенияСтрокТаблиц = Неопределено Тогда + ЗначенияСтрокТаблиц = Новый Соответствие; + КонецЕсли; + + Для Каждого ИмяТаблицыКлючаДоступа Из ТаблицыКлюча Цикл + ЗначенияСтрокТаблицы = ЗначенияСтрокТаблиц.Получить(ИмяТаблицыКлючаДоступа); + Если ЗначенияСтрокТаблицы = Неопределено Тогда + ЗначенияСтрокТаблицы = Новый Соответствие; + ЗначенияСтрокТаблиц.Вставить(ИмяТаблицыКлючаДоступа, ЗначенияСтрокТаблицы); + КонецЕсли; + Дерево = РезультатыЗапроса[Индекс].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Индекс = Индекс + 1; + Для Каждого Строка Из Дерево.Строки Цикл + ЗначенияКолонокТаблицы = Новый Массив; + Для Каждого Колонка Из Дерево.Колонки Цикл + Если СтрНачинаетсяС(Колонка.Имя, "Значение") Тогда + ЗначенияКолонокТаблицы.Добавить(Строка.Строки.ВыгрузитьКолонку(Колонка.Имя)); + КонецЕсли; + КонецЦикла; + КлючЗначенийСтрок = СтрокаДанныхДляХеширования(ЗначенияКолонокТаблицы); + Если ЗначенияСтрокТаблицы.Получить(КлючЗначенийСтрок) = Неопределено Тогда + ЗначенияСтрокТаблицы.Вставить(КлючЗначенийСтрок, Строка.Строки); + КонецЕсли; + ОписаниеКлючейЗначений = КлючиЗначенийСтрокОбъектов.Получить(Строка.ТекущаяСсылка); + Если ОписаниеКлючейЗначений = Неопределено Тогда + ОписаниеКлючейЗначений = Новый Структура( + "КлючиЗначений, ИменаТаблиц, ЗначенияКолонокТаблиц", + Новый Массив, Новый Массив, Новый Массив); + КлючиЗначенийСтрокОбъектов.Вставить(Строка.ТекущаяСсылка, ОписаниеКлючейЗначений); + КонецЕсли; + ОписаниеКлючейЗначений.ИменаТаблиц.Добавить(ИмяТаблицыКлючаДоступа); + ОписаниеКлючейЗначений.КлючиЗначений.Добавить(КлючЗначенийСтрок); + ОписаниеКлючейЗначений.ЗначенияКолонокТаблиц.Добавить(ЗначенияКолонокТаблицы); + КонецЦикла; + КонецЦикла; + + Возврат КлючиЗначенийСтрокОбъектов; + +КонецФункции + +// Для функции КлючиЗначенийСтрокОбъектов и др. +Функция СтрокаДанныхДляХеширования(Данные) + + // Возвращает строку данных для последующего хеширования, например, + // строковое описание ссылок, сохраняемых в базе данных, с учетом типов + // по внутренним идентификаторам, что обеспечивает неизменность хеш-суммы + // при изменении имен таблиц и имен реквизитов, то есть обеспечивает + // соответствие хеш-суммы данных самим данным, сохраняемым в базе данных. + // + // Это позволяет избежать избыточного массового пересоздания ключей доступа с последующим + // перерасчетом пользователей и групп доступа для пересозданных ключей доступа. + + Возврат ЗначениеВСтрокуВнутр(Данные); + +КонецФункции + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ПроверитьТипЗначенийКлючаДоступа(ОписаниеКлюча, ДопустимыеТипыЗначений, ПараметрыОбновления) + + ЗначенияКолонокТаблиц = ОписаниеКлюча.ЗначенияКолонокТаблиц; + + Для Каждого ЗначенияКолонокТаблицы Из ЗначенияКолонокТаблиц Цикл + Для Каждого ЗначенияКолонкиТаблицы Из ЗначенияКолонокТаблицы Цикл + Для Каждого Значение Из ЗначенияКолонкиТаблицы Цикл + Если Не ДопустимыеТипыЗначений.СодержитТип(ТипЗнч(Значение)) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно сохранить значение ""%1"" типа ""%2"" + |при обновлении ключей доступа списка ""%3"", + |так как этот тип не указан в определяемом типе %4.'"), + Строка(Значение), + Строка(ТипЗнч(Значение)), + ПараметрыОбновления.Список, + "ЗначениеДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЦикла; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ПодготовитьНовыйКлючДоступа(ОписаниеКлюча, ОписаниеНовыхКлючей, ПараметрыОбновления) + + НоваяСсылка = Справочники.КлючиДоступа.ПолучитьСсылку(); + НовыйКлюч = СлужебныйЭлемент(Справочники.КлючиДоступа); // СправочникОбъект.КлючиДоступа + + НовыйКлюч.УстановитьСсылкуНового(НоваяСсылка); + НовыйКлюч.Наименование = Строка(НоваяСсылка.УникальныйИдентификатор()); + НовыйКлюч.Список = ПараметрыОбновления.ИдентификаторСписка; + НовыйКлюч.СоставПолей = ПараметрыОбновления.СоставПолей; + НовыйКлюч.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + НовыйКлюч.Хеш = ОписаниеКлюча.Хеш; + + ВсеЗначенияТаблиц = ОписаниеНовыхКлючей.ЗначенияТаблиц; + + Для Каждого ЗначенияТаблицы Из ОписаниеКлюча.ЗначенияТаблиц Цикл + ВсеЗначенияТаблицы = ВсеЗначенияТаблиц[ЗначенияТаблицы.ИмяТаблицы]; // См. ЗначенияТаблицыКлюча + + Если СтрНачинаетсяС(ЗначенияТаблицы.ИмяТаблицы, "Шапка") Тогда + НоваяСтрока = ВсеЗначенияТаблицы.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ЗначенияТаблицы.Таблица[0]); + НоваяСтрока.Ссылка = НоваяСсылка; + + Если СтрЗаканчиваетсяНа(ЗначенияТаблицы.ИмяТаблицы, "0") Тогда + ЗаполнитьЗначенияСвойств(НовыйКлюч, ЗначенияТаблицы.Таблица[0],, "Родитель"); + Иначе + НомерСтроки = Число(Прав(ЗначенияТаблицы.ИмяТаблицы, 1)); + НовыйКлюч.Шапка.Добавить(); + ЗаполнитьЗначенияСвойств(НовыйКлюч.Шапка[НомерСтроки - 1], ЗначенияТаблицы.Таблица[0]); + НоваяСтрока.НомерСтроки = НомерСтроки; + КонецЕсли; + Иначе + Для Каждого Строка Из ЗначенияТаблицы.Таблица Цикл + ТабличнаяЧастьКлюча = НовыйКлюч[ЗначенияТаблицы.ИмяТаблицы]; // ТабличнаяЧасть + ЗаполнитьЗначенияСвойств(ТабличнаяЧастьКлюча.Добавить(), Строка); + НоваяСтрока = ВсеЗначенияТаблицы.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); + НоваяСтрока.Ссылка = НоваяСсылка; + КонецЦикла; + КонецЕсли; + КонецЦикла; + + ОписаниеКлюча.Вставить("КлючДоступаОбъект", НовыйКлюч); + ОписаниеНовыхКлючей.КлючиДоступа.Добавить().Ссылка = НоваяСсылка; + ОписаниеНовыхКлючей.ОписанияКлючейПоСсылке.Вставить(НоваяСсылка, ОписаниеКлюча); + +КонецПроцедуры + +// Для процедур ОбновитьПорциюЭлементов, ОбновитьПраваНаКлючиДоступа. +Процедура ОбновитьПраваПорцииКлючейДоступаСписка(ОписаниеКлючейДоступа, ПараметрыОбновления, ЭтоНовыеКлючи = Ложь) + + Если Не ПараметрыОбновления.Свойство("Кэш") Тогда + ПараметрыОбновления.Вставить("Кэш", Новый Структура); + КонецЕсли; + КлючиДоступа = ?(ЭтоНовыеКлючи, ОписаниеКлючейДоступа.КлючиДоступа, ОписаниеКлючейДоступа); + + Если ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда + Запрос = Новый Запрос; + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав; + НомерТаблицы = 0; + + Если ЭтоНовыеКлючи Тогда + ТекстыЗапроса = Новый Массив; + РеквизитыТаблицКлюча = ПараметрыОбновления.РеквизитыТаблицКлюча; + Шаблон = + "ВЫБРАТЬ + | &Поля + |ПОМЕСТИТЬ Таблица + |ИЗ + | &Таблица КАК Таблица"; + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + ПолеНомерСтроки = ""; + Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") Тогда + Если СтрЗаканчиваетсяНа(ТаблицаКлюча, "0") Тогда + ИмяВременнойТаблицы = "СправочникКлючиДоступа"; + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "@Справочник.КлючиДоступа ", ИмяВременнойТаблицы + " "); + Иначе + ИмяВременнойТаблицы = "СправочникКлючиДоступа" + ТаблицаКлюча; + ПолеНомерСтроки = "НомерСтроки, "; // @query-part-1 + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "@Справочник.КлючиДоступа.Шапка КАК " + ТаблицаКлюча, + ИмяВременнойТаблицы + " КАК " + ТаблицаКлюча); // @query-part-1, @query-part-2 + КонецЕсли; + Иначе + ИмяВременнойТаблицы = "СправочникКлючиДоступа" + ТаблицаКлюча; + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "@Справочник.КлючиДоступа." + ТаблицаКлюча, ИмяВременнойТаблицы); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(Шаблон, "Таблица", ИмяВременнойТаблицы); + РеквизитыТаблицы = РеквизитыТаблицКлюча.Получить(ТаблицаКлюча); + Поля = "Ссылка, " + ПолеНомерСтроки + СтрСоединить(РеквизитыТаблицы, ", "); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Поля", Поля); + ТекстыЗапроса.Добавить(ТекстЗапроса); + Запрос.УстановитьПараметр(ИмяВременнойТаблицы, ОписаниеКлючейДоступа.ЗначенияТаблиц[ТаблицаКлюча]); + НомерТаблицы = НомерТаблицы + 1; + КонецЦикла; + ТекстыЗапроса.Добавить(Запрос.Текст); + Запрос.Текст = СтрСоединить(ТекстыЗапроса, ОбщегоНазначения.РазделительПакетаЗапросов()); + Иначе + Запрос.Текст = СтрЗаменить(Запрос.Текст, "@Справочник.КлючиДоступа", "Справочник.КлючиДоступа"); + КонецЕсли; + Запрос.УстановитьПараметр("КлючиДоступа", КлючиДоступа); + + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОбновления.ИдентификаторТаблицыНастроекПрав); + + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Иначе + РезультатыЗапроса = Новый Массив; + КонецЕсли; + + ПараметрыОбновления.Вставить("ТипПользователя", ?(ПараметрыОбновления.ДляВнешнихПользователей, + Тип("СправочникСсылка.ВнешниеПользователи"), Тип("СправочникСсылка.Пользователи"))); + + ПараметрыОбновления.Вставить("ТипГруппыПользователей", ?(ПараметрыОбновления.ДляВнешнихПользователей, + Тип("СправочникСсылка.ГруппыВнешнихПользователей"), Тип("СправочникСсылка.ГруппыПользователей"))); + + ПараметрыОбновления.Вставить("ТипГруппыДоступа", Тип("СправочникСсылка.ГруппыДоступа")); + ПараметрыОбновления.Вставить("ПустаяГруппаДоступа", Справочники.ГруппыДоступа.ПустаяСсылка()); + + ЗначенияТаблицКлючей = НовыеЗначенияТаблицКлючей(); + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + НомерТаблицы = НомерТаблицы + 1; + ЗначенияТаблицКлючей.Вставить(ТаблицаКлюча, + РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам)); + КонецЦикла; + ЗаполнитьПраваНаВедущиеКлючиДоступаИВедущиеСписки(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления); + ЗаполнитьПраваПоВладельцамНастроекПрав(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления); + + КэшРасчетаПрав = КэшРасчетаПравДляВидаПользователей(ПараметрыОбновления.ДляВнешнихПользователей); + Если Не ПараметрыОбновления.Кэш.Свойство("ПраваРолейФункцииПравоДоступа") + Или КэшРасчетаПрав.РолиПрофилейГруппДоступа = Неопределено Тогда + ПараметрыОбновления.Кэш.Вставить("ПраваРолейФункцииПравоДоступа", Новый Соответствие); + ПараметрыОбновления.Кэш.Вставить("ОбъектыМетаданныхФункцииПравоДоступа", Новый Соответствие); + ПараметрыОбновления.Кэш.Вставить("ПраваПрофилейФункцииПравоДоступа", Новый Соответствие); + КонецЕсли; + + ЗаполнитьПраваГруппДоступаСписка(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьЗначенияГруппДоступаДляРасчетаПрав(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьПользователейГруппПользователей(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьУчастниковГруппДоступаСписка(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьГруппыПользователейКакЗначенияДоступа(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьРолиИГруппыДоступаПрофилей(ПараметрыОбновления, КэшРасчетаПрав); + + ЗначенияПервойТаблицы = ?(ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей), + ЗначенияТаблицКлючей.Получить(ПараметрыОбновления.ТаблицыКлюча[0]), + Новый Структура("Строки", КлючиДоступа)); + ИндексПоследнегоКлюча = ЗначенияПервойТаблицы.Строки.Количество() - 1; + + Для ИндексКлюча = 0 По ИндексПоследнегоКлюча Цикл + ЗначенияТаблицКлюча = НовыеЗначенияТаблицКлюча(); + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + ЗначенияТаблицы = ЗначенияТаблицКлючей.Получить(ТаблицаКлюча).Строки[ИндексКлюча].Строки; + Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") Тогда + ЗначенияТаблицы = ЗначенияТаблицы[0]; + КонецЕсли; + ЗначенияТаблицКлюча.Вставить(ТаблицаКлюча, ЗначенияТаблицы); + КонецЦикла; + СтрокаЗначений = ЗначенияПервойТаблицы.Строки[ИндексКлюча]; // СправочникОбъект.КлючиДоступа + КлючДоступа = СтрокаЗначений.Ссылка; + + ПраваНаКлюч = ПраваНаКлючДоступаСписка(ЗначенияТаблицКлюча, ПараметрыОбновления); + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьПраваНаКлючДоступаСписка(КлючДоступа, ПраваНаКлюч, + ?(ЭтоНовыеКлючи, ОписаниеКлючейДоступа, Неопределено), ПараметрыОбновления); + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура из КлючИЗначение: +// * Ключ - Строка - имя таблицы ключа +// * Значение - ДеревоЗначений +// +Функция НовыеЗначенияТаблицКлючей() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// Структура из КлючИЗначение: +// * Ключ - Строка - имя таблицы ключа +// * Значение - см. НовыеЗначенияТаблицыКлюча +// +Функция НовыеЗначенияТаблицКлюча() + Возврат Новый Структура; +КонецФункции + +// Возвращаемое значение: +// - КоллекцияСтрокДереваЗначений +// - ТаблицаЗначений +// - СтрокаДереваЗначений +// +Функция НовыеЗначенияТаблицыКлюча() + Возврат Новый ТаблицаЗначений; +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбработатьУстаревшиеКлючиДоступаСписка(ЭлементыДанных, ПараметрыОбновления) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + |ГДЕ + | КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборовГруппДоступа + |ГДЕ + | КлючиДоступаНаборовГруппДоступа.КлючДоступа = &КлючДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей + |ГДЕ + | КлючиДоступаПользователей.КлючДоступа = &КлючДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей + |ГДЕ + | КлючиДоступаВнешнихПользователей.КлючДоступа = &КлючДоступа"; + + ЭтоОчисткаВыбранныхКлючей = ПараметрыОбновления.БезЗаписиКлючейДоступа + Или ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей; + + Если Не ЭтоОчисткаВыбранныхКлючей Тогда + ЗапросИспользованияКлюча = Новый Запрос; + ЗапросИспользованияКлюча.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Ссылка = &Ссылка + | И КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1)"; + КонецЕсли; + + НаборЗаписейГруппДоступаКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); + НаборЗаписейНаборовГруппДоступаКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + НаборЗаписейПользователейКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); + НаборЗаписейВнешнихПользователейКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); + + Для Каждого Строка Из ЭлементыДанных Цикл + СтрокаЗначений = Строка; // СправочникОбъект.КлючиДоступа + Ссылка = СтрокаЗначений.Ссылка; + Если Не ЭтоОчисткаВыбранныхКлючей И Строка.Используется Тогда + ЗапросИспользованияКлюча.УстановитьПараметр("Ссылка", Ссылка); + // @skip-check query-in-loop - Порционная обработка данных + Если Не ЗапросИспользованияКлюча.Выполнить().Пустой() Тогда + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + Продолжить; + КонецЕсли; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + Если Не ЭтоОчисткаВыбранныхКлючей Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); + ЭлементБлокировки.УстановитьЗначение("Список", Строка.Список); + ЭлементБлокировки.УстановитьЗначение("Хеш", Строка.Хеш); + ЭлементБлокировки.УстановитьЗначение("СоставПолей", Строка.СоставПолей); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", + ПараметрыОбновления.ДляВнешнихПользователей); + КонецЕсли; + ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Ссылка); + УдалитьКлюч = Ложь; + Если ЭтоОчисткаВыбранныхКлючей Или Объект = Неопределено Тогда + УдалитьКлюч = Истина; + ИначеЕсли Строка.Используется Тогда + Объект.НеИспользуетсяС = '00010101'; + ИначеЕсли Не Строка.Удалить Тогда + Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); + ИначеЕсли ЗначениеЗаполнено(Объект.НеИспользуетсяС) Тогда + УдалитьКлюч = Истина; + КонецЕсли; + Если УдалитьКлюч Тогда + Запрос.УстановитьПараметр("КлючДоступа", Ссылка); + // @skip-check query-in-loop - Порционная обработка данных + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Если Не РезультатыЗапроса[0].Пустой() Тогда + НаборЗаписейГруппДоступаКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейГруппДоступаКлюча.Записать(); + КонецЕсли; + Если Не РезультатыЗапроса[1].Пустой() Тогда + НаборЗаписейНаборовГруппДоступаКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейНаборовГруппДоступаКлюча.Записать(); + КонецЕсли; + Если Не РезультатыЗапроса[2].Пустой() Тогда + НаборЗаписейПользователейКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейПользователейКлюча.Записать(); + КонецЕсли; + Если Не РезультатыЗапроса[3].Пустой() Тогда + НаборЗаписейВнешнихПользователейКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейВнешнихПользователейКлюча.Записать(); + КонецЕсли; + КонецЕсли; + Если Объект <> Неопределено Тогда + Если УдалитьКлюч Тогда + Объект.Удалить(); + ИначеЕсли Объект.Модифицированность() Тогда + Объект.Записать(); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +// +// Возвращаемое значение: +// Структура: +// * ПраваГруппДоступаСписков - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор списка +// ** Значение - см. ПраваГруппДоступаСписка +// +// * ЗначенияГруппДоступа - см. НовыеЗначенияГруппДоступа +// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа +// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей +// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа +// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа +// * РолиПрофилейГруппДоступа - см. НовыеРолиПрофилейГруппДоступа +// * ГруппыДоступаПрофилей - см. НовыеГруппыДоступаПрофилей +// +Функция КэшРасчетаПравДляВидаПользователей(ДляВнешнихПользователей) Экспорт + + КлючДанныхПовторногоИспользования = Строка(ПараметрыСеанса.КлючДанныхПовторногоИспользования); + Кэш = УправлениеДоступомСлужебныйПовтИсп.КэшРасчетаПрав(КлючДанныхПовторногоИспользования); + + ВерсияДанных = ВерсияДанныхДляКэшаРасчетаПрав(); + + Если Кэш.ВерсияДанных.ТаблицыГруппДоступа <> ВерсияДанных.ТаблицыГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "ПраваГруппДоступаСписков", Истина); + Кэш.ВерсияДанных.ТаблицыГруппДоступа = ВерсияДанных.ТаблицыГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.ЗначенияГруппДоступа <> ВерсияДанных.ЗначенияГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "ЗначенияГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыПользователейКакЗначенияДоступа"); + Кэш.ВерсияДанных.ЗначенияГруппДоступа = ВерсияДанных.ЗначенияГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.УчастникиГруппДоступа <> ВерсияДанных.УчастникиГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "УчастникиГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГрупповыеПользователиГруппДоступа"); + Кэш.ВерсияДанных.УчастникиГруппДоступа = ВерсияДанных.УчастникиГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.СоставыГруппПользователей <> ВерсияДанных.СоставыГруппПользователей Тогда + СброситьКэшРасчетаПрав(Кэш, "ПользователиГруппПользователей"); + СброситьКэшРасчетаПрав(Кэш, "УчастникиГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГрупповыеПользователиГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыПользователейКакЗначенияДоступа"); + Кэш.ВерсияДанных.СоставыГруппПользователей = ВерсияДанных.СоставыГруппПользователей; + КонецЕсли; + + Если Кэш.ВерсияДанных.РолиПрофилейГруппДоступа <> ВерсияДанных.РолиПрофилейГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "РолиПрофилейГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыДоступаПрофилей"); + Кэш.ВерсияДанных.РолиПрофилейГруппДоступа = ВерсияДанных.РолиПрофилейГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.ГруппыДоступаПрофилей <> ВерсияДанных.ГруппыДоступаПрофилей Тогда + СброситьКэшРасчетаПрав(Кэш, "РолиПрофилейГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыДоступаПрофилей"); + Кэш.ВерсияДанных.ГруппыДоступаПрофилей = ВерсияДанных.ГруппыДоступаПрофилей; + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + Возврат Кэш.ДляВнешнихПользователей; + Иначе + Возврат Кэш.ДляПользователей; + КонецЕсли; + +КонецФункции + +// Для функции КэшРасчетаПравДляВидаПользователей. +Процедура СброситьКэшРасчетаПрав(Кэш, Свойство, НовоеСоответствие = Ложь) + + Кэш.ДляПользователей[Свойство] = ?(НовоеСоответствие, Новый Соответствие, Неопределено); + Кэш.ДляВнешнихПользователей[Свойство] = ?(НовоеСоответствие, Новый Соответствие, Неопределено); + +КонецПроцедуры + +// Для процедур ЗаполнитьПраваГруппДоступаСписка и +// ЗаполнитьУчастниковГруппДоступаСписка. +// +Функция ТекстЗапросаНазначенияПрофилей() + + Возврат + "ВЫБРАТЬ + | Профили.Ссылка КАК Профиль, + | МАКСИМУМ(ВЫБОР + | КОГДА НазначениеПрофилей.ТипПользователей ЕСТЬ NULL + | ТОГДА ИСТИНА + | ИНАЧЕ ТИПЗНАЧЕНИЯ(НазначениеПрофилей.ТипПользователей) = ТИП(Справочник.Пользователи) + | КОНЕЦ) КАК ДляПользователей, + | МАКСИМУМ(ВЫБОР + | КОГДА НазначениеПрофилей.ТипПользователей ЕСТЬ NULL + | ТОГДА ЛОЖЬ + | ИНАЧЕ НазначениеПрофилей.ТипПользователей <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(НазначениеПрофилей.ТипПользователей) <> ТИП(Справочник.Пользователи) + | КОНЕЦ) КАК ДляВнешнихПользователей + |ПОМЕСТИТЬ НазначениеПрофилей + |ИЗ + | Справочник.ПрофилиГруппДоступа КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Назначение КАК НазначениеПрофилей + | ПО (НазначениеПрофилей.Ссылка = Профили.Ссылка) + | + |СГРУППИРОВАТЬ ПО + | Профили.Ссылка"; + +КонецФункции + +// Параметры: +// Права - ТаблицаЗначений +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа +// * ПравоИзменение - Булево +// * ПравоДобавление - Булево +// * ПравоЧтениеБезОграничения - Булево +// * ПравоИзменениеБезОграничения - Булево +// * ПравоДобавлениеБезОграничения - Булево +// +Функция НовыеПраваГруппДоступаСписка(Права) + Возврат Права; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПраваГруппДоступаСписка(ПараметрыОбновления, Кэш) + + ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; + ПраваГруппДоступаСписка = Кэш.ПраваГруппДоступаСписков.Получить(ИдентификаторСписка); + Если ПраваГруппДоступаСписка <> Неопределено Тогда + ПараметрыОбновления.Вставить("ПраваГруппДоступаСписка", ПраваГруппДоступаСписка); + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Таблица", ИдентификаторСписка); + Запрос.Текст = + "ВЫБРАТЬ + | ТаблицыГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | ТаблицыГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | ТаблицыГруппДоступа.ПравоДобавление КАК ПравоДобавление, + | ТаблицыГруппДоступа.ПравоЧтениеБезОграничения КАК ПравоЧтениеБезОграничения, + | ТаблицыГруппДоступа.ПравоИзменениеБезОграничения КАК ПравоИзменениеБезОграничения, + | ТаблицыГруппДоступа.ПравоДобавлениеБезОграничения КАК ПравоДобавлениеБезОграничения + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа + | ПО (ТаблицыГруппДоступа.Таблица = &Таблица) + | И (ГруппыДоступа.Ссылка = ТаблицыГруппДоступа.ГруппаДоступа) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НазначениеПрофилей КАК НазначениеПрофилей + | ПО (НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль) + | И (НазначениеПрофилей.ДляПользователей)"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); + КонецЕсли; + + Запрос.Текст = ТекстЗапросаНазначенияПрофилей() + + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + + ПраваГруппДоступаСписка = НовыеПраваГруппДоступаСписка(Запрос.Выполнить().Выгрузить()); + Кэш.ПраваГруппДоступаСписков.Вставить(ИдентификаторСписка, ПраваГруппДоступаСписка); + ПараметрыОбновления.Вставить("ПраваГруппДоступаСписка", ПраваГруппДоступаСписка); + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// ** Значение - Булево - Истина +// +Функция НовыеПользователиГруппПользователей() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПользователейГруппПользователей(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("ПользователиГруппПользователей", НовыеПользователиГруппПользователей()); + + Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Возврат; + КонецЕсли; + + Если Кэш.ПользователиГруппПользователей <> Неопределено Тогда + ПараметрыОбновления.ПользователиГруппПользователей = Кэш.ПользователиГруппПользователей; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, + | СоставыГруппПользователей.Пользователь КАК Пользователь + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи + | ПО (Пользователи.Ссылка = СоставыГруппПользователей.Пользователь) + | И (Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)) + | И (СоставыГруппПользователей.Используется) + |ИТОГИ ПО + | ГруппаПользователей"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ПользователиГруппПользователей = ПараметрыОбновления.ПользователиГруппПользователей; + + РезультатЗапроса = Запрос.Выполнить(); + ЗаполнитьПользователейГрупп(ПользователиГруппПользователей, РезультатЗапроса); + + Кэш.ПользователиГруппПользователей = ПользователиГруппПользователей; + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// ** Значение - Булево - Истина +// +Функция НовыеГруппыПользователейКакЗначенияДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьГруппыПользователейКакЗначенияДоступа(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("ГруппыПользователейКакЗначенияДоступа", + НовыеГруппыПользователейКакЗначенияДоступа()); + + Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Возврат; + КонецЕсли; + + Если Кэш.ГруппыПользователейКакЗначенияДоступа <> Неопределено Тогда + ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа = Кэш.ГруппыПользователейКакЗначенияДоступа; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, + | СоставыГруппПользователей.Пользователь КАК Пользователь + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияГруппДоступа КАК ЗначенияГруппДоступа + | ПО СоставыГруппПользователей.ГруппаПользователей = ЗначенияГруппДоступа.ЗначениеДоступа + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)) + | И (ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыПользователей)) + |ИТОГИ ПО + | ГруппаПользователей"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ГруппыПользователейКакЗначенияДоступа = ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа; + + РезультатЗапроса = Запрос.Выполнить(); + ЗаполнитьПользователейГрупп(ГруппыПользователейКакЗначенияДоступа, РезультатЗапроса); + + Кэш.ГруппыПользователейКакЗначенияДоступа = ГруппыПользователейКакЗначенияДоступа; + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыДоступа +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ВнешниеПользователи +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - Истина +// +Функция НовыеУчастникиГруппДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыДоступа +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// ** Значение - Булево - Истина +// +Функция НовыеГрупповыеПользователиГруппДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьУчастниковГруппДоступаСписка(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("УчастникиГруппДоступа", НовыеУчастникиГруппДоступа()); + ПараметрыОбновления.Вставить("ГрупповыеПользователиГруппДоступа", НовыеГрупповыеПользователиГруппДоступа()); + + Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Возврат; + КонецЕсли; + + Если Кэш.УчастникиГруппДоступа <> Неопределено Тогда + ПараметрыОбновления.УчастникиГруппДоступа = Кэш.УчастникиГруппДоступа; + ПараметрыОбновления.ГрупповыеПользователиГруппДоступа = Кэш.ГрупповыеПользователиГруппДоступа; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПользователиГруппыДоступа.Ссылка КАК ГруппаДоступа, + | ПользователиГруппыДоступа.Пользователь КАК Участник + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НазначениеПрофилей КАК НазначениеПрофилей + | ПО (НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль) + | И (НазначениеПрофилей.ДляПользователей) + | И (НЕ ГруппыДоступа.ПометкаУдаления) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппыДоступа + | ПО (ПользователиГруппыДоступа.Ссылка = ГруппыДоступа.Ссылка) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи + | ПО + | СоставыГруппПользователей.ГруппаПользователей = ПользователиГруппыДоступа.Пользователь + | И СоставыГруппПользователей.Используется + | И Пользователи.Ссылка = СоставыГруппПользователей.Пользователь + | И Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор)) + |ИТОГИ ПО + | ГруппаДоступа"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + Запрос.Текст = ТекстЗапросаНазначенияПрофилей() + + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + УчастникиГруппДоступа = ПараметрыОбновления.УчастникиГруппДоступа; + ГрупповыеПользователиГруппДоступа = ПараметрыОбновления.ГрупповыеПользователиГруппДоступа; + ТипГруппыПользователей = ПараметрыОбновления.ТипГруппыПользователей; + ПользователиГруппПользователей = ПараметрыОбновления.ПользователиГруппПользователей; + + Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + + Для Каждого Строка Из Дерево.Строки Цикл + УчастникиГруппыДоступа = Новый Соответствие; + ГрупповыеПользователиГруппыДоступа = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + УчастникиГруппыДоступа.Вставить(Подстрока.Участник, Истина); + Если ТипЗнч(Подстрока.Участник) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(Подстрока.Участник); + Если ПользователиГруппы <> Неопределено Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + ГрупповыеПользователиГруппыДоступа.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если УчастникиГруппыДоступа.Количество() > 0 Тогда + УчастникиГруппДоступа.Вставить(Строка.ГруппаДоступа, УчастникиГруппыДоступа); + КонецЕсли; + Если ГрупповыеПользователиГруппыДоступа.Количество() > 0 Тогда + ГрупповыеПользователиГруппДоступа.Вставить(Строка.ГруппаДоступа, ГрупповыеПользователиГруппыДоступа); + КонецЕсли; + КонецЦикла; + + Кэш.УчастникиГруппДоступа = УчастникиГруппДоступа; + Кэш.ГрупповыеПользователиГруппДоступа = ГрупповыеПользователиГруппДоступа; + +КонецПроцедуры + +// Для процедур ЗаполнитьПользователейГруппПользователей и +// ЗаполнитьГруппыПользователейКакЗначенияДоступа. +// +Процедура ЗаполнитьПользователейГрупп(ПользователиГруппПользователей, РезультатЗапроса) + + Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ПользователиГруппыПользователей = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПользователиГруппыПользователей.Вставить(Подстрока.Пользователь, Истина); + КонецЦикла; + ПользователиГруппПользователей.Вставить(Строка.ГруппаПользователей, ПользователиГруппыПользователей); + КонецЦикла; + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Тип - тип значений доступа +// * Значение - Структура: +// ** ВсеРазрешены - Булево +// ** Значения - Соответствие из КлючИЗначение: +// *** Ключ - ОпределяемыйТип.ЗначениеДоступа +// *** Значение - Булево - Истина +// +Функция НовыеЗначенияГруппыДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыДоступа +// * Значение - см. НовыеЗначенияГруппыДоступа +// +Функция НовыеЗначенияГруппДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьЗначенияГруппДоступаДляРасчетаПрав(ПараметрыОбновления, Кэш) + + Если Кэш.ЗначенияГруппДоступа <> Неопределено Тогда + ПараметрыОбновления.Вставить("ЗначенияГруппДоступа", Кэш.ЗначенияГруппДоступа); + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ЗначенияГруппДоступаПоУмолчанию.ГруппаДоступа КАК ГруппаДоступа, + | ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступаПоУмолчанию.ТипЗначенийДоступа) КАК ТипЗначенийДоступа, + | ЗначенияГруппДоступаПоУмолчанию.ВсеРазрешены КАК ВсеРазрешены + |ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияГруппДоступаПоУмолчанию + |ГДЕ + | НЕ ЗначенияГруппДоступаПоУмолчанию.БезНастройки + |ИТОГИ ПО + | ГруппаДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ЗначенияГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступа.ЗначениеДоступа) КАК ТипЗначенийДоступа, + | ЗначенияГруппДоступа.ЗначениеДоступа КАК ЗначениеДоступа + |ИЗ + | РегистрСведений.ЗначенияГруппДоступа КАК ЗначенияГруппДоступа + |ИТОГИ ПО + | ГруппаДоступа, + | ТипЗначенийДоступа"; + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + ЗначенияГруппДоступа = НовыеЗначенияГруппДоступа(); + + Дерево = РезультатыЗапроса[0].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ЗначенияГруппыДоступа = НовыеЗначенияГруппыДоступа(); + Для Каждого Подстрока Из Строка.Строки Цикл + ЗначенияОдногоТипа = Новый Структура; + ЗначенияОдногоТипа.Вставить("ВсеРазрешены", Подстрока.ВсеРазрешены); + ЗначенияОдногоТипа.Вставить("Значения", Новый Соответствие); + ЗначенияГруппыДоступа.Вставить(Подстрока.ТипЗначенийДоступа, ЗначенияОдногоТипа); + КонецЦикла; + ЗначенияГруппДоступа.Вставить(Строка.ГруппаДоступа, ЗначенияГруппыДоступа); + КонецЦикла; + + Дерево = РезультатыЗапроса[1].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ЗначенияГруппыДоступа = ЗначенияГруппДоступа.Получить(Строка.ГруппаДоступа); + Если ЗначенияГруппыДоступа = Неопределено Тогда + Продолжить; + КонецЕсли; + Для Каждого Подстрока Из Строка.Строки Цикл + ЗначенияОдногоТипа = ЗначенияГруппыДоступа.Получить(Подстрока.ТипЗначенийДоступа); + Если ЗначенияОдногоТипа = Неопределено Тогда + Продолжить; + КонецЕсли; + Значения = ЗначенияОдногоТипа.Значения; + Для Каждого ОписаниеЗначения Из Подстрока.Строки Цикл + Значения.Вставить(ОписаниеЗначения.ЗначениеДоступа, Истина); + КонецЦикла; + КонецЦикла; + КонецЦикла; + + ПараметрыОбновления.Вставить("ЗначенияГруппДоступа", ЗначенияГруппДоступа); + Кэш.ЗначенияГруппДоступа = ЗначенияГруппДоступа; + +КонецПроцедуры + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Профиль - СправочникСсылка.ПрофилиГруппДоступа +// * Роль - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ИмяРоли - Строка +// * ИмяРолиВерхнийРегистр - Строка +// +Функция НовыеРолиПрофилейГруппДоступа() + Возврат Новый ТаблицаЗначений; +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Профиль - СправочникСсылка.ПрофилиГруппДоступа +// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа +// +Функция НовыеГруппыДоступаПрофилей() + Возврат Новый ТаблицаЗначений; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьРолиИГруппыДоступаПрофилей(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("РолиПрофилейГруппДоступа", НовыеРолиПрофилейГруппДоступа()); + ПараметрыОбновления.Вставить("ГруппыДоступаПрофилей", НовыеГруппыДоступаПрофилей()); + + Если Не ПараметрыОбновления.ЕстьФункцияПравоДоступаИлиРольДоступна Тогда + Возврат; + КонецЕсли; + + Если Кэш.РолиПрофилейГруппДоступа <> Неопределено Тогда + ПараметрыОбновления.РолиПрофилейГруппДоступа = Кэш.РолиПрофилейГруппДоступа; + ПараметрыОбновления.ГруппыДоступаПрофилей = Кэш.ГруппыДоступаПрофилей; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | РолиПрофилей.Роль КАК Роль + |ИЗ + | НазначениеПрофилей КАК НазначениеПрофилей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей + | ПО (РолиПрофилей.Ссылка = НазначениеПрофилей.Профиль) + | И (НазначениеПрофилей.ДляПользователей) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | РолиПрофилей.Ссылка КАК Профиль, + | РолиПрофилей.Роль КАК Роль + |ИЗ + | НазначениеПрофилей КАК НазначениеПрофилей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей + | ПО (РолиПрофилей.Ссылка = НазначениеПрофилей.Профиль) + | И (НазначениеПрофилей.ДляПользователей) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НазначениеПрофилей.Профиль КАК Профиль, + | ГруппыДоступа.Ссылка КАК ГруппаДоступа + |ИЗ + | НазначениеПрофилей КАК НазначениеПрофилей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа + | ПО НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль + | И (НазначениеПрофилей.ДляПользователей)"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); + КонецЕсли; + + Запрос.Текст = ТекстЗапросаНазначенияПрофилей() + + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Роли = РезультатыЗапроса[1].Выгрузить().ВыгрузитьКолонку("Роль"); + ОбъектыМетаданныхРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(Роли, Ложь); + + РолиПрофилейГруппДоступа = РезультатыЗапроса[2].Выгрузить(); + ТипИмениРоли = Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.Имя.Тип; + РолиПрофилейГруппДоступа.Колонки.Добавить("ИмяРоли", ТипИмениРоли); + РолиПрофилейГруппДоступа.Колонки.Добавить("ИмяРолиВерхнийРегистр", ТипИмениРоли); + РолиПрофилейГруппДоступа.Индексы.Добавить("Роль"); + Отбор = Новый Структура("Роль"); + ТребуетсяПроверитьАктуальностьМетаданных = Ложь; + + Для Каждого ОписаниеРоли Из ОбъектыМетаданныхРолей Цикл + Если ТипЗнч(ОписаниеРоли.Значение) <> Тип("ОбъектМетаданных") Тогда + ТребуетсяПроверитьАктуальностьМетаданных = Истина; + Продолжить; + КонецЕсли; + ИмяРоли = ОписаниеРоли.Значение.Имя; + ИмяРолиВерхнийРегистр = ВРег(ИмяРоли); + Отбор.Роль = ОписаниеРоли.Ключ; + Строки = РолиПрофилейГруппДоступа.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + Строка.ИмяРоли = ИмяРоли; + Строка.ИмяРолиВерхнийРегистр = ИмяРолиВерхнийРегистр; + КонецЦикла; + КонецЦикла; + Если ТребуетсяПроверитьАктуальностьМетаданных Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + РолиПрофилейГруппДоступа.Индексы.Добавить("Профиль,ИмяРолиВерхнийРегистр"); + + ГруппыДоступаПрофилей = РезультатыЗапроса[3].Выгрузить(); + ГруппыДоступаПрофилей.Индексы.Добавить("ГруппаДоступа"); + + ПараметрыОбновления.РолиПрофилейГруппДоступа = РолиПрофилейГруппДоступа; + ПараметрыОбновления.ГруппыДоступаПрофилей = ГруппыДоступаПрофилей; + Кэш.РолиПрофилейГруппДоступа = РолиПрофилейГруппДоступа; + Кэш.ГруппыДоступаПрофилей = ГруппыДоступаПрофилей; + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.КлючиДоступа +// * Значение - ФиксированнаяСтруктура: +// ** ОграничениеЧтенияОтключено - Булево +// ** ОграничениеОтключено - Булево +// ** ПоГруппамДоступа - ФиксированноеСоответствие из КлючИЗначение: +// *** Ключ - СправочникСсылка.ГруппыДоступа +// *** Значение - Булево - право изменение +// +Функция НовыеПраваНаСпискиВедущихКлючейДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.КлючиДоступа +// * Значение - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ГруппыДоступа +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - право изменение +// +Функция НовыеПраваНаВедущиеКлючиДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор списка +// - Тип - тип значений списка +// * Значение - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ГруппыДоступа +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - право изменение +// +Функция НовыеПраваНаВедущиеСписки() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПраваНаВедущиеКлючиДоступаИВедущиеСписки(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления) + + ПраваНаСпискиВедущихКлючейДоступа = НовыеПраваНаСпискиВедущихКлючейДоступа(); + ПраваНаВедущиеКлючиДоступа = НовыеПраваНаВедущиеКлючиДоступа(); + Если ПараметрыОбновления.ЕстьВедущиеКлючиДоступа Тогда + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ПараметрыОбновления.ИдентификаторТранзакции, Неопределено, Ложь); + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + НомерТаблицы = НомерТаблицы + 1; + ПраваНаСписки = Новый Соответствие; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + ИдентификаторыСписков = Дерево.Строки.ВыгрузитьКолонку("Список"); + Если ПараметрыОбновления.Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда + ОбъектыМетаданныхПоИдентификаторам = ПараметрыОбновления.Кэш.ОбъектыМетаданныхПоИдентификаторам; + НенайденныеИдентификаторыСписков = Новый Массив; + Для Каждого ИдентификаторСписка Из ИдентификаторыСписков Цикл + Если ОбъектыМетаданныхПоИдентификаторам.Получить(ИдентификаторСписка) = Неопределено Тогда + НенайденныеИдентификаторыСписков.Добавить(ИдентификаторСписка); + КонецЕсли; + КонецЦикла; + Результат = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( + НенайденныеИдентификаторыСписков, Ложь); + Для Каждого КлючИЗначение Из Результат Цикл + ОбъектыМетаданныхПоИдентификаторам.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Иначе + ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( + ИдентификаторыСписков, Ложь); + КонецЕсли; + Для Каждого Строка Из Дерево.Строки Цикл + ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(Строка.Список); + Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда + Продолжить; + КонецЕсли; + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ПоГруппамДоступа = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПоГруппамДоступа.Вставить(Подстрока.ГруппаДоступа, Подстрока.ПравоИзменение); + КонецЦикла; + ПраваНаСписок = Новый Структура; + ПраваНаСписок.Вставить("ОграничениеЧтенияОтключено", + ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения.Получить(ПолноеИмя) <> Неопределено); + ПраваНаСписок.Вставить("ОграничениеОтключено", + ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(ПолноеИмя) <> Неопределено); + ПраваНаСписок.Вставить("ПоГруппамДоступа", Новый ФиксированноеСоответствие(ПоГруппамДоступа)); + ПраваНаСписки.Вставить(Строка.Список, Новый ФиксированнаяСтруктура(ПраваНаСписок)); + КонецЦикла; + НомерТаблицы = НомерТаблицы + 1; + Таблица = РезультатыЗапроса[НомерТаблицы].Выгрузить(); + Для Каждого Строка Из Таблица Цикл + ПраваНаСпискиВедущихКлючейДоступа.Вставить(Строка.КлючДоступа, + ПраваНаСписки.Получить(Строка.Список)); + КонецЦикла; + НомерТаблицы = НомерТаблицы + 1; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ПраваНаВедущийКлюч = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПраваНаВедущийКлюч.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); + КонецЦикла; + ПраваНаВедущиеКлючиДоступа.Вставить(Строка.КлючДоступа, + Новый ФиксированноеСоответствие(ПраваНаВедущийКлюч)); + КонецЦикла; + КонецЕсли; + ПараметрыОбновления.Вставить("ПраваНаСпискиВедущихКлючейДоступа", + Новый ФиксированноеСоответствие(ПраваНаСпискиВедущихКлючейДоступа)); + ПараметрыОбновления.Вставить("ПраваНаВедущиеКлючиДоступа", + Новый ФиксированноеСоответствие(ПраваНаВедущиеКлючиДоступа)); + + ПраваНаВедущиеСписки = НовыеПраваНаВедущиеСписки(); + Если ПараметрыОбновления.ЕстьВедущиеСпискиПоПравам Тогда + НомерТаблицы = НомерТаблицы + 1; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + ДобавитьПраваПоТипам = Дерево.Колонки.Найти("ТипЗначения") <> Неопределено; + Для Каждого Строка Из Дерево.Строки Цикл + ПраваНаВедущийСписок = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПраваНаВедущийСписок.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); + Если ДобавитьПраваПоТипам Тогда + ТипЗначенияСписка = Подстрока.ТипЗначения; + КонецЕсли; + КонецЦикла; + ПраваНаВедущиеСписки.Вставить(Строка.Список, + Новый ФиксированноеСоответствие(ПраваНаВедущийСписок)); + Если ДобавитьПраваПоТипам Тогда + ПраваНаВедущиеСписки.Вставить(ТипЗначенияСписка, + Новый ФиксированноеСоответствие(ПраваНаВедущийСписок)); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ПараметрыОбновления.Вставить("ПраваНаВедущиеСписки", + Новый ФиксированноеСоответствие(ПраваНаВедущиеСписки)); + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - ОпределяемыйТип.ВладелецНастроекПрав +// * Значение - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ВнешниеПользователи +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - право изменение +// +Функция НовыеПраваПоВладельцамНастроекПрав() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПраваПоВладельцамНастроекПрав(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления) + + ПраваПоВладельцамНастроекПрав = НовыеПраваПоВладельцамНастроекПрав(); + Если ПараметрыОбновления.ЕстьВладельцыНастроекПрав Тогда + НомерТаблицы = НомерТаблицы + 5; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ПраваПоВладельцуНастроекПрав = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПраваПоВладельцуНастроекПрав.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); + КонецЦикла; + ПраваПоВладельцамНастроекПрав.Вставить(Строка.ВладелецНастроекПрав, + Новый ФиксированноеСоответствие(ПраваПоВладельцуНастроекПрав)); + КонецЦикла; + КонецЕсли; + ПараметрыОбновления.Вставить("ПраваПоВладельцамНастроекПрав", + Новый ФиксированноеСоответствие(ПраваПоВладельцамНастроекПрав)); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ЗначенияТаблицКлюча - см. НовыеЗначенияТаблицКлюча +// * БезЗаписиПраваЧтение - Булево +// * РеквизитыТаблицКлюча - см. НовыеРеквизитыТаблицКлюча +// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа +// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа +// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа +// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей +// * ПраваНаСпискиВедущихКлючейДоступа - см. НовыеПраваНаСпискиВедущихКлючейДоступа +// * ПраваНаВедущиеКлючиДоступа - см. НовыеПраваНаВедущиеКлючиДоступа +// * ПраваНаВедущиеСписки - см. НовыеПраваНаВедущиеСписки +// * ПраваПоВладельцамНастроекПрав - см. НовыеПраваПоВладельцамНастроекПрав +// * ТипГруппыДоступа - Тип +// * ПустаяГруппаДоступа - СправочникСсылка.ГруппыДоступа +// * ТипПользователя - Тип +// * ТипГруппыПользователей - Тип +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ПраваРолейФункцииПравоДоступа - Соответствие +// * ОбъектыМетаданныхФункцииПравоДоступа - Соответствие +// * ПраваПрофилейФункцииПравоДоступа - Соответствие +// * РолиПрофилейГруппДоступа - см. РолиПрофилейГруппДоступа +// * ГруппыДоступаПрофилей - см. ГруппыДоступаПрофилей +// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа - текущее значение +// * ЗначенияГруппыДоступа - см. НовыеЗначенияГруппыДоступа +// * ОписанияТребуемыхТаблицКлюча - Массив из Структура: +// ** РеквизитыТаблиц - Соответствие из КлючИЗначение: +// *** Ключ - Строка - имя таблицы ключа +// *** Значение - Массив из Строка - имя реквизита таблицы ключа +// ** ЗначенияТаблиц - см. ТекущиеЗначенияТаблицКлюча +// ** ИндексыСтрокТаблиц - Соответствие +// * ТекущиеСтрокиТаблицКлюча - см. НовыеЗначенияТаблицКлюча +// +Функция НовыйКонтекстРасчетаПрав() + Возврат Новый Структура; +КонецФункции + +// Для процедуры ОбновитьПраваНаКлючиДоступаСписка. +Функция ПраваНаКлючДоступаСписка(ЗначенияТаблицКлюча, ПараметрыОбновления) + + ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); + + Если ПараметрыОбновления.ОграничениеОтключено Тогда + Если Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа Тогда + Возврат ПраваНаКлюч; + ИначеЕсли ПараметрыОбновления.ИзменениеРазрешеноДляВсехПользователей Тогда + ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); + Возврат ПраваНаКлюч; + КонецЕсли; + КонецЕсли; + + БезЗаписиПраваЧтение = ПараметрыОбновления.ОграничениеЧтенияОтключено + И Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа; + + Контекст = НовыйКонтекстРасчетаПрав(); + Контекст.Вставить("ЗначенияТаблицКлюча", ЗначенияТаблицКлюча); + Контекст.Вставить("БезЗаписиПраваЧтение", БезЗаписиПраваЧтение); + Контекст.Вставить("РеквизитыТаблицКлюча", ПараметрыОбновления.РеквизитыТаблицКлюча); + Контекст.Вставить("УчастникиГруппДоступа", ПараметрыОбновления.УчастникиГруппДоступа); + Контекст.Вставить("ГрупповыеПользователиГруппДоступа", ПараметрыОбновления.ГрупповыеПользователиГруппДоступа); + Контекст.Вставить("ГруппыПользователейКакЗначенияДоступа", ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа); + Контекст.Вставить("ПользователиГруппПользователей", ПараметрыОбновления.ПользователиГруппПользователей); + Контекст.Вставить("ПраваНаСпискиВедущихКлючейДоступа", ПараметрыОбновления.ПраваНаСпискиВедущихКлючейДоступа); + Контекст.Вставить("ПраваНаВедущиеКлючиДоступа", ПараметрыОбновления.ПраваНаВедущиеКлючиДоступа); + Контекст.Вставить("ПраваНаВедущиеСписки", ПараметрыОбновления.ПраваНаВедущиеСписки); + Контекст.Вставить("ПраваПоВладельцамНастроекПрав", ПараметрыОбновления.ПраваПоВладельцамНастроекПрав); + Контекст.Вставить("РассчитыватьПраваПользователей", ПараметрыОбновления.РассчитыватьПраваПользователей); + Контекст.Вставить("ТипГруппыДоступа", ПараметрыОбновления.ТипГруппыДоступа); + Контекст.Вставить("ПустаяГруппаДоступа", ПараметрыОбновления.ПустаяГруппаДоступа); + Контекст.Вставить("ТипПользователя", ПараметрыОбновления.ТипПользователя); + Контекст.Вставить("ТипГруппыПользователей", ПараметрыОбновления.ТипГруппыПользователей); + Контекст.Вставить("ТипыВладельцевНастроекПрав", ПараметрыОбновления.ТипыВладельцевНастроекПрав); + Контекст.Вставить("ПраваРолейФункцииПравоДоступа", ПараметрыОбновления.Кэш.ПраваРолейФункцииПравоДоступа); + Контекст.Вставить("ОбъектыМетаданныхФункцииПравоДоступа", ПараметрыОбновления.Кэш.ОбъектыМетаданныхФункцииПравоДоступа); + Контекст.Вставить("ПраваПрофилейФункцииПравоДоступа", ПараметрыОбновления.Кэш.ПраваПрофилейФункцииПравоДоступа); + Контекст.Вставить("РолиПрофилейГруппДоступа", ПараметрыОбновления.РолиПрофилейГруппДоступа); + Контекст.Вставить("ГруппыДоступаПрофилей", ПараметрыОбновления.ГруппыДоступаПрофилей); + + ЧтениеРазрешеноДляВсехГруппДоступа = Истина; + ИзменениеРазрешеноДляВсехГруппДоступа = Истина; + ДобавлениеРазрешеноДляВсехГруппДоступа = Истина; + + Для Каждого ОписаниеПрав Из ПараметрыОбновления.ПраваГруппДоступаСписка Цикл + ГруппаДоступа = ОписаниеПрав.ГруппаДоступа; + ПраваГруппыДоступа = ОписаниеПрав; // СтрокаТаблицыЗначений + + Контекст.Вставить("ГруппаДоступа", ГруппаДоступа); + Контекст.Вставить("ЗначенияГруппыДоступа", + ПараметрыОбновления.ЗначенияГруппДоступа.Получить(ГруппаДоступа)); + + Если БезЗаписиПраваЧтение + Или ПраваГруппыДоступа.ПравоЧтениеБезОграничения Тогда + + ПравоЧтение = "Истина"; + Иначе + ПравоЧтение = РассчитанноеУсловиеДляСтрок(Контекст, + ПараметрыОбновления.СтруктураРасчетаПраваЧтение); + КонецЕсли; + + Если ПравоЧтение <> "Истина" Тогда + ЧтениеРазрешеноДляВсехГруппДоступа = Ложь; + ИзменениеРазрешеноДляВсехГруппДоступа = Ложь; + ДобавлениеРазрешеноДляВсехГруппДоступа = Ложь; + КонецЕсли; + + Если ПравоЧтение = "Ложь" + Или ТипЗнч(ПравоЧтение) = Тип("Соответствие") + И ПравоЧтение.Количество() = 0 Тогда + + Продолжить; + КонецЕсли; + + Если ПраваГруппыДоступа.ПравоИзменениеБезОграничения + И ПраваГруппыДоступа.ПравоДобавлениеБезОграничения Тогда + + ПравоИзменение = "Истина"; + + ИначеЕсли Не ПраваГруппыДоступа.ПравоИзменение Тогда + ПравоИзменение = "Ложь"; + + ИначеЕсли ПараметрыОбновления.ЕстьОграничениеИзменения Тогда + ПравоИзменение = РассчитанноеУсловиеДляСтрок(Контекст, + ПараметрыОбновления.СтруктураРасчетаПраваИзменение); + + ИначеЕсли БезЗаписиПраваЧтение + Или ПраваГруппыДоступа.ПравоЧтениеБезОграничения Тогда + + ПравоИзменение = РассчитанноеУсловиеДляСтрок(Контекст, + ПараметрыОбновления.СтруктураРасчетаПраваЧтение); + Иначе + ПравоИзменение = "Истина"; + КонецЕсли; + + ПравоДобавление = ?(ПраваГруппыДоступа.ПравоДобавление, ПравоИзменение, "Ложь"); + + Если ПраваГруппыДоступа.ПравоИзменениеБезОграничения Тогда + ПравоИзменение = "Истина"; + КонецЕсли; + + Если ПравоИзменение <> "Истина" Тогда + ИзменениеРазрешеноДляВсехГруппДоступа = Ложь; + КонецЕсли; + Если ПравоДобавление <> "Истина" Тогда + ДобавлениеРазрешеноДляВсехГруппДоступа = Ложь; + КонецЕсли; + + Если Контекст.РассчитыватьПраваПользователей Тогда + ДобавитьПраваПользователейНаКлючДоступа(ПраваНаКлюч, + ПравоЧтение, ПравоИзменение, ПравоДобавление, Контекст); + + ИначеЕсли Не БезЗаписиПраваЧтение Или ПравоИзменение = "Истина" Или ПравоДобавление = "Истина" Тогда + ПраваНаКлюч.ДляГрупп.Вставить(ГруппаДоступа, Новый Структура("ПравоИзменение, ПравоДобавление", + ПравоИзменение = "Истина", ПравоДобавление = "Истина")); + КонецЕсли; + КонецЦикла; + + Если Не ЧтениеРазрешеноДляВсехГруппДоступа + Или ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа + И Не ПараметрыОбновления.ЧтениеРазрешеноДляВсехПользователей Тогда + + Возврат ПраваНаКлюч; + КонецЕсли; + + Если ДобавлениеРазрешеноДляВсехГруппДоступа + И ( Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа + Или ПараметрыОбновления.ИзменениеРазрешеноДляВсехПользователей) Тогда + + ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); + ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); + + Иначе // ЧтениеРазрешеноДляВсехГруппДоступа. + ТекущиеПраваНаКлюч = ПраваНаКлюч; + ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); + Если Не БезЗаписиПраваЧтение Или ИзменениеРазрешеноДляВсехГруппДоступа Тогда + ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", ИзменениеРазрешеноДляВсехГруппДоступа, Ложь)); + КонецЕсли; + ИмяПрава = ?(ИзменениеРазрешеноДляВсехГруппДоступа, "ПравоДобавление", "ПравоИзменение"); + Для Каждого КлючИЗначение Из ТекущиеПраваНаКлюч.ДляГрупп Цикл + Если КлючИЗначение.Значение[ИмяПрава] Тогда + ПраваНаКлюч.ДляГрупп.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + Для Каждого КлючИЗначение Из ТекущиеПраваНаКлюч.ДляПользователей Цикл + Если КлючИЗначение.Значение[ИмяПрава] Тогда + ПраваНаКлюч.ДляПользователей.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат ПраваНаКлюч; + +КонецФункции + +// Для процедуры ПраваНаКлючДоступаСписка. +Процедура ДобавитьПраваПользователейНаКлючДоступа(ПраваНаКлюч, ПравоЧтение, ПравоИзменение, ПравоДобавление, Контекст) + + Если ТипЗнч(ПравоИзменение) = Тип("Соответствие") И ПравоИзменение.Количество() = 0 Тогда + ПравоИзменение = "Ложь"; + ПравоДобавление = "Ложь"; + + ИначеЕсли ТипЗнч(ПравоДобавление) = Тип("Соответствие") И ПравоДобавление.Количество() = 0 Тогда + ПравоДобавление = "Ложь"; + КонецЕсли; + + Права = НовыеПрава(ПравоИзменение = "Истина", ПравоДобавление = "Истина"); + + Если ТипЗнч(ПравоЧтение) <> Тип("Соответствие") Тогда + Если Не Контекст.БезЗаписиПраваЧтение Или Права.ПравоИзменение Или Права.ПравоДобавление Тогда + ПраваНаКлюч.ДляГрупп.Вставить(Контекст.ГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", + Права.ПравоИзменение, Права.ПравоДобавление)); + КонецЕсли; + Иначе + ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлюч.ДляПользователей, + ПравоЧтение, Права.ПравоИзменение, Права.ПравоДобавление, Контекст.БезЗаписиПраваЧтение); + КонецЕсли; + + Если ТипЗнч(ПравоИзменение) <> Тип("Соответствие") + И ТипЗнч(ПравоДобавление) <> Тип("Соответствие") Тогда + Возврат; + КонецЕсли; + + Право = ?(ТипЗнч(ПравоИзменение) = Тип("Соответствие"), ПравоИзменение, ПравоДобавление); + ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлюч.ДляПользователей, + Право, Истина, ПравоДобавление <> "Ложь", Контекст.БезЗаписиПраваЧтение); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ПравоИзменение - Булево +// * ПравоДобавление - Булево +// +Функция НовыеПрава(ПравоИзменение, ПравоДобавление) + + Возврат Новый Структура("ПравоИзменение, ПравоДобавление", ПравоИзменение, ПравоДобавление); + +КонецФункции + +// Для процедуры ДобавитьПраваПользователейНаКлючДоступа. +Процедура ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлючДляПользователей, + СоставПользователей, ПравоИзменение, ПравоДобавление, БезЗаписиПраваЧтение) + + Если ПравоИзменение И ПравоДобавление Тогда + Для Каждого КлючИЗначение Из СоставПользователей Цикл + ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, + Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); + КонецЦикла; + + ИначеЕсли Не ПравоИзменение И Не ПравоДобавление Тогда + Если Не БезЗаписиПраваЧтение Тогда + Для Каждого КлючИЗначение Из СоставПользователей Цикл + Права = ПраваНаКлючДляПользователей.Получить(КлючИЗначение.Ключ); + Если Права = Неопределено Тогда + Права = Новый Структура("ПравоИзменение, ПравоДобавление", Ложь, Ложь); + ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, Права); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Иначе + Для Каждого КлючИЗначение Из СоставПользователей Цикл + Права = ПраваНаКлючДляПользователей.Получить(КлючИЗначение.Ключ); // См. НовыеПрава + Если Права = Неопределено Тогда + Права = Новый Структура("ПравоИзменение, ПравоДобавление", + ПравоИзменение, ПравоДобавление); + Иначе + Права.ПравоИзменение = Права.ПравоИзменение Или ПравоИзменение; + Права.ПравоДобавление = Права.ПравоДобавление Или ПравоДобавление; + КонецЕсли; + ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, Права); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для функций ПраваНаКлючДоступаСписка и РассчитанноеУсловие. +Функция РассчитанноеУсловиеДляСтрок(Контекст, Условие, УзелРеквизитов = Неопределено, ДляЛюбойИзСтрок = Истина, КорневойУзел = Истина) + + Если УзелРеквизитов = Неопределено Тогда + Контекст.Вставить("ОписанияТребуемыхТаблицКлюча", Новый Массив); + Если Условие.Узел = "ДляВсехСтрок" Или Условие.Узел = "ДляОднойИзСтрок" Тогда + Возврат РассчитанноеУсловие(Контекст, Условие, КорневойУзел); + КонецЕсли; + УзелРеквизитов = Условие; + КонецЕсли; + + Если Не ЗначениеЗаполнено(УзелРеквизитов.ТребуемыеРеквизитыТабличныхЧастейКлюча) Тогда + Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", Контекст.ЗначенияТаблицКлюча); + Возврат РассчитанноеУсловие(Контекст, Условие, КорневойУзел); + КонецЕсли; + РеквизитыТаблиц = УзелРеквизитов.ТребуемыеРеквизитыТабличныхЧастейКлюча; + ЗначенияТаблиц = ТекущиеЗначенияТаблицКлюча(Контекст, РеквизитыТаблиц); + ИндексыСтрокТаблиц = Новый Соответствие; + + Контекст.ОписанияТребуемыхТаблицКлюча.Добавить( + Новый Структура("РеквизитыТаблиц, ЗначенияТаблиц, ИндексыСтрокТаблиц", + РеквизитыТаблиц, ЗначенияТаблиц, ИндексыСтрокТаблиц)); + + ТекущиеСтрокиТаблицКлюча = ?(Контекст.Свойство("ТекущиеСтрокиТаблицКлюча"), + Контекст.ТекущиеСтрокиТаблицКлюча, Неопределено); + + Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", Новый Структура); + Для Каждого ОписаниеЗначений Из Контекст.ЗначенияТаблицКлюча Цикл + Если СтрНачинаетсяС(ОписаниеЗначений.Ключ, "Шапка") Тогда + Контекст.ТекущиеСтрокиТаблицКлюча.Вставить(ОписаниеЗначений.Ключ, ОписаниеЗначений.Значение); + КонецЕсли; + КонецЦикла; + + Результат = "Неопределено"; + + Пока Истина Цикл + ИндексИзменен = Ложь; + Для Каждого ОписаниеТаблицы Из РеквизитыТаблиц Цикл + ИмяТаблицыКлюча = ОписаниеТаблицы.Ключ; + ИндексСтроки = ИндексыСтрокТаблиц.Получить(ИмяТаблицыКлюча); + ЗначенияТаблицы = ЗначенияТаблиц[ИмяТаблицыКлюча]; + Если ИндексСтроки = Неопределено Тогда + ИндексСтроки = 0; + Иначе + Если ИндексСтроки >= ЗначенияТаблицы.Количество() - 1 Тогда + Продолжить; + КонецЕсли; + ИндексСтроки = ИндексСтроки + 1; + КонецЕсли; + ИндексИзменен = Истина; + ИндексыСтрокТаблиц.Вставить(ИмяТаблицыКлюча, ИндексСтроки); + Контекст.ТекущиеСтрокиТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицы[ИндексСтроки]); + КонецЦикла; + Если Не ИндексИзменен Тогда + Прервать; + КонецЕсли; + ТекущийРезультат = РассчитанноеУсловие(Контекст, Условие); + Если ТипЗнч(ТекущийРезультат) <> Тип("Соответствие") Тогда + Если ДляЛюбойИзСтрок Тогда + Если ТекущийРезультат = "Истина" Тогда + Результат = "Истина"; + Прервать; + ИначеЕсли ТекущийРезультат = "Ложь" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Ложь"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + КонецЕсли; + Иначе + Если ТекущийРезультат = "Ложь" Тогда + Результат = "Ложь"; + Прервать; + ИначеЕсли ТекущийРезультат = "Истина" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + КонецЕсли; + КонецЕсли; + Иначе + Если Не ДляЛюбойИзСтрок И ТекущийРезультат.Количество() = 0 Тогда + Результат = "Ложь"; + Прервать; + КонецЕсли; + Если ТипЗнч(Результат) = Тип("Строка") Тогда + Результат = ТекущийРезультат; + Иначе + ДобавитьТекущийРезультат(Результат, ТекущийРезультат, ДляЛюбойИзСтрок, Контекст); + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + ИначеЕсли КорневойУзел И Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + + Контекст.ОписанияТребуемыхТаблицКлюча.Удалить( + Контекст.ОписанияТребуемыхТаблицКлюча.Количество() - 1); + + Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", ТекущиеСтрокиТаблицКлюча); + + Возврат Результат; + +КонецФункции + +// Для функции РассчитанноеУсловиеДляСтрок. +Процедура ДобавитьТекущийРезультат(Результат, ТекущийРезультат, ДляЛюбойИзСтрок, Контекст) + + Если ДляЛюбойИзСтрок Тогда + Для Каждого КлючИЗначение Из ТекущийРезультат Цикл + Результат.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Иначе + Если Результат.Количество() > ТекущийРезультат.Количество() Тогда + МеньшийРезультат = ТекущийРезультат; + БольшийРезультат = Результат; + Иначе + МеньшийРезультат = Результат; + БольшийРезультат = ТекущийРезультат; + КонецЕсли; + Результат = Новый Соответствие; + ТипГруппыПользователей = Неопределено; + + Для Каждого КлючИЗначение Из МеньшийРезультат Цикл + Участник = КлючИЗначение.Ключ; + Если БольшийРезультат.Получить(Участник) <> Неопределено Тогда + Результат.Вставить(Участник, Истина); + Иначе + Если ТипГруппыПользователей = Неопределено Тогда + ТипГруппыПользователей = Контекст.ТипГруппыПользователей; + ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; + БольшийРезультатПользователиГрупп = ПользователиГрупп(БольшийРезультат, Контекст); + КонецЕсли; + Если ТипЗнч(Участник) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(Участник); + Если ПользователиГруппы = Неопределено Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если БольшийРезультатПользователиГрупп.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + ИначеЕсли БольшийРезультатПользователиГрупп.Получить(Участник) <> Неопределено Тогда + Результат.Вставить(Участник, Истина); + КонецЕсли; + КонецЕсли; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьТекущийРезультат и УстановитьОбратныйРезультат. +Функция ПользователиГрупп(ПользователиИГруппы, Контекст) + + ПользователиГрупп = Новый Соответствие; + + ТипГруппыПользователей = Контекст.ТипГруппыПользователей; + ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; + + Для Каждого КлючИЗначение Из ПользователиИГруппы Цикл + Если ТипЗнч(КлючИЗначение.Ключ) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(КлючИЗначение.Ключ); + Если ПользователиГруппы <> Неопределено Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + ПользователиГрупп.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Возврат ПользователиГрупп; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Процедура УстановитьОбратныйРезультат(Результат, Контекст) + + СписокИсключений = Результат; + Результат = Новый Соответствие; + + УчастникиТекущейГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если УчастникиТекущейГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + + ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; + ТипГруппыПользователей = Контекст.ТипГруппыПользователей; + ТипПользователя = Контекст.ТипПользователя; + + ПользователиИсключаемыхГрупп = ПользователиГрупп(СписокИсключений, Контекст); + + Для Каждого КлючИЗначение Из УчастникиТекущейГруппыДоступа Цикл + Участник = КлючИЗначение.Ключ; + Если СписокИсключений.Получить(Участник) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Если ТипЗнч(Участник) = ТипПользователя Тогда + Если СписокИсключений.Получить(Участник) = Неопределено + И ПользователиИсключаемыхГрупп.Получить(Участник) = Неопределено Тогда + + Результат.Вставить(Участник, Истина); + КонецЕсли; + ИначеЕсли ТипЗнч(Участник) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(Участник); + Если ПользователиГруппы = Неопределено Тогда + Продолжить; + КонецЕсли; + ВсяГруппаБезИсключений = Истина; + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если СписокИсключений.Получить(ОписаниеПользователя.Ключ) <> Неопределено + Или ПользователиИсключаемыхГрупп.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + + ВсяГруппаБезИсключений = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если ВсяГруппаБезИсключений Тогда + Результат.Вставить(Участник, Истина); + Иначе + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если СписокИсключений.Получить(ОписаниеПользователя.Ключ) = Неопределено + И ПользователиИсключаемыхГрупп.Получить(ОписаниеПользователя.Ключ) = Неопределено Тогда + + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции РассчитанноеУсловиеДляСтрок. +// +// Возвращаемое значение: +// Структура из КлючИЗначение: +// * Ключ - Строка - имя таблицы ключа +// * Значение - см. ЗначенияТаблицыКлюча +// +Функция ТекущиеЗначенияТаблицКлюча(Контекст, ТребуемыеРеквизитыТабличныхЧастейКлюча) + + ТекущиеЗначенияТаблицКлюча = Новый Структура; + Для Каждого ОписаниеТаблицы Из ТребуемыеРеквизитыТабличныхЧастейКлюча Цикл + ИмяТаблицыКлюча = ОписаниеТаблицы.Ключ; + Реквизиты = ОписаниеТаблицы.Значение; + ЗначенияТаблицыКлюча = Контекст.ЗначенияТаблицКлюча[ИмяТаблицыКлюча]; + Отбор = Новый Структура; + Для Каждого ТекущееОписание Из Контекст.ОписанияТребуемыхТаблицКлюча Цикл + РеквизитыТаблицы = ТекущееОписание.РеквизитыТаблиц.Получить(ИмяТаблицыКлюча); + ЗначенияТаблицы = ТекущееОписание.ЗначенияТаблиц[ИмяТаблицыКлюча]; + ИндексСтрокиТаблицы = ТекущееОписание.ИндексыСтрокТаблиц.Получить(ИмяТаблицыКлюча); + СтрокаТаблицы = ЗначенияТаблицы[ИндексСтрокиТаблицы]; + Для Каждого ИмяРеквизита Из РеквизитыТаблицы Цикл + Отбор.Вставить(ИмяРеквизита, СтрокаТаблицы[ИмяРеквизита]); + КонецЦикла; + КонецЦикла; + ВсегоРеквизитовТаблицы = Контекст.РеквизитыТаблицКлюча.Получить(ИмяТаблицыКлюча).Количество(); + Если ВсегоРеквизитовТаблицы = Реквизиты.Количество() И Не ЗначениеЗаполнено(Отбор) Тогда + ТекущиеЗначенияТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицыКлюча); + Продолжить; + КонецЕсли; + Строки = ЗначенияТаблицыКлюча; + Если ЗначениеЗаполнено(Отбор) Тогда + Строки = Строки.НайтиСтроки(Отбор); + КонецЕсли; + ЗначенияТаблицы = НовыеЗначенияТаблицыКлюча(); + Для Каждого ИмяРеквизита Из Реквизиты Цикл + ЗначенияТаблицы.Колонки.Добавить(ИмяРеквизита); + КонецЦикла; + Для Каждого Строка Из Строки Цикл + ЗаполнитьЗначенияСвойств(ЗначенияТаблицы.Добавить(), Строка); + КонецЦикла; + Если Реквизиты.Количество() < ВсегоРеквизитовТаблицы Тогда + РеквизитыСтрокой = СтрСоединить(Реквизиты, ", "); + ЗначенияТаблицы.Свернуть(РеквизитыСтрокой); + КонецЕсли; + ТекущиеЗначенияТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицы); + КонецЦикла; + + Возврат ТекущиеЗначенияТаблицКлюча; + +КонецФункции + +// Для функции РассчитанноеУсловиеДляСтрок. +Функция РассчитанноеУсловие(Контекст, Условие, КорневойУзел = Ложь) + + // Проверяемые типы уже учтены. + + Если Условие.Узел = "Поле" Тогда + Значение = Контекст.ТекущиеСтрокиТаблицКлюча[Условие.Таблица][Условие.Реквизит]; + Результат = ?(Значение = Перечисления.ДополнительныеЗначенияДоступа.Истина + Или Значение = Null И Условие.Свойство("ПроверкаЕстьNull"), "Истина", "Ложь"); + + ИначеЕсли Условие.Узел = "Константа" Тогда + Результат = ?(Условие.Значение = Истина, "Истина", + ?(Условие.Значение = "Пусто", "Пусто", "Ложь")); + + ИначеЕсли Условие.Узел = "И" Тогда + + Результат = "Неопределено"; + Для Каждого Аргумент Из Условие.Аргументы Цикл + ТекущийРезультат = РассчитанноеУсловие(Контекст, Аргумент); + Если ТекущийРезультат = "Ложь" Тогда + Результат = "Ложь"; + Прервать; + КонецЕсли; + Если ТекущийРезультат = "Истина" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + ИначеЕсли ТипЗнч(ТекущийРезультат) = Тип("Соответствие") Тогда + Если ТекущийРезультат.Количество() = 0 Тогда + Результат = "Ложь"; + Прервать; + КонецЕсли; + Если ТипЗнч(Результат) = Тип("Строка") Тогда + Результат = ТекущийРезультат; + Иначе + ДобавитьТекущийРезультат(Результат, ТекущийРезультат, Ложь, Контекст); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + КонецЕсли; + + ИначеЕсли Условие.Узел = "Или" Тогда + + Результат = "Неопределено"; + Для Каждого Аргумент Из Условие.Аргументы Цикл + ТекущийРезультат = РассчитанноеУсловие(Контекст, Аргумент); + Если ТекущийРезультат = "Истина" Тогда + Результат = "Истина"; + Прервать; + КонецЕсли; + Если ТекущийРезультат = "Ложь" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Ложь"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + ИначеЕсли ТипЗнч(ТекущийРезультат) = Тип("Соответствие") Тогда + Если ТекущийРезультат.Количество() = 0 Тогда + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + КонецЕсли; + ИначеЕсли ТипЗнч(Результат) = Тип("Строка") Тогда + Результат = ТекущийРезультат; + Иначе + ДобавитьТекущийРезультат(Результат, ТекущийРезультат, Истина, Контекст); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + КонецЕсли; + + ИначеЕсли Условие.Узел = "Не" Тогда + Результат = РассчитанноеУсловие(Контекст, Условие.Аргумент); + Если Результат = "Истина" Тогда + Результат = "Ложь"; + ИначеЕсли Результат = "Ложь" Тогда + Результат = "Истина"; + ИначеЕсли ТипЗнч(Результат) = Тип("Соответствие") Тогда + Если Результат.Количество() = 0 Тогда + Результат = "Истина"; + Иначе + УстановитьОбратныйРезультат(Результат, Контекст); + КонецЕсли; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + Результат = РассчитанноеУсловиеДляСтрок(Контекст, + Условие.Аргумент, Условие, Условие.Узел = "ДляОднойИзСтрок", Ложь); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + Результат = Неопределено; + Для Каждого Когда Из Условие.Когда Цикл + Если РассчитанноеУсловие(Контекст, Когда.Условие) = "Истина" Тогда + Результат = РассчитанноеУсловие(Контекст, Когда.Значение); + Прервать; + КонецЕсли; + КонецЦикла; + Если Результат = Неопределено Тогда + Результат = РассчитанноеУсловие(Контекст, Условие.Иначе); + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + Значение = Контекст.ТекущиеСтрокиТаблицКлюча[Условие.Поле.Таблица][Условие.Поле.Реквизит]; + Если Значение = Null Тогда + Значение = Перечисления.ДополнительныеЗначенияДоступа.Null; + ИначеЕсли Значение = Неопределено Тогда + Значение = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + КонецЕсли; + ОтключеноКакЛожь = Условие.УточненияСравнения.Получить("Отключено") = "Ложь"; + + Если Значение = Перечисления.ДополнительныеЗначенияДоступа.ТипРазрешенный Тогда + Если ОтключеноКакЛожь Тогда + ТекущийРезультат = "Пусто"; + Иначе + ТекущийРезультат = "Истина"; + КонецЕсли; + + ИначеЕсли Значение = Перечисления.ДополнительныеЗначенияДоступа.ТипЗапрещенный Тогда + Если ОтключеноКакЛожь Тогда + ТекущийРезультат = "Пусто"; + Иначе + ТекущийРезультат = "Ложь"; + КонецЕсли; + Иначе + ТекущийРезультат = Неопределено; + Для Каждого УточнениеСравнения Из Условие.УточненияСравнения Цикл + Если УточнениеСравнения.Ключ = "Null" + Или УточнениеСравнения.Ключ = "Неопределено" Тогда + Если Значение = Перечисления.ДополнительныеЗначенияДоступа[УточнениеСравнения.Ключ] Тогда + ТекущийРезультат = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + ИначеЕсли УточнениеСравнения.Ключ = "ПустаяСсылка" Тогда + Если Значение = Перечисления.ДополнительныеЗначенияДоступа.ПустаяСсылкаЛюбогоТипа + Или Значение.Пустая() Тогда + ТекущийРезультат = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + ИначеЕсли УточнениеСравнения.Ключ = ТипЗнч(Значение) Тогда + ТекущийРезультат = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если ТекущийРезультат <> Неопределено Тогда + Результат = ТекущийРезультат; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" Тогда + Если Значение = Перечисления.ДополнительныеЗначенияДоступа.Null + Или Значение = Перечисления.ДополнительныеЗначенияДоступа.Неопределено Тогда + Если ОтключеноКакЛожь Тогда + Результат = "Пусто"; + Иначе + Результат = "Ложь"; + КонецЕсли; + Иначе + Если Контекст.ЗначенияГруппыДоступа = Неопределено Тогда + ЗначенияОдногоТипа = Неопределено; + Иначе + ТипЗначения = ТипЗнч(Значение); + ЗначенияОдногоТипа = Контекст.ЗначенияГруппыДоступа.Получить(ТипЗначения); + КонецЕсли; + Если ЗначенияОдногоТипа = Неопределено Тогда + Если ОтключеноКакЛожь Тогда + Результат = "Пусто"; + Иначе + Результат = "Истина"; + КонецЕсли; + Иначе + ЗначениеУказано = ЗначенияОдногоТипа.Значения.Получить(Значение) <> Неопределено; + Если Не ЗначениеУказано И ТипЗначения = Контекст.ТипПользователя Тогда + ЗначениеУказано = ЗначениеУказаноВГруппеПользователей(Значение, Контекст); + КонецЕсли; + Результат = "Ложь"; + Если ЗначениеУказано И Не ЗначенияОдногоТипа.ВсеРазрешены + Или Не ЗначениеУказано И ЗначенияОдногоТипа.ВсеРазрешены Тогда + Результат = "Истина"; + + ИначеЕсли ТипЗначения = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(Результат, Значение, Контекст); + + ИначеЕсли ТипЗначения = Контекст.ТипГруппыПользователей Тогда + ЗаполнитьРезультатДляГруппыПользователей(Результат, Значение, Контекст); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" Тогда + Если ТипЗнч(Значение) = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(Результат, Значение, Контекст); + Иначе + Результат = "Ложь"; + КонецЕсли; + + ИначеЕсли ТипЗнч(Значение) = Тип("СправочникСсылка.КлючиДоступа") Тогда + ПраваНаСписок = Контекст.ПраваНаСпискиВедущихКлючейДоступа.Получить(Значение); + Если ПраваНаСписок = Неопределено Тогда + Результат = "Ложь"; + Иначе + ПравоИзменение = ПраваНаСписок.ПоГруппамДоступа.Получить(Контекст.ГруппаДоступа); + Если Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение = Неопределено + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение <> Истина Тогда + Результат = "Ложь"; + + ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" И ПраваНаСписок.ОграничениеЧтенияОтключено + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПраваНаСписок.ОграничениеОтключено Тогда + + Результат = "Истина"; + Иначе + ПраваНаВедущийКлючДоступа = Контекст.ПраваНаВедущиеКлючиДоступа.Получить(Значение); + Если ПраваНаВедущийКлючДоступа = Неопределено Тогда + Результат = "Ложь"; + + ИначеЕсли Контекст.РассчитыватьПраваПользователей Тогда + Если Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда + + Результат = "Ложь"; + ПроверятьПравоИзменение = Условие.Узел <> "ЧтениеОбъектаРазрешено"; + ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ПустаяГруппаДоступа); + Если ПравоИзменение <> Неопределено + И (Не ПроверятьПравоИзменение Или ПравоИзменение) Тогда + Результат = "Истина"; + Иначе + ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ГруппаДоступа); + Если ПравоИзменение <> Неопределено + И (Не ПроверятьПравоИзменение Или ПравоИзменение) Тогда + Результат = "Истина"; + КонецЕсли; + КонецЕсли; + Если Результат <> "Истина" Тогда + Результат = Новый Соответствие; + Для Каждого КлючИЗначение Из ПраваНаВедущийКлючДоступа Цикл + Если ПроверятьПравоИзменение И Не КлючИЗначение.Значение Тогда + Продолжить; + КонецЕсли; + ЗначениеКлюча = КлючИЗначение.Ключ; + ТипКлюча = ТипЗнч(ЗначениеКлюча); + Если ТипКлюча = Контекст.ТипГруппыДоступа Тогда + Продолжить; + КонецЕсли; + ТекущийРезультат = "Ложь"; + Если ТипКлюча = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(ТекущийРезультат, ЗначениеКлюча, Контекст); + ИначеЕсли ТипКлюча = Контекст.ТипГруппыПользователей Тогда + ЗаполнитьРезультатДляГруппыПользователей(ТекущийРезультат, ЗначениеКлюча, Контекст); + КонецЕсли; + Если ТекущийРезультат = "Ложь" Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеУчастника Из ТекущийРезультат Цикл + Результат.Вставить(ОписаниеУчастника.Ключ, Истина); + КонецЦикла; + КонецЦикла; + Если Результат.Количество() = 0 Тогда + Результат = "Ложь"; + КонецЕсли; + КонецЕсли; + Иначе + Результат = "Ложь"; + КонецЕсли; + Иначе + ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ГруппаДоступа); + Если Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение <> Неопределено + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение = Истина Тогда + Результат = "Истина"; + Иначе + Результат = "Ложь"; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ИначеЕсли Контекст.ТипыВладельцевНастроекПрав.Получить(ТипЗнч(Значение)) <> Неопределено Тогда + ПраваПоВладельцуНастроекПрав = Контекст.ПраваПоВладельцамНастроекПрав.Получить(Значение); + Если ПраваПоВладельцуНастроекПрав = Неопределено Тогда + Результат = "Ложь"; + + ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда + + ПроверятьПравоИзменение = Условие.Узел <> "ЧтениеОбъектаРазрешено"; + Результат = Новый Соответствие; + Для Каждого КлючИЗначение Из ПраваПоВладельцуНастроекПрав Цикл + Если ПроверятьПравоИзменение И Не КлючИЗначение.Значение Тогда + Продолжить; + КонецЕсли; + ЗначениеКлюча = КлючИЗначение.Ключ; + ТипКлюча = ТипЗнч(ЗначениеКлюча); + ТекущийРезультат = "Ложь"; + Если ТипКлюча = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(ТекущийРезультат, ЗначениеКлюча, Контекст); + ИначеЕсли ТипКлюча = Контекст.ТипГруппыПользователей Тогда + ЗаполнитьРезультатДляГруппыПользователей(ТекущийРезультат, ЗначениеКлюча, Контекст); + КонецЕсли; + Если ТекущийРезультат = "Ложь" Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеУчастника Из ТекущийРезультат Цикл + Результат.Вставить(ОписаниеУчастника.Ключ, Истина); + КонецЦикла; + КонецЦикла; + Если Результат.Количество() = 0 Тогда + Результат = "Ложь"; + КонецЕсли; + Иначе + Результат = "Ложь"; + КонецЕсли; + + Иначе // Проверка прав на список. + ПраваНаВедущийСписок = Контекст.ПраваНаВедущиеСписки.Получить(Значение); + Если ПраваНаВедущийСписок = Неопределено Тогда + ПраваНаВедущийСписок = Контекст.ПраваНаВедущиеСписки.Получить(ТипЗнч(Значение)); + КонецЕсли; + Если ПраваНаВедущийСписок = Неопределено Тогда + Результат = "Ложь"; + Иначе + ПравоИзменение = ПраваНаВедущийСписок.Получить(Контекст.ГруппаДоступа); + Если Условие.Узел = "ЧтениеСпискаРазрешено" И ПравоИзменение <> Неопределено + Или Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение <> Неопределено + Или Условие.Узел = "ИзменениеСпискаРазрешено" И ПравоИзменение = Истина + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение = Истина Тогда + + Результат = "Истина"; + Иначе + Результат = "Ложь"; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ПравоДоступа" Тогда + Результат = ?(ЕстьПравоДоступаВРоляхПрофиляГруппыДоступа(Условие, Контекст), "Истина", "Ложь"); + + ИначеЕсли Условие.Узел = "РольДоступна" Тогда + Результат = ?(ЕстьРольВПрофилеГруппыДоступа(Условие, Контекст), "Истина", "Ложь"); + + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При вычислении прав на ключ доступа узел не поддерживается ""%1"".'"), + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если КорневойУзел И Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Функция ЗначениеУказаноВГруппеПользователей(Пользователь, Контекст) + + УказанныеГруппыПользователей = Контекст.ЗначенияГруппыДоступа.Получить(Контекст.ТипГруппыПользователей); + Если УказанныеГруппыПользователей = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого УказаннаяГруппаПользователей Из УказанныеГруппыПользователей.Значения Цикл + ПользователиГруппы = Контекст.ГруппыПользователейКакЗначенияДоступа.Получить(УказаннаяГруппаПользователей.Ключ); + Если ПользователиГруппы = Неопределено Тогда + Продолжить; + КонецЕсли; + Если ПользователиГруппы.Получить(Пользователь) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Процедура ЗаполнитьРезультатДляПользователя(Результат, Пользователь, Контекст) + + Результат = "Ложь"; + + УчастникиГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если УчастникиГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + Если УчастникиГруппыДоступа.Получить(Пользователь) <> Неопределено Тогда + Результат = Новый Соответствие; + Результат.Вставить(Пользователь, Истина); + Возврат; + КонецЕсли; + + ГрупповыеПользователиГруппыДоступа = Контекст.ГрупповыеПользователиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если ГрупповыеПользователиГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ГрупповыеПользователиГруппыДоступа.Получить(Пользователь) <> Неопределено Тогда + Результат = Новый Соответствие; + Результат.Вставить(Пользователь, Истина); + КонецЕсли; + +КонецПроцедуры + +// Для функции РассчитанноеУсловие. +Процедура ЗаполнитьРезультатДляГруппыПользователей(Результат, ГруппаПользователей, Контекст) + + Результат = "Ложь"; + + УчастникиГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если УчастникиГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + + Если УчастникиГруппыДоступа.Получить(ГруппаПользователей) <> Неопределено Тогда + Результат = Новый Соответствие; + Результат.Вставить(ГруппаПользователей, Истина); + Возврат; + КонецЕсли; + + ПользователиГруппы = Контекст.ПользователиГруппПользователей.Получить(ГруппаПользователей); + Если ПользователиГруппы = Неопределено Тогда + Возврат; + КонецЕсли; + + ГрупповыеПользователиГруппыДоступа = Контекст.ГрупповыеПользователиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если ГрупповыеПользователиГруппыДоступа = Неопределено Тогда + ГрупповыеПользователиГруппыДоступа = Новый Соответствие; + КонецЕсли; + + Результат = Новый Соответствие; + + Если УчастникиГруппыДоступа.Количество() > ПользователиГруппы.Количество() Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если УчастникиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + Продолжить; + КонецЕсли; + Если ГрупповыеПользователиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого ОписаниеУчастника Из УчастникиГруппыДоступа Цикл + Если ПользователиГруппы.Получить(ОписаниеУчастника.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеУчастника.Ключ, Истина); + КонецЕсли; + КонецЦикла; + Если ГрупповыеПользователиГруппыДоступа.Количество() > ПользователиГруппы.Количество() Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если ГрупповыеПользователиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого ОписаниеПользователя Из ГрупповыеПользователиГруппыДоступа Цикл + Если ПользователиГруппы.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + + Если Результат.Количество() = 0 Тогда + Результат = "Ложь"; + КонецЕсли; + +КонецПроцедуры + +// Для функции РассчитанноеУсловие. +Функция ЕстьПравоДоступаВРоляхПрофиляГруппыДоступа(Условие, Контекст) + + ПолноеИмя = Условие.ПолноеИмяОбъектаМетаданных; + Описание = Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Получить(ПолноеИмя); + Если Описание = Неопределено Тогда + Описание = Новый Структура("ОбъектМетаданных, ИмяСтандартногоРеквизита"); + Описание.ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава( + ПолноеИмя, Описание.ИмяСтандартногоРеквизита); + Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Вставить(ПолноеИмя, Описание); + КонецЕсли; + + СтрокаТаблицы = Контекст.ГруппыДоступаПрофилей.Найти(Контекст.ГруппаДоступа, "ГруппаДоступа"); + Если СтрокаТаблицы = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ПраваПрофиля = Контекст.ПраваПрофилейФункцииПравоДоступа.Получить(СтрокаТаблицы.Профиль); + Если ПраваПрофиля = Неопределено Тогда + ПраваПрофиля = Новый Соответствие; + Контекст.ПраваПрофилейФункцииПравоДоступа.Вставить(СтрокаТаблицы.Профиль, ПраваПрофиля); + КонецЕсли; + + КлючПраваВРоляхПрофиля = ПолноеИмя + "/" + Условие.ИмяПрава; + ЕстьПравоВРоляхПрофиля = ПраваПрофиля.Получить(КлючПраваВРоляхПрофиля); + Если ТипЗнч(ЕстьПравоВРоляхПрофиля) = Тип("Булево") Тогда + Возврат ЕстьПравоВРоляхПрофиля; + КонецЕсли; + + Отбор = Новый Структура("Профиль", СтрокаТаблицы.Профиль); + РолиПрофиля = Контекст.РолиПрофилейГруппДоступа.НайтиСтроки(Отбор); + + ЕстьПравоВРоли = Ложь; + Для Каждого ОписаниеРоли Из РолиПрофиля Цикл + КлючПраваРоли = ОписаниеРоли.ИмяРоли + "/" + ПолноеИмя + "/" + Условие.ИмяПрава; + ЕстьПравоВРоли = Контекст.ПраваРолейФункцииПравоДоступа.Получить(КлючПраваРоли); + Если ЕстьПравоВРоли = Неопределено Тогда + Если ЗначениеЗаполнено(ОписаниеРоли.ИмяРоли) Тогда + ПолноеИмяРоли = "Роль." + ОписаниеРоли.ИмяРоли; + Роль = Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Получить(ПолноеИмяРоли); + Если Роль = Неопределено Тогда + Роль = Метаданные.Роли[ОписаниеРоли.ИмяРоли]; + Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Вставить(ПолноеИмяРоли, Роль); + КонецЕсли; + ЕстьПравоВРоли = ПравоДоступа(Условие.ИмяПрава, Описание.ОбъектМетаданных, Роль, + Описание.ИмяСтандартногоРеквизита); + Иначе + ЕстьПравоВРоли = Ложь; + КонецЕсли; + Контекст.ПраваРолейФункцииПравоДоступа.Вставить(КлючПраваРоли, ЕстьПравоВРоли); + КонецЕсли; + Если ЕстьПравоВРоли Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + ПраваПрофиля.Вставить(КлючПраваВРоляхПрофиля, ЕстьПравоВРоли); + + Возврат ЕстьПравоВРоли; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Функция ЕстьРольВПрофилеГруппыДоступа(Условие, Контекст) + + СтрокаТаблицы = Контекст.ГруппыДоступаПрофилей.Найти(Контекст.ГруппаДоступа, "ГруппаДоступа"); + Если СтрокаТаблицы = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Отбор = Новый Структура("Профиль,ИмяРолиВерхнийРегистр", СтрокаТаблицы.Профиль, ВРег(Условие.ИмяРоли)); + + Возврат Контекст.РолиПрофилейГруппДоступа.НайтиСтроки(Отбор).Количество() > 0; + +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ОбновитьПраваНаКлючДоступаСписка(КлючДоступа, ПраваНаКлюч, ОписаниеНовыхКлючей, ПараметрыОбновления) + + Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + ПраваНаКлючДляПользователей = Новый Соответствие; + ТипПользователя = ПараметрыОбновления.ТипПользователя; + Для Каждого КлючИЗначение Из ПраваНаКлюч.ДляПользователей Цикл + Если ТипЗнч(КлючИЗначение.Ключ) = ТипПользователя Тогда + Набор = Справочники.НаборыГруппДоступа.ПолучитьСсылку(КлючИЗначение.Ключ.УникальныйИдентификатор()); + ПраваНаКлючДляПользователей.Вставить(Набор, КлючИЗначение.Значение); + Иначе + ПраваНаКлюч.ДляГрупп.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + + ЗапросГрупп = Новый Запрос; + ЗапросГрупп.УстановитьПараметр("КлючДоступа", КлючДоступа); + ЗапросГрупп.Текст = + "ВЫБРАТЬ + | КлючиДоступаГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + |ГДЕ + | КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа + | И &УточнениеПланаЗапроса"; + УстановитьУточнениеПланаЗапроса(ЗапросГрупп.Текст); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + ЭлементБлокировкиГрупп = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировкиГрупп.УстановитьЗначение("КлючДоступа", КлючДоступа); + НаборЗаписейГрупп = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписейГрупп.Отбор.КлючДоступа.Установить(КлючДоступа); + КонецЕсли; + + ЗапросНаборовГруппДоступа = Новый Запрос; + ЗапросНаборовГруппДоступа.УстановитьПараметр("КлючДоступа", КлючДоступа); + ЗапросНаборовГруппДоступа.УстановитьПараметр("РазрешенныйПустойНабор", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + ЗапросНаборовГруппДоступа.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа(); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", КлючДоступа); + НаборЗаписейНаборовГруппДоступа = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписейНаборовГруппДоступа.Отбор.КлючДоступа.Установить(КлючДоступа); + КонецЕсли; + + Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("КлючДоступа", КлючДоступа); + + Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляПользователей(); + ИмяПоляВладельцаПрав = "Пользователь"; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); + Иначе + Запрос.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляВнешнихПользователей(); + ИмяПоляВладельцаПрав = "ВнешнийПользователь"; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); + КонецЕсли; + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", КлючДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.КлючДоступа.Установить(КлючДоступа); + КонецЕсли; + КонецЕсли; + + Если ОписаниеНовыхКлючей <> Неопределено Тогда + ОписаниеНовогоКлюча = ОписаниеНовыхКлючей.ОписанияКлючейПоСсылке.Получить(КлючДоступа); + КлючДоступаОбъект = ОписаниеНовогоКлюча.КлючДоступаОбъект; // СправочникОбъект.КлючиДоступа + ЭлементБлокировкиКлюча = Блокировка.Добавить("Справочник.КлючиДоступа"); + ЭлементБлокировкиКлюча.УстановитьЗначение("Хеш", КлючДоступаОбъект.Хеш); + ЭлементБлокировкиКлюча.УстановитьЗначение("Список", КлючДоступаОбъект.Список); + ЭлементБлокировкиКлюча.УстановитьЗначение("ДляВнешнихПользователей", КлючДоступаОбъект.ДляВнешнихПользователей); + ЭлементБлокировкиКлюча.УстановитьЗначение("СоставПолей", КлючДоступаОбъект.СоставПолей); + КонецЕсли; + + ОбновлениеВручную = ПараметрыОбновления.Свойство("ОбновитьПраваНаКлючи") + И ПараметрыОбновления.ОбновитьПраваНаКлючи; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Если ОписаниеНовыхКлючей <> Неопределено Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); + КонецЕсли; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + + НачатьТранзакцию(); + Попытка + ПередБлокировкойДанных(ПараметрыОбновления); + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + Блокировка.Заблокировать(); + ПослеБлокировкиДанных(ПараметрыОбновления); + + ЕстьИзмененияПрав = Ложь; + + Если ОписаниеНовыхКлючей = Неопределено + Или Не НовыйКлючДоступаУжеСуществует(ОписаниеНовыхКлючей, ОписаниеНовогоКлюча, ПараметрыОбновления) Тогда + + Если ОписаниеНовыхКлючей <> Неопределено Тогда + ПередЗаписьюНовогоКлюча(ПараметрыОбновления); + КлючДоступаОбъект.Записать(); + ПослеЗаписиНовогоКлюча(ПараметрыОбновления); + КонецЕсли; + + ПередЗапросомПравГруппДоступа(ПараметрыОбновления); + РезультатЗапросаГрупп = ЗапросГрупп.Выполнить(); + ПослеЗапросаПравГруппДоступа(ПараметрыОбновления); + + ЕстьИзменения = Новый Структура("ПраваГруппДоступа, ПраваГруппПользователей", Ложь, Ложь); + ОбновитьИсходныеПраваГруппНаКлючДоступа(РезультатЗапросаГрупп, НаборЗаписейГрупп, "ГруппаДоступа", + КлючДоступа, ПраваНаКлюч.ДляГрупп, ПараметрыОбновления, ЕстьИзменения); + + ЕстьИзмененияПрав = ЕстьИзменения.ПраваГруппДоступа Или ЕстьИзменения.ПраваГруппПользователей; + + Если ЕстьИзменения.ПраваГруппДоступа Или ОбновлениеВручную Тогда + ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления); + РезультатЗапросаНаборовГруппДоступа = ЗапросНаборовГруппДоступа.Выполнить(); + ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаНаборовГруппДоступа, + НаборЗаписейНаборовГруппДоступа, "НаборГруппДоступа", КлючДоступа, , ПараметрыОбновления); + КонецЕсли; + + Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + ЗапросыПакета = СтрРазделить(Запрос.Текст, ";", Ложь); + Если ЕстьИзменения.ПраваГруппПользователей Или ОбновлениеВручную Тогда + Запрос.Текст = ЗапросыПакета[1]; + ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления); + РезультатЗапроса = Запрос.Выполнить(); + ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапроса, + НаборЗаписей, ИмяПоляВладельцаПрав, КлючДоступа, , ПараметрыОбновления); + НаборЗаписей.Очистить(); + КонецЕсли; + Запрос.Текст = ЗапросыПакета[0]; + ПередЗапросомПравПользователей(ПараметрыОбновления); + РезультатЗапросаПользователей = Запрос.Выполнить(); + ПослеЗапросаПравПользователей(ПараметрыОбновления); + ОбновитьИсходныеПраваПользователейНаКлючДоступа(РезультатЗапросаПользователей, НаборЗаписей, + ИмяПоляВладельцаПрав, КлючДоступа, ПраваНаКлючДляПользователей, ЕстьИзмененияПрав, ПараметрыОбновления); + КонецЕсли; + + Если ОписаниеНовыхКлючей = Неопределено + И ЕстьИзмененияПрав + И ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа.Количество() > 0 Тогда + + ПередПланированиемОбновления(ПараметрыОбновления); + ЗапланироватьОбновлениеПользователейКлючейДоступа(ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа, + "ОбновитьПраваНаКлючДоступаСписка", + Не ПараметрыОбновления.ДляВнешнихПользователей, + ПараметрыОбновления.ДляВнешнихПользователей, , + Новый Структура("ПоКлючамДоступа", КлючДоступа)); + ПослеПланированияОбновления(ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + + // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, + // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), + // а в режиме анализа производительности последствия учитываются и не являются критичными. + ПередФиксациейТранзакции(ПараметрыОбновления); + ЗафиксироватьТранзакцию(); + ПослеФиксацииТранзакции(ПараметрыОбновления); + // АПК:330-вкл. + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЕстьИзмененияПрав И ПараметрыОбновления.Свойство("ЕстьИзмененияПрав") Тогда + ПараметрыОбновления.ЕстьИзмененияПрав = Истина; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьПраваНаКлючДоступаСписка, ОбновитьГруппыДоступаРазрешенногоКлючаДоступа. +Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа() + + ТекстЗапроса = + "ВЫБРАТЬ + | ВсеСтроки.НаборГруппДоступа КАК НаборГруппДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыВходящиеВНаборы.Ссылка КАК НаборГруппДоступа, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) + | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | ГруппыВходящиеВНаборы.Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | &РазрешенныйПустойНабор, + | КлючиДоступаГруппДоступа.ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление, + | 1 + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ГДЕ + | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.НаборГруппДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.НаборГруппДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедур ОбновитьПраваНаКлючДоступаСписка. +Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляПользователей() + + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступаПользователей.Пользователь КАК Пользователь, + | КлючиДоступаПользователей.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаПользователей.ПравоДобавление КАК ПравоДобавление, + | КлючиДоступаПользователей.ЭтоПраваНабораГрупп КАК ЭтоПраваНабораГрупп + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей + |ГДЕ + | КлючиДоступаПользователей.КлючДоступа = &КлючДоступа + | И НЕ КлючиДоступаПользователей.ЭтоПраваНабораГрупп + | И &УточнениеПланаЗапроса + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ВсеСтроки.Пользователь КАК Пользователь, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыВходящиеВНаборы.Ссылка КАК Пользователь, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыПользователей)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыПользователей)) + | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | ГруппыВходящиеВНаборы.Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.Пользователь, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.ЭтоПраваНабораГрупп + | И СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.Пользователь, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедур ОбновитьПраваНаКлючДоступаСписка. +Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляВнешнихПользователей() + + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступаВнешнихПользователей.ВнешнийПользователь КАК ВнешнийПользователь, + | КлючиДоступаВнешнихПользователей.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаВнешнихПользователей.ПравоДобавление КАК ПравоДобавление, + | КлючиДоступаВнешнихПользователей.ЭтоПраваНабораГрупп КАК ЭтоПраваНабораГрупп + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей + |ГДЕ + | КлючиДоступаВнешнихПользователей.КлючДоступа = &КлючДоступа + | И НЕ КлючиДоступаВнешнихПользователей.ЭтоПраваНабораГрупп + | И &УточнениеПланаЗапроса + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ВсеСтроки.ВнешнийПользователь КАК ВнешнийПользователь, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыВходящиеВНаборы.Ссылка КАК ВнешнийПользователь, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыВнешнихПользователей)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыВнешнихПользователей)) + | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | ГруппыВходящиеВНаборы.Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.ВнешнийПользователь, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.ЭтоПраваНабораГрупп + | И СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.ВнешнийПользователь, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Функция НовыйКлючДоступаУжеСуществует(ОписаниеНовыхКлючей, ОписаниеНовогоКлюча, ПараметрыОбновления) + + ЗапросСуществованияКлючей = ОписаниеНовыхКлючей.ЗапросСуществованияКлючей; + ЗапросСуществованияКлючей.УстановитьПараметр("Хеш", ОписаниеНовогоКлюча.КлючДоступаОбъект.Хеш); + + Если ЗапросСуществованияКлючей.Выполнить().Пустой() Тогда + Возврат Ложь; + КонецЕсли; + + ЗапросЗначенийКлючей = ОписаниеНовыхКлючей.ЗапросЗначенийКлючей; + ЗапросЗначенийКлючей.УстановитьПараметр("Хеши", ОписаниеНовогоКлюча.КлючДоступаОбъект.Хеш); + + РезультатыЗапросаЗначенийКлючей = ЗапросЗначенийКлючей.ВыполнитьПакет(); + + ТаблицыКлюча = ПараметрыОбновления.ТаблицыКлюча; + КлючиЗначенийСтрокКлючей = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийКлючей, + ?(Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) + Или СтрНачинаетсяС(ТаблицыКлюча[0], "Шапка"), 0, 1), + ТаблицыКлюча); + + Выборка = РезультатыЗапросаЗначенийКлючей[0].Выбрать(); + + Пока Выборка.Следующий() Цикл + Ссылка = Выборка.ТекущаяСсылка; // СправочникСсылка.КлючиДоступа + ОписаниеКлючейЗначений = КлючиЗначенийСтрокКлючей.Получить(Ссылка); + СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); + Если ОписаниеНовогоКлюча.СтрокаДляХеша = СтрокаДляХеша Тогда + ОписаниеНовогоКлюча.КлючДоступаОбъект = Новый Структура("Ссылка", Ссылка); + НеИспользуетсяС = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "НеИспользуетсяС"); + Если ЗначениеЗаполнено(НеИспользуетсяС) Тогда + Объект = СлужебныйЭлемент(Неопределено, Ссылка); + Объект.НеИспользуетсяС = '00010101'; + Объект.Записать(); + КонецЕсли; + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Процедура ОбновитьИсходныеПраваГруппНаКлючДоступа(РезультатЗапроса, НаборЗаписей, ИмяПоляВладельцаПрав, + КлючДоступа, ПраваНаКлюч, ПараметрыОбновления, ЕстьИзменения) + + Выборка = РезультатЗапроса.Выбрать(); + ТипГруппыДоступа = ПараметрыОбновления.ТипГруппыДоступа; + ЕстьИзмененияПравГруппДоступа = Ложь; + ЕстьИзмененияПравГруппПользователей = Ложь; + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + КоличествоЗаписанных = 0; + ПередЗаписьюСтрок(ПараметрыОбновления); + + Пока Выборка.Следующий() Цикл + ВладелецПрав = Выборка[ИмяПоляВладельцаПрав]; + Права = ПраваНаКлюч.Получить(ВладелецПрав); // См. НовыеПрава + Если Права = Неопределено Тогда + Если ПакетныйРежим Тогда + СтараяЗапись = НаборЗаписей.Добавить(); + СтараяЗапись.КлючДоступа = КлючДоступа; + СтараяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + НаборЗаписей.Записать(); + КонецЕсли; + Если ТипЗнч(ВладелецПрав) = ТипГруппыДоступа Тогда + ЕстьИзмененияПравГруппДоступа = Истина; + Иначе + ЕстьИзмененияПравГруппПользователей = Истина; + КонецЕсли; + ИначеЕсли Выборка.ПравоИзменение = Права.ПравоИзменение + И Выборка.ПравоДобавление = Права.ПравоДобавление Тогда + ПраваНаКлюч.Вставить(ВладелецПрав, Null); + КонецЕсли; + КонецЦикла; + + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись.КлючДоступа = КлючДоступа; + + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + + Для Каждого ОписаниеПрав Из ПраваНаКлюч Цикл + Права = ОписаниеПрав.Значение; // См. НовыеПрава + Если Права = Null Тогда + Продолжить; + КонецЕсли; + ВладелецПрав = ОписаниеПрав.Ключ; + Если ПакетныйРежим Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючДоступа = КлючДоступа; + НоваяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + НоваяЗапись.ПравоИзменение = Права.ПравоИзменение; + НоваяЗапись.ПравоДобавление = Права.ПравоДобавление; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + ОднаЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + ОднаЗапись.ПравоИзменение = Права.ПравоИзменение; + ОднаЗапись.ПравоДобавление = Права.ПравоДобавление; + НаборЗаписей.Записать(); + КонецЕсли; + Если ТипЗнч(ВладелецПрав) = ТипГруппыДоступа Тогда + ЕстьИзмененияПравГруппДоступа = Истина; + Иначе + ЕстьИзмененияПравГруппПользователей = Истина; + КонецЕсли; + КоличествоЗаписанных = КоличествоЗаписанных + 1; + КонецЦикла; + + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + + ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); + + ЕстьИзменения.ПраваГруппДоступа = ЕстьИзмененияПравГруппДоступа; + ЕстьИзменения.ПраваГруппПользователей = ЕстьИзмененияПравГруппПользователей; + +КонецПроцедуры + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Процедура ОбновитьИсходныеПраваПользователейНаКлючДоступа(РезультатЗапроса, НаборЗаписей, + ИмяПоляВладельцаПрав, КлючДоступа, ПраваНаКлюч, ЕстьИзмененияПрав, ПараметрыОбновления) + + Выборка = РезультатЗапроса.Выбрать(); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + КоличествоЗаписанных = 0; + ПередЗаписьюСтрок(ПараметрыОбновления); + + Пока Выборка.Следующий() Цикл + ВладелецПрав = Выборка[ИмяПоляВладельцаПрав]; + Права = ПраваНаКлюч.Получить(ВладелецПрав); // См. НовыеПрава + Если Права = Неопределено Тогда + Если ПакетныйРежим Тогда + СтараяЗапись = НаборЗаписей.Добавить(); + СтараяЗапись.КлючДоступа = КлючДоступа; + СтараяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + НаборЗаписей.Записать(); + КонецЕсли; + ЕстьИзмененияПрав = Истина; + ИначеЕсли Выборка.ПравоИзменение = Права.ПравоИзменение + И Выборка.ПравоДобавление = Права.ПравоДобавление + И Выборка.ЭтоПраваНабораГрупп = Ложь Тогда + ПраваНаКлюч.Вставить(ВладелецПрав, Null); + КонецЕсли; + КонецЦикла; + + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись.КлючДоступа = КлючДоступа; + + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + + Для Каждого ОписаниеПрав Из ПраваНаКлюч Цикл + Права = ОписаниеПрав.Значение; // См. НовыеПрава + Если Права = Null Тогда + Продолжить; + КонецЕсли; + ВладелецПрав = ОписаниеПрав.Ключ; + Если ПакетныйРежим Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючДоступа = КлючДоступа; + НоваяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + НоваяЗапись.ПравоИзменение = Права.ПравоИзменение; + НоваяЗапись.ПравоДобавление = Права.ПравоДобавление; + НоваяЗапись.ЭтоПраваНабораГрупп = Ложь; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + ОднаЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + ОднаЗапись.ПравоИзменение = Права.ПравоИзменение; + ОднаЗапись.ПравоДобавление = Права.ПравоДобавление; + ОднаЗапись.ЭтоПраваНабораГрупп = Ложь; + НаборЗаписей.Записать(); + КонецЕсли; + ЕстьИзмененияПрав = Истина; + КоличествоЗаписанных = КоличествоЗаписанных + 1; + КонецЦикла; + + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + + ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); + +КонецПроцедуры + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Процедура ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапроса, НаборЗаписей, ИмяПоляВладельцаПрав, + КлючДоступа, ЕстьИзменения = Ложь, ПараметрыОбновления = Неопределено) + + Выборка = РезультатЗапроса.Выбрать(); + УдалениеЗавершено = Ложь; + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + КоличествоЗаписанных = 0; + ПередЗаписьюСтрок(ПараметрыОбновления); + + Пока Выборка.Следующий() Цикл + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(Выборка[ИмяПоляВладельцаПрав]); + КонецЕсли; + Если Не УдалениеЗавершено И Выборка.ВидИзмененияСтроки = 1 Тогда + УдалениеЗавершено = Истина; + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись.КлючДоступа = КлючДоступа; + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + Если УдалениеЗавершено Тогда + ЗаполнитьЗначенияСвойств(ОднаЗапись, Выборка); + КонецЕсли; + НаборЗаписей.Записать(); + Иначе + Запись = НаборЗаписей.Добавить(); + Запись.КлючДоступа = КлючДоступа; + ЗаполнитьЗначенияСвойств(Запись, Выборка); + КонецЕсли; + ЕстьИзменения = Истина; + КоличествоЗаписанных = КоличествоЗаписанных + 1; + КонецЦикла; + + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(?(УдалениеЗавершено, РежимСлияния, РежимУдаления)); + КонецЕсли; + + ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); + +КонецПроцедуры + +// Создает служебный элемент справочника, который не участвует в подписках на события. +Функция СлужебныйЭлемент(МенеджерСправочника, Ссылка = Неопределено) + + Если Ссылка = Неопределено Тогда + ЭлементСправочника = МенеджерСправочника.СоздатьЭлемент(); + Иначе + ЭлементСправочника = Ссылка.ПолучитьОбъект(); + Если ЭлементСправочника = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + КонецЕсли; + + ЭлементСправочника.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); + ЭлементСправочника.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); + ЭлементСправочника.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; + ЭлементСправочника.ОбменДанными.Загрузка = Истина; + + Возврат ЭлементСправочника; + +КонецФункции + +// Создает набор записей служебного регистра, который не участвует в подписках на события. +Функция СлужебныйНаборЗаписей(МенеджерРегистра) + + НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей(); + НаборЗаписей.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); + НаборЗаписей.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); + НаборЗаписей.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; + НаборЗаписей.ОбменДанными.Загрузка = Истина; + + Возврат НаборЗаписей; + +КонецФункции + +// Создает менеджер значения служебной константы, которая не участвует в подписках на события. +Функция СлужебныйМенеджерЗначения(МенеджерКонстанты) + + МенеджерЗначения = МенеджерКонстанты.СоздатьМенеджерЗначения(); + МенеджерЗначения.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); + МенеджерЗначения.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); + МенеджерЗначения.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; + МенеджерЗначения.ОбменДанными.Загрузка = Истина; + + Возврат МенеджерЗначения; + +КонецФункции + +// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступа. +Процедура ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале(Списки, ПараметрыПланирования) + + КомментарийДляЖурнала = НСтр("ru = 'Источник'", ОбщегоНазначения.КодОсновногоЯзыка()) + + ": " + ПараметрыПланирования.Описание + Символы.ПС; + + Если Списки.Количество() > 1 Тогда + КомментарийДляЖурнала = КомментарийДляЖурнала + + НСтр("ru = 'Списки'", ОбщегоНазначения.КодОсновногоЯзыка()) + ":" + + Символы.ПС + Символы.Таб + СтрСоединить(Списки, Символы.ПС + Символы.Таб); + Иначе + КомментарийДляЖурнала = КомментарийДляЖурнала + + НСтр("ru = 'Список'", ОбщегоНазначения.КодОсновногоЯзыка()); + + КомментарийДляЖурнала = КомментарийДляЖурнала + " = " + Списки[0]; + КонецЕсли; + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоТочечноеЗадание" + + " = " + ?(ПараметрыПланирования.Свойство("ЭтоТочечноеЗадание"), "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "КлючиДоступаКДанным" + + " = " + ?(ПараметрыПланирования.КлючиДоступаКДанным, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "РазрешенныеКлючиДоступа" + + " = " + ?(ПараметрыПланирования.РазрешенныеКлючиДоступа, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ДляПользователей" + + " = " + ?(ПараметрыПланирования.ДляПользователей, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ДляВнешнихПользователей" + + " = " + ?(ПараметрыПланирования.ДляВнешнихПользователей, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоПродолжениеОбновления" + + " = " + ?(ПараметрыПланирования.ЭтоПродолжениеОбновления, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоОбработкаУстаревшихЭлементов" + + " = " + ?(ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов, "Да", "Нет"); + + ВедущийОбъект = Неопределено; + ОписаниеВедущегоОбъекта = ПараметрыПланирования.ВедущийОбъект; // См. ОписаниеВедущегоОбъекта + + Если ТипЗнч(ОписаниеВедущегоОбъекта) = Тип("Структура") Тогда + Если ОписаниеВедущегоОбъекта.Свойство("ПоЗначениямПолей") Тогда + Указатели = ОписаниеВедущегоОбъекта.ПоЗначениямПолей.Описание; + ВедущийОбъект = "ПоЗначениямПолей"; + ИначеЕсли ОписаниеВедущегоОбъекта.Свойство("ПоКлючамДоступа") Тогда + Указатели = ОписаниеВедущегоОбъекта.ПоКлючамДоступа; + ВедущийОбъект = "ПоКлючамДоступа"; + ИначеЕсли ОписаниеВедущегоОбъекта.Свойство("ПоЗначениямСГруппами") Тогда + Указатели = ОписаниеВедущегоОбъекта.ПоЗначениямСГруппами; + ВедущийОбъект = "ПоЗначениямСГруппами"; + КонецЕсли; + Если ВедущийОбъект <> Неопределено Тогда + Если ТипЗнч(Указатели) = Тип("Массив") И Указатели.Количество() > 1 Тогда + ВедущийОбъект = ВедущийОбъект + ":"; + Для Каждого Указатель Из Указатели Цикл + ВедущийОбъект = ВедущийОбъект + Символы.ПС + """" + Строка(Указатель) + """ " + + ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования); + КонецЦикла; + Иначе + Указатель = ?(ТипЗнч(Указатели) = Тип("Массив"), Указатели[0], Указатели); + ВедущийОбъект = ВедущийОбъект + ": """ + Строка(Указатель) + """ " + + ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования); + КонецЕсли; + КонецЕсли; + Если ОписаниеВедущегоОбъекта.Свойство("ПоДаннымКэшаРасчетаПрав") Тогда + ВедущийОбъект = "ПоДаннымКэшаРасчетаПрав" + ": """ + + ОписаниеВедущегоОбъекта.ПоДаннымКэшаРасчетаПрав; + КонецЕсли; + КонецЕсли; + + Попытка + ВызватьИсключение НСтр("ru = 'Стек вызовов'"); + Исключение + СтекВызовов = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()); + КонецПопытки; + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + Символы.ПС + СтекВызовов; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Показатели.Планирование обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, , + ВедущийОбъект, + КомментарийДляЖурнала, + ?(ТранзакцияАктивна(), РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная, Неопределено)); + +КонецПроцедуры + +// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале. +Функция ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования) + + Если ПараметрыПланирования.Свойство("ТиповСсылокВедущихОбъектов") Тогда + ТипыСсылок = ПараметрыПланирования.ТиповСсылокВедущихОбъектов; + Иначе + ТипыСсылок = УправлениеДоступомСлужебныйПовтИсп.ТиповСсылокВедущихОбъектов(); + ПараметрыПланирования.Вставить("ТиповСсылокВедущихОбъектов", ТипыСсылок); + КонецЕсли; + + Если ТипыСсылок.Получить(ТипЗнч(Указатель)) <> Неопределено Тогда + Возврат ПолучитьНавигационнуюСсылку(Указатель); + КонецЕсли; + + Описание = ""; + Для Каждого ЭлементОтбора Из Указатель Цикл + Если Не ЭлементОтбора.Использование Тогда + Продолжить; + КонецЕсли; + Если ТипыСсылок.Получить(ТипЗнч(ЭлементОтбора.Значение)) <> Неопределено Тогда + ОписаниеЗначения = ПолучитьНавигационнуюСсылку(ЭлементОтбора.Значение); + ИначеЕсли ТипЗнч(ЭлементОтбора.Значение) = Тип("Неопределено") Тогда + ОписаниеЗначения = НСтр("ru = 'Неопределено'"); + Иначе + ОписаниеЗначения = Формат(ЭлементОтбора.Значение, "ЧН=0; ДП='01.01.0001 00:00:00'"); + КонецЕсли; + Описание = Описание + ?(Описание = "", "", ", ") + + ЭлементОтбора.Имя + " = " + ОписаниеЗначения; + КонецЦикла; + + Возврат Описание; + +КонецФункции + +// Для вызова из мест планирования обновления доступа. +Процедура ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования, ВсеСписки = Ложь) + + Если Не РегистрироватьПоказателиПланированияОбновленияДоступа() + Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда + Возврат; + КонецЕсли; + + Если ПараметрыПланирования = Неопределено Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + КонецЕсли; + + Списки = Новый Массив; + + Если Не ВсеСписки Тогда + Если ПараметрыПланирования.ИдентификаторыВсехСписков <> Неопределено Тогда + ВсеПолныеИменаПоИдентификаторам = Новый Соответствие; + Для Каждого КлючИЗначение Из ПараметрыПланирования.ИдентификаторыВсехСписков Цикл + ВсеПолныеИменаПоИдентификаторам.Вставить(КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЦикла; + КонецЕсли; + Для Каждого ОписаниеСписка Из СпискиПоИдентификаторам Цикл + Если ЗначениеЗаполнено(ОписаниеСписка.Значение) Тогда + Списки.Добавить(ОписаниеСписка.Значение); + Иначе + Списки.Добавить(ПолноеИмяСписка(ОписаниеСписка.Ключ, ВсеПолныеИменаПоИдентификаторам)); + КонецЕсли; + КонецЦикла; + Иначе + Списки.Добавить("Все"); + КонецЕсли; + + ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале(Списки, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступа. +Функция ПолноеИмяСписка(ОписаниеСписка, ВсеПолныеИменаПоИдентификаторам) + + Если ТипЗнч(ОписаниеСписка) = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") + Или ТипЗнч(ОписаниеСписка) = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда + + Если ВсеПолныеИменаПоИдентификаторам = Неопределено Тогда + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(ОписаниеСписка, Ложь); + Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда + Возврат ОбъектМетаданных.ПолноеИмя(); + КонецЕсли; + Иначе + ПолноеИмя = ВсеПолныеИменаПоИдентификаторам.Получить(ОписаниеСписка); + КонецЕсли; + + Если ПолноеИмя <> Неопределено Тогда + Возврат ПолноеИмя; + Иначе + Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ОписаниеСписка, "ПолноеИмя"); + КонецЕсли; + Иначе + Возврат Строка(ОписаниеСписка); + КонецЕсли; + +КонецФункции + +// Для процедуры УправлениеДоступом.ОтключитьОбновлениеКлючейДоступа. +// +// Параметры: +// Списки - Массив +// ДобавленныеСписки - Соответствие +// НедоступныеСписки - Массив - возвращаемое значение. +// +Процедура ДобавитьЗависимыеСписки(Списки, ДобавленныеСписки, НедоступныеСписки) Экспорт + + ИсходныеСписки = Новый ФиксированныйМассив(Списки); + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + + НенайденныеСписки = Новый Массив; + + Для Каждого ИсходныйСписок Из ИсходныеСписки Цикл + Свойства = ДействующиеПараметры.ВедущиеСписки.Получить(ИсходныйСписок); + Если Свойства = Неопределено Тогда + Продолжить; + КонецЕсли; + Для Каждого КлючИЗначение Из Свойства.ЗависимыеСписки Цикл + Если ДобавленныеСписки.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(КлючИЗначение.Ключ); + Если ОбъектМетаданных = Неопределено Тогда + НенайденныеСписки.Добавить(КлючИЗначение.Ключ); + Иначе + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + Списки.Добавить(ПолноеИмя); + ДобавленныеСписки.Вставить(ПолноеИмя, Истина); + КонецЕсли; + ДобавленныеСписки.Вставить(КлючИЗначение.Ключ, Истина); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Если НенайденныеСписки.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + НедоступныеСписки = ВсеИдентификаторыСПодобнымиПолнымиИменами(НенайденныеСписки); + +КонецПроцедуры + +Функция ОписаниеОграниченийДанных() Экспорт + + ОбщийКонтекст = Новый Структура; + ОбщийКонтекст.Вставить("СпискиСОграничением", УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением()); + + Результат = Новый Соответствие; + + Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); + Результат.Вставить(ПолноеИмя, ОписаниеОграничения); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +#Область ПараметрыДляПереопределенияЧерезРасширениеКонфигурации + +Функция КоличествоЧасовУстареванияНеиспользуемыхЭлементов() + + Возврат 47; + +КонецФункции + +Функция КоличествоЧасовМеждуПланированиемОбработкиУстаревшихЭлементов() + + Возврат 48; + +КонецФункции + +Функция МаксимальноеКоличествоМинутВыполненияФоновогоЗаданияОбновленияДоступа() + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Возврат 2; + Иначе + Возврат 15; + КонецЕсли; + +КонецФункции + +Функция МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке() Экспорт + + Возврат 900; // 15 минут (например, избыточно длительный запрос SQL). + +КонецФункции + +Функция МинимальноеКоличествоСекундОбработкиПорцииВОтдельномПотоке() + + Возврат 1; + +КонецФункции + +Функция МинимальноеКоличествоСекундВыполненияТочечногоЗадания() + + Возврат 15; + +КонецФункции + +Функция ЗагружатьСвободныеПотокиСледующимиЗаданиямиПриДлительныхЗапросах() + + Возврат Истина; + +КонецФункции + +Функция МаксимальныйПериодПолученияПорцийЗапросом() + + Возврат "Год"; // Год, Квартал, Месяц, Неделя. + +КонецФункции + +Функция ЗапускатьОбновлениеПолученныхПорцийПриПолученииНовыхПорций() + + Возврат Ложь; + +КонецФункции + +Функция МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных() + + Возврат 15; // 0 - отключить балансировку нагрузки на диск. + +КонецФункции + +Функция КоличествоЭлементовДанныхВЗапросе() + + Возврат 1000; + +КонецФункции + +Функция КоличествоЭлементовДанныхВПорции() + + Возврат 1000; + +КонецФункции + +Функция КоличествоКлючейДоступаВЗапросе() + + Возврат 1000; + +КонецФункции + +Функция КоличествоКлючейДоступаВПорции() + + Возврат 200; + +КонецФункции + +Функция ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных() + + Возврат Ложь; + +КонецФункции + +Функция МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных() + + Возврат 100; + +КонецФункции + +Функция КоличествоСекундПередОтключениемРегламентногоЗаданияПослеПолногоЗавершенияОбновления() + + Возврат 15; + +КонецФункции + +Функция ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(ПроверкаПриЗапуске) + + Результат = Ложь; + + Если ОбщегоНазначения.РазделениеВключено() Тогда + Результат = Истина; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Функция РегистрироватьПоказателиОбновленияДоступа() + + Возврат Истина; + +КонецФункции + +Функция РегистрироватьПоказателиПланированияОбновленияДоступа() + + Возврат Ложь; + +КонецФункции + +Функция РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() + + Возврат Ложь; + +КонецФункции + +#КонецОбласти + +#Область ТочкиПодключенияДляАнализаПроизводительностиЧерезРасширениеКонфигурации + +Процедура ПередБлокировкойДанных(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеБлокировкиДанных(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗаписьюСтрок(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных) + Возврат; +КонецПроцедуры + +Процедура ПередФиксациейТранзакции(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеФиксацииТранзакции(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередПланированиемОбновления(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеПланированияОбновления(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗаписьюНовогоКлюча(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗаписиНовогоКлюча(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомПравГруппДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаПравГруппДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомПравПользователей(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаПравПользователей(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередИзменениемПараметровСеансаДляШаблонов(НовыеЗначения, ЭтоУстановка) + Возврат; +КонецПроцедуры + +Процедура ПриОшибкеПроверкиАктуальностиМетаданных(ТекстОшибки) + Возврат; +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область ПараметрыОграниченияДоступа + +#Область ПараметрыОграниченияДоступаОбщаяЧасть + +// Основная функция, возвращающая параметры, необходимые для регистрации +// необходимости обновления ключей доступа к элементам данных. +// +// Параметры: +// ПолноеИмя - Строка - полное имя списка +// ИдентификаторТранзакции - УникальныйИдентификатор +// ПовторныйВызов - Булево - только при вызове из самой же функции +// +// Возвращаемое значение: +// Структура: +// * ЗависимыеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка. +// ** Значение - Булево - Истина. +// * ПоЗначениямПолей - см. ВедущийСписокПоЗначениямПолей +// * ПоКлючамДоступа - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// * ПоЗначениямСГруппами - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// +Функция СвойстваСпискаКакВедущего(ПолноеИмя, ИдентификаторТранзакции = Неопределено, ПовторныйВызов = Ложь) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, Неопределено, ПовторныйВызов); + ХранимыеСвойстваСпискаКакВедущего = ДействующиеПараметры.ВедущиеСписки.Получить(ПолноеИмя); + + Если ХранимыеСвойстваСпискаКакВедущего = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Кэш = КэшПараметровОграничения(); + + СвойстваСпискаКакВедущего = Кэш.ВедущиеСпискиПроверенные.Получить(ПолноеИмя); + Если СвойстваСпискаКакВедущего <> Неопределено Тогда + Возврат СвойстваСпискаКакВедущего; + КонецЕсли; + + СвойстваСпискаКакВедущего = Новый Структура(ХранимыеСвойстваСпискаКакВедущего); + Отказ = Ложь; + ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка(ПолноеИмя, + СвойстваСпискаКакВедущего, Отказ); + + Если Не Отказ Тогда + Кэш.ВедущиеСпискиПроверенные.Вставить(ПолноеИмя, + Новый ФиксированнаяСтруктура(СвойстваСпискаКакВедущего)); + + Возврат СвойстваСпискаКакВедущего; + КонецЕсли; + + Если ПовторныйВызов Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось подготовить свойства списка ""%1"" как ведущего, + |из-за некорректного состояния параметров ограничения доступа.'"), + ПолноеИмя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Возврат СвойстваСпискаКакВедущего(ПолноеИмя, ИдентификаторТранзакции, Истина); + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ВедущиеСпискиПроверенные - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. УправлениеДоступомСлужебный.СвойстваСпискаКакВедущего +// * ОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. УправлениеДоступомСлужебный.РассчитанныеПараметрыОграничения +// * ИдентификаторыТранзакции - Соответствие из КлючИЗначение: +// ** Ключ - УникальныйИдентификатор - произвольный УИД. +// ** Значение - Булево - значение Истина. +// * ВидыОграниченийПравДляПользователей - Неопределено +// - Строка +// * ВидыОграниченийПравДляВнешнихПользователей - Неопределено +// - Строка +// +Функция НовыйКэшПараметровОграничения() Экспорт + + Хранилище = Новый Структура; + Хранилище.Вставить("ВедущиеСпискиПроверенные", Новый Соответствие); + Хранилище.Вставить("ОграниченияСписков", Новый Соответствие); + Хранилище.Вставить("ИдентификаторыТранзакции", Новый Соответствие); + Хранилище.Вставить("ВидыОграниченийПравДляПользователей", Неопределено); + Хранилище.Вставить("ВидыОграниченийПравДляВнешнихПользователей", Неопределено); + + Возврат Хранилище; + +КонецФункции + +// Для функции СвойстваСпискаКакВедущего и процедур ЗаполнитьПараметрыОграничения, +// ОбновитьИдентификаторыТранзакции, УстановитьВерсиюПараметров. +// +Функция КэшПараметровОграничения() + + КлючДанныхПовторногоИспользования = Строка(ПараметрыСеанса.КлючДанныхПовторногоИспользования); + + Возврат УправлениеДоступомСлужебныйПовтИсп.КэшПараметровОграничения(КлючДанныхПовторногоИспользования); + +КонецФункции + +Процедура СброситьКэшПараметровОграничения() + + Кэш = КэшПараметровОграничения(); + НовыйКэш = НовыйКэшПараметровОграничения(); + + Для Каждого КлючИЗначение Из НовыйКэш Цикл + Кэш.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для функции СвойстваСпискаКакВедущего. +Процедура ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка(ПолноеИмя, Свойства, Отказ) + + Свойства.Удалить("ЗависимыеСписки"); + Если Свойства.ПоЗначениямПолей = Неопределено Тогда + Возврат; + КонецЕсли; + + ПоЗначениямПолей = Новый Структура(Свойства.ПоЗначениямПолей); // См. ВедущийСписокПоЗначениямПолей + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); + + Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда + Если ЗначениеЗаполнено(ПоЗначениямПолей.ПоляШапки.ВсеПоля) Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | (ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина) КАК ЗначениеИстина + | ЛЕВОЕ СОЕДИНЕНИЕ ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.Ссылка = &СсылкаНаОбъект)"; + ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, + ПолноеИмя, ПоЗначениямПолей.ПоляШапки.ВсеПоля, ОбъектМетаданных, Отказ); + Иначе + ТекстЗапроса = ""; + КонецЕсли; + + Для Каждого ТабличнаяЧасть Из ПоЗначениямПолей.ТабличныеЧасти Цикл + Коллекции = Новый Структура("СтандартныеТабличныеЧасти, ТабличныеЧасти"); + ТабличнаяЧастьИмя = ТабличнаяЧасть.Имя; + ЗаполнитьЗначенияСвойств(Коллекции, ОбъектМетаданных); + МетаданныеТаблицы = Неопределено; + Если ТипЗнч(Коллекции.ТабличныеЧасти) = Тип("КоллекцияОбъектовМетаданных") Тогда + МетаданныеТаблицы = ОбъектМетаданных.ТабличныеЧасти.Найти(ТабличнаяЧастьИмя); + КонецЕсли; + Если МетаданныеТаблицы = Неопределено + И ТипЗнч(Коллекции.СтандартныеТабличныеЧасти) = Тип("ОписанияСтандартныхТабличныхЧастей") Тогда + Для Каждого СтандартнаяТабличнаяЧасть Из Коллекции.СтандартныеТабличныеЧасти Цикл + СтандартнаяТабличнаяЧасть = СтандартнаяТабличнаяЧасть; // ОписаниеСтандартнойТабличнойЧасти + Если СтандартнаяТабличнаяЧасть.Имя = ТабличнаяЧастьИмя Тогда + МетаданныеТаблицы = СтандартнаяТабличнаяЧасть; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если МетаданныеТаблицы = Неопределено Тогда + Отказ = Истина; + Прервать; + КонецЕсли; + + ТекстЗапросаТабличнойЧасти = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100 + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Ссылка = &СсылкаНаОбъект"; + ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапросаТабличнойЧасти, + ПолноеИмя + "." + ТабличнаяЧастьИмя, ТабличнаяЧасть.ВсеПоля, МетаданныеТаблицы, Отказ, Истина); + + ТекстЗапроса = ТекстЗапроса + ?(ТекстЗапроса = "", "", + ОбщегоНазначения.РазделительПакетаЗапросов()) + ТекстЗапросаТабличнойЧасти; + КонецЦикла; + + ИначеЕсли ЗначениеЗаполнено(ПоЗначениямПолей.ПоляШапки.ВсеПоля) Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100 + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям"; + ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, + ПолноеИмя, ПоЗначениямПолей.ПоляШапки.ВсеПоля, ОбъектМетаданных, Отказ); + Иначе + ТекстЗапроса = ""; + КонецЕсли; + + ПоЗначениямПолей.Вставить("ТекстЗапроса", ТекстЗапроса); + Свойства.ПоЗначениямПолей = Новый ФиксированнаяСтруктура(ПоЗначениямПолей); + +КонецПроцедуры + +// Для процедуры ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка. +Процедура ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, ПолноеИмя, ОписаниеПолей, + МетаданныеТаблицы, Отказ, ЭтоТабличнаяЧасть = Ложь) + + КоллекцииПолей = Новый Структура("Реквизиты, Измерения, Ресурсы, СтандартныеРеквизиты"); + ЗаполнитьЗначенияСвойств(КоллекцииПолей, МетаданныеТаблицы); + + ПоляВыбора = ""; + Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл + ИмяПоля = ?(ТипЗнч(ОписаниеПолей) = Тип("ФиксированныйМассив"), ОписаниеПоля, ОписаниеПоля.Ключ); + + Если Не ПолеСуществует(КоллекцииПолей.Реквизиты, ИмяПоля) + И Не ПолеСуществует(КоллекцииПолей.Измерения, ИмяПоля) + И Не ПолеСуществует(КоллекцииПолей.Ресурсы, ИмяПоля) + И Не ПолеСуществует(КоллекцииПолей.СтандартныеРеквизиты, ИмяПоля) + И Не (ЭтоТабличнаяЧасть + И (ВРег(ИмяПоля) = ВРег("Ссылка") + Или ВРег(ИмяПоля) = ВРег("Ref"))) Тогда // @Non-NLS + + Отказ = Истина; + Прервать; + КонецЕсли; + + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", "," + Символы.ПС) + + "ТекущаяТаблица." + ИмяПоля + " КАК " + ИмяПоля; // @query-part-5 + КонецЦикла; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекущаяТаблица.Поле1 КАК Поле1", ТекстСОтступом(СокрЛ(ПоляВыбора), " ")); // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущаяТаблицаЭлементовДанных", ПолноеИмя); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПЕРВЫЕ 100", "ПЕРВЫЕ " + Формат( + МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных() * 10, "ЧГ=")); // @query-part-1, @query-part-2 + +КонецПроцедуры + +// Для процедуры ЗаполнитьПоляВыбораТекущейТаблицы. +Функция ПолеСуществует(Коллекция, ИмяПоля) + + Если ТипЗнч(Коллекция) = Тип("КоллекцияОбъектовМетаданных") Тогда + Возврат Коллекция.Найти(ИмяПоля) <> Неопределено; + + ИначеЕсли ТипЗнч(Коллекция) = Тип("ОписанияСтандартныхРеквизитов") Тогда + Для Каждого СтандартныйРеквизит Из Коллекция Цикл + Если СтандартныйРеквизит.Имя = ИмяПоля Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Основная функция, возвращающая параметры, необходимые для проверки прав в момент записи элементов данных. +// +// Возвращаемое значение: +// см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции = Неопределено, ДляВнешнихПользователей = Неопределено) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, Неопределено, Ложь); + Параметры = КэшПараметровОграничения().ОграниченияСписков.Получить(ПолноеИмя); + + Если Параметры = Неопределено Тогда + ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры); + КонецЕсли; + + Если ДляВнешнихПользователей = Null Тогда + Возврат Параметры; + КонецЕсли; + + Если ДляВнешнихПользователей = Неопределено Тогда + ДляВнешнихПользователей = Пользователи.ЭтоСеансВнешнегоПользователя(); + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + Возврат Параметры.ДляВнешнихПользователей; + КонецЕсли; + + Возврат Параметры.ДляПользователей; + +КонецФункции + +// Для функций СвойстваСпискаКакВедущего, ПараметрыОграничения. +Процедура ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры, + ОбщийКонтекст = Неопределено, ПовторныйВызов = Ложь) + + Если ОбщийКонтекст = Неопределено Тогда + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(ПолноеИмя); + ОбщийКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); + КонецЕсли; + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, Ложь); + + ВерсияОграничений = ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя); + ЕстьОшибка = Ложь; + Попытка + РассчитанныеПараметры = РассчитанныеПараметрыОграничения(ПолноеИмя, ОбщийКонтекст, ДействующиеПараметры); + Исключение + Если ПовторныйВызов Тогда + ВызватьИсключение; + КонецЕсли; + Попытка + Значение = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + Исключение + Значение = Неопределено; + КонецПопытки; + Если Значение = Неопределено Тогда + ВызватьИсключение; + КонецЕсли; + ЕстьОшибка = Истина; + КонецПопытки; + + Если ЕстьОшибка Или ВерсияОграничений <> РассчитанныеПараметры.Версия Тогда + Если ПовторныйВызов Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить параметры ограничения доступа списка ""%1"" + |из-за нестабильной строки свойств версии параметров для вычисления хеш-суммы.'"), + ПолноеИмя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, Истина); + ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры, ОбщийКонтекст, Истина); + Возврат; + КонецЕсли; + + Параметры = ОбщегоНазначения.ФиксированныеДанные(РассчитанныеПараметры); + + КэшПараметровОграничения().ОграниченияСписков.Вставить(ПолноеИмя, Параметры); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыОграничения и функций +// ХранимыеПараметрыОграниченияДоступа, ОшибкиОграниченийДоступа. +// +// Возвращаемое значение: +// Структура: +// * СвойстваВидовДоступа - см. СвойстваВидовДоступа +// * ТипыПользователя - Массив из Тип +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ОтдельныеТаблицыНастроекПрав - ФиксированноеСоответствие +// * ВнешниеПользователиВключены - Булево +// * ИспользуемыеТипыЗначений - см. ИспользуемыеТипыЗначений +// * СпискиСОграничением - см. УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением +// +Функция ОбщийКонтекстРасчетаПараметровОграничения(ПолноеИмя = Неопределено, + ВсеВидыДоступаИспользуются = Неопределено, ЗаполнитьСпискиСОграничением = Истина) + + ТипыПользователя = Новый Массив; + ТипыПользователя.Добавить(Тип("СправочникСсылка.Пользователи")); + ТипыПользователя.Добавить(Тип("СправочникСсылка.ГруппыПользователей")); + ТипыПользователя.Добавить(Тип("СправочникСсылка.ВнешниеПользователи")); + ТипыПользователя.Добавить(Тип("СправочникСсылка.ГруппыВнешнихПользователей")); + + ОграничениеДоступаВключено = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + Если УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() <> ОграничениеДоступаВключено Тогда + ОбновитьПовторноИспользуемыеЗначения(); + КонецЕсли; + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ИспользуемыеТипыЗначений = ИспользуемыеТипыЗначений(СвойстваВидовДоступа, ПолноеИмя, ВсеВидыДоступаИспользуются); + Если ТипЗнч(ВсеВидыДоступаИспользуются) = Тип("Булево") Тогда + ОграничениеДоступаВключено = ВсеВидыДоступаИспользуются; + ВнешниеПользователиВключены = ВсеВидыДоступаИспользуются; + Иначе + ВнешниеПользователиВключены = Константы.ИспользоватьВнешнихПользователей.Получить(); + КонецЕсли; + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + + ОбщийКонтекст = Новый Структура; + ОбщийКонтекст.Вставить("СвойстваВидовДоступа", СвойстваВидовДоступа); + ОбщийКонтекст.Вставить("ТипыПользователя", ТипыПользователя); + ОбщийКонтекст.Вставить("ТипыВладельцевНастроекПрав", ВозможныеПрава.ПоТипамСсылок); + ОбщийКонтекст.Вставить("ОтдельныеТаблицыНастроекПрав", ВозможныеПрава.ОтдельныеТаблицы); + ОбщийКонтекст.Вставить("ВнешниеПользователиВключены", ВнешниеПользователиВключены); + ОбщийКонтекст.Вставить("ОграничениеДоступаВключено", ОграничениеДоступаВключено); + ОбщийКонтекст.Вставить("ИспользуемыеТипыЗначений", ИспользуемыеТипыЗначений); + + Если ЗаполнитьСпискиСОграничением Тогда + ОбщийКонтекст.Вставить("СпискиСОграничением", УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением()); + КонецЕсли; + + Возврат ОбщийКонтекст; + +КонецФункции + +// Для функций ОбщийКонтекстРасчетаПараметровОграничения и ИспользованиеВидовДоступаИзменено. +// +// Параметры: +// СвойстваВидовДоступа - см. СвойстваВидовДоступа +// ПолноеИмя - Строка +// ВсеВидыДоступаИспользуются - Неопределено +// - Булево +// ТолькоХешСумма - Булево +// +// Возвращаемое значение: +// Структура: +// * ДляИБ - Соответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - Булево - Истина +// * ПоТаблицам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя объекта метаданных +// ** Значение - Соответствие из КлючИЗначение: +// *** Ключ - Тип +// *** Значение - Булево - Истина +// * ХешСумма - Строка - контрольная сумма настроек использования ДляИБ и ПоТаблицам. +// * ПолноеИмяТаблицы - Строка - полное имя таблицы, когда свойство ПоТаблицам +// заполнено только для одной таблицы. +// - Неопределено - когда свойство ПоТаблицам не заполнялось (ВсеВидыДоступаИспользуются = Истина). +// +Функция ИспользуемыеТипыЗначений(СвойстваВидовДоступа, ПолноеИмя = Неопределено, ВсеВидыДоступаИспользуются = Неопределено, ТолькоХешСумма = Ложь) + + ИспользуемыеТипыЗначений = Новый Структура; + ИспользуемыеТипыЗначений.Вставить("ДляИБ", Новый Соответствие); + ИспользуемыеТипыЗначений.Вставить("ПоТаблицам", Новый Соответствие); + ИспользуемыеТипыЗначений.Вставить("ХешСумма", ""); + ИспользуемыеТипыЗначений.Вставить("ПолноеИмяТаблицы", ""); + + Если ВсеВидыДоступаИспользуются = Ложь Тогда + Возврат ИспользуемыеТипыЗначений; + КонецЕсли; + + Если ВсеВидыДоступаИспользуются = Истина Тогда + ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Неопределено; + Иначе + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ИспользуемыеВидыДоступа.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа + |ГДЕ + | ИспользуемыеВидыДоступа.Используется = ИСТИНА + | И &ОграничиватьДоступНаУровнеЗаписей + | + |УПОРЯДОЧИТЬ ПО + | ТипЗначенийДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ИспользуемыеВидыДоступаПоТаблицам.Таблица КАК Таблица, + | ИспользуемыеВидыДоступаПоТаблицам.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступаПоТаблицам КАК ИспользуемыеВидыДоступаПоТаблицам + |ГДЕ + | ИспользуемыеВидыДоступаПоТаблицам.Таблица = &Таблица + | + |УПОРЯДОЧИТЬ ПО + | Таблица, + | ТипЗначенийДоступа"; + + Если ПолноеИмя <> Неопределено Тогда + Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПолноеИмя, Ложь); + Если Идентификатор <> Null Тогда + Запрос.УстановитьПараметр("Таблица", Идентификатор); + КонецЕсли; + КонецЕсли; + Если ПолноеИмя = Неопределено Или Идентификатор = Null Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ИспользуемыеВидыДоступаПоТаблицам.Таблица = &Таблица", "ИСТИНА"); + Иначе + ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = ПолноеИмя; + КонецЕсли; + СтрокаОграничениеДоступаВключено = + ?(Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(), "ИСТИНА", "ЛОЖЬ"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОграничиватьДоступНаУровнеЗаписей", + СтрокаОграничениеДоступаВключено); + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Используемые = РезультатыЗапроса[0].Выгрузить(); + ИспользуемыеПоТаблицам = РезультатыЗапроса[1].Выгрузить(); + Если ПолноеИмя = Неопределено Тогда + Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); + Хеширование.Добавить(СтрокаОграничениеДоступаВключено); + Хеширование.Добавить(СтрокаДанныхДляХеширования(Используемые)); + Хеширование.Добавить(СтрокаДанныхДляХеширования(ИспользуемыеПоТаблицам)); + ИспользуемыеТипыЗначений.ХешСумма = Base64Строка(Хеширование.ХешСумма); + Если ТолькоХешСумма Тогда + Возврат ИспользуемыеТипыЗначений; + КонецЕсли; + КонецЕсли; + Таблицы = ИспользуемыеПоТаблицам.Скопировать(, "Таблица"); + Таблицы.Свернуть("Таблица"); + Идентификаторы = Таблицы.ВыгрузитьКолонку("Таблица"); + ОбъектыМетаданных = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, Ложь); + ТекущаяТаблица = Неопределено; + Для Каждого Строка Из ИспользуемыеПоТаблицам Цикл + Если ТекущаяТаблица <> Строка.Таблица Тогда + ОбъектМетаданных = ОбъектыМетаданных.Получить(Строка.Таблица); + Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда + Продолжить; + КонецЕсли; + ТекущееПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ТекущаяТаблица = Строка.Таблица; + ТекущиеИспользуемыеТипы = Новый Соответствие; + ИспользуемыеТипыЗначений.ПоТаблицам.Вставить(ТекущееПолноеИмя, ТекущиеИспользуемыеТипы); + КонецЕсли; + ТекущиеИспользуемыеТипы.Вставить(ТипЗнч(Строка.ТипЗначенийДоступа), Истина); + КонецЦикла; + КонецЕсли; + + СвойстваВидовДоступаМассив = СвойстваВидовДоступа.Массив; // Массив Из см. СвойстваВидаДоступа + Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступаМассив Цикл + Если ВсеВидыДоступаИспользуются <> Истина + И Используемые.Найти(СвойстваВидаДоступа.Ссылка) = Неопределено Тогда + Продолжить; + КонецЕсли; + ИспользуемыеТипыЗначений.ДляИБ.Вставить(СвойстваВидаДоступа.ТипЗначений, Истина); + Для Каждого ОписаниеДополнительногоТипа Из СвойстваВидаДоступа.ДополнительныеТипы Цикл + ИспользуемыеТипыЗначений.ДляИБ.Вставить(ОписаниеДополнительногоТипа.ТипЗначений, Истина); + КонецЦикла; + КонецЦикла; + + Возврат ИспользуемыеТипыЗначений; + +КонецФункции + +// Для процедуры ДобавитьПараметрыОграниченияСписка. +// +// Возвращаемое значение: +// Структура: +// * Версия - Строка +// * ВедущиеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СвойстваСпискаКакВедущего +// * ДляПользователей - см. ПараметрыОграниченияПоСтруктуреОграничения +// * ДляВнешнихПользователей - см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция РассчитанныеПараметрыОграничения(ПолноеИмя, ОбщийКонтекст, ДействующиеПараметры) Экспорт + + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); + + // Для пользователей. + СтруктураОграниченияДляПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.Текст, ОписаниеОграничения.ТекстВМодулеМенеджера, Ложь); + + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДополнительныйКонтекст, ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Ложь); + + РезультатДляПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляПользователей, Ложь, ОбщийКонтекст, ДополнительныйКонтекст); + + // Для внешних пользователей. + СтруктураОграниченияДляВнешнихПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.ТекстДляВнешнихПользователей, ОписаниеОграничения.ТекстВМодулеМенеджера, Истина); + + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДополнительныйКонтекст, ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Истина); + + РезультатДляВнешнихПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляВнешнихПользователей, Истина, ОбщийКонтекст, ДополнительныйКонтекст); + + // Заполнение параметров на основе параметров обоих видов пользователей. + Версия = ОбщаяВерсия(ОбщийКонтекст, ПолноеИмя, РезультатДляПользователей.Версия, РезультатДляВнешнихПользователей.Версия); + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляПользователей); + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляВнешнихПользователей); + СЗаписьюДвухКлючей = Не РезультатДляПользователей.БезЗаписиКлючейДоступа И Не РезультатДляВнешнихПользователей.БезЗаписиКлючейДоступа; + БезЗаписиКлючей = РезультатДляПользователей.БезЗаписиКлючейДоступа И РезультатДляВнешнихПользователей.БезЗаписиКлючейДоступа; + РезультатДляПользователей.Вставить( "СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", СЗаписьюДвухКлючей); + РезультатДляВнешнихПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", СЗаписьюДвухКлючей); + РезультатДляПользователей.Вставить( "БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", БезЗаписиКлючей); + РезультатДляВнешнихПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", БезЗаписиКлючей); + + // Формирование текстов запросов. + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляПользователей); + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляВнешнихПользователей); + + ВедущиеСписки = Новый Структура; + ВедущиеСписки.Вставить("ДляПользователей", РезультатДляПользователей.ВедущиеСписки); + ВедущиеСписки.Вставить("ДляВнешнихПользователей", РезультатДляВнешнихПользователей.ВедущиеСписки); + + Параметры = Новый Структура; + Параметры.Вставить("Версия", Версия); + Параметры.Вставить("ВедущиеСписки", ВедущиеСписки); + Параметры.Вставить("ДляПользователей", РезультатДляПользователей); + Параметры.Вставить("ДляВнешнихПользователей", РезультатДляВнешнихПользователей); + + Возврат Параметры; + +КонецФункции + +// Для функции ОшибкиОграниченийДоступа. +Функция ОшибкаОграниченияДоступа(ОбщийКонтекст, ПолноеИмя) + + ТекстОшибкиДляПользователей = ""; + ТекстОшибкиДляВнешнихПользователей = ""; + + Попытка + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, Истина); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Возврат ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Если ТипЗнч(ОписаниеОграничения) = Тип("Строка") Тогда + Возврат ОписаниеОграничения; + КонецЕсли; + + // Для пользователей. + СтруктураОграниченияДляПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.Текст, ОписаниеОграничения.ТекстВМодулеМенеджера, Ложь, Истина); + + Если СтруктураОграниченияДляПользователей <> Неопределено + И СтруктураОграниченияДляПользователей.ОписаниеОшибок.ЕстьОшибки Тогда + + ТекстОшибкиДляПользователей = ТекстОшибокДляВызоваИсключения(ПолноеИмя, + СтруктураОграниченияДляПользователей.ОписаниеОшибок, Ложь, ОписаниеОграничения.ТекстВМодулеМенеджера); + Иначе + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Ложь); + + ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); + ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); + Попытка + РезультатДляПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляПользователей, Ложь, ОбщийКонтекст, ДополнительныйКонтекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать параметры ограничения доступа для пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + + Если Не ЗначениеЗаполнено(ТекстОшибкиДляПользователей) Тогда + РезультатДляПользователей.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляПользователей); + РезультатДляПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); + РезультатДляПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); + Попытка + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляПользователей); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа + |для пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + КонецЕсли; + КонецЕсли; + + // Для внешних пользователей. + СтруктураОграниченияДляВнешнихПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.ТекстДляВнешнихПользователей, ОписаниеОграничения.ТекстВМодулеМенеджера, Истина, Истина); + + Если СтруктураОграниченияДляВнешнихПользователей <> Неопределено + И СтруктураОграниченияДляВнешнихПользователей.ОписаниеОшибок.ЕстьОшибки Тогда + + ТекстОшибкиДляВнешнихПользователей = ТекстОшибокДляВызоваИсключения(ПолноеИмя, + СтруктураОграниченияДляВнешнихПользователей.ОписаниеОшибок, Истина, ОписаниеОграничения.ТекстВМодулеМенеджера); + Иначе + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Истина); + + ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); + ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); + Попытка + РезультатДляВнешнихПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляВнешнихПользователей, Истина, ОбщийКонтекст, ДополнительныйКонтекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляВнешнихПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляВнешнихПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать параметры ограничения доступа для внешних пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + + Если Не ЗначениеЗаполнено(ТекстОшибкиДляВнешнихПользователей) Тогда + РезультатДляВнешнихПользователей.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляВнешнихПользователей); + РезультатДляВнешнихПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); + РезультатДляВнешнихПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); + Попытка + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляВнешнихПользователей); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляВнешнихПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляВнешнихПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа + |для внешних пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + КонецЕсли; + КонецЕсли; + + Возврат СокрЛП(ТекстОшибкиДляПользователей + + Символы.ПС + Символы.ПС + ТекстОшибкиДляВнешнихПользователей); + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступа. +Функция РезультатПроверкиОграниченияДоступаОбъекта(ПолноеИмя, ДополнительныеПараметры) + + Параметры = Новый Структура; + Параметры.Вставить("Текст", Неопределено); + Параметры.Вставить("ТекстДляВнешнихПользователей", Неопределено); + Параметры.Вставить("УчитыватьЗависимости", Ложь); + Параметры.Вставить("ВсеВидыДоступаИспользуются", Истина); + + Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда + ЗаполнитьЗначенияСвойств(Параметры, ДополнительныеПараметры); + КонецЕсли; + + ДляПользователей = СтруктураРезультатаПроверкиОграниченияДляВидаПользователей(); + ДляВнешнихПользователей = СтруктураРезультатаПроверкиОграниченияДляВидаПользователей(); + + Результат = Новый Структура; + Результат.Вставить("ОшибкаОписанияОграничения", ""); + Результат.Вставить("ТекстВМодулеМенеджера", Неопределено); + Результат.Вставить("ДляПользователей", ДляПользователей); + Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Результат.Вставить("НастройкиВнедрения", Новый Структура); + + ОбщийКонтекст = Неопределено; + Попытка + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Параметры.ВсеВидыДоступаИспользуются, Ложь); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + + Если ОбщийКонтекст = Неопределено Тогда + Возврат Результат; + КонецЕсли; + + УчетЗависимостейДоступен = Истина; + СпискиСОграничением = Неопределено; + Попытка + СпискиСОграничением = УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + УчетЗависимостейДоступен = Ложь; + КонецПопытки; + + Если СпискиСОграничением <> Неопределено Тогда + СпискиСОграничением = Новый Соответствие(СпискиСОграничением); + Иначе + СпискиСОграничением = Новый Соответствие; + УчетЗависимостейДоступен = Ложь; + КонецЕсли; + ОбщийКонтекст.Вставить("СпискиСОграничением", СпискиСОграничением); + + ОписаниеОграничения = Неопределено; + Попытка + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, Истина); + Исключение + Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + УчетЗависимостейДоступен = Ложь; + КонецПопытки; + Если ТипЗнч(ОписаниеОграничения) = Тип("Строка") Тогда + Результат.ОшибкаОписанияОграничения = ОписаниеОграничения; + ОписаниеОграничения = Неопределено; + КонецЕсли; + + Если ОписаниеОграничения <> Неопределено Тогда + Результат.ТекстВМодулеМенеджера = ОписаниеОграничения.ТекстВМодулеМенеджера; + ДляПользователей.ОграничениеВМодуле = ОписаниеОграничения.Текст; + ДляПользователей.ПоВладельцуБезЗаписиКлючейДоступа = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступа; + ДляВнешнихПользователей.ОграничениеВМодуле = ОписаниеОграничения.ТекстДляВнешнихПользователей; + ДляВнешнихПользователей.ПоВладельцуБезЗаписиКлючейДоступа = + ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей; + + Если Параметры.Текст = Неопределено Тогда + ДляПользователей.ПроверяемоеОграничение = ДляПользователей.ОграничениеВМодуле; + Иначе + ДляПользователей.ПроверяемоеОграничение = Параметры.Текст; + ОписаниеОграничения.Текст = Параметры.Текст; + КонецЕсли; + + Если Параметры.ТекстДляВнешнихПользователей = Неопределено Тогда + ДляВнешнихПользователей.ПроверяемоеОграничение = ДляВнешнихПользователей.ОграничениеВМодуле; + Иначе + ДляВнешнихПользователей.ПроверяемоеОграничение = Параметры.ТекстДляВнешнихПользователей; + ОписаниеОграничения.ТекстДляВнешнихПользователей = Параметры.ТекстДляВнешнихПользователей; + КонецЕсли; + КонецЕсли; + + Если СпискиСОграничением.Получить(ПолноеИмя) = Неопределено Тогда + СпискиСОграничением.Вставить(ПолноеИмя, Истина); + Результат.ТекстВМодулеМенеджера = Неопределено; + КонецЕсли; + + Контекст = Новый Структура; + Контекст.Вставить("ПолноеИмя", ПолноеИмя); + Контекст.Вставить("ОбщийРезультат", Результат); + Контекст.Вставить("ОбщийКонтекст", ОбщийКонтекст); + Контекст.Вставить("ОписаниеОграничения", ОписаниеОграничения); + Контекст.Вставить("УчитыватьЗависимости", Параметры.УчитыватьЗависимости); + Контекст.Вставить("УчетЗависимостейДоступен", УчетЗависимостейДоступен); + Контекст.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + Контекст.Вставить("ВедущиеСписки", Новый Соответствие); + Контекст.Вставить("ДополнительныйКонтекст", Новый Структура("ДляПользователей, ДляВнешнихПользователей")); + + ПроверитьОграничениеДляВидаПользователей(Контекст, ДляПользователей, Ложь, + Контекст.ДополнительныйКонтекст.ДляПользователей); + + ПроверитьОграничениеДляВидаПользователей(Контекст, ДляВнешнихПользователей, Истина, + Контекст.ДополнительныйКонтекст.ДляВнешнихПользователей); + + Если Не Контекст.УчетЗависимостейДоступен Тогда + Возврат Результат; + КонецЕсли; + + Если Параметры.УчитыватьЗависимости Тогда + ОбщийКонтекст.Вставить("СпециальноеПолноеИмя", ПолноеИмя); + ОбщийКонтекст.Вставить("СпециальноеОписаниеОграничения", ОписаниеОграничения); + ОбщийКонтекст.Вставить("СпискиСОграничением", Новый ФиксированноеСоответствие(СпискиСОграничением)); + НовыеХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст); + ДействующиеПараметры = Новый Структура(НовыеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); // см. НоваяСтруктураХранимыхПараметровЗаписи + Если ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя) = Неопределено Тогда + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, Истина); + Иначе + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, + ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя)); + КонецЕсли; + УстановитьОграничениеПоВладельцуИспользуется(ДляПользователей, + ПолноеИмя, ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей); + УстановитьОграничениеПоВладельцуИспользуется(ДляВнешнихПользователей, + ПолноеИмя, ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей); + Иначе + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, Истина); + ДействующиеПараметры = Новый Структура; + ДействующиеПараметры.Вставить("ДополнительныйКонтекст", Контекст.ДополнительныйКонтекст); + КонецЕсли; + ДействующиеПараметры.Вставить("ВерсииОграниченийСписков", Контекст.ВерсииОграниченийСписков); + ДействующиеПараметры.Вставить("ВедущиеСписки", Контекст.ВедущиеСписки); + + Настройки = НастройкиВнедрения(ДействующиеПараметры); + + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + УстановитьНастройкиВнедрения(Результат.НастройкиВнедрения, Настройки, ТипыТаблицПоИменам); + + Результат.ДляПользователей.ОграничениеВРолях = Настройки.ОграниченияВРолях.ДляПользователей.Получить( + ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам)); + + Результат.ДляВнешнихПользователей.ОграничениеВРолях = Настройки.ОграниченияВРолях.ДляВнешнихПользователей.Получить( + ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам)); + + Возврат Результат; + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта +Процедура УстановитьОграничениеПоВладельцуИспользуется(Результат, ПолноеИмя, ДополнительныйКонтекст) + + Свойства = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(ПолноеИмя); + Если Свойства = Неопределено Тогда + Возврат; + КонецЕсли; + + Результат.ОграничениеПоВладельцуИспользуется = + Свойства.ПолеВладельца <> Неопределено И Не Свойства.ПолеВладельца.Отключено; + +КонецПроцедуры + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта. +Процедура УстановитьНастройкиВнедрения(НастройкиВнедрения, Данные, ТипыТаблицПоИменам) + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, + Данные.ЗначенияДоступа, "ЗначениеДоступа"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, + Данные.ВладельцыЗначенийКлючейДоступа.Ссылки, "ВладелецЗначенийКлючейДоступа"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.Объекты, "ВладелецЗначенийКлючейДоступаОбъект"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.Документы, "ВладелецЗначенийКлючейДоступаДокумент"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписей, "ВладелецЗначенийКлючейДоступаНаборЗаписей"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета, + "ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета, + "ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета"); + + НастройкиВнедрения.Вставить("ПолеРегистраКлючейДоступаКРегистрам", ""); + НастройкиВнедрения.Вставить("ТипыИзмеренийОтдельногоРегистраКлючей", Неопределено); + Для Каждого КлючИЗначение Из Данные.ТипыИзмеренийРегистровКлючей Цикл + Если СтрНайти(КлючИЗначение.Ключ, ".") > 0 Тогда + Продолжить; + КонецЕсли; + ИмяРегистраКлючей = КлючИЗначение.Ключ; + + Если ИмяРегистраКлючей = "КлючиДоступаКРегистрам" Тогда + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, + КлючИЗначение.Значение.ИменаТипов, "ПолеРегистраКлючейДоступаКРегистрам"); + Иначе + ИзмеренияРегистра = Метаданные.РегистрыСведений[ИмяРегистраКлючей].Измерения; + СписокТипов = ""; + НомерПоля = 1; + Для Каждого ОписаниеПолейРегистра Из КлючИЗначение.Значение.ПоляРегистров Цикл + Прервать; + КонецЦикла; + Для Каждого ОписаниеПоля Из ОписаниеПолейРегистра.Значение Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ПолеРегистра = ИзмеренияРегистра.Найти(ИмяПоля); + ОписаниеТипов = ?(ПолеРегистра = Неопределено, Новый ОписаниеТипов, ПолеРегистра.Тип); + СписокТипов = СписокТипов + ?(СписокТипов = "", "", Символы.ПС) + + НСтр("ru = '- для измерения'") + " " + ИмяПоля + ":" + Символы.ПС + + " " + ТекстСОтступом(СписокТиповИзМассива(ОписаниеПоля.Тип.Типы(), + Истина, ТипыТаблицПоИменам, ОписаниеТипов), " "); + НомерПоля = НомерПоля + 1; + КонецЦикла; + НастройкиВнедрения.Вставить("ТипыИзмеренийОтдельногоРегистраКлючей", + Новый Структура("ИмяРегистраСведений, ТипыИзмерений", ИмяРегистраКлючей, СписокТипов)); + КонецЕсли; + КонецЦикла; + + НастройкиВнедрения.Вставить("ПредопределенныйИдентификатор", Неопределено); + Для Каждого КлючИЗначение Из Данные.ПредопределенныеИдентификаторы Цикл + ЧастиИмени = СтрРазделить(КлючИЗначение.Ключ, ".", Ложь); + УжеДобавлен = Метаданные.Справочники[ЧастиИмени[0]].ПолучитьИменаПредопределенных().Найти(ЧастиИмени[1]) <> Неопределено; + НастройкиВнедрения.Вставить("ПредопределенныйИдентификатор", + Новый Структура("ИмяСправочника, ИмяПредопределенного", ЧастиИмени[0], + "- " + ЧастиИмени[1] + ?(УжеДобавлен, " (" + НСтр("ru = 'уже добавлен'") + ")", ""))); + Прервать; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры УстановитьНастройкиВнедрения. +Процедура ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, ТипыСсылок, ИменаТипов, ИмяОпределяемогоТипа) + + НастройкиВнедрения.Вставить(ИмяОпределяемогоТипа, ""); + Если ИменаТипов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + НастройкиВнедрения[ИмяОпределяемогоТипа] = СписокТиповИзМассива(ИменаТипов, + ТипыСсылок, ТипыТаблицПоИменам, Метаданные.ОпределяемыеТипы[ИмяОпределяемогоТипа].Тип); + +КонецПроцедуры + +// Для процедур УстановитьНастройкиВнедрения, ДобавитьТипыТребуемыеВОпределяемомТипе. +Функция СписокТиповИзМассива(ИменаТипов, ТипыСсылок, ТипыТаблицПоИменам, ОписаниеТипов) + + СписокТипов = ""; + Для Каждого ИмяТипа Из ИменаТипов Цикл + Если ТипЗнч(ИмяТипа) = Тип("Тип") Тогда + Тип = ИмяТипа; + Иначе + Тип = Тип(ИмяТипа); + КонецЕсли; + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + Если ОбъектМетаданных = Неопределено Тогда + ИмяТипа = Строка(Тип); + Иначе + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ИмяТипа = ?(ТипыСсылок, ИмяТипаСсылки(ПолноеИмя, ТипыТаблицПоИменам), + ИмяТипаОбъектаИлиНабораЗаписей(ПолноеИмя, ТипыТаблицПоИменам)); + КонецЕсли; + + СписокТипов = СписокТипов + ?(СписокТипов = "", "", Символы.ПС) + "- " + ИмяТипа; + + Если ОписаниеТипов.СодержитТип(Тип) Тогда + СписокТипов = СписокТипов + " (" + НСтр("ru = 'уже добавлен'") + ")"; + КонецЕсли; + КонецЦикла; + + Возврат СписокТипов; + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта. +Функция СтруктураРезультатаПроверкиОграниченияДляВидаПользователей() + + Свойства = Новый Структура; + Свойства.Вставить("ПроверяемоеОграничение"); + Свойства.Вставить("ОписаниеОшибок"); + Свойства.Вставить("ОшибкаФормированияПараметровОграничения"); + Свойства.Вставить("ОшибкаФормированияТекстовЗапросов"); + Свойства.Вставить("ОграничениеПоВладельцуВозможно"); + Свойства.Вставить("ОграничениеПоВладельцуИспользуется"); + Свойства.Вставить("ОграничениеВРолях"); + Свойства.Вставить("ОграничениеВМодуле"); + Свойства.Вставить("ПоВладельцуБезЗаписиКлючейДоступа"); + + Возврат Свойства; + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта. +Процедура ПроверитьОграничениеДляВидаПользователей(Контекст, Результат, ДляВнешнихПользователей, ДополнительныйКонтекст) + + ТекстОграничения = ?(ДляВнешнихПользователей, Контекст.ОбщийРезультат.ДляВнешнихПользователей, + Контекст.ОбщийРезультат.ДляПользователей).ПроверяемоеОграничение; + + СтруктураОграничения = РассчитаннаяСтруктураОграничения(Контекст.ПолноеИмя, + ТекстОграничения, Контекст.ОбщийРезультат.ТекстВМодулеМенеджера, ДляВнешнихПользователей, Истина); + + Если СтруктураОграничения <> Неопределено + И СтруктураОграничения.ОписаниеОшибок.ЕстьОшибки Тогда + + Результат.ОписаниеОшибок = СтруктураОграничения.ОписаниеОшибок; + Контекст.УчетЗависимостейДоступен = Ложь; + Возврат; + КонецЕсли; + + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ДобавитьДополнительныйКонтекст(Контекст.ПолноеИмя, + ДополнительныйКонтекст, Контекст.ОписаниеОграничения, ДляВнешнихПользователей); + + ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); + ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); + + Попытка + ПараметрыОграничения = ПараметрыОграниченияПоСтруктуреОграничения(Контекст.ПолноеИмя, + СтруктураОграничения, ДляВнешнихПользователей, Контекст.ОбщийКонтекст, ДополнительныйКонтекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ПараметрыОграничения = Неопределено; + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + Результат.ОшибкаФормированияПараметровОграничения = ОшибкаПриВызовеИсключения.Текст; + Иначе + Результат.ОшибкаФормированияПараметровОграничения = + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать параметры ограничения доступа по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + Контекст.УчетЗависимостейДоступен = Ложь; + КонецПопытки; + + Если ПараметрыОграничения <> Неопределено Тогда + Результат.ОграничениеПоВладельцуВозможно = ПараметрыОграничения.ПолеВладельца <> Неопределено; + ПараметрыОграничения.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + УстановитьСвойстваЗаписиКлючейДоступа(ПараметрыОграничения); + ПараметрыОграничения.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); + ПараметрыОграничения.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); + Для Каждого КлючИЗначение Из ПараметрыОграничения.ВедущиеСписки.ПоЗначениямПолей Цикл + Контекст.ВедущиеСписки.Вставить(КлючИЗначение.Ключ, Неопределено); + КонецЦикла; + Для Каждого КлючИЗначение Из ПараметрыОграничения.ВедущиеСписки.ПоКлючамДоступа Цикл + Контекст.ВерсииОграниченийСписков.Вставить(КлючИЗначение.Ключ, Неопределено); + КонецЦикла; + Попытка + ДобавитьТекстыЗапросовВПараметрыОграничения(ПараметрыОграничения); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + Результат.ОшибкаФормированияТекстовЗапросов = ОшибкаПриВызовеИсключения.Текст; + Иначе + Результат.ОшибкаФормированияТекстовЗапросов = + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + Контекст.УчетЗависимостейДоступен = Ложь; + КонецПопытки; + КонецЕсли; + + Если Контекст.УчитыватьЗависимости Тогда + Возврат; + КонецЕсли; + + СокращенныеСвойства = Новый Структура; + СокращенныеСвойства.Вставить("ДоступЗапрещен", Ложь); + СокращенныеСвойства.Вставить("ПолеВладельца", Неопределено); + СокращенныеСвойства.Вставить("ОпорныеПоля", Неопределено); + СокращенныеСвойства.Вставить("ИмяОтдельногоРегистраКлючей", Неопределено); + ДополнительныйКонтекст.СвойстваОграниченияСписков.Вставить(Контекст.ПолноеИмя, СокращенныеСвойства); + + Если Не Контекст.УчетЗависимостейДоступен Тогда + Возврат; + КонецЕсли; + + ЗаполнитьЗначенияСвойств(СокращенныеСвойства, ПараметрыОграничения); + +КонецПроцедуры + +// Для функций ХранимыеПараметрыОграниченияДоступа, РассчитанныеПараметрыОграничения. +Функция ОбщаяВерсия(ОбщийКонтекст, ПолноеИмя, ВерсияДляПользователей, ВерсияДляВнешнихПользователей) + + Если ОбщийКонтекст.СпискиСОграничением.Получить(ПолноеИмя) = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Возврат СтрПолучитьСтроку(ВерсияДляПользователей, 1) + + Символы.ПС + СтрПолучитьСтроку(ВерсияДляВнешнихПользователей, 1) + + Символы.ПС + СтрПолучитьСтроку(ВерсияДляПользователей, 2) + + Символы.ПС + СтрПолучитьСтроку(ВерсияДляВнешнихПользователей, 2) + +КонецФункции + +// Для функции РассчитанныеПараметрыОграничения. +Процедура УстановитьСвойстваЗаписиКлючейДоступа(Результат) + + БезЗаписиКлючей = Ложь; + СЗаписьюКлючаДляЗависимыхСписковБезКлючей = Ложь; + + Если Результат.ОграничениеОтключено + Или Результат.ДоступЗапрещен + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + Если Результат.ИспользуетсяОграничениеПоВладельцу + Или Результат.Контекст.БезОбъектаМетаданных + Или Результат.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить( + Результат.Список) = Неопределено Тогда + + БезЗаписиКлючей = Истина; + Иначе + СЗаписьюКлючаДляЗависимыхСписковБезКлючей = Истина; + КонецЕсли; + КонецЕсли; + + Результат.Вставить("БезЗаписиКлючейДоступа", БезЗаписиКлючей); + Результат.Вставить("СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей", + СЗаписьюКлючаДляЗависимыхСписковБезКлючей); + +КонецПроцедуры + +// Для функций РассчитанныеПараметрыОграничения, ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * Текст - Строка +// * ТекстДляВнешнихПользователей - Строка +// * ПоВладельцуБезЗаписиКлючейДоступа - Булево +// - Неопределено +// * ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей - Булево +// - Неопределено +// * ТекстВМодулеМенеджера - Булево +// +Функция ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, БезВызоваИсключения = Ложь) + + Ограничение = Новый Структура; + Ограничение.Вставить("Текст", ""); + Ограничение.Вставить("ТекстДляВнешнихПользователей", ""); + Ограничение.Вставить("ПоВладельцуБезЗаписиКлючейДоступа", Неопределено); + Ограничение.Вставить("ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", Неопределено); + Ограничение.Вставить("ТекстВМодулеМенеджера", Ложь); + + ТекстВМодулеМенеджера = ОбщийКонтекст.СпискиСОграничением.Получить(ПолноеИмя); + Если ТекстВМодулеМенеджера = Неопределено Тогда + Возврат Ограничение; + КонецЕсли; + + Ограничение.ТекстВМодулеМенеджера = ТекстВМодулеМенеджера; + + Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда + МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный"); + ЭтоСправочникФайлов = МодульРаботаСФайламиСлужебный.ЭтоСправочникФайловИлиВерсийФайлов(ПолноеИмя); + Иначе + ЭтоСправочникФайлов = Ложь; + КонецЕсли; + + Если ЭтоЖурналДокументов(ПолноеИмя) Или ЭтоСправочникФайлов Тогда + // Для журналов документов ограничение должно быть + // по документу-владельцу без записи ключей доступа, если не требуется другое. + // Аналогично (по умолчанию) для справочников файлов и версий файлов. + Ограничение.ПоВладельцуБезЗаписиКлючейДоступа = Истина; + Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей = Истина; + КонецЕсли; + + Если ТекстВМодулеМенеджера Тогда + Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя); + + Попытка + Менеджер.ПриЗаполненииОграниченияДоступа(Ограничение); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в модуле менеджера + |в процедуре %4 по причине: + | + |%5'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + + Если БезВызоваИсключения Тогда + Возврат ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецПопытки; + Иначе + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); + Попытка + УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа(ОбъектМетаданных, Ограничение); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в общем модуле %4 + |в процедуре %5 по причине: + | + |%6'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + + Если БезВызоваИсключения Тогда + Возврат ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецПопытки; + КонецЕсли; + + Если ЭтоЖурналДокументов(ПолноеИмя) + И ( Ограничение.ПоВладельцуБезЗаписиКлючейДоступа <> Истина + Или Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей <> Истина) Тогда + + Если ВариантВстроенногоЯзыкаРусский() Тогда + ШаблонОграничения = + "РазрешитьЧтениеИзменение + |ГДЕ + | ЧтениеОбъектаРазрешено(Ссылка)"; // @Non-NLS + Иначе + ШаблонОграничения = + "AllowReadWrite + |WHERE + | ObjectReadingAllowed(Ref)"; + КонецЕсли; + + Если ТекстВМодулеМенеджера Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в модуле менеджера + |в процедуре %4 по причине: + | + |Для журналов документов не поддерживается ограничение, как для регистров, + |то есть, кроме варианта ограничения по владельцу без записи ключей доступа: + | + |%5'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ШаблонОграничения); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в общем модуле %4 + |в процедуре %5 по причине: + | + |Для журналов документов не поддерживается ограничение, как для регистров, + |то есть, кроме варианта ограничения по владельцу без записи ключей доступа: + | + |%6'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ШаблонОграничения); + КонецЕсли; + Если БезВызоваИсключения Тогда + Возврат ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Возврат Ограничение; + +КонецФункции + +// Для функции ОписаниеОграниченияДанных. +Функция ЭтоЖурналДокументов(ПолноеИмя) + + Возврат СтрНачинаетсяС(ВРег(ПолноеИмя), ВРег("ЖурналДокументов.")) + Или СтрНачинаетсяС(ВРег(ПолноеИмя), ВРег("DocumentJournal.")); // @Non-NLS + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ПараметрыОграниченияДляВидаПользователей. +// +// Возвращаемое значение: +// см. СтруктураОграничения +// +Функция РассчитаннаяСтруктураОграничения(ПолноеИмя, ТекстОграничения, ТекстВМодулеМенеджера, ДляВнешнихПользователей, БезИсключения = Ложь) + + Если Не ЗначениеЗаполнено(ТекстОграничения) Тогда + Возврат Неопределено; + КонецЕсли; + + РазобранноеОграничение = РазобранноеОграничение(ПолноеИмя, ТекстОграничения); + + ПроверитьТаблицыПоляИТипыПолей(РазобранноеОграничение); + + СтруктураОграничения = СтруктураОграничения(РазобранноеОграничение); + + Если БезИсключения Или Не СтруктураОграничения.ОписаниеОшибок.ЕстьОшибки Тогда + Возврат СтруктураОграничения; + КонецЕсли; + + ТекстОшибок = ТекстОшибокДляВызоваИсключения(ПолноеИмя, + СтруктураОграничения.ОписаниеОшибок, ДляВнешнихПользователей, ТекстВМодулеМенеджера); + + ВызватьИсключение ТекстОшибок; + +КонецФункции + +// Для функций СвойстваСпискаКакВедущего, ПараметрыОграничения и процедур УстановкаПараметровСеанса, +// ЗаполнитьПараметрыОграничения, ДобавитьПараметрыОграниченияСписка. +// +// Возвращаемое значение: +// см. НоваяСтруктураХранимыхПараметровЗаписи +// +Функция ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, + Обновить, УстановкаПараметровСеансаДляШаблонов = Ложь, + УстановкаПараметровДляОтчетаПраваДоступа = Ложь, ЕстьИзменения = Ложь) Экспорт + + Если Обновить Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст, ЕстьИзменения); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст); + ПараметрыОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа + Возврат ПараметрыОграниченияДоступа.Параметры; + КонецЕсли; + + ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа + + Если Не ТекущиеПараметры.Свойство("Параметры") Или ТекущиеПараметры.Параметры = Неопределено Тогда + ТекущиеПараметры = Новый Структура("Версия, ХешСумма", "", ""); // См. СеансовыеПараметрыОграниченияДоступа + ИдентификаторыТранзакции = Новый Соответствие; + Иначе + ИдентификаторыТранзакции = КэшПараметровОграничения().ИдентификаторыТранзакции; + КонецЕсли; + + Если ТранзакцияАктивна() + И ИдентификаторыТранзакции.Получить(ИдентификаторТранзакции) <> Неопределено Тогда + + Возврат ТекущиеПараметры.Параметры; + КонецЕсли; + + Пока Истина Цикл + ОписаниеВерсии = ОписаниеПоследнейВерсии(); + Если ТекущиеПараметры.Версия = ОписаниеВерсии.Версия + И ТекущиеПараметры.ХешСумма = ОписаниеВерсии.ХешСумма Тогда + Прервать; + КонецЕсли; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Прервать; + КонецЕсли; + Если ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + Если Не УстановкаПараметровСеансаДляШаблонов + И Не УстановкаПараметровДляОтчетаПраваДоступа + И ТекущиеПараметры.Версия = ОписаниеВерсии.Версия + И ТекущиеПараметры.ХешСумма = ОписаниеВерсии.ХешСумма Тогда + + ОбновитьИдентификаторыТранзакции(ИдентификаторТранзакции); + Возврат ТекущиеПараметры.Параметры; + КонецЕсли; + + // Параметры в базе данных отличаются от параметров в памяти. + Если ЗначениеЗаполнено(ОписаниеВерсии.Версия) Тогда + ВерсияПараметров = ВерсияПараметров(ОписаниеВерсии.Версия, + УстановкаПараметровСеансаДляШаблонов, УстановкаПараметровДляОтчетаПраваДоступа); + Иначе + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + КонецЕсли; + + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов); + + ПараметрыОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа + Возврат ПараметрыОграниченияДоступа.Параметры; + +КонецФункции + +// Для отчета ПраваДоступа. +// +// Возвращаемое значение: +// Структура: +// * ДляПользователей - Строка +// * ДляВнешнихПользователей - Строка +// +Функция ВсеВидыОграниченийПравДляОтчетаПраваДоступа() + + Кэш = КэшПараметровОграничения(); + + Если Кэш.ВидыОграниченийПравДляПользователей <> Неопределено + И Кэш.ВидыОграниченийПравДляВнешнихПользователей <> Неопределено Тогда + Возврат Новый Структура("ДляПользователей, ДляВнешнихПользователей", + Кэш.ВидыОграниченийПравДляПользователей, + Кэш.ВидыОграниченийПравДляВнешнихПользователей); + КонецЕсли; + + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь, Ложь, Истина); + + Возврат ВсеВидыОграниченийПравДляОтчетаПраваДоступа(); + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Функция ЗаписьПараметровОграниченияДоступаВТекущемСеансе() + + УстановитьПривилегированныйРежим(Истина); + ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; + УстановитьПривилегированныйРежим(Ложь); + + Возврат ТекущиеПараметры.Свойство("ЗаписьПараметровОграниченияДоступаВТекущемСеансе"); + +КонецФункции + +// Для функций ДействующиеПараметрыОграниченияДоступа, НоваяВерсияПараметровОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * Версия - Число +// - Неопределено +// * ХешСумма - Строка +// - Неопределено +// * ДатаСоздания - Дата +// - Неопределено +// * ВерсииПараметровШаблонов - ХранилищеЗначения +// - Неопределено +// +Функция ОписаниеПоследнейВерсии(ПрочитатьВерсииПараметровШаблонов = Ложь) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ПараметрыОграниченияДоступа.Версия КАК Версия, + | ПараметрыОграниченияДоступа.ХешСумма КАК ХешСумма, + | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания, + | ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов КАК ВерсииПараметровШаблонов + |ИЗ + | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа + | + |УПОРЯДОЧИТЬ ПО + | ПараметрыОграниченияДоступа.Версия УБЫВ"; + + Если Не ПрочитатьВерсииПараметровШаблонов Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов", "Неопределено"); + КонецЕсли; + + Выборка = Запрос.Выполнить().Выбрать(); + Выборка.Следующий(); + + Результат = Новый Структура("Версия, ХешСумма, ДатаСоздания, ВерсииПараметровШаблонов"); + ЗаполнитьЗначенияСвойств(Результат, Выборка); + + Возврат Результат; + +КонецФункции + +// Для функции ДействующиеПараметрыОграниченияДоступа. +Функция ВерсияПараметров(Версия, УстановкаПараметровСеансаДляШаблонов, УстановкаПараметровДляОтчетаПраваДоступа) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ПараметрыОграниченияДоступа.Версия КАК Версия, + | ПараметрыОграниченияДоступа.ХешСумма КАК ХешСумма, + | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания, + | ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей КАК ДляШаблоновВСеансахПользователей, + | ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей КАК ДляШаблоновВСеансахВнешнихПользователей, + | ПараметрыОграниченияДоступа.ДляЗаписиОбъектовИПроверкиПрав КАК ДляЗаписиОбъектовИПроверкиПрав, + | ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов КАК ВерсииПараметровШаблонов, + | ПараметрыОграниченияДоступа.ДляОтчетаПоПравамДоступа КАК ДляОтчетаПоПравамДоступа + |ИЗ + | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа + |ГДЕ + | ПараметрыОграниченияДоступа.Версия = &Версия"; + + Если УстановкаПараметровСеансаДляШаблонов Или УстановкаПараметровДляОтчетаПраваДоступа Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляЗаписиОбъектовИПроверкиПрав", "Неопределено"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов", "Неопределено"); + КонецЕсли; + Если Не УстановкаПараметровДляОтчетаПраваДоступа Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляОтчетаПоПравамДоступа", "Неопределено"); + КонецЕсли; + + Если УстановкаПараметровСеансаДляШаблонов + Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + + Запрос.Текст = СтрЗаменить(Запрос.Текст, ?(Пользователи.ЭтоСеансВнешнегоПользователя(), + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей", + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей"), "Неопределено"); + Иначе + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей", "Неопределено"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей", "Неопределено"); + КонецЕсли; + + Запрос.УстановитьПараметр("Версия", Версия); + + Выборка = Запрос.Выполнить().Выбрать(); + Выборка.Следующий(); + + Возврат Выборка; + +КонецФункции + +// Для функции ДействующиеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// см. ХранимыеПараметрыОграниченияДоступа +// +Функция НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст, ЕстьИзменения = Ложь) + + Попытка + ПроверитьАктуальностьМетаданных(); + Исключение + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "НоваяВерсияПараметровОграниченияДоступа", Истина); + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + + УдалитьСтрокиВерсииХранимыхПараметров = Ложь; + + Если ТипЗнч(ОбщийКонтекст) <> Тип("Структура") + Или ЗначениеЗаполнено(ОбщийКонтекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы) Тогда + ОбновитьПовторноИспользуемыеЗначения(); + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); + КонецЕсли; + + Если РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() Тогда + Если Не ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.Вставить("СтрокиВерсииХранимыхПараметров"); + УдалитьСтрокиВерсииХранимыхПараметров = Истина; + КонецЕсли; + КонецЕсли; + + ВерсииОграниченийСписков = Новый Соответствие; + ОбщийКонтекст.Вставить("ИнформацияДляЖурнала", НоваяИнформацияНесоответствияПараметровДляЖурнала()); + ХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст, ВерсииОграниченийСписков); + ВерсииОграниченийСписков.Вставить("Справочник.НаборыГруппДоступа", "1"); + + ПараметрыЗаписи = Новый Структура; + ПараметрыЗаписи.Вставить("ВерсииОграниченийСписков", ВерсииОграниченийСписков); + ПараметрыЗаписи.Вставить("ИдентификаторыВсехСписков"); + ПараметрыЗаписи.Вставить("ХранимыеПараметры", ХранимыеПараметры); + ПараметрыЗаписи.Вставить("ИдентификаторДоступа", ИдентификаторДоступа()); + ПараметрыЗаписи.Вставить("ИнформацияДляЖурнала", ОбщийКонтекст.ИнформацияДляЖурнала); + ОбщийКонтекст.Удалить("ИнформацияДляЖурнала"); + + Если ОбщийКонтекст.Свойство("СпискиСУстаревшимиВариантамиДоступа") Тогда + ПараметрыЗаписи.Вставить("СпискиСУстаревшимиВариантамиДоступа", + ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа); + Иначе + ПараметрыЗаписи.Вставить("СпискиСУстаревшимиВариантамиДоступа"); + КонецЕсли; + + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ПараметрыЗаписи.Вставить("СтрокиВерсии", ОбщийКонтекст.СтрокиВерсииХранимыхПараметров); + КонецЕсли; + + Если Не ТранзакцияАктивна() + Или МонопольныйРежим() + Или ОбщийКонтекст.Свойство("ЗаписатьВТекущейТранзакции") + Или ОбщегоНазначения.ИнформационнаяБазаФайловая() + Или СтандартныеПодсистемыСервер.ЭтоРазделенныйРежимСеансаБезРазделителей() + Или ЗаписьПараметровОграниченияДоступаВТекущемСеансе() Тогда + + НомерПопыткиБлокировки = 0; + Пока Истина Цикл + НомерПопыткиБлокировки = НомерПопыткиБлокировки + 1; + ЭтоОшибкаБлокировки = Ложь; + Попытка + ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа(ПараметрыЗаписи,, ЭтоОшибкаБлокировки); + Исключение + Если ЭтоОшибкаБлокировки + И НомерПопыткиБлокировки < 3 + И Не ТранзакцияАктивна() Тогда + Продолжить; + КонецЕсли; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "НоваяВерсияПараметровОграниченияДоступа", Истина); + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + Прервать; + КонецЦикла; + Иначе + ПараметрыЗаписиВХранилище = Новый ХранилищеЗначения(ПараметрыЗаписи); + ОписаниеВерсии = Неопределено; + Пока Истина Цикл + ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа( + ПараметрыЗаписиВХранилище.Получить(), Истина); + Если ОписаниеВерсии <> Неопределено Тогда + Прервать; + КонецЕсли; + Если ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() Тогда + Прервать; + КонецЕсли; + КонецЦикла; + Если ОписаниеВерсии = Неопределено Тогда + ПараметрыЗаписи.ИдентификаторыВсехСписков = ИдентификаторыВсехСписков(); + ПараметрыЗаписиВХранилище = Новый ХранилищеЗначения(ПараметрыЗаписи); + ИмяПроцедуры = ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа(); + АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено); + ПараметрыПроцедуры = Новый Массив; + ПараметрыПроцедуры.Добавить(АдресРезультата); + ПараметрыПроцедуры.Добавить(ПараметрыЗаписиВХранилище); + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + НаименованиеЗадания = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Управление доступом: Запись новой версии параметров ограничения доступа (из сеанса %1 от %2)'", + ОбщегоНазначения.КодОсновногоЯзыка()), + Формат(ТекущийСеанс.НомерСеанса, "ЧГ="), + Формат(ТекущийСеанс.НачалоСеанса, "ДЛФ=DT")); + ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяПроцедуры, ПараметрыПроцедуры,, НаименованиеЗадания); + ФоновоеЗадание = ФоновоеЗадание.ОжидатьЗавершенияВыполнения(60); + Результат = ПолучитьИзВременногоХранилища(АдресРезультата); + ЗаголовокОшибки = НСтр("ru = 'Не удалось записать новую версию параметров ограничения доступа по причине:'"); + Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + ФоновоеЗадание.Отменить(); + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание выполняется более 60 секунд, поэтому отменено.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Отменено Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание отменено администратором.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Завершено Тогда + Если ТипЗнч(ФоновоеЗадание.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ФоновоеЗадание.ИнформацияОбОшибке); + Иначе + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание завершилось аварийно.'"); + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ТипЗнч(Результат) <> Тип("Структура") Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание не вернуло результат.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если Результат.ТребуетсяПерезапускСеанса Тогда + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "НоваяВерсияПараметровОграниченияДоступа", Истина); + ПроверитьАктуальностьМетаданных(); + СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(Результат.ТекстОшибки); + ВызватьИсключение Результат.ТекстОшибки; + КонецЕсли; + Если ЗначениеЗаполнено(Результат.ТекстОшибки) Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + Результат.ТекстОшибки; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ОписаниеВерсии = Результат.ОписаниеВерсии; + КонецЕсли; + КонецЕсли; + + Если ОбщийКонтекст.Свойство("СпискиСУстаревшимиВариантамиДоступа") Тогда + ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа = + ОписаниеВерсии.СпискиСУстаревшимиВариантамиДоступа; + КонецЕсли; + + Если УдалитьСтрокиВерсииХранимыхПараметров Тогда + ОбщийКонтекст.Удалить("СтрокиВерсииХранимыхПараметров"); + + ИначеЕсли ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров = ОписаниеВерсии.СтрокиВерсии; + КонецЕсли; + + Если ОписаниеВерсии.ЕстьИзменения Тогда + ЕстьИзменения = Истина; + КонецЕсли; + + Для Каждого КлючИЗначение Из ОписаниеВерсии.ЗаполняемыеСвойстваВерсии Цикл + ХранимыеПараметры.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + + Возврат ХранимыеПараметры; + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Функция ИдентификаторыВсехСписков() + + Списки = Новый Массив; + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыОбмена); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Справочники); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Документы); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ЖурналыДокументов); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыВидовХарактеристик); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыСчетов); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыВидовРасчета); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыСведений); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыНакопления); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыБухгалтерии); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыРасчета); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.БизнесПроцессы); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Задачи); + + Возврат ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки); + +КонецФункции + +// Для функции ИдентификаторыВсехСписков. +Процедура ДобавитьПолныеИменаКоллекции(Списки, КоллекцияОбъектовМетаданных) + + Для Каждого ОбъектМетаданных Из КоллекцияОбъектовМетаданных Цикл + Списки.Добавить(ОбъектМетаданных.ПолноеИмя()); + КонецЦикла; + +КонецПроцедуры + +// Для функций НоваяВерсияПараметровОграниченияДоступа и +// ДействующиеПараметрыОграниченияДоступа. +// +Функция ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() + + ОтборЗаданий = Новый Структура("ИмяМетода, Состояние", + ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа(), + СостояниеФоновогоЗадания.Активно); + + НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(ОтборЗаданий); + + Если НайденныеЗадания.Количество() = 0 Тогда + Возврат Истина; + КонецЕсли; + + ФоновыеЗадания.ОжидатьЗавершенияВыполнения(НайденныеЗадания, 1); + + Возврат Ложь; + +КонецФункции + +// Для функций НоваяВерсияПараметровОграниченияДоступа и +// ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа. +// +Функция ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() + + Возврат "УправлениеДоступомСлужебный.ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне"; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// Предупреждение - Строка +// Ошибка - Строка +// ВерсияТекстовОграниченияДоступа - Строка +// +Функция НоваяИнформацияНесоответствияПараметровДляЖурнала() + + Результат = Новый Структура; + Результат.Вставить("Предупреждение", ""); + Результат.Вставить("Ошибка", ""); + Результат.Вставить("ВерсияТекстовОграниченияДоступа", ""); + + Возврат Результат; + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Процедура ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне(АдресРезультата, ХранилищеПараметров) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне"); + + Результат = Новый Структура; + Результат.Вставить("ОписаниеВерсии", Новый Структура); + Результат.Вставить("ТекстОшибки", ""); + Результат.Вставить("ТребуетсяПерезапускСеанса", Ложь); + + УстановитьПривилегированныйРежим(Истина); + Попытка + Параметры = ХранилищеПараметров.Получить(); + Если Параметры.ИдентификаторДоступа = ИдентификаторДоступа() Тогда + Результат.ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа(Параметры); + Иначе + Результат.ТекстОшибки = НСтр("ru = 'Ошибка проверки доступа.'"); + КонецЕсли; + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(Результат.ТекстОшибки) Тогда + Результат.ТребуетсяПерезапускСеанса = Истина; + КонецЕсли; + Если Не Результат.ТребуетсяПерезапускСеанса + Или Не СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + Результат.ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецЕсли; + КонецПопытки; + УстановитьПривилегированныйРежим(Ложь); + + ПоместитьВоВременноеХранилище(Результат, АдресРезультата); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа и +// процедуры ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне. +// +Функция ИдентификаторДоступа() + + Возврат ПоследнееОбновлениеДоступа().ИдентификаторДоступа; + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа и +// процедуры ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне. +// +Функция ОписаниеНовойВерсииПараметровОграниченияДоступа(Параметры, БезЗаписи = Ложь, ЭтоОшибкаБлокировки = Ложь) + + Запись = НоваяТаблицаРегистраСведенийПараметрыОграниченияДоступа().Добавить(); + ЗаполнитьЗначенияСвойств(Запись, Параметры.ХранимыеПараметры); + + ЗаполняемыеСвойстваВерсии = Новый Структура("Версия, ДатаСоздания, ХешСумма, + |ВерсииПараметровШаблонов, ХешСуммаПостоянныхПараметров, ХешСуммаПараметровШаблонов, + |ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей"); + + Результат = Новый Структура; + Результат.Вставить("ЕстьИзменения", Ложь); + Результат.Вставить("ЗаполняемыеСвойстваВерсии", ЗаполняемыеСвойстваВерсии); + Результат.Вставить("СпискиСУстаревшимиВариантамиДоступа", + Параметры.СпискиСУстаревшимиВариантамиДоступа); + Параметры.Вставить("СпискиСНовымОсновнымВариантомДоступа", Новый Массив); + Если Параметры.Свойство("СтрокиВерсии") Тогда + Результат.Вставить("СтрокиВерсии", Параметры.СтрокиВерсии); + КонецЕсли; + + Если БезЗаписи Тогда + ОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); + ЗаполнитьПараметрыДляШаблонов(Запись, Параметры, ОписаниеВерсии); + Если ОписаниеВерсии.ХешСумма <> Запись.ХешСумма Тогда + Возврат Неопределено; + КонецЕсли; + Иначе + НачатьТранзакцию(); + Попытка + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(ЭтоОшибкаБлокировки, Истина); + КонецЕсли; + ОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); + Пока Истина Цикл + ЗаполнитьПараметрыДляШаблонов(Запись, Параметры, ОписаниеВерсии); + Если ОписаниеВерсии.ХешСумма = Запись.ХешСумма Тогда + Прервать; + КонецЕсли; + + ПроверитьАктуальностьМетаданных(); + + Если ЗначениеЗаполнено(ОписаниеВерсии.Версия) Тогда + НоваяВерсия = ОписаниеВерсии.Версия + 1; + Иначе + НоваяВерсия = 1; + КонецЕсли; + + БлокировкаДанных = Новый БлокировкаДанных; + ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); + ЭлементБлокировки.УстановитьЗначение("Версия", НоваяВерсия); + БлокировкаДанных.Заблокировать(); + НовоеОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); + + Если ОписаниеВерсии.Версия <> НовоеОписаниеВерсии.Версия + Или НовоеОписаниеВерсии.Версия = НоваяВерсия Тогда + + ОписаниеВерсии = НовоеОписаниеВерсии; + Продолжить; + КонецЕсли; + + ПроверитьАктуальностьМетаданных(); + + Запись.Версия = НоваяВерсия; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ПараметрыОграниченияДоступа); + ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), Запись); + Запись = НаборЗаписей[0]; + НаборЗаписей.Отбор.Версия.Установить(НоваяВерсия); + ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, Запись); + + ЗапланироватьОбновлениеДоступаПриИзмененииПараметров(ОписаниеВерсии.Версия, Параметры); + НаборЗаписей.Записать(); + Результат.ЕстьИзменения = Истина; + + ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Параметры.ИнформацияДляЖурнала.Предупреждение); + ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Параметры.ИнформацияДляЖурнала.Ошибка, Истина); + + Если РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() Тогда + ЗарегистрироватьСтрокуВерсииПараметровОграниченияДоступа(НаборЗаписей[0], + Параметры.СтрокиВерсии); + КонецЕсли; + + Прервать; + КонецЦикла; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Если Не Результат.ЕстьИзменения Тогда + ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, ОписаниеВерсии, + "Версия, ДатаСоздания, ХешСумма, ВерсииПараметровШаблонов"); + ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, Запись, + "ХешСуммаПостоянныхПараметров, ХешСуммаПараметровШаблонов, + |ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей"); + ИначеЕсли Не ТранзакцияАктивна() Тогда + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ТекущаяДатаСеанса(), Истина); + ВерсияТекстов = Параметры.ИнформацияДляЖурнала.ВерсияТекстовОграниченияДоступа; + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ВерсияТекстов, Истина); + УстановитьОбновлениеДоступа(Истина); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Версия - Число +// * ХешСумма - Строка +// * ХешСуммаПостоянныхПараметров - Строка +// * ДляЗаписиОбъектовИПроверкиПрав - ХранилищеЗначения +// * ДляОтчетаПоПравамДоступа - ХранилищеЗначения +// * ХешСуммаПараметровШаблонов - Строка +// * ДляШаблоновВСеансахПользователей - ХранилищеЗначения +// * ДляШаблоновВСеансахВнешнихПользователей - ХранилищеЗначения +// * ВерсииПараметровШаблонов - ХранилищеЗначения +// * ДатаСоздания - Дата +// +Функция НоваяТаблицаРегистраСведенийПараметрыОграниченияДоступа() + + ТипВерсии = Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(15, 0, ДопустимыйЗнак.Неотрицательный)); + ТипХешСуммы = Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(48, ДопустимаяДлина.Переменная)); + + Таблица = Новый ТаблицаЗначений; + Таблица.Колонки.Добавить("Версия", ТипВерсии); + Таблица.Колонки.Добавить("ХешСумма", ТипХешСуммы); + Таблица.Колонки.Добавить("ХешСуммаПостоянныхПараметров", ТипХешСуммы); + Таблица.Колонки.Добавить("ДляЗаписиОбъектовИПроверкиПрав", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ДляОтчетаПоПравамДоступа", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ХешСуммаПараметровШаблонов", ТипХешСуммы); + Таблица.Колонки.Добавить("ДляШаблоновВСеансахПользователей", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ДляШаблоновВСеансахВнешнихПользователей", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ВерсииПараметровШаблонов", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ДатаСоздания", Новый ОписаниеТипов("Дата")); + + Возврат Таблица; + +КонецФункции + +// Для функции ОписаниеНовойВерсииПараметровОграниченияДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииПараметров(СтараяВерсия, Параметры) + + НедоступныеСписки = Новый Массив; + СтараяВерсияСтруктурыКэша = "0"; + Списки = СпискиСИзменениемВерсий(СтараяВерсия, + Параметры.ВерсииОграниченийСписков, НедоступныеСписки, СтараяВерсияСтруктурыКэша); + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.ВерсииОграниченийСписков = Параметры.ВерсииОграниченийСписков; + ПараметрыПланирования.ИдентификаторыВсехСписков = Параметры.ИдентификаторыВсехСписков; + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + ПараметрыПланирования.Описание = "НоваяВерсияПараметровОграниченияДоступа"; + + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + + Если ЗначениеЗаполнено(НедоступныеСписки) Тогда + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Ложь; + ЗапланироватьОбновлениеДоступа(НедоступныеСписки, ПараметрыПланирования); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(НедоступныеСписки, ПараметрыПланирования); + КонецЕсли; + + Если ЗначениеЗаполнено(Параметры.СпискиСНовымОсновнымВариантомДоступа) Тогда + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Ложь; + ЗапланироватьОбновлениеДоступа(Параметры.СпискиСНовымОсновнымВариантомДоступа, + ПараметрыПланирования); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(Параметры.СпискиСНовымОсновнымВариантомДоступа, + ПараметрыПланирования); + КонецЕсли; + Если ЗначениеЗаполнено(Параметры.СпискиСУстаревшимиВариантамиДоступа) Тогда + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(Параметры.СпискиСУстаревшимиВариантамиДоступа, + ПараметрыПланирования); + КонецЕсли; + + Если Списки = Неопределено + Или СтараяВерсияСтруктурыКэша = ВерсияСтруктурыКэша() Тогда + Возврат; + КонецЕсли; + + НовыеПараметры = Новый Структура(Параметры.ХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); + НовыеПараметры.Вставить("ИдентификаторыВсехСписков", Параметры.ИдентификаторыВсехСписков); + РегистрыСведений.ПараметрыОграниченияДоступа.ПриИзмененииВерсииСтруктурыКэша( + СтараяВерсияСтруктурыКэша, НовыеПараметры); + +КонецПроцедуры + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений и +// функции НоваяВерсияПараметровОграниченияДоступа. +// +Процедура ПроверитьАктуальностьМетаданных() Экспорт + + КонфигурацияИзменена = КонфигурацияБазыДанныхИзмененаДинамически(); + РасширенияИзменены = Справочники.ВерсииРасширений.РасширенияИзмененыДинамически(); + + Если Не КонфигурацияИзменена И Не РасширенияИзменены Тогда + Возврат; + КонецЕсли; + + Попытка + Попытка + Если КонфигурацияИзменена Тогда + СтандартныеПодсистемыСервер.ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияВерсииПрограммы(); + ИначеЕсли РасширенияИзменены Тогда + СтандартныеПодсистемыСервер.ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияРасширенийПрограммы(); + КонецЕсли; + Исключение + Если ЭтоСеансФоновогоЗадания() + Или СтандартныеПодсистемыСервер.ЭтоРазделенныйРежимСеансаБезРазделителей() Тогда + ВызватьИсключение; + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось проверить или обновить права доступа по причине: + |%1 + | + |Повторите операцию через минуту, и если проблема останется, перезапустите сеанс.'"), + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); + ВызватьИсключение ТекстОшибки; + КонецПопытки; + Исключение + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); + СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(ТекстОшибки); + ПриОшибкеПроверкиАктуальностиМетаданных(ТекстОшибки); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ПроверитьАктуальностьМетаданных +Функция ЭтоСеансФоновогоЗадания() + + Если ТекущийРежимЗапуска() <> Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + Возврат ТекущийСеанс.ИмяПриложения = "BackgroundJob"; + +КонецФункции + +// Для процедуры УстановитьОбновлениеДоступа +Функция ЭтоСеансФоновогоОбновленияДоступа() + + УстановитьПривилегированныйРежим(Истина); + Возврат ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЭтоСеансФоновогоОбновленияДоступа"); + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура УстановитьЭтоСеансФоновогоОбновленияДоступа() + + Если ТекущийРежимЗапуска() <> Неопределено Тогда + Возврат; + КонецЕсли; + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда + Возврат; + КонецЕсли; + + УстановитьПривилегированныйРежим(Истина); + + Параметры = Новый Структура(ПараметрыСеанса.ПараметрыОграниченияДоступа); + Параметры.Вставить("ЭтоСеансФоновогоОбновленияДоступа"); + ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(Параметры); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Процедура ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Комментарий, ЭтоОшибка = Ложь) + + Если Не ЗначениеЗаполнено(Комментарий) Тогда + Возврат; + КонецЕсли; + + ИмяСобытия = НСтр("ru = 'Управление доступом.Параметры ограничения доступа.Несоответствие'", + ОбщегоНазначения.КодОсновногоЯзыка()); + ШаблонЗаголовка = + НСтр("ru = 'Есть несоответствие в записанных параметрах ограничения доступа + |Версия %1, Дата создания %2, Хеш-Сумма: %3, + |Хеш-сумма постоянных параметров: %4'"); + + Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗаголовка, + Запись.Версия, + Запись.ДатаСоздания, + Запись.ХешСумма, + Запись.ХешСуммаПостоянныхПараметров); + + УровеньЖурнала = ?(ЭтоОшибка, УровеньЖурналаРегистрации.Ошибка, + УровеньЖурналаРегистрации.Предупреждение); + + ЗаписьЖурналаРегистрации(ИмяСобытия, + УровеньЖурнала, + Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа,, + Заголовок + Символы.ПС + Символы.ПС + Комментарий, + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Процедура ЗарегистрироватьСтрокуВерсииПараметровОграниченияДоступа(Запись, СтрокиВерсии) + + Состав = Новый Массив; + Состав.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + "Версия = %1 + |ДатаСоздания = %2 + |ХешСумма = %3 + |ХешСуммаПостоянныхПараметров = %4 + |ХешСуммаПараметровШаблонов = %5", + Запись.Версия, + Формат(Запись.ДатаСоздания, "ДЛФ=DT"), + Запись.ХешСумма, + Запись.ХешСуммаПостоянныхПараметров, + Запись.ХешСуммаПараметровШаблонов)); + + Для Каждого Строка Из СтрокиВерсии.СтрокиВерсийСписков Цикл + Состав.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + "[Список = %1, ДляВнешнихПользователей = %2, Версия = %3] + |%4", + Строка.Список, + ?(Строка.ДляВнешнихПользователей, "Да", "Нет"), + Строка.Версия, + Строка.СтрокаВерсии)); + КонецЦикла; + + Состав.Добавить("[ВсеВерсииСтрокой] + |" + СтрокиВерсии.ВсеВерсииСтрокой); + + Состав.Добавить("[ВидыОграниченийПравДляПользователейСтрокой] + |" + СтрокиВерсии.ВидыОграниченийПравДляПользователейСтрокой); + + Состав.Добавить("[ВидыОграниченийПравДляВнешнихПользователейСтрокой] + |" + СтрокиВерсии.ВидыОграниченийПравДляВнешнихПользователейСтрокой); + + Состав.Добавить("[СпискиСОграничениемПоПолямВСеансахПользователей] + |" + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахПользователей); + + Состав.Добавить("[СпискиСОграничениемПоПолямВСеансахВнешнихПользователей] + |" + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахВнешнихПользователей); + + Комментарий = СтрСоединить(Состав, Символы.ПС); + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Параметры ограничения доступа.Строка версии'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа,, + Комментарий, + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Функция СпискиСИзменениемВерсий(Версия, НовыеВерсииОграниченийСписков, НедоступныеСписки, + СтараяВерсияСтруктурыКэша) + + Если Не ЗначениеЗаполнено(Версия) Тогда + Возврат Неопределено; + КонецЕсли; + + ВерсияПараметров = ВерсияПараметров(Версия, Ложь, Ложь); + ПараметрыЗаписиХранилище = ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав; + + Если ТипЗнч(ПараметрыЗаписиХранилище) <> Тип("ХранилищеЗначения") Тогда + Возврат Неопределено; + КонецЕсли; + ПараметрыЗаписи = ЗначениеИзХранилища(ПараметрыЗаписиХранилище); + + Если ТипЗнч(ПараметрыЗаписи) <> Тип("ФиксированнаяСтруктура") + Или Не ПараметрыЗаписи.Свойство("ВерсииОграниченийСписков") + Или ТипЗнч(ПараметрыЗаписи.ВерсииОграниченийСписков) <> Тип("ФиксированноеСоответствие") Тогда + Возврат Неопределено; + КонецЕсли; + + Свойства = Новый Структура("ВерсияСтруктурыКэша", СтараяВерсияСтруктурыКэша); + ЗаполнитьЗначенияСвойств(Свойства, ПараметрыЗаписи); + СтараяВерсияСтруктурыКэша = Свойства.ВерсияСтруктурыКэша; + + Таблица = Новый ТаблицаЗначений; + Таблица.Колонки.Добавить("Список", Новый ОписаниеТипов("Строка")); + Таблица.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка")); + Таблица.Колонки.Добавить("ВидИзменения", Новый ОписаниеТипов("Число")); + + Для Каждого КлючИЗначение Из ПараметрыЗаписи.ВерсииОграниченийСписков Цикл + Строка = Таблица.Добавить(); + Строка.Список = КлючИЗначение.Ключ; + Строка.Версия = СтрПолучитьСтроку(КлючИЗначение.Значение, 1) + + Символы.ПС + СтрПолучитьСтроку(КлючИЗначение.Значение, 2); + Строка.ВидИзменения = -1; + КонецЦикла; + + Для Каждого КлючИЗначение Из НовыеВерсииОграниченийСписков Цикл + Строка = Таблица.Добавить(); + Строка.Список = КлючИЗначение.Ключ; + Строка.Версия = СтрПолучитьСтроку(КлючИЗначение.Значение, 1) + + Символы.ПС + СтрПолучитьСтроку(КлючИЗначение.Значение, 2); + Строка.ВидИзменения = 1; + КонецЦикла; + + Таблица.Свернуть("Список, Версия", "ВидИзменения"); + Списки = Новый Массив; + НенайденныеСписки = Новый Массив; + + Для Каждого Строка Из Таблица Цикл + Если Строка.ВидИзменения = 0 Тогда + Продолжить; + КонецЕсли; + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Строка.Список); + Если ОбъектМетаданных = Неопределено Тогда + НенайденныеСписки.Добавить(Строка.Список); + Продолжить; + КонецЕсли; + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + Если Списки.Найти(ПолноеИмя) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Списки.Добавить(ПолноеИмя); + КонецЦикла; + + Если НенайденныеСписки.Количество() > 0 Тогда + НедоступныеСписки = ВсеИдентификаторыСПодобнымиПолнымиИменами(НенайденныеСписки); + + ИначеЕсли Списки.Количество() = 1 И Списки[0] = "Справочник.НаборыГруппДоступа" Тогда + Списки = Новый Массив; + КонецЕсли; + + Возврат Списки; + +КонецФункции + +// Для функции СпискиСИзменениемВерсий и для процедуры ДобавитьЗависимыеСписки. +Функция ВсеИдентификаторыСПодобнымиПолнымиИменами(ПолныеИмена) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | Идентификаторы.Ссылка КАК Ссылка + |ИЗ + | Справочник.ИдентификаторыОбъектовМетаданных КАК Идентификаторы + |ГДЕ + | &УсловияОтбораИОМ + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | Идентификаторы.Идентификатор + |ИЗ + | РегистрСведений.ИдентификаторыОбъектовВерсийРасширений КАК Идентификаторы + |ГДЕ + | &УсловияОтбораИОР"; + + УсловияОтбораИОМ = Новый Массив; + УсловияОтбораИОР = Новый Массив; + + НомерПараметра = 1; + Для Каждого ПолноеИмя Из ПолныеИмена Цикл + ИмяПараметра = "ПолноеИмя" + Формат(НомерПараметра, "ЧГ="); + Запрос.УстановитьПараметр(ИмяПараметра, ПолноеИмя); + УсловияОтбораИОМ.Добавить(СтрЗаменить("Идентификаторы.ПолноеИмя ПОДОБНО &ИмяПараметра СПЕЦСИМВОЛ ""~""", + "ИмяПараметра", ИмяПараметра)); // @query-part-1, @query-part-2 + УсловияОтбораИОР.Добавить(СтрЗаменить("Идентификаторы.ПолноеИмяОбъекта ПОДОБНО &ИмяПараметра СПЕЦСИМВОЛ ""~""", + "ИмяПараметра", ИмяПараметра)); // @query-part-1, @query-part-2 + НомерПараметра = НомерПараметра + 1; + КонецЦикла; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловияОтбораИОМ", + СтрСоединить(УсловияОтбораИОМ, Символы.ПС + " ИЛИ ")); // @query-part-2 + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловияОтбораИОР", + СтрСоединить(УсловияОтбораИОР, Символы.ПС + " ИЛИ ")); // @query-part-2 + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +// Для процедуры ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Строка +// +Функция ВерсияСтруктурыКэша() Экспорт + + // Число нужно увеличивать при внесении изменений в состав параметров кэша + // (в том числе при изменении версии шаблонов). + Возврат "28.2" + ВерсияПеревода(); + +КонецФункции + +Функция ВерсияПеревода() + + Если ВариантВстроенногоЯзыкаРусский() Тогда + Возврат ""; + Иначе + Возврат "/" + Метаданные.Версия; + КонецЕсли; + +КонецФункции + +// Для процедур УстановкаПараметровСеанса, УточнитьВерсииШаблоновОграниченияДоступа и +// для функции СтруктураХранимыхПараметровШаблонов. +// +// Возвращаемое значение: +// Строка +// +Функция ВерсииШаблоновОграниченияДоступа() + + Возврат + ",ДляОбъекта9, + |,ДляРегистра9, + |,ПоЗначениям18, + |,ПоЗначениямРасширенный18, + |,ПоЗначениямИНаборамРасширенный18, + |,ПоНаборамЗначений18,"; + +КонецФункции + +// Для процедур УстановитьВерсиюПараметров, ЗаполнитьПараметрыДляШаблонов и +// функции НоваяСтруктураХранимыхВерсийПараметровШаблонов. +// +// +// Возвращаемое значение: +// Строка +// +Функция ВерсияСтруктурыВерсийПараметровШаблонов() + + // Число нужно увеличивать только при внесении изменений + // в состав параметра ВерсииПараметровШаблонов. + Возврат "1"; + +КонецФункции + +// Для функции ДействующиеПараметрыОграниченияДоступа. +Процедура ОбновитьИдентификаторыТранзакции(ИдентификаторТранзакции) + + Кэш = КэшПараметровОграничения(); + + Если Не ТранзакцияАктивна() И Кэш.ИдентификаторыТранзакции.Количество() = 0 + Или ТранзакцияАктивна() И ИдентификаторТранзакции = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ИдентификаторТранзакции <> Неопределено И ТранзакцияАктивна() Тогда + Кэш.ИдентификаторыТранзакции.Вставить(ИдентификаторТранзакции, Истина); + Иначе + Кэш.ИдентификаторыТранзакции.Очистить(); + КонецЕсли; + +КонецПроцедуры + +// Для функции ДействующиеПараметрыОграниченияДоступа. +Процедура УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов = Ложь, ПовторныйВызов = Ложь) + + Если Не ПовторныйВызов Тогда + Если УстановкаПараметровСеансаДляШаблонов Тогда + СброситьКэшПараметровОграничения(); + Иначе + ОбновитьПовторноИспользуемыеЗначения(); + КонецЕсли; + КонецЕсли; + + Если ИдентификаторТранзакции <> Неопределено И ТранзакцияАктивна() Тогда + Кэш = КэшПараметровОграничения(); + Кэш.ИдентификаторыТранзакции.Вставить(ИдентификаторТранзакции, Истина); + КонецЕсли; + + Если ТипЗнч(ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав) = Тип("ХранилищеЗначения") Тогда + ДляЗаписиОбъектовИПроверкиПрав = СтруктураХранимыхПараметровЗаписи( + ЗначениеИзХранилища(ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав)); + + Если ДляЗаписиОбъектовИПроверкиПрав.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Иначе + ДляЗаписиОбъектовИПроверкиПрав = Неопределено; + КонецЕсли; + + Если ТипЗнч(ВерсияПараметров.ВерсииПараметровШаблонов) = Тип("ХранилищеЗначения") Тогда + ВерсииПараметровШаблонов = СтруктураХранимыхВерсийПараметровШаблонов( + ЗначениеИзХранилища(ВерсияПараметров.ВерсииПараметровШаблонов)); + + Если ВерсииПараметровШаблонов.ВерсияСтруктурыВерсий <> ВерсияСтруктурыВерсийПараметровШаблонов() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Иначе + ВерсииПараметровШаблонов = Неопределено; + КонецЕсли; + + Если ТипЗнч(ВерсияПараметров.ДляОтчетаПоПравамДоступа) = Тип("ХранилищеЗначения") Тогда + ДляОтчетаПоПравамДоступа = СтруктураХранимыхПараметровОтчета( + ЗначениеИзХранилища(ВерсияПараметров.ДляОтчетаПоПравамДоступа)); + + Если ДляОтчетаПоПравамДоступа.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Кэш = КэшПараметровОграничения(); + Кэш.ВидыОграниченийПравДляПользователей + = ДляОтчетаПоПравамДоступа.ВидыОграниченийПравДляПользователей; + Кэш.ВидыОграниченийПравДляВнешнихПользователей + = ДляОтчетаПоПравамДоступа.ВидыОграниченийПравДляВнешнихПользователей; + КонецЕсли; + + Если УстановкаПараметровСеансаДляШаблонов + Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + + ХранилищеДляШаблоновВСеансах = ?(Пользователи.ЭтоСеансВнешнегоПользователя(), + ВерсияПараметров.ДляШаблоновВСеансахВнешнихПользователей, + ВерсияПараметров.ДляШаблоновВСеансахПользователей); + + Если ТипЗнч(ХранилищеДляШаблоновВСеансах) = Тип("ХранилищеЗначения") Тогда + ДляШаблоновОграниченияДоступа = СтруктураХранимыхПараметровШаблонов( + ЗначениеИзХранилища(ХранилищеДляШаблоновВСеансах)); + + Если ДляШаблоновОграниченияДоступа.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Иначе + ДляШаблоновОграниченияДоступа = НоваяСтруктураХранимыхПараметровШаблонов(); + КонецЕсли; + + ВерсииШаблонов = СтрСоединить(СтрРазделить( + ДляШаблоновОграниченияДоступа.ВерсииШаблонов, Символы.ПС + Символы.ВК, Ложь), Символы.ПС); + УточнитьВерсииШаблоновОграниченияДоступа(ВерсииШаблонов); + + ПараметрыШаблонов = Новый Структура(СтруктураПараметровШаблонов( + ДляШаблоновОграниченияДоступа.ПараметрыШаблонов)); + ПараметрыШаблонов.Вставить("ВерсииШаблоновОграниченияДоступа", ВерсииШаблонов); + + ОбновитьПараметрыСеансаДляШаблонов = УстановкаПараметровСеансаДляШаблонов; + Если Не УстановкаПараметровСеансаДляШаблонов + И ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + + Для Каждого КлючИЗначение Из ПараметрыШаблонов Цикл + Если ПараметрыСеанса[КлючИЗначение.Ключ] <> КлючИЗначение.Значение Тогда + ОбновитьПараметрыСеансаДляШаблонов = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ОбновитьПараметрыСеансаДляШаблонов Тогда + ПередИзменениемПараметровСеансаДляШаблонов(ПараметрыШаблонов, УстановкаПараметровСеансаДляШаблонов); + ЗаполнитьЗначенияСвойств(ПараметрыСеанса, ПараметрыШаблонов); + КонецЕсли; + КонецЕсли; + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(УстановкаПараметровСеансаДляШаблонов, Истина); + + Параметры = СеансовыеПараметрыОграниченияДоступа(ВерсияПараметров, + ДляЗаписиОбъектовИПроверкиПрав, ВерсииПараметровШаблонов, УстановкаПараметровСеансаДляШаблонов); + ПараметрыСеанса.ПараметрыОграниченияДоступа = Параметры; + +КонецПроцедуры + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Версия - Строка +// * ХешСумма - Строка +// * ДатаСоздания - Дата +// * Параметры - см. СтруктураХранимыхПараметровЗаписи +// +Функция СеансовыеПараметрыОграниченияДоступа(ВерсияПараметров, ДляЗаписиОбъектовИПроверкиПрав, + ВерсииПараметровШаблонов, УстановкаПараметровСеансаДляШаблонов) + + ПараметрыОграничения = Новый Структура; + ПараметрыОграничения.Вставить("Версия", ВерсияПараметров.Версия); + ПараметрыОграничения.Вставить("ХешСумма", ВерсияПараметров.ХешСумма); + ПараметрыОграничения.Вставить("ДатаСоздания", ВерсияПараметров.ДатаСоздания); + + Если ДляЗаписиОбъектовИПроверкиПрав = Неопределено Тогда + Параметры = Неопределено; + Иначе + ПрочитанныеПараметры = Новый Структура(ДляЗаписиОбъектовИПроверкиПрав); + ДополнительныйКонтекст = Новый Структура(ПрочитанныеПараметры.ДополнительныйКонтекст); + ДляПользователей = Новый Структура(ДополнительныйКонтекст.ДляПользователей); + ДляПользователей.ОсновныеВариантыДоступа = Новый ФиксированноеСоответствие( + ВерсииПараметровШаблонов.ДляПользователей.ОсновныеВариантыДоступа); + ДополнительныйКонтекст.ДляПользователей = Новый ФиксированнаяСтруктура(ДляПользователей); + ДляВнешнихПользователей = Новый Структура(ДополнительныйКонтекст.ДляВнешнихПользователей); + ДляВнешнихПользователей.ОсновныеВариантыДоступа = Новый ФиксированноеСоответствие( + ВерсииПараметровШаблонов.ДляВнешнихПользователей.ОсновныеВариантыДоступа); + ДополнительныйКонтекст.ДляВнешнихПользователей = Новый ФиксированнаяСтруктура(ДляВнешнихПользователей); + ПрочитанныеПараметры.ДополнительныйКонтекст = Новый ФиксированнаяСтруктура(ДополнительныйКонтекст); + Параметры = Новый ФиксированнаяСтруктура(ПрочитанныеПараметры); + КонецЕсли; + + ПараметрыОграничения.Вставить("Параметры", Параметры); + + Если УстановкаПараметровСеансаДляШаблонов + Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + ПараметрыОграничения.Вставить("ПараметрыСеансаДляШаблоновУстановлены"); + КонецЕсли; + + Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЗаписьПараметровОграниченияДоступаВТекущемСеансе") Тогда + ПараметрыОграничения.Вставить("ЗаписьПараметровОграниченияДоступаВТекущемСеансе", + ПараметрыСеанса.ПараметрыОграниченияДоступа.ЗаписьПараметровОграниченияДоступаВТекущемСеансе); + КонецЕсли; + + Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЭтоСеансФоновогоОбновленияДоступа") Тогда + ПараметрыОграничения.Вставить("ЭтоСеансФоновогоОбновленияДоступа"); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ПараметрыОграничения); + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +Процедура УточнитьВерсииШаблоновОграниченияДоступа(ВерсииШаблонов) + + Если ВерсииШаблонов = ВерсииШаблоновОграниченияДоступа() Тогда + Возврат; + КонецЕсли; + + ВерсииШаблонов = ВерсииШаблоновОграниченияДоступа() + " + |,ТребуетсяПерезапуститьСеанс,"; + +КонецПроцедуры + +// Для процедуры УстановитьВерсиюПараметров, ПроверитьДоступКОбъекту, +// ПроверитьДоступКНаборуЗаписей и функции ДоступРазрешен. +// +Процедура ОбновитьРазрешенныеНаборыВПараметрахСеанса(УстановкаПараметровСеансаДляШаблонов = Ложь, + УстановкаПараметровОграниченияДоступа = Ложь) + + Если Не УстановкаПараметровСеансаДляШаблонов + И Не ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + Возврат; + КонецЕсли; + + ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); + + Если Не УстановкаПараметровСеансаДляШаблонов + И Не УстановкаПараметровОграниченияДоступа + И ПоследняяПроверка.Дата + 5 >= ТекущаяДатаСеанса() Тогда + Возврат; + КонецЕсли; + + ПоследняяПроверка.Дата = ТекущаяДатаСеанса(); + + Состав = РазрешенныеНаборыПараметровЗапроса(); + + Если Не УстановкаПараметровСеансаДляШаблонов + И ПараметрыСеанса.РазрешенныйПользователь = Состав.РазрешенныйПользователь + И ПараметрыСеанса.РазрешенныйНаборГруппДоступа = Состав.РазрешенныйНаборГруппДоступа + И ПараметрыСеанса.РазрешенныйНаборГруппПользователей = Состав.РазрешенныйНаборГруппПользователей + И ПараметрыСеанса.РазрешенныйПустойНаборГруппДоступа = Состав.РазрешенныйПустойНаборГруппДоступа Тогда + + Возврат; + КонецЕсли; + + Состав.Вставить("ОбщиеПараметрыШаблоновОграниченияДоступа", ""); + УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса(Состав); + + ПередИзменениемПараметровСеансаДляШаблонов(Состав, УстановкаПараметровСеансаДляШаблонов); + ЗаполнитьЗначенияСвойств(ПараметрыСеанса, Состав); + +КонецПроцедуры + +// Для процедуры ОбновитьРазрешенныеНаборыВПараметрахСеанса и +// УстановитьРазрешенныеНаборыВПараметрыЗапроса. +// +// Параметры: +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - Неопределено - текущий пользователь. +// +// Возвращаемое значение: +// Структура: +// * РазрешенныйПользователь - СправочникСсылка.НаборыГруппДоступа +// * РазрешенныйНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа +// * РазрешенныйНаборГруппПользователей - СправочникСсылка.НаборыГруппДоступа +// * РазрешенныйПустойНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа +// +Функция РазрешенныеНаборыПараметровЗапроса(Знач Пользователь = Неопределено) + + ПустойНаборГруппДоступа = Справочники.НаборыГруппДоступа.ПустаяСсылка(); + + Состав = Новый Структура; + Состав.Вставить("РазрешенныйПользователь", ПустойНаборГруппДоступа); + Состав.Вставить("РазрешенныйНаборГруппДоступа", ПустойНаборГруппДоступа); + Состав.Вставить("РазрешенныйНаборГруппПользователей", ПустойНаборГруппДоступа); + Состав.Вставить("РазрешенныйПустойНаборГруппДоступа", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + Если Пользователи.ЭтоПолноправныйПользователь(Пользователь,, Ложь) Тогда + Возврат Состав; + КонецЕсли; + + Если Пользователь = Неопределено Тогда + Пользователь = Пользователи.АвторизованныйПользователь(); + КонецЕсли; + + Состав.РазрешенныйПользователь = Справочники.НаборыГруппДоступа.ПолучитьСсылку( + Пользователь.УникальныйИдентификатор()); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("РазрешенныйПользователь", Состав.РазрешенныйПользователь); + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.РазрешенныйНаборГруппДоступа КАК РазрешенныйНаборГруппДоступа, + | НаборыГруппДоступа.РазрешенныйНаборГруппПользователей КАК РазрешенныйНаборГруппПользователей + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.Ссылка = &РазрешенныйПользователь"; + + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + Состав.РазрешенныйНаборГруппДоступа = Выборка.РазрешенныйНаборГруппДоступа; + Состав.РазрешенныйНаборГруппПользователей = Выборка.РазрешенныйНаборГруппПользователей; + КонецЕсли; + + Возврат Состав; + +КонецФункции + +// Для процедуры ОбновитьРазрешенныеНаборыВПараметрахСеанса. +Процедура УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса(Состав) + + Если Не УправлениеДоступомСлужебныйПовтИсп.ТребуетсяУточнениеПланаЗапроса() Тогда + Возврат; + КонецЕсли; + + Состав.ОбщиеПараметрыШаблоновОграниченияДоступа = ";УточнитьДляВсех;" + + ОписаниеХешСуммыНастроекПрав(Состав.РазрешенныйНаборГруппДоступа) + + ОписаниеХешСуммыНастроекПрав(Состав.РазрешенныйПользователь, "^"); + +КонецПроцедуры + +// Для процедуры УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса. +Функция ОписаниеХешСуммыНастроекПрав(НаборГруппДоступа, Символ = "") + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.CRC32); + ХешированиеДанных.Добавить(ПолучитьДвоичныеДанныеИзHexСтроки(СтрЗаменить( + НаборГруппДоступа.УникальныйИдентификатор(), "-", ""))); + Остаток = ХешированиеДанных.ХешСумма; + + Результат = ""; + Для Счетчик = 1 По 32 Цикл + Целое = Цел(Остаток / 2); + Результат = ?(Остаток - Целое * 2 = 0, "", XMLСтрока(Счетчик) + Символ + ";") + Результат; + Остаток = Целое; + КонецЦикла; + + Возврат Символы.ПС + ";" + Результат; + +КонецФункции + +// Для функции ДоступРазрешен и процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. +Процедура УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос, Знач Пользователь = Неопределено) + + Если Пользователь = Неопределено Тогда + Параметры = ПараметрыСеанса; + Пользователь = Пользователи.АвторизованныйПользователь(); + Иначе + Параметры = РазрешенныеНаборыПараметровЗапроса(Пользователь); + КонецЕсли; + + Запрос.УстановитьПараметр("РазрешенныйНаборГруппДоступа", Параметры.РазрешенныйНаборГруппДоступа); + Запрос.УстановитьПараметр("РазрешенныйПустойНаборГруппДоступа", Параметры.РазрешенныйПустойНаборГруппДоступа); + Запрос.УстановитьПараметр("РазрешенныйНаборГруппПользователей", Параметры.РазрешенныйНаборГруппПользователей); + Запрос.УстановитьПараметр("РазрешенныйПользователь", Параметры.РазрешенныйПользователь); + Запрос.УстановитьПараметр("АвторизованныйПользователь", Пользователь); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +// +// Параметры: +// ОбщийКонтекст - см. ОбщийКонтекстРасчетаПараметровОграничения +// ВерсииОграниченийСписков - Соответствие +// +// Возвращаемое значение: +// Структура: +// * ДатаСоздания - Дата +// * ДляЗаписиОбъектовИПроверкиПрав - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровЗаписи +// * ДляОтчетаПоПравамДоступа - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровОтчета +// * ХешСуммаПостоянныхПараметров - Строка +// * ДляШаблоновВСеансахПользователей - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровШаблонов +// * ДляШаблоновВСеансахВнешнихПользователей - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровШаблонов +// * ВерсииПараметровШаблонов - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхВерсийПараметровШаблонов +// * ХешСуммаПараметровШаблонов - Строка - заполняется при записи после обновления +// параметра ВерсииПараметровШаблонов и заполнения свойства СпискиСОграничениемПоПолям +// параметров ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей. +// * ХешСумма - Строка - заполняется при записи, +// вычисляется из хеш-сумм ХешСуммаПостоянныхПараметров и ХешСуммаПараметровШаблонов. +// +Функция ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст, ВерсииОграниченийСписков = Неопределено) + + ДатаСоздания = ТекущаяДатаСеанса(); + + Если ОбщийКонтекст = Неопределено Тогда + ОбновитьПовторноИспользуемыеЗначения(); + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); + + ИначеЕсли ОбщийКонтекст.Свойство("СпециальноеПолноеИмя") Тогда + СпециальноеПолноеИмя = ОбщийКонтекст.СпециальноеПолноеИмя; + СпециальноеОписаниеОграничения = ОбщийКонтекст.СпециальноеОписаниеОграничения; + КонецЕсли; + + ДополнительныйКонтекстДляПользователей = НовыйДополнительныйКонтекст(); + ДополнительныйКонтекстДляВнешнихПользователей = НовыйДополнительныйКонтекст(); + + ОписаниеОграничений = Новый Соответствие; + ПолныеИменаСписков = Новый Массив; + Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + ПолныеИменаСписков.Добавить(ПолноеИмя); + Если ПолноеИмя = СпециальноеПолноеИмя Тогда + ОписаниеОграничения = СпециальноеОписаниеОграничения; + Иначе + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); + КонецЕсли; + ОписаниеОграничений.Вставить(ПолноеИмя, ОписаниеОграничения); + + ДобавитьДополнительныйКонтекст(ПолноеИмя, + ДополнительныйКонтекстДляПользователей, ОписаниеОграничения, Ложь); + + ДобавитьДополнительныйКонтекст(ПолноеИмя, + ДополнительныйКонтекстДляВнешнихПользователей, ОписаниеОграничения, Истина); + КонецЦикла; + + СпискиСДатой = Новый Соответствие; + ИдентификаторыСписков = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИменаСписков); + ВерсияТекстовОграниченияДоступа = + РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(ОписаниеОграничений); + + ВидыОграниченийПравДляПользователей = Новый Соответствие; + ВидыОграниченийПравДляВнешнихПользователей = Новый Соответствие; + + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + СтрокиВерсийСписков = НовыеСтрокиВерсийСписков(); + СтрокиВерсииХранимыхПараметров = Новый Структура; + СтрокиВерсииХранимыхПараметров.Вставить("ВсеВерсииСтрокой", ""); + СтрокиВерсииХранимыхПараметров.Вставить("ВидыОграниченийПравДляПользователейСтрокой", ""); + СтрокиВерсииХранимыхПараметров.Вставить("ВидыОграниченийПравДляВнешнихПользователейСтрокой", ""); + СтрокиВерсииХранимыхПараметров.Вставить("СтрокиВерсийСписков", СтрокиВерсийСписков); + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров = СтрокиВерсииХранимыхПараметров; + КонецЕсли; + + Если ОбщийКонтекст.Свойство("ИнформацияДляЖурнала") Тогда + СпискиБезВнедрения = Новый Структура; + СпискиБезВнедрения.Вставить("ОбъектыПредупреждения", Новый Соответствие); + СпискиБезВнедрения.Вставить("ОбъектыОшибки", Новый Соответствие); + СпискиБезВнедрения.Вставить("РегистрыПредупреждения", Новый Массив); + Иначе + СпискиБезВнедрения = Неопределено; + КонецЕсли; + + // Заполнение для пользователей. + КонтекстДляПользователей = Новый Структура; + КонтекстДляПользователей.Вставить("ДляВнешнихПользователей", Ложь); + КонтекстДляПользователей.Вставить("ДатаСоздания", ДатаСоздания); + КонтекстДляПользователей.Вставить("ОбщийКонтекст", ОбщийКонтекст); + КонтекстДляПользователей.Вставить("ДополнительныйКонтекст", ДополнительныйКонтекстДляПользователей); + КонтекстДляПользователей.Вставить("ВедущиеСписки", Новый Соответствие); + КонтекстДляПользователей.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + КонтекстДляПользователей.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); + КонтекстДляПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + КонтекстДляПользователей.Вставить("СпискиСДатой", СпискиСДатой); + КонтекстДляПользователей.Вставить("ИдентификаторыСписков", ИдентификаторыСписков); + КонтекстДляПользователей.Вставить("ВсеВидыОграниченийПрав", ВидыОграниченийПравДляПользователей); + КонтекстДляПользователей.Вставить("ВедущиеРоли", Новый Соответствие); + КонтекстДляПользователей.Вставить("СпискиБезВнедрения", СпискиБезВнедрения); + + ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(КонтекстДляПользователей); + + // Заполнение для внешних пользователей. + КонтекстДляВнешнихПользователей = Новый Структура; + КонтекстДляВнешнихПользователей.Вставить("ДляВнешнихПользователей", Истина); + КонтекстДляВнешнихПользователей.Вставить("ДатаСоздания", ДатаСоздания); + КонтекстДляВнешнихПользователей.Вставить("ОбщийКонтекст", ОбщийКонтекст); + КонтекстДляВнешнихПользователей.Вставить("ДополнительныйКонтекст", ДополнительныйКонтекстДляВнешнихПользователей); + КонтекстДляВнешнихПользователей.Вставить("ВедущиеСписки", Новый Соответствие); + КонтекстДляВнешнихПользователей.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + КонтекстДляВнешнихПользователей.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); + КонтекстДляВнешнихПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + КонтекстДляВнешнихПользователей.Вставить("СпискиСДатой", СпискиСДатой); + КонтекстДляВнешнихПользователей.Вставить("ИдентификаторыСписков", ИдентификаторыСписков); + КонтекстДляВнешнихПользователей.Вставить("ВсеВидыОграниченийПрав", ВидыОграниченийПравДляВнешнихПользователей); + КонтекстДляВнешнихПользователей.Вставить("ВедущиеРоли", Новый Соответствие); + КонтекстДляВнешнихПользователей.Вставить("СпискиБезВнедрения", СпискиБезВнедрения); + + ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(КонтекстДляВнешнихПользователей); + + Если ОбщийКонтекст.Свойство("ИнформацияДляЖурнала") Тогда + ЗаполнитьНесоответствиеПараметровДляЖурнала(СпискиБезВнедрения, ОбщийКонтекст.ИнформацияДляЖурнала); + ОбщийКонтекст.ИнформацияДляЖурнала.ВерсияТекстовОграниченияДоступа = ВерсияТекстовОграниченияДоступа; + КонецЕсли; + + // Заполнение общей и отдельной частей ведущих списков для пользователей и внешних пользователей. + ВедущиеСписки = Новый Соответствие; + Для Каждого ОписаниеВедущихСписков Из КонтекстДляПользователей.ВедущиеСписки Цикл + ДобавитьВедущиеСписки(ВедущиеСписки, + "ДляПользователей", ОписаниеВедущихСписков.Ключ, ОписаниеВедущихСписков.Значение); + КонецЦикла; + Для Каждого ОписаниеВедущихСписков Из КонтекстДляВнешнихПользователей.ВедущиеСписки Цикл + ДобавитьВедущиеСписки(ВедущиеСписки, + "ДляВнешнихПользователей", ОписаниеВедущихСписков.Ключ, ОписаниеВедущихСписков.Значение); + КонецЦикла; + Свойства = ВедущийСписокПоЗначениямПолей(); + Для Каждого ВедущийСписок Из ВедущиеСписки Цикл + Свойства = ВедущийСписок.Значение; + Если Свойства.ПоЗначениямПолей <> Неопределено Тогда + ПоЗначениямПолей = Свойства.ПоЗначениямПолей; + Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда + ТабличныеЧасти = Новый Массив; + Для Каждого ОписаниеТабличнойЧасти Из ПоЗначениямПолей.ТабличныеЧасти Цикл + ТабличныеЧасти.Добавить(ОписаниеТабличнойЧасти.Значение); + КонецЦикла; + ПоЗначениямПолей.ТабличныеЧасти = ТабличныеЧасти; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + // Заполнение ведущих ролей для пользователей и внешних пользователей. + ВедущиеРоли = Новый Соответствие; + ДобавитьВедущиеРоли(ВедущиеРоли, "ДляПользователей", КонтекстДляПользователей); + ДобавитьВедущиеРоли(ВедущиеРоли, "ДляВнешнихПользователей", КонтекстДляВнешнихПользователей); + + // Расчет версий ограничения доступа. + ВерсииОграниченийСписков = Новый Соответствие; + Версии = Новый СписокЗначений; + Версии.Добавить(ВерсияСтруктурыКэша()); + Для Каждого ОписаниеВерсии Из КонтекстДляПользователей.ВерсииОграниченийСписков Цикл + ОбщаяВерсия = ОбщаяВерсия(ОбщийКонтекст, ОписаниеВерсии.Ключ, ОписаниеВерсии.Значение, + КонтекстДляВнешнихПользователей.ВерсииОграниченийСписков.Получить(ОписаниеВерсии.Ключ)); + ВерсииОграниченийСписков.Вставить(ОписаниеВерсии.Ключ, ОбщаяВерсия); + Версии.Добавить(ОбщаяВерсия, ПолучитьHexСтрокуИзДвоичныхДанных( + ПолучитьДвоичныеДанныеИзСтроки(Строка(ОбщаяВерсия)))); + КонецЦикла; + Версии.СортироватьПоПредставлению(); + ВерсииСтрокой = СтрСоединить(Версии.ВыгрузитьЗначения(), Символы.ПС); + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + ХешированиеДанных.Добавить(ВерсииСтрокой); + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВсеВерсииСтрокой = ВерсииСтрокой; + КонецЕсли; + + // Подготовка дополнительного контекста для расчета параметров ограничения отдельного списка. + ДляПользователей = НовыйХранимыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДляПользователей, КонтекстДляПользователей.ДополнительныйКонтекст); + ДляВнешнихПользователей = НовыйХранимыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДляВнешнихПользователей, КонтекстДляВнешнихПользователей.ДополнительныйКонтекст); + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("ДляПользователей", ДляПользователей); + ДополнительныйКонтекст.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + + ПараметрыЗаписи = НоваяСтруктураХранимыхПараметровЗаписи(); + ПараметрыЗаписи.ВерсииОграниченийСписков = ВерсииОграниченийСписков; + ПараметрыЗаписи.ВедущиеСписки = ВедущиеСписки; + ПараметрыЗаписи.ДополнительныйКонтекст = ДополнительныйКонтекст; + ПараметрыЗаписи.СпискиСДатой = СпискиСДатой; + ПараметрыЗаписи.ВедущиеРоли = ВедущиеРоли; + ПараметрыЗаписи.ИспользуемыеТипыЗначений = Новый ХранилищеЗначения( + Новый Структура("ХешСумма", ОбщийКонтекст.ИспользуемыеТипыЗначений.ХешСумма)); + ПараметрыЗаписи.ВнешниеПользователиВключены = ОбщийКонтекст.ВнешниеПользователиВключены; + ПараметрыЗаписи.ОграничениеДоступаВключено = ОбщийКонтекст.ОграничениеДоступаВключено; + ПараметрыЗаписи.ВерсияТекстовОграниченияДоступа = ВерсияТекстовОграниченияДоступа; + ХешированиеДанных.Добавить(ОбщийКонтекст.ИспользуемыеТипыЗначений.ХешСумма); + + ХранимыеПараметры = Новый Структура; + + ХранимыеПараметрыШаблоновДляПользователей = НоваяСтруктураХранимыхПараметровШаблонов(); + ХранимыеПараметрыШаблоновДляПользователей.ПараметрыШаблонов = КонтекстДляПользователей.ПараметрыШаблонов; + ХранимыеПараметры.Вставить("ДляШаблоновВСеансахПользователей", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыШаблоновДляПользователей))); + + ХранимыеПараметрыШаблоновДляВнешнихПользователей = НоваяСтруктураХранимыхПараметровШаблонов(); + ХранимыеПараметрыШаблоновДляВнешнихПользователей.ПараметрыШаблонов = КонтекстДляВнешнихПользователей.ПараметрыШаблонов; + ХранимыеПараметры.Вставить("ДляШаблоновВСеансахВнешнихПользователей", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыШаблоновДляВнешнихПользователей))); + + ХранимыеВерсииПараметровШаблонов = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + ХранимыеВерсииПараметровШаблонов.ДляПользователей.ВерсииПараметровШаблонов = + КонтекстДляПользователей.ВерсииПараметровШаблонов; + ХранимыеВерсииПараметровШаблонов.ДляВнешнихПользователей.ВерсииПараметровШаблонов = + КонтекстДляВнешнихПользователей.ВерсииПараметровШаблонов; + ХранимыеПараметры.Вставить("ВерсииПараметровШаблонов", + Новый ХранилищеЗначения(ХранимыеВерсииПараметровШаблонов)); + + ХранимыеПараметры.Вставить("ДляЗаписиОбъектовИПроверкиПрав", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ПараметрыЗаписи))); + + ХранимыеПараметрыОтчета = НоваяСтруктураХранимыхПараметровОтчета(); + ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей = + ВидыОграниченийПравСтрокой(ВидыОграниченийПравДляПользователей); + ХешированиеДанных.Добавить(ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей); + ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей = + ВидыОграниченийПравСтрокой(ВидыОграниченийПравДляВнешнихПользователей); + ХешированиеДанных.Добавить(ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей); + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВидыОграниченийПравДляПользователейСтрокой + = ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей; + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВидыОграниченийПравДляВнешнихПользователейСтрокой + = ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей; + КонецЕсли; + + ХранимыеПараметры.Вставить("ДляОтчетаПоПравамДоступа", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыОтчета))); + + ХранимыеПараметры.Вставить("ХешСуммаПостоянныхПараметров", Base64Строка(ХешированиеДанных.ХешСумма)); + ХранимыеПараметры.Вставить("ДатаСоздания", ДатаСоздания); + + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + СтрокиВерсийСписков.Сортировать("Список, ДляВнешнихПользователей"); + КонецЕсли; + + Возврат ХранимыеПараметры; + +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Список - Строка +// * ДляВнешнихПользователей - Булево +// * Версия - Строка +// * СтрокаВерсии - Строка +// +Функция НовыеСтрокиВерсийСписков() + + СтрокиВерсийСписков = Новый ТаблицаЗначений; + СтрокиВерсийСписков.Колонки.Добавить("Список", Новый ОписаниеТипов("Строка")); + СтрокиВерсийСписков.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + СтрокиВерсийСписков.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка")); + СтрокиВерсийСписков.Колонки.Добавить("СтрокаВерсии", Новый ОписаниеТипов("Строка")); + + Возврат СтрокиВерсийСписков; + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ОписанияОграничений - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СокращенноеОписаниеОграничения +// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * СпискиСОграничениемПоВладельцу - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - значение ПоВладельцу, кроме Неопределено. +// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// +Функция НовыйДополнительныйКонтекст() + + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СвойстваОграниченияСписков", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОграничениемПоВладельцу", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничением", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничениемЧтения", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей", Неопределено); + ДополнительныйКонтекст.Вставить("ОсновныеВариантыДоступа", Новый Соответствие); + + Возврат ДополнительныйКонтекст; + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// +Функция НовыйХранимыйДополнительныйКонтекст() + + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("СвойстваОграниченияСписков", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничением", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничениемЧтения", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей", Неопределено); + ДополнительныйКонтекст.Вставить("ОсновныеВариантыДоступа", Новый Соответствие); + + Возврат ДополнительныйКонтекст; + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, + ОписаниеОграничения, ДляВнешнихПользователей) + + Если ДляВнешнихПользователей Тогда + Текст = ОписаниеОграничения.ТекстДляВнешнихПользователей; + ПоВладельцу = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей; + Иначе + Текст = ОписаниеОграничения.Текст; + ПоВладельцу = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступа; + КонецЕсли; + ВМодулеМенеджера = ОписаниеОграничения.ТекстВМодулеМенеджера; + + СокращенноеОписаниеОграничения = СокращенноеОписаниеОграничения(); + СокращенноеОписаниеОграничения.Вставить("Текст", Текст); + СокращенноеОписаниеОграничения.Вставить("ВМодулеМенеджера", ВМодулеМенеджера); + + ДополнительныйКонтекст.ОписанияОграничений.Вставить(ПолноеИмя, СокращенноеОписаниеОграничения); + + Если ПоВладельцу <> Неопределено Тогда + ДополнительныйКонтекст.СпискиСОграничениемПоВладельцу.Вставить(ПолноеИмя, ПоВладельцу); + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Текст - Строка +// * ВМодулеМенеджера - Булево +// +Функция СокращенноеОписаниеОграничения() + + Возврат Новый Структура; + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(Контекст) + + // Подготовка параметров с учетом зависимостей только по ключам доступа. + ТаблицаСвойств = СвойстваСписковДляРасчетаХранимыхПараметров(); + ТаблицаСвойств = Новый ТаблицаЗначений; + ТаблицаСвойств.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка")); + ТаблицаСвойств.Колонки.Добавить("Зависимый", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("Ведущие", Новый ОписаниеТипов("Массив")); + ТаблицаСвойств.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число")); + ТаблицаСвойств.Колонки.Добавить("Ведущий", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("Зависимые", Новый ОписаниеТипов("Массив")); + ТаблицаСвойств.Колонки.Добавить("Параметры", Новый ОписаниеТипов("Структура")); + ТаблицаСвойств.Колонки.Добавить("Обработан", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ОграничениеПоВладельцуВозможно", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ОграничениеПоВладельцуВключено", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("КлючиДоступаПользователей", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ЗависимыеСпискиБезЗаписиКлючейДоступа", Новый ОписаниеТипов("Соответствие")); + ТаблицаСвойств.Колонки.Добавить("КлючиДоступаПользователейИГруппДоступа", Новый ОписаниеТипов("Булево")); + + СпискиСОграничением = Новый Соответствие(Контекст.ОбщийКонтекст.СпискиСОграничением); + СпискиСОтключеннымОграничением = Новый Соответствие; + СпискиСОтключеннымОграничениемЧтения = Новый Соответствие; + + Для Каждого ОписаниеСписка Из СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + + Если ТипЗнч(ОписаниеСписка.Значение) = Тип("Булево") Тогда + Свойства = ТаблицаСвойств.Добавить(); + Свойства.ПолноеИмя = ПолноеИмя; + СпискиСОграничением.Вставить(ПолноеИмя, Свойства); + Параметры = ПараметрыОграниченияДляВидаПользователей(ПолноеИмя, Контекст); + Свойства.Параметры = Параметры; + Иначе + Свойства = ОписаниеСписка.Значение; // См. СвойстваСписковДляРасчетаХранимыхПараметров + Параметры = Свойства.Параметры; + КонецЕсли; + + Если Параметры.ОграничениеЧтенияОтключено Тогда + СпискиСОтключеннымОграничениемЧтения.Вставить(ПолноеИмя, Истина); + КонецЕсли; + Если Параметры.ОграничениеОтключено Тогда + СпискиСОтключеннымОграничением.Вставить(ПолноеИмя, Истина); + КонецЕсли; + Если Параметры.ЕстьОграничениеПоПользователям Тогда + Свойства.КлючиДоступаПользователей = Истина; + УстановитьСвойствоОграничения(ПолноеИмя, "РассчитыватьПраваПользователей", Истина, Контекст); + КонецЕсли; + Если Параметры.ПолеВладельца <> Неопределено Тогда + УстановитьСвойствоОграничения(ПолноеИмя, "ПолеВладельца", Параметры.ПолеВладельца, Контекст); + КонецЕсли; + + ВедущиеСписки = Параметры.ВедущиеСписки; + Если ВедущиеСписки.ПоКлючамДоступа.Количество() > 0 Тогда + Свойства.Зависимый = Истина; + Для Каждого КлючИЗначение Из ВедущиеСписки.ПоКлючамДоступа Цикл + ВедущийСписок = КлючИЗначение.Ключ; + Свойства.Ведущие.Добавить(ВедущийСписок); + СвойстваВедущего = СпискиСОграничением.Получить(ВедущийСписок); + Если СвойстваВедущего = Неопределено Или ТипЗнч(СвойстваВедущего) = Тип("Булево") Тогда + СвойстваВедущего = ТаблицаСвойств.Добавить(); + СвойстваВедущего.ПолноеИмя = ВедущийСписок; + СпискиСОграничением.Вставить(ВедущийСписок, СвойстваВедущего); + ПараметрыВедущего = ПараметрыОграниченияДляВидаПользователей(ВедущийСписок, Контекст); + СвойстваВедущего.Параметры = ПараметрыВедущего; + Если ПараметрыВедущего.ОграничениеЧтенияОтключено Тогда + СпискиСОтключеннымОграничениемЧтения.Вставить(ВедущийСписок, Истина); + КонецЕсли; + Если ПараметрыВедущего.ОграничениеОтключено Тогда + СпискиСОтключеннымОграничением.Вставить(ВедущийСписок, Истина); + КонецЕсли; + Если ПараметрыВедущего.ЕстьОграничениеПоПользователям Тогда + СвойстваВедущего.КлючиДоступаПользователей = Истина; + УстановитьСвойствоОграничения(ВедущийСписок, + "РассчитыватьПраваПользователей", Истина, Контекст); + КонецЕсли; + Если ПараметрыВедущего.ПолеВладельца <> Неопределено Тогда + УстановитьСвойствоОграничения(ВедущийСписок, + "ПолеВладельца", ПараметрыВедущего.ПолеВладельца, Контекст); + КонецЕсли; + КонецЕсли; + СвойстваВедущего.Ведущий = Истина; + СвойстваВедущего.Зависимые.Добавить(ПолноеИмя); + КонецЦикла; + КонецЕсли; + КонецЦикла; + + МаксимальныйУровень = 0; + Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Зависимый, Ведущий", Ложь, Истина)); + Для Каждого Строка Из Строки Цикл + УстановитьУровеньЗависимыхСписков(Строка, СпискиСОграничением, Новый Массив, МаксимальныйУровень); + КонецЦикла; + // Обработка зависимых списков, ведущих для самих себя (зацикленных на себя). + Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Обработан", Ложь)); + Для Каждого Строка Из Строки Цикл + УстановитьУровеньЗависимыхСписков(Строка, СпискиСОграничением, Новый Массив, МаксимальныйУровень); + КонецЦикла; + + Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Зависимый, Ведущий", Истина, Ложь)); + Для Каждого Строка Из Строки Цикл + НастроитьОптимизациюПоПолюВладельцу(Строка, СпискиСОграничением, Контекст); + КонецЦикла; + + // Сокращение зависимостей по ключам доступа зависимых объектов. + СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + Отбор = Новый Структура("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Истина); + Строки = ТаблицаСвойств.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Вставить(Строка.ПолноеИмя, Истина); + КонецЦикла; + ДополнительныйКонтекст = Контекст.ДополнительныйКонтекст; + ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения = СпискиСОтключеннымОграничениемЧтения; + ДополнительныйКонтекст.СпискиСОтключеннымОграничением = СпискиСОтключеннымОграничением; + ДополнительныйКонтекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей + = СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей; + + Отбор = Новый Структура("Уровень, ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", 0, Истина); + Строки = ТаблицаСвойств.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + Строка.Параметры = ПараметрыОграниченияДляВидаПользователей(Строка.ПолноеИмя, Контекст); + КонецЦикла; + + СвойстваСписковПоУровням = Новый Массив; + Для Уровень = 1 По МаксимальныйУровень Цикл + СвойстваСписков = ТаблицаСвойств.НайтиСтроки(Новый Структура("Уровень", Уровень)); + СвойстваСписковПоУровням.Добавить(СвойстваСписков); + КонецЦикла; + + ОбщийКонтекстСпискиСОграничением = Контекст.ОбщийКонтекст.СпискиСОграничением; + + Для Каждого СвойстваСписков Из СвойстваСписковПоУровням Цикл + Для Каждого СвойстваСписка Из СвойстваСписков Цикл + СвойстваСписка = СвойстваСписка; // См. СвойстваСписковДляРасчетаХранимыхПараметров + + ВсеВедущиеСпискиСОграничением = Истина; + ИзмененоСвойствоРассчитыватьПраваПользователей = Ложь; + КлючиДоступаПользователей = Ложь; + КлючиДоступаГруппДоступа = Ложь; + + Для Каждого Ведущий Из СвойстваСписка.Ведущие Цикл + СвойстваВедущего = СпискиСОграничением.Получить(Ведущий); + Если СвойстваВедущего.КлючиДоступаПользователей Тогда + КлючиДоступаПользователей = Истина; + Иначе + КлючиДоступаГруппДоступа = Истина; + КонецЕсли; + Если ОбщийКонтекстСпискиСОграничением.Получить(Ведущий) = Неопределено + Или СпискиСОтключеннымОграничением.Получить(Ведущий) <> Неопределено Тогда + ВсеВедущиеСпискиСОграничением = Ложь; + КонецЕсли; + КонецЦикла; + + Если КлючиДоступаПользователей Тогда + Если Не СвойстваСписка.ОграничениеПоВладельцуВключено + И Не СвойстваСписка.КлючиДоступаПользователей Тогда + + ИзмененоСвойствоРассчитыватьПраваПользователей = Истина; + УстановитьСвойствоОграничения(СвойстваСписка.ПолноеИмя, + "РассчитыватьПраваПользователей", Истина, Контекст); + КонецЕсли; + СвойстваСписка.КлючиДоступаПользователей = Истина; + Если СвойстваСписка.ОграничениеПоВладельцуВключено + И КлючиДоступаГруппДоступа Тогда + СвойстваСписка.КлючиДоступаПользователейИГруппДоступа = Истина; + КонецЕсли; + КонецЕсли; + + Если СвойстваСписка.ОграничениеПоВладельцуВключено + И ВсеВедущиеСпискиСОграничением + И Не ИзмененоСвойствоРассчитыватьПраваПользователей + И СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(СвойстваСписка.ПолноеИмя) = Неопределено + Тогда + Продолжить; + КонецЕсли; + + СвойстваСписка.Параметры = + ПараметрыОграниченияДляВидаПользователей(СвойстваСписка.ПолноеИмя, Контекст); + КонецЦикла; + КонецЦикла; + + // Заполнение хранимых свойств списков. + Для Каждого СвойстваСписка Из ТаблицаСвойств Цикл + ПолноеИмя = СвойстваСписка.ПолноеИмя; + + Если СвойстваСписка.Параметры.ДоступЗапрещен Тогда + УстановитьСвойствоОграничения(ПолноеИмя, "ДоступЗапрещен", Истина, Контекст); + КонецЕсли; + Если ЗначениеЗаполнено(СвойстваСписка.Параметры.ИмяОтдельногоРегистраКлючей) Тогда + УстановитьСвойствоОграничения(ПолноеИмя, + "ИмяОтдельногоРегистраКлючей", СвойстваСписка.Параметры.ИмяОтдельногоРегистраКлючей, Контекст); + КонецЕсли; + Если ЗначениеЗаполнено(СвойстваСписка.Параметры.ОпорныеПоля) Тогда + ОпорныеПоля = Новый Структура("Все, ТипыВсех, Используемые"); + ЗаполнитьЗначенияСвойств(ОпорныеПоля, СвойстваСписка.Параметры.ОпорныеПоля); + УстановитьСвойствоОграничения(ПолноеИмя, "ОпорныеПоля", ОпорныеПоля, Контекст); + КонецЕсли; + Если СвойстваСписка.КлючиДоступаПользователейИГруппДоступа Тогда + УстановитьСвойствоОграничения(ПолноеИмя, + "ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа", Истина, Контекст); + ИначеЕсли СвойстваСписка.КлючиДоступаПользователей Тогда + УстановитьСвойствоОграничения(ПолноеИмя, + "ОграничениеВШаблонахЧерезКлючиДоступаПользователей", Истина, Контекст); + КонецЕсли; + Если СвойстваСписка.Параметры.ОграничениеЧтенияОтключено Тогда + СпискиСОтключеннымОграничениемЧтения.Вставить(ПолноеИмя, Истина); + КонецЕсли; + Если СвойстваСписка.Параметры.ОграничениеОтключено Тогда + СпискиСОтключеннымОграничением.Вставить(ПолноеИмя, Истина); + КонецЕсли; + УстановитьСвойствоОграничения(ПолноеИмя, "ИспользуемыеТипыЗначенийДоступа", + Новый ХранилищеЗначения(СвойстваСписка.Параметры.ИспользуемыеТипыЗначенийДоступа), Контекст); + + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, СвойстваСписка.Параметры.Версия); + Если Контекст.ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + СтрокиВерсийСписков = Контекст.ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.СтрокиВерсийСписков; // См. НовыеСтрокиВерсийСписков + НоваяСтрока = СтрокиВерсийСписков.Добавить(); + НоваяСтрока.Список = СвойстваСписка.ПолноеИмя; + НоваяСтрока.ДляВнешнихПользователей = Контекст.ДляВнешнихПользователей; + НоваяСтрока.Версия = СвойстваСписка.Параметры.Версия; + НоваяСтрока.СтрокаВерсии = СвойстваСписка.Параметры.Контекст.СтрокаСвойствВерсии; + КонецЕсли; + + ВедущиеСписки = СвойстваСписка.Параметры.ВедущиеСписки; + + Если ВедущиеСписки.ПоЗначениямПолей.Количество() > 0 + Или ВедущиеСписки.ПоКлючамДоступа.Количество() > 0 + Или ВедущиеСписки.ПоЗначениямСГруппами.Количество() > 0 Тогда + + Контекст.ВедущиеСписки.Вставить(ПолноеИмя, ВедущиеСписки); + КонецЕсли; + + НастроитьПараметрыШаблонов(СвойстваСписка, Контекст); + + Если СвойстваСписка.Параметры.СписокСДатой Тогда + Контекст.СпискиСДатой.Вставить(СвойстваСписка.ПолноеИмя, Истина); + КонецЕсли; + + Для Каждого КлючИЗначение Из СвойстваСписка.Параметры.ВсеВидыОграниченийПрав Цикл + Контекст.ВсеВидыОграниченийПрав.Вставить(СвойстваСписка.ПолноеИмя + "." + КлючИЗначение.Ключ, Истина); + КонецЦикла; + + Если ЗначениеЗаполнено(СвойстваСписка.Параметры.Контекст.ВедущиеРоли) Тогда + Для Каждого КлючИЗначение Из СвойстваСписка.Параметры.Контекст.ВедущиеРоли Цикл + ЗависимыеСписки = Контекст.ВедущиеРоли.Получить(КлючИЗначение.Ключ); + Если ЗависимыеСписки = Неопределено Тогда + ЗависимыеСписки = Новый Соответствие; + Контекст.ВедущиеРоли.Вставить(КлючИЗначение.Ключ, ЗависимыеСписки); + КонецЕсли; + ЗависимыеСписки.Вставить(СвойстваСписка.ПолноеИмя, Истина); + КонецЦикла; + КонецЕсли; + + ЗаполнитьСпискиБезВнедрения(Контекст.СпискиБезВнедрения, СвойстваСписка); + КонецЦикла; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ПолноеИмя - Строка +// * Зависимый - Булево +// * Ведущие - Массив +// * Уровень - Число +// * Ведущий - Булево +// * Параметры - Структура +// * Обработан - Булево +// * ОграничениеПоВладельцуВозможно - Булево +// * ОграничениеПоВладельцуВключено - Булево +// * КлючиДоступаПользователей - Булево +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево +// * КлючиДоступаПользователейИГруппДоступа - Булево +// +Функция СвойстваСписковДляРасчетаХранимыхПараметров() + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ХранимыеПараметрыОграниченияДляВидаПользователей. +// +// Возвращаемое значение: +// см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция ПараметрыОграниченияДляВидаПользователей(ПолноеИмя, Контекст) + + ОписаниеОграничения = Контекст.ДополнительныйКонтекст.ОписанияОграничений.Получить(ПолноеИмя); + + Если ОписаниеОграничения = Неопределено Тогда + СтруктураОграничения = Неопределено; + Иначе + СтруктураОграничения = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.Текст, ОписаниеОграничения.ВМодулеМенеджера, Контекст.ДляВнешнихПользователей); + КонецЕсли; + + Возврат ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграничения, + Контекст.ДляВнешнихПользователей, + Контекст.ОбщийКонтекст, + Контекст.ДополнительныйКонтекст); + +КонецФункции + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура УстановитьУровеньЗависимыхСписков(СвойстваВедущегоСписка, СвойстваСписков, ПредыдущиеВедущие, + МаксимальныйУровень) + + ПредыдущиеВедущие.Добавить(СвойстваВедущегоСписка.ПолноеИмя); + + Для Каждого ЗависимыйСписок Из СвойстваВедущегоСписка.Зависимые Цикл + Если ПредыдущиеВедущие.Найти(ЗависимыйСписок) <> Неопределено Тогда + УчастникиЦикла = ""; + Индекс = ПредыдущиеВедущие.Количество() - 1; + Пока Истина Цикл + УчастникиЦикла = "- " + ПредыдущиеВедущие[Индекс] + Символы.ПС + УчастникиЦикла; + Если ПредыдущиеВедущие[Индекс] = ЗависимыйСписок Тогда + Прервать; + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + УчастникиЦикла = УчастникиЦикла + "(!) " + ЗависимыйСписок; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ограничения доступа, заполненные в процедурах %1 + |модулей менеджеров или общем модуле %2, + |содержат недопустимую циклическую зависимость при использовании функции + |%3 или %4 в одном или нескольких + |списках-участниках цикла: + |%5'"), + "ПриЗаполненииОграниченияДоступа", + "УправлениеДоступомПереопределяемый", + "ЧтениеОбъектаРазрешено", + "ИзменениеОбъектаРазрешено", + УчастникиЦикла); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + СвойстваЗависимогоСписка = СвойстваСписков.Получить(ЗависимыйСписок); + Если СвойстваЗависимогоСписка.Уровень < СвойстваВедущегоСписка.Уровень + 1 Тогда + СвойстваЗависимогоСписка.Уровень = СвойстваВедущегоСписка.Уровень + 1; + Если МаксимальныйУровень < СвойстваЗависимогоСписка.Уровень Тогда + МаксимальныйУровень = СвойстваЗависимогоСписка.Уровень; + КонецЕсли; + КонецЕсли; + Если Не СвойстваЗависимогоСписка.Ведущий Тогда + СвойстваЗависимогоСписка.Обработан = Истина; + Продолжить; + КонецЕсли; + УстановитьУровеньЗависимыхСписков(СвойстваЗависимогоСписка, СвойстваСписков, ПредыдущиеВедущие, МаксимальныйУровень); + КонецЦикла; + + ПредыдущиеВедущие.Удалить(ПредыдущиеВедущие.Количество() - 1); + СвойстваВедущегоСписка.Обработан = Истина; + +КонецПроцедуры + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура НастроитьОптимизациюПоПолюВладельцу(СвойстваЗависимогоСписка, СвойстваСписков, Контекст) + + СвойстваЗависимогоСписка.ОграничениеПоВладельцуВозможно = + СвойстваЗависимогоСписка.Параметры.ПолеВладельца <> Неопределено; + + СвойстваЗависимогоСписка.ОграничениеПоВладельцуВключено = + СвойстваЗависимогоСписка.ОграничениеПоВладельцуВозможно + И Не СвойстваЗависимогоСписка.Параметры.ПолеВладельца.Отключено; + + ЗависимыйСписокСОптимизацией = СвойстваЗависимогоСписка.ОграничениеПоВладельцуВключено; + + Для Каждого ВедущийСписок Из СвойстваЗависимогоСписка.Ведущие Цикл + СвойстваВедущегоСписка = СвойстваСписков.Получить(ВедущийСписок); // См. СвойстваСписковДляРасчетаХранимыхПараметров + Если СвойстваВедущегоСписка.Параметры.ДоступЗапрещен Тогда + Продолжить; + КонецЕсли; + Если Не СвойстваВедущегоСписка.Зависимый Тогда + Если ЗависимыйСписокСОптимизацией Тогда + УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка); + КонецЕсли; + Продолжить; + КонецЕсли; + Если ЗависимыйСписокСОптимизацией Тогда + Если СвойстваВедущегоСписка.Параметры.ПолеВладельца <> Неопределено + И Не СвойстваВедущегоСписка.Параметры.ПолеВладельца.Отключено Тогда + Если СвойстваВедущегоСписка.Параметры.ТребуетсяОграничениеПоВладельцу Тогда + ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, + "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", но такая + |оптимизация невозможна, так как она требуется для зависимого списка ""%2"".'"), + ИмяПризнакаОптимизации, + СвойстваЗависимогоСписка.ПолноеИмя); + КонтекстОшибки = Новый Структура("СпискиСОграничением, ОписанияОграничений"); + КонтекстОшибки.Вставить("Список", СвойстваВедущегоСписка.ПолноеИмя); + КонтекстОшибки.Вставить("ОписанияОграничений", Контекст.ДополнительныйКонтекст.ОписанияОграничений); + КонтекстОшибки.Вставить("ДляВнешнихПользователей", Контекст.ДляВнешнихПользователей); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, КонтекстОшибки); + ВызватьИсключение ТекстОшибки; + Иначе + СвойстваВедущегоСписка.ОграничениеПоВладельцуВключено = Ложь; + СвойстваВедущегоСписка.Параметры.ПолеВладельца.Отключено = Истина; + УстановитьСвойствоОграничения(СвойстваВедущегоСписка.ПолноеИмя, + "ПолеВладельца", СвойстваВедущегоСписка.Параметры.ПолеВладельца, Контекст); + КонецЕсли; + КонецЕсли; + УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка); + КонецЕсли; + НастроитьОптимизациюПоПолюВладельцу(СвойстваВедущегоСписка, СвойстваСписков, Контекст); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры НастроитьОптимизациюПоПолюВладельцу. +Процедура УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка) + + СвойстваВедущегоСписка.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина; + СвойстваВедущегоСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа.Вставить(СвойстваЗависимогоСписка.ПолноеИмя, Истина); + +КонецПроцедуры + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура ЗаполнитьСпискиБезВнедрения(СпискиБезВнедрения, СвойстваСписка) + + Если СпискиБезВнедрения = Неопределено Тогда + Возврат; + КонецЕсли; + + Параметры = СвойстваСписка.Параметры; + + Если Параметры.БезОбновленияКлючейДоступаКОбъектам + И СтрПолучитьСтроку(Параметры.Версия, 1) <> " " + И Не ЭтоУстаревшийОбъектМетаданных(СвойстваСписка.ПолноеИмя) Тогда + + Если СтрПолучитьСтроку(Параметры.Версия, 1) = " " Тогда + Списки = СпискиБезВнедрения.ОбъектыПредупреждения; + Иначе + Списки = СпискиБезВнедрения.ОбъектыОшибки; + КонецЕсли; + ЗависимыеСписки = Списки.Получить(СвойстваСписка.ПолноеИмя); + Если ЗначениеЗаполнено(ЗависимыеСписки) Тогда + Для Каждого КлючИЗначение Из СвойстваСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа Цикл + ЗависимыеСписки.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Иначе + ЗависимыеСписки = СвойстваСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа; + Списки.Вставить(СвойстваСписка.ПолноеИмя, ЗависимыеСписки); + КонецЕсли; + Если ЗначениеЗаполнено(СтрПолучитьСтроку(Параметры.Версия, 1)) Тогда + ЗависимыеСписки.Вставить("ЕстьОграничениеСписка", Истина); + КонецЕсли; + КонецЕсли; + + Если Параметры.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей Тогда + Контекст = Параметры.Контекст; + ТекстОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список).Текст; + ОписаниеРегистра = Новый Структура; + ОписаниеРегистра.Вставить("ПолноеИмя", СвойстваСписка.ПолноеИмя); + ОписаниеРегистра.Вставить("ИмяОтдельногоРегистраКлючей", Параметры.ИмяОтдельногоРегистраКлючей); + ОписаниеРегистра.Вставить("НедостающиеТипы", Контекст.ОпорныеПоля.НедостающиеТипы); + ОписаниеРегистра.Вставить("ПоляНедостающихТипов", Контекст.ОпорныеПоля.ПоляНедостающихТипов); + ОписаниеРегистра.Вставить("ТекстОграничения", ТекстОграничения); + СпискиБезВнедрения.РегистрыПредупреждения.Добавить(ОписаниеРегистра); + КонецЕсли; + +КонецПроцедуры + +// Для функции ЗаполнитьСпискиБезВнедрения. +Функция ЭтоУстаревшийОбъектМетаданных(ПолноеИмя) + + ЧастиИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Если ЧастиИмени.Количество() <> 2 Тогда + Возврат Ложь; + КонецЕсли; + + Возврат СтрНачинаетсяС(ВРег(ЧастиИмени[1]), ВРег("Удалить")); + +КонецФункции + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура УстановитьСвойствоОграничения(ПолноеИмя, ИмяСвойства, ЗначениеСвойства, Контекст) + + Свойства = СвойстваОграниченияСписка(ПолноеИмя, Контекст.ДополнительныйКонтекст, Истина); + + Свойства[ИмяСвойства] = ЗначениеСвойства; + +КонецПроцедуры + +// Для процедур УстановитьСвойствоОграничения, ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Функция СвойстваОграниченияСписка(ПолноеИмя, Контекст, ДобавлятьВКоллекцию = Ложь) + + Свойства = Контекст.СвойстваОграниченияСписков.Получить(ПолноеИмя); + + Если Свойства = Неопределено Тогда + Свойства = НовыеСвойстваОграниченияСписка(); + Если ДобавлятьВКоллекцию Тогда + Контекст.СвойстваОграниченияСписков.Вставить(ПолноеИмя, Свойства); + КонецЕсли; + КонецЕсли; + + Возврат Свойства; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ДоступЗапрещен - Булево +// * ПолеВладельца - см. НовоеПолеВладельца +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ИмяОтдельногоРегистраКлючей - Строка +// * РассчитыватьПраваПользователей - Булево +// * ИспользуемыеТипыЗначенийДоступа - ХранилищеЗначения - содержит тип Массив из Тип +// * ОграничениеВШаблонахЧерезКлючиДоступаПользователей - Булево +// * ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа - Булево +// +Функция НовыеСвойстваОграниченияСписка() + + Свойства = Новый Структура; + Свойства.Вставить("ДоступЗапрещен", Ложь); + Свойства.Вставить("ПолеВладельца", Неопределено); + Свойства.Вставить("ОпорныеПоля", Неопределено); + Свойства.Вставить("ИмяОтдельногоРегистраКлючей", ""); + Свойства.Вставить("РассчитыватьПраваПользователей", Ложь); + Свойства.Вставить("ОграничениеВШаблонахЧерезКлючиДоступаПользователей", Ложь); + Свойства.Вставить("ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа", Ложь); + Свойства.Вставить("ИспользуемыеТипыЗначенийДоступа", Неопределено); + + Возврат Свойства; + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +// +// Параметры: +// СпискиБезВнедрения - Соответствие +// ИнформацияДляЖурнала - см. НоваяИнформацияНесоответствияПараметровДляЖурнала +// +Процедура ЗаполнитьНесоответствиеПараметровДляЖурнала(СпискиБезВнедрения, ИнформацияДляЖурнала); + + Если ЗначениеЗаполнено(СпискиБезВнедрения.ОбъектыПредупреждения) Тогда + ИнформацияДляЖурнала.Предупреждение = ОписаниеНесоответствияПараметров( + СпискиБезВнедрения.ОбъектыПредупреждения); + КонецЕсли; + + Если ЗначениеЗаполнено(СпискиБезВнедрения.ОбъектыОшибки) Тогда + ИнформацияДляЖурнала.Ошибка = ОписаниеНесоответствияПараметров( + СпискиБезВнедрения.ОбъектыОшибки); + КонецЕсли; + + Если Не ЗначениеЗаполнено(СпискиБезВнедрения.РегистрыПредупреждения) Тогда + Возврат; + КонецЕсли; + + Предупреждения = Новый СписокЗначений; + + Для Каждого ОписаниеРегистра Из СпискиБезВнедрения.РегистрыПредупреждения Цикл + Если ЗначениеЗаполнено(ОписаниеРегистра.ИмяОтдельногоРегистраКлючей) Тогда + Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В таблице %1 будут недоступны строки + |для значений которых в измерениях регистра сведений + | %2 + |не хватает типов: + | - %3, + |имеющихся у полей (%4) в ограничении доступа: + | %5'"), + ОписаниеРегистра.ПолноеИмя, + ОписаниеРегистра.ИмяОтдельногоРегистраКлючей, + СтрСоединить(ОписаниеРегистра.НедостающиеТипы, "," + Символы.ПС + " - "), + СтрСоединить(ОписаниеРегистра.ПоляНедостающихТипов, ", "), + ТекстСОтступом(ОписаниеРегистра.ТекстОграничения, " ")); + Иначе + Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В таблице %1 будут недоступны строки для значений которых + |в определяемом типе %2 не хватает типов: + | - %3, + |имеющихся у полей (%4) в ограничении доступа: + | %5'"), + ОписаниеРегистра.ПолноеИмя, + "ПолеРегистраКлючейДоступаКРегистрам", + СтрСоединить(ОписаниеРегистра.НедостающиеТипы, "," + Символы.ПС + " - "), + СтрСоединить(ОписаниеРегистра.ПоляНедостающихТипов, ", "), + ТекстСОтступом(ОписаниеРегистра.ТекстОграничения, " ")); + КонецЕсли; + Предупреждения.Добавить(Текст, ОписаниеРегистра.ПолноеИмя); + КонецЦикла; + + Предупреждения.СортироватьПоПредставлению(); + Если ЗначениеЗаполнено(ИнформацияДляЖурнала.Предупреждение) Тогда + Предупреждения.Вставить(0, ИнформацияДляЖурнала.Предупреждение); + КонецЕсли; + ИнформацияДляЖурнала.Предупреждение = + СтрСоединить(Предупреждения.ВыгрузитьЗначения(), Символы.ПС + Символы.ПС + Символы.ПС); + +КонецПроцедуры + +// Для процедуры ЗаполнитьНесоответствиеПараметровДляЖурнала. +Функция ОписаниеНесоответствияПараметров(СпискиБезВнедрения) + + Списки = Новый СписокЗначений; + ВедущиеСписки = Новый СписокЗначений; + + Для Каждого ВедущийСписок Из СпискиБезВнедрения Цикл + ЗависимыеСписки = Новый СписокЗначений; + Для Каждого ЗависимыйСписок Из ВедущийСписок.Значение Цикл + Если ЗависимыйСписок.Ключ = "ЕстьОграничениеСписка" Тогда + Списки.Добавить(ВедущийСписок.Ключ); + Иначе + ЗависимыеСписки.Добавить(ЗависимыйСписок.Ключ); + КонецЕсли; + КонецЦикла; + Если Не ЗначениеЗаполнено(ЗависимыеСписки) Тогда + Продолжить; + КонецЕсли; + ЗависимыеСписки.СортироватьПоЗначению(); + + ВедущиеСписки.Добавить(ВедущийСписок.Ключ + " {" + Символы.ПС + " " + + СтрСоединить(ЗависимыеСписки.ВыгрузитьЗначения(), Символы.ПС + " ") + + Символы.ПС + "}", ВедущийСписок.Ключ); + КонецЦикла; + + Результат = Новый Массив; + + Если ЗначениеЗаполнено(Списки) Тогда + Списки.СортироватьПоПредставлению(); + Результат.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Типы следующих таблиц не указаны в определяемом типе %1, + |поэтому их строки будут недоступны: + | + |%2'"), + "ВладелецЗначенийКлючейДоступа", + СтрСоединить(Списки.ВыгрузитьЗначения(), Символы.ПС))); + КонецЕсли; + + Если ЗначениеЗаполнено(ВедущиеСписки) Тогда + ВедущиеСписки.СортироватьПоПредставлению(); + Результат.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Типы следующих ведущих таблиц не указаны в определяемом типе %1, + |поэтому в зависимых от них таблицах (в фигурных скобках) + |будут недоступны строки, содержащие ссылки на объекты этих типов + |в тех полях, которые используются в ограничении доступа к ним: + | + |%2'"), + "ВладелецЗначенийКлючейДоступа", + СтрСоединить(ВедущиеСписки.ВыгрузитьЗначения(), Символы.ПС))); + КонецЕсли; + + Возврат СтрСоединить(Результат, Символы.ПС + Символы.ПС + Символы.ПС); + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьВедущиеРоли(ВедущиеРоли, ИмяСвойстваВидаПользователей, КонтекстВидаПользователей) + + Для Каждого ОписаниеВедущейРоли Из КонтекстВидаПользователей.ВедущиеРоли Цикл + ИмяРоли = ОписаниеВедущейРоли.Ключ; + ЗависимыеСписки = ВедущиеРоли.Получить(ИмяРоли); + Если ЗависимыеСписки = Неопределено Тогда + ЗависимыеСписки = Новый Структура("ДляПользователей, ДляВнешнихПользователей"); + ВедущиеРоли.Вставить(ИмяРоли, ЗависимыеСписки); + КонецЕсли; + ЗависимыеСписки[ИмяСвойстваВидаПользователей] = + Новый ФиксированноеСоответствие(ОписаниеВедущейРоли.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьВедущиеСписки(ВедущиеСписки, ИмяСвойстваВидаПользователей, ЗависимыйСписок, + ВедущиеСпискиЗависимогоСписка) + + Для Каждого ОписаниеВедущегоСписка Из ВедущиеСпискиЗависимогоСписка.ПоЗначениямПолей Цикл + ВедущийСписок = ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ОписаниеВедущегоСписка.Ключ); + ВедущийСписок.ЗависимыеСписки.Вставить(ЗависимыйСписок, Истина); + ДобавляемыеПоля = ОписаниеВедущегоСписка.Значение; + + Если ВедущийСписок.ПоЗначениямПолей = Неопределено Тогда + ПоЗначениямПолей = Новый Структура; + ПоЗначениямПолей.Вставить("ЭтоСсылочныйТип", ДобавляемыеПоля.ЭтоСсылочныйТип); + ПоЗначениямПолей.Вставить("ПоляШапки", ОписаниеПолейВедущегоСписка()); + Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда + ПоЗначениямПолей.Вставить("ТабличныеЧасти", Новый Соответствие); + КонецЕсли; + ВедущийСписок.ПоЗначениямПолей = ПоЗначениямПолей; + Иначе + ПоЗначениямПолей = ВедущийСписок.ПоЗначениямПолей; + КонецЕсли; + + ДобавитьПоляВедущегоСписка(ПоЗначениямПолей.ПоляШапки, ДобавляемыеПоля.ДляОтслеживания.ПоляШапки, + ДобавляемыеПоля.ДляОтбора.ПоляШапки, ЗависимыйСписок, ИмяСвойстваВидаПользователей); + + Для Каждого ТабличнаяЧасть Из ДобавляемыеПоля.ДляОтслеживания.ТабличныеЧасти Цикл + ОписаниеТабличнойЧасти = ПоЗначениямПолей.ТабличныеЧасти.Получить(ТабличнаяЧасть.Ключ); + Если ОписаниеТабличнойЧасти = Неопределено Тогда + ОписаниеТабличнойЧасти = ОписаниеПолейВедущегоСписка(); + ОписаниеТабличнойЧасти.Вставить("Имя", ТабличнаяЧасть.Ключ); + ПоЗначениямПолей.ТабличныеЧасти.Вставить(ТабличнаяЧасть.Ключ, ОписаниеТабличнойЧасти); + КонецЕсли; + ТабличнаяЧастьПоляОтбора = ДобавляемыеПоля.ДляОтбора.ТабличныеЧасти.Получить(ТабличнаяЧасть.Ключ); + ДобавитьПоляВедущегоСписка(ОписаниеТабличнойЧасти, ТабличнаяЧасть.Значение, + ТабличнаяЧастьПоляОтбора, ЗависимыйСписок, ИмяСвойстваВидаПользователей); + КонецЦикла; + КонецЦикла; + + ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, + ИмяСвойстваВидаПользователей, ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, "ПоКлючамДоступа"); + + ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, + ИмяСвойстваВидаПользователей, ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, "ПоЗначениямСГруппами"); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ЭтоСсылочныйТип - Булево +// * ПоляШапки - см. ОписаниеПолейВедущегоСписка +// * ТабличныеЧасти - Массив из см. ОписаниеПолейВедущегоСписка +// +Функция ВедущийСписокПоЗначениямПолей() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ДляПользователей - Массив из Строка - полные имена списков +// * ДляВнешнихПользователей - Массив из Строка - полные имена списков +// +Функция ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ДобавитьВедущиеСписки. +// +// Возвращаемое значение: +// Структура: +// * ВсеПоля - Массив +// * ТипыВсехПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя поля. +// ** Значение - ХранилищеЗначения - содержит тип ОписаниеТипов - тип поля. +// * НаборыПолей - Структура: +// ** ДляПользователей - Булево +// ** ДляВнешнихПользователей - Булево +// * Имя - Строка - имя табличной части (есть только у полей табличной части) +// +Функция ОписаниеПолейВедущегоСписка() + + Описание = Новый Структура; + Описание.Вставить("ВсеПоля", Новый Массив); + Описание.Вставить("ТипыВсехПолей", Новый Соответствие); + Описание.Вставить("НаборыПолей", Новый Структура("ДляПользователей, ДляВнешнихПользователей")); + + Возврат Описание; + +КонецФункции + +// Для процедуры ДобавитьВедущиеСписки. +Процедура ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, ИмяСвойстваВидаПользователей, + ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, ВидЗависимости) + + Для Каждого ОписаниеВедущегоСписка Из ВедущиеСпискиЗависимогоСписка[ВидЗависимости] Цикл + ВедущийСписок = ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ОписаниеВедущегоСписка.Ключ); + ВедущийСписок.ЗависимыеСписки.Вставить(ЗависимыйСписок, Истина); + + Если ВедущийСписок[ВидЗависимости] = Неопределено Тогда + Свойства = ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами(); + Свойства.Вставить("ДляПользователей", Неопределено); + Свойства.Вставить("ДляВнешнихПользователей", Неопределено); + ВедущийСписок[ВидЗависимости] = Свойства; + Иначе + Свойства = ВедущийСписок[ВидЗависимости]; + КонецЕсли; + + Если Свойства[ИмяСвойстваВидаПользователей] = Неопределено Тогда + Свойства[ИмяСвойстваВидаПользователей] = Новый Массив; + КонецЕсли; + ЗависимыеСписки = Свойства[ИмяСвойстваВидаПользователей]; // Массив + ЗависимыеСписки.Добавить(ЗависимыйСписок); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьВедущиеСписки. +// +// Возвращаемое значение: +// Структура: +// * ЗависимыеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ПоЗначениямПолей - Структура - похожая на см. ВедущийСписокПоПоЗначениямПолей +// * ПоКлючамДоступа - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// * ПоЗначениямСГруппами - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// +Функция ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ПолноеИмя) + + ВедущийСписок = ВедущиеСписки.Получить(ПолноеИмя); + Если ВедущийСписок = Неопределено Тогда + ВедущийСписок = Новый Структура; + ВедущийСписок.Вставить("ЗависимыеСписки", Новый Соответствие); + ВедущийСписок.Вставить("ПоЗначениямПолей", Неопределено); + ВедущийСписок.Вставить("ПоКлючамДоступа", Неопределено); + ВедущийСписок.Вставить("ПоЗначениямСГруппами", Неопределено); + ВедущиеСписки.Вставить(ПолноеИмя, ВедущийСписок) + КонецЕсли; + + Возврат ВедущийСписок; + +КонецФункции + +// Для процедуры ДобавитьВедущиеСписки. +Процедура ДобавитьПоляВедущегоСписка(ТекущиеПоля, ОписаниеПолей, ОписаниеПолейОтбора, ЗависимыйСписок, + ИмяСвойстваВидаПользователей) + + СписокПолей = Новый СписокЗначений; + Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл + Если ТекущиеПоля.ВсеПоля.Найти(ОписаниеПоля.Ключ) = Неопределено Тогда + ТекущиеПоля.ВсеПоля.Добавить(ОписаниеПоля.Ключ); + ТекущиеПоля.ТипыВсехПолей.Вставить(ОписаниеПоля.Ключ, ОписаниеПоля.Значение); + КонецЕсли; + СписокПолей.Добавить(ОписаниеПоля.Ключ); + КонецЦикла; + СписокПолей.СортироватьПоЗначению(); + НаборПолей = СтрСоединить(СписокПолей.ВыгрузитьЗначения(), ", "); + + НаборыПолей = ТекущиеПоля.НаборыПолей[ИмяСвойстваВидаПользователей]; + Если НаборыПолей = Неопределено Тогда + НаборыПолей = Новый Соответствие; + ТекущиеПоля.НаборыПолей[ИмяСвойстваВидаПользователей] = НаборыПолей; + КонецЕсли; + ЗависимыеСпискиПоПолямОтбора = НаборыПолей.Получить(НаборПолей); + Если ЗависимыеСпискиПоПолямОтбора = Неопределено Тогда + ЗависимыеСпискиПоПолямОтбора = Новый Соответствие; + НаборыПолей.Вставить(НаборПолей, ЗависимыеСпискиПоПолямОтбора); + КонецЕсли; + + СписокПолей = Новый СписокЗначений; + Для Каждого ОписаниеПоля Из ОписаниеПолейОтбора Цикл + СписокПолей.Добавить(ОписаниеПоля.Ключ); + КонецЦикла; + СписокПолей.СортироватьПоЗначению(); + НаборПолейОтбора = СтрСоединить(СписокПолей.ВыгрузитьЗначения(), ", "); + + ЗависимыеСписки = ЗависимыеСпискиПоПолямОтбора.Получить(НаборПолейОтбора); + Если ЗависимыеСписки = Неопределено Тогда + ЗависимыеСписки = Новый Массив; + ЗависимыеСпискиПоПолямОтбора.Вставить(НаборПолейОтбора, ЗависимыеСписки); + КонецЕсли; + ЗависимыеСписки.Добавить(ЗависимыйСписок); + +КонецПроцедуры + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура НастроитьПараметрыШаблонов(СвойстваСписка, Контекст) + + Параметры = СвойстваСписка.Параметры; + ПараметрыШаблонов = Контекст.ПараметрыШаблонов; + + Если Параметры.ДоступЗапрещен Тогда + Уточнение = ?(Контекст.ДляВнешнихПользователей + И Не Контекст.ОбщийКонтекст.ВнешниеПользователиВключены, "1", "0"); + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа + + СвойстваСписка.ПолноеИмя + ";" + Уточнение + Символы.ПС; + Возврат; + КонецЕсли; + + Если Не Параметры.ИспользуетсяОграничениеПоВладельцу + И Не Параметры.ЭтоСсылочныйТип + И Не Параметры.ОграничениеОтключено Тогда + + ОпорныеПоля = Параметры.ОпорныеПоля; + Версия = НоваяВерсияПараметровШаблонов(); + Версия.ДатаСоздания = Контекст.ДатаСоздания; + Версия.Список = СвойстваСписка.ПолноеИмя; + Версия.ПоляСоединения = СтрСоединить(ОпорныеПоля.Используемые, ","); + Версия.ПоляШаблона = СтрСоединить(ОпорныеПоля.Все, ","); + Версия.ВариантДоступа = ОпорныеПоля.Используемые.Количество() * 2 + + ?(Контекст.ДляВнешнихПользователей, 1, 0); + Версии = Новый Массив; + Версии.Добавить(Версия); + КлючТаблицы = КлючТаблицы(СвойстваСписка.ПолноеИмя, Параметры.Контекст.ИмяКоллекцииТипа); + Контекст.ВерсииПараметровШаблонов.Вставить(КлючТаблицы, Версии); + КонецЕсли; + + Если Параметры.ОграничениеЧтенияОтключено Тогда + ПараметрыШаблонов.СпискиСОтключеннымОграничениемЧтения = + ПараметрыШаблонов.СпискиСОтключеннымОграничениемЧтения + + СвойстваСписка.ПолноеИмя + ";" + Символы.ПС; + Возврат; + КонецЕсли; + + ПолеВладельцаОтключено = ""; + + Если Параметры.ИспользуетсяОграничениеПоВладельцу + Или Параметры.ЭтоСсылочныйТип Тогда + + ПолеВладельца = Параметры.ПолеВладельца; // См. НовоеПолеВладельца + Если ПолеВладельца <> Неопределено Тогда + Поля = ":" + ПолеВладельца.Имя; + Если Не Параметры.ИспользуетсяОграничениеПоВладельцу Тогда + ПолеВладельцаОтключено = ";-"; + КонецЕсли; + Иначе + Поля = ":"; + КонецЕсли; + Иначе + ОпорныеПоля = Параметры.ОпорныеПоля; + Если ЗначениеЗаполнено(Параметры.ИмяОтдельногоРегистраКлючей) Тогда + Поля = "КлючиДоступаКРегистру" + СтрРазделить(СвойстваСписка.ПолноеИмя, ".")[1]; + Иначе + Поля = УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных( + СвойстваСписка.ПолноеИмя); + КонецЕсли; + Поля = ":[" + Поля + "]"; + Номер = 1; + Для Каждого ИмяПоля Из ОпорныеПоля.Все Цикл + Поля = Поля + ":" + ИмяПоля; + Номер = Номер + 1; + КонецЦикла; + НомерПустогоПоля = ОпорныеПоля.Все.Количество() + 1; + Для Номер = НомерПустогоПоля По ОпорныеПоля.МаксимальноДопустимоеКоличество Цикл + Поля = Поля + ":"; + КонецЦикла; + КонецЕсли; + + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа + + СвойстваСписка.ПолноеИмя + Поля + ";*" + ПолеВладельцаОтключено + Символы.ПС; + + Если СвойстваСписка.КлючиДоступаПользователейИГруппДоступа + Или СвойстваСписка.КлючиДоступаПользователей Тогда + + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаПользователей = + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаПользователей + + СвойстваСписка.ПолноеИмя + Поля + ";+" + ПолеВладельцаОтключено + Символы.ПС; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры НастроитьПараметрыШаблонов. +// +// Параметры: +// ПолноеИмя - Строка +// ИмяКоллекцииТипа - Строка +// ТипыТаблицПоИменам - Соответствие +// +// Возвращаемое значение: +// Строка +// +Функция КлючТаблицы(ПолноеИмя, ИмяКоллекцииТипа = Неопределено, ТипыТаблицПоИменам = Неопределено) + + Если ИмяКоллекцииТипа = Неопределено Тогда + СвойстваТипа = ТипыТаблицПоИменам.Получить(ВРег(СтрРазделить(ПолноеИмя, ".", Ложь)[0])); + ИмяКоллекцииТипа = СвойстваТипа.ИмяКоллекции; + КонецЕсли; + + Если ИмяКоллекцииТипа = "РегистрыСведений" + Или ИмяКоллекцииТипа = "РегистрыНакопления" + Или ИмяКоллекцииТипа = "РегистрыБухгалтерии" + Или ИмяКоллекцииТипа = "РегистрыРасчета" Тогда + + ТипКлючаТаблицы = ТипКлючаЗаписиПоПолномуИмениМетаданных(ПолноеИмя); + + ИначеЕсли ИмяКоллекцииТипа = "Последовательности" Тогда + ТипКлючаТаблицы = ТипНабораЗаписейПоПолномуИмениМетаданных(ПолноеИмя); + + ИначеЕсли ИмяКоллекцииТипа = "ЖурналыДокументов" Тогда + ТипКлючаТаблицы = ТипМенеджераОбъектаПоПолномуИмениМетаданных(ПолноеИмя); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неизвестный нессылочный объект метаданных + |""%1"" + |с поддержкой ограничений на уровне записей.'"), ПолноеИмя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + СтрокаДляХеширования = СтрокаДанныхДляХеширования(ТипКлючаТаблицы); + ХешированиеДанных.Добавить(СтрокаДляХеширования); + + Возврат Base64Строка(ХешированиеДанных.ХешСумма); + +КонецФункции + +// Для процедуры ОписаниеНовойВерсииПараметровОграниченияДоступа. +Процедура ЗаполнитьПараметрыДляШаблонов(Запись, ПараметрыЗаписи, ОписаниеВерсии) + + Если ТипЗнч(ОписаниеВерсии.ДатаСоздания) = Тип("Дата") Тогда + СтараяДатаСоздания = ОписаниеВерсии.ДатаСоздания; + Иначе + СтараяДатаСоздания = '00010101'; + КонецЕсли; + + ХранимыеТекущиеВерсии = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + ТекущиеСвойстваОграниченияСписковДляПользователей = Новый Соответствие; + ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = Новый Соответствие; + ВерсииПараметровШаблоновПолучены = Ложь; + + Если ТипЗнч(ОписаниеВерсии.ВерсииПараметровШаблонов) = Тип("ХранилищеЗначения") Тогда + СодержимоеХранилища = ЗначениеИзХранилища(ОписаниеВерсии.ВерсииПараметровШаблонов); + Если ЗначениеЗаполнено(СодержимоеХранилища) Тогда + ХранимыеТекущиеВерсии = СтруктураХранимыхВерсийПараметровШаблонов(СодержимоеХранилища); + Если ХранимыеТекущиеВерсии.ВерсияСтруктурыВерсий = ВерсияСтруктурыВерсийПараметровШаблонов() Тогда + ВерсииПараметровШаблоновПолучены = Истина; + ТекущиеСвойстваОграниченияСписковДляПользователей = Неопределено; + ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = Неопределено; + Иначе + ХранимыеТекущиеВерсии = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + КонецЕсли; + ИначеЕсли ТипЗнч(ОписаниеВерсии.Версия) = Тип("Число") Тогда + ТекущиеХранимыеПараметры = ВерсияПараметров(ОписаниеВерсии.Версия, Ложь, Ложь); + Если ТипЗнч(ТекущиеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав) = Тип("ХранилищеЗначения") Тогда + ТекущиеПараметрыЗаписи = СтруктураХранимыхПараметровЗаписи( + ЗначениеИзХранилища(ТекущиеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав)); + Если ТекущиеПараметрыЗаписи.ВерсияСтруктурыКэша = ВерсияСтруктурыКэша() + Или ТекущиеПараметрыЗаписи.ВерсияСтруктурыКэша = "20" Тогда + ТекущиеСвойстваОграниченияСписковДляПользователей = + ТекущиеПараметрыЗаписи.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков; + ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = + ТекущиеПараметрыЗаписи.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + Если Не ВерсииПараметровШаблоновПолучены Тогда + ОписаниеВерсии.ХешСумма = "#" + ОписаниеВерсии.ХешСумма; + КонецЕсли; + + Если ПараметрыЗаписи.Свойство("СтрокиВерсии") Тогда + СтрокиВерсии = ПараметрыЗаписи.СтрокиВерсии; + Иначе + СтрокиВерсии = Новый Структура; + КонецЕсли; + СтрокиВерсии.Вставить("СпискиСОграничениемПоПолямВСеансахПользователей"); + СтрокиВерсии.Вставить("СпискиСОграничениемПоПолямВСеансахВнешнихПользователей"); + + Если ТекущиеСвойстваОграниченияСписковДляПользователей <> Неопределено Тогда + НовыеПараметрыЗаписи = ПараметрыЗаписи.ХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить(); + НовыеСвойстваОграниченияСписковДляПользователей = + НовыеПараметрыЗаписи.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков; + НовыеСвойстваОграниченияСписковДляВнешнихПользователей = + НовыеПараметрыЗаписи.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков; + КонецЕсли; + + ХранимыеНовыеВерсии = ПараметрыЗаписи.ХранимыеПараметры.ВерсииПараметровШаблонов.Получить(); + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + + Параметры = НоваяСтруктураДляЗаполненияПараметровШаблонов(); + Параметры.Вставить("ИдентификаторыВсехСписков", ПараметрыЗаписи.ИдентификаторыВсехСписков); + Если ТипЗнч(ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа) = Тип("Массив") Тогда + Параметры.Вставить("ОтключитьДополнительныеВариантыДоступа"); + Иначе + ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа = Новый Массив; + КонецЕсли; + Параметры.Вставить("СтараяДатаСоздания", СтараяДатаСоздания); + Параметры.Вставить("ХешированиеДанных", ХешированиеДанных); + Параметры.Вставить("СпискиСНовымОсновнымВариантомДоступа", ПараметрыЗаписи.СпискиСНовымОсновнымВариантомДоступа); + Параметры.Вставить("СпискиСУстаревшимиВариантамиДоступа", ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа); + + Параметры.Вставить("ХранимыеТекущиеВерсии", ХранимыеТекущиеВерсии.ДляПользователей); + Параметры.Вставить("НовыеВерсииПолейСписков", ХранимыеНовыеВерсии.ДляПользователей.ВерсииПараметровШаблонов); + Параметры.Вставить("ТекущиеСвойстваОграниченияСписков", ТекущиеСвойстваОграниченияСписковДляПользователей); + Параметры.Вставить("НовыеСвойстваОграниченияСписков", НовыеСвойстваОграниченияСписковДляПользователей); + + ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, + Запись.ДляШаблоновВСеансахПользователей, + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахПользователей); + + Параметры.ХранимыеТекущиеВерсии = ХранимыеТекущиеВерсии.ДляВнешнихПользователей; + Параметры.НовыеВерсииПолейСписков = ХранимыеНовыеВерсии.ДляВнешнихПользователей.ВерсииПараметровШаблонов; + Параметры.ТекущиеСвойстваОграниченияСписков = ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей; + Параметры.НовыеСвойстваОграниченияСписков = НовыеСвойстваОграниченияСписковДляВнешнихПользователей; + + ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, + Запись.ДляШаблоновВСеансахВнешнихПользователей, + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахВнешнихПользователей); + + Запись.ХешСуммаПараметровШаблонов = Base64Строка(ХешированиеДанных.ХешСумма); + Запись.ВерсииПараметровШаблонов = Новый ХранилищеЗначения(ХранимыеТекущиеВерсии); + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + ХешированиеДанных.Добавить(Запись.ХешСуммаПостоянныхПараметров); + ХешированиеДанных.Добавить(Запись.ХешСуммаПараметровШаблонов); + Запись.ХешСумма = Base64Строка(ХешированиеДанных.ХешСумма); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблонов. +// +// Возвращаемое значение: +// Структура: +// * СтараяДатаСоздания - Дата +// * ХешированиеДанных - ХешированиеДанных +// * СпискиСНовымОсновнымВариантомДоступа - Массив из Строка +// * СпискиСУстаревшимиВариантамиДоступа - Массив из Строка +// * ХранимыеТекущиеВерсии - Структура: +// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов +// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// * НовыеВерсииПолейСписков - см. НовыеВерсииПараметровШаблонов +// * ТекущиеСвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * НовыеСвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * ИдентификаторыВсехСписков - Неопределено +// - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// +Функция НоваяСтруктураДляЗаполненияПараметровШаблонов() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ЗаполнитьПараметрыДляШаблонов. +// +// Параметры: +// Параметры - см. НоваяСтруктураДляЗаполненияПараметровШаблонов +// ХранилищеДляШаблоновВСеансах - ХранилищеЗначения - обновляемое значение +// СпискиСОграничениемПоПолям - Строка - возвращаемое значение +// +Процедура ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, + ХранилищеДляШаблоновВСеансах, СпискиСОграничениемПоПолям) + + МаксимальноеКоличествоВерсий = МаксимальноеКоличествоВерсийВВариантеДоступа(); + НастройкиОграниченийСписков = Новый СписокЗначений; + ТекущиеВерсииПолейСписков = Параметры.ХранимыеТекущиеВерсии.ВерсииПараметровШаблонов; + + Если Параметры.ТекущиеСвойстваОграниченияСписков <> Неопределено Тогда + ВариантыДоступаВБазеДанных = ВариантыДоступаВБазеДанных(Параметры); + Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл + ТекущиеВерсииПолейСписка = Новый Массив; + ДобавитьСуществующиеВерсииПолейСписка(ТекущиеВерсииПолейСписка, + КлючИЗначение.Значение[0], ВариантыДоступаВБазеДанных, Параметры); + Если ЗначениеЗаполнено(ТекущиеВерсииПолейСписка) Тогда + ТекущиеВерсииПолейСписков.Вставить(КлючИЗначение.Ключ, ТекущиеВерсииПолейСписка); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ВозможноНеиспользуемыеВерсииПолейСписков = Новый Массив; + + Для Каждого КлючИЗначение Из ТекущиеВерсииПолейСписков Цикл + ТекущиеВерсииПолейСписка = КлючИЗначение.Значение; + НовыеВерсииПолейСписка = Параметры.НовыеВерсииПолейСписков.Получить(КлючИЗначение.Ключ); + + Если НовыеВерсииПолейСписка = Неопределено Тогда + ИспользованиеОтключалось = Ложь; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + Если Версия.Используется Тогда + Версия.Используется = Ложь; + ИспользованиеОтключалось = Истина; + КонецЕсли; + КонецЦикла; + Если ИспользованиеОтключалось И ТекущиеВерсииПолейСписка.Количество() > 0 Тогда + ПолноеИмя = ТекущиеВерсииПолейСписка[0].Список; + Если ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) <> Неопределено Тогда + Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + КонецЕсли; + Продолжить; + КонецЕсли; + + НоваяВерсия = НовыеВерсииПолейСписка[0]; + НоваяВерсияСуществует = Ложь; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + Если ВРег(Версия.ПоляСоединения) = ВРег(НоваяВерсия.ПоляСоединения) + И Версия.ВариантДоступа > 1 Тогда + НоваяВерсияСуществует = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + ОсновнаяВерсияИзменена = Истина; + Если НоваяВерсияСуществует Тогда + Индекс = ТекущиеВерсииПолейСписка.Найти(Версия); + Если Индекс > 0 Тогда + ТекущиеВерсииПолейСписка.Удалить(Индекс); + ТекущиеВерсииПолейСписка.Вставить(0, Версия); + Иначе + ОсновнаяВерсияИзменена = Ложь; + КонецЕсли; + ЗаполнитьЗначенияСвойств(Версия, НоваяВерсия,, "ВариантДоступа"); + Иначе + ИспользуемыеНомераВерсий = Новый Массив(МаксимальноеКоличествоВерсий); + СамаяСтараяВерсия = Неопределено; + УдаляемыеВерсии = Новый Массив; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + НомерВерсии = Цел(Версия.ВариантДоступа / 64); + Если НоваяВерсия.ВариантДоступа <> (Версия.ВариантДоступа - НомерВерсии * 64) Тогда + Продолжить; + КонецЕсли; + Если НомерВерсии < МаксимальноеКоличествоВерсий Тогда + ИспользуемыеНомераВерсий[НомерВерсии] = Версия; + СамаяСтараяВерсия = Версия; + Иначе + УдаляемыеВерсии.Добавить(Версия); + КонецЕсли; + КонецЦикла; + Для Индекс = 0 По МаксимальноеКоличествоВерсий - 1 Цикл + Если ИспользуемыеНомераВерсий[Индекс] = Неопределено Тогда + Прервать; + КонецЕсли; + КонецЦикла; + Если Индекс >= МаксимальноеКоличествоВерсий Тогда + УдаляемыеВерсии.Добавить(СамаяСтараяВерсия); + НоваяВерсия.ВариантДоступа = НоваяВерсия.ВариантДоступа + + ИспользуемыеНомераВерсий.Найти(СамаяСтараяВерсия) * 64; + Иначе + НоваяВерсия.ВариантДоступа = НоваяВерсия.ВариантДоступа + Индекс * 64; + КонецЕсли; + Для Каждого УдаляемаяВерсия Из УдаляемыеВерсии Цикл + ТекущиеВерсииПолейСписка.Удалить(ТекущиеВерсииПолейСписка.Найти(УдаляемаяВерсия)); + КонецЦикла; + ТекущиеВерсииПолейСписка.Вставить(0, НоваяВерсия); + КонецЕсли; + + Если ОсновнаяВерсияИзменена Тогда + Параметры.СпискиСНовымОсновнымВариантомДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + + ОбновитьИспользованиеВерсийПолейСписка(ТекущиеВерсииПолейСписка, ОсновнаяВерсияИзменена, + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры); + КонецЦикла; + + ОтключитьИспользованиеВерсийКромеОсновнойДляОбновленныхСписков( + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры); + + ОсновныеВариантыДоступа = Параметры.ХранимыеТекущиеВерсии.ОсновныеВариантыДоступа; + + Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл + ТекущиеВерсииПолейСписка = ТекущиеВерсииПолейСписков.Получить(КлючИЗначение.Ключ); + Если ТекущиеВерсииПолейСписка = Неопределено Тогда + ТекущиеВерсииПолейСписка = КлючИЗначение.Значение; + ТекущиеВерсииПолейСписков.Вставить(КлючИЗначение.Ключ, ТекущиеВерсииПолейСписка); + Параметры.СпискиСНовымОсновнымВариантомДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + ИспользуемыеВариантыДоступа = Новый Массив; + Для Каждого ВерсияПолейСписка Из ТекущиеВерсииПолейСписка Цикл + Если ВерсияПолейСписка.Используется Тогда + ИспользуемыйВариантДоступа = НовыйИспользуемыйВариантДоступа(); + ИспользуемыйВариантДоступа.ВариантДоступа = ВерсияПолейСписка.ВариантДоступа; + ИспользуемыйВариантДоступа.ПоляСоединения = ВерсияПолейСписка.ПоляСоединения; + ИспользуемыеВариантыДоступа.Добавить(Новый ФиксированнаяСтруктура(ИспользуемыйВариантДоступа)); + КонецЕсли; + КонецЦикла; + ОсновныеВариантыДоступа.Вставить(ТекущиеВерсииПолейСписка[0].Список, + Новый ФиксированныйМассив(ИспользуемыеВариантыДоступа)); + КонецЦикла; + + Для Каждого КлючИЗначение Из ТекущиеВерсииПолейСписков Цикл + ДобавитьПоляОграниченияСписка(НастройкиОграниченийСписков, КлючИЗначение.Значение); + КонецЦикла; + + НастройкиОграниченийСписков.СортироватьПоПредставлению(); + СпискиСОграничениемПоПолям = СтрСоединить(НастройкиОграниченийСписков.ВыгрузитьЗначения(), Символы.ПС); + Параметры.ХешированиеДанных.Добавить(СпискиСОграничениемПоПолям); + + ХранимыеПараметрыШаблонов = Новый Структура(ХранилищеДляШаблоновВСеансах.Получить()); + ПараметрыШаблонов = Новый Структура(ХранимыеПараметрыШаблонов.ПараметрыШаблонов); + ПараметрыШаблонов.СпискиСОграничениемПоПолям = СпискиСОграничениемПоПолям; + ХранимыеПараметрыШаблонов.ПараметрыШаблонов = Новый ФиксированнаяСтруктура(ПараметрыШаблонов); + ХранилищеДляШаблоновВСеансах = Новый ХранилищеЗначения( + Новый ФиксированнаяСтруктура(ХранимыеПараметрыШаблонов)); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ОбновитьИспользованиеВерсийПолейСписка(ТекущиеВерсииПолейСписка, ОсновнаяВерсияИзменена, + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры) + + МаксимальноеКоличествоВариантовСоединений = МаксимальноеКоличествоВариантовСоединений(); + НоваяВерсия = ТекущиеВерсииПолейСписка[0]; + ПоляШаблона = СтрРазделить(ВРег(НоваяВерсия.ПоляШаблона), ",", Ложь); + + КоличествоИспользуемыхВерсий = 0; + ИспользованиеОтключалось = Ложь; + + Для Каждого ТекущаяВерсия Из ТекущиеВерсииПолейСписка Цикл + Если Не ТекущаяВерсия.Используется Тогда + Продолжить; + КонецЕсли; + Если ВРег(ТекущаяВерсия.ПоляШаблона) <> ВРег(НоваяВерсия.ПоляШаблона) Тогда + ИменаПолей = СтрРазделить(ТекущаяВерсия.ПоляСоединения, ",", Ложь); + Для Каждого ИмяПоля Из ИменаПолей Цикл + Если ПоляШаблона.Найти(ВРег(ИмяПоля)) = Неопределено Тогда + ТекущаяВерсия.Используется = Ложь; + ИспользованиеОтключалось = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если Не ТекущаяВерсия.Используется Тогда + Продолжить; + КонецЕсли; + Если КоличествоИспользуемыхВерсий >= МаксимальноеКоличествоВариантовСоединений Тогда + ТекущаяВерсия.Используется = Ложь; + ИспользованиеОтключалось = Истина; + Иначе + КоличествоИспользуемыхВерсий = КоличествоИспользуемыхВерсий + 1; + КонецЕсли; + КонецЦикла; + + Если ИспользованиеОтключалось Тогда + Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + + Если Не ОсновнаяВерсияИзменена И КоличествоИспользуемыхВерсий > 1 Тогда + ВозможноНеиспользуемыеВерсииПолейСписков.Добавить(ТекущиеВерсииПолейСписка); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ДобавитьПоляОграниченияСписка(СпискиСОграничениемПоПолям, ТекущиеВерсииПолейСписка) + + НоваяВерсия = ТекущиеВерсииПолейСписка[0]; + ПолноеИмя = НоваяВерсия.Список; + ПоляШаблона = СтрРазделить(ВРег(НоваяВерсия.ПоляШаблона), ",", Ложь); + НастройкиОграниченийСписка = Новый Массив; + МаксимальноеКоличествоВариантов = МаксимальноеКоличествоВариантовСоединений(); + + НомерВарианта = 1; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + Если Не Версия.Используется Тогда + Прервать; + КонецЕсли; + + НомерПоляСоединения = 1; + ИменаПолей = СтрРазделить(Версия.ПоляСоединения, ",", Ложь); + Для Каждого ИмяПоля Из ИменаПолей Цикл + НомерПоляШаблона = ПоляШаблона.Найти(ВРег(ИмяПоля)) + 1; + НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=%4;", + ПолноеИмя, + "Вариант" + XMLСтрока(НомерВарианта), + "Поле" + XMLСтрока(НомерПоляСоединения), + "Поле" + XMLСтрока(НомерПоляШаблона))); + НомерПоляСоединения = НомерПоляСоединения + 1; + КонецЦикла; + + Если Цел(Версия.ВариантДоступа / 2) = 0 Тогда + НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=0;", + ПолноеИмя, + "Вариант" + XMLСтрока(НомерВарианта), + "Версия" + XMLСтрока(НомерВарианта))); + Иначе + Остаток = Цел(Версия.ВариантДоступа / 64); + НомерБита = 0; + Пока Остаток > 0 Цикл + НовыйОстаток = Цел(Остаток / 2); + Если Остаток - НовыйОстаток * 2 > 0 Тогда + НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=1;", + ПолноеИмя, + "Версия" + XMLСтрока(НомерВарианта), + "Бит" + XMLСтрока(НомерБита))); + КонецЕсли; + Остаток = НовыйОстаток; + НомерБита = НомерБита + 1; + КонецЦикла; + КонецЕсли; + + НомерВарианта = НомерВарианта + 1; + Если НомерВарианта > МаксимальноеКоличествоВариантов Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + СпискиСОграничениемПоПолям.Добавить( + СтрСоединить(НастройкиОграниченийСписка, Символы.ПС), ПолноеИмя); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Функция ВариантыДоступаВБазеДанных(Параметры) + + Если Не ЗначениеЗаполнено(Параметры.НовыеВерсииПолейСписков) Тогда + Возврат Новый Соответствие; + КонецЕсли; + + ТекстОбщегоЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.Регистр КАК Регистр, + | ТекущаяТаблица.ВариантДоступа КАК ВариантДоступа + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК ТекущаяТаблица + |ГДЕ + | ВЫБОР + | КОГДА ТекущаяТаблица.ВариантДоступа = 0 + | ТОГДА ЛОЖЬ + | ИНАЧЕ ТекущаяТаблица.ВариантДоступа - (ВЫРАЗИТЬ(ТекущаяТаблица.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 + | КОНЕЦ = &ДляВнешнихПользователей + | + |УПОРЯДОЧИТЬ ПО + | Регистр, + | ВариантДоступа"; + + ТекстыЗапросов = Новый Массив; + ТекстыЗапросов.Добавить(ТекстОбщегоЗапроса); + + ПолныеИмена = Новый Массив; + ИндексыРезультатовЗапроса = Новый Соответствие; + + Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл + Список = КлючИЗначение.Значение[0].Список; + СвойстваСписка = Параметры.НовыеСвойстваОграниченияСписков.Получить(Список); + Если СвойстваСписка = Неопределено + Или Не ЗначениеЗаполнено(СвойстваСписка.ОпорныеПоля) Тогда + Продолжить; + КонецЕсли; + ПолныеИмена.Добавить(Список); + Если ЗначениеЗаполнено(СвойстваСписка.ИмяОтдельногоРегистраКлючей) Тогда + ИндексыРезультатовЗапроса.Вставить(Список, ТекстыЗапросов.Количество()); + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.ВариантДоступа КАК ВариантДоступа + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ВЫБОР + | КОГДА ТекущаяТаблица.ВариантДоступа = 0 + | ТОГДА ЛОЖЬ + | ИНАЧЕ ТекущаяТаблица.ВариантДоступа - (ВЫРАЗИТЬ(ТекущаяТаблица.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 + | КОНЕЦ = &ДляВнешнихПользователей + | + |УПОРЯДОЧИТЬ ПО + | ВариантДоступа"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", + "РегистрСведений." + СвойстваСписка.ИмяОтдельногоРегистраКлючей); + ТекстыЗапросов.Добавить(ТекстЗапроса); + Иначе + ИндексыРезультатовЗапроса.Вставить(Список, 0); + КонецЕсли; + КонецЦикла; + + ИдентификаторыСписков = ?(Параметры.ИдентификаторыВсехСписков = Неопределено, + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена, Ложь), + Параметры.ИдентификаторыВсехСписков); + + Запрос = Новый Запрос; + ВариантДоступа = КлючИЗначение.Значение[0].ВариантДоступа; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ВариантДоступа - Цел(ВариантДоступа / 2) * 2 > 0); + Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Выгрузка = РезультатыЗапроса[0].Выгрузить(); + Выгрузка.Индексы.Добавить("Регистр"); + + Результат = Новый Соответствие; + + Для Каждого КлючИЗначение Из ИндексыРезультатовЗапроса Цикл + Если КлючИЗначение.Значение = 0 Тогда + ИдентификаторСписка = ИдентификаторыСписков.Получить(КлючИЗначение.Ключ); + ВариантыДоступа = Новый Массив; + Если ИдентификаторСписка <> Неопределено И ИдентификаторСписка <> Null Тогда + НайденныеСтроки = Выгрузка.НайтиСтроки(Новый Структура("Регистр", ИдентификаторСписка)); + Для Каждого НайденнаяСтрока Из НайденныеСтроки Цикл + ВариантыДоступа.Добавить(НайденнаяСтрока.ВариантДоступа); + КонецЦикла; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не найден идентификатор объекта метаданных ""%1"".'"), КлючИЗначение.Ключ); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + Результат.Вставить(КлючИЗначение.Ключ, ВариантыДоступа); + Иначе + Результат.Вставить(КлючИЗначение.Ключ, + РезультатыЗапроса[КлючИЗначение.Значение].Выгрузить().ВыгрузитьКолонку("ВариантДоступа")); + КонецЕсли; + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ОтключитьИспользованиеВерсийКромеОсновнойДляОбновленныхСписков( + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры) + + Если Не ЗначениеЗаполнено(ВозможноНеиспользуемыеВерсииПолейСписков) + Или Не Параметры.Свойство("ОтключитьДополнительныеВариантыДоступа") Тогда + Возврат; + КонецЕсли; + + Списки = Новый Массив; + ВерсииПолейСписков = Новый Соответствие; + Для Каждого ВерсииПолейСписка Из ВозможноНеиспользуемыеВерсииПолейСписков Цикл + Список = ВерсииПолейСписка[0].Список; + Списки.Добавить(Список); + ВерсииПолейСписков.Вставить(Список, ВерсииПолейСписка); + КонецЦикла; + + ДляВнешнихПользователей = ВерсииПолейСписка[0].ВариантДоступа + - Цел(ВерсииПолейСписка[0].ВариантДоступа / 2) * 2 = 1; + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + ИдентификаторыСписков = Новый ТаблицаЗначений; + ИдентификаторыСписков.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); + + СпискиПоИдентификаторам = Новый Соответствие; + ИдентификаторыОбъектов = ?(Параметры.ИдентификаторыВсехСписков = Неопределено, + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки, Ложь), + Параметры.ИдентификаторыВсехСписков); + + Для Каждого Список Из Списки Цикл + ИдентификаторСписка = ИдентификаторыОбъектов.Получить(Список); + Если ИдентификаторСписка <> Неопределено И ИдентификаторСписка <> Null Тогда + ИдентификаторыСписков.Добавить().ИдентификаторСписка = ИдентификаторСписка; + СпискиПоИдентификаторам.Вставить(ИдентификаторСписка, Список); + КонецЕсли; + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ИдентификаторыСписков", ИдентификаторыСписков); + Запрос.Текст = + "ВЫБРАТЬ + | ИдентификаторыСписков.ИдентификаторСписка КАК ИдентификаторСписка + |ПОМЕСТИТЬ ИдентификаторыСписков + |ИЗ + | &ИдентификаторыСписков КАК ИдентификаторыСписков + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ИдентификаторыСписков.ИдентификаторСписка КАК ИдентификаторСписка + |ИЗ + | ИдентификаторыСписков КАК ИдентификаторыСписков + |ГДЕ + | НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | ГДЕ + | ОбновлениеКлючейДоступаКДанным.Список = ИдентификаторыСписков.ИдентификаторСписка + | И ОбновлениеКлючейДоступаКДанным.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ОбновлениеКлючейДоступаКДанным.РазмерЗадания = 3)"; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + Список = СпискиПоИдентификаторам.Получить(Выборка.ИдентификаторСписка); + ВерсииПолейСписка = ВерсииПолейСписков.Получить(Список); + ОсновнаяВерсия = ВерсииПолейСписка[0]; + Для Каждого ВерсияПолейСписка Из ВерсииПолейСписка Цикл + Если ВерсияПолейСписка = ОсновнаяВерсия Тогда + Продолжить; + КонецЕсли; + Если ВерсияПолейСписка.Используется Тогда + ВерсияПолейСписка.Используется = Ложь; + Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить(Список); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ДобавитьСуществующиеВерсииПолейСписка(ТекущиеВерсииПолейСписка, НоваяВерсия, + ВариантыДоступаВБазеДанных, Параметры) + + ВариантыДоступа = ВариантыДоступаВБазеДанных.Получить(НоваяВерсия.Список); + Если Не ЗначениеЗаполнено(ВариантыДоступа) Тогда + Возврат; + КонецЕсли; + + ТекущиеСвойстваСписка = Параметры.ТекущиеСвойстваОграниченияСписков.Получить(НоваяВерсия.Список); + ОпорныеПоля = ?(ТекущиеСвойстваСписка = Неопределено, Неопределено, ТекущиеСвойстваСписка.ОпорныеПоля); + Если ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) И ЗначениеЗаполнено(ОпорныеПоля) Тогда + ТребуемыйВариантДоступа = ОпорныеПоля.Используемые.Количество() * 2 + + НоваяВерсия.ВариантДоступа - Цел(НоваяВерсия.ВариантДоступа / 2) * 2; + Иначе + ТребуемыйВариантДоступа = НоваяВерсия.ВариантДоступа; + КонецЕсли; + + Если ВариантыДоступа.Количество() = 1 + И (Не ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) + Или ЗначениеЗаполнено(ОпорныеПоля)) + И ( ВариантыДоступа[0] < 2 + Или ВариантыДоступа[0] - Цел(ВариантыДоступа[0] / 64) * 64 = ТребуемыйВариантДоступа) Тогда + + // Переход с версий конфигурации без поля ВариантДоступа или восстановление + // либо после очистки регистра ПараметрыОграниченияДоступа, + // либо после изменения номера в функции ВерсияСтруктурыВерсийПараметровШаблонов. + Если Не ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) Тогда + ПоляСоединения = НоваяВерсия.ПоляСоединения; + ПоляШаблона = НоваяВерсия.ПоляСоединения; + Иначе + ПоляСоединения = СтрСоединить(ОпорныеПоля.Используемые, ","); + ПоляШаблона = СтрСоединить(ОпорныеПоля.Все, ","); + КонецЕсли; + + ПредыдущаяВерсия = НоваяВерсияПараметровШаблонов(); + ПредыдущаяВерсия.ДатаСоздания = Параметры.СтараяДатаСоздания; + ПредыдущаяВерсия.Список = НоваяВерсия.Список; + ПредыдущаяВерсия.ПоляСоединения = ПоляСоединения; + ПредыдущаяВерсия.ПоляШаблона = ПоляШаблона; + ПредыдущаяВерсия.ВариантДоступа = ВариантыДоступа[0]; + + ТекущиеВерсииПолейСписка.Добавить(ПредыдущаяВерсия); + Иначе + // Несколько версий существующих одновременно не могут быть сопоставлены + // одному набору полей и не могут использоваться для новых наборов полей. + Для Каждого ВариантДоступа Из ВариантыДоступа Цикл + НеизвестнаяВерсия = НоваяВерсияПараметровШаблонов(); + НеизвестнаяВерсия.ДатаСоздания = Параметры.СтараяДатаСоздания; + НеизвестнаяВерсия.Список = НоваяВерсия.Список; + НеизвестнаяВерсия.ВариантДоступа = ВариантДоступа; + НеизвестнаяВерсия.Используется = Ложь; + + ТекущиеВерсииПолейСписка.Добавить(НеизвестнаяВерсия); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьИспользованиеВерсийПолейСписка и ДобавитьПоляОграниченияСписка. +Функция МаксимальноеКоличествоВариантовСоединений() + + // При изменении нужно синхронно изменить шаблон ограничения доступа ДляРегистра. + Возврат 3; + +КонецФункции + +// Для процедур ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Функция МаксимальноеКоличествоВерсийВВариантеДоступа() + + Возврат 16; + +КонецФункции + +// Для процедур УстановитьВерсиюПараметров, ЗаполнитьПараметрыДляШаблонов, +// ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений и +// функции СпискиСИзменениемВерсий. +// +Функция ЗначениеИзХранилища(ХранилищеЗначения) + + Попытка + Значение = ХранилищеЗначения.Получить(); + Исключение + Значение = Неопределено; + КонецПопытки; + + Возврат Значение; + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров, и для функции ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииОграниченийСписков - ФиксированноеСоответствие +// * ВедущиеСписки - ФиксированноеСоответствие +// * ДополнительныйКонтекст - ФиксированнаяСтруктура +// * СпискиСДатой - ФиксированноеСоответствие +// * ВнешниеПользователиВключены - Булево +// * ОграничениеДоступаВключено - Булево +// * ИспользуемыеТипыЗначений - ХранилищеЗначения +// +Функция СтруктураХранимыхПараметровЗаписи(Значения) + + ХранимыеПараметрыЗаписи = НоваяСтруктураХранимыхПараметровЗаписи(); + ХранимыеПараметрыЗаписи.ВерсияСтруктурыКэша = ""; + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("ВерсияСтруктурыКэша") + И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") + И Значения.Свойство("ВерсииОграниченийСписков") + И ТипЗнч(Значения.ВерсииОграниченийСписков) = Тип("ФиксированноеСоответствие") + И Значения.Свойство("ВедущиеСписки") + И ТипЗнч(Значения.ВедущиеСписки) = Тип("ФиксированноеСоответствие") + И Значения.Свойство("ДополнительныйКонтекст") + И ТипЗнч(Значения.ДополнительныйКонтекст) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("СпискиСДатой") + И ТипЗнч(Значения.СпискиСДатой) = Тип("ФиксированноеСоответствие") + И Значения.Свойство("ВнешниеПользователиВключены") + И ТипЗнч(Значения.ВнешниеПользователиВключены) = Тип("Булево") + И Значения.Свойство("ОграничениеДоступаВключено") + И ТипЗнч(Значения.ОграничениеДоступаВключено) = Тип("Булево") + И Значения.Свойство("ИспользуемыеТипыЗначений") + И ТипЗнч(Значения.ИспользуемыеТипыЗначений) = Тип("ХранилищеЗначения") + И Значения.Свойство("ВерсияТекстовОграниченияДоступа") + И ТипЗнч(Значения.ВерсияТекстовОграниченияДоступа) = Тип("Строка") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеПараметрыЗаписи, Значения); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыЗаписи); + +КонецФункции + +// Для функций СтруктураХранимыхПараметровЗаписи и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииОграниченийСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Строка - общая версия ограничения списка +// первая строка - хеш-сумма свойств версии для пользователей и через Символы.ПС +// вторая строка - хеш-сумма свойств версии для внешних пользователей. +// +// * ВедущиеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СвойстваСпискаКакВедущего +// +// * ДополнительныйКонтекст - Структура: +// ** ДляПользователей - см. НовыйХранимыйДополнительныйКонтекст +// ** ДляВнешнихПользователей - см. НовыйХранимыйДополнительныйКонтекст +// +// * СпискиСДатой - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ВнешниеПользователиВключены - Булево +// * ОграничениеДоступаВключено - Булево +// * ИспользуемыеТипыЗначений - ХранилищеЗначения - смотри функцию ИспользуемыеТипыЗначений. +// * ВерсияТекстовОграниченияДоступа - Строка +// +Функция НоваяСтруктураХранимыхПараметровЗаписи() Экспорт + + ХранимыеПараметрыЗаписи = Новый Структура; + ХранимыеПараметрыЗаписи.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); + ХранимыеПараметрыЗаписи.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ВедущиеСписки", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ДополнительныйКонтекст", Новый Структура); + ХранимыеПараметрыЗаписи.Вставить("СпискиСДатой", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ВедущиеРоли", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ВнешниеПользователиВключены", Ложь); + ХранимыеПараметрыЗаписи.Вставить("ОграничениеДоступаВключено", Ложь); + ХранимыеПараметрыЗаписи.Вставить("ИспользуемыеТипыЗначений", Новый ХранилищеЗначения(Новый Соответствие)); + ХранимыеПараметрыЗаписи.Вставить("ВерсияТекстовОграниченияДоступа", ""); + + Возврат ХранимыеПараметрыЗаписи; + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииШаблонов - см. ВерсииШаблоновОграниченияДоступа +// * ПараметрыШаблонов - см. СтруктураПараметровШаблонов +// +Функция СтруктураХранимыхПараметровШаблонов(Значения) + + ХранимыеПараметрыШаблонов = НоваяСтруктураХранимыхПараметровШаблонов(); + ХранимыеПараметрыШаблонов.ВерсияСтруктурыКэша = ""; + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("ВерсияСтруктурыКэша") + И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") + И Значения.Свойство("ВерсииШаблонов") + И ТипЗнч(Значения.ВерсииШаблонов) = Тип("Строка") + И Значения.Свойство("ПараметрыШаблонов") + И ТипЗнч(Значения.ПараметрыШаблонов) = Тип("ФиксированнаяСтруктура") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеПараметрыШаблонов, Значения); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыШаблонов); + +КонецФункции + +// Для функций СтруктураХранимыхПараметровШаблонов, СтруктураХранимыхПараметровЗаписи и +// ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииШаблонов - см. ВерсииШаблоновОграниченияДоступа +// * ПараметрыШаблонов - см. СтруктураПараметровШаблонов +// +Функция НоваяСтруктураХранимыхПараметровШаблонов() + + ХранимыеПараметрыШаблонов = Новый Структура; + ХранимыеПараметрыШаблонов.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); + ХранимыеПараметрыШаблонов.Вставить("ВерсииШаблонов", ВерсииШаблоновОграниченияДоступа()); + ХранимыеПараметрыШаблонов.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); + + Возврат ХранимыеПараметрыШаблонов; + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - Строка +// * СпискиСОграничениемЧерезКлючиДоступаПользователей - Строка +// * СпискиСОграничениемПоПолям - Строка +// * СпискиСОтключеннымОграничениемЧтения - Строка +// +Функция СтруктураПараметровШаблонов(Значения) + + ПараметрыШаблонов = НоваяСтруктураПараметровШаблонов(); + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Количество() = ПараметрыШаблонов.Количество() Тогда + + Совпадает = Истина; + Для Каждого КлючИЗначение Из ПараметрыШаблонов Цикл + Если Не Значения.Свойство(КлючИЗначение.Ключ) + Или Не ТипЗнч(Значения[КлючИЗначение.Ключ]) = ТипЗнч(КлючИЗначение.Значение) Тогда + Совпадает = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если Совпадает Тогда + ЗаполнитьЗначенияСвойств(ПараметрыШаблонов, Значения); + КонецЕсли; + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ПараметрыШаблонов); + +КонецФункции + +// Для функций СтруктураПараметровШаблонов, ХранимыеПараметрыОграниченияДоступа и +// НоваяСтруктураХранимыхПараметровШаблонов. +// +// Возвращаемое значение: +// Структура: +// * СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - Строка +// * СпискиСОграничениемЧерезКлючиДоступаПользователей - Строка +// * СпискиСОграничениемПоПолям - Строка +// * СпискиСОтключеннымОграничениемЧтения - Строка +// +Функция НоваяСтруктураПараметровШаблонов() + + ПараметрыШаблонов = Новый Структура; + ПараметрыШаблонов.Вставить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа", ""); + ПараметрыШаблонов.Вставить("СпискиСОграничениемЧерезКлючиДоступаПользователей", ""); + ПараметрыШаблонов.Вставить("СпискиСОграничениемПоПолям", ""); + ПараметрыШаблонов.Вставить("СпискиСОтключеннымОграничениемЧтения", ""); + + Возврат ПараметрыШаблонов; + +КонецФункции + +// Для процедур УстановитьВерсиюПараметров и ЗаполнитьПараметрыДляШаблонов. +// +// Возвращаемое значение: +// см. НоваяСтруктураХранимыхВерсийПараметровШаблонов +// +Функция СтруктураХранимыхВерсийПараметровШаблонов(Значения) + + ХранимыеВерсийПараметровШаблонов = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + ХранимыеВерсийПараметровШаблонов.ВерсияСтруктурыВерсий = ""; + + Если ТипЗнч(Значения) = Тип("Структура") + И Значения.Свойство("ВерсияСтруктурыВерсий") + И ТипЗнч(Значения.ВерсияСтруктурыВерсий) = Тип("Строка") + И Значения.Свойство("ДляПользователей") + + И ТипЗнч(Значения.ДляПользователей) = Тип("Структура") + И Значения.ДляПользователей.Свойство("ВерсииПараметровШаблонов") + И ТипЗнч(Значения.ДляПользователей.ВерсииПараметровШаблонов) = Тип("Соответствие") + И Значения.ДляПользователей.Свойство("ОсновныеВариантыДоступа") + И ТипЗнч(Значения.ДляПользователей.ОсновныеВариантыДоступа) = Тип("Соответствие") + + И Значения.Свойство("ДляВнешнихПользователей") + И ТипЗнч(Значения.ДляВнешнихПользователей) = Тип("Структура") + И Значения.ДляВнешнихПользователей.Свойство("ВерсииПараметровШаблонов") + И ТипЗнч(Значения.ДляВнешнихПользователей.ВерсииПараметровШаблонов) = Тип("Соответствие") + И Значения.ДляВнешнихПользователей.Свойство("ОсновныеВариантыДоступа") + И ТипЗнч(Значения.ДляВнешнихПользователей.ОсновныеВариантыДоступа) = Тип("Соответствие") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеВерсийПараметровШаблонов, Значения); + КонецЕсли; + + Возврат ХранимыеВерсийПараметровШаблонов; + +КонецФункции + +// Для функций ХранимыеПараметрыОграниченияДоступа, СтруктураХранимыхВерсийПараметровШаблонов и +// процедуры ЗаполнитьПараметрыДляШаблонов. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыВерсий - см. ВерсияСтруктурыВерсийПараметровШаблонов +// * ДляПользователей - Структура: +// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов +// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// * ДляВнешнихПользователей - Структура: +// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов +// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// +Функция НоваяСтруктураХранимыхВерсийПараметровШаблонов() + + ДляПользователей = Новый Структура; + ДляПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + ДляПользователей.Вставить("ОсновныеВариантыДоступа", НовыеОсновныеВариантыДоступа()); + + ДляВнешнихПользователей = Новый Структура; + ДляВнешнихПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + ДляВнешнихПользователей.Вставить("ОсновныеВариантыДоступа", НовыеОсновныеВариантыДоступа()); + + ХранимыеПараметрыШаблонов = Новый Структура; + ХранимыеПараметрыШаблонов.Вставить("ВерсияСтруктурыВерсий", ВерсияСтруктурыВерсийПараметровШаблонов()); + ХранимыеПараметрыШаблонов.Вставить("ДляПользователей", ДляПользователей); + ХранимыеПараметрыШаблонов.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + + Возврат ХранимыеПараметрыШаблонов; + +КонецФункции + +// Для функций ХранимыеПараметрыОграниченияДоступа и +// НоваяСтруктураХранимыхВерсийПараметровШаблонов. +// +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - полное имя регистра. +// * Значение - Массив из см. НоваяВерсияПараметровШаблонов +// +Функция НовыеВерсииПараметровШаблонов() + + Возврат Новый Соответствие; + +КонецФункции + +// Для функции НовыеВерсииПараметровШаблонов и процедуры НастроитьПараметрыШаблонов. +// +// Возвращаемое значение: +// Структура: +// * ДатаСоздания - Дата - момент добавления новой версии. +// * Список - Строка - полное имя объекта метаданных. +// * ПоляСоединения - Строка - список полей, используемых в соединении. +// * ПоляШаблона - Строка - список полей, указанных в шаблоне #ДляРегистра. +// * Используется - Булево - признак того, что версия используется в шаблонах. +// * ВариантДоступа - Число - значение поля ВариантДоступа в регистрах КлючиДоступаКРегистрам, +// КлючиДоступаКРегистру*. +// +Функция НоваяВерсияПараметровШаблонов() + + ВерсияПараметров = Новый Структура; + ВерсияПараметров.Вставить("ДатаСоздания", '00010101'); + ВерсияПараметров.Вставить("Список", ""); + ВерсияПараметров.Вставить("ПоляСоединения", ""); + ВерсияПараметров.Вставить("ПоляШаблона", ""); + ВерсияПараметров.Вставить("Используется", Истина); + ВерсияПараметров.Вставить("ВариантДоступа", 0); + + Возврат ВерсияПараметров; + +КонецФункции + +// Для функции НоваяСтруктураХранимыхВерсийПараметровШаблонов. +// +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - полное имя регистра. +// * Значение - Массив из см. НовыйИспользуемыйВариантДоступа +// +Функция НовыеОсновныеВариантыДоступа() + + Возврат Новый Соответствие; + +КонецФункции + +// Для функции ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +// +// Возвращаемое значение: +// Структура: +// * ВариантДоступа - Число - значение поля ВариантДоступа +// в регистрах КлючиДоступаКРегистрам, КлючиДоступаКРегистру*, +// начиная с основного варианта доступа. +// * ПоляСоединения - Строка - имена полей соединения для варианта доступа через запятую. +// +Функция НовыйИспользуемыйВариантДоступа() + + Возврат Новый Структура("ВариантДоступа, ПоляСоединения"); + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВидыОграниченийПравДляПользователей - Строка +// * ВидыОграниченийПравДляВнешнихПользователей - Строка +// +Функция СтруктураХранимыхПараметровОтчета(Значения) + + ХранимыеПараметрыОтчета = НоваяСтруктураХранимыхПараметровОтчета(); + ХранимыеПараметрыОтчета.ВерсияСтруктурыКэша = ""; + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("ВерсияСтруктурыКэша") + И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") + И Значения.Свойство("ВидыОграниченийПравДляПользователей") + И ТипЗнч(Значения.ВидыОграниченийПравДляПользователей) = Тип("Строка") + И Значения.Свойство("ВидыОграниченийПравДляВнешнихПользователей") + И ТипЗнч(Значения.ВидыОграниченийПравДляВнешнихПользователей) = Тип("Строка") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеПараметрыОтчета, Значения); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыОтчета); + +КонецФункции + +// Для функций СтруктураХранимыхПараметровОтчета и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВидыОграниченийПравДляПользователей - Строка +// * ВидыОграниченийПравДляВнешнихПользователей - Строка +// +Функция НоваяСтруктураХранимыхПараметровОтчета() + + ХранимыеПараметрыОтчета = Новый Структура; + ХранимыеПараметрыОтчета.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); + ХранимыеПараметрыОтчета.Вставить("ВидыОграниченийПравДляПользователей", ""); + ХранимыеПараметрыОтчета.Вставить("ВидыОграниченийПравДляВнешнихПользователей", ""); + + Возврат ХранимыеПараметрыОтчета; + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Функция ВидыОграниченийПравСтрокой(ВидыОграниченийПрав) + + Список = Новый СписокЗначений; + Для Каждого КлючИЗначение Из ВидыОграниченийПрав Цикл + Список.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + Список.СортироватьПоЗначению(); + ВидыОграниченийСтрокой = СтрСоединить(Список.ВыгрузитьЗначения(), Символы.ПС); + + Возврат ВидыОграниченийСтрокой; + +КонецФункции + +#КонецОбласти + +#Область ПараметрыОграниченияДоступаДляСпискаОтдельно + +// Основная функция области, возвращающая параметры ограничения доступа +// для вида пользователей списка без учета зависимости от других списков, +// как по ключам доступа, так и по наличию видов доступа Пользователи и ВнешниеПользователи. +// +// Возвращаемое значение: +// Структура: +// * Список - Строка - полное имя таблицы объекта метаданных. +// * ДляВнешнихПользователей - Булево - вид пользователей, для которых предназначены параметры. +// * Версия - Строка - хеш-сумма параметров ограничения доступа для отслеживания их изменения. +// * ВедущиеСписки - см. НовыеВедущиеСписки +// * ДоступЗапрещен - Булево - Истина, если текст ограничения "ГДЕ ЛОЖЬ", +// а также не указан для внешних пользователей. +// * ОграничениеОтключено - Булево - Истина, если текст ограничения не указан или указан, +// но ограничение отключено из-за отключения использования +// видов доступа, задействованных в нем. +// * ОграничениеЧтенияОтключено - Булево - Истина, если текст ограничения чтения не указан или указан, +// но ограничение отключено из-за отключения использования +// видов доступа, задействованных в нем. +// +// Поле владельца, когда возможно ограничение только по объекту-владельцу. +// * ПолеВладельца - см. НовоеПолеВладельца +// +// * ТребуетсяОграничениеПоВладельцу - Булево - признак оптимизации, указанный разработчиком +// рядом с текстом ограничения. +// * ИспользуетсяОграничениеПоВладельцу - Булево - признак использования оптимизации, +// вычисленный на втором проходе графа. +// * РассчитыватьПраваПользователей - Булево - признак расчета прав на ключи доступа для пользователей, +// а не для групп доступа, вычисленный на втором проходе графа. +// Имеет смысл только, когда признак +// ИспользуетсяОграничениеПоВладельцу = Ложь. +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево - признак того, что ведущий список должен записывать +// ключи для зависимых списков, которые не записывают +// своих ключей. Признак вычисляется на втором проходе графа. +// * БезОбновленияКлючейДоступаКОбъектам - Булево - когда Истина, запись связи объекта с ключом доступа +// пропускается так как тип списка не указан +// в определяемом типе ВладелецЗначенийКлючейДоступа. +// * БезОбновленияВсехКомбинацийЗначенийОпорныхПолей - Булево - когда Истина, запись связи строки регистра с ключом +// доступа пропускается, если тип значения опорного поля регистра не +// указан в определяемом типе ПолеРегистраКлючейДоступаКРегистрам +// или типе соответствующего поля отдельного регистра ключей. +// * ЧтениеРазрешеноДляВсехПользователей - Булево - признак, вычисленный на втором проходе графа. +// Когда ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина, +// тогда показывает наличие права Чтение в одной из ролей +// БазовыеПрава* или БазовыеПраваВнешнихПользователей*. +// * ИзменениеРазрешеноДляВсехПользователей - Булево - признак, вычисленный на втором проходе графа. +// Когда ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина, +// тогда показывает наличие права Изменение в одной из ролей +// БазовыеПрава* или БазовыеПраваВнешнихПользователей*. +// * ЕстьВедущиеКлючиДоступа - Булево - признак наличия ведущих ключей доступа в ограничении. +// * ЕстьВедущиеСпискиПоПравам - Булево - признак наличия ведущих списков по правам в ограничении. +// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево - признак наличия перечисленных функций в ограничении. +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие - типы владельцев настроек прав, используемые +// при расчете прав на ключи доступа (см. ПоТипамСсылок). +// * ИдентификаторТаблицыНастроекПрав - СправочникСсылка.ИдентификаторыОбъектовМетаданных - идентификатор +// списка, если для него используются отдельные настройки прав +// или пустой идентификатор. +// * ЕстьВладельцыНастроекПрав - Булево - признак наличия ограничения по владельцу настроек прав. +// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип - описание типов значений доступа, +// которые используются в ограничении доступа. +// * ВсеВидыОграниченийПрав - Соответствие - все виды ограничений прав без учета использования. +// * ПоляТаблицОбъекта - Массив из см. НовыеПоляТаблицыОбъекта +// * ИмяОтдельногоРегистраКлючей - Строка - для регистров. +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ВариантДоступа - Число - основной вариант доступа смотри также НовыеОсновныеВариантыДоступа. +// * СоставПолей - Число - число, описывающее реквизиты, используемые в ключе. +// * ЕстьОграничениеЧтения - Булево - установлено, если ограничение чтения отличается от "ГДЕ ИСТИНА". +// * ЕстьОграничениеИзменения - Булево - установлено, если ограничение изменения отличается от "ГДЕ ИСТИНА". +// * ЕстьОграничениеПоПользователям - Булево - установлено, если проверяются значения Пользователь +// или ГруппаПользователей или ВнешнийПользователь +// или ГруппаВнешнихПользователей для функций +// ЗначениеРазрешено или ЭтоАвторизованныйПользователь. +// * СтруктураРасчетаПраваЧтение - см. СтруктураРасчетаПрава +// * СтруктураРасчетаПраваИзменение - см. СтруктураРасчетаПрава +// * Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Функция ПараметрыОграниченияПоСтруктуреОграничения(Список, СтруктураОграничения, + ДляВнешнихПользователей, ОбщийКонтекст, ДополнительныйКонтекст) + + ВедущиеСписки = НовыеВедущиеСписки(); + + Результат = Новый Структура; + Результат.Вставить("Список", Список); + Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Результат.Вставить("Версия", ""); + Результат.Вставить("ВедущиеСписки", ВедущиеСписки); + Результат.Вставить("ДоступЗапрещен", ДляВнешнихПользователей); + Результат.Вставить("ОграничениеОтключено", Не ДляВнешнихПользователей); + Результат.Вставить("ОграничениеЧтенияОтключено", Не ДляВнешнихПользователей); + Результат.Вставить("ПолеВладельца"); + Результат.Вставить("ТребуетсяОграничениеПоВладельцу", Ложь); + Результат.Вставить("ИспользуетсяОграничениеПоВладельцу", Ложь); + Результат.Вставить("РассчитыватьПраваПользователей", Ложь); + Результат.Вставить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Ложь); + Результат.Вставить("БезОбновленияКлючейДоступаКОбъектам", Ложь); + Результат.Вставить("БезОбновленияВсехКомбинацийЗначенийОпорныхПолей", Ложь); + Результат.Вставить("ЧтениеРазрешеноДляВсехПользователей", Ложь); + Результат.Вставить("ИзменениеРазрешеноДляВсехПользователей", Ложь); + Результат.Вставить("ЕстьВедущиеКлючиДоступа", Ложь); + Результат.Вставить("ЕстьВедущиеСпискиПоПравам", Ложь); + Результат.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступна", Ложь); + Результат.Вставить("ТипыВладельцевНастроекПрав", ОбщийКонтекст.ТипыВладельцевНастроекПрав); + Результат.Вставить("ИдентификаторТаблицыНастроекПрав", Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка()); + Результат.Вставить("ЕстьВладельцыНастроекПрав", Ложь); + Результат.Вставить("ИспользуемыеТипыЗначенийДоступа", Новый Массив); + Результат.Вставить("ВсеВидыОграниченийПрав", Новый Соответствие); + Результат.Вставить("ПоляТаблицОбъекта", Новый Массив); + Результат.Вставить("ИмяОтдельногоРегистраКлючей", ""); + Результат.Вставить("ОпорныеПоля"); + Результат.Вставить("ВариантДоступа"); + Результат.Вставить("СоставПолей"); + Результат.Вставить("ЕстьОграничениеЧтения", Ложь); + Результат.Вставить("ЕстьОграничениеИзменения", Ложь); + Результат.Вставить("ЕстьОграничениеПоПользователям", Ложь); + Результат.Вставить("СтруктураРасчетаПраваЧтение", СтруктураРасчетаПрава()); + Результат.Вставить("СтруктураРасчетаПраваИзменение", СтруктураРасчетаПрава()); + + ИмяКоллекцииТипа = ""; + Результат.Вставить("ЭтоСсылочныйТип", ?(ЗначениеЗаполнено(Список), + ЭтоСсылочныйТипТаблицы(Список, ИмяКоллекцииТипа), Ложь)); + + Результат.Вставить("СписокСДатой", + ИмяКоллекцииТипа = "Документы" + Или ИмяКоллекцииТипа = "БизнесПроцессы" + Или ИмяКоллекцииТипа = "Задачи"); + + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Список); + + Если Результат.ЭтоСсылочныйТип И ОбъектМетаданных <> Неопределено Тогда + ТипПоля = Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект.Тип; + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + ТипСсылки = Тип(ИмяТипаСсылки(Список, ТипыТаблицПоИменам)); + Если Не ТипПоля.СодержитТип(ТипСсылки) Тогда + Результат.БезОбновленияКлючейДоступаКОбъектам = Истина; + КонецЕсли; + КонецЕсли; + + Если ИмяКоллекцииТипа = "РегистрыСведений" Тогда + Результат.Вставить("СписокСПериодом", ?(ОбъектМетаданных = Неопределено, Ложь, + ОбъектМетаданных.ПериодичностьРегистраСведений + <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический)); + Иначе + Результат.Вставить("СписокСПериодом", + ИмяКоллекцииТипа = "РегистрыНакопления" + Или ИмяКоллекцииТипа = "РегистрыБухгалтерии" + Или ИмяКоллекцииТипа = "РегистрыРасчета"); + КонецЕсли; + + Контекст = КонтекстПараметровПоСтруктуреОграничения(); + Контекст.Вставить("СтрокаСвойствВерсии", ""); + Результат.Вставить("Контекст", Контекст); + + Для Каждого КлючИЗначение Из ОбщийКонтекст Цикл + Контекст.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Для Каждого КлючИЗначение Из ДополнительныйКонтекст Цикл + Контекст.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + + Контекст.Вставить("Список", Список); + Контекст.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Контекст.Вставить("ЭтоСсылочныйТип", Результат.ЭтоСсылочныйТип); + Контекст.Вставить("СписокСДатой", Результат.СписокСДатой); + Контекст.Вставить("СписокСПериодом", Результат.СписокСПериодом); + Контекст.Вставить("ИмяКоллекцииТипа", ИмяКоллекцииТипа); + Контекст.Вставить("СвойстваВерсии", Новый Массив); + Контекст.Вставить("ВедущиеРоли", Новый Соответствие); + + ДобавитьСвойствоВерсии(Контекст, Контекст, "Список"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ДляВнешнихПользователей"); + + ОписаниеОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список); + Если ОписаниеОграничения = Неопределено Тогда + ОписаниеОграничения = Новый Структура("Текст", ""); + КонецЕсли; + ДобавитьСвойствоВерсии(Контекст, ОписаниеОграничения, "Текст"); + + ДобавитьСвойствоВерсии(Контекст, Контекст, "ЭтоСсылочныйТип"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "СписокСДатой"); + + // Поля таблиц требуются только для ссылочных объектов. + Контекст.Вставить("ПоляТаблицОбъекта", НовоеОписаниеПолейТаблицОбъекта(Результат)); + + // Опорные поля не требуются для ссылочных типов данных (всегда Ссылка). + ЗаполнитьНовоеОписаниеОпорныхПолей(Результат, Контекст); + + Контекст.Вставить("БезОбъектаМетаданных", ОбъектМетаданных = Неопределено); + + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено Тогда + Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); + Результат.РассчитыватьПраваПользователей = Свойства.РассчитыватьПраваПользователей; + Результат.ИспользуетсяОграничениеПоВладельцу = Свойства.ПолеВладельца <> Неопределено + И Не Свойства.ПолеВладельца.Отключено; + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(Список) <> Неопределено Тогда + Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина; + Результат.ЧтениеРазрешеноДляВсехПользователей = + ПравоРазрешеноДляВсехПользователей("Чтение", ОбъектМетаданных, ДляВнешнихПользователей); + Результат.ИзменениеРазрешеноДляВсехПользователей = + ПравоРазрешеноДляВсехПользователей("Изменение", ОбъектМетаданных, ДляВнешнихПользователей); + КонецЕсли; + КонецЕсли; + Контекст.Вставить("ИспользуетсяОграничениеПоВладельцу", Результат.ИспользуетсяОграничениеПоВладельцу); + Контекст.Вставить("РассчитыватьПраваПользователей", Результат.РассчитыватьПраваПользователей); + Контекст.Вставить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа); + Контекст.Вставить("ЧтениеРазрешеноДляВсехПользователей", Результат.ЧтениеРазрешеноДляВсехПользователей); + Контекст.Вставить("ИзменениеРазрешеноДляВсехПользователей", Результат.ИзменениеРазрешеноДляВсехПользователей); + + Если СтруктураОграничения = Неопределено Тогда + Если Не Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа + Или Результат.ДоступЗапрещен + Или Контекст.БезОбъектаМетаданных Тогда + Возврат Результат; + КонецЕсли; + СтруктураОграничения = РассчитаннаяСтруктураОграничения(Список, + "РазрешитьЧтениеИзменение ГДЕ ИСТИНА", Истина, ДляВнешнихПользователей); + КонецЕсли; + + Контекст.Вставить("СтруктураОграничения", СтруктураОграничения); + Контекст.Вставить("ВедущиеСпискиПоЗначениямПолей", ОписаниеВедущихСписковПоЗначениямПолей()); + Контекст.Вставить("ВедущиеСпискиПоКлючамДоступа", ОписаниеВедущихСписковПоПолюСсылка()); + Контекст.Вставить("ВедущиеСпискиПоЗначениямСГруппами", ОписаниеВедущихСписковПоПолюСсылка()); + Контекст.Вставить("ЕстьПроверкаАвторизованногоПользователя", Ложь); + Контекст.Вставить("НеиспользуемыеТипыЗначенийДоступа", Новый Массив); + Контекст.Вставить("ВсеВидыОграниченийПрав", Результат.ВсеВидыОграниченийПрав); + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Результат.ИмяОтдельногоРегистраКлючей = Контекст.ИмяОтдельногоРегистраКлючей; + КонецЕсли; + + ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, Ложь); + ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения(Результат, Контекст); + + ЗаполнитьСвойстваПолей(Контекст); + + Результат.ЕстьФункцияПравоДоступаИлиРольДоступна = Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна; + + Если ДляВнешнихПользователей И Не ОбщийКонтекст.ВнешниеПользователиВключены + Или ЭтоБезусловноеОграничение(Контекст, Результат) Тогда + + Результат.ДоступЗапрещен = Истина; + Результат.Версия = " "; + Возврат Результат; + КонецЕсли; + + Результат.ДоступЗапрещен = Ложь; + Результат.ОграничениеОтключено = Истина; + Результат.ОграничениеЧтенияОтключено = Истина; + + ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, Истина); + ЗаполнитьОграничениеПоОбъектуВладельцуПослеУпрощения(Результат, Контекст); + ЗаполнитьНаличиеВедущихКлючейИСписковИВладельцевНастроекПрав(Результат, Контекст); + УдалитьПоляНеиспользуемыхВидовДоступа(Результат, Контекст); + ЗаполнитьНаличиеОграниченияПоВидуДоступаПользователи(Результат, Контекст); + ЗаполнитьНаличиеОграниченияЧтения(Результат, Контекст); + + Контекст.Вставить("ЕстьОграничениеПоПользователям", Результат.ЕстьОграничениеПоПользователям); + + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Неопределено Тогда + Результат.РассчитыватьПраваПользователей = Результат.ЕстьОграничениеПоПользователям; + Результат.ИспользуетсяОграничениеПоВладельцу = Результат.ПолеВладельца <> Неопределено + И Не Результат.ПолеВладельца.Отключено; + + Контекст.Вставить("ИспользуетсяОграничениеПоВладельцу", Результат.ИспользуетсяОграничениеПоВладельцу); + Контекст.Вставить("РассчитыватьПраваПользователей", Результат.РассчитыватьПраваПользователей); + КонецЕсли; + ДобавитьСвойствоВерсии(Контекст, Контекст, "ИспользуетсяОграничениеПоВладельцу"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "РассчитыватьПраваПользователей"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ЧтениеРазрешеноДляВсехПользователей"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ИзменениеРазрешеноДляВсехПользователей"); + + Контекст.Вставить("ГруппыПолей"); + Контекст.Вставить("ПсевдонимыТабличныхЧастейОбъекта"); + Контекст.Вставить("ГруппыДополнительныхТаблиц"); + Контекст.Вставить("КоличествоТабличныхЧастейКлюча"); + + ЗаполнитьГруппыПолейИДополнительныхТаблиц(Контекст); + + Результат.СоставПолей = Контекст.СоставПолей; + + Если Результат.Контекст.СвойстваПолей.Количество() = 0 + И (Не Результат.ЭтоСсылочныйТип + Или Не Результат.ЕстьФункцияПравоДоступаИлиРольДоступна) Тогда // Ограничение отключено. + + Если Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа Тогда + НастроитьСозданиеКлючаДоступаДляЗависимыхСписковБезКлючей(Результат); + Если Контекст.СпискиСОграничением.Получить(Результат.Список) = Неопределено Тогда + Результат.Версия = " "; + Иначе + Результат.Версия = " "; + КонецЕсли; + Иначе + Результат.Версия = " "; + КонецЕсли; + КонецЕсли; + + Если Результат.Версия <> " " И Результат.БезОбновленияКлючейДоступаКОбъектам Тогда + ДобавитьСвойствоВерсии(Контекст, Результат, "БезОбновленияКлючейДоступаКОбъектам"); + КонецЕсли; + Если Результат.Версия <> " " + И Контекст.ИмяКоллекцииТипа <> "ЖурналыДокументов" + И УправлениеДоступомСлужебныйПовтИсп.ТаблицыВПодпискахПроверитьДоступ().Получить(Список) = Неопределено Тогда + ДобавитьЭлементВерсии(Контекст, "ОбъектВПодпискахПроверитьДоступ", Ложь) + КонецЕсли; + + Если Результат.Версия <> "" Тогда + Возврат Результат; + КонецЕсли; + + ЗаполнитьНедостающиеТипыОпорныхПолей(Результат, Контекст); + + Результат.ОграничениеОтключено = Ложь; + + Контекст.Вставить("ИмяПрава", "Чтение"); + ЗаполнитьСтруктуруРасчетаПрава(Результат.СтруктураРасчетаПраваЧтение, + Контекст.СтруктураОграничения.ОграничениеЧтения, Контекст); + + Контекст.Вставить("ИмяПрава", "Изменение"); + ЗаполнитьСтруктуруРасчетаПрава(Результат.СтруктураРасчетаПраваИзменение, + Контекст.СтруктураОграничения.ОграничениеИзменения, Контекст); + + Контекст.Удалить("ИмяПрава"); + ДобавитьСвойствоВерсииВедущиеРоли(Контекст); + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + Контекст.ВедущиеСпискиПоЗначениямПолей = ОписаниеВедущихСписковПоЗначениямПолей(); + КонецЕсли; + ВедущиеСписки.ПоЗначениямПолей = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля; + ВедущиеСписки.ПоКлючамДоступа = Контекст.ВедущиеСпискиПоКлючамДоступа.Списки; + ВедущиеСписки.ПоЗначениямСГруппами = Контекст.ВедущиеСпискиПоЗначениямСГруппами.Списки; + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + СтрокаСвойствВерсии = СтрСоединить(Контекст.СвойстваВерсии, Символы.ПС); + Контекст.СтрокаСвойствВерсии = СтрокаСвойствВерсии; + ХешированиеДанных.Добавить(СтрокаСвойствВерсии); + Результат.Версия = Base64Строка(ХешированиеДанных.ХешСумма); + + Возврат Результат; + +КонецФункции + +// Списки с полями от которых зависит ограничение доступа. +// +// Возвращаемое значение: +// Структура: +// * ПоЗначениямПолей - Соответствие - списки с полями, от которых зависит ограничение доступа +// (для регистрации заданий обновления). +// * ПоКлючамДоступа - Соответствие - списки от ключей доступа которых зависит ограничение доступа +// (для установки параметров сеанса и регистрации заданий обновления). +// * ПоЗначениямСГруппами - Соответствие - списки значений доступа с группами, от которых зависит +// ограничение доступа (для регистрации заданий обновления). +// +Функция НовыеВедущиеСписки() + + ВедущиеСписки = Новый Структура; + ВедущиеСписки.Вставить("ПоЗначениямПолей", Новый Соответствие); + ВедущиеСписки.Вставить("ПоКлючамДоступа", Новый Соответствие); + ВедущиеСписки.Вставить("ПоЗначениямСГруппами", Новый Соответствие); + + Возврат ВедущиеСписки; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * СтрокаСвойствВерсии - Строка +// * Список - Строка +// * ДляВнешнихПользователей - Булево +// * ЭтоСсылочныйТип - Булево +// * СписокСДатой - Булево +// * СписокСПериодом - Булево +// * ИмяКоллекцииТипа - Строка +// * СвойстваВерсии - Массив из Строка +// * ПоляТаблицОбъекта - см. НовоеОписаниеПолейТаблицОбъекта +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ВариантДоступа - Число - основной вариант доступа смотри также НовыеОсновныеВариантыДоступа. +// * ИспользуетсяОграничениеПоВладельцу - Булево +// * РассчитыватьПраваПользователей - Булево +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево +// * ЧтениеРазрешеноДляВсехПользователей - Булево +// * ИзменениеРазрешеноДляВсехПользователей - Булево +// * БезОбъектаМетаданных - Булево +// * СтруктураОграничения - см. СтруктураОграничения +// * ИсходнаяСтруктураОграничения - см. СтруктураОграничения +// * ВедущиеСпискиПоЗначениямПолей - см. ОписаниеВедущихСписковПоЗначениямПолей +// * ВедущиеСпискиПоКлючамДоступа - см. ОписаниеВедущихСписковПоПолюСсылка +// * ВедущиеСпискиПоЗначениямСГруппами - см. ОписаниеВедущихСписковПоПолюСсылка +// * ЕстьПроверкаАвторизованногоПользователя - Булево +// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево +// * ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения - Булево +// * НеиспользуемыеТипыЗначенийДоступа - Массив из Тип +// * ВсеВидыОграниченийПрав - Соответствие +// * ЕстьОграничениеПоПользователям - Булево +// * ИспользуетсяОграничениеПоВладельцу - Булево +// * РассчитыватьПраваПользователей - Булево +// * СвойстваВсехПолей - Соответствие из КлючИЗначение: +// ** Ключ - см. ОписаниеУзла +// ** Значение - см. СвойстваПоля +// * ОставшиесяПоляПослеУпрощения - Соответствие из КлючИЗначение: +// ** Ключ - см. ОписаниеУзла +// ** Значение - Массив из см. ОписаниеУзла +// * ПоляКлючаДоступаПослеУпрощения - Массив из см. НовоеПолеКлючаДоступа +// * СвойстваПолейКлючаДоступа - Соответствие из КлючИЗначение: +// ** Ключ - см. ОписаниеУзла +// ** Значение - см. СвойстваПоля +// * ГруппыПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя группы полей (Шапка?, ТабличнаяЧасть?) +// ** Значение - Массив из см. СвойстваПоля +// * ПсевдонимыТабличныхЧастейОбъекта - Соответствие из КлючИЗначение: +// ** Ключ - Число - номер табличной части ключа +// ** Значение - Строка - псевдоним таблицы +// * ГруппыДополнительныхТаблиц - см. ГруппыДополнительныхТаблиц +// * КоличествоТабличныхЧастейКлюча - Число +// * ПоляУсловияСоединенияДополнительныхТаблиц - Массив из Структура: +// ** УзелПоле - см. ОписаниеУзла +// ** ПсевдонимТаблицыУсловия - Строка +// * ИмяПрава - Строка +// * ТребуемыеРеквизитыТабличныхЧастейКлюча - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя таблицы ключа (ИмяГруппыПолейКлючаДоступа) +// ** Значение - Массив из Строка - имя реквизита таблицы ключа (ИмяРеквизитаГруппыПолейКлючаДоступа) +// * СтруктураРасчетаПраваСвойстваВерсии - Массив из Строка +// * ВедущиеРоли - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя роли +// ** Значение - Булево - значение Истина. +// +// Свойства, скопированные от ОбщийКонтекст: +// * СвойстваВидовДоступа - см. СвойстваВидовДоступа +// * ТипыПользователя - Массив из Тип +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ОтдельныеТаблицыНастроекПрав - ФиксированноеСоответствие +// * ИспользуемыеТипыЗначений - см. ИспользуемыеТипыЗначений +// * СпискиСОграничением - см. УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением +// * ВнешниеПользователиВключены - Булево +// +// Свойства, скопированные от ДополнительныйКонтекст: +// * ОписанияОграничений - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СокращенноеОписаниеОграничения +// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * СпискиСОграничениемПоВладельцу - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - значение ПоВладельцу, кроме Неопределено. +// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// +Функция КонтекстПараметровПоСтруктуреОграничения() + + Возврат Новый Структура; + +КонецФункции + +// Структура ограничения, приведенную к формату размещения значений в ключах доступа. +// +// Возвращаемое значение: +// Структура: +// * Узел - Строка - одна из строк "Поле", "Константа", "И", "Или", "Не", "Выбор", +// "ЗначениеРазрешено", "ЭтоАвторизованныйПользователь", +// "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено", +// "ЧтениеСпискаРазрешено", "ИзменениеСпискаРазрешено", +// "ДляВсехСтрок", "ДляОднойИзСтрок". +// +// Свойства узла Поле. +// * Таблица - Строка - таблица ключа доступа (Шапка?, ТабличнаяЧасть?). +// * Реквизит - Строка - имя реквизита таблицы ключа доступа (Реквизит?). +// * ПроверкаЕстьNull - Булево - Истина (необязательное свойство). +// +// Свойства узла Константа. +// * Значение - Булево +// - Число +// - Строка +// - Неопределено - Ложь, Истина, произвольное +// целое число до 16 разрядов или произвольная строка до 150 символов. +// +// Свойства узлов И, Или. +// * Аргументы - Массив из см. СтруктураРасчетаПрава +// +// Свойства узла Не. +// * Аргумент - см. СтруктураРасчетаПрава +// +// * Узел - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла Выбор (Иначе может быть Неопределено). +// * Иначе - см. СтруктураРасчетаПрава +// * Когда - Массив из Структура: +// ** Условие - см. СтруктураРасчетаПрава +// ** Значение - см. СтруктураРасчетаПрава +// +// * Узел - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узлов ЗначениеРазрешено, ЭтоАвторизованныйПользователь, +// ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, +// ЧтениеСпискаРазрешено, ИзменениеСпискаРазрешено. +// * Поле - см. СтруктураРасчетаПрава +// * УточненияСравнения - Соответствие из КлючИЗначение: +// ** Ключ - Строка +// - Тип - уточняемое значение "Неопределено", "Null", "ПустаяСсылка", +// "Отключено", Тип (Ссылка, Число, Даты, Булево). +// ** Значение - Строка - результат "Ложь", "Истина". +// +// Свойства узлов ДляВсехСтрок, ДляОднойИзСтрок. +// * Аргумент - см. СтруктураРасчетаПрава +// +Функция СтруктураРасчетаПрава() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура НастроитьСозданиеКлючаДоступаДляЗависимыхСписковБезКлючей(Результат) + + Если Не Результат.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + Если Результат.СоставПолей <> 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Для списка %1 некорректно рассчиталось поле %2. + |Указано значение %3, ожидалось значение 0.'"), + Результат.Список, "СоставПолей", Формат(Результат.СоставПолей, "ЧН=0; ЧГ=")); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Результат.ЕстьОграничениеЧтения = Истина; + Результат.ЕстьОграничениеИзменения = Истина; + + Результат.ЕстьФункцияПравоДоступаИлиРольДоступна = Истина; + + СтруктураРасчетаПраваЧтение = Новый Структура; + СтруктураРасчетаПраваЧтение.Вставить("Узел", "ПравоДоступа"); + СтруктураРасчетаПраваЧтение.Вставить("ИмяПрава", "Чтение"); + СтруктураРасчетаПраваЧтение.Вставить("ПолноеИмяОбъектаМетаданных", Результат.Список); + СтруктураРасчетаПраваЧтение.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + Результат.СтруктураРасчетаПраваЧтение = СтруктураРасчетаПраваЧтение; + + СтруктураРасчетаПраваИзменение = Новый Структура; + СтруктураРасчетаПраваИзменение.Вставить("Узел", "ПравоДоступа"); + СтруктураРасчетаПраваИзменение.Вставить("ИмяПрава", "Изменение"); + СтруктураРасчетаПраваИзменение.Вставить("ПолноеИмяОбъектаМетаданных", Результат.Список); + СтруктураРасчетаПраваИзменение.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + Результат.СтруктураРасчетаПраваИзменение = СтруктураРасчетаПраваИзменение; + +КонецПроцедуры + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Функция ПравоРазрешеноДляВсехПользователей(ИмяПрава, ОбъектМетаданных, ДляВнешнихПользователей) + + Если ОбъектМетаданных = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ИменаРолейБазовыеПрава = УправлениеДоступомСлужебныйПовтИсп.ИменаРолейБазовыеПрава(ДляВнешнихПользователей); + МетаданныеРоли = Метаданные.Роли; + + Для Каждого ИмяРоли Из ИменаРолейБазовыеПрава Цикл + Если ПравоДоступа(ИмяПрава, ОбъектМетаданных, МетаданныеРоли[ИмяРоли]) Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура ДобавитьСвойствоВерсииВедущиеРоли(Контекст) + + Если Не ЗначениеЗаполнено(Контекст.ВедущиеРоли) Тогда + Возврат; + КонецЕсли; + + СписокЗначений = Новый СписокЗначений; + Для Каждого КлючИЗначение Из Контекст.ВедущиеРоли Цикл + СписокЗначений.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + СписокЗначений.СортироватьПоПредставлению(); + + ДобавитьЭлементВерсии(Контекст, "ВедущиеРоли", СписокЗначений.ВыгрузитьЗначения()); + +КонецПроцедуры + +// Для процедуры УдалитьПоляНеиспользуемыхВидовДоступа и функции ГруппыДополнительныхТаблиц. +Процедура ДобавитьСвойстваВерсии(Контекст, Структура, ИменаПолей = "") Экспорт + + Если ЗначениеЗаполнено(ИменаПолей) Тогда + СохраняемаяСтруктура = Новый Структура(ИменаПолей); + ЗаполнитьЗначенияСвойств(СохраняемаяСтруктура, Структура); + Иначе + СохраняемаяСтруктура = Структура; + КонецЕсли; + + СписокЗначений = Новый СписокЗначений; + Для Каждого КлючИЗначение Из СохраняемаяСтруктура Цикл + СписокЗначений.Добавить(КлючИЗначение.Значение, КлючИЗначение.Ключ) + КонецЦикла; + СписокЗначений.СортироватьПоПредставлению(); + + Для Каждого ЭлементСписка Из СписокЗначений Цикл + ДобавитьЭлементВерсии(Контекст, ЭлементСписка.Представление, ЭлементСписка.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура ДобавитьСвойствоВерсии(Контекст, Структура, ИмяПоля) + + ДобавитьЭлементВерсии(Контекст, ИмяПоля, Структура[ИмяПоля]); + +КонецПроцедуры + +// Для процедур ДобавитьСвойстваВерсии, ДобавитьСвойствоВерсии. +Процедура ДобавитьЭлементВерсии(Контекст, ИмяПоля, Значение) Экспорт + + Если ТипЗнч(Значение) = Тип("Строка") Тогда + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + Значение); + + ИначеЕсли ТипЗнч(Значение) = Тип("Число") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + Формат(Значение, "ЧГ=")); + + ИначеЕсли ТипЗнч(Значение) = Тип("Булево") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + ?(Значение, "Да", "Нет")); + + ИначеЕсли ТипЗнч(Значение) = Тип("Неопределено") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + "Неопределено"); + + ИначеЕсли ТипЗнч(Значение) = Тип("ФиксированныйМассив") Тогда + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + СтрокаДанныхДляХеширования(Новый Массив(Значение))); + + ИначеЕсли ТипЗнч(Значение) = Тип("ОписаниеТипов") + Или ТипЗнч(Значение) = Тип("Тип") + Или ТипЗнч(Значение) = Тип("Массив") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + СтрокаДанныхДляХеширования(Значение)); + Иначе + ТекстОшибки = НСтр("ru = 'Некорректный тип данных для версии ограничения доступа.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения и формы ОбновлениеДоступаРучноеУправление. +// +// Возвращаемое значение: +// Булево +// +Функция ЭтоСсылочныйТипТаблицы(ПолноеИмя, ИмяКоллекцииТипа = "") Экспорт + + СинтаксисЯзыка = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка(); + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + + ТипТаблицы = СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0])); + Если ТипТаблицы = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ИмяКоллекцииТипа = ТипТаблицы.ИмяКоллекции; + + Возврат ТипТаблицы.ЭтоСсылочныйТип; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПолноеИмяТаблицы - Строка +// * ТабличнаяЧасть - Строка +// * Поля - Массив из Строка - с полем Ссылка +// * СписокПолей - Строка - без поля Ссылка +// * ТаблицаСПолями - ХранилищеЗначения - с объектом ТаблицаЗначений +// с типизированными полями (включая поле Ссылка). +// +Функция НовыеПоляТаблицыОбъекта() + + ПоляТаблицы = Новый Структура; + ПоляТаблицы.Вставить("ПолноеИмяТаблицы", ""); + ПоляТаблицы.Вставить("ТабличнаяЧасть", ""); + ПоляТаблицы.Вставить("Поля", Новый Массив); + ПоляТаблицы.Вставить("СписокПолей", ""); + ПоляТаблицы.Вставить("ТаблицаСПолями", Новый ХранилищеЗначения(Новый ТаблицаЗначений)); + + Возврат ПоляТаблицы; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Результат - Массив из см. НовыеПоляТаблицыОбъекта +// * Состав - Структура: +// ** Ключ - Строка - полное имя таблицы объекта. +// ** Значение - Структура: +// *** Ключ - Строка - имя поля. +// *** Значение - Структура: +// **** Тип - ОписаниеТипов - типы поля. +// **** Использование - Булево - использование поля. +// * ПоСвойствамПолей - Соответствие из КлючИЗначение: +// ** Ключ - см. НовыеСвойстваПоля +// ** Значение - Структура: +// *** Таблица - Строка - полное имя таблицы объекта. +// *** Поле - Строка - имя поля. +// * ПоДополнительнымТаблицам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - дополнительная таблица +// ** Значение - Структура: +// *** Ключ - Строка - полное имя таблицы объекта. +// *** Значение - Массив из Строка - имя поля. +// +Функция НовоеОписаниеПолейТаблицОбъекта(Результат) + + Возврат Новый Структура("Результат, Состав", Результат.ПоляТаблицОбъекта, Новый Структура); + +КонецФункции + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНовоеОписаниеОпорныхПолей(Результат, Контекст) + + ОпорныеПоля = НовоеОписаниеОпорныхПолей(); + Контекст.Вставить("ОпорныеПоля", ОпорныеПоля); + Контекст.Вставить("ВариантДоступа", Неопределено); + + Если Контекст.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + Если Контекст.Свойство("ОсновныеВариантыДоступа") Тогда + ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); + Если ИспользуемыеВариантыДоступа <> Неопределено Тогда + Результат.ВариантДоступа = ИспользуемыеВариантыДоступа[0].ВариантДоступа; + КонецЕсли; + Контекст.Вставить("ВариантДоступа", Результат.ВариантДоступа); + КонецЕсли; + + Если СтрРазделить(Контекст.Список, ".").Количество() > 1 Тогда + ИмяОтдельногоРегистраКлючей = "КлючиДоступаКРегистру" + СтрРазделить(Контекст.Список, ".")[1]; + Если Метаданные.РегистрыСведений.Найти(ИмяОтдельногоРегистраКлючей) = Неопределено Тогда + ИмяОтдельногоРегистраКлючей = ""; + КонецЕсли; + Иначе + ИмяОтдельногоРегистраКлючей = ""; + КонецЕсли; + Контекст.Вставить("ИмяОтдельногоРегистраКлючей", ИмяОтдельногоРегистраКлючей); + + ОпорныеПоля.МаксимальноеКоличество = + УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяОтдельногоРегистраКлючей); + + ОпорныеПоля.МаксимальноДопустимоеКоличество = + УправлениеДоступомСлужебныйПовтИсп.МаксимальноеКоличествоОпорныхПолейРегистра(); + + Если ОпорныеПоля.МаксимальноеКоличество > ОпорныеПоля.МаксимальноДопустимоеКоличество Тогда + // Превышение количества опорных полей в отдельном регистре. + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Количество опорных полей в регистре сведений %1 + |превышает максимально допустимое количество: %2'"), + ?(ИмяОтдельногоРегистраКлючей = "", "КлючиДоступаКРегистрам", ИмяОтдельногоРегистраКлючей), + ОпорныеПоля.МаксимальноДопустимоеКоличество); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, ОпорныеПоля, "МаксимальноеКоличество"); + + Результат.ОпорныеПоля = НовоеОписаниеОпорныхПолей(); + ЗаполнитьЗначенияСвойств(Результат.ОпорныеПоля, Контекст.ОпорныеПоля); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Все - Массив +// * ТипыВсех - Массив из ХранилищеЗначения - содержит тип ОписаниеТипов +// * Используемые - Массив +// * ТипыИспользуемых - Массив из ХранилищеЗначения - содержит тип ОписаниеТипов +// * МаксимальноеКоличество - Число +// * МаксимальноДопустимоеКоличество - Число +// +// * Список - СписокЗначений +// * ТипыПоИменамПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя опорного поля +// ** Значение - ОписаниеТипов - типы опорного поля +// * ПоСвойствамПолей - Соответствие из КлючИЗначение: +// ** Ключ - см. НовыеСвойстваПоля +// ** Значение - Строка - имя опорного поля +// * ПоДополнительнымТаблицам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - дополнительная таблица +// ** Значение - Массив из Строка - имена опорных полей +// * НедостающиеТипы - Массив из Строка - полные имена типов +// * ПоляНедостающихТипов - Массив из Строка - имена полей регистра ключей +// +Функция НовоеОписаниеОпорныхПолей() + + ОпорныеПоля = Новый Структура; + ОпорныеПоля.Вставить("Все", Новый Массив); + ОпорныеПоля.Вставить("ТипыВсех", Новый Массив); + ОпорныеПоля.Вставить("Используемые", Новый Массив); + ОпорныеПоля.Вставить("ТипыИспользуемых", Новый Массив); + ОпорныеПоля.Вставить("МаксимальноеКоличество", 0); + ОпорныеПоля.Вставить("МаксимальноДопустимоеКоличество", 0); + + Возврат ОпорныеПоля; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция ЭтоБезусловноеОграничение(Контекст, Результат) + + СтруктураОграничения = Контекст.СтруктураОграничения; + + Возврат ЗначениеЗаполнено(СтруктураОграничения.ОграничениеЧтения) + И СтруктураОграничения.ОграничениеЧтения.Узел = "Константа" + И СтруктураОграничения.ОграничениеЧтения.Значение = Ложь; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, ПослеУпрощения) + + СтруктураОграничения = Контекст.СтруктураОграничения; + + Результат.ЕстьОграничениеЧтения = + ЗначениеЗаполнено(СтруктураОграничения.ОграничениеЧтения) + И ( СтруктураОграничения.ОграничениеЧтения.Узел <> "Константа" + Или СтруктураОграничения.ОграничениеЧтения.Значение <> Истина); + + Результат.ЕстьОграничениеИзменения = + ЗначениеЗаполнено(СтруктураОграничения.ОграничениеИзменения) + И ( СтруктураОграничения.ОграничениеИзменения.Узел <> "Константа" + Или СтруктураОграничения.ОграничениеИзменения.Значение <> Истина); + + Если ПослеУпрощения Тогда + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеЧтения"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеИзменения"); + КонецЕсли; + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения(Результат, Контекст) + + НастройкаПоВладельцу = Контекст.СпискиСОграничениемПоВладельцу.Получить(Контекст.Список); + ПолеВладельца = НовоеПолеВладельца(); + + ТребуетсяОграничениеПоВладельцу = Ложь; + Если ТипЗнч(НастройкаПоВладельцу) = Тип("Булево") Тогда + ТребуетсяОграничениеПоВладельцу = НастройкаПоВладельцу; + КонецЕсли; + Результат.ТребуетсяОграничениеПоВладельцу = ТребуетсяОграничениеПоВладельцу; + + ОграничениеЧтения = Контекст.СтруктураОграничения.ОграничениеЧтения; + ОграничениеИзменения = Контекст.СтруктураОграничения.ОграничениеИзменения; + + ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, + "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); + + Если Результат.ЕстьОграничениеЧтения Тогда + + Если ТребуетсяОграничениеПоВладельцу Или Не Контекст.ЭтоСсылочныйТип Тогда + Если ОграничениеЧтения.Узел <> "ЧтениеОбъектаРазрешено" Тогда + Если Не ТребуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + Если ЗначениеЗаполнено(ОграничениеИзменения) Тогда + ШаблонОшибки = + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение чтения изменения не представлено одной функцией ""%2"".'"); + Иначе + ШаблонОшибки = + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение чтения не представлено одной функцией ""%2"".'"); + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Иначе + ОграничениеЧтения = ВозможноеОграничениеПоОбъектуВладельцу(ОграничениеЧтения, Ложь, Контекст); + Если ОграничениеЧтения = Неопределено Тогда + Возврат; + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(ОграничениеЧтения) Тогда + Если Не ФункцияБезУточненийТиповСПолемБезВложений(ОграничениеЧтения) Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но параметры функции ""%2"" не представлены + |только одним параметром - полем владельцем без других параметров.'"), + ИмяПризнакаОптимизации, + "ЧтениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + ОграничениеЧтенияПоле = ОграничениеЧтения.Поле; // См. ОписаниеУзла + ПолеВладельца.Имя = ОграничениеЧтенияПоле.Имя; + КонецЕсли; + КонецЕсли; + + Если Результат.ЕстьОграничениеИзменения Тогда + + Если ТребуетсяОграничениеПоВладельцу Или Не Контекст.ЭтоСсылочныйТип Тогда + + Если ОграничениеИзменения.Узел <> "ЧтениеОбъектаРазрешено" + И ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено" Тогда + + Если Не ТребуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение изменения не представлено одной функцией + |""%2"" или ""%3"".'"), + ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Иначе + ОграничениеИзменения = ВозможноеОграничениеПоОбъектуВладельцу(ОграничениеИзменения, Истина, Контекст); + Если ОграничениеИзменения = Неопределено Тогда + Возврат; + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(ОграничениеИзменения) Тогда + Если Не ФункцияБезУточненийТиповСПолемБезВложений(ОграничениеИзменения) Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но параметры функции ""%2"" не представлены + |только одним параметром - полем владельцем без других параметров.'"), + ИмяПризнакаОптимизации, + ОграничениеИзменения.Узел); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + ОграничениеИзмененияПоле = ОграничениеИзменения.Поле; // См. ОписаниеУзла + + Если ПолеВладельца.Имя = "" Тогда + ПолеВладельца.Имя = ОграничениеИзмененияПоле.Имя; + + ИначеЕсли ПолеВладельца.Имя <> ОграничениеИзмененияПоле.Имя Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но поле владельца не совпадает в ограничениях чтения и изменения.'"), + ИмяПризнакаОптимизации, + ОграничениеИзменения.Узел); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + ПолеВладельца.ИзменениеКакЧтение = + ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено"; + Иначе + ПолеВладельца.ИзменениеКакЧтение = Истина; + КонецЕсли; + Иначе + ПолеВладельца.ИзменениеКакЧтение = Истина; + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПолеВладельца.Имя) Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение не содержит ни одной из функций + |""%2"", ""%3"".'"), + ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + + Результат.ПолеВладельца = ПолеВладельца; + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Результат.ТребуетсяОграничениеПоВладельцу = Истина; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения. +Функция ВозможноеОграничениеПоОбъектуВладельцу(Условие, ЭтоОграничениеИзменения, Контекст) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат Новый Структура; + КонецЕсли; + + Если Условие.Узел = "Поле" + Или Условие.Узел = "ЕстьNull" + Или Условие.Узел = "=" + Или Условие.Узел = "<>" + Или Условие.Узел = "В" + Или Условие.Узел = "Константа" + Или Условие.Узел = "ЗначениеРазрешено" Тогда + + Возврат Новый Структура; + + ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" + Или Условие.Узел = "ПравоДоступа" + Или Условие.Узел = "РольДоступна" Тогда + + Возврат Неопределено; + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + НайденноеОграничение = Новый Структура; + Для Каждого Аргумент Из Условие.Аргументы Цикл + Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Аргумент, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда + Возврат Неопределено; + КонецЕсли; + КонецЦикла; + Возврат НайденноеОграничение; + + ИначеЕсли Условие.Узел = "Не" + Или Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + Возврат ВозможноеОграничениеПоОбъектуВладельцу(Условие.Аргумент, + ЭтоОграничениеИзменения, Контекст); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + НайденноеОграничение = Новый Структура; + Для Каждого Когда Из Условие.Когда Цикл + Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Когда.Значение, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда + Возврат Неопределено; + КонецЕсли; + КонецЦикла; + Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Условие.Иначе, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда + Возврат Неопределено; + КонецЕсли; + Возврат НайденноеОграничение; + + ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ЭтоОграничениеИзменения Тогда + + Возврат Условие; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При заполнении возможного ограничения по объекту владельцу + |для списка ""%1"" + |узел не поддерживается ""%2"".'"), + Контекст.Список, + Условие.Узел); + + ВызватьИсключение ТекстОшибки; + +КонецФункции + +// Для функции ВозможноеОграничениеПоОбъектуВладельцу. +Функция ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Условие, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) + + ВложенноеОграничение = ВозможноеОграничениеПоОбъектуВладельцу(Условие, + ЭтоОграничениеИзменения, Контекст); + + Если ВложенноеОграничение = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Если ЗначениеЗаполнено(ВложенноеОграничение) Тогда + Если ЗначениеЗаполнено(НайденноеОграничение) Тогда + Возврат Ложь; + КонецЕсли; + НайденноеОграничение = ВложенноеОграничение; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьОграничениеПоОбъектуВладельцуПослеУпрощения(Результат, Контекст) + + ПолеВладельца = Результат.ПолеВладельца; + Если ПолеВладельца = Неопределено Тогда + Возврат; + КонецЕсли; + ТребуетсяОграничениеПоВладельцу = Результат.ТребуетсяОграничениеПоВладельцу; + + НастройкаПоВладельцу = Контекст.СпискиСОграничениемПоВладельцу.Получить(Контекст.Список); + Если ТипЗнч(НастройкаПоВладельцу) = Тип("Булево") Тогда + ПолеВладельца.Отключено = Не НастройкаПоВладельцу; + Иначе + ПолеВладельца.Отключено = Ложь; + КонецЕсли; + + ОграничениеЧтения = Контекст.СтруктураОграничения.ОграничениеЧтения; + ОграничениеИзменения = Контекст.СтруктураОграничения.ОграничениеИзменения; + + ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, + "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); + + Если Не Результат.ЕстьОграничениеЧтения + И Не Результат.ЕстьОграничениеИзменения + Или Результат.ЕстьОграничениеЧтения + И ОграничениеЧтения.Узел <> "ЧтениеОбъектаРазрешено" + Или Результат.ЕстьОграничениеИзменения + И ОграничениеИзменения.Узел <> "ЧтениеОбъектаРазрешено" + И ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено" Тогда + + ПолеВладельца.Отключено = Истина; + Иначе + СвойстваПолей = Контекст.СвойстваПолей; + + Если СвойстваПолей.Количество() <> 1 Тогда + Если ТребуетсяОграничениеПоВладельцу И СвойстваПолей.Количество() <> 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но количество полей, используемых в ограничении, не равно одному.'"), + ИмяПризнакаОптимизации); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + ПолеВладельца.Отключено = Истина; + КонецЕсли; + Иначе + СвойстваПоля = СвойстваПолей[0]; + + ТипИОМ = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных"); + ТипИОР = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений"); + + КоличествоТиповИдентификаторовВКонечномПоле = 0; + Если СвойстваПоля.ТипКонечногоПоля.СодержитТип(ТипИОМ) Тогда + КоличествоТиповИдентификаторовВКонечномПоле = 1; + КонецЕсли; + Если СвойстваПоля.ТипКонечногоПоля.СодержитТип(ТипИОР) Тогда + КоличествоТиповИдентификаторовВКонечномПоле = КоличествоТиповИдентификаторовВКонечномПоле + 1; + КонецЕсли; + + Если СвойстваПоля.ТипКонечногоПоля.Типы().Количество() - КоличествоТиповИдентификаторовВКонечномПоле + <> СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() Тогда + + НекорректныеТипы = Новый Массив; + Для Каждого Тип Из СвойстваПоля.ТипКонечногоПоля.Типы() Цикл + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Найти(Тип) <> Неопределено + Или Тип = ТипИОМ + Или Тип = ТипИОР Тогда + Продолжить; + КонецЕсли; + НекорректныеТипы.Добавить(ИмяТипаНаЯзыкеЗапросов(Тип)); + КонецЦикла; + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но для следующих таблиц невозможно записать ключи доступа: + |%2'"), + ИмяПризнакаОптимизации, + СтрСоединить(НекорректныеТипы, Символы.ПС)); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + ПолеВладельца.Отключено = Истина; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "ИзменениеКакЧтение"); + ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "Имя"); + ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "Отключено"); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Имя - Строка +// * ИзменениеКакЧтение - Булево +// * Отключено - Булево +// +Функция НовоеПолеВладельца() + + Возврат Новый Структура("Имя, ИзменениеКакЧтение, Отключено", "", Ложь, Истина); + +КонецФункции + +// Для функции ЗаполнитьОграничениеПоОбъектуВладельцу и процедуры НастроитьОптимизациюПоПолюВладельцу. +Функция ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст) + + ОписаниеОшибок = ОписаниеОшибок(); + ОписаниеОшибок.ЕстьОшибки = Истина; + ОписаниеОшибок.ТекстОшибок = ТекстОшибки; + ОписаниеОшибок.Ошибки = Новый Массив(1); + + ОписаниеОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список); + + ОписаниеОшибок.Ограничение = + ПронумерованныйТекстОграниченияСОтметкамиОшибок(ОписаниеОграничения.Текст, + Новый Массив, СтрДлина(Формат(СтрЧислоСтрок(ОписаниеОграничения.Текст), "ЧГ="))); + + Возврат СокрЛП(ТекстОшибокДляВызоваИсключения(Контекст.Список, + ОписаниеОшибок, Контекст.ДляВнешнихПользователей, ОписаниеОграничения.ВМодулеМенеджера)); + +КонецФункции + +// Для процедуры ЗаполнитьОграничениеПоОбъектуВладельцу. +Функция ФункцияБезУточненийТиповСПолемБезВложений(Ограничение) + + Если Ограничение.Типы.Количество() <> 0 + Или Ограничение.УточненияСравнения.Количество() <> 0 Тогда + Возврат Ложь; + КонецЕсли; + + Поле = Ограничение.Поле; + + Возврат Не ЗначениеЗаполнено(Поле.Выразить) + И Не ЗначениеЗаполнено(Поле.Вложение) + И Не ЗначениеЗаполнено(Поле.ЕстьNull); + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеВедущихКлючейИСписковИВладельцевНастроекПрав(Результат, Контекст) + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() > 0 Тогда + Результат.ЕстьВедущиеКлючиДоступа = Истина; + КонецЕсли; + Если СвойстваПоля.ЕстьТипВедущегоСписка Тогда + Результат.ЕстьВедущиеСпискиПоПравам = Истина; + КонецЕсли; + Если СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда + Результат.ЕстьВладельцыНастроекПрав = Истина; + КонецЕсли; + Если СвойстваПоля.ЕстьПроверкаАвторизованногоПользователя Тогда + Контекст.ЕстьПроверкаАвторизованногоПользователя = Истина; + КонецЕсли; + Для Каждого Тип Из СвойстваПоля.ИспользуемыеТипыЗначенийДоступа Цикл + Если Результат.ИспользуемыеТипыЗначенийДоступа.Найти(Тип) = Неопределено Тогда + Результат.ИспользуемыеТипыЗначенийДоступа.Добавить(Тип); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Для Каждого КлючИЗначение Из Контекст.ОтдельныеТаблицыНастроекПрав Цикл + Если КлючИЗначение.Значение = Контекст.Список Тогда + Результат.ИдентификаторТаблицыНастроекПрав = КлючИЗначение.Ключ; + Прервать; + КонецЕсли; + КонецЦикла; + + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВедущиеКлючиДоступа"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВедущиеСпискиПоПравам"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВладельцыНастроекПрав"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ИспользуемыеТипыЗначенийДоступа"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "НеиспользуемыеТипыЗначенийДоступа"); + + СохраняемыеСвойства = Новый Структура("ОтдельнаяТаблицаНастроекПрав", + ЗначениеЗаполнено(Результат.ИдентификаторТаблицыНастроекПрав)); + + ДобавитьСвойствоВерсии(Контекст, СохраняемыеСвойства, "ОтдельнаяТаблицаНастроекПрав"); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура УдалитьПоляНеиспользуемыхВидовДоступа(Результат, Контекст) + + СвойстваПолей = Контекст.СвойстваПолей; + + Если Не Результат.ЕстьВедущиеКлючиДоступа + И Не Результат.ЕстьВедущиеСпискиПоПравам + И Не Результат.ЕстьВладельцыНастроекПрав + И Не Результат.ЕстьФункцияПравоДоступаИлиРольДоступна + И Не Контекст.ЕстьПроверкаАвторизованногоПользователя + И Результат.ИспользуемыеТипыЗначенийДоступа.Количество() = 0 + И Контекст.НеиспользуемыеТипыЗначенийДоступа.Количество() > 0 Тогда + + СвойстваПолей.Очистить(); + Возврат; + КонецЕсли; + + Индекс = СвойстваПолей.Количество(); + Пока Индекс > 0 Цикл + Индекс = Индекс - 1; + СвойстваПоля = СвойстваПолей.Получить(Индекс); + УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, СвойстваПоля); + УстановитьИспользованиеОпорногоПоля(Контекст, СвойстваПоля); + ДобавитьСвойстваВерсии(Контекст, СвойстваПоля, + "ЕстьУточнениеNull, + |ЕстьУточнениеНеопределено, + |ИмяПоляДляЗапроса, + |НесколькоГруппЗначений, + |ТипКонечногоПоля, + |ТипыСохраненияГруппЗначений, + |ТипыСохраненияЗначений, + |ТипыСохраненияКлючейДоступа, + |ТипыСохраненияПустойСсылки, + |ТипыСохраненияТипаРазрешенный, + |ТипыСохраненияТипаЗапрещенный, + |ТипыСохраненияТипов, + |ТипыСохраненияТиповКонфигурации, + |ТипыСохраненияТиповПростых, + |ТипыСохраненияТиповРасширений, + |ТипыСтрокой"); + КонецЦикла; + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеОграниченияПоВидуДоступаПользователи(Результат, Контекст) + + Если Результат.ЕстьВладельцыНастроекПрав Тогда + Результат.ЕстьОграничениеПоПользователям = Истина; + Иначе + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ТипыСохраненияЗначений.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + ОписаниеТипов = Новый ОписаниеТипов(СвойстваПоля.ТипыСохраненияЗначений); + Если Не Результат.ДляВнешнихПользователей + И ( ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.Пользователи")) + Или ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ГруппыПользователей")) ) Тогда + + Результат.ЕстьОграничениеПоПользователям = Истина; + Прервать; + КонецЕсли; + Если Результат.ДляВнешнихПользователей + И ( ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ВнешниеПользователи")) + Или ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ГруппыВнешнихПользователей")) ) Тогда + + Результат.ЕстьОграничениеПоПользователям = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеПоПользователям"); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеОграниченияЧтения(Результат, Контекст) + + Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения Тогда + Результат.ОграничениеЧтенияОтключено = Ложь; + Иначе + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.Чтение Тогда + Результат.ОграничениеЧтенияОтключено = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, Результат, "ОграничениеЧтенияОтключено"); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьГруппыПолейИДополнительныхТаблиц(Контекст) + + // Поля шапки (начинаются от шапки - группировка по пустому псевдониму, если нет имени табличной части). + // Поля каждой ТЧ (начинаются от табличной части - группировка по имени табличной части). + // Поля группы связанных дополнительных таблиц (начинаются от экземпляра доп. таблицы - группировка + // по псевдониму, но если одна таблица ссылается на другую в соединении, тогда образуется группа таблиц). + + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = 0; + НомерПоследнейТабличнойЧастиОбъекта = 0; + НомераТабличныхЧастейОбъекта = Новый Соответствие; + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" + И СвойстваПоля.НесколькоГруппЗначений Тогда + + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + 1; + + ИначеЕсли СвойстваПоля.ПсевдонимТаблицы <> "ТекущийСписок" + И СтрНачинаетсяС(СвойстваПоля.ПсевдонимТаблицы, "ТекущийСписок") + И НомераТабличныхЧастейОбъекта.Получить(СвойстваПоля.ПсевдонимТаблицы) = Неопределено Тогда + + НомерПоследнейТабличнойЧастиОбъекта = НомерПоследнейТабличнойЧастиОбъекта + 1; + НомераТабличныхЧастейОбъекта.Вставить(СвойстваПоля.ПсевдонимТаблицы, НомерПоследнейТабличнойЧастиОбъекта); + КонецЕсли; + КонецЦикла; + + РазмерностьКлючаДоступа = УправлениеДоступомСлужебныйПовтИсп.РазмерностьКлючаДоступа(); + + КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта = Цел( + (НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + + РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти - 1) + / РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти); + + ГруппыДополнительныхТаблиц = ГруппыДополнительныхТаблиц(Контекст); + КоличествоТабличныхЧастейКлюча = НомерПоследнейТабличнойЧастиОбъекта + + ГруппыДополнительныхТаблиц.ТаблицыПоГруппам.Количество() + + КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта; + + ЗавершитьПодготовкуПолейТаблицОбъекта(Контекст); + ЗавершитьПодготовкуОпорныхПолей(Контекст); + + Если КоличествоТабличныхЧастейКлюча > РазмерностьКлючаДоступа.КоличествоТабличныхЧастей Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей, требующих отдельных табличных частей в ключе доступа, + |более, чем количество доступных табличных частей в ключе доступа. + | + |К таким полям относятся: + |- поля табличных частей, + |- поля дополнительных таблиц, присоединенных к списку, + |- поля шапки, у которых значение доступа может иметь более одной группы значений доступа.'"), + Контекст.Список); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Не Контекст.ЭтоСсылочныйТип + И Контекст.ОпорныеПоля.Все.Количество() > Контекст.ОпорныеПоля.МаксимальноеКоличество Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей списка, используемых в ограничении доступа, + |превышает максимально допустимое количество опорных полей: %2.'"), + Контекст.Список, + Контекст.ОпорныеПоля.МаксимальноеКоличество); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ГруппыПолей = Новый Соответствие; + ПсевдонимыТабличныхЧастейОбъекта = Новый Соответствие; + НомерПоследнегоРеквизитаШапки = 0; + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = 0; + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" Тогда + + Если СвойстваПоля.НесколькоГруппЗначений Тогда + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + 1; + + НомерТабличнойЧастиКлюча = Цел(НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + / РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти) + 1; + + ИмяГруппыПолей = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + Иначе + НомерПоследнегоРеквизитаШапки = НомерПоследнегоРеквизитаШапки + 1; + Если НомерПоследнегоРеквизитаШапки < 6 Тогда + ИмяГруппыПолей = "Шапка0"; + ИначеЕсли НомерПоследнегоРеквизитаШапки < 11 Тогда + ИмяГруппыПолей = "Шапка1"; + ИначеЕсли НомерПоследнегоРеквизитаШапки < 16 Тогда + ИмяГруппыПолей = "Шапка2"; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей списка, используемых в ограничении доступа, + |превышает максимально допустимое количество: 15.'"), + Контекст.Список); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЕсли; + Иначе + Если СвойстваПоля.ПсевдонимТаблицы <> "ТекущийСписок" + И СтрНачинаетсяС(СвойстваПоля.ПсевдонимТаблицы, "ТекущийСписок") Тогда + + НомерТабличнойЧастиКлюча = КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта + + НомераТабличныхЧастейОбъекта.Получить(СвойстваПоля.ПсевдонимТаблицы); + + Если ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча) = Неопределено Тогда + ПсевдонимыТабличныхЧастейОбъекта.Вставить(НомерТабличнойЧастиКлюча, СвойстваПоля.ПсевдонимТаблицы) + КонецЕсли; + Иначе + НомерТабличнойЧастиКлюча = КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта + + НомераТабличныхЧастейОбъекта.Количество() + + ГруппыДополнительныхТаблиц.НомераПоПсевдонимам.Получить(СвойстваПоля.ПсевдонимТаблицы); + КонецЕсли; + ИмяГруппыПолей = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + КонецЕсли; + ГруппаПолей = ГруппыПолей.Получить(ИмяГруппыПолей); + Если ГруппаПолей = Неопределено Тогда + ГруппаПолей = Новый Массив; + ГруппыПолей.Вставить(ИмяГруппыПолей, ГруппаПолей); + КонецЕсли; + ГруппаПолей.Добавить(СвойстваПоля); + СвойстваПоля.Вставить("ИмяГруппыПолейКлючаДоступа", ИмяГруппыПолей); + СвойстваПоля.Вставить("ИмяРеквизитаГруппыПолейКлючаДоступа", + "Значение" + XMLСтрока(ГруппаПолей.Количество() + ?(ИмяГруппыПолей = "Шапка1" Или ИмяГруппыПолей = "Шапка2", 5, 0))); + + Если Не СтрНачинаетсяС(ИмяГруппыПолей, "Шапка") + И ГруппаПолей.Количество() > РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей одной табличной части, используемых в ограничении доступа, + |превышает максимально допустимое количество: %2.'"), + Контекст.Список, + РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЦикла; + + Контекст.Вставить("ГруппыПолей", ГруппыПолей); + Контекст.Вставить("ПсевдонимыТабличныхЧастейОбъекта", ПсевдонимыТабличныхЧастейОбъекта); + Контекст.Вставить("ГруппыДополнительныхТаблиц", ГруппыДополнительныхТаблиц); + Контекст.Вставить("КоличествоТабличныхЧастейКлюча", КоличествоТабличныхЧастейКлюча); + + // Расчет числа СоставПолей. + + // Шапка и табличные части: ТЧ4 ТЧ3 ТЧ2 ТЧ1 Ш. + // Двоичный формат: 0000 0000 0000 0000 0000. + // Шестнадцатеричный формат: x0 x0 x0 x0 x0. + // + // Например: Ш0=1, ТЧ1=1. + // Двоичный формат: 0000 0000 0000 0001 0001. + // Шестнадцатеричный формат: x0 x0 x0 x1 x1. + // Число = 1*16^0 + 1*16^1 = 1 + 16 = 17. + + СоставПолей = НомерПоследнегоРеквизитаШапки; + + Для НомерТабличнойЧастиКлюча = 1 По КоличествоТабличныхЧастейКлюча Цикл + ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + ГруппаПолей = ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); + СоставПолей = СоставПолей + ГруппаПолей.Количество() * Степень16(НомерТабличнойЧастиКлюча); + КонецЦикла; + + Контекст.Вставить("СоставПолей", СоставПолей); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// УсловиеРасчета - см. СтруктураРасчетаПрава +// Условие - см. ОписаниеУзла +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета, Условие, Контекст, КореньУсловия = Истина) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат; + КонецЕсли; + + Если КореньУсловия Тогда + Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + Контекст.Вставить("СтруктураРасчетаПраваСвойстваВерсии", Новый Массив); + КонецЕсли; + + СвойстваПоля = Неопределено; + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Узел", Условие.Узел); + + Если Условие.Узел = "Поле" Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие); + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + УсловиеРасчета = Новый Структура("Узел, Аргументы", Условие.Узел, Новый Массив); + Индекс = 0; + Для Каждого Аргумент Из Условие.Аргументы Цикл + УсловиеРасчета.Аргументы.Добавить(Неопределено); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргументы[Индекс], Аргумент, Контекст, Ложь); + Индекс = Индекс + 1; + КонецЦикла; + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "Не" Тогда + УсловиеРасчета = Новый Структура("Узел, Аргумент", Условие.Узел, Неопределено); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргумент, Условие.Аргумент, Контекст, Ложь); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + Если Не КореньУсловия Тогда + ТребуемыеРеквизитыТабличныхЧастейКлюча = Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча; + Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + КонецЕсли; + + УсловиеРасчета = Новый Структура("Узел, Аргумент", Условие.Узел, Неопределено); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргумент, Условие.Аргумент, Контекст, Ложь); + + Если Не КореньУсловия Тогда + УсловиеРасчета.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча); + Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", ТребуемыеРеквизитыТабличныхЧастейКлюча); + КонецЕсли; + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ЕстьNull" Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.Аргумент); + + ИначеЕсли Условие.Узел = "=" + Или Условие.Узел = "<>" Тогда + + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.ПервыйАргумент); + Если СвойстваПоля = Неопределено Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.ВторойАргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "В" Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.Искомое); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + УсловиеРасчета = Новый Структура("Узел, Когда, Иначе", Условие.Узел, Новый Массив, Неопределено); + Для Каждого Когда Из Условие.Когда Цикл + СтруктураКогда = Новый Структура("Условие, Значение"); + УсловиеРасчета.Когда.Добавить(СтруктураКогда); + Если Условие.Выбор = Неопределено Тогда + ЗаполнитьСтруктуруРасчетаПрава(СтруктураКогда.Условие, Когда.Условие, Контекст, Ложь); + Иначе + Свойства = Контекст.СвойстваПолейКлючаДоступа.Получить(Когда.Условие); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Узел", "Поле"); + УсловиеРасчетаПоле(СтруктураКогда.Условие, Свойства, Контекст); + КонецЕсли; + ЗаполнитьСтруктуруРасчетаПрава(СтруктураКогда.Значение, Когда.Значение, Контекст, Ложь); + КонецЦикла; + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Иначе, Условие.Иначе, Контекст, Ложь); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + УсловиеРасчета = Новый Структура("Узел, Поле", Условие.Узел, Неопределено); + УсловиеРасчета.Вставить("УточненияСравнения", Новый Соответствие); + Для Каждого КлючИЗначение Из Условие.УточненияСравнения Цикл + Если КлючИЗначение.Ключ = "Null" + Или КлючИЗначение.Ключ = "Неопределено" + Или КлючИЗначение.Ключ = "ПустаяСсылка" + Или КлючИЗначение.Ключ = "Отключено" Тогда + УсловиеРасчета.УточненияСравнения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + Иначе + ИмяТипа = СтрЗаменить(КлючИЗначение.Ключ, ".", "Ссылка."); + УсловиеРасчета.УточненияСравнения.Вставить(Тип(ИмяТипа), КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "УточненияСравнения", Условие.УточненияСравнения); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Поле, Условие.Поле, Контекст, Ложь); + + Если УсловиеРасчета.Поле = Null Тогда + УсловиеРасчета = Новый Структура("Узел, Значение", "Константа", Истина); + КонецЕсли; + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "Константа" Тогда + УсловиеРасчета = Новый Структура("Узел, Значение", Условие.Узел, Условие.Значение); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Значение", Условие.Значение); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ПравоДоступа" Тогда + УсловиеРасчета = Новый Структура("Узел, ИмяПрава, ПолноеИмяОбъектаМетаданных", + Условие.Узел, Условие.ИмяПрава, Условие.ПолноеИмяОбъектаМетаданных); + ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ИмяПрава", Условие.ИмяПрава); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ПолноеИмяОбъектаМетаданных", + Условие.ПолноеИмяОбъектаМетаданных); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "РольДоступна" Тогда + УсловиеРасчета = Новый Структура("Узел, ИмяРоли", Условие.Узел, Условие.ИмяРоли); + ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ИмяРоли", Условие.ИмяРоли); + СвойстваПоля = Null; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При заполнении структуры расчета права %1 на ключи доступа + |списка ""%2"" + |узел не поддерживается ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если СвойстваПоля = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При заполнении структуры расчета права %1 на ключи доступа + |списка ""%2"" + |свойства поля не определены для узла ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если СвойстваПоля <> Null Тогда + УсловиеРасчетаПоле(УсловиеРасчета, СвойстваПоля, Контекст); + КонецЕсли; + + Если КореньУсловия Тогда + УсловиеРасчета.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", + Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча); + + ДобавитьЭлементВерсии(Контекст, ?(Контекст.ИмяПрава = "Чтение", + "СтруктураРасчетаПраваЧтение", "СтруктураРасчетаПраваИзменение"), + Контекст.СтруктураРасчетаПраваСвойстваВерсии); + + Контекст.Удалить("СтруктураРасчетаПраваСвойстваВерсии"); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьСтруктуруРасчетаПрава. +Процедура УсловиеРасчетаПоле(УсловиеРасчета, СвойстваПоля, Контекст) + + Если Контекст.СвойстваПолей.Найти(СвойстваПоля) = Неопределено Тогда + УсловиеРасчета = Null; // Поле удалено из-за неиспользуемых типов значений доступа. + Иначе + УсловиеРасчета = Новый Структура("Узел", "Поле"); + УсловиеРасчета.Вставить("Таблица", СвойстваПоля.ИмяГруппыПолейКлючаДоступа); + УсловиеРасчета.Вставить("Реквизит", СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + Если СтрНачинаетсяС(УсловиеРасчета.Таблица, "ТабличнаяЧасть") Тогда + Реквизиты = Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча.Получить(УсловиеРасчета.Таблица); + Если Реквизиты = Неопределено Тогда + Реквизиты = Новый Массив; + Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча.Вставить(УсловиеРасчета.Таблица, Реквизиты); + КонецЕсли; + Если Реквизиты.Найти(УсловиеРасчета.Реквизит) = Неопределено Тогда + Реквизиты.Добавить(УсловиеРасчета.Реквизит); + КонецЕсли; + КонецЕсли; + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Таблица", УсловиеРасчета.Таблица); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Реквизит", УсловиеРасчета.Реквизит); + Если СвойстваПоля.Свойство("ПроверкаЕстьNull") Тогда + УсловиеРасчета.Вставить("ПроверкаЕстьNull"); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ПроверкаЕстьNull", Истина); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьСтруктуруРасчетаПрава. +Процедура ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета) + + Если УсловиеРасчета.Свойство("ИмяРоли") Тогда + Роль = Метаданные.Роли.Найти(УсловиеРасчета.ИмяРоли); + Контекст.ВедущиеРоли.Вставить(Роль.Имя, Истина); + Возврат; + КонецЕсли; + + ИмяСтандартногоРеквизита = Неопределено; + ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава( + УсловиеРасчета.ПолноеИмяОбъектаМетаданных, ИмяСтандартногоРеквизита); + + Для Каждого Роль Из Метаданные.Роли Цикл + Если ПравоДоступа(УсловиеРасчета.ИмяПрава, ОбъектМетаданных, Роль, ИмяСтандартногоРеквизита) Тогда + Контекст.ВедущиеРоли.Вставить(Роль.Имя, Истина); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗаполнитьСтруктуруРасчетаПрава, УсловиеРасчетаПоле. +Процедура ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, Имя, Значение); + + Если ТипЗнч(Значение) = Тип("Соответствие") Тогда + СписокЗначений = Новый СписокЗначений; + Для Каждого КлючИЗначение Из Значение Цикл + СписокЗначений.Добавить(КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЦикла; + СписокЗначений.СортироватьПоПредставлению(); + Для Каждого ЭлементСписка Из СписокЗначений Цикл + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(ЭлементСписка.Представление); + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(ЭлементСписка.Значение); + КонецЦикла; + Иначе + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(Имя); + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(Значение); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. +Функция Степень16(Степень) + + Степень16 = 1; + + Для Счетчик = 1 По Степень Цикл + Степень16 = Степень16 * 16; + КонецЦикла; + + Возврат Степень16; + +КонецФункции + +// Для функции ЗаполнитьГруппыПолейИДополнительныхТаблиц. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +// Возвращаемое значение: +// Структура: +// * НомераПоПсевдонимам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - псевдоним дополнительной таблицы +// ** Значение - Число - номер группы дополнительных таблиц +// +// * ТаблицыПоГруппам - Соответствие из КлючИЗначение: +// ** Ключ - Число - номер группы дополнительных таблиц +// ** Значение - Массив из см. НовоеОписаниеСоединения +// +// * ПсевдонимыТаблицСПолями - Соответствие из КлючИЗначение: +// ** Ключ - Строка - псевдоним дополнительной таблицы +// с полями ключа доступа (кроме полей соединений). +// ** Значение - Булево - Истина. +// +Функция ГруппыДополнительныхТаблиц(Контекст) + + ДополнительныеТаблицы = Контекст.СтруктураОграничения.ДополнительныеТаблицы; + НомераГруппПоПсевдонимам = Новый Соответствие; + + Контекст.ОпорныеПоля.Вставить("ПоДополнительнымТаблицам", Новый Соответствие); + Контекст.ПоляТаблицОбъекта.Вставить("ПоДополнительнымТаблицам", Новый Соответствие); + Контекст.Вставить("ПоляУсловияСоединенияДополнительныхТаблиц", Новый Массив); + + ПоследняяГруппа = 0; + Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл + ДополнительнаяТаблица.Вставить("ПсевдонимыТребуемыхТаблиц", Новый Массив); + ДополнительнаяТаблица.Вставить("ПоляУсловияСоединения", Новый Массив); + + ТекстУсловияСоединения = ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст); + ДополнительнаяТаблица.Вставить("ТекстУсловияСоединения", ?(Лев(ТекстУсловияСоединения, 1) = "(", + ТекстУсловияСоединения, "(" + ТекстУсловияСоединения + ")")); + + ТекущаяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); + Если ТекущаяГруппа = Неопределено Тогда + ПоследняяГруппа = ПоследняяГруппа + 1; + ТекущаяГруппа = ПоследняяГруппа; + НомераГруппПоПсевдонимам.Вставить(ДополнительнаяТаблица.Псевдоним, ТекущаяГруппа); + КонецЕсли; + + Для Каждого Псевдоним Из ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц Цикл + ГруппаТребуемойТаблицы = НомераГруппПоПсевдонимам.Получить(Псевдоним); + Если ГруппаТребуемойТаблицы = Неопределено Тогда + НомераГруппПоПсевдонимам.Вставить(Псевдоним, ТекущаяГруппа); + Продолжить; + КонецЕсли; + Если ГруппаТребуемойТаблицы = ТекущаяГруппа Тогда + Продолжить; + КонецЕсли; + ПсевдонимыЗаменяемойГруппы = Новый Массив; + Для Каждого КлючИЗначение Из НомераГруппПоПсевдонимам Цикл + Если КлючИЗначение.Значение <> ГруппаТребуемойТаблицы Тогда + Продолжить; + КонецЕсли; + ПсевдонимыЗаменяемойГруппы.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + Для Каждого Псевдоним Из ПсевдонимыЗаменяемойГруппы Цикл + НомераГруппПоПсевдонимам.Вставить(Псевдоним, ТекущаяГруппа); + КонецЦикла; + КонецЦикла; + КонецЦикла; + + ПсевдонимыТаблицСПолями = Новый Соответствие; + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" Тогда + Продолжить; + КонецЕсли; + ПсевдонимыТаблицСПолями.Вставить(СвойстваПоля.ПсевдонимТаблицы, Истина); + КонецЦикла; + + ИспользованиеГрупп = Новый Соответствие; + Для Группа = 1 По ПоследняяГруппа Цикл + Для Каждого КлючИЗначение Из НомераГруппПоПсевдонимам Цикл + Если КлючИЗначение.Значение <> Группа Тогда + Продолжить; + КонецЕсли; + Если ИспользованиеГрупп.Получить(Группа) = Неопределено Тогда + ИспользованиеГрупп.Вставить(Группа, Ложь); + КонецЕсли; + Если ПсевдонимыТаблицСПолями.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда + ИспользованиеГрупп.Вставить(Группа, Истина); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + НоваяГруппа = 1; + НовыеГруппы = Новый Соответствие; + Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл + СтараяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); + Если Не ИспользованиеГрупп.Получить(СтараяГруппа) Тогда + Продолжить; + КонецЕсли; + Если НовыеГруппы.Получить(СтараяГруппа) <> Неопределено Тогда + Продолжить; + КонецЕсли; + НовыеГруппы.Вставить(СтараяГруппа, НоваяГруппа); + НоваяГруппа = НоваяГруппа + 1; + КонецЦикла; + + Группы = Новый Структура; + Группы.Вставить("НомераПоПсевдонимам", Новый Соответствие); + Группы.Вставить("ТаблицыПоГруппам", Новый Соответствие); + Группы.Вставить("ПсевдонимыТаблицСПолями", ПсевдонимыТаблицСПолями); + + Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл + СтараяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); + Если Не ИспользованиеГрупп.Получить(СтараяГруппа) Тогда + Продолжить; + КонецЕсли; + УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, , ДополнительнаяТаблица); + УстановитьИспользованиеОпорногоПоля(Контекст, , ДополнительнаяТаблица); + Группа = НовыеГруппы.Получить(СтараяГруппа); + Группы.НомераПоПсевдонимам.Вставить(ДополнительнаяТаблица.Псевдоним, Группа); + ГруппаТаблиц = Группы.ТаблицыПоГруппам.Получить(Группа); + Если ГруппаТаблиц = Неопределено Тогда + ГруппаТаблиц = Новый Массив; + Группы.ТаблицыПоГруппам.Вставить(Группа, ГруппаТаблиц); + КонецЕсли; + ГруппаТаблиц.Добавить(ДополнительнаяТаблица); + КонецЦикла; + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + ТекущиеСвойства = СвойстваПоля; + Пока ТекущиеСвойства <> Неопределено Цикл + ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, + ТекущиеСвойства.УзелПоле, + ТекущиеСвойства.СвойстваВложения, + ?(ТекущиеСвойства.ЭтоПолеСписка, Неопределено, ТекущиеСвойства.ПсевдонимТаблицы)); + ТекущиеСвойства = ТекущиеСвойства.СвойстваВложения; + КонецЦикла; + КонецЦикла; + + Для Каждого ОписаниеПоляУсловия Из Контекст.ПоляУсловияСоединенияДополнительныхТаблиц Цикл + Группа = Группы.НомераПоПсевдонимам.Получить(ОписаниеПоляУсловия.ПсевдонимТаблицыУсловия); + Если Группа <> Неопределено Тогда + УзелПоле = ОписаниеПоляУсловия.УзелПоле; + ДобавитьСвойстваВерсии(Контекст, УзелПоле, "Псевдоним, Имя, ТипыСтрокой"); + ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, УзелПоле,, + Группы.ТаблицыПоГруппам.Получить(Группа), ОписаниеПоляУсловия.ПсевдонимТаблицыУсловия); + КонецЕсли; + КонецЦикла; + + Для Каждого Описание Из Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов Цикл + ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка(Описание.Ключ, + Описание.Значение, Группы, Контекст); + КонецЦикла; + ЗаполнитьОтборыВедущихСписковПоПолюСсылка(Контекст.ВедущиеСпискиПоКлючамДоступа, Группы, Контекст); + ЗаполнитьОтборыВедущихСписковПоПолюСсылка(Контекст.ВедущиеСпискиПоЗначениямСГруппами, Группы, Контекст); + + Возврат Группы; + +КонецФункции + +// Для функции ГруппыДополнительныхТаблиц. +Функция ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст, + Условие = Null, Поле = Неопределено, Псевдоним = Неопределено) + + Если Условие = Null Тогда + Условие = ДополнительнаяТаблица.УсловиеСоединения; + КонецЕсли; + + // Возможные узлы: "Поле", "Значение", "Константа", "И", "=". + + Если Условие.Узел = "Поле" Тогда + Контекст.ПоляУсловияСоединенияДополнительныхТаблиц.Добавить(Новый Структура( + "УзелПоле, ПсевдонимТаблицыУсловия", Условие, ДополнительнаяТаблица.Псевдоним)); + ДобавитьПолеТаблицыОбъекта(Контекст, Условие, , ДополнительнаяТаблица); + Если Условие.Псевдоним = Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + ДобавитьОпорноеПоле(Контекст, Условие, , ДополнительнаяТаблица); + Псевдоним = "ТекущийСписок"; + Поле = Псевдоним + "." + Условие.Имя; + Возврат ИмяПоляСРазверткойОпорногоПоляПоТипам(Псевдоним, Условие); + КонецЕсли; + Псевдоним = Условие.Псевдоним; + Если Псевдоним <> ДополнительнаяТаблица.Псевдоним + И ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц.Найти(Псевдоним) = Неопределено Тогда + ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц.Добавить(Псевдоним); + КонецЕсли; + Поле = Псевдоним + "." + Условие.Имя; + Возврат Поле; + КонецЕсли; + + Если Условие.Узел = "Значение" + Или Условие.Узел = "Константа" Тогда + + Поле = ВыражениеУзлаЗначениеИлиКонстанта(Условие); + Возврат Поле; + КонецЕсли; + + Если Условие.Узел = "И" Тогда + Текст = ""; + Для Каждого Аргумент Из Условие.Аргументы Цикл + Текст = Текст + ?(Текст = "", "", Символы.ПС + "И "); + Текст = Текст + ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст, Аргумент); + КонецЦикла; + Возврат Текст; + КонецЕсли; + + Если Условие.Узел = "=" Тогда + ПервоеПоле = НовоеПолеУсловияСоединения(); + ВтороеПоле = НовоеПолеУсловияСоединения(); + + ПервыйАргумент = ТекстУсловияСоединения(ДополнительнаяТаблица, + Контекст, Условие.ПервыйАргумент, ПервоеПоле.Поле, ПервоеПоле.Псевдоним); + + ВторойАргумент = ТекстУсловияСоединения(ДополнительнаяТаблица, + Контекст, Условие.ВторойАргумент, ВтороеПоле.Поле, ВтороеПоле.Псевдоним); + + Если ПервоеПоле.Псевдоним = ДополнительнаяТаблица.Псевдоним + Или Не ЗначениеЗаполнено(ВтороеПоле.Псевдоним) Тогда + ТекстУсловия = "(" + ПервыйАргумент + " = " + ВторойАргумент + ")"; + ПоляУсловия = ПараПолейУсловияСоединения(ПервоеПоле, ВтороеПоле); + Иначе + ТекстУсловия = "(" + ВторойАргумент + " = " + ПервыйАргумент + ")"; + ПоляУсловия = ПараПолейУсловияСоединения(ВтороеПоле, ПервоеПоле); + КонецЕсли; + ДополнительнаяТаблица.ПоляУсловияСоединения.Добавить(ПоляУсловия); + Возврат ТекстУсловия; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка узла ""%1""'"), Условие.Узел); + + ВызватьИсключение ТекстОшибки; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПервоеПоле - см. НовоеПолеУсловияСоединения +// * ВтороеПоле - см. НовоеПолеУсловияСоединения +// +Функция ПараПолейУсловияСоединения(ПервоеПоле, ВтороеПоле) + + Возврат Новый Структура("ПервоеПоле, ВтороеПоле", ПервоеПоле, ВтороеПоле); + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Поле - Строка +// * Псевдоним - Строка +// +Функция НовоеПолеУсловияСоединения() + + Возврат Новый Структура("Поле, Псевдоним"); + +КонецФункции + +// Для функций СвойстваПоля, ТекстУсловияСоединения. +Процедура ДобавитьПолеТаблицыОбъекта(Контекст, УзелПоле, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено, ТабличнаяЧасть = "") + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + ИмяТаблицыОбъекта = Контекст.Список; + + Если ЗначениеЗаполнено(УзелПоле.Псевдоним) + И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы + И ВРег(Контекст.Список) <> ВРег(УзелПоле.Таблица) Тогда + + ЧастиИмениТаблицы = СтрРазделить(УзелПоле.Таблица, ".", Ложь); + Если ЧастиИмениТаблицы.Количество() <> 3 Тогда + Возврат; + КонецЕсли; + ИмяТаблицыОбъекта = Контекст.Список + "." + ЧастиИмениТаблицы[2]; + КонецЕсли; + + ЧастиИмениПоля = СтрРазделить(УзелПоле.Имя, ".", Ложь); + Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда + ИмяПоляТаблицы = ЧастиИмениПоля[1]; + ТипыПоляТаблицы = УзелПоле.ТипыПоля[1]; + ИмяТаблицыОбъекта = Контекст.Список + "." + ТабличнаяЧасть; + Иначе + ИмяПоляТаблицы = ЧастиИмениПоля[0]; + ТипыПоляТаблицы = УзелПоле.ТипыПоля[0]; + КонецЕсли; + + ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; + ИмяТаблицыОбъекта = СтрЗаменить(ИмяТаблицыОбъекта, ".", "_"); + + Если СвойстваПоля <> Неопределено Тогда + ОписаниеПоляТаблицы = Новый Структура("Таблица, Поле", ИмяТаблицыОбъекта, ИмяПоляТаблицы); + ПоляТаблицОбъекта.ПоСвойствамПолей.Вставить(СвойстваПоля, ОписаниеПоляТаблицы); + КонецЕсли; + + Если ДополнительнаяТаблица <> Неопределено Тогда + ПоляТаблиц = ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ПоляТаблиц = Неопределено Тогда + ПоляТаблиц = Новый Структура; + ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Вставить(ДополнительнаяТаблица, ПоляТаблиц); + КонецЕсли; + Если Не ПоляТаблиц.Свойство(ИмяТаблицыОбъекта) Тогда + ПоляТаблиц.Вставить(ИмяТаблицыОбъекта, Новый Массив); + КонецЕсли; + ПоляТаблицы = ПоляТаблиц[ИмяТаблицыОбъекта]; // Массив + ПоляТаблицы.Добавить(ИмяПоляТаблицы); + КонецЕсли; + + Если Не ПоляТаблицОбъекта.Состав.Свойство(ИмяТаблицыОбъекта) Тогда + ПоляТаблицОбъекта.Состав.Вставить(ИмяТаблицыОбъекта, Новый Структура); + КонецЕсли; + ПоляТаблицы = ПоляТаблицОбъекта.Состав[ИмяТаблицыОбъекта]; + Если Не ПоляТаблицы.Свойство(ИмяПоляТаблицы) Тогда + ПоляТаблицы.Вставить(ИмяПоляТаблицы, Новый Структура("Тип, Использование", ТипыПоляТаблицы, Ложь)); + КонецЕсли; + +КонецПроцедуры + +// Для функций СвойстваПоля, ТекстУсловияСоединения. +Процедура ДобавитьОпорноеПоле(Контекст, УзелПоле, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) + + Если Не УзелПоле.Свойство("ОсновнойПорядок") Тогда + Возврат; + КонецЕсли; + + Позиция = СтрНайти(УзелПоле.Имя, "."); + Если Позиция = 0 Тогда + ИмяОпорногоПоля = УзелПоле.Имя; + Иначе + ИмяОпорногоПоля = Лев(УзелПоле.Имя, Позиция - 1); + КонецЕсли; + + ОпорныеПоля = Контекст.ОпорныеПоля; + + Если СвойстваПоля <> Неопределено Тогда + ОпорныеПоля.ПоСвойствамПолей.Вставить(СвойстваПоля, ИмяОпорногоПоля); + КонецЕсли; + + Если ДополнительнаяТаблица <> Неопределено Тогда + ИменаОпорныхПолей = ОпорныеПоля.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ИменаОпорныхПолей = Неопределено Тогда + ИменаОпорныхПолей = Новый Массив; + ОпорныеПоля.ПоДополнительнымТаблицам.Вставить(ДополнительнаяТаблица, ИменаОпорныхПолей); + КонецЕсли; + ИменаОпорныхПолей.Добавить(ИмяОпорногоПоля); + КонецЕсли; + + Если ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля) = Неопределено Тогда + ОпорныеПоля.Список.Добавить(ИмяОпорногоПоля, УзелПоле.ОсновнойПорядок); + ТипыОпорногоПоля = УзелПоле.ТипыПоля[0]; + ОпорныеПоля.ТипыПоИменамПолей.Вставить(ИмяОпорногоПоля, ТипыОпорногоПоля); + Если Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + ЗапрещенныеТипы = Новый Массив; + Если ЕстьПростойТип(ТипыОпорногоПоля) Тогда + Для Каждого Тип Из ТипыОпорногоПоля.Типы() Цикл + Если ЭтоПростойТип(Тип) Тогда + ЗапрещенныеТипы.Добавить(Строка(Тип)); + КонецЕсли; + КонецЦикла; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |опорное поле %2 содержит простые типы: %3. + | + |Это недопустимо при использовании общего регистра сведений %4. + |Либо исключите простые типы из состава типов опорного поля, + |либо создайте отдельный регистр ключей доступа для этого списка.'"), + Контекст.Список, + ИмяОпорногоПоля, + СтрСоединить(ЗапрещенныеТипы, ", "), + "КлючиДоступаКРегистрам"); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур УдалитьПоляНеиспользуемыхВидовДоступа, ГруппыДополнительныхТаблиц. +Процедура УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; + + Если СвойстваПоля <> Неопределено Тогда + ОписаниеПоля = ПоляТаблицОбъекта.ПоСвойствамПолей.Получить(СвойстваПоля); + Если ОписаниеПоля <> Неопределено Тогда + ПоляТаблицОбъекта.Состав[ОписаниеПоля.Таблица][ОписаниеПоля.Поле].Использование = Истина; + КонецЕсли; + Иначе + ПоляТаблиц = ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ПоляТаблиц <> Неопределено Тогда + Для Каждого ОписаниеПолей Из ПоляТаблиц Цикл + ПоляТаблицы = ПоляТаблицОбъекта.Состав[ОписаниеПолей.Ключ]; + Для Каждого ИмяПоля Из ОписаниеПолей.Значение Цикл + ПоляТаблицы[ИмяПоля].Использование = Истина; + КонецЦикла; + КонецЦикла; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур УдалитьПоляНеиспользуемыхВидовДоступа, ГруппыДополнительныхТаблиц. +Процедура УстановитьИспользованиеОпорногоПоля(Контекст, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) + + ОпорныеПоля = Контекст.ОпорныеПоля; + + Если СвойстваПоля <> Неопределено Тогда + ИмяОпорногоПоля = ОпорныеПоля.ПоСвойствамПолей.Получить(СвойстваПоля); + Если ИмяОпорногоПоля <> Неопределено Тогда + ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля).Пометка = Истина; + КонецЕсли; + Иначе + ИменаОпорныхПолей = ОпорныеПоля.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ИменаОпорныхПолей <> Неопределено Тогда + Для Каждого ИмяОпорногоПоля Из ИменаОпорныхПолей Цикл + ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля).Пометка = Истина; + КонецЦикла; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗавершитьПодготовкуПолейТаблицОбъекта(Контекст) + + ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; + + Если Не Контекст.ЭтоСсылочныйТип Тогда + ПоляТаблицОбъекта.Удалить("ПоСвойствамПолей"); + ПоляТаблицОбъекта.Удалить("ПоДополнительнымТаблицам"); + Возврат; + КонецЕсли; + + ПолноеИмяОсновнойТаблицы = СтрЗаменить(Контекст.Список, ".", "_"); + ТипСсылки = Тип(ИмяТипаСсылки(Контекст.Список, Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам)); + ОписаниеТипаСсылки = Новый ОписаниеТипов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки)); + СвойстваВидаДоступа = Контекст.СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамСсылок.Получить(ТипСсылки); + Если СвойстваВидаДоступа <> Неопределено И Не СвойстваВидаДоступа.НесколькоГруппЗначений Тогда + МетаданныеТаблицы = Метаданные.НайтиПоТипу(ТипСсылки); + РеквизитГруппаДоступа = МетаданныеТаблицы.Реквизиты.Найти("ГруппаДоступа"); + КонецЕсли; + + ЕстьОсновнаяТаблица = Ложь; + ЕстьТабличнаяЧасть = Ложь; + + Для Каждого ОписаниеТаблицы Из ПоляТаблицОбъекта.Состав Цикл + ПоляТаблицы = НовыеПоляТаблицыОбъекта(); + ПоляТаблицы.ПолноеИмяТаблицы = ОписаниеТаблицы.Ключ; + ТаблицаЗначений = Новый ТаблицаЗначений; + ЕстьИспользуемыеПоля = Ложь; + Для Каждого ОписаниеПоля Из ОписаниеТаблицы.Значение Цикл + Если Не ОписаниеПоля.Значение.Использование Тогда + Продолжить; + КонецЕсли; + ЕстьИспользуемыеПоля = Истина; + Если ВРег("Ссылка") = ВРег(ОписаниеПоля.Ключ) Тогда + Продолжить; + КонецЕсли; + ПоляТаблицы.Поля.Добавить(ОписаниеПоля.Ключ); + ТаблицаЗначений.Колонки.Добавить(ОписаниеПоля.Ключ, ОписаниеПоля.Значение.Тип); + КонецЦикла; + Если Не ЕстьИспользуемыеПоля Тогда + Продолжить; + КонецЕсли; + Если ТипЗнч(РеквизитГруппаДоступа) = Тип("ОбъектМетаданных") + И ПоляТаблицы.Поля.Найти("ГруппаДоступа") = Неопределено Тогда + ПоляТаблицы.Поля.Добавить("ГруппаДоступа"); + ТаблицаЗначений.Колонки.Добавить("ГруппаДоступа", РеквизитГруппаДоступа.Тип); + КонецЕсли; + ПоляТаблицы.СписокПолей = СтрСоединить(ПоляТаблицы.Поля, ", "); + ПоляТаблицы.Поля.Вставить(0, "Ссылка"); + ТаблицаЗначений.Колонки.Добавить("Ссылка", ОписаниеТипаСсылки); + ПоляТаблицы.ТаблицаСПолями = Новый ХранилищеЗначения(ТаблицаЗначений); + Если ПоляТаблицы.ПолноеИмяТаблицы = ПолноеИмяОсновнойТаблицы Тогда + ЕстьОсновнаяТаблица = Истина; + Иначе + ЕстьТабличнаяЧасть = Истина; + ПоляТаблицы.ТабличнаяЧасть = Сред(ПоляТаблицы.ПолноеИмяТаблицы, + СтрДлина(ПолноеИмяОсновнойТаблицы) + 2); + КонецЕсли; + ПоляТаблицОбъекта.Результат.Добавить(ПоляТаблицы); + КонецЦикла; + + Если ЕстьТабличнаяЧасть И Не ЕстьОсновнаяТаблица Тогда + ПоляТаблицы = НовыеПоляТаблицыОбъекта(); + ПоляТаблицы.ПолноеИмяТаблицы = ПолноеИмяОсновнойТаблицы; + ПоляТаблицы.Поля.Вставить(0, "Ссылка"); + ТаблицаЗначений = Новый ТаблицаЗначений; + ТаблицаЗначений.Колонки.Добавить("Ссылка", ОписаниеТипаСсылки); + ПоляТаблицы.ТаблицаСПолями = Новый ХранилищеЗначения(ТаблицаЗначений); + ПоляТаблицОбъекта.Результат.Вставить(0, ПоляТаблицы); + КонецЕсли; + + ПоляТаблицОбъекта.Удалить("ПоСвойствамПолей"); + ПоляТаблицОбъекта.Удалить("ПоДополнительнымТаблицам"); + +КонецПроцедуры + +// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗавершитьПодготовкуОпорныхПолей(Контекст) + + ОпорныеПоля = Контекст.ОпорныеПоля; + ОпорныеПоля.Список.СортироватьПоПредставлению(); + + Для Каждого ЭлементСписка Из ОпорныеПоля.Список Цикл + ОпорныеПоля.Все.Добавить(ЭлементСписка.Значение); + ОпорныеПоля.ТипыВсех.Добавить(Новый ХранилищеЗначения( + ОпорныеПоля.ТипыПоИменамПолей.Получить(ЭлементСписка.Значение))); + + Если ЭлементСписка.Пометка Тогда + ОпорныеПоля.Используемые.Добавить(ЭлементСписка.Значение); + ОпорныеПоля.ТипыИспользуемых.Добавить(Новый ХранилищеЗначения( + ОпорныеПоля.ТипыПоИменамПолей.Получить(ЭлементСписка.Значение))); + КонецЕсли; + КонецЦикла; + + ОпорныеПоля.Удалить("Список"); + ОпорныеПоля.Удалить("ТипыПоИменамПолей"); + ОпорныеПоля.Удалить("ПоСвойствамПолей"); + ОпорныеПоля.Удалить("ПоДополнительнымТаблицам"); + +КонецПроцедуры + +// Для функций ТекстУсловияСоединения, СвойстваПоля. +Функция ИмяПоляСРазверткойОпорногоПоляПоТипам(Псевдоним, УзелПоле) + + Если Не УзелПоле.Свойство("ОсновнойПорядок") + Или Не УзелПоле.Свойство("ТаблицыСледующегоПоля") Тогда + + Возврат Псевдоним + "." + УзелПоле.Имя; + КонецЕсли; + + КоличествоТаблиц = УзелПоле.ТаблицыСледующегоПоля[0].Количество(); + + Если КоличествоТаблиц >= 70 Тогда // Ограничение платформы. + Возврат Псевдоним + "." + УзелПоле.Имя; + КонецЕсли; + + Позиция = СтрНайти(УзелПоле.Имя, "."); + ОпорноеПоле = Псевдоним + "." + Лев(УзелПоле.Имя, Позиция - 1); + ОстальныеПоля = Сред(УзелПоле.Имя, Позиция + 1); + + ИмяПоля = ""; + Для Каждого ИмяТипа Из УзелПоле.ТаблицыСледующегоПоля[0] Цикл + ТекущееИмяПоля = СтрШаблон("ВЫРАЗИТЬ(%1 КАК %2).%3", ОпорноеПоле, ИмяТипа, ОстальныеПоля); // @query-part-1 + Если ЗначениеЗаполнено(ИмяПоля) Тогда + ИмяПоля = + "ЕСТЬNULL(" + ТекущееИмяПоля + ", + | " + ТекстСОтступом(ИмяПоля, " ") + ")"; // @query-part-1 + Иначе + ИмяПоля = ТекущееИмяПоля; + КонецЕсли; + КонецЦикла; + + Возврат ИмяПоля; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +Процедура ЗаполнитьСвойстваПолей(Контекст) + + // 1. Для полей-аргументов узлов сравнения =, <>, В, ЕстьNull + // вычисляется результат сравнения и сохраняется в ключе. + + // 2. Для значений типа Булево сохраняются значения: + // - Перечисления.ДополнительныеЗначенияДоступа.ЗначениеИстина, + // - Перечисления.ДополнительныеЗначенияДоступа.ЗначениеЛожь. + + // 3. Для значений типов Число, Дата, Строка сохраняется результат + // сравнения со значением Истина, как указано в пункте 2. + + Контекст.ОпорныеПоля.Вставить("Список", Новый СписокЗначений); + Контекст.ОпорныеПоля.Вставить("ТипыПоИменамПолей", Новый Соответствие); + Контекст.ОпорныеПоля.Вставить("ПоСвойствамПолей", Новый Соответствие); + Контекст.ПоляТаблицОбъекта.Вставить("ПоСвойствамПолей", Новый Соответствие); + + СвойстваВсехПолей = Новый Соответствие; + ПоляКлючаДоступаДоУпрощения = Контекст.СтруктураОграничения.ВнутренниеДанные.ПоляКлючаДоступа; + Для Каждого ОписаниеПоля Из ПоляКлючаДоступаДоУпрощения Цикл + СвойстваПоля = СвойстваПоля(ОписаниеПоля.Поле, Контекст); + СвойстваВсехПолей.Вставить(ОписаниеПоля.Поле, СвойстваПоля); + КонецЦикла; + Контекст.Вставить("СвойстваВсехПолей", СвойстваВсехПолей); + + Контекст.Вставить("ОставшиесяПоляПослеУпрощения", Новый Соответствие); + Контекст.Вставить("ИсходнаяСтруктураОграничения", Контекст.СтруктураОграничения); + Контекст.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступна", Ложь); + + СтруктураОграничения = Новый Структура(Новый ФиксированнаяСтруктура(Контекст.СтруктураОграничения)); // см. СтруктураОграничения + Контекст.Вставить("ИмяПрава", "Чтение"); + СтруктураОграничения.ОграничениеЧтения = УпрощенноеУсловиеОграничения( + СтруктураОграничения.ОграничениеЧтения, Контекст, Истина); + Контекст.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения", + Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна); + Контекст.Вставить("ИмяПрава", "Изменение"); + СтруктураОграничения.ОграничениеИзменения = УпрощенноеУсловиеОграничения( + СтруктураОграничения.ОграничениеИзменения, Контекст, Истина); + Контекст.Вставить("СтруктураОграничения", СтруктураОграничения); + + Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения Тогда + ДобавитьВидОграниченияПрав("ФункцияПравоДоступаИлиРольДоступна", + Новый Структура("Чтение, Изменение", Истина, Ложь), Контекст); + КонецЕсли; + Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна Тогда + ДобавитьВидОграниченияПрав("ФункцияПравоДоступаИлиРольДоступна", + Новый Структура("Чтение, Изменение", Ложь, Истина), Контекст); + КонецЕсли; + + ПоляКлючаДоступаПослеУпрощения = Новый Массив; // Массив Из см. НовоеПолеКлючаДоступа + Для Каждого ОписаниеПоля Из ПоляКлючаДоступаДоУпрощения Цикл + РодителиПоля = Контекст.ОставшиесяПоляПослеУпрощения.Получить(ОписаниеПоля.Поле); // Массив из см. ОписаниеУзла + Если РодителиПоля = Неопределено Тогда + Продолжить; + КонецЕсли; + РодителиПоля.Добавить(Новый Структура("Узел", "")); + ОписаниеПоля.Вставить("Родители", РодителиПоля); + ПоляКлючаДоступаПослеУпрощения.Добавить(ОписаниеПоля); + КонецЦикла; + Контекст.Вставить("ПоляКлючаДоступаПослеУпрощения", ПоляКлючаДоступаПослеУпрощения); + + Контекст.Вставить("СвойстваПолейКлючаДоступа", Новый Соответствие); + Контекст.Вставить("ОбратныйТипПользователя", ?(Контекст.ДляВнешнихПользователей, + Тип("СправочникСсылка.Пользователи"), Тип("СправочникСсылка.ВнешниеПользователи"))); + Контекст.Вставить("ОбратныйТипГруппыПользователей", ?(Контекст.ДляВнешнихПользователей, + Тип("СправочникСсылка.ГруппыПользователей"), Тип("СправочникСсылка.ГруппыВнешнихПользователей"))); + ДобавленныеПоля = Новый Соответствие; + ИменаПолейДляЗапроса = Новый Массив; + Для Каждого ОписаниеПоля Из ПоляКлючаДоступаПослеУпрощения Цикл + СвойстваПоля = СвойстваВсехПолей.Получить(ОписаниеПоля.Поле); // см. СвойстваПоля + СвойстваПоля.Вставить("Чтение", ОписаниеПоля.Чтение); + СвойстваПоля.Вставить("Изменение", ОписаниеПоля.Изменение); + УточнитьСвойстваПоляСравнения(СвойстваПоля, ОписаниеПоля, Контекст); + НаборПолей = НаборПолейУсловияКогда(СвойстваПоля, ОписаниеПоля, Контекст); + Для Каждого СвойстваПоля Из НаборПолей Цикл + ДобавитьСвойстваТиповПоля(СвойстваПоля, ОписаниеПоля, Контекст); + ОдинаковыеПоля = ДобавленныеПоля.Получить(ВРег(СвойстваПоля.ИмяПоляДляЗапроса)); + Если ОдинаковыеПоля = Неопределено Тогда + ОдинаковыеПоля = Новый Массив; + ДобавленныеПоля.Вставить(ВРег(СвойстваПоля.ИмяПоляДляЗапроса), ОдинаковыеПоля); + ИменаПолейДляЗапроса.Добавить(СвойстваПоля.ИмяПоляДляЗапроса); + КонецЕсли; + ОдинаковыеПоля.Добавить(СвойстваПоля); + КонецЦикла; + КонецЦикла; + + СвойстваПолей = Новый Массив; // Массив из см. СвойстваПоля + СовмещенныеПоля = Новый Соответствие; + Для Каждого ИмяПоляДляЗапроса Из ИменаПолейДляЗапроса Цикл + ОдинаковыеПоля = ДобавленныеПоля.Получить(ВРег(ИмяПоляДляЗапроса)); + ОбработанныеОдинаковыеПоля = Новый Массив; + Для Каждого СвойстваПоля Из ОдинаковыеПоля Цикл + СовмещенноеПоле = ОбработанноеСовмещенноеПоле(ОбработанныеОдинаковыеПоля, СвойстваПоля); + Если СовмещенноеПоле <> Неопределено Тогда + СовмещенныеПоля.Вставить(СвойстваПоля, СовмещенноеПоле); + Продолжить; + КонецЕсли; + ОбработанныеОдинаковыеПоля.Добавить(СвойстваПоля); + КонецЦикла; + Для Каждого СвойстваПоля Из ОбработанныеОдинаковыеПоля Цикл + СвойстваПолей.Добавить(СвойстваПоля); + КонецЦикла; + КонецЦикла; + + Для Каждого Описание Из Контекст.СвойстваПолейКлючаДоступа Цикл + СовмещенноеПоле = СовмещенныеПоля.Получить(Описание.Значение); + Если СовмещенноеПоле <> Неопределено Тогда + Контекст.СвойстваПолейКлючаДоступа[Описание.Ключ] = СовмещенноеПоле; + КонецЕсли; + КонецЦикла; + + Для Каждого СвойстваПоля Из СвойстваПолей Цикл + СвойстваПоля.Вставить("ТипыСохраненияТиповКонфигурации", Новый Массив); + СвойстваПоля.Вставить("ТипыСохраненияТиповРасширений", Новый Массив); + СвойстваПоля.Вставить("ТипыСохраненияТиповПростых", Новый Массив); + + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипов Цикл + ОбъектМетаданных = Неопределено; + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип, ОбъектМетаданных); + + Если СтрНайти(ИмяТипа, ".") = 0 Тогда + СвойстваПоля.ТипыСохраненияТиповПростых.Добавить(Тип); + + ИначеЕсли ОбъектМетаданных.РасширениеКонфигурации() = Неопределено Тогда + СвойстваПоля.ТипыСохраненияТиповКонфигурации.Добавить(Тип); + Иначе + СвойстваПоля.ТипыСохраненияТиповРасширений.Добавить(Тип); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Контекст.Вставить("СвойстваПолей", СвойстваПолей); + +КонецПроцедуры + +// Для процедуры ЗаполнитьСвойстваПолей. +Функция УпрощенноеУсловиеОграничения(Знач Условие, Контекст, КореньУсловия = Ложь, ДобавитьОставшиесяПоля = Истина) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат Условие; + КонецЕсли; + + ОставшиесяПоляПослеУпрощения = Контекст.ОставшиесяПоляПослеУпрощения; + Контекст.ОставшиесяПоляПослеУпрощения = Новый Соответствие; + + Если Условие.Узел = "Поле" Тогда + Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие, Новый Массив); + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + БезусловныйРезультат = ?(Условие.Узел = "И", Ложь, Истина); + ЕстьБезусловныйРезультат = Ложь; + Аргументы = Новый Массив; + ЕстьФункцияПравоДоступаИлиРольДоступна = Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна; + Для Каждого ТекущийАргумент Из Условие.Аргументы Цикл + Аргумент = УпрощенноеУсловиеОграничения(ТекущийАргумент, Контекст); + Если Аргумент.Узел <> "Константа" Тогда + Аргументы.Добавить(Аргумент); + ИначеЕсли Аргумент.Значение = БезусловныйРезультат Тогда + ЕстьБезусловныйРезультат = Истина; + КонецЕсли; + КонецЦикла; + Если ЕстьБезусловныйРезультат Или Аргументы.Количество() = 0 Тогда + Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна = ЕстьФункцияПравоДоступаИлиРольДоступна; + Условие = Новый Структура("Узел, Значение", "Константа", + ?(ЕстьБезусловныйРезультат, БезусловныйРезультат, Истина)); + ИначеЕсли Аргументы.Количество() = 1 Тогда + Условие = Аргументы[0]; + Иначе + Условие = Новый Структура("Узел, Аргументы", Условие.Узел, Аргументы); + КонецЕсли; + + ИначеЕсли Условие.Узел = "Не" Тогда + Аргумент = УпрощенноеУсловиеОграничения(Условие.Аргумент, Контекст); + Если Аргумент.Узел = "Константа" Тогда + Условие = Новый Структура("Узел, Значение", "Константа", + ?(Аргумент.Значение = "Пусто", "Пусто", Не Аргумент.Значение)); + Иначе + Условие = Новый Структура("Узел, Аргумент", Условие.Узел, Аргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" + Или Условие.Узел = "ЕстьNull" + Или Условие.Узел = "ТипЗначения" Тогда + + Аргумент = УпрощенноеУсловиеОграничения(Условие.Аргумент, Контекст); + Если Аргумент.Узел = "Константа" Тогда + Условие = Аргумент; + Иначе + Условие = Новый Структура("Узел, Аргумент", Условие.Узел, Аргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "=" + Или Условие.Узел = "<>" Тогда + + ПервыйАргумент = УпрощенноеУсловиеОграничения(Условие.ПервыйАргумент, Контекст); + ВторойАргумент = УпрощенноеУсловиеОграничения(Условие.ВторойАргумент, Контекст); + + Если ПервыйАргумент.Узел = "Константа" + И ВторойАргумент.Узел = "Константа" Тогда + + Условие = Новый Структура("Узел, Значение", "Константа", ?(Условие.Узел = "=", + ПервыйАргумент.Значение = ВторойАргумент.Значение, + ПервыйАргумент.Значение <> ВторойАргумент.Значение)); + Иначе + Условие = Новый Структура("Узел, ПервыйАргумент, ВторойАргумент", + Условие.Узел, ПервыйАргумент, ВторойАргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "В" Тогда + Условие = Новый Структура("Узел, Искомое, Значения", + Условие.Узел, + УпрощенноеУсловиеОграничения(Условие.Искомое, Контекст), + Условие.Значения); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + ВсеЗначенияВыбораИстина = Истина; + ВсеЗначенияВыбораЛожь = Истина; + ВсеЗначенияВыбораПусто = Истина; + Выбор = Новый Структура("Узел, Выбор, Когда, Иначе", Условие.Узел, Условие.Выбор, Новый Массив); + НовоеУсловиеИначе = Неопределено; + Для Каждого Когда Из Условие.Когда Цикл + Если Условие.Выбор = Неопределено Тогда + УсловиеКогда = УпрощенноеУсловиеОграничения(Когда.Условие, Контекст); + Если УсловиеКогда.Узел = "Константа" Тогда + Если УсловиеКогда.Значение Тогда + НовоеУсловиеИначе = ?(НовоеУсловиеИначе = Неопределено, Когда.Значение, НовоеУсловиеИначе); + КонецЕсли; + ЗначениеКогда = УпрощенноеУсловиеОграничения(Когда.Значение, Контекст, , Ложь); + Продолжить; + КонецЕсли; + Иначе + УсловиеКогда = Когда.Условие; + КонецЕсли; + ЗначениеКогда = УпрощенноеУсловиеОграничения(Когда.Значение, Контекст); + ОбработатьУпрощенноеЗначениеВыбора(ЗначениеКогда, + ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто); + СтруктураКогда = Новый Структура("Условие, Значение", УсловиеКогда, ЗначениеКогда); + Выбор.Когда.Добавить(СтруктураКогда); + КонецЦикла; + УсловиеИначе = ?(НовоеУсловиеИначе = Неопределено, Условие.Иначе, НовоеУсловиеИначе); + Выбор.Иначе = УпрощенноеУсловиеОграничения(УсловиеИначе, Контекст); + ОбработатьУпрощенноеЗначениеВыбора(Выбор.Иначе, + ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто); + Если ВсеЗначенияВыбораИстина Или ВсеЗначенияВыбораЛожь Или ВсеЗначенияВыбораПусто Тогда + Условие = Новый Структура("Узел, Значение", "Константа", + ?(ВсеЗначенияВыбораПусто, "Пусто", ВсеЗначенияВыбораИстина)); + ИначеЕсли Выбор.Когда.Количество() = 0 Тогда + Условие = Выбор.Иначе; + Иначе + Условие = Выбор; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда + + СвойстваПоля = Контекст.СвойстваВсехПолей.Получить(Условие.Поле); + Если СвойстваПоля = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При упрощении условия ограничения права %1 + |списка ""%2"" + |свойства поля не определены для узла ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ТипыКонечногоПоля = СвойстваПоля.ТипКонечногоПоля.Типы(); + + Если Условие.Узел = "ЗначениеРазрешено" Тогда + Результат = РезультатФункцииЗначениеРазрешено(Условие, ТипыКонечногоПоля, Контекст); + Иначе + Результат = РезультатФункцииПравоОбъектаРазрешено(Условие, ТипыКонечногоПоля, Контекст); + КонецЕсли; + + Если Результат <> Неопределено Тогда + Условие = Новый Структура("Узел, Значение", "Константа", Результат); + Иначе + Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие.Поле, Новый Массив); + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие.Поле, Новый Массив); + + ИначеЕсли Условие.Узел = "ПравоДоступа" + Или Условие.Узел = "РольДоступна" Тогда + + Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна = Истина; + + ИначеЕсли Условие.Узел <> "Константа" + И Условие.Узел <> "Значение" + И Условие.Узел <> "Тип" Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При упрощении условия ограничения права %1 + |списка ""%2"" + |узел не поддерживается ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Условие.Узел = "Константа" Тогда + Если КореньУсловия И Условие.Значение = "Пусто" Тогда + Условие.Значение = Истина; + КонецЕсли; + ИначеЕсли ДобавитьОставшиесяПоля Тогда + Для Каждого КлючИЗначение Из Контекст.ОставшиесяПоляПослеУпрощения Цикл + Если Условие.Узел <> "Поле" Тогда + РодителиПоля = КлючИЗначение.Значение; // Массив Из см. ОписаниеУзла + РодителиПоля.Добавить(Условие); + КонецЕсли; + ОставшиесяПоляПослеУпрощения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + Контекст.ОставшиесяПоляПослеУпрощения = ОставшиесяПоляПослеУпрощения; + + Возврат Условие; + +КонецФункции + +// Для функции УпрощенноеУсловиеОграничения. +Процедура ОбработатьУпрощенноеЗначениеВыбора(Условие, + ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто) + + Если Условие.Узел <> "Константа" Тогда + ВсеЗначенияВыбораИстина = Ложь; + ВсеЗначенияВыбораЛожь = Ложь; + ВсеЗначенияВыбораПусто = Ложь; + + ИначеЕсли Условие.Значение = "Пусто" Тогда + ВсеЗначенияВыбораИстина = Ложь; + ВсеЗначенияВыбораЛожь = Ложь; + + ИначеЕсли Условие.Значение Тогда + ВсеЗначенияВыбораЛожь = Ложь; + ВсеЗначенияВыбораПусто = Ложь; + Иначе + ВсеЗначенияВыбораИстина = Ложь; + ВсеЗначенияВыбораПусто = Ложь; + КонецЕсли; + +КонецПроцедуры + +// Для функции УпрощенноеУсловиеОграничения. +Функция РезультатФункцииЗначениеРазрешено(Условие, ТипыКонечногоПоля, Контекст) + + СвойстваВидовДоступаПоТипам = Контекст.СвойстваВидовДоступа.ПоТипамГруппИЗначений; + ОтключеноКакЛожь = УточнениеТипа(Условие, "Отключено") = "Ложь"; + + РезультатВсегдаЛожь = Истина; + РезультатВсегдаИстина = Истина; + ЕстьРезультатПусто = Ложь; + + Для Каждого Тип Из ТипыКонечногоПоля Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Условие, ИмяТипа); + Если Уточнение = "Истина" Тогда + РезультатВсегдаЛожь = Ложь; + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + РезультатВсегдаИстина = Ложь; + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Условие, ИмяТипа) Тогда + РезультатВсегдаИстина = Ложь; + Продолжить; + КонецЕсли; + + СвойстваВидаДоступа = СвойстваВидовДоступаПоТипам.Получить(Тип); + Если СвойстваВидаДоступа = Неопределено Тогда + РезультатВсегдаЛожь = Ложь; + Продолжить; + КонецЕсли; + + Если Не ТипЗначенийДоступаИспользуется(Контекст, СвойстваВидаДоступа.ТипЗначений) Тогда + Если Контекст.НеиспользуемыеТипыЗначенийДоступа.Найти(СвойстваВидаДоступа.ТипЗначений) = Неопределено Тогда + Контекст.НеиспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); + КонецЕсли; + Если ОтключеноКакЛожь Тогда + РезультатВсегдаИстина = Ложь; + ЕстьРезультатПусто = Истина; + Иначе + РезультатВсегдаЛожь = Ложь; + КонецЕсли; + Иначе + РезультатВсегдаИстина = Ложь; + РезультатВсегдаЛожь = Ложь; + КонецЕсли; + КонецЦикла; + + Если РезультатВсегдаИстина Тогда + Возврат Истина; + ИначеЕсли РезультатВсегдаЛожь Тогда + Если ЕстьРезультатПусто Тогда + Возврат "Пусто"; + Иначе + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для функции РезультатФункцииЗначениеРазрешено и процедуры ДобавитьСвойстваТиповПоля. +Функция ТипЗначенийДоступаИспользуется(Контекст, ТипЗначений) + + Если Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Неопределено Тогда + ИспользуемыеТипыЗначений = Контекст.ИспользуемыеТипыЗначений.ДляИБ; + Иначе + ИспользуемыеТипыЗначений = Контекст.ИспользуемыеТипыЗначений.ПоТаблицам.Получить(Контекст.Список); + КонецЕсли; + + Если ИспользуемыеТипыЗначений = Неопределено Тогда + Если Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Контекст.Список + Или Не ЗначениеЗаполнено(Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы) Тогда + Возврат Ложь; + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка вызова функции %1 общего модуля %2: + |Для таблицы %3 + |не заполнены используемые типы значений доступа.'"), + "ТипЗначенийДоступаИспользуется", + "УправлениеДоступомСлужебный", + Контекст.Список); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Возврат ИспользуемыеТипыЗначений.Получить(ТипЗначений) <> Неопределено; + +КонецФункции + +// Для функции УпрощенноеУсловиеОграничения. +Функция РезультатФункцииПравоОбъектаРазрешено(Условие, ТипыКонечногоПоля, Контекст) + + Если Контекст.ОграничениеДоступаВключено Тогда + Возврат Неопределено; + КонецЕсли; + + РезультатВсегдаИстина = Истина; + + Для Каждого Тип Из ТипыКонечногоПоля Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Условие, ИмяТипа); + Если Уточнение = "Истина" Тогда + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + РезультатВсегдаИстина = Ложь; + Прервать; + КонецЕсли; + + Если Не ТипПроверяется(Условие, ИмяТипа) Тогда + РезультатВсегдаИстина = Ложь; + Прервать; + КонецЕсли; + + Значение = Контекст.ТипыВладельцевНастроекПрав.Получить(Тип); + Если Значение = Неопределено + Или ВРег(Контекст.Список) <> ВРег(Значение[0].ВладелецПрав) Тогда + + РезультатВсегдаИстина = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + + Если РезультатВсегдаИстина Тогда + Возврат Истина; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ЗаполнитьСвойстваПолей. +Функция ОбработанноеСовмещенноеПоле(ОбработанныеОдинаковыеПоля, СвойстваПоля) + + Для Каждого Поле Из ОбработанныеОдинаковыеПоля Цикл + Совместимо = Истина; + Если Поле.ПсевдонимТаблицы = "ТекущийСписок" + И Поле.НесколькоГруппЗначений <> СвойстваПоля.НесколькоГруппЗначений Тогда + Продолжить; + КонецЕсли; + // По пустой ссылке на ключ доступа или значению Null невозможно определить тип значения, + // поэтому сохранение ключа доступа несовместимо с остальными вариантами. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияКлючейДоступа Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияГруппЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Тип Из Поле.ТипыСохраненияКлючейДоступа Цикл + Если СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияГруппЗначений.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если Не Совместимо Тогда + Продолжить; + КонецЕсли; + // По значению Null вместо группы значений невозможно определить тип значения, + // поэтому сохранение группы значений несовместимо с остальными вариантами. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияГруппЗначений Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Тип Из Поле.ТипыСохраненияГруппЗначений Цикл + Если СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + // Вместо простых типов сохраняется значения ТипРазрешенный или ТипЗапрещенный, + // поэтому сохранение запрещенного простого типа несовместимо с остальными вариантами. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаЗапрещенный Цикл + Если Не ЭтоПростойТип(Тип) Тогда + Продолжить; + КонецЕсли; + Если Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Тип Из Поле.ТипыСохраненияТипаЗапрещенный Цикл + Если Не ЭтоПростойТип(Тип) Тогда + Продолжить; + КонецЕсли; + Если СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если Не Совместимо Тогда + Продолжить; + КонецЕсли; + // Объединение уточнений специальных значений. + Поле.ЕстьУточнениеNull = + Поле.ЕстьУточнениеNull Или СвойстваПоля.ЕстьУточнениеNull; + Поле.ЕстьУточнениеНеопределено = + Поле.ЕстьУточнениеНеопределено Или СвойстваПоля.ЕстьУточнениеНеопределено; + Поле.ЕстьТипВедущегоСписка = + Поле.ЕстьТипВедущегоСписка Или СвойстваПоля.ЕстьТипВедущегоСписка; + Поле.ЕстьТипВладельцаНастроекПрав = + Поле.ЕстьТипВладельцаНастроекПрав Или СвойстваПоля.ЕстьТипВладельцаНастроекПрав; + Поле.ЕстьПроверкаАвторизованногоПользователя = + Поле.ЕстьПроверкаАвторизованногоПользователя Или СвойстваПоля.ЕстьПроверкаАвторизованногоПользователя; + // Объединение типов сохранения пустой ссылки. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияПустойСсылки Цикл + Если Поле.ТипыСохраненияПустойСсылки.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Поле.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения значения ТипРазрешенный. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаРазрешенный Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); + Поле.ТипыСохраненияТипов.Добавить(Тип); + Продолжить; + КонецЕсли; + Поле.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения значения ТипЗапрещенный. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаЗапрещенный Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); + Поле.ТипыСохраненияТипов.Добавить(Тип); + Продолжить; + КонецЕсли; + Поле.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения типа значения. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипов Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); + КонецЕсли; + Поле.ТипыСохраненияТипов.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения значения. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияЗначений Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипов.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипов.Удалить(Индекс); + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); + КонецЕсли; + Поле.ТипыСохраненияЗначений.Добавить(Тип); + КонецЦикла; + // Объединение неиспользуемых типов значений доступа. + Для Каждого Тип Из СвойстваПоля.НеиспользуемыеТипыЗначенийДоступа Цикл + Если Поле.НеиспользуемыеТипыЗначенийДоступа.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Поле.НеиспользуемыеТипыЗначенийДоступа.Добавить(Тип); + КонецЦикла; + // Объединение используемых типов значений доступа. + Для Каждого Тип Из СвойстваПоля.ИспользуемыеТипыЗначенийДоступа Цикл + Если Поле.ИспользуемыеТипыЗначенийДоступа.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Поле.ИспользуемыеТипыЗначенийДоступа.Добавить(Тип); + КонецЦикла; + Поле.Чтение = Поле.Чтение Или СвойстваПоля.Чтение; + Если Поле.ТипыСтрокой <> СвойстваПоля.ТипыСтрокой Тогда + Поле.ТипыСтрокой = Поле.ТипыСтрокой + Символы.ПС + СвойстваПоля.ТипыСтрокой; + КонецЕсли; + Возврат Поле; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ЗаполнитьСвойстваПолей. +Процедура УточнитьСвойстваПоляСравнения(Свойства, ОписаниеПоля, Контекст) + + Контекст.СвойстваПолейКлючаДоступа.Вставить(ОписаниеПоля.Поле, Свойства); + + Родитель = ОписаниеПоля.Родители[0]; + + Узлы = ",ТипЗначения,=,<>,В,ЕстьNull,"; // В ключ сохраняется результат сравнения. + Если СтрНайти(Узлы, "," + Родитель.Узел + ",") = 0 Тогда + Возврат; + КонецЕсли; + + Если Родитель.Узел = "ТипЗначения" Тогда + РодительУзлаСравнения = ОписаниеПоля.Родители[1]; + + Если РодительУзлаСравнения.ВторойАргумент = Родитель Тогда + УзелТип = РодительУзлаСравнения.ПервыйАргумент; // См. ОписаниеУзла + УзелТипЗначения = РодительУзлаСравнения.ВторойАргумент; + Иначе + УзелТип = РодительУзлаСравнения.ВторойАргумент; // См. ОписаниеУзла + УзелТипЗначения = РодительУзлаСравнения.ПервыйАргумент; + КонецЕсли; + Контекст.СвойстваПолейКлючаДоступа.Вставить(УзелТипЗначения, Свойства); + + ВыражениеТипаЗначения = "ТИПЗНАЧЕНИЯ(" + Свойства.ИмяПоляДляЗапроса + ")"; // @query-part-1 + ВыражениеТипа = "ТИП(" + УзелТип.Имя + ")"; // @query-part-1 + ОднойСтрокой = СтрДлина(ВыражениеТипаЗначения) + СтрДлина(ВыражениеТипа) < 60; + + Свойства.ИмяПоляДляЗапроса = ВыражениеТипаЗначения + ?(ОднойСтрокой, " ", " + | ") + РодительУзлаСравнения.Узел + " " + ВыражениеТипа; + + ИначеЕсли Родитель.Узел = "=" + Или Родитель.Узел = "<>" Тогда + + УзелЗначениеИлиКонстанта = ?(Родитель.ВторойАргумент = ОписаниеПоля.Поле, + Родитель.ПервыйАргумент, Родитель.ВторойАргумент); + + ВыражениеУзла = ВыражениеУзлаЗначениеИлиКонстанта(УзелЗначениеИлиКонстанта); + ОднойСтрокой = СтрДлина(Свойства.ИмяПоляДляЗапроса) + СтрДлина(ВыражениеУзла) < 60; + + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + ?(ОднойСтрокой, " ", " + | ") + Родитель.Узел + " " + ВыражениеУзла; + + ИначеЕсли Родитель.Узел = "В" Тогда + + СписокЗначений = ""; + Для Каждого УзелЗначениеИлиКонстанта Из Родитель.Значения Цикл + СписокЗначений = СписокЗначений + ?(СписокЗначений = "", "", ","); + ПоследняяСтрока = СтрПолучитьСтроку(СписокЗначений, СтрЧислоСтрок(СписокЗначений)); + Если СтрДлина(ПоследняяСтрока) > 40 Тогда + СписокЗначений = СписокЗначений + " + | "; + Иначе + СписокЗначений = СписокЗначений + " "; + КонецЕсли; + СписокЗначений = СписокЗначений + + ВыражениеУзлаЗначениеИлиКонстанта(УзелЗначениеИлиКонстанта); + КонецЦикла; + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " + | В (" + СписокЗначений + ")"; + + Иначе // Родитель.Узел = "ЕстьNull". + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " ЕСТЬ NULL"; + Свойства.Вставить("ПроверкаЕстьNull"); + КонецЕсли; + + Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); + +КонецПроцедуры + +// Для процедуры ЗаполнитьСвойстваПолей. +Функция НаборПолейУсловияКогда(ИсходныеСвойстваПоля, ОписаниеПоля, Контекст) + + Родитель = ОписаниеПоля.Родители[0]; + НаборПолей = Новый Массив; + + Если Родитель.Узел <> "Выбор" + Или Родитель.Выбор = Неопределено Тогда + + НаборПолей.Добавить(ИсходныеСвойстваПоля); + Возврат НаборПолей; + КонецЕсли; + + // Для "ВЫБОР <Поле> КОГДА <Значение>" в ключ сохраняется + // результат сравнения "<Поле> = <Значение>". + + Для Каждого ОписаниеКогда Из Родитель.Когда Цикл + ФиксированныеСвойства = Новый ФиксированнаяСтруктура(ИсходныеСвойстваПоля); + Свойства = Новый Структура(ФиксированныеСвойства); + + ВыражениеУзла = ВыражениеУзлаЗначениеИлиКонстанта(ОписаниеКогда.Условие); + ОднойСтрокой = СтрДлина(Свойства.ИмяПоляДляЗапроса) + СтрДлина(ВыражениеУзла) < 60; + + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + ?(ОднойСтрокой, " = ", " + | = ") + ВыражениеУзла; + + Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); + НаборПолей.Добавить(Свойства); + + Контекст.СвойстваПолейКлючаДоступа.Вставить(ОписаниеКогда.Условие, Свойства); + КонецЦикла; + + Возврат НаборПолей; + +КонецФункции + +// Для функций СвойстваПоля, УточнитьСвойстваПоляСравнения, НаборПолейУсловияКогда. +Функция БезЗначенияNull(СвойстваПоля) + + Возврат СтрЧислоВхождений(СвойстваПоля.ИмяПоляДляЗапроса, ".") = 1 + И Не СвойстваПоля.Свойство("ПолеСодержитNull") + И СтрНачинаетсяС(СвойстваПоля.ИмяПоляДляЗапроса, "ТекущийСписок."); + +КонецФункции + +// Для процедуры ЗаполнитьСвойстваПолей. +// +// Параметры: +// Свойства - см. СвойстваПоля +// ОписаниеПоля - см. НовоеПолеКлючаДоступа +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ДобавитьСвойстваТиповПоля(Свойства, ОписаниеПоля, Контекст) + + Свойства.Вставить("ТипыСохраненияКлючейДоступа", Новый Массив); + Свойства.Вставить("ТипыСохраненияГруппЗначений", Новый Массив); + Свойства.Вставить("ТипыСохраненияЗначений", Новый Массив); + Свойства.Вставить("ТипыСохраненияПустойСсылки", Новый Массив); + Свойства.Вставить("ТипыСохраненияТипов", Новый Массив); + Свойства.Вставить("ТипыСохраненияТипаЗапрещенный", Новый Массив); + Свойства.Вставить("ТипыСохраненияТипаРазрешенный", Новый Массив); + Свойства.Вставить("НеиспользуемыеТипыЗначенийДоступа", Новый Массив); + Свойства.Вставить("ИспользуемыеТипыЗначенийДоступа", Новый Массив); + Свойства.Вставить("НесколькоГруппЗначений", Ложь); + Свойства.Вставить("ЭтоСписокЗначенийДоступаСГруппамиЗначений", Ложь); + Свойства.Вставить("ЕстьУточнениеNull", Ложь); + Свойства.Вставить("ЕстьУточнениеНеопределено", Ложь); + Свойства.Вставить("ЕстьТипВедущегоСписка", Ложь); + Свойства.Вставить("ЕстьТипВладельцаНастроекПрав", Ложь); + Свойства.Вставить("ЕстьПроверкаАвторизованногоПользователя", Ложь); + + Родитель = ОписаниеПоля.Родители[0]; + + Если Родитель.Узел = "ЧтениеОбъектаРазрешено" + Или Родитель.Узел = "ИзменениеОбъектаРазрешено" + Или Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ИзменениеСпискаРазрешено" + Или Родитель.Узел = "ЗначениеРазрешено" + Или Родитель.Узел = "ЭтоАвторизованныйПользователь" Тогда + + ЕстьУточнениеПустойСсылки = ТипУточнен(Родитель, "ПустаяСсылка"); + Свойства.ЕстьУточнениеNull = ТипУточнен(Родитель, "Null") Или Свойства.Свойство("ЕстьВыразить"); + Свойства.ЕстьУточнениеНеопределено = ТипУточнен(Родитель, "Неопределено"); + КонецЕсли; + + Если Родитель.Узел = "ЧтениеОбъектаРазрешено" + Или Родитель.Узел = "ИзменениеОбъектаРазрешено" + Или Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ИзменениеСпискаРазрешено" Тогда + + Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Родитель, ИмяТипа); + Если Уточнение = "Истина" Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если ЭтоПростойТип(Тип) Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") + Или Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Свойства.ЕстьТипВедущегоСписка = Истина; + + ВидОграничения = ?(Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ЧтениеОбъектаРазрешено", "ПравоЧтения", "ПравоИзменения"); + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Если Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ИзменениеСпискаРазрешено" Тогда + + Свойства.ТипыСохраненияТипов.Добавить(Тип); + Свойства.ЕстьТипВедущегоСписка = Истина; + + ВидОграничения = ?(Родитель.Узел = "ЧтениеСпискаРазрешено", "ПравоЧтения", "ПравоИзменения"); + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено + И Не Контекст.ИспользуетсяОграничениеПоВладельцу + И ( Контекст.СпискиСОграничением.Получить(ИмяТипа) = Неопределено + Или Контекст.СпискиСОтключеннымОграничением.Получить(ИмяТипа) <> Неопределено) Тогда + + Свойства.ТипыСохраненияТипов.Добавить(Тип); + Свойства.ЕстьТипВедущегоСписка = Истина; + + ВидОграничения = ?(Родитель.Узел = "ЧтениеОбъектаРазрешено", "ПравоЧтения", "ПравоИзменения"); + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Если ЕстьУточнениеПустойСсылки Тогда + Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЕсли; + + ИмяВедущегоПрава = ?(Родитель.Узел = "ЧтениеОбъектаРазрешено", "Чтение", "Изменение"); + + Значение = Контекст.ТипыВладельцевНастроекПрав.Получить(Тип); + Если Значение <> Неопределено + И (ВРег(Контекст.Список) = ВРег(Значение[0].ВладелецПрав) + Или Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено + И Не Контекст.ИспользуетсяОграничениеПоВладельцу) Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Свойства.ЕстьТипВладельцаНастроекПрав = Истина; + ВидОграничения = "НастройкиПрав." + ИмяТипа + "." + ИмяВедущегоПрава; + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Свойства.ТипыСохраненияКлючейДоступа.Добавить(Тип); + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Неопределено + Или ( Контекст.СпискиСОграничением.Получить(ИмяТипа) <> Неопределено + И Контекст.СпискиСОтключеннымОграничением.Получить(ИмяТипа) = Неопределено) Тогда + + ДобавитьВедущийСписокПоПолюСсылка(Контекст.ВедущиеСпискиПоКлючамДоступа, + ИмяТипа, ОписаниеПоля, Свойства, Контекст); + + ВидОграничения = "Объект." + ИмяТипа + "." + ИмяВедущегоПрава; + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + КонецЕсли; + КонецЦикла; + + Возврат; + КонецЕсли; + + Если Родитель.Узел = "ЗначениеРазрешено" Тогда + СвойстваВидовДоступа = Контекст.СвойстваВидовДоступа; + ОтключеноКакЛожь = УточнениеТипа(Родитель, "Отключено") = "Ложь"; + + Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Родитель, ИмяТипа); + Если Уточнение = "Истина" Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + СвойстваВидаДоступа = СвойстваВидовДоступа.ПоТипамГруппИЗначений.Получить(Тип); // См. СвойстваВидаДоступа + Если СвойстваВидаДоступа = Неопределено Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Тип = Контекст.ОбратныйТипПользователя + Или Тип = Контекст.ОбратныйТипГруппыПользователей Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + ДобавитьВидОграниченияПрав(СвойстваВидаДоступа.Имя, Свойства, Контекст); + + Если Не ТипЗначенийДоступаИспользуется(Контекст, СвойстваВидаДоступа.ТипЗначений) Тогда + Свойства.НеиспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); + + Если ОтключеноКакЛожь Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Иначе + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + КонецЕсли; + Продолжить; + КонецЕсли; + + Свойства.ИспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); + + Если СвойстваВидовДоступа.ПоТипамЗначений.Получить(Тип) = Неопределено Тогда + // Тип группы значений доступа. + Если Контекст.Список = Метаданные.НайтиПоТипу(Тип).ПолноеИмя() + Или Контекст.ТипыПользователя.Найти(Тип) <> Неопределено Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Иначе + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + КонецЕсли; + Продолжить; + КонецЕсли; + + Если ЕстьУточнениеПустойСсылки Тогда + Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЕсли; + + Если СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами.Получить(Тип) = Неопределено + Или Контекст.ТипыПользователя.Найти(Тип) <> Неопределено Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Продолжить; + КонецЕсли; + Свойства.ТипыСохраненияГруппЗначений.Добавить(Тип); + + Если Контекст.Список = ИмяТипа + И ВРег(Свойства.ИмяПоляДляЗапроса) = ВРег("ТекущийСписок.Ссылка") Тогда // @query-part-1 + + Свойства.ЭтоСписокЗначенийДоступаСГруппамиЗначений = Истина; + Иначе + ДобавитьВедущийСписокПоПолюСсылка(Контекст.ВедущиеСпискиПоЗначениямСГруппами, + ИмяТипа, ОписаниеПоля, Свойства, Контекст); + КонецЕсли; + + Если Не СвойстваВидаДоступа.НесколькоГруппЗначений Тогда + Продолжить; + КонецЕсли; + Свойства.НесколькоГруппЗначений = Истина; + КонецЦикла; + + Возврат; + КонецЕсли; + + Если Родитель.Узел = "ЭтоАвторизованныйПользователь" Тогда + Свойства.ЕстьПроверкаАвторизованногоПользователя = Истина; + ДобавитьВидОграниченияПрав("ФункцияЭтоАвторизованныйПользователь", Свойства, Контекст); + + Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Родитель, ИмяТипа); + Если Уточнение = "Истина" Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Тип <> Тип("СправочникСсылка.Пользователи") + И Тип <> Тип("СправочникСсылка.ВнешниеПользователи") Тогда + + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если ЕстьУточнениеПустойСсылки Тогда + Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЕсли; + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + КонецЦикла; + + Возврат; + КонецЕсли; + + // Остались только узлы Поле для получения значения Булево. + Свойства.ТипыСохраненияЗначений.Добавить(Тип("Булево")); + + Если Свойства.ТипКонечногоПоля.Типы().Количество() = 1 + И Свойства.ТипКонечногоПоля.СодержитТип(Тип("Булево")) Тогда + Возврат; + КонецЕсли; + Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " = ИСТИНА"; // @query-part-1 + +КонецПроцедуры + +// Для функций СвойстваПоля, ДобавитьСвойстваТиповПоля. +Функция ИмяТипаНаЯзыкеЗапросов(Тип, ОбъектМетаданных = Неопределено) + + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + Если ОбъектМетаданных <> Неопределено Тогда + Возврат ОбъектМетаданных.ПолноеИмя(); + КонецЕсли; + + Возврат Строка(Тип); + +КонецФункции + +// Для процедуры ДобавитьСвойстваТиповПоля. +Процедура ДобавитьВидОграниченияПрав(ВидОграничения, СвойстваПоля, Контекст, ПоОбъекту = Ложь) + + Если СвойстваПоля.Чтение Тогда + Контекст.ВсеВидыОграниченийПрав.Вставить("Чтение." + ВидОграничения, Истина); + КонецЕсли; + Если Не ПоОбъекту Или СвойстваПоля.Изменение Тогда + Контекст.ВсеВидыОграниченийПрав.Вставить("Изменение." + ВидОграничения, Истина); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьСвойстваПолей. +// +// Параметры: +// УзелПоле - см. ОписаниеУзла +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// СвойстваПоля - см. СвойстваПоля +// +// Возвращаемое значение: +// Структура: +// * ПсевдонимТаблицы - Строка +// * ИмяПоляДляЗапроса - Строка +// * ТабличнаяЧасть - Строка +// * ЭтоПолеСписка - Булево +// * БезЗначенияNull - Булево +// * ПолеСодержитNull - Неопределено +// * ЕстьВыразить - Неопределено +// * УзелПоле - см. ОписаниеУзла +// * СвойстваВложения - см. СвойстваПоля +// * Чтение - Булево +// * ПроверкаЕстьNull - Неопределено +// * ТипыСохраненияКлючейДоступа - Массив из Тип +// * ТипыСохраненияГруппЗначений - Массив из Тип +// * ТипыСохраненияЗначений - Массив из Тип +// * ТипыСохраненияПустойСсылки - Массив из Тип +// * ТипыСохраненияТипов - Массив из Тип +// * ТипыСохраненияТипаЗапрещенный - Массив из Тип +// * ТипыСохраненияТипаРазрешенный - Массив из Тип +// * НеиспользуемыеТипыЗначенийДоступа - Массив из Тип +// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип +// * НесколькоГруппЗначений - Булево +// * ЭтоСписокЗначенийДоступаСГруппамиЗначений - Булево +// * ЕстьУточнениеNull - Булево +// * ЕстьУточнениеНеопределено - Булево +// * ЕстьТипВедущегоСписка - Булево +// * ЕстьТипВладельцаНастроекПрав - Булево +// * ЕстьПроверкаАвторизованногоПользователя - Булево +// * ТипыСохраненияТиповКонфигурации - Массив из Тип +// * ТипыСохраненияТиповРасширений - Массив из Тип +// * ТипыСохраненияТиповПростых - Массив из Тип +// * ИмяГруппыПолейКлючаДоступа - Строка +// * ИмяРеквизитаГруппыПолейКлючаДоступа - Строка +// +Функция СвойстваПоля(УзелПоле, Контекст, СвойстваПоля = Неопределено) + + Свойства = Новый Структура; + ЭтоКорневойУзел = СвойстваПоля = Неопределено; + + Если ЭтоКорневойУзел Тогда + СвойстваПоля = Свойства; + // Внутри функции ЕстьNull() может быть только поле, т.е. функции Выразить() не может быть. + Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + Типы = Новый Массив; + Типы.Добавить(ТипСсылкиПоПолномуИмениМетаданных(УзелПоле.Выразить)); + ТипКонечногоПоля = Новый ОписаниеТипов(Типы); + Иначе + ТипКонечногоПоля = УзелПоле.ТипыПоля[УзелПоле.ТипыПоля.Количество() - 1]; + Если ЗначениеЗаполнено(УзелПоле.ЕстьNull) Тогда + Типы = Новый Массив; + Типы.Добавить(ТипЗначенияУзлаЗначениеИлиКонстанта(УзелПоле.ЕстьNull)); + ТипКонечногоПоля = Новый ОписаниеТипов(ТипКонечногоПоля, Типы); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если УзелПоле.Вложение <> Неопределено Тогда + СвойстваВложения = СвойстваПоля(УзелПоле.Вложение, Контекст, СвойстваПоля); + ТабличнаяЧасть = СвойстваВложения.ТабличнаяЧасть; + ПсевдонимТаблицы = СвойстваВложения.ПсевдонимТаблицы; + ИмяПоляДляЗапроса = СвойстваВложения.ИмяПоляДляЗапроса + "." + УзелПоле.Имя; + ТипыСтрокой = СвойстваВложения.ТипыСтрокой + Символы.ПС + УзелПоле.ТипыСтрокой; + Иначе + Если ТипЗнч(УзелПоле.ТипыПоля[0]) = Тип("ОписаниеТипов") Тогда + ТабличнаяЧасть = ""; + Если ЗначениеЗаполнено(УзелПоле.Псевдоним) + И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + + ПсевдонимТаблицы = УзелПоле.Псевдоним; + ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + УзелПоле.Имя; + Иначе + ПсевдонимТаблицы = "ТекущийСписок"; + ДобавитьОпорноеПоле(Контекст, УзелПоле, СвойстваПоля); + Если Не ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + ИмяПоляДляЗапроса = ТекстСОтступом( + ИмяПоляСРазверткойОпорногоПоляПоТипам(ПсевдонимТаблицы, УзелПоле), " "); + Иначе + ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + УзелПоле.Имя; + КонецЕсли; + КонецЕсли; + Иначе // Первая часть имени поля - это имя табличной части. + ТабличнаяЧасть = УзелПоле.ТипыПоля[0]; + ПсевдонимТаблицы = "ТекущийСписок" + ТабличнаяЧасть; + ЧастиИмени = СтрРазделить(УзелПоле.Имя, "."); + ЧастиИмени.Удалить(0); + ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + СтрСоединить(ЧастиИмени, "."); + КонецЕсли; + ДобавитьПолеТаблицыОбъекта(Контекст, УзелПоле, СвойстваПоля,, ТабличнаяЧасть); + ТипыСтрокой = УзелПоле.ТипыСтрокой; + КонецЕсли; + + // Внутри функции ЕстьNull() может быть только поле, т.е. функции Выразить() не может быть. + Если ЗначениеЗаполнено(УзелПоле.ЕстьNull) Тогда + ИмяПоляДляЗапроса = "ЕСТЬNULL(" + ИмяПоляДляЗапроса + ", " + + ВыражениеУзлаЗначениеИлиКонстанта(УзелПоле.ЕстьNull) + ")"; // @query-part-1 + + Если ЭтоКорневойУзел Тогда + Свойства.Вставить("БезЗначенияNull", Истина); + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + ИмяПоляДляЗапроса = "ВЫРАЗИТЬ(" + ИмяПоляДляЗапроса + " КАК " + УзелПоле.Выразить + ")"; // @query-part-1, @query-part-2 + СвойстваПоля.Вставить("ЕстьВыразить"); + КонецЕсли; + + Свойства.Вставить("ПсевдонимТаблицы", ПсевдонимТаблицы); + Свойства.Вставить("ИмяПоляДляЗапроса", ИмяПоляДляЗапроса); + Свойства.Вставить("ТипКонечногоПоля", ТипКонечногоПоля); + Свойства.Вставить("ТипыСтрокой", ТипыСтрокой); + + Если УзелПоле.Свойство("ПолеСодержитNull") Тогда + Свойства.Вставить("ПолеСодержитNull"); + КонецЕсли; + + // Для расчета ведущих списков. + Свойства.Вставить("ТабличнаяЧасть", ТабличнаяЧасть); + Свойства.Вставить("СвойстваВложения", СвойстваВложения); + Свойства.Вставить("УзелПоле", УзелПоле); + Свойства.Вставить("ЭтоПолеСписка", + ПсевдонимТаблицы = "ТекущийСписок" + Или СвойстваВложения <> Неопределено + И ЗначениеЗаполнено(СвойстваВложения.ТабличнаяЧасть)); + + Возврат Свойства; + +КонецФункции + + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения. +// +// Возвращаемое значение: +// Структура: +// * Поля - Соответствие +// * СоединенияОтборов - Соответствие +// +Функция ОписаниеВедущихСписковПоЗначениямПолей() + + Возврат Новый Структура("Поля, СоединенияОтборов", Новый Соответствие, Новый Соответствие); + +КонецФункции + +// Для функций ГруппыДополнительныхТаблиц. +Процедура ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, УзелПоле, СвойстваВложения = Неопределено, + ГруппаТаблиц = Неопределено, ПсевдонимТаблицыУсловия = Неопределено) + + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("СвойстваПоляРодителя", СвойстваВложения); + ДополнительныйКонтекст.Вставить("ГруппаТаблиц", ГруппаТаблиц); + ДополнительныйКонтекст.Вставить("ПсевдонимТаблицыУсловия", ПсевдонимТаблицыУсловия); + ДополнительныйКонтекст.Вставить("ПсевдонимТаблицыПоля", УзелПоле.Псевдоним); + + ИменаПолей = СтрРазделить(УзелПоле.Имя, "."); + + Если УзелПоле.Вложение <> Неопределено Тогда + ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, УзелПоле.Таблица, ИменаПолей[0], + УзелПоле.ТипыПоля[0], ДополнительныйКонтекст, Истина, Истина); + + ИначеЕсли ЗначениеЗаполнено(УзелПоле.Псевдоним) + И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + + ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, УзелПоле.Таблица, ИменаПолей[0], + УзелПоле.ТипыПоля[0], ДополнительныйКонтекст); + КонецЕсли; + + ИндексПервогоПоля = ?(ТипЗнч(УзелПоле.ТипыПоля[0]) = Тип("ОписаниеТипов"), 0, 1); + + Если ИндексПервогоПоля + 2 > ИменаПолей.Количество() Тогда + Возврат; + КонецЕсли; + + СвойстваПоляРодителя = Новый Структура("ИмяПоляДляЗапроса, ТабличнаяЧасть"); + Если СвойстваВложения <> Неопределено Тогда + ЗаполнитьЗначенияСвойств(СвойстваПоляРодителя, СвойстваВложения); + СвойстваПоляРодителя.ИмяПоляДляЗапроса = СвойстваПоляРодителя.ИмяПоляДляЗапроса + "." + ИменаПолей[ИндексПервогоПоля]; + Иначе + Если ИндексПервогоПоля > 0 Тогда + СвойстваПоляРодителя.ТабличнаяЧасть = ИменаПолей[0]; + КонецЕсли; + Если Не ЗначениеЗаполнено(УзелПоле.Псевдоним) + Или УзелПоле.Псевдоним = Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + + ПсевдонимПоляРодителя = "ТекущийСписок"; + ДополнительныйКонтекст.ГруппаТаблиц = Неопределено; + Иначе + ПсевдонимПоляРодителя = УзелПоле.Псевдоним; + КонецЕсли; + СвойстваПоляРодителя.ИмяПоляДляЗапроса = ПсевдонимПоляРодителя + "." + ИменаПолей[ИндексПервогоПоля]; + КонецЕсли; + ДополнительныйКонтекст.СвойстваПоляРодителя = СвойстваПоляРодителя; + + Для Индекс = ИндексПервогоПоля + 1 По ИменаПолей.Количество()-1 Цикл + Поле = ИменаПолей[Индекс]; + ТипПоля = УзелПоле.ТипыПоля[Индекс]; + Для Каждого Таблица Из УзелПоле.ТаблицыСледующегоПоля[Индекс-1] Цикл + ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, Таблица, Поле, + ТипПоля, ДополнительныйКонтекст, Истина, Истина); + КонецЦикла; + СвойстваПоляРодителя.ИмяПоляДляЗапроса = СвойстваПоляРодителя.ИмяПоляДляЗапроса + "." + Поле; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьВедущиеСпискиПоЗначениямПолей. +Процедура ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, Таблица, Поле, ТипПоля, ДополнительныйКонтекст, + ЭтоОсновнаяТаблица = Ложь, ЭтоСсылочныйТипТаблицы = Неопределено) + + Если Не ЭтоОсновнаяТаблица + И СтрЧислоВхождений(Таблица, ".") = 2 Тогда + + СоставИмени = СтрРазделить(Таблица, "."); + ТабличнаяЧасть = СоставИмени[2]; + СоставИмени.Удалить(2); + ПолноеИмя = СтрСоединить(СоставИмени, "."); + Иначе + ТабличнаяЧасть = ""; + ПолноеИмя = Таблица; + КонецЕсли; + + Если ТипЗнч(ДополнительныйКонтекст.ГруппаТаблиц) <> Тип("Массив") + И ( ВРег(Поле) = ВРег("Ссылка") + Или ВРег(Поле) = ВРег("Ref")) Тогда // @Non-NLS-2 + + Если ЭтоСсылочныйТипТаблицы = Неопределено Тогда + СоставИмени = СтрРазделить(Таблица, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ЭтоСсылочныйТипТаблицы = ТипТаблицы.ЭтоСсылочныйТип; + КонецЕсли; + Если ЭтоСсылочныйТипТаблицы Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + ОписаниеПолей = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Получить(ПолноеИмя); + ОписаниеСоединений = Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов.Получить(ПолноеИмя); + + Если ОписаниеПолей = Неопределено Тогда + Если ЭтоСсылочныйТипТаблицы = Неопределено Тогда + СоставИмени = СтрРазделить(Таблица, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ЭтоСсылочныйТипТаблицы = ТипТаблицы.ЭтоСсылочныйТип; + КонецЕсли; + ОписаниеПолей = Новый Структура; + ОписаниеПолей.Вставить("ЭтоСсылочныйТип", ЭтоСсылочныйТипТаблицы); + ОписаниеПолей.Вставить("ДляОтслеживания", Новый Структура("ПоляШапки, ТабличныеЧасти", + Новый Соответствие, Новый Соответствие)); + ОписаниеПолей.Вставить("ДляОтбора", Новый Структура("ПоляШапки, ТабличныеЧасти", + Новый Соответствие, Новый Соответствие)); + Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Вставить(ПолноеИмя, ОписаниеПолей); + + ОписаниеСоединений = Новый Структура("ПоляШапки, ТабличныеЧасти", Новый Соответствие, Новый Соответствие); + Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов.Вставить(ПолноеИмя, ОписаниеСоединений); + КонецЕсли; + + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтслеживания, ТабличнаяЧасть, Поле, ТипПоля); + + Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда + СоединенияОтборов = ОписаниеСоединений.ТабличныеЧасти.Получить(ТабличнаяЧасть); + Если СоединенияОтборов = Неопределено Тогда + СоединенияОтборов = Новый Соответствие; + ОписаниеСоединений.ТабличныеЧасти.Вставить(ТабличнаяЧасть, СоединенияОтборов); + КонецЕсли; + Иначе + СоединенияОтборов = ОписаниеСоединений.ПоляШапки; + КонецЕсли; + + Если ДополнительныйКонтекст.СвойстваПоляРодителя <> Неопределено Тогда + Если СоставИмени = Неопределено Тогда + СоставИмени = СтрРазделить(Таблица, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + КонецЕсли; + ТипСсылки = Новый ОписаниеТипов(ТипТаблицы.ЯзыкРусский + "Ссылка." + СоставИмени[1]); // @Non-NLS + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтслеживания, "", "Ссылка", ТипСсылки); + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтбора, "", "Ссылка", ТипСсылки); + ИмяПоляДляЗапроса = ДополнительныйКонтекст.СвойстваПоляРодителя.ИмяПоляДляЗапроса; + СоединениеОтбора = СоединенияОтборов.Получить(ВРег(ИмяПоляДляЗапроса)); + Если СоединениеОтбора = Неопределено Тогда + СоединениеОтбора = Новый Структура; + СоединениеОтбора.Вставить("ПолеИлиПсевдоним", ИмяПоляДляЗапроса); + СоединениеОтбора.Вставить("ПоляДляОтбора", "Ссылка"); + СоединениеОтбора.Вставить("ТабличнаяЧасть", ДополнительныйКонтекст.СвойстваПоляРодителя.ТабличнаяЧасть); + СоединениеОтбора.Вставить("ГруппаТаблиц", ДополнительныйКонтекст.ГруппаТаблиц); + СоединенияОтборов.Вставить(ВРег(ИмяПоляДляЗапроса), СоединениеОтбора); + КонецЕсли; + Иначе + Если ТипЗнч(ДополнительныйКонтекст.ГруппаТаблиц) = Тип("Массив") Тогда + СоединениеОтбора = СоединенияОтборов.Получить(ВРег(ДополнительныйКонтекст.ПсевдонимТаблицыПоля)); + Если СоединениеОтбора = Неопределено Тогда + СоединениеОтбора = Новый Структура; + СоединениеОтбора.Вставить("ПолеИлиПсевдоним", ДополнительныйКонтекст.ПсевдонимТаблицыПоля); + СоединениеОтбора.Вставить("ПоляДляОтбора", Новый Массив); + СоединениеОтбора.Вставить("ТабличнаяЧасть", Неопределено); + СоединениеОтбора.Вставить("ГруппаТаблиц", ДополнительныйКонтекст.ГруппаТаблиц); + СоединенияОтборов.Вставить(ВРег(ДополнительныйКонтекст.ПсевдонимТаблицыПоля), СоединениеОтбора); + КонецЕсли; + Если СоединениеОтбора.ПоляДляОтбора.Найти(Поле) = Неопределено + И ДополнительныйКонтекст.ПсевдонимТаблицыПоля = ДополнительныйКонтекст.ПсевдонимТаблицыУсловия Тогда + + СоединениеОтбора.ПоляДляОтбора.Добавить(Поле); + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтбора, ТабличнаяЧасть, Поле, ТипПоля); + КонецЕсли; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуру ДобавитьПолеВедущегоСпискаПоЗначениямПолей. +Процедура ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей, ТабличнаяЧасть, Поле, ТипПоля) + + Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда + Поля = ОписаниеПолей.ТабличныеЧасти.Получить(ТабличнаяЧасть); + Если Поля = Неопределено Тогда + Поля = Новый Соответствие; + ОписаниеПолей.ТабличныеЧасти.Вставить(ТабличнаяЧасть, Поля); + КонецЕсли; + Иначе + Поля = ОписаниеПолей.ПоляШапки; + КонецЕсли; + + Если Поля.Получить(Поле) <> Неопределено Тогда + Возврат; + КонецЕсли; + + Поля.Вставить(Поле, Новый ХранилищеЗначения(ТипПоля)); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения. +// +// Возвращаемое значение: +// Структура: +// * Списки - Соответствие +// * КлючиЗапросовПоТипам - Соответствие +// * СоединенияОтборов - Соответствие +// * ТипСсылки - ОписаниеТипов +// +Функция ОписаниеВедущихСписковПоПолюСсылка() + + Описание = Новый Структура; + Описание.Вставить("Списки", Новый Соответствие); + Описание.Вставить("КлючиЗапросовПоТипам", Новый Соответствие); + Описание.Вставить("СоединенияОтборов", Новый Соответствие); + Описание.Вставить("ТипСсылки", Новый ОписаниеТипов); + + Возврат Описание; + +КонецФункции + +// Для процедуры ДобавитьСвойстваТиповПоля. +Процедура ДобавитьВедущийСписокПоПолюСсылка(ВедущиеСписки, ВедущийСписок, УзелПоле, СвойстваПоля, Контекст) + + СоставИмени = СтрРазделить(ВедущийСписок, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ИмяТипаСсылки = ТипТаблицы.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS + + ВедущиеСписки.ТипСсылки = Новый ОписаниеТипов(ВедущиеСписки.ТипСсылки, ИмяТипаСсылки); + ТипСсылки = Тип(ИмяТипаСсылки); + + Ключи = ВедущиеСписки.КлючиЗапросовПоТипам.Получить(ТипСсылки); + Если Ключи = Неопределено Тогда + Ключи = Новый Массив; + ВедущиеСписки.КлючиЗапросовПоТипам.Вставить(ТипСсылки, Ключи); + ВедущиеСписки.Списки.Вставить(ВедущийСписок, Истина); + КонецЕсли; + + Ключ = ВРег(СвойстваПоля.ИмяПоляДляЗапроса); + Если Ключи.Найти(Ключ) = Неопределено Тогда + Ключи.Добавить(Ключ); + КонецЕсли; + + ГруппаТаблиц = ?(СвойстваПоля.ЭтоПолеСписка, Неопределено, СвойстваПоля.ПсевдонимТаблицы); + + СоединениеОтбора = ВедущиеСписки.СоединенияОтборов.Получить(Ключ); + Если СоединениеОтбора = Неопределено Тогда + СоединениеОтбора = Новый Структура; + СоединениеОтбора.Вставить("ПолеИлиПсевдоним", СвойстваПоля.ИмяПоляДляЗапроса); + СоединениеОтбора.Вставить("ПоляДляОтбора", "Ссылка"); // @query-part-2 + СоединениеОтбора.Вставить("ТабличнаяЧасть", СвойстваПоля.ТабличнаяЧасть); + СоединениеОтбора.Вставить("ГруппаТаблиц", ГруппаТаблиц); + ВедущиеСписки.СоединенияОтборов.Вставить(Ключ, СоединениеОтбора); + КонецЕсли; + +КонецПроцедуры + +// Для функции ГруппыДополнительныхТаблиц. +Процедура ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка(ВедущийСписок, Описание, Группы, Контекст) + + СоединенияОтборов = Новый Массив; + Для Каждого СоединениеОтбора Из Описание.ПоляШапки Цикл + СоединенияОтборов.Добавить(ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); + КонецЦикла; + Описание.ПоляШапки = СоединенияОтборов; + + ТабличныеЧасти = Новый Соответствие; + Для Каждого ОписаниеТабличнойЧасти Из Описание.ТабличныеЧасти Цикл + СоединенияОтборов = Новый Массив; + ТабличныеЧасти.Вставить(ОписаниеТабличнойЧасти.Ключ, СоединенияОтборов); + Для Каждого СоединениеОтбора Из ОписаниеТабличнойЧасти.Значение Цикл + СоединенияОтборов.Добавить(ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); + КонецЦикла; + КонецЦикла; + Описание.ТабличныеЧасти = ТабличныеЧасти; + +КонецПроцедуры + +// Для функции ГруппыДополнительныхТаблиц. +Процедура ЗаполнитьОтборыВедущихСписковПоПолюСсылка(ВедущиеСписки, Группы, Контекст) + + СоединенияОтборов = Новый Соответствие; + Для Каждого СоединениеОтбора Из ВедущиеСписки.СоединенияОтборов Цикл + СоединенияОтборов.Вставить(СоединениеОтбора.Ключ, + ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); + КонецЦикла; + ВедущиеСписки.СоединенияОтборов = СоединенияОтборов; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка. +Функция ТекстСоединенияОтбораПоЗначениямПолей(Условие, Группы, Контекст) + + Если Контекст.ЭтоСсылочныйТип Тогда + ДополнительноеУсловие = " + | И (&УточнениеПланаЗапроса)"; // @query-part-1 + Иначе + ДополнительноеУсловие = ?(Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей), " + | И (ТекущийСписок.Регистр = &ИдентификаторРегистра)", "") + " + | И (ТекущийСписок.ВариантДоступа = &ВариантДоступа) + | И (&УточнениеПланаЗапроса)"; // @query-part-1, @query-part-3 + КонецЕсли; + + Если Условие.ГруппаТаблиц = Неопределено Или ЗначениеЗаполнено(Условие.ТабличнаяЧасть) Тогда + ТекстСоединения = + "#ТекущиеДанныеДляОтбора КАК ТекущиеДанныеДляОтбора + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО (" + Условие.ПолеИлиПсевдоним + " = ТекущиеДанныеДляОтбора." + Условие.ПоляДляОтбора + ")"; // @query-part-1 + Если ЗначениеЗаполнено(Условие.ТабличнаяЧасть) Тогда + ТекстСоединения = СтрЗаменить(ТекстСоединения, + "&ТекущийСписок", "&ТекущийСписок." + Условие.ТабличнаяЧасть); + ТекстСоединения = СтрЗаменить(ТекстСоединения, + "ТекущийСписок" + Условие.ТабличнаяЧасть + ".", "ТекущийСписок."); + КонецЕсли; + Возврат ТекстСоединения + ДополнительноеУсловие; + КонецЕсли; + + Если ТипЗнч(Условие.ГруппаТаблиц) = Тип("Строка") Тогда + ЭтоПолеУсловияСоединения = Ложь; + ПсевдонимПолейОтбора = Условие.ГруппаТаблиц; + Группа = Группы.НомераПоПсевдонимам.Получить(ПсевдонимПолейОтбора); + ГруппаТаблиц = Группы.ТаблицыПоГруппам.Получить(Группа); + Иначе + ЭтоПолеУсловияСоединения = Истина; + ГруппаТаблиц = Условие.ГруппаТаблиц; + ЗаменяемоеПоле = Условие.ПолеИлиПсевдоним; + ПсевдонимПолейОтбора = СтрРазделить(ЗаменяемоеПоле, ".")[0]; + КонецЕсли; + + Индекс = ГруппаТаблиц.Количество(); + ПерваяДополнительнаяТаблицаНайдена = Ложь; + ОбратнаяГруппаТаблиц = Новый Массив; + ТребуемыеПсевдонимы = Новый Соответствие; + + Пока Индекс >= 1 Цикл + Индекс = Индекс - 1; + ДополнительнаяТаблица = ГруппаТаблиц[Индекс]; + ТекущийПсевдоним = ДополнительнаяТаблица.Псевдоним; + Если Не ПерваяДополнительнаяТаблицаНайдена И ТекущийПсевдоним <> ПсевдонимПолейОтбора Тогда + Продолжить; + КонецЕсли; + ПерваяДополнительнаяТаблицаНайдена = Истина; + Если ТекущийПсевдоним <> ПсевдонимПолейОтбора + И ТребуемыеПсевдонимы.Получить(ДополнительнаяТаблица.Псевдоним) = Неопределено Тогда + Продолжить; + КонецЕсли; + СвойстваТаблицы = Новый Структура("Таблица, Псевдоним, ПоляУсловияСоединения", + ДополнительнаяТаблица.Таблица, ДополнительнаяТаблица.Псевдоним, Новый Массив); + ОбратнаяГруппаТаблиц.Добавить(СвойстваТаблицы); + Для Каждого ПараПолей Из ДополнительнаяТаблица.ПоляУсловияСоединения Цикл + ТребуемыеПсевдонимы.Вставить(ПараПолей.ПервоеПоле.Псевдоним, Истина); + ТребуемыеПсевдонимы.Вставить(ПараПолей.ВтороеПоле.Псевдоним, Истина); + СвойстваТаблицы.ПоляУсловияСоединения.Добавить( + Новый Структура(Новый ФиксированнаяСтруктура(ПараПолей))); + КонецЦикла; + КонецЦикла; + + ВспомогательнаяТаблица = Неопределено; + ПерваяТаблица = ОбратнаяГруппаТаблиц[0]; + ВсеПервыеПоляЗаменяемые = Истина; + + Если ЭтоПолеУсловияСоединения Тогда + Для Каждого ПараПолей Из ПерваяТаблица.ПоляУсловияСоединения Цикл + Если СтрНайти(ПараПолей.ПервоеПоле.Поле, ПерваяТаблица.Псевдоним + ".") > 0 + И СтрНайти(ПараПолей.ПервоеПоле.Поле, ЗаменяемоеПоле + ".") = 0 Тогда + ВсеПервыеПоляЗаменяемые = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если Не ЭтоПолеУсловияСоединения Или Не ВсеПервыеПоляЗаменяемые Тогда + ВспомогательнаяТаблица = Новый Структура("Таблица, Псевдоним, ПоляУсловияСоединения", + ПерваяТаблица.Таблица, "ТекущиеДанныеДляОтбора", Новый Массив); + ОбратнаяГруппаТаблиц.Вставить(0, ВспомогательнаяТаблица); + ПараПолей = Новый Структура("ПервоеПоле, ВтороеПоле"); + ВспомогательнаяТаблица.ПоляУсловияСоединения.Добавить(ПараПолей); + ПараПолей.ПервоеПоле = Новый Структура("Поле, Псевдоним", + Условие.ПолеИлиПсевдоним, "ТекущиеДанныеДляОтбора"); + ПараПолей.ВтороеПоле = Новый Структура("Поле, Псевдоним", + "ТекущиеДанныеДляОтбора." + Условие.ПоляДляОтбора, ПсевдонимПолейОтбора); + КонецЕсли; + + ТекстСоединения = + "#ТекущиеДанныеДляОтбора КАК ТекущиеДанныеДляОтбора"; + ОставшиесяПсевдонимы = Новый Соответствие; + ОставшиесяПсевдонимы.Вставить("ТекущийСписок", Новый Массив); + + Для Каждого ДополнительнаяТаблица Из ОбратнаяГруппаТаблиц Цикл + ОставшиесяПсевдонимы.Вставить(ДополнительнаяТаблица.Псевдоним, + Новый Массив(Новый ФиксированныйМассив(ДополнительнаяТаблица.ПоляУсловияСоединения))); + КонецЦикла; + + ПервыеПсевдонимы = Новый Соответствие; + Индекс = -1; + Для Каждого ДополнительнаяТаблица Из ОбратнаяГруппаТаблиц Цикл + Индекс = Индекс + 1; + + ПервыйПсевдоним = ДополнительнаяТаблица.Псевдоним; + ПоляУсловияСоединения = ОставшиесяПсевдонимы.Получить(ПервыйПсевдоним); + ОставшиесяПсевдонимы.Удалить(ПервыйПсевдоним); + ПервыеПсевдонимы.Вставить(ПервыйПсевдоним, Истина); + + Если Индекс >= ОбратнаяГруппаТаблиц.Количество() - 1 Тогда + ВторойПсевдоним = "ТекущийСписок"; + Иначе + ВторойПсевдоним = ОбратнаяГруппаТаблиц[Индекс + 1].Псевдоним; + КонецЕсли; + ОстальныеПоляУсловияСоединения = ОставшиесяПсевдонимы.Получить(ВторойПсевдоним); + Для Каждого ПараПолей Из ОстальныеПоляУсловияСоединения Цикл + ПоляУсловияСоединения.Добавить(ПараПолей); + КонецЦикла; + ОставшиесяПсевдонимы.Вставить(ВторойПсевдоним, Новый Массив); + + УсловияСоединения = Новый Массив; + Для Каждого ПараПолей Из ПоляУсловияСоединения Цикл + Если Не ЗначениеЗаполнено(ПараПолей.ПервоеПоле.Псевдоним) + И Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) Тогда + + УсловияСоединения.Добавить(ПараПолей.ПервоеПоле.Поле + + " = " + ПараПолей.ВтороеПоле.Поле); + + ИначеЕсли ПервыеПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним) <> Неопределено + И (Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) + Или ПараПолей.ВтороеПоле.Псевдоним = ВторойПсевдоним) + Или ПараПолей.ПервоеПоле.Псевдоним = ВторойПсевдоним + И Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) Тогда + + ПервоеПоле = ПараПолей.ПервоеПоле.Поле; + + Если ПервыеПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним) <> Неопределено + И ПараПолей.ПервоеПоле.Псевдоним = ПсевдонимПолейОтбора + И ВспомогательнаяТаблица = Неопределено + И СтрНачинаетсяС(ПервоеПоле, ЗаменяемоеПоле) Тогда + + КонецПоля = Сред(ПервоеПоле, СтрДлина(ЗаменяемоеПоле) + 1); + ПервоеПоле = "ТекущиеДанныеДляОтбора" + + ?(ЗаменяемоеПоле <> ПсевдонимПолейОтбора, ".Ссылка", "") + КонецПоля; // @query-part-2 + КонецЕсли; + Если СтрНачинаетсяС(ПервоеПоле, "ТекущиеДанныеДляОтбора.") Тогда + УсловияСоединения.Добавить(ПараПолей.ВтороеПоле.Поле + " = " + ПервоеПоле); + + ИначеЕсли СтрНачинаетсяС(ПараПолей.ВтороеПоле.Поле, "ТекущиеДанныеДляОтбора.") Тогда + УсловияСоединения.Добавить(ПервоеПоле + " = " + ПараПолей.ВтороеПоле.Поле); + + ИначеЕсли ПараПолей.ВтороеПоле.Псевдоним = ВторойПсевдоним Тогда + УсловияСоединения.Добавить(ПараПолей.ВтороеПоле.Поле + " = " + ПервоеПоле); + Иначе + УсловияСоединения.Добавить(ПервоеПоле + " = " + ПараПолей.ВтороеПоле.Поле); + КонецЕсли; + Иначе + ОставшиесяУсловия = ОставшиесяПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним); + Если ОставшиесяУсловия = Неопределено Тогда + ОставшиесяУсловия = ОставшиесяПсевдонимы.Получить(ПараПолей.ВтороеПоле.Псевдоним); + КонецЕсли; + ОставшиесяУсловия.Добавить(ПараПолей); + КонецЕсли; + КонецЦикла; + Если ВторойПсевдоним = "ТекущийСписок" Тогда + ТаблицаИПсевдоним = "&ТекущийСписок КАК ТекущийСписок"; + Иначе + СледующаяТаблица = ОбратнаяГруппаТаблиц[Индекс + 1]; + ТаблицаИПсевдоним = СледующаяТаблица.Таблица + " КАК " + СледующаяТаблица.Псевдоним; + КонецЕсли; + ТекстСоединения = ТекстСоединения + " + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ " + ТаблицаИПсевдоним + " + | ПО (" + СтрСоединить(УсловияСоединения, ") + | И (") + ")"; // @query-part-1, @query-part-2, @query-part-3 + КонецЦикла; + + Возврат ТекстСоединения + ДополнительноеУсловие; + +КонецФункции + + +// Для процедур ДобавитьОпорноеПоле, ДобавитьТипыИзмерения, ДобавитьСвойстваТиповПоля, +// ДобавитьПроверкуПоТипам и функции СвойстваПоля. +// +Функция ЭтоПростойТип(Тип) + + Возврат Тип = Тип("Булево") + Или Тип = Тип("Дата") + Или Тип = Тип("Строка") + Или Тип = Тип("Число") + Или Тип = Тип("УникальныйИдентификатор") + Или Тип = Тип("ХранилищеЗначения"); + +КонецФункции + +// Для функции ДобавитьСвойстваТиповПоля. +Функция ТипПроверяется(Узел, ПолноеИмя) + + Если Узел.Типы.Количество() = 0 Тогда + Возврат Истина; + КонецЕсли; + + ТипУказан = Ложь; + Для Каждого ИмяТаблицы Из Узел.Типы Цикл + Если ВРег(ИмяТаблицы) = ВРег(ПолноеИмя) Тогда + ТипУказан = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Узел.ПроверятьТипыКромеУказанных И Не ТипУказан + Или Не Узел.ПроверятьТипыКромеУказанных И ТипУказан; + +КонецФункции + +// Для функции ДобавитьСвойстваТиповПоля. +Функция ТипУточнен(Узел, ИмяТипаНаЯзыкеЗапросов) + + ТипУточнен = Ложь; + Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл + Если ВРег(УточнениеСравнения.Ключ) = ВРег(ИмяТипаНаЯзыкеЗапросов) Тогда + ТипУточнен = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат ТипУточнен; + +КонецФункции + +// Для функции ДобавитьСвойстваТиповПоля. +Функция УточнениеТипа(Узел, ИмяТипаНаЯзыкеЗапросов) + + Уточнение = ""; + Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл + Если ВРег(УточнениеСравнения.Ключ) = ВРег(ИмяТипаНаЯзыкеЗапросов) Тогда + Уточнение = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Уточнение; + +КонецФункции + +// Для функции СвойстваПоля. +Функция ТипЗначенияУзлаЗначениеИлиКонстанта(Узел) + + Если Узел.Узел = "Значение" Тогда + Возврат ТипСсылкиПоПолномуИмениПредопределенного(Узел.Имя); + КонецЕсли; + + Возврат ТипЗнч(Узел.Значение); + +КонецФункции + +// Для функций ТекстУсловияСоединения, СвойстваПоля, НаборПолейУсловияКогда и +// процедуры УточнитьСвойстваПоляСравнения. +// +Функция ВыражениеУзлаЗначениеИлиКонстанта(Узел) + + Если Узел.Узел = "Значение" Тогда + Выражение = "Значение(" + Узел.Имя + ")"; + + ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Булево") Тогда + Выражение = ?(Узел.Значение, "Истина", "Ложь"); + + ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Число") Тогда + Выражение = Формат(Узел.Значение, "ЧН=0; ЧГ="); + + ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Неопределено") Тогда + Выражение = "Неопределено"; + Иначе + Выражение = """" + Узел.Значение + """"; + КонецЕсли; + + Возврат Выражение; + +КонецФункции + +// Для функции ТипЗначенияУзлаЗначениеИлиКонстанта. +Функция ТипСсылкиПоПолномуИмениПредопределенного(ПолноеИмяПредопределенного) + + ЧастиИмени = СтрРазделить(ПолноеИмяПредопределенного, "."); + ЧастиИмени.Удалить(2); + + ПолноеИмя = СтрСоединить(ЧастиИмени, "."); + + Возврат ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); + +КонецФункции + +// Для функций СвойстваПоля, ТипСсылкиПоПолномуИмениПредопределенного. +Функция ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаСсылки = СтрЗаменить(ПолноеИмя, ".", "Ссылка."); // @Non-NLS-2 + Иначе + ИмяТипаСсылки = СтрЗаменить(ПолноеИмя, ".", "Ref."); + КонецЕсли; + + Возврат Тип(ИмяТипаСсылки); + +КонецФункции + +// Для функции КлючТаблицы. +Функция ТипКлючаЗаписиПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаКлючаЗаписи = СтрЗаменить(ПолноеИмя, ".", "КлючЗаписи."); // @Non-NLS-2 + Иначе + ИмяТипаКлючаЗаписи = СтрЗаменить(ПолноеИмя, ".", "RecordKey."); + КонецЕсли; + + Возврат Тип(ИмяТипаКлючаЗаписи); + +КонецФункции + +// Для функции КлючТаблицы. +Функция ТипНабораЗаписейПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаНабораЗаписей = СтрЗаменить(ПолноеИмя, ".", "НаборЗаписей."); // @Non-NLS-2 + Иначе + ИмяТипаНабораЗаписей = СтрЗаменить(ПолноеИмя, ".", "RecordSet."); + КонецЕсли; + + Возврат Тип(ИмяТипаНабораЗаписей); + +КонецФункции + +// Для функции КлючТаблицы. +Функция ТипМенеджераОбъектаПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаМенеджера = СтрЗаменить(ПолноеИмя, ".", "Менеджер."); // @Non-NLS-2 + Иначе + ИмяТипаМенеджера = СтрЗаменить(ПолноеИмя, ".", "Manager."); + КонецЕсли; + + Возврат Тип(ИмяТипаМенеджера); + +КонецФункции + +// Для функций ТипСсылкиПоПолномуИмениМетаданных, ТипКлючаЗаписиПоПолномуИмениМетаданных, +// ТипНабораЗаписейПоПолномуИмениМетаданных, ТипМенеджераОбъектаПоПолномуИмениМетаданных. +// +Функция ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) + + ПервыйСимвол = Лев(ПолноеИмя, 1); + + Возврат ПервыйСимвол > "А" + И ПервыйСимвол < "Я" + Или ПервыйСимвол > "а" + И ПервыйСимвол < "я"; // @Non-NLS-1, @Non-NLS-2, @Non-NLS-3, @Non-NLS-4 + +КонецФункции + +#КонецОбласти + +#Область ПараметрыОграниченияДоступаТекстыЗапросовДляСписка + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка +// * Значение - Массив из Строка +// +Функция НовыеРеквизитыТаблицКлюча() + Возврат Новый Соответствие; +КонецФункции + +// Основная функция области, которая является второй частью +// функции ПараметрыОграниченияПоСтруктуреОграничения, но +// не используется при подготовке хранимых параметров ограничения доступа, +// а используется при вызове функции ПараметрыОграничения. +// +Процедура ДобавитьТекстыЗапросовВПараметрыОграничения(Результат) + + Контекст = Результат.Контекст; + Результат.Удалить("Контекст"); + + // Проверка прав Чтение и Изменение объекта или набора записей в базе данных. + Результат.Вставить("ТекстЗапросаПроверкиПравЧтениеИзменение"); + // Проверка права Чтение объекта или набора записей в базе данных. + Результат.Вставить("ТекстЗапросаПроверкиПраваЧтение"); + // Текст извлечения владельца из ссылки объекта. + Результат.Вставить("ПолеОбъектаВладельцаВЗапросеПроверкиПрав"); + // Получение прав пользователей на список элементов данных. + Результат.Вставить("ТекстЗапросаПравПользователей"); + + ДобавитьТекстЗапросаДатыСледующегоЭлементаДанных(Результат, Контекст); + ЗаполнитьЗапросыПравПользователей(Результат, Контекст); + + Если Результат.БезЗаписиКлючейДоступа Тогда + // Запрос объектов или отборов записей для удаления или установки пустых ключей. + Результат.Вставить("ТекстЗапросаУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаПроверкиУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра"); + ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст); + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + // Формирование запросов проверки прав. + ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст); + КонецЕсли; + + Возврат; + КонецЕсли; + + // Имена используемых таблиц ключа. + Результат.Вставить("ТаблицыКлюча"); + // Имена используемых реквизитов таблиц ключа. + Результат.Вставить("РеквизитыТаблицКлюча"); + + // Запрос объекта или отбора записей для вычисления диапазона требуемого размера. + Результат.Вставить("ТекстЗапросаДиапазонаЭлементовДанных"); + // Запрос объектов или отборов записей, у которых устарели ключи доступа. + Результат.Вставить("ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами"); + // Запрос проверки актуальности ключа доступа у объекта. + Результат.Вставить("ТекстЗапросаПроверкиКлючаДоступаОбъекта"); + // Запрос отборов записей, которых нет в регистре ключей доступа регистров при фоновом обновлении. + Результат.Вставить("ТекстЗапросаЭлементовДанныхБезКлючейДоступа"); + // Запрос отборов записей, которых нет в регистре ключей доступа регистров при записи нового набора. + Результат.Вставить("ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей"); + Результат.Вставить("ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей"); + // Запросы объектов или отборов записей, у которых устарели ключи доступа + // по составу изменений ведущих объектов (для точечного задания). + Результат.Вставить("ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам", Новый Соответствие); + // Запрос несуществующих объектов и отборов записей, которые не используются. + Результат.Вставить("ТекстЗапросаУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаПроверкиУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра"); + + // Запрос текущих ключей доступа отборов записей регистра перед записью рассчитанных ключей доступа. + Результат.Вставить("ТекстЗапросаТекущихКлючейДоступаРегистра"); + + // Запрос значений объектов или отборов записей. + Результат.Вставить("ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа"); + // Запрос значений объектов в памяти. + Результат.Вставить("ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа"); + // Запрос значений из используемых ключей доступа для сравнения со значениями из объектов или отборов записей. + Результат.Вставить("ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения"); + // Запрос значений из всех ключей доступа для сравнения со значениями из объектов или + // отборов записей перед записью нового ключа. + Результат.Вставить("ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения"); + // Запрос проверки существования ключа доступа перед записью нового ключа. + Результат.Вставить("ТекстЗапросаСуществованияКлючейДляСравнения"); + + // Запрос ключей доступа для обновления пользователей и групп доступа, которым они разрешены. + Результат.Вставить("ТекстЗапросаКлючейДоступаДляОбновленияПрав"); + // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. + Результат.Вставить("ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав"); + // Запрос значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + Результат.Вставить("ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав"); + // Запрос неиспользуемых ключей доступа для установки даты неиспользования или удаления. + Результат.Вставить("ТекстЗапросаУстаревшихКлючейДоступа"); + + Контекст.Вставить("ОтдельныйРегистр", Истина); // Уточнение регистра ключей для нессылочных типов. + + Контекст.Вставить("ТаблицыКлюча", Новый Массив); + Контекст.Вставить("РеквизитыТаблицКлюча", НовыеРеквизитыТаблицКлюча()); + Контекст.Вставить("ИспользуемыеПоляОсновнойТаблицы", ""); + Контекст.Вставить("ЧастиУсловияПроверки", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзОбъектов", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзОбъектовВПамяти", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзКлючейДляСравнения", Новый Массив); + Контекст.Вставить("ЧастиЗапросаСуществованияКлючейДляСравнения", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав", Новый Массив); + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихКлючейДоступа", Новый Массив); + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписков", Новый Массив); + Контекст.Вставить("ЧастиУсловияВыбораПравПоВладельцамНастроекПрав", Новый Массив); + Контекст.Вставить("ЧастиУсловияОтбораПоВедущимКлючамДоступа", Новый Массив); + Контекст.Вставить("ОписаниеЗапросовПроверкиПоВедущимОбъектам", Новый Соответствие); + + // Формирование запроса элементов данных с устаревшими ключами. + ЗаполнитьШаблоныЧастейЗапросаПроверки(Контекст); + ЗаполнитьИспользуемыеПоляОсновнойТаблицы(Контекст); + + Для НомерШапки = 0 По 2 Цикл + ДобавитьПроверкуШапкиКлюча(Контекст, НомерШапки); + КонецЦикла; + + Для НомерТабличнойЧастиКлюча = 1 По Контекст.КоличествоТабличныхЧастейКлюча Цикл + ДобавитьПроверкуТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча); + КонецЦикла; + СобратьЧастиЗапросаПроверки(Результат, Контекст); + + // Формирование запросов значений из элементов данных и из ключей. + Для НомерШапки = 0 По 2 Цикл + ДобавитьЗаполнениеШапкиКлюча(Контекст, НомерШапки); + КонецЦикла; + ДобавитьВыборКлючейБезПолейВШапке(Контекст); + + Для НомерТабличнойЧастиКлюча = 1 По Контекст.КоличествоТабличныхЧастейКлюча Цикл + ДобавитьЗаполнениеТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча); + КонецЦикла; + СобратьЧастиЗапросовЗаполнения(Результат, Контекст); + + Результат.ТаблицыКлюча = Контекст.ТаблицыКлюча; + Результат.РеквизитыТаблицКлюча = Контекст.РеквизитыТаблицКлюча; + + ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст); + + // Формирование запросов проверки прав. + ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст); + +КонецПроцедуры + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура ЗаполнитьНедостающиеТипыОпорныхПолей(Результат, Контекст) + + Если Контекст.ЭтоСсылочныйТип Или Контекст.ИспользуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + + Если ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + Измерения = Метаданные.РегистрыСведений[Контекст.ИмяОтдельногоРегистраКлючей].Измерения; + Иначе + Измерения = Метаданные.РегистрыСведений.КлючиДоступаКРегистрам.Измерения; + КонецЕсли; + + НедостающиеТипы = Новый Соответствие; + Поля = Новый Соответствие; + СписокНедостающихТипов = Новый СписокЗначений; + СписокПолей = Новый СписокЗначений; + + КоличествоПолей = Контекст.ОпорныеПоля.ТипыИспользуемых.Количество(); + Индекс = 0; + Пока Индекс < КоличествоПолей Цикл + ТребуемыйТип = Контекст.ОпорныеПоля.ТипыИспользуемых.Получить(Индекс).Получить(); + ТипИзмерения = Измерения[СтрШаблон("Поле%1", Индекс + 1)].Тип; + НедостающийТип = Новый ОписаниеТипов(ТребуемыйТип, , ТипИзмерения.Типы()); + Для Каждого Тип Из НедостающийТип.Типы() Цикл + Если НедостающиеТипы.Получить(Тип) = Неопределено Тогда + НедостающиеТипы.Вставить(Тип, Истина); + СписокНедостающихТипов.Добавить(ИмяТипаСсылки(ИмяТипаНаЯзыкеЗапросов(Тип), + Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам)); + Поле = Контекст.ОпорныеПоля.Все.Получить(Индекс); + Если Поля.Получить(Поле) = Неопределено Тогда + Поля.Вставить(Поле, Истина); + СписокПолей.Добавить(Поле); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Индекс = Индекс + 1; + КонецЦикла; + + Если СписокНедостающихТипов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Результат.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей = Истина; + + СписокНедостающихТипов.СортироватьПоЗначению(); + Контекст.ОпорныеПоля.Вставить("НедостающиеТипы", СписокНедостающихТипов.ВыгрузитьЗначения()); + Контекст.ОпорныеПоля.Вставить("ПоляНедостающихТипов", СписокПолей.ВыгрузитьЗначения()); + + ДобавитьСвойствоВерсии(Контекст, Результат, "БезОбновленияВсехКомбинацийЗначенийОпорныхПолей"); + ДобавитьСвойствоВерсии(Контекст, Контекст.ОпорныеПоля, "НедостающиеТипы"); + ДобавитьСвойствоВерсии(Контекст, Контекст.ОпорныеПоля, "ПоляНедостающихТипов"); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьТекстЗапросаДатыСледующегоЭлементаДанных(Результат, Контекст) + + Если Не Результат.СписокСДатой И Не Результат.СписокСПериодом Тогда + Возврат; + КонецЕсли; + + Если Результат.СписокСДатой Тогда + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Дата КАК Дата + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.Дата < &ДатаНачала + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Дата УБЫВ"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Период КАК Период + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.Период < &ДатаНачала + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Период УБЫВ"; + Если Контекст.ИмяКоллекцииТипа = "РегистрыРасчета" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ".Период", ".ПериодРегистрации"); // @query-part-1, @query-part-2 + КонецЕсли; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + Результат.Вставить("ТекстЗапросаДатыСледующегоЭлементаДанных", ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст) + + Если Результат.ЭтоСсылочныйТип Тогда + ТипСсылки = ?(ЗначениеЗаполнено(СтрПолучитьСтроку(Результат.Версия, 1)) + Или ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Результат.Список) <> Неопределено, + ТипСсылкиПоПолномуИмениМетаданных(Результат.Список), Неопределено); + ТипыСсылок = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ВладелецЗначенийКлючейДоступа"); + + Если ТипыСсылок.Получить(ТипСсылки) = Неопределено Тогда + ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); + ТекстЗапросаНекорректных = ПризнакПустогоЗапроса(); + + ИначеЕсли Результат.БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей Тогда + ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); + ТекстЗапросаНекорректных = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, + | ИСТИНА КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступаКОбъектам.Объект"; // @query-part-1 + + Иначе + Если Результат.ДляВнешнихПользователей Тогда + ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); + Иначе + ТекстЗапросаУстаревших = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, + | ЛОЖЬ КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО (ТекущийСписок.Ссылка = КлючиДоступаКОбъектам.Объект) + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка + | И ТекущийСписок.Ссылка ЕСТЬ NULL + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступаКОбъектам.Объект"; // @query-part-1 + ТекстЗапросаУстаревших = СтрЗаменить(ТекстЗапросаУстаревших, "&ТекущийСписок", Результат.Список); + + ТекстЗапроса = // ТекстЗапросаПроверкиУстаревшихЭлементовДанных + "ВЫБРАТЬ + | ЭлементыДанных.ТекущаяСсылка КАК Объект + |ПОМЕСТИТЬ КлючиДоступаКОбъектам + |ИЗ + | &ЭлементыДанных КАК ЭлементыДанных + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка + |ИЗ + | КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО (ТекущийСписок.Ссылка = КлючиДоступаКОбъектам.Объект) + |ГДЕ + | ТекущийСписок.Ссылка ЕСТЬ NULL + | И &УточнениеПланаЗапроса"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + Результат.ТекстЗапросаПроверкиУстаревшихЭлементовДанных = ТекстЗапроса; + КонецЕсли; + Если Не Результат.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей + И Не Результат.БезЗаписиКлючейДоступа Тогда + ТекстЗапросаНекорректных = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, + | ЛОЖЬ КАК Удалить, + | ИСТИНА КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка + | И КлючиДоступаКОбъектам.#КлючДоступаПользователей <> ЗНАЧЕНИЕ(Справочник.КлючиДоступа.ПустаяСсылка) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступаКОбъектам.Объект"; // @query-part-1 + ТекстЗапросаНекорректных = СтрЗаменить(ТекстЗапросаНекорректных, "#КлючДоступаПользователей", + ?(Результат.ДляВнешнихПользователей, "КлючДоступаПользователей", "КлючДоступаВнешнихПользователей")); + + ТекстЗапроса = // ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных + "ВЫБРАТЬ + | ЭлементыДанных.ТекущаяСсылка КАК ТекущаяСсылка + |ПОМЕСТИТЬ ЭлементыДанных + |ИЗ + | &ЭлементыДанных КАК ЭлементыДанных + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК Объект, + | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, + | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей + |ИЗ + | ЭлементыДанных КАК ЭлементыДанных + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ЭлементыДанных.ТекущаяСсылка)"; + Результат.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных = ТекстЗапроса; + Иначе + ТекстЗапросаНекорректных = ПризнакПустогоЗапроса(); + КонецЕсли; + КонецЕсли; + ТекстЗапросаНекорректных = СтрЗаменить(ТекстЗапросаНекорректных, "&ТекущийСписок", Результат.Список); + Результат.ТекстЗапросаУстаревшихЭлементовДанных = ТекстЗапросаУстаревших; + Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапросаНекорректных; + Возврат; + КонецЕсли; + + ОпорныеПоляВыбора = "КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа"; + + Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистра = Результат.ИмяОтдельногоРегистраКлючей; + ОсновнойОтбор = "ИСТИНА"; // @query-part-1 + Иначе + ИмяРегистра = "КлючиДоступаКРегистрам"; + ОсновнойОтбор = "КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра"; + ОпорныеПоляВыбора = "КлючиДоступаКРегистрам.Регистр КАК Регистр, + | " + ОпорныеПоляВыбора; + КонецЕсли; + + ОтборПоВидуПользователей = "ВЫБОР + | КОГДА КлючиДоступаКРегистрам.ВариантДоступа = 0 + | ТОГДА ЛОЖЬ + | ИНАЧЕ КлючиДоступаКРегистрам.ВариантДоступа - (ВЫРАЗИТЬ(КлючиДоступаКРегистрам.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 + | КОНЕЦ = " + ?(Результат.ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ"); // @query-part-1 + + ОпорныеПоля = Контекст.ОпорныеПоля; + Если ОпорныеПоля = Неопределено Тогда + МаксимальноеКоличествоОпорныхПолей = + УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистра); + Иначе + МаксимальноеКоличествоОпорныхПолей = ОпорныеПоля.МаксимальноеКоличество; + КонецЕсли; + + ОпорныеПоляДляОтбора = "КлючиДоступаКРегистрам.ВариантДоступа >= &ВариантДоступа + | И (КлючиДоступаКРегистрам.ВариантДоступа > &ВариантДоступа + | ИЛИ КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа"; // @query-part-1 + ОпорныеПоляДляУпорядочения = "ВариантДоступа"; + СтрокаТабуляций = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(" ", + 2 + МаксимальноеКоличествоОпорныхПолей * 2); + + Для Номер = 1 По МаксимальноеКоличествоОпорныхПолей Цикл + // Поля для выбора. + ОпорныеПоляВыбора = ОпорныеПоляВыбора + СтрШаблон(", + | КлючиДоступаКРегистрам.Поле%1 КАК Поле%1", Номер); // @query-part-1 + + // Поля для отбора. + Если Номер = МаксимальноеКоличествоОпорныхПолей Тогда + Отбор = "КлючиДоступаКРегистрам.Поле%1 > &Поле%1"; // @query-part-1 + Иначе + Отбор = "(КлючиДоступаКРегистрам.Поле%1 > &Поле%1 + | ИЛИ КлючиДоступаКРегистрам.Поле%1 = &Поле%1"; // @query-part-1 + КонецЕсли; + ОпорныеПоляДляОтбора = ОпорныеПоляДляОтбора + ТекстСОтступом(" + |И " + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, 2 + Номер * 2)); // @query-part-1 + + // Поля для упорядочения. + ОпорныеПоляДляУпорядочения = ОпорныеПоляДляУпорядочения + + ?(ОпорныеПоляДляУпорядочения = "", "", ", ") + СтрШаблон("Поле%1", Номер); + КонецЦикла; + ОпорныеПоляДляОтбора = ОпорныеПоляДляОтбора + + УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", МаксимальноеКоличествоОпорныхПолей); + + Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда + // Запрос очистки общего регистра. + ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра + "ВЫБРАТЬ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора, + | ИСТИНА КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра + | И &ОтборПоВидуПользователей + | И &ОпорныеПоляДляОтбора + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); + Результат.ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра = ТекстЗапроса; + КонецЕсли; + + Если Результат.БезЗаписиКлючейДоступа Тогда + Результат.ТекстЗапросаУстаревшихЭлементовДанных = ПризнакПустогоЗапроса(); + ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора, + | ИСТИНА КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + |ГДЕ + | &ОсновнойОтбор + | И &ОтборПоВидуПользователей + | И &ОпорныеПоляДляОтбора + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); + Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапроса; + Возврат; + КонецЕсли; + + КоличествоИспользуемыхОпорныхПолей = ОпорныеПоля.Используемые.Количество(); + Номер = 1; + ОпорныеПоляВыбораПриПроверке = ?(ОсновнойОтбор = "ИСТИНА", "", + "КлючиДоступаКРегистрам.Регистр КАК Регистр, + | ") + "КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа"; + ОпорныеПоляВыбораИзСписка = ""; + ОпорныеПоляДляСравнения = ""; + ОпорныеПоляДляСоединения = ?(ОсновнойОтбор = "ИСТИНА", "", + "(КлючиДоступаКРегистрам.Регистр = ЭлементыДанных.Регистр) + |И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = ЭлементыДанных.ВариантДоступа)"; + ОпорныеПоляДляОтбора2 = + "КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа + | И "; // @query-part-1 + УсловиеПроверкиПервогоПоля = ""; + ОпорныеПоляДляУпорядоченияПриПроверке = ""; + Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл + // Поля для выбора. + ОпорныеПоляВыбораПриПроверке = ОпорныеПоляВыбораПриПроверке + СтрШаблон(", + | КлючиДоступаКРегистрам.Поле%1 КАК Поле%1", Номер); // @query-part-1 + ОпорныеПоляВыбораИзСписка = ОпорныеПоляВыбораИзСписка + ?(ОпорныеПоляВыбораИзСписка = "", "", ", + | ") + СтрШаблон("ТекущийСписок.%1", ИмяОпорногоПоля); + + // Поля для отбора. + Если Номер = КоличествоИспользуемыхОпорныхПолей Тогда + Отбор = "КлючиДоступаКРегистрам.Поле%1 > &Поле%1"; // @query-part-1 + Иначе + Отбор = "(КлючиДоступаКРегистрам.Поле%1 > &Поле%1 + | ИЛИ КлючиДоступаКРегистрам.Поле%1 = &Поле%1"; // @query-part-1 + КонецЕсли; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + + // Поля для сравнения и соединения. + ОпорныеПоляДляСравнения = ОпорныеПоляДляСравнения + ?(ОпорныеПоляДляСравнения = "", "", " + |И ") + СтрШаблон("(ТекущийСписок.%2 = КлючиДоступаКРегистрам.Поле%1)", Номер, ИмяОпорногоПоля); // @query-part-3 + ОпорныеПоляДляСоединения = ОпорныеПоляДляСоединения + ?(ОпорныеПоляДляСоединения = "", "", " + |И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ЭлементыДанных.Поле%1)", Номер); // @query-part-3 + + // Условие проверки по первому полю. + Если УсловиеПроверкиПервогоПоля = "" Тогда + УсловиеПроверкиПервогоПоля = СтрШаблон("ТекущийСписок.%1 ЕСТЬ NULL", ИмяОпорногоПоля); // @query-part-1 + КонецЕсли; + + // Поля для упорядочения. + ОпорныеПоляДляУпорядоченияПриПроверке = ОпорныеПоляДляУпорядоченияПриПроверке + + ?(ОпорныеПоляДляУпорядоченияПриПроверке = "", "", ", ") + СтрШаблон("Поле%1", Номер); + + Номер = Номер + 1; + КонецЦикла; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + + УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", КоличествоИспользуемыхОпорныхПолей - 1); + + ТекстЗапроса = // ТекстЗапросаУстаревшихЭлементовДанных + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ОпорныеПоляВыбора1 + |ПОМЕСТИТЬ ЗначенияИспользуемыхОпорныхПолей + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + | + |ИНДЕКСИРОВАТЬ ПО + | &ОпорныеПоляВыбора1 + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора2, + | ЛОЖЬ КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + | ЛЕВОЕ СОЕДИНЕНИЕ ЗначенияИспользуемыхОпорныхПолей КАК ТекущийСписок + | ПО &ОпорныеПоляДляСравнения + |ГДЕ + | &ОсновнойОтбор + | И &ОпорныеПоляДляОтбора + | И &УсловиеПроверкиПервогоПоля + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора1", ОпорныеПоляВыбораИзСписка); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора2", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСравнения", + ТекстСОтступом(ОпорныеПоляДляСравнения, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиПервогоПоля", УсловиеПроверкиПервогоПоля); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядоченияПриПроверке); + + ВариантДоступаСтрокой = XMLСтрока(Контекст.ВариантДоступа); + ВариантДоступаСтрокой = ?(ЗначениеЗаполнено(ВариантДоступаСтрокой), ВариантДоступаСтрокой, "NULL"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойВариантДоступа", ВариантДоступаСтрокой); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + Результат.ТекстЗапросаУстаревшихЭлементовДанных = ТекстЗапроса; + + ТекстЗапроса = // ТекстЗапросаПроверкиУстаревшихЭлементовДанных + "ВЫБРАТЬ + | &ОпорныеПоляВыбораПриПроверке + |ПОМЕСТИТЬ КлючиДоступаКРегистрам + |ИЗ + | &КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | &ОпорныеПоляВыбораПриПроверке + |ИЗ + | КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО &ОпорныеПоляДляСравнения + |ГДЕ + | &УсловиеПроверкиПервогоПоля + | И &УточнениеПланаЗапроса"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораПриПроверке", ОпорныеПоляВыбораПриПроверке); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСравнения", + ТекстСОтступом(ОпорныеПоляДляСравнения, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиПервогоПоля", УсловиеПроверкиПервогоПоля); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + Результат.ТекстЗапросаПроверкиУстаревшихЭлементовДанных = ТекстЗапроса; + + Если Номер <= МаксимальноеКоличествоОпорныхПолей Тогда + ПроверкаNULL = ""; + Для Счетчик = Номер По МаксимальноеКоличествоОпорныхПолей Цикл + ПроверкаNULL = ПроверкаNULL + ?(ПроверкаNULL = "", "", " + |ИЛИ ") + СтрШаблон("КлючиДоступаКРегистрам.Поле%1 <> ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)", Счетчик); // @query-part-3 + КонецЦикла; + Иначе + ПроверкаNULL = "ЛОЖЬ"; + КонецЕсли; + + ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора, + | НЕ КлючиДоступаКРегистрам.ВариантДоступа В (&ИспользуемыеВариантыДоступа) КАК Удалить, + | КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа + | И &ПроверкаNULL2 КАК Обновить + |ИЗ + | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + |ГДЕ + | &ОсновнойОтбор + | И &ОтборПоВидуПользователей + | И &ОпорныеПоляДляОтбора + | И (НЕ КлючиДоступаКРегистрам.ВариантДоступа В (&ИспользуемыеВариантыДоступа) + | ИЛИ КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа + | И &ПроверкаNULL1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверкаNULL1", + "(" + ТекстСОтступом(ПроверкаNULL, " ") + ")"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверкаNULL2", + "(" + ТекстСОтступом(ПроверкаNULL, " ") + ")"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойВариантДоступа", ВариантДоступаСтрокой); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); + ВариантыДоступаСтрокой = Новый Массив; + Если ИспользуемыеВариантыДоступа = Неопределено Тогда + ВариантыДоступаСтрокой.Добавить("NULL"); + Иначе + Для Каждого ИспользуемыйВариантДоступа Из ИспользуемыеВариантыДоступа Цикл + ВариантыДоступаСтрокой.Добавить(XMLСтрока(ИспользуемыйВариантДоступа.ВариантДоступа)); + КонецЦикла; + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИспользуемыеВариантыДоступа", + СтрСоединить(ВариантыДоступаСтрокой, ",")); + + Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапроса; + + ОпорныеПоляВыбораДляОбновления = ОпорныеПоляВыбора + ", + | КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа"; // @query-part-1 + + ТекстЗапроса = // ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных + "ВЫБРАТЬ + | &ОпорныеПоляВыбораПриПроверке + |ПОМЕСТИТЬ ЭлементыДанных + |ИЗ + | &ЭлементыДанных КАК КлючиДоступаКРегистрам + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | &ОпорныеПоляВыбораДляОбновления + |ИЗ + | ЭлементыДанных КАК ЭлементыДанных + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + | ПО &ОпорныеПоляДляСоединения"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораПриПроверке", ОпорныеПоляВыбораПриПроверке); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораДляОбновления", ОпорныеПоляВыбораДляОбновления); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСоединения", + ТекстСОтступом(ОпорныеПоляДляСоединения, " ")); + + Результат.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных = ТекстЗапроса; + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьИспользуемыеПоляОсновнойТаблицы(Контекст) + + Если Не ЗначениеЗаполнено(Контекст.ПоляТаблицОбъекта.Результат) Тогда + Возврат; + КонецЕсли; + + ОписаниеОсновнойТаблицы = Неопределено; + Для Каждого ОписаниеТаблицы Из Контекст.ПоляТаблицОбъекта.Результат Цикл + Если Не ЗначениеЗаполнено(ОписаниеТаблицы.ТабличнаяЧасть) Тогда + ОписаниеОсновнойТаблицы = ОписаниеТаблицы; + Прервать; + КонецЕсли; + КонецЦикла; + + Если ОписаниеОсновнойТаблицы = Неопределено Тогда + Возврат; + КонецЕсли; + + ДополнительныеПоля = ""; + Для Каждого ИмяПоля Из ОписаниеОсновнойТаблицы.Поля Цикл + Если ИмяПоля = "Ссылка" Тогда + Продолжить; + КонецЕсли; + ДополнительныеПоля = ДополнительныеПоля + СтрШаблон(", + |ТекущийСписок.%1 КАК %1", ИмяПоля); + КонецЦикла; + + Контекст.ИспользуемыеПоляОсновнойТаблицы = ДополнительныеПоля; + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьШаблоныЧастейЗапросаПроверки(Контекст) + + Если Контекст.ЭтоСсылочныйТип Тогда + ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта(Контекст); + Иначе + ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра(Контекст); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьШаблоныЧастейЗапросаПроверки. +Процедура ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта(Контекст) + + Контекст.Вставить("ТекстЗапросаДиапазонаЭлементовДанных"); + Контекст.Вставить("ТекстЗапросаПроверки"); + Контекст.Вставить("ТекстЗапросаПроверкиСвязи"); + Контекст.Вставить("ТекстЗапросаПроверкиШапки"); + Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧасти"); + Контекст.Вставить("ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта"); + Контекст.Вставить("ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта"); + Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверки"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиСвязи"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиШапки"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиТабличнойЧасти"); + + Если Контекст.СписокСДатой Тогда + Контекст.ТекстЗапросаДиапазонаЭлементовДанных = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЭлементыДанных.Дата КАК ДатаНачалаДиапазона, + | ЭлементыДанных.Ссылка КАК СсылкаДатыНачалаДиапазона + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Дата >= &ДатаНачала + | И ТекущийСписок.Дата <= &ДатаОкончанияДиапазона + | И (ТекущийСписок.Дата < &ДатаОкончанияДиапазона + | ИЛИ ТекущийСписок.Дата = &ДатаОкончанияДиапазона + | И ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона) + | + | УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Дата УБЫВ, + | ТекущийСписок.Ссылка УБЫВ) КАК ЭлементыДанных + | + |УПОРЯДОЧИТЬ ПО + | ЭлементыДанных.Дата, + | ЭлементыДанных.Ссылка"; + + Контекст.ТекстЗапросаПроверки = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля1, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2 + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Дата >= &ДатаНачалаДиапазона + | И (ТекущийСписок.Дата > &ДатаНачалаДиапазона + | ИЛИ ТекущийСписок.Дата = &ДатаНачалаДиапазона + | И ТекущийСписок.Ссылка >= &СсылкаДатыНачалаДиапазона) + | И ТекущийСписок.Дата <= &ДатаОкончанияДиапазона + | И (ТекущийСписок.Дата < &ДатаОкончанияДиапазона + | ИЛИ ТекущийСписок.Дата = &ДатаОкончанияДиапазона + | И ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона)) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Дата УБЫВ, + | ТекущийСписок.Ссылка УБЫВ"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиСвязи = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ТекущийКлючДоступа ЕСТЬ NULL"; + + Контекст.ТекстЗапросаПроверкиШапки = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиТабличнойЧасти = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Дата, + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + Иначе + Контекст.ТекстЗапросаДиапазонаЭлементовДанных = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЭлементыДанных.Ссылка КАК СсылкаОкончанияДиапазона + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Ссылка > &СсылкаНачалаДиапазона + | + | УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка) КАК ЭлементыДанных + | + |УПОРЯДОЧИТЬ ПО + | ЭлементыДанных.Ссылка УБЫВ"; + + Контекст.ТекстЗапросаПроверки = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля1, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2 + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Ссылка > &СсылкаНачалаДиапазона + | И ТекущийСписок.Ссылка <= &СсылкаОкончанияДиапазона) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиСвязи = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ТекущийКлючДоступа ЕСТЬ NULL"; + + Контекст.ТекстЗапросаПроверкиШапки = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиТабличнойЧасти = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + КонецЕсли; + + Контекст.ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |ГДЕ + | КлючиДоступаКОбъектам.Объект ЕСТЬ NULL"; + + Контекст.ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + | ГДЕ + | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + | ГДЕ + | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + // Запросы точечной проверки. + Контекст.ТекстЗапросаТочечнойПроверки = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + |ГДЕ + | &УточнениеПланаЗапроса"; + + Контекст.ТекстЗапросаТочечнойПроверкиСвязи = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам + | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка)) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |ГДЕ + | КлючиДоступаКОбъектам.Объект ЕСТЬ NULL"; + + Контекст.ТекстЗапросаТочечнойПроверкиШапки = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам + | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка)) КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаТочечнойПроверкиТабличнойЧасти = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам + | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка)) КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + Если Не Контекст.Свойство("ОписаниеЗапросовПроверкиПоВедущимОбъектам") Тогда + Возврат; + КонецЕсли; + + ТекстЗапроса = // ТекстЗапросаОберткиВыбораДанных + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам + |ИЗ + | #ЗапросыВыбораДанных КАК ТекущийСписок"; + + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаОберткиВыбораДанных", ТекстЗапроса); + + ШаблонЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | "; // @query-part-1 + ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст); + +КонецПроцедуры + +// Для процедуры ЗаполнитьШаблоныЧастейЗапросаПроверки. +Процедура ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра(Контекст) + + ОпорныеПоля = Контекст.ОпорныеПоля; + ОпорныеПоля.Вставить("ДляВыбора", ""); + ОпорныеПоля.Вставить("ДляУпорядочения", ""); + + КоличествоИспользуемыхПолей = ОпорныеПоля.Используемые.Количество(); + ДобавлятьОтборПоПервомуПолю = КоличествоИспользуемыхПолей > 1 + И ОпорныеПоля.ТипыИспользуемых[0].Получить().Типы().Количество() = 1; + + // Для запроса новых комбинаций. + ОпорныеПоляДляВыбора = ""; + ОпорныеПоляУсловиеСоединения = ""; + ОпорныеПоляДляГруппировкиИлиУпорядочения = ""; + ОпорныеПоляДляОтбора1 = ""; // СписокСПериодом + ОпорныеПоляДляОтбора2 = ?(Не ДобавлятьОтборПоПервомуПолю, "", СтрШаблон( + "ТекущийРегистр.%2 >= &Поле%1 + | И ", 1, ОпорныеПоля.Используемые[0])); + + // Для запроса текущих ключей доступа. + УсловиеОтбора = ""; + ПоляОтбора = ""; + + Если Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + Контекст.ОтдельныйРегистр = Ложь; + // Для запроса новых комбинаций. + ОпорныеПоляУсловиеСоединения = "(КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра)"; + // Для запроса текущих ключей доступа. + УсловиеОтбора = "ТекущийСписок.Регистр = &ИдентификаторРегистра"; + // Для запроса комбинаций с устаревшими ключами. + ПоляОтбора = "ТекущийСписок.Регистр = &ИдентификаторРегистра"; + КонецЕсли; + + // Для запроса новых комбинаций. + ОпорныеПоляУсловиеСоединения = ОпорныеПоляУсловиеСоединения + ?(ОпорныеПоляУсловиеСоединения = "", "", " + | И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа)"; // @query-part-3 + + // Для запроса текущих ключей доступа. + УсловиеОтбора = УсловиеОтбора + ?(УсловиеОтбора = "", "", " + | И ") + "ТекущийСписок.ВариантДоступа = &ВариантДоступа"; // @query-part-3 + + // Для запроса комбинаций с устаревшими ключами. + ПоляОтбора = ПоляОтбора + ?(ПоляОтбора = "", "", " + | И ") + "ТекущийСписок.ВариантДоступа = &ВариантДоступа"; // @query-part-3 + + ПоляДляВыбораДиапазона = ""; + + ПоляОтбора1 = ""; + ПоляОтбора2 = ""; + + СтрокаТабуляций = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(" ", + КоличествоИспользуемыхПолей * 3); + + Номер = 0; + Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл + Номер = Номер + 1; + + // Для запроса новых комбинаций. + ОпорныеПоляДляВыбора = ОпорныеПоляДляВыбора + ?(ОпорныеПоляДляВыбора = "", "", ", + | ") + СтрШаблон("ТекущийРегистр.%2 КАК Поле%1", Номер, ИмяОпорногоПоля); // @query-part-4 + + ОпорныеПоляУсловиеСоединения = ОпорныеПоляУсловиеСоединения + ?(ОпорныеПоляУсловиеСоединения = "", "", " + | И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ТекущийРегистр.%2)", Номер, ИмяОпорногоПоля); // @query-part-3 + + ОпорныеПоляДляГруппировкиИлиУпорядочения = ОпорныеПоляДляГруппировкиИлиУпорядочения + + ?(ОпорныеПоляДляГруппировкиИлиУпорядочения = "", "", ", ") + ИмяОпорногоПоля; + + Если Номер = КоличествоИспользуемыхПолей Тогда + Отбор = "ТекущийРегистр.%2 > &Поле%1"; // @query-part-1 + Иначе + Отбор = "(ТекущийРегистр.%2 > &Поле%1 + | ИЛИ ТекущийРегистр.%2 = &Поле%1"; // @query-part-1 + КонецЕсли; + Отбор = ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер, ИмяОпорногоПоля), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + ОпорныеПоляДляОтбора1 = ОпорныеПоляДляОтбора1 + Отбор; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + Отбор; + + // Для запроса текущих ключей доступа. + УсловиеОтбора = УсловиеОтбора + ?(УсловиеОтбора = "", "", " + | И ") + СтрШаблон("ТекущийСписок.Поле%1 = &Поле%1", Номер) + "_%1"; // @query-part-3 + + // Для запроса комбинаций с устаревшими ключами. + ОпорныеПоля.ДляВыбора = ОпорныеПоля.ДляВыбора + ?(ОпорныеПоля.ДляВыбора = "", "", ", + | ") + СтрШаблон("ТекущийСписок.Поле%1 КАК Поле%1", Номер); // @query-part-4 + + ПоляДляВыбораДиапазона = ПоляДляВыбораДиапазона + ?(ПоляДляВыбораДиапазона = "", "", ", + | ") + СтрШаблон("ЭлементыДанных.Поле%1 КАК Поле%1ОкончанияДиапазона", Номер); // @query-part-4 + + Если Номер = КоличествоИспользуемыхПолей Тогда + Отбор = "ТекущийСписок.Поле%1 > &Поле%1НачалаДиапазона"; // @query-part-1 + Иначе + Отбор = "(ТекущийСписок.Поле%1 > &Поле%1НачалаДиапазона + | ИЛИ ТекущийСписок.Поле%1 = &Поле%1НачалаДиапазона"; // @query-part-1 + КонецЕсли; + ПоляОтбора1 = ПоляОтбора1 + ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + + Если Номер = КоличествоИспользуемыхПолей Тогда + Отбор = "ТекущийСписок.Поле%1 <= &Поле%1ОкончанияДиапазона"; // @query-part-1 + Иначе + Отбор = "(ТекущийСписок.Поле%1 < &Поле%1ОкончанияДиапазона + | ИЛИ ТекущийСписок.Поле%1 = &Поле%1ОкончанияДиапазона"; // @query-part-1 + КонецЕсли; + ПоляОтбора2 = ПоляОтбора2 + ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + + ОпорныеПоля.ДляУпорядочения = ОпорныеПоля.ДляУпорядочения + + ?(ОпорныеПоля.ДляУпорядочения = "", "", ", ") + СтрШаблон("Поле%1", Номер); + КонецЦикла; + + Если КоличествоИспользуемыхПолей > 1 Тогда + Скобки = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", КоличествоИспользуемыхПолей - 1); + ОпорныеПоляДляОтбора1 = ОпорныеПоляДляОтбора1 + Скобки; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + Скобки; + ПоляОтбора1 = ПоляОтбора1 + Скобки; + ПоляОтбора2 = ПоляОтбора2 + Скобки; + КонецЕсли; + ПоляОтбора1 = ПоляОтбора + " + | И " + ПоляОтбора1; // @query-part-1 + ПоляОтбора2 = ПоляОтбора1 + " + | И " + ПоляОтбора2; // @query-part-1 + + // Запросы комбинаций с устаревшими ключами. + ТекстЗапроса = // ТекстЗапросаДиапазонаЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 1 + | &ПоляДляВыбораДиапазона + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | &ОпорныеПоляДляВыбора + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | &ОпорныеПоляДляОтбора + | + | УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения) КАК ЭлементыДанных + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляОбратногоУпорядочения"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляДляВыбораДиапазона", ПоляДляВыбораДиапазона); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ТекстСОтступом(ОпорныеПоля.ДляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ТекстСОтступом(ПоляОтбора1, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоля.ДляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОбратногоУпорядочения", + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ",", " УБЫВ,") + " УБЫВ"); // @query-part-3, @query-part-4 + Контекст.Вставить("ТекстЗапросаДиапазонаЭлементовДанных", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверки + "ВЫБРАТЬ ПЕРВЫЕ 993 + | &ОпорныеПоляДляВыбора, + | ТекущийСписок.КлючДоступа КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | &ОпорныеПоляДляОтбора + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ОпорныеПоляДляВыбора + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ПоляОтбора2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоля.ДляУпорядочения); + Контекст.Вставить("ТекстЗапросаПроверки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверкиШапки + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.Вставить("ТекстЗапросаПроверкиШапки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверкиТабличнойЧасти + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | &ОпорныеПоляДляГруппировки, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировки", + "ТекущийСписок." + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ", ", ", + | ТекущийСписок.")); + Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧасти", ТекстЗапроса); + + // Запросы точечной проверки. + ТекстЗапроса = // ТекстЗапросаТочечнойПроверки + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ОпорныеПоляДляВыбора + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + |ГДЕ + | &УточнениеПланаЗапроса"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.Вставить("ТекстЗапросаТочечнойПроверки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаТочечнойПроверкиШапки + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущийСписокПоВедущимОбъектам КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиШапки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверкиТабличнойЧасти + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущийСписокПоВедущимОбъектам КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | &ОпорныеПоляДляГруппировки, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировки", + "ТекущийСписок." + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ", ", ", + | ТекущийСписок.")); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиТабличнойЧасти", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаОберткиВыбораДанныхДляТочечнойПроверкиКомбинаций + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляДляВыбора, + | ТекущийСписок.ТекущийКлючДоступа КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам + |ИЗ + | #ЗапросыВыбораДанных КАК ТекущийСписок"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаОберткиВыбораДанных", ТекстЗапроса); + + ШаблонЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляДляВыбора, + | ТекущийСписок.КлючДоступа КАК ТекущийКлючДоступа + |ИЗ + | "; // @query-part-1 + ШаблонЗапроса = СтрЗаменить(ШаблонЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст); + + // Запросы новых комбинаций значений полей. + Если Контекст.СписокСПериодом Тогда + ТекстЗапроса = // ТекстЗапросаНовыхКомбинаций + "ВЫБРАТЬ ПЕРВЫЕ 995 + | МАКСИМУМ(ТекущийРегистр.Период) КАК Период, + | &ОпорныеПоляДляВыбора + |ИЗ + | &ТекущийРегистр КАК ТекущийРегистр + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО &ОпорныеПоляУсловиеСоединения + |ГДЕ + | ТекущийРегистр.Период >= &ДатаНачала + | И ТекущийРегистр.Период <= &ДатаОкончания + | И (ТекущийРегистр.Период < &ДатаОкончания + | ИЛИ ТекущийРегистр.Период = &ДатаОкончания + | И &ОпорныеПоляДляОтбора) + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL + | И &УточнениеПланаЗапроса + | + |СГРУППИРОВАТЬ ПО + | &ОпорныеПоляДляГруппировкиИлиУпорядочения + | + |УПОРЯДОЧИТЬ ПО + | Период УБЫВ, &ОпорныеПоляДляГруппировкиИлиУпорядочения"; + Если Контекст.ИмяКоллекцииТипа = "РегистрыРасчета" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + ".Период", ".ПериодРегистрации"); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоляДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляУсловиеСоединения", ОпорныеПоляУсловиеСоединения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ТекстСОтступом(ОпорныеПоляДляОтбора1, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировкиИлиУпорядочения", + ОпорныеПоляДляГруппировкиИлиУпорядочения); + Иначе + ТекстЗапроса = // ТекстЗапросаНовыхКомбинаций + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляДляВыбора + |ИЗ + | &ТекущийРегистр КАК ТекущийРегистр + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО &ОпорныеПоляУсловиеСоединения + |ГДЕ + | &ОпорныеПоляДляОтбора + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляГруппировкиИлиУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоляДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляУсловиеСоединения", ОпорныеПоляУсловиеСоединения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировкиИлиУпорядочения", + ОпорныеПоляДляГруппировкиИлиУпорядочения); + КонецЕсли; + Контекст.Вставить("ТекстЗапросаНовыхКомбинаций", ТекстЗапроса); + + // Запрос текущих ключей доступа. + ТекстЗапроса = // ТекстЗапросаТекущихКлючейДоступа + "ВЫБРАТЬ ПЕРВЫЕ 2 + | ТекущийСписок.КлючДоступа КАК КлючДоступа + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | &УсловиеОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + Контекст.Вставить("ТекстЗапросаТекущихКлючейДоступа", ТекстЗапроса); + +КонецПроцедуры + +// Для процедур ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта, ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра. +Процедура ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст) + + ОписаниеЗапросов = Новый Соответствие; + Для Каждого СоединениеОтбора Из Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов Цикл + ОписаниеСоединения = СоединениеОтбора.Значение; + Поля = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Получить(СоединениеОтбора.Ключ); + ВедущаяТаблица = СоединениеОтбора.Ключ; + Если ОписаниеСоединения.ПоляШапки.Количество() > 0 Тогда + ОписаниеЗапросов.Вставить(ВедущаяТаблица, + ОписаниеЗапросовПроверкиПоВедущейТаблице(ОписаниеСоединения.ПоляШапки, + Поля.ДляОтбора.ПоляШапки, ВедущаяТаблица, ШаблонЗапроса, Контекст)); + КонецЕсли; + Для Каждого ОписаниеТабличнойЧасти Из ОписаниеСоединения.ТабличныеЧасти Цикл + ВедущаяТаблица = СоединениеОтбора.Ключ + "." + ОписаниеТабличнойЧасти.Ключ; + ТипыПолей = Поля.ДляОтбора.ТабличныеЧасти.Получить(ОписаниеТабличнойЧасти.Ключ); + ОписаниеЗапросов.Вставить(ВедущаяТаблица, + ОписаниеЗапросовПроверкиПоВедущейТаблице(ОписаниеТабличнойЧасти.Значение, + ТипыПолей, ВедущаяТаблица, ШаблонЗапроса, Контекст)); + КонецЦикла; + КонецЦикла; + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ПоЗначениямПолей", ОписаниеЗапросов); + + ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков("ПоЗначениямСГруппами", ШаблонЗапроса, Контекст); + ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков("ПоКлючамДоступа", ШаблонЗапроса, Контекст); + +КонецПроцедуры + +// Для процедуры ДобавитьЗапросыПроверкиПоВедущимСпискам. +Функция ОписаниеЗапросовПроверкиПоВедущейТаблице(СоединенияОтборов, ТипыПолей, + ВедущаяТаблица, ШаблонЗапроса, Контекст) + + ВедущаяТаблицаБезТочек = СтрЗаменить(ВедущаяТаблица, ".", "_"); + + Поля = Новый Массив; + Для Каждого ОписаниеПоля Из ТипыПолей Цикл + Поля.Добавить(ОписаниеПоля.Ключ + " КАК " + ОписаниеПоля.Ключ); + КонецЦикла; + + ТекстЗапроса = // ТекстЗапросаПараметров + "ВЫБРАТЬ + | &ПоляТаблицы + |ПОМЕСТИТЬ #ВедущаяТаблицаБезТочек + |ИЗ + | &ВедущаяТаблицаБезТочек КАК ТекущиеДанныеДляОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляТаблицы", + "ТекущиеДанныеДляОтбора." + СтрСоединить(Поля, ", + | ТекущиеДанныеДляОтбора.")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ВедущаяТаблицаБезТочек", ВедущаяТаблицаБезТочек); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВедущаяТаблицаБезТочек", "&" + ВедущаяТаблицаБезТочек); + + ОписаниеЗапросов = Новый Структура; + ОписаниеЗапросов.Вставить("ТипыПолей", ТипыПолей); + ОписаниеЗапросов.Вставить("ТекстЗапросаПараметров", ТекстЗапроса); + ОписаниеЗапросов.Вставить("ТекстыЗапросовДанных", Новый Массив); + + Для Каждого СоединениеОтбора Из СоединенияОтборов Цикл + ТекстЗапроса = ШаблонЗапроса + ТекстСОтступом(СоединениеОтбора, " "); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТекущиеДанныеДляОтбора", ВедущаяТаблицаБезТочек); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + ОписаниеЗапросов.ТекстыЗапросовДанных.Добавить(ТекстЗапроса); + КонецЦикла; + + Возврат ОписаниеЗапросов; + +КонецФункции + +// Для процедуры ДобавитьЗапросыПроверкиПоВедущимСпискам. +Процедура ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков(ВидВедущегоСписка, ШаблонЗапроса, Контекст) + + Свойства = ?(ВидВедущегоСписка = "ПоКлючамДоступа", + Контекст.ВедущиеСпискиПоКлючамДоступа, Контекст.ВедущиеСпискиПоЗначениямСГруппами); + + Если Не ЗначениеЗаполнено(Свойства.СоединенияОтборов) Тогда + Возврат; + КонецЕсли; + + ИмяВременнойТаблицы = "ТекущиеДанныеДляОтбора" + ВидВедущегоСписка; + + ТекстЗапросаПараметров = + "ВЫБРАТЬ + | ТекущиеДанныеДляОтбора.Ссылка + |ПОМЕСТИТЬ #ИмяВременнойТаблицы + |ИЗ + | &ВидВедущегоСписка КАК ТекущиеДанныеДляОтбора"; + ТекстЗапросаПараметров = СтрЗаменить(ТекстЗапросаПараметров, "#ИмяВременнойТаблицы", ИмяВременнойТаблицы); + ТекстЗапросаПараметров = СтрЗаменить(ТекстЗапросаПараметров, "&ВидВедущегоСписка", "&" + ВидВедущегоСписка); + + ТекстыЗапросовПоКлючам = Новый Соответствие; + Для Каждого СоединениеОтбора Из Свойства.СоединенияОтборов Цикл + ТекстЗапроса = ШаблонЗапроса + ТекстСОтступом(СоединениеОтбора.Значение, " "); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТекущиеДанныеДляОтбора", ИмяВременнойТаблицы); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + ТекстыЗапросовПоКлючам.Вставить(СоединениеОтбора.Ключ, ТекстЗапроса); + КонецЦикла; + + ОписаниеЗапросов = Новый Структура; + ОписаниеЗапросов.Вставить("ТипСсылки", Новый ХранилищеЗначения(Свойства.ТипСсылки)); + ОписаниеЗапросов.Вставить("КлючиЗапросовПоТипам", Свойства.КлючиЗапросовПоТипам); + ОписаниеЗапросов.Вставить("ТекстыЗапросовПоКлючам", ТекстыЗапросовПоКлючам); + ОписаниеЗапросов.Вставить("ТекстЗапросаПараметров", ТекстЗапросаПараметров); + + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить(ВидВедущегоСписка, ОписаниеЗапросов); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура СобратьЧастиЗапросаПроверки(Результат, Контекст) + + ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаДиапазонаЭлементовДанных, Контекст); + Результат.ТекстЗапросаДиапазонаЭлементовДанных = Контекст.ТекстЗапросаДиапазонаЭлементовДанных; + + ЧастиЗапроса1 = Новый Массив; + ЧастиЗапроса2 = Новый Массив; + ЧастиЗапроса3 = Новый Массив; + Если Контекст.ЭтоСсылочныйТип Тогда + ЧастиЗапроса1.Добавить(Контекст.ТекстЗапросаПроверкиСвязи); + ЧастиЗапроса2.Добавить(Контекст.ТекстЗапросаТочечнойПроверкиСвязи); + ЧастиЗапроса3.Добавить(Контекст.ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта); + КонецЕсли; + + Для Каждого ЧастьУсловияПроверки Из Контекст.ЧастиУсловияПроверки Цикл + ДобавитьЧастьЗапроса(ЧастиЗапроса1, ЧастьУсловияПроверки, Контекст, + Контекст.ТекстЗапросаПроверкиШапки, + Контекст.ТекстЗапросаПроверкиТабличнойЧасти); + + ДобавитьЧастьЗапроса(ЧастиЗапроса2, ЧастьУсловияПроверки, Контекст, + Контекст.ТекстЗапросаТочечнойПроверкиШапки, + Контекст.ТекстЗапросаТочечнойПроверкиТабличнойЧасти); + + Если Контекст.ЭтоСсылочныйТип Тогда + ДобавитьЧастьЗапроса(ЧастиЗапроса3, ЧастьУсловияПроверки, Контекст, + Контекст.ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта, + Контекст.ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта); + КонецЕсли; + КонецЦикла; + + ТекстЧастейЗапроса = СтрСоединить(ЧастиЗапроса1, ОбщегоНазначения.ТекстОбъединитьВсе()); + ТекстЗапроса = СтрЗаменить(Контекст.ТекстЗапросаПроверки, ",&ДополнительныеПоля1", + ТекстСОтступом(Контекст.ИспользуемыеПоляОсновнойТаблицы, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ДополнительныеПоля2", + ТекстСОтступом(Контекст.ИспользуемыеПоляОсновнойТаблицы, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ЧастиЗапросаПроверки", + "(" + ТекстСОтступом(ТекстЧастейЗапроса, " ") + ")"); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами = ТекстЗапроса; + + ТекстЧастейЗапроса = СтрСоединить(ЧастиЗапроса2, ОбщегоНазначения.ТекстОбъединитьВсе()); + ТекстЗапроса = СтрЗаменить(Контекст.ТекстЗапросаТочечнойПроверки, "&ЧастиЗапросаПроверки", + "(" + ТекстСОтступом(ТекстЧастейЗапроса, " ") + ")"); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаТочечнойПроверки", ТекстЗапроса); + + Результат.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам = + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам; + + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = СтрСоединить(ЧастиЗапроса3, ОбщегоНазначения.ТекстОбъединитьВсе()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаПроверкиКлючаДоступаОбъекта = ТекстЗапроса; + Иначе + ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаНовыхКомбинаций, Контекст); + Результат.ТекстЗапросаЭлементовДанныхБезКлючейДоступа = Контекст.ТекстЗапросаНовыхКомбинаций; + + ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаТекущихКлючейДоступа, Контекст); + Результат.ТекстЗапросаТекущихКлючейДоступаРегистра = Контекст.ТекстЗапросаТекущихКлючейДоступа; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросаПроверки. +Процедура ДобавитьЧастьЗапроса(ЧастиЗапроса, ЧастьУсловияПроверки, Контекст, + ТекстДляШапки, ТекстДляТабличнойЧасти) + + Если ЗначениеЗаполнено(ЧастьУсловияПроверки.ИмяТабличнойЧастиКлюча) Тогда + ТекущийТекст = ТекстДляТабличнойЧасти; + Иначе + ТекущийТекст = ТекстДляШапки; + КонецЕсли; + + ТекущийТекст = СтрЗаменить(ТекущийТекст, ",&ДополнительныеПоля2", + ТекстСОтступом(ЧастьУсловияПроверки.ДополнительныеПоля, " ")); + + ТекущийТекст = СтрЗаменить(ТекущийТекст, " #Соединения", " + | " + ТекстСОтступом(ЧастьУсловияПроверки.Соединения, " ")); + + ТекущийТекст = СтрЗаменить(ТекущийТекст, + "ТабличнаяЧасть?", ЧастьУсловияПроверки.ИмяТабличнойЧастиКлюча); + + ЧастиЗапроса.Добавить(СтрЗаменить(ТекущийТекст, + "&УсловиеЗапроса", ТекстСОтступом(ЧастьУсловияПроверки.Условие, " "))); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура СобратьЧастиЗапросовЗаполнения(Результат, Контекст) + + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзОбъектов, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа = ТекстЗапроса; + + Если ЗначениеЗаполнено(Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти) Тогда + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ИмяВременнойТаблицы = СтрЗаменить(Контекст.Список, ".", "_"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок.", ИмяВременнойТаблицы + "_"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", ИмяВременнойТаблицы); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа = ТекстЗапроса; + КонецЕсли; + + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения = ТекстЗапроса; + Результат.ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения = СтрЗаменить(ТекстЗапроса, + ".НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1)", ".Список = &Список"); // @query-part-1 + + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаСуществованияКлючейДляСравнения = ТекстЗапроса; + + ДобавитьЧастьЗапросаВыбораПравВедущихКлючейДоступа(Контекст); + ДобавитьЧастьЗапросаВыбораПравВедущихСписков(Контекст); + ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав(Контекст); + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав = ТекстЗапроса; + + Результат.ТекстЗапросаКлючейДоступаДляОбновленияПрав = + ТекстЗапросаКлючейДоступаДляОбновленияПрав(Контекст); + + Результат.ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав = + ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав(Контекст); + + Результат.ТекстЗапросаУстаревшихКлючейДоступа = + ТекстЗапросаУстаревшихКлючейДоступа(Контекст); + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Процедура ДобавитьЧастьЗапросаВыбораПравВедущихКлючейДоступа(Контекст) + + Если Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа[0]; + Иначе + УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа, + Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаСпискиВедущихКлючейДоступа.Таблица КАК Список, + | ПраваНаСпискиВедущихКлючейДоступа.ГруппаДоступа КАК ГруппаДоступа, + | ПраваНаСпискиВедущихКлючейДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСпискиВедущихКлючейДоступа + |ГДЕ + | ПраваНаСпискиВедущихКлючейДоступа.Таблица В + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | СпискиВедущихКлючейДоступа.Список + | ИЗ + | Справочник.КлючиДоступа КАК СпискиВедущихКлючейДоступа + | ГДЕ + | &УсловиеОтбора) + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | Список"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", + СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "СпискиВедущихКлючейДоступа.Ссылка")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + ТекстЗапроса = + "ВЫБРАТЬ + | СпискиВедущихКлючейДоступа.Ссылка КАК КлючДоступа, + | СпискиВедущихКлючейДоступа.Список КАК Список + |ИЗ + | Справочник.КлючиДоступа КАК СпискиВедущихКлючейДоступа + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", + СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "СпискиВедущихКлючейДоступа.Ссылка")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + Если Не Контекст.РассчитыватьПраваПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, + | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа + |ГДЕ + | ТИПЗНАЧЕНИЯ(ПраваНаКлючиДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа) + | И &УсловиеОтбора + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | КлючДоступа"; + ИначеЕсли Не Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, + | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа, + | ПраваНаКлючиДоступа.Пользователь.Пользователь, + | ПраваНаКлючиДоступа.ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК ПраваНаКлючиДоступа + |ГДЕ + | ПраваНаКлючиДоступа.ЭтоПраваНабораГрупп = ЛОЖЬ + | И ЕСТЬNULL(ПраваНаКлючиДоступа.Пользователь.Пользователь, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И &УсловиеОтбора + |ИТОГИ ПО + | КлючДоступа"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, + | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа, + | ПраваНаКлючиДоступа.ВнешнийПользователь.Пользователь, + | ПраваНаКлючиДоступа.ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК ПраваНаКлючиДоступа + |ГДЕ + | ПраваНаКлючиДоступа.ЭтоПраваНабораГрупп = ЛОЖЬ + | И ЕСТЬNULL(ПраваНаКлючиДоступа.ВнешнийПользователь.Пользователь, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И &УсловиеОтбора + |ИТОГИ ПО + | КлючДоступа"; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", + СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "ПраваНаКлючиДоступа.КлючДоступа")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Процедура ДобавитьЧастьЗапросаВыбораПравВедущихСписков(Контекст) + + Если Контекст.ЧастиУсловияВыбораПравВедущихСписков.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если Контекст.Свойство("ЧастиУсловияВыбораПравВедущихСписковСТипами") Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаСписки.Таблица КАК Список, + | ТИПЗНАЧЕНИЯ(ПраваНаСписки.Таблица.ЗначениеПустойСсылки) КАК ТипЗначения, + | ПраваНаСписки.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаСписки.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСписки + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | Список"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаСписки.Таблица КАК Список, + | ПраваНаСписки.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаСписки.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСписки + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | Список"; + КонецЕсли; + + Если Контекст.ЧастиУсловияВыбораПравВедущихСписков.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравВедущихСписков[0]; + Иначе + УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияВыбораПравВедущихСписков, + Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 + КонецЕсли; + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "ПраваНаСписки.Таблица"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Процедура ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав(Контекст) + + Если Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ТекстЗапроса = ТекстЗапросаВыбораПравПоВладельцамНастроекПрав(); + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Если Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав[0]; + Иначе + УсловиеОтбора = СтрСоединить(Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав, + Символы.ПС + " ИЛИ "); // @query-part-1 + КонецЕсли; + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "НаследованиеНастроек.Объект"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", ТекстСОтступом(УсловиеОтбора, " ")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав и +// функции ТекстЗапросаПравПользователейПоВладельцамНастроекПрав. +// +Функция ТекстЗапросаВыбораПравПоВладельцамНастроекПрав() + + Возврат + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект + |ПОМЕСТИТЬ ОбъектыСЗапрещениемЧтения + |ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияЧтения) + | И (&УсловиеОтбора) + | И (&УточнениеПланаЗапроса) + | + |ИНДЕКСИРОВАТЬ ПО + | Объект + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект + |ПОМЕСТИТЬ ОбъектыСЗапрещениемИзменения + |ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения) + | И (&УсловиеОтбора) + | И (&УточнениеПланаЗапроса) + | + |ИНДЕКСИРОВАТЬ ПО + | Объект + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НастройкиПравЧтения.Объект КАК Объект, + | НастройкиПравЧтения.Пользователь КАК Пользователь + |ПОМЕСТИТЬ НастройкиПравЧтения + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект, + | ВЫБОР + | КОГДА НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемЧтения.Объект + | ИЗ + | ОбъектыСЗапрещениемЧтения) + | ТОГДА СоставыГруппПользователей.Пользователь + | ИНАЧЕ СоставыГруппПользователей.ГруппаПользователей + | КОНЕЦ КАК Пользователь, + | ИСТИНА КАК ЧтениеРазрешено, + | ЛОЖЬ КАК ЧтениеЗапрещено + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияЧтения) + | И (&УсловиеОтбора) + | И (&УточнениеПланаЗапроса) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект, + | СоставыГруппПользователей.Пользователь, + | ЛОЖЬ, + | ИСТИНА + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО (НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемЧтения.Объект + | ИЗ + | ОбъектыСЗапрещениемЧтения)) + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияЧтения) + | И (&УсловиеОтбора) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор)) КАК НастройкиПравЧтения + | + |СГРУППИРОВАТЬ ПО + | НастройкиПравЧтения.Объект, + | НастройкиПравЧтения.Пользователь + | + |ИМЕЮЩИЕ + | МАКСИМУМ(НастройкиПравЧтения.ЧтениеРазрешено) = ИСТИНА И + | МАКСИМУМ(НастройкиПравЧтения.ЧтениеЗапрещено) = ЛОЖЬ + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НастройкиПравИзменения.Объект КАК Объект, + | НастройкиПравИзменения.Пользователь КАК Пользователь + |ПОМЕСТИТЬ НастройкиПравИзменения + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект, + | ВЫБОР + | КОГДА НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемИзменения.Объект + | ИЗ + | ОбъектыСЗапрещениемИзменения) + | ТОГДА СоставыГруппПользователей.Пользователь + | ИНАЧЕ СоставыГруппПользователей.ГруппаПользователей + | КОНЕЦ КАК Пользователь, + | ИСТИНА КАК ИзменениеРазрешено, + | ЛОЖЬ КАК ИзменениеЗапрещено + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияИзменения) + | И (&УсловиеОтбора) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НастройкиПравЧтения КАК НастройкиПравЧтения + | ПО (НастройкиПравЧтения.Объект = НаследованиеНастроек.Объект) + | И (НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | ИЛИ НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.Пользователь) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект, + | СоставыГруппПользователей.Пользователь, + | ЛОЖЬ, + | ИСТИНА + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО (НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемИзменения.Объект + | ИЗ + | ОбъектыСЗапрещениемИзменения)) + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения) + | И (&УсловиеОтбора) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НастройкиПравЧтения КАК НастройкиПравЧтения + | ПО (НастройкиПравЧтения.Объект = НаследованиеНастроек.Объект) + | И (НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | ИЛИ НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.Пользователь)) КАК НастройкиПравИзменения + | + |СГРУППИРОВАТЬ ПО + | НастройкиПравИзменения.Объект, + | НастройкиПравИзменения.Пользователь + | + |ИМЕЮЩИЕ + | МАКСИМУМ(НастройкиПравИзменения.ИзменениеРазрешено) = ИСТИНА И + | МАКСИМУМ(НастройкиПравИзменения.ИзменениеЗапрещено) = ЛОЖЬ + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НастройкиПрав.Объект КАК ВладелецНастроекПрав, + | НастройкиПрав.Пользователь КАК ВладелецПрав, + | МАКСИМУМ(НастройкиПрав.ПравоИзменение) КАК ПравоИзменение + |ИЗ + | (ВЫБРАТЬ + | НастройкиПрав.Объект КАК Объект, + | НастройкиПрав.Пользователь КАК Пользователь, + | ЛОЖЬ КАК ПравоИзменение + | ИЗ + | НастройкиПравЧтения КАК НастройкиПрав + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | НастройкиПрав.Объект, + | НастройкиПрав.Пользователь, + | ИСТИНА + | ИЗ + | НастройкиПравИзменения КАК НастройкиПрав) КАК НастройкиПрав + | + |СГРУППИРОВАТЬ ПО + | НастройкиПрав.Объект, + | НастройкиПрав.Пользователь + |ИТОГИ ПО + | ВладелецНастроекПрав"; + +КонецФункции + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Функция ТекстЗапросаКлючейДоступаДляОбновленияПрав(Контекст) + + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.СоставПолей = &СоставПолей + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Функция ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав(Контекст) + + Если Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Количество() = 0 Тогда + Возврат ""; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.СоставПолей = &СоставПолей + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И &УсловиеОтбора + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Если Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа[0]; + Иначе + УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа, + Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Функция ТекстЗапросаУстаревшихКлючейДоступа(Контекст) + + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапросаИспользуемых = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК КлючДоступа + |ПОМЕСТИТЬ ИспользуемыеКлючиДоступа + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.#КлючДоступаПользователей > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |ИНДЕКСИРОВАТЬ ПО + | КлючДоступа"; // @query-part + Иначе + ТекстЗапросаИспользуемых = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа + |ПОМЕСТИТЬ ИспользуемыеКлючиДоступа + |ИЗ + | &ТекущийСписок КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = &Список + | И КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа + | И КлючиДоступаКРегистрам.КлючДоступа > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |ИНДЕКСИРОВАТЬ ПО + | КлючДоступа"; + Если ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + ТекстЗапросаИспользуемых = СтрЗаменить(ТекстЗапросаИспользуемых, + "КлючиДоступаКРегистрам.Регистр = &Список + | И ", ""); // @query-part-1 + КонецЕсли; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка, + | КлючиДоступа.Список КАК Список, + | КлючиДоступа.СоставПолей КАК СоставПолей, + | КлючиДоступа.Хеш КАК Хеш, + | НЕ ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL КАК Используется, + | КлючиДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(1, 1, 1) + | И КлючиДоступа.НеИспользуетсяС < &ДатаУстаревания КАК Удалить + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + | ЛЕВОЕ СОЕДИНЕНИЕ ИспользуемыеКлючиДоступа КАК ИспользуемыеКлючиДоступа + | ПО (ИспользуемыеКлючиДоступа.КлючДоступа = КлючиДоступа.Ссылка) + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И ВЫБОР + | КОГДА КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | ТОГДА ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL + | ИНАЧЕ НЕ ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL + | ИЛИ КлючиДоступа.НеИспользуетсяС < &ДатаУстаревания + | КОНЕЦ + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ТекстЗапроса = ТекстЗапросаИспользуемых + + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьЗапросыПравПользователей(Результат, Контекст) + + Если Контекст.БезОбъектаМетаданных + Или Не Контекст.ЭтоСсылочныйТип + И Контекст.ИмяКоллекцииТипа <> "РегистрыСведений" + И Контекст.ИмяКоллекцииТипа <> "РегистрыНакопления" + И Контекст.ИмяКоллекцииТипа <> "РегистрыБухгалтерии" + И Контекст.ИмяКоллекцииТипа <> "РегистрыРасчета" Тогда + Возврат; + КонецЕсли; + + Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); + ТекстыЗапросов = Новый Массив; + ЧастиЗапроса = Новый Массив; + + Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа + Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда + + ТекстЗапроса = + "ВЫБРАТЬ + | НаборыПользователей.Пользователь КАК ПользовательСПравом, + | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа + | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыПользователей + | ПО (НаборыПользователей.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) + | И (ВЫБОР + | КОГДА НаборыПользователей.Ссылка = РазрешенныеКлючиДоступа.Пользователь + | ТОГДА ИСТИНА + | ИНАЧЕ НаборыПользователей.РазрешенныйНаборГруппПользователей = РазрешенныеКлючиДоступа.Пользователь + | КОНЕЦ) + | И (&ОтборПользователей1)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | НаборыПользователей.Пользователь КАК ПользовательСПравом, + | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыПользователей + | ПО (НаборыПользователей.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) + | И (НаборыПользователей.РазрешенныйНаборГруппДоступа = РазрешенныеКлючиДоступа.НаборГруппДоступа) + | И (&ОтборПользователей1)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + + ТекстЗапроса = + "ВЫБРАТЬ + | &РазрешенныйПустойНаборГруппДоступа КАК ПользовательСПравом, + | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | И (РазрешенныеКлючиДоступа.НаборГруппДоступа = &РазрешенныйПустойНаборГруппДоступа)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + + ТекстыЗапросов = Новый Массив; + УсловиеПроверкиТипаВладельцаНастроекПрав1 = "ИСТИНА"; + УсловиеПроверкиТипаВладельцаНастроекПрав2 = "ИСТИНА"; + + Если Не Результат.ИспользуетсяОграничениеПоВладельцу Тогда + ТипыВладельцевНастроекПравПоля = Неопределено; + Иначе + ТипКонечногоПоля = Контекст.СвойстваПолей[0].ТипКонечногоПоля; + ТипыВладельцевНастроекПравПоля = Новый Соответствие; + Если Контекст.ОграничениеДоступаВключено Тогда + Для Каждого КлючИЗначение Из Контекст.ТипыВладельцевНастроекПрав Цикл + Если ТипКонечногоПоля.СодержитТип(КлючИЗначение.Ключ) Тогда + ТипыВладельцевНастроекПравПоля.Вставить(КлючИЗначение.Ключ, + ИмяТипаНаЯзыкеЗапросов(КлючИЗначение.Ключ)); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ТипыВладельцевНастроекПравПоля.Количество() = 0 Тогда + ТипыВладельцевНастроекПравПоля = Неопределено; + + ИначеЕсли ТипКонечногоПоля.Типы().Количество() = ТипыВладельцевНастроекПравПоля.Количество() Тогда + ЧастиЗапроса.Очистить(); + Иначе + Условие1 = ""; + Условие2 = ""; + Для Каждого СвойстваТипа Из ТипыВладельцевНастроекПравПоля Цикл + Условие1 = Условие1 + ?(Условие1 = "", "", " + | И ") + "ТИПЗНАЧЕНИЯ(&ПолеОбъекта) <> ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 + Условие2 = Условие2 + ?(Условие2 = "", "", " + | ИЛИ ") + "ТИПЗНАЧЕНИЯ(&ПолеОбъекта) = ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 + КонецЦикла; + УсловиеПроверкиТипаВладельцаНастроекПрав1 = Условие1; + УсловиеПроверкиТипаВладельцаНастроекПрав2 = Условие2; + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(ТипыВладельцевНастроекПравПоля) Тогда + ДобавитьТекстЗапросаПравПользователейПоВладельцамНастроекПрав(Контекст.ДляВнешнихПользователей, + ЧастиЗапроса, ТекстыЗапросов); + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | МАКСИМУМ(ПраваПользователей.ПравоИзменение) КАК ПравоИзменение, + | ПраваПользователей.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПользователиСПравамиНаЭлементыДанных + |ИЗ + | (#ЧастиЗапроса) КАК ПраваПользователей + | + |СГРУППИРОВАТЬ ПО + | ПраваПользователей.Ссылка, + | ПраваПользователей.ПользовательСПравом"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ЧастиЗапроса", + ТекстСОтступом(СтрСоединить(ЧастиЗапроса, ОбщегоНазначения.ТекстОбъединитьВсе()), " ")); + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", + "РегистрСведений.КлючиДоступаВнешнихПользователей"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", + "РазрешенныеКлючиДоступа.ВнешнийПользователь"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", + "Справочник.ВнешниеПользователи"); + + Если Контекст.ЭтоСсылочныйТип + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", + "КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей"); + КонецЕсли; + КонецЕсли; + + ТекстыЗапросов.Добавить(ТекстЗапроса); + ТекстЗапроса = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + + Если Контекст.ЭтоСсылочныйТип + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав1", + УсловиеПроверкиТипаВладельцаНастроекПрав1); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав2", + УсловиеПроверкиТипаВладельцаНастроекПрав2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав3", + ТекстСОтступом(УсловиеПроверкиТипаВладельцаНастроекПрав2, " ")); + КонецЕсли; + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + Если Контекст.ЭтоСсылочныйТип Тогда + ПолеОбъекта = "Ссылка." + Результат.ПолеВладельца.Имя; + Иначе + ЧастиПоляВладельца = СтрРазделить(Результат.ПолеВладельца.Имя, "."); + ЧастиПоляВладельца[0] = "Ссылка"; + ПолеОбъекта = СтрСоединить(ЧастиПоляВладельца, "."); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеОбъекта", "ТекущаяТаблица." + ПолеОбъекта); + + ИначеЕсли Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеОбъекта", "ТекущаяТаблица.Ссылка"); + + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "КлючиДоступаКОбъектам.Объект = &ПолеОбъекта", + "КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)"); // @query-part-1, @query-part-2 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + " И (&УсловиеПроверкиТипаВладельцаНастроекПрав1)", + " И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + | И (&ОтборПоИзмерениям)"); // @query-part-1 @query-part-2 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", + "КлючиДоступаКРегистрам.КлючДоступа"); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам", "КлючиДоступаКРегистрам"); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекущаяТаблица КАК ТекущаяТаблица", + Контекст.Список + " КАК ТекущаяТаблица"); // @query-part-1, @query-part-2 + + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст); + + УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, Контекст.Список); + КонецЕсли; + + Результат.ТекстЗапросаПравПользователей = ТекстЗапроса; + +КонецПроцедуры + +// Для процедуры ЗаполнитьЗапросыПравПользователей. +Процедура УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, ПолноеИмяРегистра) + + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); + + ИзмеренияДляВыбора = Новый Массив; + ИзмеренияДляГруппировки = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + УточненноеИмя = УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ОписаниеПоля.Имя); + ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %2", ОписаниеПоля.Имя, УточненноеИмя)); + ИзмеренияДляГруппировки.Добавить(СтрШаблон("ПраваПользователей.%1,", УточненноеИмя)); + КонецЦикла; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущаяТаблица.Ссылка КАК Ссылка", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка КАК Ссылка", + СтрЗаменить(СтрСоединить(ИзмеренияДляВыбора, ", + | "), "ТекущаяТаблица.", "ПраваПользователей.")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка,", + СтрСоединить(ИзмеренияДляГруппировки, " + | ")); + +КонецПроцедуры + +// Для процедуры УстановитьПоляИзмеренийДляВыбораИГруппировки +Функция УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ИмяПоля) + + Если ВРег(ИмяПоля) = ВРег("ПользовательСПравом") + Или ВРег(ИмяПоля) = ВРег("ПравоИзменение") Тогда + Возврат ИмяПоля + "_"; + КонецЕсли; + + Возврат ИмяПоля; + +КонецФункции + +// Для процедуры ЗаполнитьЗапросыПравПользователей. +Процедура ДобавитьТекстЗапросаПравПользователейПоВладельцамНастроекПрав(ДляВнешнихПользователей, + ЧастиЗапроса, ТекстыЗапросов) + + ТекстЗапроса = ТекстЗапросаВыбораПравПоВладельцамНастроекПрав(); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УточнениеПланаЗапроса", "ИСТИНА"); + + Если ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + УсловиеОтбора = + "НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | &ПолеОбъекта + | ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ГДЕ + | &УсловиеПроверкиТипаВладельцаНастроекПрав3)"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + + ЗапросыПакета = СтрРазделить(ТекстЗапроса, ";"); + ЗапросыПакета.Удалить(ЗапросыПакета.Количество() - 1); + ТекстыЗапросов.Добавить(СокрП(СтрСоединить(ЗапросыПакета, ";"))); + + ТекстЗапроса = + "ВЫБРАТЬ + | СоставыГруппПользователей.Пользователь КАК ПользовательСПравом, + | ЛОЖЬ КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | НастройкиПравЧтения КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица + | ПО (НастройкиПрав.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав2) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (&ОтборПользователей2)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + + ТекстЗапроса = + "ВЫБРАТЬ + | СоставыГруппПользователей.Пользователь КАК ПользовательСПравом, + | ИСТИНА КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | НастройкиПравИзменения КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица + | ПО (НастройкиПрав.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав2) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (&ОтборПользователей2)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст) + + Если Контекст.ИмяКоллекцииТипа = "ЖурналыДокументов" Тогда + Возврат; + КонецЕсли; + + Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); + + Если Контекст.ЭтоСсылочныйТип + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа + Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | КлючиДоступаКОбъектам.Объект = &Объект + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей + | И РазрешенныеКлючиДоступа.Пользователь В (&РазрешенныйПользователь, &РазрешенныйНаборГруппПользователей) + | И РазрешенныеКлючиДоступа.ПравоИзменение) + | ИЛИ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей + | И РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа) + | И РазрешенныеКлючиДоступа.ПравоИзменение))"; + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", + "РегистрСведений.КлючиДоступаВнешнихПользователей"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", + "РазрешенныеКлючиДоступа.ВнешнийПользователь"); + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (КлючиДоступаКОбъектам.Объект = &Объект) + | И (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | И (РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа)) + | И (РазрешенныеКлючиДоступа.ПравоИзменение)"; + КонецЕсли; + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", + "КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей"); + КонецЕсли; + КонецЕсли; + + Если Не Результат.ИспользуетсяОграничениеПоВладельцу Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = ""; + Иначе + ТипКонечногоПоля = Контекст.СвойстваПолей[0].ТипКонечногоПоля; + ТипыВладельцевНастроекПравПоля = Новый Соответствие; + Если Контекст.ОграничениеДоступаВключено Тогда + Для Каждого КлючИЗначение Из Контекст.ТипыВладельцевНастроекПрав Цикл + Если ТипКонечногоПоля.СодержитТип(КлючИЗначение.Ключ) Тогда + ТипыВладельцевНастроекПравПоля.Вставить(КлючИЗначение.Ключ, + ИмяТипаНаЯзыкеЗапросов(КлючИЗначение.Ключ)); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ТипыВладельцевНастроекПравПоля.Количество() = 0 Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = ""; + + ИначеЕсли ТипКонечногоПоля.Типы().Количество() = ТипыВладельцевНастроекПравПоля.Количество() Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав(); + Иначе + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ГДЕ + | ВЫБОР + | КОГДА &УсловиеПроверкиТипаВладельцаНастроекПрав + | ТОГДА &УсловиеСПроверкойПоВладельцамНастроекПрав + | ИНАЧЕ ИСТИНА В + | (&ТекстЗапросаСтандартнойПроверки) + | КОНЕЦ"; + Иначе + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ КАК ЗначениеЛожь + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям + | И ВЫБОР + | КОГДА &УсловиеПроверкиТипаВладельцаНастроекПрав + | ТОГДА &УсловиеСПроверкойПоВладельцамНастроекПрав + | ИНАЧЕ ИСТИНА В + | (&ТекстЗапросаСтандартнойПроверки) + | КОНЕЦ"; + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&ТекущаяТаблица", Контекст.Список) + КонецЕсли; + УсловиеПроверкиТипа = ""; + Для Каждого СвойстваТипа Из ТипыВладельцевНастроекПравПоля Цикл + УсловиеПроверкиТипа = УсловиеПроверкиТипа + ?(УсловиеПроверкиТипа = "", "", " + | ИЛИ ") + "ТИПЗНАЧЕНИЯ(&Объект) = ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 + КонецЦикла; + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&УсловиеПроверкиТипаВладельцаНастроекПрав", + УсловиеПроверкиТипа); + + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&УсловиеСПроверкойПоВладельцамНастроекПрав", + ТекстСОтступом(УсловиеИзЗапросаСПроверкойПоВладельцамНастроекПрав(), + " ")); + + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&ТекстЗапросаСтандартнойПроверки", + ТекстСОтступом(ТекстЗапроса, " ")); + КонецЕсли; + КонецЕсли; + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + Если Контекст.ЭтоСсылочныйТип Тогда + ПолеОбъекта = "ВЫРАЗИТЬ(&Объект КАК " + Контекст.Список + ")." + Результат.ПолеВладельца.Имя; // @query-part-1 + Результат.ПолеОбъектаВладельцаВЗапросеПроверкиПрав = ПолеОбъекта; + Иначе + ПолеОбъекта = "ТекущаяТаблица." + Результат.ПолеВладельца.Имя; + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Объект", ПолеОбъекта); + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + СтрЗаменить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, "&Объект", ПолеОбъекта); + + ИначеЕсли Не Контекст.ЭтоСсылочныйТип Тогда + + Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа + Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка) + | И КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1 + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа + | И РазрешенныеКлючиДоступа.Пользователь В (&РазрешенныйПользователь, &РазрешенныйНаборГруппПользователей) + | И РазрешенныеКлючиДоступа.ПравоИзменение) + | ИЛИ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа + | И РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа) + | И РазрешенныеКлючиДоступа.ПравоИзменение))"; + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", + "РегистрСведений.КлючиДоступаВнешнихПользователей"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", + "РазрешенныеКлючиДоступа.ВнешнийПользователь"); + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) + | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + | И (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа) + | И (РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа)) + | И (РазрешенныеКлючиДоступа.ПравоИзменение)"; + КонецЕсли; + + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст); + + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ТекущаяТаблицаПоле1 КАК Поле1 + |ИЗ + | &Список КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) + | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + |ГДЕ + | &ОтборПоИзмерениям + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей = + "ВЫБРАТЬ + | &ТекущаяТаблицаПоле1 КАК ТекущаяТаблицаПоле1 + |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей + |ИЗ + | &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ТекущаяТаблицаПоле1 КАК Поле1 + |ИЗ + | КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) + | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + |ГДЕ + | КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей, + Результат, Контекст, Истина); + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей, + Результат, Контекст, Истина); + + Результат.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей = + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей; + Результат.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей = + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей; + КонецЕсли; + + Если Не Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапросаРегистра = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ КАК ЗначениеЛожь + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям + | И НЕ ИСТИНА В + | (&УсловиеЗапроса)"; + ТекстЗапросаРегистра = СтрЗаменить(ТекстЗапросаРегистра, "&ТекущаяТаблица", Контекст.Список); + ТекстЗапроса = СтрЗаменить(ТекстЗапросаРегистра, "&УсловиеЗапроса", ТекстСОтступом(ТекстЗапроса, " ")); + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав) Тогда + Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = ТекстЗапросаСПроверкойПоВладельцамНастроекПрав; + Иначе + Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = ТекстЗапроса; + КонецЕсли; + + Если Не Результат.ОграничениеЧтенияОтключено Тогда + Результат.ТекстЗапросаПроверкиПраваЧтение = СтрЗаменить(ТекстЗапроса, + "РазрешенныеКлючиДоступа.ПравоИзменение", "Истина"); + КонецЕсли; + + Если Результат.ИспользуетсяОграничениеПоВладельцу + И Результат.ПолеВладельца.ИзменениеКакЧтение Тогда + + Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = Результат.ТекстЗапросаПроверкиПраваЧтение; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Функция УсловиеИзЗапросаСПроверкойПоВладельцамНастроекПрав() + + Строки = СтрРазделить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав(), Символы.ПС, ""); + Строки.Удалить(0); + Строки.Удалить(0); + Строки.Удалить(0); + + Возврат СокрЛП(СтрСоединить(Строки, Символы.ПС)); + +КонецФункции + +// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Функция ТекстЗапросаСПроверкойПоВладельцамНастроекПрав() + + Возврат + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ГДЕ + | ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО + | НаследованиеНастроек.Объект = &Объект + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав + | И НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияИзменения + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь + | И СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО + | НаследованиеНастроек.Объект = &Объект + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав + | И НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь + | И СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь)"; + +КонецФункции + +// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Процедура УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст, ДобавитьПоляВыбора = Ложь) + + Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "РегистрСведений.КлючиДоступаКРегистрам", + "РегистрСведений." + Результат.ИмяОтдельногоРегистраКлючей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)", // @query-part-1 + "ИСТИНА"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ИдентификаторыОбъектовМетаданных.ПустаяСсылка", + УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных( + Контекст.Список)); + КонецЕсли; + + ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); + Если ИспользуемыеВариантыДоступа = Неопределено Тогда + ИспользуемыйВариантДоступа = НовыйИспользуемыйВариантДоступа(); + ИспользуемыйВариантДоступа.ВариантДоступа = Результат.ВариантДоступа; + ИспользуемыйВариантДоступа.ПоляСоединения = СтрСоединить(Результат.ОпорныеПоля.Используемые, ","); + ИспользуемыеВариантыДоступа = Новый Массив; + ИспользуемыеВариантыДоступа.Добавить(ИспользуемыйВариантДоступа); + КонецЕсли; + Если ДобавитьПоляВыбора Тогда + ИспользуемыйВариантДоступа = ИспользуемыеВариантыДоступа[0]; + ИспользуемыеВариантыДоступа = Новый Массив; + ИспользуемыеВариантыДоступа.Добавить(ИспользуемыйВариантДоступа); + КонецЕсли; + + УсловияОтбора = Новый Массив; + УсловияСоединения = Новый Массив; + Для Каждого ИспользуемыйВариантДоступа Из ИспользуемыеВариантыДоступа Цикл + Условие = Новый Массив; + ВариантДоступаСтрокой = XMLСтрока(ИспользуемыйВариантДоступа.ВариантДоступа); + ВариантДоступаСтрокой = ?(ЗначениеЗаполнено(ВариантДоступаСтрокой), ВариантДоступаСтрокой, "NULL"); + Условие.Добавить("КлючиДоступаКРегистрам.ВариантДоступа = " + ВариантДоступаСтрокой); + НомерПоля = 1; + ИменаПолей = СтрРазделить(ИспользуемыйВариантДоступа.ПоляСоединения, ",", Ложь); + Для Каждого ИмяПоля Из ИменаПолей Цикл + Условие.Добавить(СтрШаблон("КлючиДоступаКРегистрам.Поле%1 = ТекущаяТаблица.%2", НомерПоля, ИмяПоля)); + НомерПоля = НомерПоля + 1; + КонецЦикла; + Если ИспользуемыеВариантыДоступа.Количество() = 1 Тогда + УсловияОтбора.Добавить("И " + СтрСоединить(Условие, Символы.ПС + "И ")); // @query-part-1, @query-part-2 + УсловияСоединения.Добавить("И (" + СтрСоединить(Условие, ")" + Символы.ПС + "И (") + ")"); // @query-part-1, @query-part-3 + Иначе + УсловияОтбора.Добавить(СтрСоединить(Условие, Символы.ПС + " И ")); + УсловияСоединения.Добавить(СтрСоединить(Условие, Символы.ПС + " И ")); + КонецЕсли; + КонецЦикла; + + Если ИспользуемыеВариантыДоступа.Количество() = 1 Тогда + УсловиеОтбора = УсловияОтбора[0]; + УсловиеСоединения = УсловияСоединения[0]; + Иначе + УсловиеОтбора = "И (" + СтрСоединить(УсловияОтбора, Символы.ПС + " ИЛИ ") + ")"; // @query-part-1, @query-part-2 + УсловиеСоединения = "И (" + СтрСоединить(УсловияСоединения, Символы.ПС + " ИЛИ ") + ")"; // @query-part-1, @query-part-2 + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "И КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1", + ТекстСОтступом(СокрЛ(УсловиеОтбора), " ")); // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1)", + ТекстСОтступом(СокрЛ(УсловиеСоединения), " ")); // @query-part-1 + + Если Не ДобавитьПоляВыбора Тогда + Возврат; + КонецЕсли; + + ОпорныеПоля = ""; + ПоляВыбора = ""; + НомерПоля = 1; + Для Каждого Поле Из Результат.ОпорныеПоля.Используемые Цикл + ОпорныеПоля = ОпорныеПоля + ?(ОпорныеПоля = "", "", "," + Символы.ПС) + + СтрШаблон("ТекущаяТаблица.%1 КАК %1", Поле); // @query-part-4 + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", "," + Символы.ПС) + + СтрШаблон("ТекущаяТаблица.%2 КАК Поле%1", НомерПоля, Поле); // @query-part-4 + НомерПоля = НомерПоля + 1; + КонецЦикла; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "&ТекущаяТаблицаПоле1 КАК ТекущаяТаблицаПоле1", + ТекстСОтступом(СокрЛ(ОпорныеПоля), " ")); // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "&ТекущаяТаблицаПоле1 КАК Поле1", + ТекстСОтступом(СокрЛ(ПоляВыбора), " ")); // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Список", Контекст.Список); + +КонецПроцедуры + +// Для функции СобратьЧастиЗапросов. +Процедура ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст) + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователейКОбъекту", "КлючДоступаВнешнихПользователей"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователейКОбъекту", "КлючДоступаПользователей"); + КонецЕсли; + + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Контекст.Список); + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступаВнешнихПользователей"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступаПользователей"); + КонецЕсли; + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистр", Контекст.Список); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок.Регистр = &ИдентификаторРегистра", "#1"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок.ВариантДоступа = &ВариантДоступа", "#2"); + Номер = 0; + Для Каждого ИмяОпорногоПоля Из Контекст.ОпорныеПоля.Используемые Цикл + Номер = Номер + 1; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, СтрШаблон("ТекущийСписок.%1", ИмяОпорногоПоля), + СтрШаблон("ТекущийСписок.Поле%1", Номер)); + КонецЦикла; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#1", "ТекущийСписок.Регистр = &ИдентификаторРегистра"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#2", "ТекущийСписок.ВариантДоступа = &ВариантДоступа"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", ?(Контекст.ИмяОтдельногоРегистраКлючей = "", + "РегистрСведений.КлючиДоступаКРегистрам", "РегистрСведений." + Контекст.ИмяОтдельногоРегистраКлючей)); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступа"); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СоставПолей", Формат(Контекст.СоставПолей, "ЧН=0; ЧГ=")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВариантДоступа", XMLСтрока(Контекст.ВариантДоступа)); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДляВнешнихПользователей", + ?(Контекст.ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ")); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьПроверкуШапкиКлюча(Контекст, НомерШапки) + + ГруппаПолей = Контекст.ГруппыПолей.Получить(СтрШаблон("Шапка%1", НомерШапки)); + Если ГруппаПолей = Неопределено Тогда + Если НомерШапки > 0 Тогда + Возврат; + КонецЕсли; + СоединенияИПоля = Новый Структура("Соединения, Поля", "", ""); + Иначе + СоединенияИПоля = СоединенияИПоляПоТаблицам(ГруппаПолей, + Ложь, НомерШапки).Получить("ТекущийСписок"); + КонецЕсли; + + Если НомерШапки = 0 Тогда + Соединения = СоединенияИПоля.Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа КАК Шапка0 + |ПО (Шапка0.Ссылка = ТекущийСписок.ТекущийКлючДоступа)" + + ?(Контекст.СоставПолей = 0, " + | И (Шапка0.Список = &Список)", "") + + " + | И (Шапка0.СоставПолей = &СоставПолей)"; // @query-part-1, @query-part-2, @query-part-4 + Иначе + Соединения = СоединенияИПоля.Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа.Шапка КАК Шапка? + |ПО (Шапка?.Ссылка = ТекущийСписок.ТекущийКлючДоступа) + | И (Шапка?.НомерСтроки = &НомерШапки)"; // @query-part-1 + Соединения = СтрЗаменить(Соединения, "&НомерШапки", НомерШапки); + КонецЕсли; + + Соединения = СокрЛ(Соединения) + ТекстСОтступом(СоединенияИПоля.Поля, " "); + Условие = "Шапка?.Ссылка ЕСТЬ NULL"; // @query-part-1 + + Соединения = СтрЗаменить(Соединения, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Условие = СтрЗаменить(Условие, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + + Контекст.ЧастиУсловияПроверки.Добавить(ЧастьУсловияПроверки(Соединения, Условие, + Контекст.ИспользуемыеПоляОсновнойТаблицы)); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьПроверкуТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча) + + ТаблицыПоГруппам = Контекст.ГруппыДополнительныхТаблиц.ТаблицыПоГруппам; + ГруппаДополнительныхТаблиц = ТаблицыПоГруппам.Получить(НомерТабличнойЧастиКлюча + - (Контекст.КоличествоТабличныхЧастейКлюча - ТаблицыПоГруппам.Количество())); + + ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + ГруппаПолей = Контекст.ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); + + СоединенияИПоляПоТаблицам = СоединенияИПоляПоТаблицам(ГруппаПолей, Истина); + + Соединения = ""; + Поля = ""; + + Если ГруппаДополнительныхТаблиц = Неопределено Тогда + ПсевдонимТабличнойЧастиОбъекта = Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча); + Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить("ТекущийСписок"); + Иначе + ИмяТабличнойЧастиОбъекта = СтрЗаменить(ПсевдонимТабличнойЧастиОбъекта, "ТекущийСписок", ""); + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ПсевдонимТабличнойЧастиОбъекта); + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок." + ИмяТабличнойЧастиОбъекта + " КАК " + ПсевдонимТабличнойЧастиОбъекта + " + |ПО " + ПсевдонимТабличнойЧастиОбъекта + ".Ссылка = ТекущийСписок.Ссылка"; // @query-part-1, @query-part-2, @query-part-3, @query-part-4 + КонецЕсли; + Соединения = Соединения + СоединенияИПоля.Соединения; + Поля = СоединенияИПоля.Поля; + Иначе + Для Каждого ДополнительнаяТаблица Из ГруппаДополнительныхТаблиц Цикл + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3 + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ДополнительнаяТаблица.Псевдоним); + Если СоединенияИПоля = Неопределено Тогда + Продолжить; + КонецЕсли; + Соединения = Соединения + СоединенияИПоля.Соединения; + Поля = Поля + СоединенияИПоля.Поля; + КонецЦикла; + КонецЕсли; + + // Прямое соединение (проверка наличия требуемых записей в ключе). + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + |ПО (ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа)"; // @query-part + Соединения = СокрЛ(Соединения) + ТекстСОтступом(Поля, " "); + Условие = "ТабличнаяЧасть?.Ссылка ЕСТЬ NULL"; // @query-part-1 + + Соединения = СтрЗаменить(Соединения, "ТабличнаяЧасть?", ИмяТабличнойЧастиКлюча); + Условие = СтрЗаменить(Условие, "ТабличнаяЧасть?", ИмяТабличнойЧастиКлюча); + + ДополнительныеПоля = ""; + Если Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча) = Неопределено Тогда + ДополнительныеПоля = Контекст.ИспользуемыеПоляОсновнойТаблицы; + КонецЕсли; + + Контекст.ЧастиУсловияПроверки.Добавить(ЧастьУсловияПроверки(Соединения, + Условие, ДополнительныеПоля, ИмяТабличнойЧастиКлюча)); + +КонецПроцедуры + +// Для процедур ДобавитьПроверкуШапкиКлюча, ДобавитьПроверкуТабличнойЧастиКлюча. +// +// Возвращаемое значение: +// Структура: +// * Соединения - Строка +// * Условие - Строка +// * ДополнительныеПоля - Строка +// * ИмяТабличнойЧастиКлюча - Строка +// +Функция ЧастьУсловияПроверки(Соединения, Условие, ДополнительныеПоля, ИмяТабличнойЧастиКлюча = "") + + Результат = Новый Структура; + Результат.Вставить("Соединения", Соединения); + Результат.Вставить("Условие", Условие); + Результат.Вставить("ИмяТабличнойЧастиКлюча", ИмяТабличнойЧастиКлюча); + Результат.Вставить("ДополнительныеПоля", ДополнительныеПоля); + + Возврат Результат; + +КонецФункции + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьЗаполнениеШапкиКлюча(Контекст, НомерШапки) + + Если Не Контекст.ЭтоСсылочныйТип И НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка, + | &ОпорныеПоляДляВыбора + |ПОМЕСТИТЬ ТекущийСписок + |ИЗ + | &ЗначенияОпорныхПолей КАК ТекущийСписок"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", Контекст.ОпорныеПоля.ДляВыбора); + Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); + + ИначеЕсли НомерШапки = 0 Тогда + Для Каждого ОписаниеТаблицы Из Контекст.ПоляТаблицОбъекта.Результат Цикл + ТекстЗапроса = + "ВЫБРАТЬ + | &ПоляТаблицы + | ПОМЕСТИТЬ #ПолноеИмяТаблицы + |ИЗ + | &ПолноеИмяТаблицы КАК ТекущаяТаблица"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляТаблицы", + "ТекущаяТаблица." + СтрСоединить(ОписаниеТаблицы.Поля, ", + | ТекущаяТаблица.")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ПолноеИмяТаблицы", ОписаниеТаблицы.ПолноеИмяТаблицы); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяТаблицы", "&" + ОписаниеТаблицы.ПолноеИмяТаблицы); + Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить(ТекстЗапроса); + КонецЦикла; + КонецЕсли; + + ГруппаПолей = Контекст.ГруппыПолей.Получить(СтрШаблон("Шапка%1", НомерШапки)); + Если ГруппаПолей = Неопределено Тогда + Возврат; + КонецЕсли; + ДобавитьОписаниеТаблицыКлюча(СтрШаблон("Шапка%1", НомерШапки), ГруппаПолей, Контекст); + + СоединенияИПоля = СоединенияИПоляПоТаблицам(ГруппаПолей, Ложь, + НомерШапки, Истина).Получить("ТекущийСписок"); + + // Выбор значений из объектов для поиска и создания ключей доступа. + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляЗапроса + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка,&ПоляЗапроса + |ИЗ + | ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ОпорныеПоляДляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", Контекст.ОпорныеПоля.ДляУпорядочения); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляЗапроса", ТекстСОтступом(СоединенияИПоля.Поля, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(СоединенияИПоля.Соединения, " ")); + + Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); + Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить(ТекстЗапроса); + + // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | Шапка0.Ссылка КАК ТекущаяСсылка,&Реквизиты + |ИЗ + | Справочник.КлючиДоступа КАК Шапка0 + |ГДЕ + | Шапка0.Хеш В(&Хеши) + | И Шапка0.Список = &Список + | И Шапка0.СоставПолей = &СоставПолей + | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И Шапка0.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка + |ИТОГИ ПО + | ТекущаяСсылка"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | Шапка?.Ссылка КАК ТекущаяСсылка,&Реквизиты + |ИЗ + | Справочник.КлючиДоступа.Шапка КАК Шапка? + |ГДЕ + | Шапка?.НомерСтроки = &НомерШапки + | И Шапка?.Ссылка.Хеш В(&Хеши) + | И Шапка?.Ссылка.Список = &Список + | И Шапка?.Ссылка.СоставПолей = &СоставПолей + | И Шапка?.Ссылка.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И Шапка?.Ссылка.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&НомерШапки", НомерШапки); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(СоединенияИПоля.Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Проверка существования ключа доступа перед записью нового ключа. + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.КлючиДоступа КАК Шапка0 + |ГДЕ + | Шапка0.Хеш = &Хеш + | И Шапка0.Список = &Список + | И Шапка0.СоставПолей = &СоставПолей + | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И &УточнениеПланаЗапроса"; + Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения.Добавить(ТекстЗапроса); + КонецЕсли; + + // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. + ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, НомерШапки); + + // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступа.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПорцияКлючей + |ИЗ + | &КлючиДоступа КАК КлючиДоступа + | + |ИНДЕКСИРОВАТЬ ПО + | Ссылка"; + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + КонецЕсли; + + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты + |ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка0 + | ПО + | Шапка0.Ссылка = ПорцияКлючей.Ссылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | Ссылка + |ИТОГИ ПО + | Ссылка"; // @query-part + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты + |ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.Шапка КАК Шапка? + | ПО + | Шапка?.Ссылка = ПорцияКлючей.Ссылка + | И &УсловиеНомераШапки + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | Ссылка + |ИТОГИ ПО + | Ссылка"; // @query-part + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеНомераШапки", + СтрШаблон("Шапка%1.НомерСтроки = %1", НомерШапки)); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(СоединенияИПоля.Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + // Условие отбора прав ведущих ключей доступа. + ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВедущихКлючей"); + + // Условие отбора прав ведущих списков. + ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВедущихСписков"); + + // Условие отбора прав по владельцам настроек прав. + ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВладельцевНастроекПрав"); + +КонецПроцедуры + +// Для процедуры ДобавитьЗаполнениеШапкиКлюча. +Процедура ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, НазначениеУсловия) + + // Условие выбора прав ведущих ключей доступа. + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + Если НазначениеУсловия = "ДляВедущихКлючей" + И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 + Или НазначениеУсловия = "ДляВедущихСписков" + И Не СвойстваПоля.ЕстьТипВедущегоСписка + Или НазначениеУсловия = "ДляВладельцевНастроекПрав" + И Не СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда + Продолжить; + КонецЕсли; + + Если НазначениеУсловия = "ДляВедущихСписков" + И СвойстваПоля.ТипыСохраненияЗначений.Количество() > 0 Тогда + + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписковСТипами"); + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | ЕСТЬNULL(ТипыКонфигурации.Ссылка, ЕСТЬNULL(ТипыРасширений.Ссылка, Шапка?.Реквизит?)) + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка? + | ПО + | Шапка?.Ссылка = ПорцияКлючей.Ссылка + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации + | ПО + | Шапка?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовМетаданных) + | И ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовРасширений) + | И ТИПЗНАЧЕНИЯ(ТипыКонфигурации.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений + | ПО + | Шапка?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(ТипыРасширений.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?))"; // @query-part-1 + Иначе + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | Шапка?.Реквизит? + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка? + | ПО + | Шапка?.Ссылка = ПорцияКлючей.Ссылка)"; // @query-part-1 + КонецЕсли; + Если НомерШапки > 0 Тогда + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, + "Справочник.КлючиДоступа КАК Шапка?", "Справочник.КлючиДоступа.Шапка КАК Шапка?"); // @query-part-1, @query-part-2 + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, + "Шапка?.Ссылка = ПорцияКлючей.Ссылка", ТекстСОтступом( + "Шапка?.Ссылка = ПорцияКлючей.Ссылка" + СтрШаблон(" + | И Шапка?.НомерСтроки = %1", НомерШапки), " ")); // @query-part-3 + КонецЕсли; + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Реквизит?", СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + + Если НазначениеУсловия = "ДляВедущихКлючей" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Добавить(УсловиеОтбора); + + ИначеЕсли НазначениеУсловия = "ДляВедущихСписков" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихСписков.Добавить(УсловиеОтбора); + Иначе + Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Добавить(УсловиеОтбора); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьВыборКлючейБезПолейВШапке(Контекст) + + Если Контекст.ГруппыПолей.Получить("Шапка0") <> Неопределено Тогда + Возврат; + КонецЕсли; + + // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступа.Ссылка КАК ТекущаяСсылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Хеш В(&Хеши) + | И КлючиДоступа.Список = &Список + | И КлючиДоступа.СоставПолей = &СоставПолей + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка"; + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Проверка существования ключа доступа перед записью нового ключа. + ТекстЗапроса = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.КлючиДоступа КАК Шапка0 + |ГДЕ + | Шапка0.Хеш = &Хеш + | И Шапка0.Список = &Список + | И Шапка0.СоставПолей = &СоставПолей + | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И &УточнениеПланаЗапроса"; + Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступа.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПорцияКлючей + |ИЗ + | &КлючиДоступа КАК КлючиДоступа + | + |ИНДЕКСИРОВАТЬ ПО + | Ссылка"; + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьЗаполнениеТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча) + + ТаблицыПоГруппам = Контекст.ГруппыДополнительныхТаблиц.ТаблицыПоГруппам; + ГруппаДополнительныхТаблиц = ТаблицыПоГруппам.Получить(НомерТабличнойЧастиКлюча + - (Контекст.КоличествоТабличныхЧастейКлюча - ТаблицыПоГруппам.Количество())); + + ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + ГруппаПолей = Контекст.ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); + + ДобавитьОписаниеТаблицыКлюча(ИмяТабличнойЧастиКлюча, ГруппаПолей, Контекст); + + СоединенияИПоляПоТаблицам = СоединенияИПоляПоТаблицам(ГруппаПолей, Истина, , Истина); + + // Выбор значений из объектов для поиска и создания ключей доступа. + Если ГруппаДополнительныхТаблиц = Неопределено Тогда + ПсевдонимТабличнойЧастиОбъекта = Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча); + Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить("ТекущийСписок"); + Иначе + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ПсевдонимТабличнойЧастиОбъекта); + КонецЕсли; + ПоляВыбора = СоединенияИПоля.Поля; + Соединения = СоединенияИПоля.Соединения; + ПоляУпорядочения = СоединенияИПоля.ПоляУпорядочения; + Реквизиты = СоединенияИПоля.Реквизиты; + Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + Иначе + ИмяТабличнойЧастиОбъекта = СтрЗаменить(ПсевдонимТабличнойЧастиОбъекта, "ТекущийСписок", ""); + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ ИмяТабличнойЧастиОбъекта КАК ПсевдонимТабличнойЧастиОбъекта + | ПО (ПсевдонимТабличнойЧастиОбъекта.Ссылка = ТекущийСписок.Ссылка) #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПсевдонимТабличнойЧастиОбъекта", ПсевдонимТабличнойЧастиОбъекта); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИмяТабличнойЧастиОбъекта", "&ТекущийСписок." + ИмяТабличнойЧастиОбъекта); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); + Иначе + ПоляВыбора = ""; + Соединения = ""; + СоединенияВБазеДанных = ""; + СоединенияВПамяти = ""; + ПоляУпорядочения = ""; + Реквизиты = ""; + Для Каждого ДополнительнаяТаблица Из ГруппаДополнительныхТаблиц Цикл + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ДополнительнаяТаблица.Псевдоним); + ТекущееСоединение = " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3 + Соединения = Соединения + ТекущееСоединение; + Если Контекст.ЭтоСсылочныйТип Тогда + Если ВРег(Контекст.Список) = ВРег(ДополнительнаяТаблица.Таблица) Тогда + ДополнительноеИмя = "&ТекущийСписок"; + ИначеЕсли СтрНачинаетсяС(ВРег(ДополнительнаяТаблица.Таблица), ВРег(Контекст.Список) + ".") Тогда + ДополнительноеИмя = "&ТекущийСписок." + СтрРазделить(ДополнительнаяТаблица.Таблица, ".")[2]; + Иначе + ДополнительноеИмя = ДополнительнаяТаблица.Таблица; + КонецЕсли; + Если ДополнительноеИмя = ДополнительнаяТаблица.Таблица Тогда + СоединенияВБазеДанных = СоединенияВБазеДанных + ТекущееСоединение; + СоединенияВПамяти = СоединенияВПамяти + ТекущееСоединение; + Иначе + СоединенияВБазеДанных = СоединенияВБазеДанных + " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " ") + " + | И НЕ " + ДополнительнаяТаблица.Псевдоним + ".Ссылка В (&СсылкиНаОбъекты)"; // @query-part-1, @query-part-2, @query-part-3, @query-part-5, @query-part-6 + + СоединенияВПамяти = СоединенияВПамяти + " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительноеИмя + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3, + КонецЕсли; + КонецЕсли; + Если СоединенияИПоля = Неопределено Тогда + Продолжить; + КонецЕсли; + Соединения = Соединения + СоединенияИПоля.Соединения; + Если Контекст.ЭтоСсылочныйТип Тогда + СоединенияВБазеДанных = СоединенияВБазеДанных + СоединенияИПоля.Соединения; + СоединенияВПамяти = СоединенияВПамяти + СоединенияИПоля.Соединения; + КонецЕсли; + ПоляВыбора = ПоляВыбора + СоединенияИПоля.Поля; + ПоляУпорядочения = ПоляУпорядочения + СоединенияИПоля.ПоляУпорядочения; + Реквизиты = Реквизиты + СоединенияИПоля.Реквизиты; + КонецЦикла; + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); + + Если СоединенияВПамяти <> СоединенияВБазеДанных Тогда + // АПК:96-выкл - №434 Использование ОБЪЕДИНИТЬ допустимо, так как + // строки не должны повторятся и объем данных небольшой. + ТекстЗапросаВПамяти = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #СоединенияВБазеДанных + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |ОБЪЕДИНИТЬ + | + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #СоединенияВПамяти + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + // АПК:96-вкл. + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, " #СоединенияВБазеДанных", + ТекстСОтступом(СоединенияВБазеДанных, " ")); + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, " #СоединенияВПамяти", + ТекстСОтступом(СоединенияВПамяти, " ")); + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | ТекущийСписок КАК ТекущийСписок #Соединения + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка, &ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляУпорядочения", + Контекст.ОпорныеПоля.ДляУпорядочения + ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); + КонецЕсли; + КонецЕсли; + + Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); + Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить( + ?(ЗначениеЗаполнено(ТекстЗапросаВПамяти), ТекстЗапросаВПамяти, ТекстЗапроса)); + + // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. + ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, , НомерТабличнойЧастиКлюча); + + // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. + ТекстЗапроса = + "ВЫБРАТЬ + | ТабличнаяЧасть?.Ссылка КАК ТекущаяСсылка,&Реквизиты + |ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + |ГДЕ + | ТабличнаяЧасть?.Ссылка.Хеш В(&Хеши) + | И ТабличнаяЧасть?.Ссылка.Список = &Список + | И ТабличнаяЧасть?.Ссылка.СоставПолей = &СоставПолей + | И ТабличнаяЧасть?.Ссылка.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТабличнаяЧасть?.Ссылка.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТабличнаяЧасть?", СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + ТекстЗапроса = + "ВЫБРАТЬ + | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты + |ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ПО + | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка + | + |УПОРЯДОЧИТЬ ПО + | Ссылка + |ИТОГИ ПО + | Ссылка"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТабличнаяЧасть?", СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + // Условие отбора прав ведущих ключей доступа. + ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, + ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВедущихКлючей"); + + // Условие отбора прав ведущих списков. + ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, + ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВедущихСписков"); + + // Условие отбора прав по владельцам настроек прав. + ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, + ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВладельцевНастроекПрав"); + +КонецПроцедуры + +// Для процедуры ДобавитьЗаполнениеТабличнойЧастиКлюча. +Процедура ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, ГруппаПолей, + НомерТабличнойЧастиКлюча, НазначениеУсловия) + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + Если НазначениеУсловия = "ДляВедущихКлючей" + И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 + Или НазначениеУсловия = "ДляВедущихСписков" + И Не СвойстваПоля.ЕстьТипВедущегоСписка + Или НазначениеУсловия = "ДляВладельцевНастроекПрав" + И Не СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда + Продолжить; + КонецЕсли; + + Если НазначениеУсловия = "ДляВедущихСписков" + И СвойстваПоля.ТипыСохраненияЗначений.Количество() > 0 Тогда + + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписковСТипами"); + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | ЕСТЬNULL(ТипыКонфигурации.Ссылка, ЕСТЬNULL(ТипыРасширений.Ссылка, ТабличнаяЧасть?.Реквизит?)) + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ПО + | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации + | ПО + | ТабличнаяЧасть?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовМетаданных) + | И ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовРасширений) + | И ТИПЗНАЧЕНИЯ(ТипыКонфигурации.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений + | ПО + | ТабличнаяЧасть?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(ТипыРасширений.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?))"; // @query-part-1 + Иначе + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | ТабличнаяЧасть?.Реквизит? + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ПО + | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка)"; // @query-part-1 + КонецЕсли; + + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "ТабличнаяЧасть?", + СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Реквизит?", + СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + + Если НазначениеУсловия = "ДляВедущихКлючей" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Добавить(УсловиеОтбора); + + ИначеЕсли НазначениеУсловия = "ДляВедущихСписков" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихСписков.Добавить(УсловиеОтбора); + Иначе + Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Добавить(УсловиеОтбора); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ДобавитьЗаполнениеШапкиКлюча, ДобавитьЗаполнениеТабличнойЧастиКлюча. +Процедура ДобавитьОписаниеТаблицыКлюча(ИмяТаблицыКлюча, ГруппаПолей, Контекст) + + ПоляТаблицыКлюча = Новый Массив; + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + ПоляТаблицыКлюча.Добавить(СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + КонецЦикла; + + Контекст.ТаблицыКлюча.Добавить(ИмяТаблицыКлюча); + Контекст.РеквизитыТаблицКлюча.Вставить(ИмяТаблицыКлюча, ПоляТаблицыКлюча); + +КонецПроцедуры + +// Для процедуры ДобавитьЗаполнениеШапкиКлюча, ДобавитьЗаполнениеТабличнойЧастиКлюча. +Процедура ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, НомерШапки = 0, НомерТабличнойЧастиКлюча = 0) + + УсловиеОтбора = ""; + НомерРеквизита = ?(НомерШапки = 0, 0, 5); + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + НомерРеквизита = НомерРеквизита + 1; + + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + + УсловиеОтбора = + "КлючиДоступа.Ссылка В + | (ВЫБРАТЬ + | Шапка?.Ссылка + | ИЗ + | Справочник.КлючиДоступа КАК Шапка? + | ГДЕ + | Шапка?.Значение? В (&ВедущиеКлючиДоступа))"; // @query-part-1 + + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Значение?", + СтрШаблон("Значение%1", НомерРеквизита)); + + Если НомерШапки > 0 Тогда + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, + "Справочник.КлючиДоступа КАК Шапка?", + "Справочник.КлючиДоступа.Шапка КАК Шапка?"); // @query-part-1, @query-part-2 + КонецЕсли; + + Если НомерТабличнойЧастиКлюча = 0 Тогда + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Иначе + ИмяТабличнойЧасти = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, " КАК", "." + ИмяТабличнойЧасти + " КАК"); // @query-part-1, @query-part-3 + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", ИмяТабличнойЧасти); + КонецЕсли; + + Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Добавить(УсловиеОтбора); + КонецЦикла; + +КонецПроцедуры + +// Для процедур ДобавитьПроверкуШапкиКлюча, ДобавитьПроверкуТабличнойЧастиКлюча. +Функция СоединенияИПоляПоТаблицам(ГруппаПолей, ТабличнаяЧастьКлюча, НомерШапки = 0, ДляВыбораЗначений = Ложь) + + СоединенияИПоляПоТаблицам = Новый Соответствие; + НомерРеквизита = 1 + ?(НомерШапки = 0, 0, 5); + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(СвойстваПоля.ПсевдонимТаблицы); + Если СоединенияИПоля = Неопределено Тогда + СоединенияИПоля = Новый Структура; + СоединенияИПоля.Вставить("Соединения", ""); + СоединенияИПоля.Вставить("Поля", ""); + СоединенияИПоля.Вставить("ПоляУпорядочения", ""); + СоединенияИПоля.Вставить("Реквизиты", ""); + СоединенияИПоляПоТаблицам.Вставить(СвойстваПоля.ПсевдонимТаблицы, СоединенияИПоля); + КонецЕсли; + + Соединения = ""; + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() > 0 Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам? + |ПО (КлючиДоступаКОбъектам?.Объект = #ИмяПоляДляЗапроса)"; // @query-part-1 + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияГруппЗначений.Количество() > 0 Тогда + Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначений? + |ПО (ГруппыЗначений?.ЗначениеДоступа = #ИмяПоляДляЗапроса) + | И (ГруппыЗначений?.ГруппаДанных = 0)"; // @query-part-1 + ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок.ГруппыДоступа КАК ГруппыЗначений? + |ПО (ГруппыЗначений?.Ссылка = #ИмяПоляДляЗапроса)"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияТиповКонфигурации.Количество() > 0 Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации? + |ПО (#ИмяПоляДляЗапроса <> НЕОПРЕДЕЛЕНО) + | И (ТИПЗНАЧЕНИЯ(ТипыКонфигурации?.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса))"; // @query-part-1 + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияТиповРасширений.Количество() > 0 Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений? + |ПО (#ИмяПоляДляЗапроса <> НЕОПРЕДЕЛЕНО) + | И (ТИПЗНАЧЕНИЯ(ТипыРасширений?.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса))"; // @query-part-1 + КонецЕсли; + + Поле = СравнениеПоля(СвойстваПоля); + + Если ДляВыбораЗначений Тогда + Поле = СтрЗаменить(Поле, "Шапка?.Значение? = ", ""); + Поле = СтрЗаменить(Поле, " ", " "); + Позиция = СтрДлина(Символы.ПС + "И ()"); // @query-part-1 + Поле = "," + Символы.ПС + Сред(Поле, Позиция, СтрДлина(Поле) - Позиция) + " КАК " + "Значение?"; // @query-part-2 + + СоединенияИПоля.ПоляУпорядочения = СоединенияИПоля.ПоляУпорядочения + + ", " + СтрШаблон("Значение%1", НомерРеквизита); + + СоединенияИПоля.Реквизиты = СоединенияИПоля.Реквизиты + СтрШаблон(", + |Шапка?.Значение%1 КАК Значение%1", НомерРеквизита); // @query-part-1 + КонецЕсли; + + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "Значение?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ГруппыЗначений?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "КлючиДоступаКОбъектам?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ТипыКонфигурации?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ТипыРасширений?"); + + Соединения = СтрЗаменить(Соединения, "#ИмяПоляДляЗапроса", СвойстваПоля.ИмяПоляДляЗапроса); + Поле = СтрЗаменить(Поле, "#ИмяПоляДляЗапроса", СвойстваПоля.ИмяПоляДляЗапроса); + + Если ТабличнаяЧастьКлюча Тогда + Поле = СтрЗаменить(Поле, "Шапка?", "ТабличнаяЧасть?"); + СоединенияИПоля.Реквизиты = СтрЗаменить(СоединенияИПоля.Реквизиты, "Шапка?", "ТабличнаяЧасть?"); + КонецЕсли; + + СоединенияИПоля.Соединения = СоединенияИПоля.Соединения + Соединения; + СоединенияИПоля.Поля = СоединенияИПоля.Поля + Поле; + НомерРеквизита = НомерРеквизита + 1; + КонецЦикла; + + Возврат СоединенияИПоляПоТаблицам; + +КонецФункции + +// Для функции СоединенияИПоляПоТаблицам. +Функция СравнениеПоля(СвойстваПоля) + + КоличествоТиповПоля = СвойстваПоля.ТипКонечногоПоля.Типы().Количество(); + + БезЗначенияНеопределено = КоличествоТиповПоля = 1; + Если СвойстваПоля.Свойство("БезЗначенияNull") Тогда + БезЗначенияNull = СвойстваПоля.БезЗначенияNull; + Иначе + БезЗначенияNull = БезЗначенияNull(СвойстваПоля); + КонецЕсли; + + БезУточненияНеопределено = Не СвойстваПоля.ЕстьУточнениеНеопределено Или БезЗначенияНеопределено; + БезУточненияNull = Не СвойстваПоля.ЕстьУточнениеNull Или БезЗначенияNull; + + // Сохранение только ключей доступа. + Если СвойстваПоля.ТипыСохраненияПустойСсылки.Количество() = 0 + И БезУточненияНеопределено + И БезУточненияNull + И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = КоличествоТиповПоля Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(КлючиДоступаКОбъектам?.#КлючДоступаПользователейКОбъекту, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + КонецЕсли; + + // Сохранение только групп значений доступа. + Если СвойстваПоля.ТипыСохраненияПустойСсылки.Количество() = 0 + И БезУточненияНеопределено + И БезУточненияNull + И СвойстваПоля.ТипыСохраненияГруппЗначений.Количество() = КоличествоТиповПоля Тогда + + Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаЗначенийДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + Иначе + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ТекущийСписок.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + // Сохранение только значений. + Если Не ЕстьПростойТип(СвойстваПоля.ТипКонечногоПоля) + И КоличествоТиповПоля = 1 + И СвойстваПоля.ТипыСохраненияЗначений.Количество() = КоличествоТиповПоля Тогда + + Если БезЗначенияNull Тогда + Возврат " + |И (Шапка?.Значение? = #ИмяПоляДляЗапроса)"; // @query-part-1 + Иначе + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(#ИмяПоляДляЗапроса, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + // Сохранение одного ссылочного типа. + Если БезУточненияNull + И КоличествоТиповПоля = 1 + И СвойстваПоля.ТипыСохраненияТипов.Количество() = КоличествоТиповПоля + И СвойстваПоля.ТипыСохраненияТиповПростых.Количество() = 0 Тогда + + Если СвойстваПоля.ТипыСохраненияТиповРасширений.Количество() = 0 Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ТипыКонфигурации?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)))"; // @query-part-1 + ИначеЕсли СвойстваПоля.ТипыСохраненияТиповКонфигурации.Количество() = 0 Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ТипыРасширений?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовРасширений.ПустаяСсылка)))"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + // Сохранение одного простого типа. + Если БезУточненияNull + И КоличествоТиповПоля = 1 + И СвойстваПоля.ТипыСохраненияТиповПростых.Количество() = 1 Тогда + + Возврат " + |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный))"; // @query-part-1 + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Количество() = КоличествоТиповПоля Тогда + Возврат " + |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипЗапрещенный))"; // @query-part-1 + КонецЕсли; + + // Сохранение только значения ТипРазрешенный. + Если СвойстваПоля.ТипыСохраненияТипаРазрешенный.Количество() = КоличествоТиповПоля Тогда + Возврат " + |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный))"; // @query-part-1 + КонецЕсли; + + СравнениеПоля = " + |И (ВЫБОР + | #СодержаниеВыбора + |КОНЕЦ)"; // @query-part-1 + СодержаниеВыбора = ""; + + СохранениеЗначенияБулево = СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип("Булево")) <> Неопределено; + + Если Не БезЗначенияNull + И Не (СохранениеЗначенияБулево И КоличествоТиповПоля = 1) Тогда + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса ЕСТЬ NULL + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)"; // @query-part-1 + КонецЕсли; + Если КоличествоТиповПоля > 1 Тогда + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса = НЕОПРЕДЕЛЕНО + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Неопределено)"; // @query-part-1 + КонецЕсли; + Если СохранениеЗначенияБулево Тогда + Если КоличествоТиповПоля > 1 Тогда + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Истина) + |КОГДА НЕ #ИмяПоляДляЗапроса + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Ложь)"; // @query-part-1 + Иначе + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Истина) + |ИНАЧЕ Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Ложь)"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + ПроверкиПоТипам = Новый СписокЗначений; + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповПростых, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный)"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияКлючейДоступа, + "Шапка?.Значение? = ЕСТЬNULL(КлючиДоступаКОбъектам?.#КлючДоступаПользователейКОбъекту, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + + Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, + "Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаЗначенийДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, + "Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + Иначе + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, + "Шапка?.Значение? = ЕСТЬNULL(ТекущийСписок.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + КонецЕсли; + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияЗначений, + "Шапка?.Значение? = #ИмяПоляДляЗапроса", , СохранениеЗначенияБулево); + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияПустойСсылки, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ПустаяСсылкаЛюбогоТипа)", + "ЭтоПроверкаПустойСсылки"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповКонфигурации, + "Шапка?.Значение? = ЕСТЬNULL(ТипыКонфигурации?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка))"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповРасширений, + "Шапка?.Значение? = ЕСТЬNULL(ТипыРасширений?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовРасширений.ПустаяСсылка))"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТипаЗапрещенный, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипЗапрещенный)"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТипаРазрешенный, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный)"); // @query-part-1 + + ПроверкиПоТипам.СортироватьПоПредставлению(); + + Для Каждого ПроверкаПоТипам Из ПроверкиПоТипам Цикл + Если ПроверкаПоТипам.Значение.Типы.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + Если ПроверкиПоТипам.Индекс(ПроверкаПоТипам) < ПроверкиПоТипам.Количество() - 1 Тогда + ПроверкаТипов = ""; + Для Каждого Тип Из ПроверкаПоТипам.Значение.Типы Цикл + Если ЭтоПростойТип(Тип) Тогда + ИмяТипа = Строка(Тип); + Иначе + ИмяТипа = Метаданные.НайтиПоТипу(Тип).ПолноеИмя(); + КонецЕсли; + Если ПроверкаТипов <> "" Тогда + ПроверкаТипов = ПроверкаТипов + " + | ИЛИ "; + КонецЕсли; + ШаблонПроверки = ?(ПроверкаПоТипам.Значение.Свойство("ЭтоПроверкаПустойСсылки"), + "#ИмяПоляДляЗапроса = ЗНАЧЕНИЕ(#ИмяТипа.ПустаяСсылка)", + "ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса) = ТИП(#ИмяТипа)"); // @query-part-3 + ПроверкаТипов = ПроверкаТипов + СтрЗаменить(ШаблонПроверки, "#ИмяТипа", ИмяТипа); + КонецЦикла; + Проверка = " + |КОГДА #ПроверкаТипов + | ТОГДА #Проверка"; // @query-part-1 + Проверка = СтрЗаменить(Проверка, "#ПроверкаТипов", ПроверкаТипов); + Иначе + Проверка = " + |ИНАЧЕ #Проверка"; // @query-part-1 + КонецЕсли; + Проверка = СтрЗаменить(Проверка, "#Проверка", ПроверкаПоТипам.Значение.Проверка); + СодержаниеВыбора = СодержаниеВыбора + Проверка; + КонецЦикла; + + Возврат СтрЗаменить(СравнениеПоля, "#СодержаниеВыбора", ТекстСОтступом(СокрЛ(СодержаниеВыбора), " ")); + +КонецФункции + +// Для функции СравнениеПоля. +Процедура ДобавитьПроверкуПоТипам(ПроверкиПоТипам, ИсходныеТипы, Проверка, ДополнительноеСвойство = "", ПропуститьБулево = Ложь) + + Типы = Новый Массив; + Для Каждого Тип Из ИсходныеТипы Цикл + Если ПропуститьБулево И Тип = Тип("Булево") Тогда + Продолжить; + КонецЕсли; + Типы.Добавить(Тип); + КонецЦикла; + + Если Типы.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Структура = Новый Структура("Типы, Проверка", Типы, Проверка); + ПроверкиПоТипам.Добавить(Структура, Формат(Структура.Типы.Количество(), "ЧЦ=10; ЧВН=; ЧГ=")); + + Если ДополнительноеСвойство = "" Тогда + Возврат; + КонецЕсли; + + Структура.Вставить(ДополнительноеСвойство); + +КонецПроцедуры + +// Для функции ДобавитьПроверкуШапкиКлюча. +Процедура ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, Псевдоним) + + ПсевдонимСНомером = СтрЗаменить(Псевдоним, "?", НомерРеквизита); + + Соединения = СтрЗаменить(Соединения, Псевдоним, ПсевдонимСНомером); + Поле = СтрЗаменить(Поле, Псевдоним, ПсевдонимСНомером); + +КонецПроцедуры + +// Для функций ДобавитьПроверкуШапкиКлюча, СравнениеПоля. +Функция ТекстСОтступом(Текст, Отступ) + + Возврат СтрЗаменить(Текст, Символы.ПС, Символы.ПС + Отступ); + +КонецФункции + +// Для функции СравнениеПоля, ДобавитьОпорноеПоле. +Функция ЕстьПростойТип(ОписаниеТипов) + + Возврат ОписаниеТипов.СодержитТип(Тип("Булево")) + Или ОписаниеТипов.СодержитТип(Тип("Дата")) + Или ОписаниеТипов.СодержитТип(Тип("Строка")) + Или ОписаниеТипов.СодержитТип(Тип("Число")) + Или ОписаниеТипов.СодержитТип(Тип("УникальныйИдентификатор")) + Или ОписаниеТипов.СодержитТип(Тип("ХранилищеЗначения")); + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область ПреобразованиеТекстовОграниченийВСтруктуры + +// См. также УправлениеДоступом.РазобранноеОграничение. +// +// Возвращаемое значение: +// Структура: +// * ПоляТаблиц - см. НовыеПоляТаблиц +// * ВнутренниеДанные - см. НовыеВнутренниеДанные +// +Функция РазобранноеОграничение(ОсновнаяТаблица, ТекстОграничения) Экспорт + + ВнутренниеДанные = НовыеВнутренниеДанные(); + ВнутренниеДанные.Вставить("ОсновнаяТаблица", ОсновнаяТаблица); + ВнутренниеДанные.Вставить("ТекстОграничения", СокрЛП(ТекстОграничения)); + + ВнутренниеДанные.Вставить("СинтаксисЯзыка", УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка()); + ВнутренниеДанные.Вставить("ПоляТаблиц", НовыеПоляТаблиц()); + ВнутренниеДанные.Вставить("Псевдонимы", Новый Соответствие); + + ВнутренниеДанные.Вставить("ПоляКлючаДоступа", Новый Массив); + + ВнутренниеДанные.Вставить("ТаблицаНаборовСимволов", ТаблицаНаборовСимволов(ВнутренниеДанные)); + ВнутренниеДанные.Вставить("ЧастиОграничения", ЧастиОграничения(ВнутренниеДанные)); + + Результат = Новый Структура; + Результат.Вставить("ВнутренниеДанные", ВнутренниеДанные); + Результат.Вставить("ПоляТаблиц", ВнутренниеДанные.ПоляТаблиц); + + Возврат Результат; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ОсновнаяТаблица - Строка - таблица, которая ограничивается. +// * ТекстОграничения - Строка +// * СинтаксисЯзыка - см. СинтаксисЯзыка +// * ПоляТаблиц - см. НовыеПоляТаблиц +// * Псевдонимы - Соответствие +// * ПоляКлючаДоступа - Массив из см. НовоеПолеКлючаДоступа +// * ТаблицаНаборовСимволов - см. ТаблицаНаборовСимволов +// * ЧастиОграничения - см. ЧастиОграничения +// +Функция НовыеВнутренниеДанные() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ОсновнаяТаблица - Строка - таблица, которая ограничивается. +// * ТекстОграничения - Строка +// * СинтаксисЯзыка - см. СинтаксисЯзыка +// * ПоляТаблиц - см. НовыеПоляТаблиц +// * Псевдонимы - Соответствие +// * ПоляКлючаДоступа - Массив из см. НовоеПолеКлючаДоступа +// * ТаблицаНаборовСимволов - см. ТаблицаНаборовСимволов +// * ЧастиОграничения - см. ЧастиОграничения +// * ЭтоУсловиеСоединения - Булево +// * ЭтоУсловиеКогда - Булево +// * ЭтоЗначениеТогдаИначе - Булево +// * КорневойУзел - см. ОписаниеУзла +// +Функция РасширенныеВнутренниеДанные(ВнутренниеДанные) + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ВнутренниеДанные); + Возврат Новый Структура(ФиксированныйКонтекст); + +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - имя коллекции объектов метаданных, например, Справочники. +// * Значение - см. НовыйСоставКоллекции +// +Функция НовыеПоляТаблиц() + + Возврат Новый Соответствие; + +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - имя таблицы (объекта метаданных) в верхнем регистре. +// * Значение - см. НовыеСвойстваТаблицы +// +Функция НовыйСоставКоллекции() + + Возврат Новый Соответствие; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ТаблицаСуществует - Булево - Ложь (для заполнения Истина, если существует). +// * ЭтоОсновнаяТаблица - Булево +// * Источники - Массив +// * ПервоеПоле - Неопределено +// * Поля - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя реквизита в верхнем регистре, в том числе через точки, +// например, "ВЛАДЕЛЕЦ.ОРГАНИЗАЦИЯ", "ТОВАРЫ.НОМЕНКЛАТУРА". +// ** Значение - см. НовыеСвойстваПоля +// * Предопределенные - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя предопределенного элемента. +// ** Значение - см. НовыеСвойстваПредопределенного +// * Расширения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя третьего имени таблицы, например, имя табличной части. +// ** Значение - см. НовыеСвойстваРасширения +// +Функция НовыеСвойстваТаблицы() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПолеСОшибкой - Число - 0 (для заполнения, если поле содержит ошибку, +// если 1, то ошибка в имени первой части поля, +// если 2, то ошибка в имени второй части поля, т.е. после первой точки). +// * ВидОшибки - Строка - "НеНайдено", "ТабличнаяЧастьБезПоля", +// "ТабличнаяЧастьПослеТочки". +// * Коллекция - Строка - пустая строка (для заполнения, если первая часть +// поля существует, т.е. часть поля до первой точки). Варианты: "Реквизиты", +// "ТабличныеЧасти", "СтандартныеРеквизиты", "СтандартныеТабличныеЧасти", +// "Измерения", "Ресурсы", "Графы", "ПризнакиУчета", "ПризнакиУчетаСубконто", +// "РеквизитыАдресации", "СпециальныеПоля". Специальные поля - это +// "Значение" - у таблиц "Константа.*", +// "Регистратор" и "Период" - у таблиц "Последовательность.*", +// "ОбъектПерерасчета", "ВидРасчета" у таблиц "РегистрРасчета.<Имя>.<ИмяПерерасчета>". +// Поля после первой точки могут относится только к коллекциям: "Реквизиты", +// "СтандартныеРеквизиты", "ПризнакиУчета", "РеквизитыАдресации". Для этих +// частей имени поля не требуется уточнять коллекцию. +// * СодержитТипы - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя ссылочной таблицы в верхнем регистре. +// ** Значение - Структура: +// *** ИмяТипа - Строка - имя типа, наличие которого нужно проверить. +// *** СодержитТип - Булево - Ложь (для заполнения Истина, +// если у поля последнего поля есть тип). +// * ПервыйИсточник - Структура: +// ** Ключ - СтрокаТаблицыЗначений - строка-источник первого поля. +// ** Значение - Строка - таблица +// +Функция НовыеСвойстваПоля() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ИмяСуществует - Булево - Ложь (для заполнения Истина, если предопределенный есть). +// * Источники - Массив +// +Функция НовыеСвойстваПредопределенного() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ТаблицаСуществует - Булево - Ложь (для заполнения Истина, если существует). +// * Источники - Массив +// * ПервоеПоле - Неопределено +// * Поля - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя реквизита в верхнем регистре, в том числе через точки, +// например, "ВЛАДЕЛЕЦ.ОРГАНИЗАЦИЯ", "ТОВАРЫ.НОМЕНКЛАТУРА". +// ** Значение - см. НовыеСвойстваПоля +// +Функция НовыеСвойстваРасширения() + + Возврат Новый Структура; + +КонецФункции + + +// Смотри также УправлениеДоступом.СтруктураОграничения +// +// Параметры: +// РазобранноеОграничение - см. РазобранноеОграничение +// +// Возвращаемое значение: +// Структура: +// * ОписаниеОшибок - см. ОписаниеОшибок +// * ДополнительныеТаблицы - Массив из см. НовоеОписаниеСоединения +// * ПсевдонимОсновнойТаблицы - Строка - заполнено, если указаны дополнительные таблицы. +// * ОграничениеЧтения - см. ОписаниеУзла +// * ОграничениеИзменения - см. ОписаниеУзла +// +Функция СтруктураОграничения(РазобранноеОграничение) Экспорт + + ВнутренниеДанные = РазобранноеОграничение.ВнутренниеДанные; + + ОтметитьНекорректныеИменаТаблицПолейИТиповПолей(РазобранноеОграничение.ПоляТаблиц, + ВнутренниеДанные); + + // Заполнение найденных ошибок. + ОписаниеОшибок = ОписаниеОшибок(); + + Таблица = ВнутренниеДанные.ТаблицаНаборовСимволов; + ОтборСтрокБезОшибок = Новый Структура("ТекстОшибки", ""); + Если Таблица.Количество() <> Таблица.НайтиСтроки(ОтборСтрокБезОшибок).Количество() Тогда + ОписаниеОшибок.ЕстьОшибки = Истина; + ТребуетсяДополнение = Ложь; + ДлинаНомераСтроки = СтрДлина(Формат(СтрЧислоСтрок(ВнутренниеДанные.ТекстОграничения), "ЧГ=")); + Для Каждого Строка Из Таблица Цикл + Если Строка.ТекстОшибки = "" Тогда + Продолжить; + КонецЕсли; + ДобавитьОшибку(Строка, ОписаниеОшибок, ВнутренниеДанные, ДлинаНомераСтроки); + Если Строка.ПозицияОшибки = -1 Тогда + ТребуетсяДополнение = Истина; + КонецЕсли; + КонецЦикла; + ОписаниеОшибок.Ограничение = ПронумерованныйТекстОграниченияСОтметкамиОшибок( + ВнутренниеДанные.ТекстОграничения, ОписаниеОшибок.Ошибки, ДлинаНомераСтроки); + Если ТребуетсяДополнение Тогда + ОписаниеОшибок.Дополнение = ОписаниеДопустимыхШаблонов(); + КонецЕсли; + КонецЕсли; + + ЧастиОграничения = ВнутренниеДанные.ЧастиОграничения; + + СтруктураОграничения = Новый Структура; + СтруктураОграничения.Вставить("ОписаниеОшибок", ОписаниеОшибок); + СтруктураОграничения.Вставить("ДополнительныеТаблицы", ЧастиОграничения.ДополнительныеТаблицы); + СтруктураОграничения.Вставить("ПсевдонимОсновнойТаблицы", ЧастиОграничения.ПсевдонимОсновнойТаблицы); + СтруктураОграничения.Вставить("ОграничениеЧтения", ЧастиОграничения.ОграничениеЧтения); + СтруктураОграничения.Вставить("ОграничениеИзменения", ЧастиОграничения.ОграничениеИзменения); + + // Дополнительные сведения для внутреннего использования. + ИмяТипаТаблицы = СтрРазделить(ВнутренниеДанные.ОсновнаяТаблица, ".")[0]; + СвойстваТипаТаблиц = ВнутренниеДанные.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + + НовыеВнутренниеДанные = Новый Структура; + НовыеВнутренниеДанные.Вставить("ПоляКлючаДоступа", ВнутренниеДанные.ПоляКлючаДоступа); + НовыеВнутренниеДанные.Вставить("ЭтоСсылочныйТип", СвойстваТипаТаблиц.ЭтоСсылочныйТип); + НовыеВнутренниеДанные.Вставить("ИмяКоллекцииТипа", СвойстваТипаТаблиц.ИмяКоллекции); + НовыеВнутренниеДанные.Вставить("ТипыТаблицПоИменам", ВнутренниеДанные.СинтаксисЯзыка.ТипыТаблиц.ПоИменам); + + СтруктураОграничения.Вставить("ВнутренниеДанные", НовыеВнутренниеДанные); + + Для Каждого Строка Из ВнутренниеДанные.ТаблицаНаборовСимволов Цикл + Строка.Строки.Очистить(); + Строка.КонечнаяСтрока = Неопределено; + КонецЦикла; + ВнутренниеДанные.ТаблицаНаборовСимволов.Очистить(); + ВнутренниеДанные.ЧастиОграничения.Очистить(); + ВнутренниеДанные.Очистить(); + + Возврат СтруктураОграничения; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ЕстьОшибки - Булево +// * ТекстОшибок - Строка +// * Ограничение - Строка +// * Ошибки - Массив из см. СвойстваОшибки +// * Дополнение - Строка +// +Функция ОписаниеОшибок() + + ОписаниеОшибок = Новый Структура; + ОписаниеОшибок.Вставить("ЕстьОшибки", Ложь); + ОписаниеОшибок.Вставить("ТекстОшибок", ""); + ОписаниеОшибок.Вставить("Ограничение", ""); + ОписаниеОшибок.Вставить("Ошибки", Новый Массив); + ОписаниеОшибок.Вставить("Дополнение", ""); + + Возврат ОписаниеОшибок; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * НомерСтроки - Число - номер строки текста ограничения, в которой найдена ошибка. +// * ПозицияВСтроке - Число - позиция в строке текста ограничения, в которой найдена ошибка. +// * ТекстОшибки - Строка - описание ошибки. +// * СтрокаОшибки - Строка - строка текста ограничения, в которой найдена ошибка. +// +Функция СвойстваОшибки() + + Возврат Новый Структура; + +КонецФункции + +// Формирует полный текст ошибок описания ограничения доступа с дополнением, +// который можно указать, как текст для вызова исключения. +// +// Параметры: +// ПолноеИмя - Строка - полное имя таблицы списка. +// ОписаниеОшибок - Структура - значение возвращаемое функцией СтруктураОграничения. +// ДляВнешнихПользователей - Булево - если передать Истина, тогда текст ошибки будет содержать +// назначение ограничения для внешних пользователей. +// +// Возвращаемое значение: +// Строка - текст для вызова исключения. +// +Функция ТекстОшибокДляВызоваИсключения(ПолноеИмя, ОписаниеОшибок, ДляВнешнихПользователей, ВМодулеМенеджера) + + Если Не ОписаниеОшибок.ЕстьОшибки Тогда + Возврат ""; + КонецЕсли; + + Если ОписаниеОшибок.Ошибки.Количество() = 1 Тогда + Уточнение = ""; + Если ВМодулеМенеджера = Неопределено Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"":'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"":'"); + КонецЕсли; + ИначеЕсли ВМодулеМенеджера Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + КонецЕсли; + Уточнение = "ПриЗаполненииОграниченияДоступа"; + Иначе + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + КонецЕсли; + Уточнение = "УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа"; + КонецЕсли; + Иначе + Если ВМодулеМенеджера = Неопределено Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"":'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"":'"); + КонецЕсли; + ИначеЕсли ВМодулеМенеджера Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + КонецЕсли; + Уточнение = "ПриЗаполненииОграниченияДоступа"; + Иначе + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + КонецЕсли; + Уточнение = "УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа"; + КонецЕсли; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ЗаголовокОшибки, ПолноеИмя, Уточнение); + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.ТекстОшибок; + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.Ограничение; + + Если ЗначениеЗаполнено(ОписаниеОшибок.Дополнение) Тогда + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.Дополнение; + КонецЕсли; + + Возврат Символы.ПС + ТекстОшибки + Символы.ПС; + +КонецФункции + +// Для функции СтруктураОграничения. +Процедура ДобавитьОшибку(Строка, ОписаниеОшибок, ВнутренниеДанные, ДлинаНомераСтроки) + + ПозицияВТексте = Строка.Позиция; + ПозицияОшибкиВКонцеСтроки = Ложь; + ТекстОграничения = ВнутренниеДанные.ТекстОграничения; + + Если Строка.ПозицияОшибки > 0 Тогда + ПозицияВТексте = ПозицияВТексте + Строка.ПозицияОшибки; + Если Строка.ПозицияОшибки = СтрДлина(Строка.Символы) Тогда + ПозицияВТексте = ПозицияВТексте - 1; + ПозицияОшибкиВКонцеСтроки = Истина; + КонецЕсли; + ИначеЕсли Строка.Позиция > СтрДлина(ТекстОграничения) Тогда + ПозицияВТексте = ПозицияВТексте - 1; + ПозицияОшибкиВКонцеСтроки = Истина; + КонецЕсли; + + Координаты = КоординатыПозицииВТексте(ТекстОграничения, ПозицияВТексте); + Координаты.ПозицияВСтроке = Координаты.ПозицияВСтроке + ?(ПозицияОшибкиВКонцеСтроки, 1, 0); + + СтрокаОшибки = СтрПолучитьСтроку(ТекстОграничения, Координаты.НомерСтроки); + СтрокаОшибки = Лев(СтрокаОшибки, Координаты.ПозицияВСтроке - 1) + + "<>" + Сред(СтрокаОшибки, Координаты.ПозицияВСтроке); + + Ошибка = СвойстваОшибки(); + Ошибка.Вставить("НомерСтроки", Координаты.НомерСтроки); + Ошибка.Вставить("ПозицияВСтроке", Координаты.ПозицияВСтроке); + Ошибка.Вставить("ТекстОшибки", Строка.ТекстОшибки); + Ошибка.Вставить("СтрокаОшибки", СтрокаОшибки); + + ОписаниеОшибок.Ошибки.Добавить(Ошибка); + + Если ЗначениеЗаполнено(ОписаниеОшибок.ТекстОшибок) Тогда + ОписаниеОшибок.ТекстОшибок = ОписаниеОшибок.ТекстОшибок + Символы.ПС + Символы.ПС; + КонецЕсли; + + ОписаниеОшибок.ТекстОшибок = ОписаниеОшибок.ТекстОшибок + + "{(" + Формат(Ошибка.НомерСтроки, "ЧЦ=" + ДлинаНомераСтроки + "; ЧВН=; ЧГ=") + + ", " + Формат(Ошибка.ПозицияВСтроке, "ЧГ=") + ")}:" + + " " + Ошибка.ТекстОшибки + Символы.ПС + Ошибка.СтрокаОшибки; + +КонецПроцедуры + +// Для функции СтруктураОграничения. +Функция ПронумерованныйТекстОграниченияСОтметкамиОшибок(ТекстОграничения, Ошибки, ДлинаНомераСтроки) + + КоличествоСтрок = СтрЧислоСтрок(ТекстОграничения); + СтрокиТекстаОграничений = Новый Массив; + + Для НомерСтроки = 1 По КоличествоСтрок Цикл + Строка = СтрПолучитьСтроку(ТекстОграничения, НомерСтроки); + СтрокиТекстаОграничений.Добавить(Строка); + КонецЦикла; + + Индекс = Ошибки.Количество() - 1; + Пока Индекс >= 0 Цикл + Ошибка = Ошибки[Индекс]; + Строка = СтрокиТекстаОграничений[Ошибка.НомерСтроки - 1]; + СтрокиТекстаОграничений[Ошибка.НомерСтроки - 1] = Лев(Строка, Ошибка.ПозицияВСтроке - 1) + + "<>" + Сред(Строка, Ошибка.ПозицияВСтроке); + Индекс = Индекс - 1; + КонецЦикла; + + Текст = ""; + НомерСтроки = 1; + + Для Каждого Строка Из СтрокиТекстаОграничений Цикл + Текст = Текст + ?(Текст = "", "", Символы.ПС) + + ?(СтрНайти(Строка, "<>") > 0, "*", " ") + + " " + Формат(НомерСтроки, "ЧЦ=" + ДлинаНомераСтроки + "; ЧВН=; ЧГ=") + " " + Строка; + НомерСтроки = НомерСтроки + 1; + КонецЦикла; + + Возврат Текст; + +КонецФункции + +// Для функции СтруктураОграничения. +Функция ОписаниеДопустимыхШаблонов() + + Если ВариантВстроенногоЯзыкаРусский() Тогда + Шаблон1 = + " РазрешитьЧтениеИзменение + | ГДЕ ..."; // @Non-NLS + + Шаблон2 = + " РазрешитьЧтение + | ГДЕ ... + | ; + | РазрешитьИзменениеЕслиРазрешеноЧтение + | ГДЕ ..."; // @Non-NLS + + Шаблон3 = + " ПрисоединитьДополнительныеТаблицы + | ЭтотСписок КАК <Псевдоним> + | ЛЕВОЕ СОЕДИНЕНИЕ ... + | ; + | РазрешитьЧтение + | ГДЕ ... + | ; + | РазрешитьИзменениеЕслиРазрешеноЧтение + | ГДЕ ..."; // @Non-NLS + Иначе + Шаблон1 = + " AllowReadWrite + | WHERE ..."; + + Шаблон2 = + " AllowRead + | WHERE ... + | ; + | AllowWriteIfAllowRead + | WHERE ..."; + + Шаблон3 = + " AttachAdditionalTables + | LIST AS + | LEFT/INNER JOIN ... + | ; + | AllowRead + | WHERE ... + | ; + | AllowWriteIfAllowRead + | WHERE ..."; + КонецЕсли; + + Описание = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ограничение может состоять из 1-3 частей в одном из 4 вариантов: + |1) одинаковое ограничение чтения и изменения: + |%1 + |2) разные ограничения чтения и изменения: + |%2 + |3) любой из вариантов выше с дополнительными таблицами, например: + |%3'"), + Шаблон1, Шаблон2, Шаблон3); + + Возврат Описание; + +КонецФункции + +// Для процедуры ДобавитьОшибку. +Функция КоординатыПозицииВТексте(Текст, ПозицияВТексте) + + Результат = Новый Структура; + Результат.Вставить("НомерСтроки", 0); + Результат.Вставить("ПозицияВСтроке", 0); + + КоличествоСтрок = СтрЧислоСтрок(Текст); + ПозицияНачалаСтроки = 1; + Для НомерСтроки = 1 По КоличествоСтрок Цикл + ДлинаТекущейСтроки = СтрДлина(СтрПолучитьСтроку(Текст, НомерСтроки)); + Если ПозицияВТексте < ПозицияНачалаСтроки + ДлинаТекущейСтроки Тогда + Прервать; + КонецЕсли; + ПозицияНачалаСтроки = ПозицияНачалаСтроки + ДлинаТекущейСтроки + 1; + КонецЦикла; + + Результат.НомерСтроки = НомерСтроки; + Результат.ПозицияВСтроке = ПозицияВТексте - ПозицияНачалаСтроки + 1; + + Возврат Результат; + +КонецФункции + +#Область ЛексическийАнализ + +// Для функции РазобранноеОграничение. +// Раскладывает текст в таблицу наборов символов, в которых: +// - нет символов отступа (пробелов, табуляций, переводов строки); +// - выделены символы произвольных строк и чисел; +// - определены ключевые слова и операции; +// - проверен формат имен и чисел; +// - добавлены ошибки с описанием. +// +// Параметры: +// ТекстОграничения - Строка - текст ограничения доступа. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Символы - Строка - символ, пара символов или слово. +// * Позиция - Число - позиция символов в тексте ограничения. +// * Вид - Строка - "КлючевоеСлово", "Операция", "Имя", "Разделитель", +// "Число", "ПроизвольнаяСтрока", "НедопустимыйСимвол", "Конец". +// * Тип - Строка - тип для для видов "КлючевоеСлово" и "Операция". +// * Приоритет - Число - приоритет для видов "КлючевоеСлово" и "Операция". +// * Уточнение - Число - числовое значение для вида "Число". +// - Строка - имя для вида "КлючевоеСлово", строка символов для вида "ПроизвольнаяСтрока". +// * ЭтоРезерв - Булево - если Истина, значит это зарезервированная операция или ключевое слово. +// * ПозицияОшибки - Число - позиция ошибки в тексте ограничения, если текст ошибки не пустой. +// * ТекстОшибки - Строка - текст ошибки, если найдена ошибка. +// +Функция ТаблицаНаборовСимволов(ВнутренниеДанные) + + ТаблицаНаборовСимволов = Новый ТаблицаЗначений; + ТаблицаНаборовСимволов.Колонки.Добавить("Символы", Новый ОписаниеТипов("Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("Позиция", Новый ОписаниеТипов("Число")); + ТаблицаНаборовСимволов.Колонки.Добавить("Вид", Новый ОписаниеТипов("Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("Приоритет", Новый ОписаниеТипов("Число")); + ТаблицаНаборовСимволов.Колонки.Добавить("Уточнение", Новый ОписаниеТипов("Число, Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("ЭтоРезерв", Новый ОписаниеТипов("Булево")); + ТаблицаНаборовСимволов.Колонки.Добавить("ПозицияОшибки", Новый ОписаниеТипов("Число")); + ТаблицаНаборовСимволов.Колонки.Добавить("ТекстОшибки", Новый ОписаниеТипов("Строка")); + + ТекстОграничения = ВнутренниеДанные.ТекстОграничения; + + Если Не ЗначениеЗаполнено(ТекстОграничения) Тогда + Возврат ТаблицаНаборовСимволов; + КонецЕсли; + + ДлинаТекстаОграничения = СтрДлина(ТекстОграничения); + + СинтаксисЯзыка = ВнутренниеДанные.СинтаксисЯзыка; + СимволыЯзыка = СинтаксисЯзыка.СимволыЯзыка; + + ВидНабораСимволов = ""; // Слово, ПроизвольнаяСтрока, Операция. + ПозицияНабораСимволов = 0; + НаборСимволов = Новый Массив; + СтрокаТаблицы = Неопределено; + + Для НомерСимвола = 1 По ДлинаТекстаОграничения Цикл + Символ = Сред(ТекстОграничения, НомерСимвола, 1); + ТипСимвола = СимволыЯзыка.Получить(Символ); + // Сначала обработка символов слов, так как они встречаются наиболее часто. + Если ТипСимвола = "СимволСлова" И ВидНабораСимволов = "Слово" Тогда + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + // Обработка произвольной строки символов. + Если ВидНабораСимволов = "ПроизвольнаяСтрока" Тогда + Если ТипСимвола = "ОграничительСтроки" Тогда + Если Сред(ТекстОграничения, НомерСимвола + 1, 1) <> Символ Тогда + СтрокаТаблицы.Уточнение = СтрСоединить(НаборСимволов); + СтрокаТаблицы.Позиция = ПозицияНабораСимволов; + НаборСимволов = Новый Массив; + ВидНабораСимволов = ""; + Продолжить; + Иначе + НомерСимвола = НомерСимвола + 1; + КонецЕсли; + КонецЕсли; + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + Если ВидНабораСимволов = "Слово" Тогда + // Вначале цикла уже обработан случай, когда ТипСимвола = "СимволСлова", + // для остальных типов символов слово завершено и его нужно добавить в дерево. + ВидНабораСимволов = ""; + ДобавитьСловоВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + НаборСимволов = Новый Массив; + КонецЕсли; + // Обработка набора составных разделителей. + Если ВидНабораСимволов = "Операция" Тогда + Если ТипСимвола = "СимволОперации" Тогда + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + ВидНабораСимволов = ""; + ДобавитьОперациюВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + НаборСимволов = Новый Массив; + КонецЕсли; + // Обработка первого символа наборов символов. + Если ВидНабораСимволов = "" Тогда + Если ТипСимвола = "СимволСлова" Тогда + ВидНабораСимволов = "Слово"; + ПозицияНабораСимволов = НомерСимвола; + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + Если ТипСимвола = "СимволОперации" Тогда + ВидНабораСимволов = "Операция"; + ПозицияНабораСимволов = НомерСимвола; + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + Если ТипСимвола = "ОграничительСтроки" Тогда + ВидНабораСимволов = "ПроизвольнаяСтрока"; + ПозицияНабораСимволов = НомерСимвола; + СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); + СтрокаТаблицы.Символы = Символ; + СтрокаТаблицы.Вид = ВидНабораСимволов; + Продолжить; + КонецЕсли; + КонецЕсли; + // Обработка отдельных символов. + Если ТипСимвола = "Отступ" Тогда + Продолжить; + КонецЕсли; + Если ТипСимвола = "Разделитель" Тогда + СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); + СтрокаТаблицы.Символы = Символ; + СтрокаТаблицы.Позиция = НомерСимвола; + СтрокаТаблицы.Вид = "Разделитель"; + Продолжить; + КонецЕсли; + СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); + СтрокаТаблицы.Символы = Символ; + СтрокаТаблицы.Позиция = НомерСимвола; + СтрокаТаблицы.Вид = "НедопустимыйСимвол"; + СтрокаТаблицы.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимый символ ""%1"" с кодом %2'"), Символ, КодСимвола(Символ)); + КонецЦикла; + + Если ВидНабораСимволов = "Слово" Тогда + ДобавитьСловоВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + + ИначеЕсли ВидНабораСимволов = "Операция" Тогда + ДобавитьОперациюВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + + ИначеЕсли ВидНабораСимволов = "ПроизвольнаяСтрока" Тогда + СтрокаТаблицы.Уточнение = СтрСоединить(НаборСимволов); + СтрокаТаблицы.Позиция = ПозицияНабораСимволов; + СтрокаТаблицы.ПозицияОшибки = НомерСимвола - ПозицияНабораСимволов; + СтрокаТаблицы.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не указан символ окончания произвольной строки %1'"), СтрокаТаблицы.Символы); + КонецЕсли; + + ПоследняяСтрока = ТаблицаНаборовСимволов.Добавить(); + ПоследняяСтрока.Позиция = СтрДлина(ТекстОграничения) + 1; + ПоследняяСтрока.Вид = "Конец"; // Для установки текста ошибки недостатка описания. + ТаблицаНаборовСимволов.Индексы.Добавить("Вид, Уточнение"); + + Возврат ТаблицаНаборовСимволов; + +КонецФункции + +// Для функции ТаблицаНаборовСимволов. +Процедура ДобавитьСловоВТаблицуНаборовСимволов(Таблица, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка) + + СтрокаСимволов = СтрСоединить(НаборСимволов); + СвойстваСлова = СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(СтрокаСимволов)); // См. СвойстваСлова + + НоваяСтрока = Таблица.Добавить(); + НоваяСтрока.Символы = СтрокаСимволов; + НоваяСтрока.Позиция = ПозицияНабораСимволов; + + Если СвойстваСлова <> Неопределено Тогда + НоваяСтрока.Вид = "КлючевоеСлово"; + НоваяСтрока.Тип = СвойстваСлова.Тип; + НоваяСтрока.Приоритет = СвойстваСлова.Приоритет; + НоваяСтрока.Уточнение = СвойстваСлова.Идентификатор; + НоваяСтрока.ЭтоРезерв = СвойстваСлова.ЭтоРезерв; + + Если СвойстваСлова.ЭтоРезерв Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ключевое слово ""%1"" не поддерживается'"), СтрокаСимволов); + КонецЕсли; + Возврат; + КонецЕсли; + + // Слово является именем или числом. + СимволыЦифр = СинтаксисЯзыка.СимволыЦифр; + + Если НаборСимволов[0] = "." Тогда + Если НаборСимволов.Количество() > 1 Тогда + ЭтоЧисло = Ложь; + Иначе + НоваяСтрока.Вид = "Имя"; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'Имя не может начинаться с точки'"); + Возврат; + КонецЕсли; + Иначе + ЭтоЧисло = СимволыЦифр.Получить(НаборСимволов[0]) <> Неопределено; + КонецЕсли; + + Если ЭтоЧисло Тогда + НоваяСтрока.Вид = "Число"; + НомерСимвола = 1; + Для Каждого Символ Из НаборСимволов Цикл + Если СимволыЦифр.Получить(Символ) = Неопределено Тогда + НоваяСтрока.ПозицияОшибки = НомерСимвола - 1; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'Число может состоять только из цифр'"); + Возврат; + КонецЕсли; + НомерСимвола = НомерСимвола + 1; + КонецЦикла; + СимволыЧисла = Лев(СтрокаСимволов, НомерСимвола - 1); + Если СтрДлина(СимволыЧисла) > 16 Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Слишком большое число ""%1""'"), СимволыЧисла); + Возврат; + КонецЕсли; + НоваяСтрока.Уточнение = Число(СимволыЧисла); + Иначе + НоваяСтрока.Вид = "Имя"; + ЧастиИмени = СтрРазделить(СтрокаСимволов, "."); + ПозицияЧастиИмени = 1; + Для Каждого ЧастьИмени Из ЧастиИмени Цикл + Если ЧастьИмени = "" И ПозицияЧастиИмени > 1 Тогда + НоваяСтрока.ПозицияОшибки = ПозицияЧастиИмени - 1; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'После точки не указано имя'"); + Возврат; + ИначеЕсли СимволыЦифр.Получить(Лев(ЧастьИмени, 1)) <> Неопределено Тогда + НоваяСтрока.ПозицияОшибки = ПозицияЧастиИмени - 1; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'После точки в имени не может следовать число'"); + Возврат; + КонецЕсли; + ПозицияЧастиИмени = ПозицияЧастиИмени + СтрДлина(ЧастьИмени) + 1; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для функции ТаблицаНаборовСимволов. +Процедура ДобавитьОперациюВТаблицуНаборовСимволов(Таблица, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка) + + СтрокаСимволов = СтрСоединить(НаборСимволов); + СвойстваОперации = СинтаксисЯзыка.ОперацииЯзыка.Получить(СтрокаСимволов); + + НоваяСтрока = Таблица.Добавить(); + НоваяСтрока.Символы = СтрокаСимволов; + НоваяСтрока.Позиция = ПозицияНабораСимволов; + НоваяСтрока.Вид = "Операция"; + НоваяСтрока.Тип = СвойстваОперации.Тип; + НоваяСтрока.Приоритет = СвойстваОперации.Приоритет; + НоваяСтрока.ЭтоРезерв = СвойстваОперации.ЭтоРезерв; + + Если СвойстваОперации = Неопределено Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимая операция ""%1""'"), СтрокаСимволов); + + ИначеЕсли СвойстваОперации.ЭтоРезерв Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Операция ""%1"" не поддерживается'"), СтрокаСимволов); + КонецЕсли; + +КонецПроцедуры + +// Для функции РазобранноеОграничение и косвенно для многих других. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * СимволыЯзыка - см. СимволыЯзыка +// * СимволыЦифр - см. СимволыЦифр +// * ОперацииЯзыка - см. ОперацииЯзыка +// * СловаЯзыка - см. СловаЯзыка +// * ТипыТаблиц - см. ТипыТаблиц +// +Функция СинтаксисЯзыка() Экспорт + + СинтаксисЯзыка = Новый Структура; + СинтаксисЯзыка.Вставить("СимволыЯзыка", СимволыЯзыка()); + СинтаксисЯзыка.Вставить("СимволыЦифр", СимволыЦифр()); + СинтаксисЯзыка.Вставить("ОперацииЯзыка", ОперацииЯзыка()); + СинтаксисЯзыка.Вставить("СловаЯзыка", СловаЯзыка()); + СинтаксисЯзыка.Вставить("ТипыТаблиц", ТипыТаблиц()); + + Возврат Новый ФиксированнаяСтруктура(СинтаксисЯзыка); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - символ +// * Значение - Строка - вид символа +// +Функция СимволыЯзыка() + + СимволыЯзыка = Новый Соответствие; + + Для КодСимвола = КодСимвола("А") // @Non-NLS + По КодСимвола("Я") Цикл // @Non-NLS + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + Для КодСимвола = КодСимвола("а") // @Non-NLS + По КодСимвола("я") Цикл // @Non-NLS + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + Для КодСимвола = КодСимвола("A") По КодСимвола("Z") Цикл + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + Для КодСимвола = КодСимвола("a") По КодСимвола("z") Цикл + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + + СимволыЯзыка.Вставить("_", "СимволСлова"); + СимволыЯзыка.Вставить(".", "СимволСлова"); + + Для КодСимвола = КодСимвола("0") По КодСимвола("9") Цикл + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + + СимволыЯзыка.Вставить(" ", "Отступ"); + СимволыЯзыка.Вставить(Символы.Таб, "Отступ"); + СимволыЯзыка.Вставить(Символы.ПС, "Отступ"); + + СимволыЯзыка.Вставить("""", "ОграничительСтроки"); + + СимволыЯзыка.Вставить("(", "Разделитель"); + СимволыЯзыка.Вставить(")", "Разделитель"); + СимволыЯзыка.Вставить(",", "Разделитель"); + СимволыЯзыка.Вставить(";", "Разделитель"); + СимволыЯзыка.Вставить("=", "СимволОперации"); + СимволыЯзыка.Вставить("<", "СимволОперации"); + СимволыЯзыка.Вставить(">", "СимволОперации"); + + // Не поддерживаются. + СимволыЯзыка.Вставить("+", "СимволОперации"); + СимволыЯзыка.Вставить("-", "СимволОперации"); + СимволыЯзыка.Вставить("*", "СимволОперации"); + СимволыЯзыка.Вставить("/", "СимволОперации"); + + Возврат Новый ФиксированноеСоответствие(СимволыЯзыка); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - символ +// * Значение - Булево - Истина +// +Функция СимволыЦифр() + + СимволыЦифр = Новый Соответствие; + + Для КодСимвола = КодСимвола("0") По КодСимвола("9") Цикл + СимволыЦифр.Вставить(Символ(КодСимвола), Истина); + КонецЦикла; + + Возврат Новый ФиксированноеСоответствие(СимволыЦифр); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - слово на русском и английском языках. +// * Значение - см. СвойстваСлова +// +Функция СловаЯзыка() + + Слова = Новый Соответствие; + + ДобавитьСловоЯзыка(Слова, "ПрисоединитьДополнительныеТаблицы", + "AttachAdditionalTables", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЭтотСписок", + "ThisList", "НачалоСписок", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазрешитьЧтениеИзменение", + "AllowReadUpdate", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазрешитьЧтение", + "AllowRead", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазрешитьИзменениеЕслиРазрешеноЧтение", + "AllowUpdateIfReadingAllowed", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Где", + "Where", "НачалоГде"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "Левое", + "Left", "Присоединение"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Соединение", + "Join", "Присоединение"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "По", + "On", "Присоединение"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "И", + "And", "Соединитель", , 2); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Или", + "Or", "Соединитель", , 1); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "В", + "In", "Соединитель", , 5); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Как", + "As", "Соединитель"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Кроме", + "Except", "Соединитель"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Только", + "Only", "Соединитель"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Есть", + "Is", "Соединитель", , 7); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Не", + "Not", "Оператор", , 3); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "Выбор", + "Case", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Когда", + "When", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Тогда", + "Then", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Иначе", + "Else", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Конец", + "End", "СловоВыбора"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "ЕстьNull", + "IsNull", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Выразить", + "Cast", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Значение", + "Value", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ТипЗначения", + "ValueType", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Тип", + "Type", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЗначениеРазрешено", + "ValueAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЧтениеОбъектаРазрешено", + "ObjectReadingAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ИзменениеОбъектаРазрешено", + "ObjectUpdateAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЧтениеСпискаРазрешено", + "ListReadingAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ИзменениеСпискаРазрешено", + "ListUpdateAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДляВсехСтрок", + "ForAllRows", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДляОднойИзСтрок", + "ForAtLeastOneRow", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЭтоАвторизованныйПользователь", + "IsAuthorizedUser", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ПравоДоступа", + "AccessRight", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РольДоступна", + "IsInRole", "Функция", Ложь); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "ПустаяСсылка", + "EmptyRef", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Отключено", + "Disabled", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Неопределено", + "Undefined", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Null", + "Null", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Ложь", + "False", "ЗначениеУточнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Истина", + "True", "ЗначениеУточнения"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "Строка", + "String", "ИмяТипа"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Число", + "Number", "ИмяТипа"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Дата", + "Date", "ИмяТипа"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Булево", + "Boolean", "ИмяТипа"); // @Non-NLS + + // Неподдерживаемые, зарезервированные слова. + ДобавитьСловоЯзыка(Слова, "Выбрать", + "Select", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Первые", + "Top", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Различные", + "Distinct", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Из", + "From", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Внутреннее", + "Inner", "Присоединение", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Полное", + "Full", "Присоединение", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Сгруппировать", + "Group", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Имеющие", + "Having", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Упорядочить", + "Order", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Итоги", + "Totals", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Год", + "Year", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Квартал", + "Quarter", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Месяц", + "Month", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДеньГода", + "DayOfYear", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "День", + "Day", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Неделя", + "Week", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДеньНедели", + "Weekday", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Час", + "Hour", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Минута", + "Minute", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Секунда", + "Second", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "НачалоПериода", + "BeginOfPeriod", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "КонецПериода", + "EndOfPeriod", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДобавитьКДате", + "DateAdd", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазностьДат", + "DateDiff", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Сумма", + "Sum", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Минимум", + "Min", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Максимум", + "Max", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Среднее", + "Avg", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Количество", + "Count", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Представление", + "Presentation", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ПредставлениеСсылки", + "RefPresentation", "Функция", Ложь, , Истина); // @Non-NLS + + Возврат Новый ФиксированноеСоответствие(Слова); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - слово на русском и английском языках. +// * Значение - см. СвойстваСлова +// +Функция ОперацииЯзыка() + + ОперацииЯзыка = Новый Соответствие; + + ДобавитьСловоЯзыка(ОперацииЯзыка, "=", "=", "Соединитель", , 4); + ДобавитьСловоЯзыка(ОперацииЯзыка, "<>", "<>", "Соединитель", , 4); + + // Неподдерживаемые, зарезервированные операции. + ДобавитьСловоЯзыка(ОперацииЯзыка, "<", "<", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "<=", "<=", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, ">", ">", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, ">=", ">=", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "+", "+", "Соединитель", , 1, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "-", "-", "Соединитель", , 1, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "*", "*", "Соединитель", , 6, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "/", "/", "Соединитель", , 6, Истина); + + Возврат Новый ФиксированноеСоответствие(ОперацииЯзыка); + +КонецФункции + +// Для функций СловаЯзыка и ОперацииЯзыка. +Процедура ДобавитьСловоЯзыка(Слова, ЯзыкРусский, ЯзыкАнглийский, ТипСлова, + ВерхнийРегистр = Истина, Приоритет = 0, ЭтоРезерв = Ложь) + + СвойстваСлова = СвойстваСлова(ЯзыкРусский, + ЯзыкАнглийский, ТипСлова, ВерхнийРегистр, Приоритет, ЭтоРезерв); + + Слова.Вставить(ВРег(ЯзыкРусский), СвойстваСлова); + Слова.Вставить(ВРег(ЯзыкАнглийский), СвойстваСлова); + +КонецПроцедуры + +// Для процедуры ДобавитьСловоЯзыка. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Идентификатор - Строка - слово языка на языке конфигурации (русском или английском). +// * ЯзыкРусский - Строка - слово языка на русском языке. +// * ЯзыкАнглийский - Строка - слово языка на английском языке. +// * Тип - Строка - имя типа слова. +// * ВерхнийРегистр - Булево +// * Приоритет - Число +// * ЭтоРезерв - Булево +// +Функция СвойстваСлова(ЯзыкРусский, ЯзыкАнглийский, ТипСлова, ВерхнийРегистр, Приоритет, ЭтоРезерв) + + СвойстваСлова = Новый Структура; + СвойстваСлова.Вставить("Идентификатор", ?(КодСимвола(Лев(ТипСлова, 1)) > 122, ЯзыкРусский, ЯзыкАнглийский)); + СвойстваСлова.Вставить("ЯзыкРусский", ЯзыкРусский); + СвойстваСлова.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + СвойстваСлова.Вставить("Тип", ТипСлова); + СвойстваСлова.Вставить("ВерхнийРегистр", ВерхнийРегистр); + СвойстваСлова.Вставить("Приоритет", Приоритет); + СвойстваСлова.Вставить("ЭтоРезерв", ЭтоРезерв); + + Возврат Новый ФиксированнаяСтруктура(СвойстваСлова); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// Структура: +// * ПоИменам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя типа таблиц на русском и на английском языках. +// ** Значение - см. СвойстваТипаТаблиц +// * ПоКоллекциям - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя коллекции на языке конфигурации (русском или английском). +// ** Значение - см. СвойстваТипаТаблиц +// +Функция ТипыТаблиц() + + ТипыТаблиц = Новый Структура; + ТипыТаблиц.Вставить("ПоИменам", Новый Соответствие); + ТипыТаблиц.Вставить("ПоКоллекциям", Новый Соответствие); + + // Установка имен типов таблиц. + ДобавитьТипТаблиц(ТипыТаблиц, "ПланОбмена", + "ExchangePlan", "ПланыОбмена"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "КритерийОтбора", + "FilterCriterion", "КритерииОтбора"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Константы", + "Constants", ""); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Константа", + "Constant", "Константы"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Справочник", + "Catalog", "Справочники"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Последовательность", + "Sequence", "Последовательности"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Документ", + "Document", "Документы"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ЖурналДокументов", + "DocumentJournal", "ЖурналыДокументов"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Перечисление", + "Enum", "Перечисления"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ПланВидовХарактеристик", + "ChartOfCharacteristicTypes", "ПланыВидовХарактеристик"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ПланСчетов", + "ChartOfAccounts", "ПланыСчетов"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ПланВидовРасчета", + "ChartOfCalculationTypes", "ПланыВидовРасчета"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрСведений", + "InformationRegister", "РегистрыСведений"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрНакопления", + "AccumulationRegister", "РегистрыНакопления"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрБухгалтерии", + "AccountingRegister", "РегистрыБухгалтерии"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрРасчета", + "CalculationRegister", "РегистрыРасчета"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "БизнесПроцесс", + "BusinessProcess", "БизнесПроцессы"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Задача", + "Task", "Задачи"); // @Non-NLS + + // Установка основных свойств основных типов таблиц. + ИменаТиповТаблиц = "ПланОбмена,Справочник,Документ,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета,БизнесПроцесс,Задача"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЭтоСсылочныйТип", Истина); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьОграничение", Истина); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Разрешены"); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Использование", "Разрешено"); + + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Разрешены"); + + ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ТабличныеЧасти", "Разрешены"); + + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ВерсияДанных", + "DataVersion", "Запрещено"); // @Non-NLS + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Представление", + "Presentation", "Запрещено"); // @Non-NLS + + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Изменения", + "Changes", "Запрещено"); // @Non-NLS + + // Установка основных свойств регистров. + ИменаТиповТаблиц = "РегистрСведений,РегистрРасчета"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Ресурсы", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Разрешены"); + + ИменаТиповТаблиц = "РегистрНакопления,РегистрБухгалтерии"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Недопустимы"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Ресурсы", "Недопустимы"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Недопустимы"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Недопустимы"); + + ИменаТиповТаблиц = "РегистрСведений,РегистрНакопления,РегистрБухгалтерии,РегистрРасчета"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьОграничение", Истина); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Измерения", "Разрешены"); + + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Изменения", + "Changes", "Запрещено"); // @Non-NLS + + // Установка некоторых из указанных ранее свойств для остальных типов таблиц. + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "Последовательность", "ЕстьОграничение", Истина); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Последовательность", "Измерения", "Разрешены"); + + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "ОбщиеРеквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "СтандартныеРеквизиты", "Разрешены"); + + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "Перечисление", "ЭтоСсылочныйТип", Истина); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Перечисление", "СтандартныеРеквизиты", "Разрешены"); + + ИменаТиповТаблиц = "Константа,РегистрСведений"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Использование", "Разрешено"); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "КритерийОтбора", "Использование", "Недопустимо"); + + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "Константа", "Изменения", + "Changes", + "Запрещено"); // @Non-NLS-2 + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "РегистрСведений", "СрезПервых", + "SliceFirst", + "Недопустимо"); // @Non-NLS-2 + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "РегистрСведений", "СрезПоследних", + "SliceLast", + "Недопустимо"); // @Non-NLS-2 + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "БизнесПроцесс", "Точки", + "Points", + "Запрещено"); // @Non-NLS-2 + + // Установка специализированных свойств. + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "ПланСчетов", "ПризнакиУчетаСубконто", "Разрешены"); + + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "Графы", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ПланСчетов", "ПризнакиУчета", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Задача", "РеквизитыАдресации", "Разрешены"); + + ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, "ПланСчетов", "СтандартныеТабличныеЧасти", "Разрешены"); + ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, "ПланВидовРасчета", "СтандартныеТабличныеЧасти", "Разрешены"); + + ИменаТиповТаблиц = "Справочник,Перечисление,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьПредопределенные", Истина); + + // Уточнение стандартных полей типов таблиц. + ИменаТиповТаблиц = "Документ,РегистрСведений,РегистрНакопления,РегистрБухгалтерии"; + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "МоментВремени", + "PointInTime", "Недопустимо"); // @Non-NLS + + ИменаТиповТаблиц = "Справочник,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета"; + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ИмяПредопределенныхДанных", + "PredefinedDataName", "Запрещено"); // @Non-NLS + + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Константа", "Значение", + "Value", + "Разрешено"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Последовательность", "Регистратор", + "Recorder", + "Разрешено"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Последовательность", "Период", + "Period", + "Разрешено"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "Тип", + "Type", + "Недопустимо"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Перечисление", "Порядок", + "Order", + "Запрещено"); // @Non-NLS-2 + + Возврат ТипыТаблиц; + +КонецФункции + +// Для функции ТипыТаблиц. +Процедура ДобавитьТипТаблиц(ТипыТаблиц, ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции) + + СвойстваТипаТаблиц = СвойстваТипаТаблиц(ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции); + + ТипыТаблиц.ПоИменам.Вставить(ВРег(ЯзыкРусский), СвойстваТипаТаблиц); + ТипыТаблиц.ПоИменам.Вставить(ВРег(ЯзыкАнглийский), СвойстваТипаТаблиц); + + Если ЗначениеЗаполнено(ИмяКоллекции) Тогда + ТипыТаблиц.ПоКоллекциям.Вставить(ИмяКоллекции, СвойстваТипаТаблиц); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьСловоЯзыка. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ИмяКоллекции - Строка - имя коллекции на языке конфигурации (русском или английском). +// * ЯзыкРусский - Строка - имя типа таблиц на русском языке. +// * ЯзыкАнглийский - Строка - имя типа таблиц на английском языке. +// * ЭтоСсылочныйТип - Булево +// * ЕстьОграничение - Булево +// * ЕстьПредопределенные - Булево +// * КоллекцииПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя коллекции полей на языке конфигурации (русском или английском). +// ** Значение - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// +// * КоллекцииТабличныхЧастей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя коллекции табличных частей на языке конфигурации (русском или английском). +// ** Значение - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// +// * ОбщиеРеквизиты - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Отсутствуют" - не существуют у объекта метаданных. +// +// * ПризнакиУчетаСубконто - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Отсутствуют" - не существуют у объекта метаданных. +// +// * УточнениеПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя поля таблиц на русском и на английском языках. +// ** Значение - см. УточнениеПоля +// +// * УточнениеТаблиц - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя расширения таблиц на русском и на английском языках. +// ** Значение - см. УточнениеТаблиц +// +// * Использование - Строка - +// "Разрешено" - можно использовать без ограничений. +// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Запрещено" - запрещено присоединять, как дополнительную таблицу в ограничении доступа БСП. +// +Функция СвойстваТипаТаблиц(ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции) + + СвойстваТипаТаблиц = Новый Структура; + СвойстваТипаТаблиц.Вставить("ИмяКоллекции", ИмяКоллекции); + СвойстваТипаТаблиц.Вставить("ЯзыкРусский", ЯзыкРусский); + СвойстваТипаТаблиц.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + СвойстваТипаТаблиц.Вставить("ЭтоСсылочныйТип", Ложь); + СвойстваТипаТаблиц.Вставить("ЕстьОграничение", Ложь); + СвойстваТипаТаблиц.Вставить("ЕстьПредопределенные", Ложь); + СвойстваТипаТаблиц.Вставить("КоллекцииПолей", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("КоллекцииТабличныхЧастей", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("ОбщиеРеквизиты", "Отсутствуют"); + СвойстваТипаТаблиц.Вставить("ПризнакиУчетаСубконто", "Отсутствуют"); + СвойстваТипаТаблиц.Вставить("УточнениеПолей", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("УточнениеТаблиц", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("Использование", "Запрещено"); + + Возврат СвойстваТипаТаблиц; + +КонецФункции + +// Для функции ТипыТаблиц. +Процедура УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, Свойство, Значение) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + СвойстваТипаТаблиц[Свойство] = Значение; + КонецЦикла; + +КонецПроцедуры + +// Для функции ТипыТаблиц. +Процедура ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ИмяКоллекции, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + СвойстваТипаТаблиц.КоллекцииПолей.Вставить(ИмяКоллекции, Использование); + КонецЦикла; + +КонецПроцедуры + +// Для функции ТипыТаблиц. +Процедура ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ИмяКоллекции, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + СвойстваТипаТаблиц.КоллекцииТабличныхЧастей.Вставить(ИмяКоллекции, Использование); + КонецЦикла; + +КонецПроцедуры + +// Для функции ТипыТаблиц. +Процедура ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ЯзыкРусский, ЯзыкАнглийский, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + УточнениеПоля = УточнениеПоля(ЯзыкРусский, ЯзыкАнглийский, Использование); + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + + СвойстваТипаТаблиц.УточнениеПолей.Вставить(ВРег(ЯзыкРусский), УточнениеПоля); + СвойстваТипаТаблиц.УточнениеПолей.Вставить(ВРег(ЯзыкАнглийский), УточнениеПоля); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьПолеТипаТаблиц. +// +// Возвращаемое значение: +// Структура: +// * ЯзыкРусский - Строка - имя поля таблиц на русском языке. +// * ЯзыкАнглийский - Строка - имя поля таблиц на английском языке. +// * Использование - Строка - +// "Разрешено" - можно использовать без ограничений. +// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Запрещено" - запрещено использовать в ограничении доступа БСП. +// +Функция УточнениеПоля(ЯзыкРусский, ЯзыкАнглийский, Использование) + + УточнениеПоля = Новый Структура; + УточнениеПоля.Вставить("ЯзыкРусский", ЯзыкРусский); + УточнениеПоля.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + УточнениеПоля.Вставить("Использование", Использование); + + Возврат УточнениеПоля; + +КонецФункции + +// Для функции ТипыТаблиц. +Процедура ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ЯзыкРусский, ЯзыкАнглийский, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + УточнениеТаблиц = УточнениеТаблиц(ЯзыкРусский, ЯзыкАнглийский, Использование); + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + + СвойстваТипаТаблиц.УточнениеТаблиц.Вставить(ВРег(ЯзыкРусский), УточнениеТаблиц); + СвойстваТипаТаблиц.УточнениеТаблиц.Вставить(ВРег(ЯзыкАнглийский), УточнениеТаблиц); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьПолеТипаТаблиц. +// +// Возвращаемое значение: +// Структура: +// * ЯзыкРусский - Строка - имя расширения таблиц на русском языке. +// * ЯзыкАнглийский - Строка - имя расширения таблиц на английском языке. +// * Использование - Строка - +// "Разрешено" - можно использовать без ограничений. +// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Запрещено" - запрещено использовать в ограничении доступа БСП. +// +Функция УточнениеТаблиц(ЯзыкРусский, ЯзыкАнглийский, Использование) + + УточнениеТаблиц = Новый Структура; + УточнениеТаблиц.Вставить("ЯзыкРусский", ЯзыкРусский); + УточнениеТаблиц.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + УточнениеТаблиц.Вставить("Использование", Использование); + + Возврат УточнениеТаблиц; + +КонецФункции + +#КонецОбласти + +#Область СинтаксическийАнализ + +// Для функции РазобранноеОграничение. +// +// Параметры: +// ВнутренниеДанные - см. НовыеВнутренниеДанные +// +// Возвращаемое значение: +// Структура: +// * ДополнительныеТаблицы - Массив из см. НовоеОписаниеСоединения +// * ПсевдонимОсновнойТаблицы - Строка +// * ОграничениеЧтения - Структура +// * ОграничениеИзменения - Структура +// +Функция ЧастиОграничения(ВнутренниеДанные) + + ЧастиОграничения = Новый Структура; + ЧастиОграничения.Вставить("ДополнительныеТаблицы", Новый Массив); + ЧастиОграничения.Вставить("ПсевдонимОсновнойТаблицы", ""); + ЧастиОграничения.Вставить("ОграничениеЧтения", Новый Структура); + ЧастиОграничения.Вставить("ОграничениеИзменения", Новый Структура); + + ТаблицаНаборовСимволов = ВнутренниеДанные.ТаблицаНаборовСимволов; + + Если ТаблицаНаборовСимволов.Количество() = 0 Тогда + Возврат ЧастиОграничения; + КонецЕсли; + + ТаблицаНаборовСимволов.Колонки.Добавить("Строки", Новый ОписаниеТипов("Массив")); + ТаблицаНаборовСимволов.Колонки.Добавить("КонечнаяСтрока"); + + // Разделение ограничения на основные части. + Строки = ТаблицаНаборовСимволов.НайтиСтроки(Новый Структура("Символы, Вид", ";", "Разделитель")); + + ИндексыСтрокРазделителя = Новый Массив; + Для Каждого Строка Из Строки Цикл + ИндексыСтрокРазделителя.Добавить(ТаблицаНаборовСимволов.Индекс(Строка)); + КонецЦикла; + ИндексыСтрокРазделителя.Добавить(ТаблицаНаборовСимволов.Количество() - 1); + + СвойстваЧастей = Новый Массив; // Массив из см. НовыеСвойстваЧасти + ИндексСтроки = 0; + Для Каждого ИндексСтрокиРазделителя Из ИндексыСтрокРазделителя Цикл + СтрокиЧасти = Новый Массив; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + Пока ИндексСтроки < ИндексСтрокиРазделителя Цикл + СтрокаЧасти = ТаблицаНаборовСимволов[ИндексСтроки]; + Если СтрокаЧасти.Вид <> "НедопустимыйСимвол" Тогда + СтрокиЧасти.Добавить(СтрокаЧасти); + КонецЕсли; + ИндексСтроки = ИндексСтроки + 1; + КонецЦикла; + СтрокаРазделителя = ТаблицаНаборовСимволов[ИндексСтрокиРазделителя]; + Если СтрокиЧасти.Количество() = 0 Тогда + СтрокиЧасти.Добавить(СтрокаРазделителя); + КонецЕсли; + СвойстваЧасти = НовыеСвойстваЧасти(); + СвойстваЧасти.Вставить("Строки", СтрокиЧасти); + СвойстваЧасти.Вставить("СтрокаРазделителя", СтрокаРазделителя); + СвойстваЧастей.Добавить(СвойстваЧасти); + ПерваяСтрокаЧасти = СтрокиЧасти[0]; + Если ПерваяСтрокаЧасти.Вид = "КлючевоеСлово" + И ПерваяСтрокаЧасти.Тип = "Начало" Тогда + + СвойстваЧасти.Вставить("Имя", ПерваяСтрокаЧасти.Уточнение); + СвойстваЧасти.Вставить("Представление", ПерваяСтрокаЧасти.Символы); + + РазобратьЧастьОграничения(СвойстваЧасти, ВнутренниеДанные); + Иначе + СвойстваЧасти.Вставить("Имя", ""); + СвойстваЧасти.Вставить("Представление", ""); + КонецЕсли; + ИндексСтроки = ИндексСтрокиРазделителя + 1; + КонецЦикла; + + ДобавитьПсевдонимыПоУмолчанию(ВнутренниеДанные); + + // Анализ части 1. + СвойстваЧасти1 = СвойстваЧастей[0]; + + Если СвойстваЧасти1.Имя = "" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти1, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале первой части текста ограничения нет ни одного из ключевых слов + |""%1"", ""%2"", ""%3""'"), + "РазрешитьЧтениеИзменение,РазрешитьЧтение,ПрисоединитьДополнительныеТаблицы")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧасти1.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти1, + НСтр("ru = 'В начале первой части текста ограничения найдено недопустимое ключевое слово'")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧастей.Количество() = 1 + И ( СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы" + Или СвойстваЧасти1.Имя = "РазрешитьЧтение" ) Тогда + + УстановитьОшибкуНачалаЧасти(ТаблицаНаборовСимволов, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Текст ограничения не может быть только из одной части + |с ключевым словом ""%1""'"), СвойстваЧасти1.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти1); + + Если СвойстваЧастей.Количество() < 2 Тогда + Возврат ЧастиОграничения; + КонецЕсли; + + // Анализ части 2. + СвойстваЧасти2 = СвойстваЧастей[1]; + + Если СвойстваЧасти1.Имя = "РазрешитьЧтениеИзменение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти1.СтрокаРазделителя, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Второй части текста ограничения не должно быть, когда + |в первой части указано ключевое слово ""%1""'"), СвойстваЧасти1.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + Если СвойстваЧасти2.Имя = "" Тогда + Если СвойстваЧасти1.Имя = "РазрешитьЧтение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале второй части текста ограничения нет + |ключевого слова ""%1""'"), + "РазрешитьИзменениеЕслиРазрешеноЧтение")); + Иначе // СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы". + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале второй части текста ограничения нет ни одного из ключевых слов + |""%1"", ""%2""'"), + "РазрешитьЧтениеИзменение,РазрешитьЧтение")); + КонецЕсли; + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧасти1.Имя = "РазрешитьЧтение" + И СвойстваЧасти2.Имя <> "РазрешитьИзменениеЕслиРазрешеноЧтение" + Или СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы" + И СвойстваЧасти2.Имя <> "РазрешитьЧтениеИзменение" + И СвойстваЧасти2.Имя <> "РазрешитьЧтение" Тогда + + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, + НСтр("ru = 'В начале второй части текста ограничения найдено недопустимое ключевое слово'")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧастей.Количество() = 2 + И СвойстваЧасти2.Имя = "РазрешитьЧтение" Тогда + + УстановитьОшибкуНачалаЧасти(ТаблицаНаборовСимволов, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Текст ограничения не может быть только из двух частей, когда + |во второй части указано ключевое слово ""%1""'"), СвойстваЧасти2.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти2); + + Если СвойстваЧастей.Количество() < 3 Тогда + Возврат ЧастиОграничения; + КонецЕсли; + + // Анализ части 3. + СвойстваЧасти3 = СвойстваЧастей[2]; + + Если СвойстваЧасти2.Имя = "РазрешитьЧтениеИзменение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2.СтрокаРазделителя, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Третьей части текста ограничения не должно быть, когда + |во второй части указано ключевое слово ""%1""'"), СвойстваЧасти2.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + Если СвойстваЧасти3.Имя = "" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти3, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале третьей части текста ограничения нет + |ключевого слово ""%1""'"), + "РазрешитьИзменениеЕслиРазрешеноЧтение")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧасти2.Имя = "РазрешитьЧтение" + И СвойстваЧасти3.Имя <> "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда + + УстановитьОшибкуНачалаЧасти(СвойстваЧасти3, + НСтр("ru = 'В начале третьей части текста ограничения найдено недопустимое ключевое слово'")); + Возврат ЧастиОграничения; + КонецЕсли; + + УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти3); + + Возврат ЧастиОграничения; + +КонецФункции + +// Процедура: +// Родитель - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// - Структура +// Строка - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// Контекст - Структура: +// * Таблица - см. ТаблицаНаборовСимволов +// +Процедура СтрокаДобавить(Родитель, Строка, Контекст) + + Если ТипЗнч(Строка) = Тип("СтрокаТаблицыЗначений") Тогда + Родитель.Строки.Добавить(Контекст.ТаблицаНаборовСимволов.Индекс(Строка)); + Иначе + Родитель.Строки.Добавить(Строка); + КонецЕсли; + +КонецПроцедуры + +// Параметры: +// ОписаниеСтроки - Число - индекс таблицы значений. +// - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// - Структура - см. ДополнительнаяСтрока +// Контекст - Структура: +// * Таблица - см. ТаблицаНаборовСимволов +// +// Возвращаемое значение: +// см. ДополнительнаяСтрока +// +Функция СтрокаТаблицы(ОписаниеСтроки, Контекст) + + Если ТипЗнч(ОписаниеСтроки) = Тип("Число") Тогда + Строка = Контекст.ТаблицаНаборовСимволов[ОписаниеСтроки]; + Иначе + Строка = ОписаниеСтроки; + КонецЕсли; + + Возврат Строка; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// * СтрокаРазделителя - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// * Имя - Строка +// * Представление - Строка +// +Функция НовыеСвойстваЧасти() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Таблица - Строка +// * Псевдоним - Строка +// * УсловиеСоединения - см. ОписаниеУзла +// * ПсевдонимыТребуемыхТаблиц - Массив из Строка +// * ПоляУсловияСоединения - Массив из см. ПараПолейУсловияСоединения +// * ТекстУсловияСоединения - Строка +// +Функция НовоеОписаниеСоединения() + + Возврат Новый Структура; + +КонецФункции + + +// Возвращаемое значение: +// Структура: +// * Источник - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// +// * Узел - Строка - одна из строк "Поле", "Значение", "Константа", +// "И", "Или", "Не", "=", "<>", "В", "ЕстьNull", "Тип", "ТипЗначения", "Выбор", +// "ЗначениеРазрешено", "ЭтоАвторизованныйПользователь", +// "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено", +// "ЧтениеСпискаРазрешено", "ИзменениеСпискаРазрешено", +// "ДляВсехСтрок", "ДляОднойИзСтрок", +// "ПравоДоступа", "РольДоступна". +// +// Свойства узла Поле. +// * Имя - Строка - имя поля, например, "Организация" или "ОсновнаяОрганизация". +// * Таблица - Строка - имя таблицы этого поля (или пустая строка для основной таблицы). +// * Псевдоним - Строка - имя псевдонима присоединяемой таблицы этого поля (или пустая строка для основной таблицы), +// например, "РегистрСведенийНастройки" для поля "ОсновнаяОрганизация". +// * Выразить - Строка - имя таблицы (если используется), например, для описания поля в виде: +// "ВЫРАЗИТЬ(ВЫРАЗИТЬ(Владелец КАК Справочник.Файлы).ВладелецФайла КАК Справочник.Организации).Ссылка". +// * Вложение - Структура - узел Поле, содержащий вложенное действие ВЫРАЗИТЬ (с или без ЕстьNull). +// - Неопределено - нет вложенного поля. +// * ЕстьNull - Структура - узел Значение Или Константа, например, для описания выражения вида +// "ЕстьNULL(Владелец, Значение(Справочник.Файлы.ПустаяСсылка))". +// - Неопределено - если ЕстьNull не используется (в том числе, когда свойство Вложение заполнено). +// * ИмяИсточник - СтрокаТаблицыЗначений +// - Неопределено +// * ВыразитьИсточник - СтрокаТаблицыЗначений +// - Неопределено +// * ЕстьNullИсточник - СтрокаТаблицыЗначений +// - Неопределено +// +// Свойства узлов Значение и Тип. +// * Имя - Строка - имя значения, например, "Справочник.Организации.Основная", +// "Справочник.Организации.ПустаяСсылка", +// имя таблицы, например, "Справочник.Организации". +// +// Свойства узла Константа. +// * Значение - Булево +// - Число +// - Строка +// - Неопределено - Ложь, Истина, произвольное +// целое число до 16 разрядов или произвольная строка до 150 символов. +// +// Свойства узлов И, Или (любой узел, кроме Значение и Константа). +// * Аргументы - Массив из см. ОписаниеУзла +// +// Свойства узла Не (любой узел, кроме Значение и Константа). +// * Аргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узлов =, <> (ПервыйАргумент - узел Поле, +// ВторойАргумент - узел Значение, Константа, а узел Поле только для условия соединения). +// * ПервыйАргумент - см. ОписаниеУзла +// * ВторойАргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла В (Искомое - узел Поле, Значения - узлы Значение и/или Константа). +// * Искомое - см. ОписаниеУзла +// * Значения - Массив из см. ОписаниеУзла +// +// Свойства узла ЕстьNull (узел Поле - выражение вида "<Поле> ЕСТЬ NULL"). +// * Аргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла ТипЗначения (узел Поле). +// * Аргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла Выбор +// В свойстве Выбор +// узел Поле +// Неопределено - условия содержат выражение, а не узел Значение +// В свойстве Когда +// Условие - узел Значение, если свойство Выбор указано, в противном случае +// узлы И, Или, Не, =, <>, В (распространяется на вложенное содержимое) +// Значение - узел, кроме Выбор +// В свойстве Иначе +// узел, кроме ВЫБОР и Значение (Поле и Константа может быть только типа Булево). +// * Выбор - см. ОписаниеУзла +// * Когда - Массив из Структура: +// ** Условие - см. ОписаниеУзла +// ** Значение - см. ОписаниеУзла +// * Иначе - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узлов ЗначениеРазрешено, ЭтоАвторизованныйПользователь, +// ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, +// ЧтениеСпискаРазрешено, ИзменениеСпискаРазрешено. +// В свойстве Поле - узел Поле. +// * Поле - см. ОписаниеУзла +// * Типы - Массив из Строка - полное имя таблицы +// * ПроверятьТипыКромеУказанных - Булево - если Истина, то все типы свойства Поле, +// кроме указанных в свойстве Типы. +// * УточненияСравнения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - уточняемое значение "Неопределено", "Null", "ПустаяСсылка", +// <полное имя таблицы>, "Число", "Строка", "Дата", "Булево". +// ** Значение - Строка - результат "Ложь", "Истина". +// +// Свойства узлов ДляВсехСтрок, ДляОднойИзСтрок (любой узел). +// * Аргумент - см. ОписаниеУзла. +// +Функция ОписаниеУзла() + + Возврат Новый Структура; + +КонецФункции + +// Для функции ЧастиОграничения. +Процедура УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти) + + Если СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" + Или СвойстваЧасти.Имя = "РазрешитьЧтение" Тогда + + ИмяСвойства = "ОграничениеЧтения"; + + ИначеЕсли СвойстваЧасти.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда + + ИмяСвойства = "ОграничениеИзменения"; + + Иначе // ПрисоединитьДополнительныеТаблицы. + + ИмяСвойства = "ДополнительныеТаблицы"; + ЧастиОграничения.ПсевдонимОсновнойТаблицы = СвойстваЧасти.ПсевдонимОсновнойТаблицы; + КонецЕсли; + + ЧастиОграничения[ИмяСвойства] = СвойстваЧасти.Состав; + +КонецПроцедуры + +// Для функции ЧастиОграничения, процедур РазобратьДополнительныеТаблицы, РазобратьУсловиеОграничения. +// Параметры: +// СвойстваЧасти - см. НовыеСвойстваЧасти +// ТекстОшибки - Строка +// +Процедура УстановитьОшибкуНачалаЧасти(СвойстваЧасти, ТекстОшибки) + + Если ТипЗнч(СвойстваЧасти) = Тип("ТаблицаЗначений") Тогда + СтрокаСОшибкой = СвойстваЧасти[СвойстваЧасти.Количество() - 1]; + + ИначеЕсли ТипЗнч(СвойстваЧасти) = Тип("СтрокаТаблицыЗначений") Тогда + СтрокаСОшибкой = СвойстваЧасти; + Иначе + СтрокаСОшибкой = СвойстваЧасти.Строки[0]; + КонецЕсли; + + СтрокаСОшибкой.ТекстОшибки = ТекстОшибки; + + // Требуется описание вариантов первых ключевых слов частей. + СтрокаСОшибкой.ПозицияОшибки = -1; + +КонецПроцедуры + +// Для процедуры РазобратьСоединение. +// Параметры: +// Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// ИндексСтроки - Число +// ТекстОшибки - Строка +// +Процедура УстановитьОшибкуВнутриЧасти(Строки, ИндексСтроки, ТекстОшибки) + + Если ИндексСтроки < Строки.Количество() Тогда + СтрокаСОшибкой = Строки[ИндексСтроки]; + Иначе + СтрокаСОшибкой = Строки[ИндексСтроки - 1]; + // Ошибка в конце слова. + СтрокаСОшибкой.ПозицияОшибки = СтрДлина(СтрокаСОшибкой.Символы); + КонецЕсли; + + СтрокаСОшибкой.ТекстОшибки = ТекстОшибки; + +КонецПроцедуры + +// Для функции ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. +Процедура УстановитьОшибкуВСтроке(Строка, ТекстОшибки, ВКонцеСлова = Ложь, НомерСлова = 1) + + Если ЗначениеЗаполнено(Строка.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если ВКонцеСлова Тогда + Строка.ПозицияОшибки = СтрДлина(Строка.Символы); + + ИначеЕсли НомерСлова > 1 Тогда + СоставИмени = СтрРазделить(Строка.Символы, "."); + Если СоставИмени.Количество() > 1 Тогда + Строка.ПозицияОшибки = СтрДлина(СоставИмени[0]) + 1; + КонецЕсли; + КонецЕсли; + + Строка.ТекстОшибки = ТекстОшибки; + +КонецПроцедуры + +// Для функции ЧастиОграничения. +Процедура РазобратьЧастьОграничения(СвойстваЧасти, ВнутренниеДанные) + + Если СвойстваЧасти.Имя = "ПрисоединитьДополнительныеТаблицы" Тогда + СвойстваЧасти.Вставить("Состав", Новый Массив); + СвойстваЧасти.Вставить("ПсевдонимОсновнойТаблицы", ""); + РазобратьДополнительныеТаблицы(СвойстваЧасти, ВнутренниеДанные); + Иначе + СвойстваЧасти.Вставить("Состав", ОписаниеУзла()); + РазобратьУсловиеОграничения(СвойстваЧасти, ВнутренниеДанные); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьЧастьОграничения. +Процедура РазобратьДополнительныеТаблицы(СвойстваЧасти, ВнутренниеДанные) + + СтрокиЧасти = СвойстваЧасти.Строки; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + + Если СтрокиЧасти.Количество() < 2 + Или СтрокиЧасти[1].Вид <> "КлючевоеСлово" + Или СтрокиЧасти[1].Уточнение <> "ЭтотСписок" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 3, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[1]), + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет + |ключевого слово ""%2""'"), + СвойстваЧасти.Представление, + КлючевоеСловоСУчетомЯзыка("ЭтотСписок", ВнутренниеДанные))); + Возврат; + КонецЕсли; + + ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти, СтрокиЧасти[1]); + + Если СтрокиЧасти.Количество() < 3 + Или СтрокиЧасти[2].Вид <> "КлючевоеСлово" + Или СтрокиЧасти[2].Уточнение <> "Как" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 3, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[2]), + ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%1"" нет ключевого слово ""%2""'"), + "ЭтотСписок,Как")); + Возврат; + КонецЕсли; + + Если СтрокиЧасти.Количество() < 4 + Или СтрокиЧасти[3].Вид <> "Имя" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 4, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[3]), + ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%1"" нет псевдонима'"), + "Как")); + Возврат; + КонецЕсли; + + УстановитьПсевдоним(СтрокиЧасти[3], СвойстваЧасти.ПсевдонимОсновнойТаблицы, ВнутренниеДанные); + + // Разделение описания на группы левых соединений. + Соединения = Новый Массив; + ТекущееСоединение = Новый Массив; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + + Для Индекс = 4 По СтрокиЧасти.Количество()-1 Цикл + СтрокаЧасти = СтрокиЧасти[Индекс]; + + Если СтрокаЧасти.Вид = "КлючевоеСлово" + И СтрокаЧасти.Уточнение = "Левое" Тогда + + Если ТекущееСоединение.Количество() > 0 Тогда + Соединения.Добавить(ТекущееСоединение); + КонецЕсли; + ТекущееСоединение = Новый Массив; + ТекущееСоединение.Добавить(СтрокаЧасти); + + Если Индекс + 1 < СтрокиЧасти.Количество() + И СтрокиЧасти[Индекс + 1].Вид = "КлючевоеСлово" + И СтрокиЧасти[Индекс + 1].Уточнение = "Соединение" Тогда + + Индекс = Индекс + 1; + ТекущееСоединение.Добавить(СтрокиЧасти[Индекс]); + КонецЕсли; + + Продолжить; + КонецЕсли; + ТекущееСоединение.Добавить(СтрокаЧасти); + КонецЦикла; + + Если ТекущееСоединение.Количество() > 0 + Или Соединения.Количество() = 0 Тогда + + Соединения.Добавить(ТекущееСоединение); + КонецЕсли; + + ВнутренниеДанные.Вставить("ДоступныеПсевдонимы", + Новый Соответствие(Новый ФиксированноеСоответствие(ВнутренниеДанные.Псевдонимы))); + + Для Каждого Соединение Из Соединения Цикл + // Условие разбирается универсально (по максимуму возможностей) + // после чего устанавливаются ошибки на запрещенные возможности. + РазобратьСоединение(Соединение, СвойстваЧасти, ВнутренниеДанные); + КонецЦикла; + + // Продолжение разбора после заполнения псевдонимов всех дополнительных таблиц. + Для Каждого ОписаниеСоединения Из СвойстваЧасти.Состав Цикл + ВнутренниеДанные.ДоступныеПсевдонимы.Вставить(ВРег(ОписаниеСоединения.Псевдоним), Истина); + // Допустимы только простые условия: + // Поле1 = Поле2 [И Поле3 = Поле4] [И Поле5 = Константа]. + РазобратьПоляУсловияСоединенияИОтметитьЗапреты(ОписаниеСоединения, ВнутренниеДанные); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьДополнительныеТаблицы. +// +// Параметры: +// Соединение - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьСоединение(Соединение, СвойстваЧасти, ВнутренниеДанные) + + ОписаниеСоединения = НовоеОписаниеСоединения(); + ОписаниеСоединения.Вставить("Таблица", ""); + ОписаниеСоединения.Вставить("Псевдоним", ""); + ОписаниеСоединения.Вставить("УсловиеСоединения", Неопределено); + + Если Соединение[0].Вид <> "КлючевоеСлово" + Или Соединение[0].Уточнение <> "Левое" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 0, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'Нет ключевого слова ""%1""'"), "Левое")); + + Если Соединение[0].Вид <> "КлючевоеСлово" + Или Соединение[0].Уточнение <> "Внутреннее" + И Соединение[0].Уточнение <> "Полное" Тогда + + Возврат; + КонецЕсли; + КонецЕсли; + + Если Соединение.Количество() < 2 + Или Соединение[1].Вид <> "КлючевоеСлово" + Или Соединение[1].Уточнение <> "Соединение" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 1, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет ключевого слова ""%2""'"), + Соединение[0].Символы, + КлючевоеСловоСУчетомЯзыка("Соединение", ВнутренниеДанные))); + Возврат; + КонецЕсли; + + Если Соединение.Количество() < 3 + Или Соединение[2].Вид <> "Имя" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 2, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет имени таблицы'"), + Соединение[1].Символы)); + Возврат; + КонецЕсли; + + УстановитьИмяТаблицы(Соединение[2], ОписаниеСоединения, ВнутренниеДанные); + + Если Соединение.Количество() < 4 + Или Соединение[3].Вид <> "КлючевоеСлово" + Или Соединение[3].Уточнение <> "Как" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 3, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После имени таблицы нет ключевого слова ""%1""'"), "Как")); + Возврат; + КонецЕсли; + + Если Соединение.Количество() < 5 + Или Соединение[4].Вид <> "Имя" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 4, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%1"" нет псевдонима таблицы'"), "Как")); + Возврат; + КонецЕсли; + + УстановитьПсевдоним(Соединение[4], ОписаниеСоединения, ВнутренниеДанные); + + Если Соединение.Количество() < 6 + Или Соединение[5].Вид <> "КлючевоеСлово" + Или Соединение[5].Уточнение <> "По" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 5, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После псевдонима таблицы нет ключевого слова ""%1""'"), "По")); + Возврат; + КонецЕсли; + + Условие = Новый Массив(Новый ФиксированныйМассив(Соединение)); + Для Индекс = 0 По 5 Цикл + Условие.Удалить(0); + КонецЦикла; + + РазобратьУсловие(Условие, ОписаниеСоединения.УсловиеСоединения, ВнутренниеДанные); + + СвойстваЧасти.Состав.Добавить(ОписаниеСоединения); + +КонецПроцедуры + +// Для процедуры РазобратьДополнительныеТаблицы. +Процедура РазобратьПоляУсловияСоединенияИОтметитьЗапреты(ОписаниеСоединения, ВнутренниеДанные) + + // Отметка некорректных аргументов операций и запрещенных возможностей. + ОбщиеУзлы = Новый Соответствие(УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( + "Поле,Значение,Константа,И,=", Ложь)); + + ОбщиеУзлы.Вставить("Поле", Новый Структура("Выразить, Вложение, ЕстьNull", Ложь, Ложь, Ложь)); + + ДоступныеУзлы = Новый Структура; + ДоступныеУзлы.Вставить("Общие", ОбщиеУзлы); + ДоступныеУзлы.Вставить("УзлыКогда", ОбщиеУзлы); + ДоступныеУзлы.Вставить("УзлыТогдаИначе", ОбщиеУзлы); + + Контекст = РасширенныеВнутренниеДанные(ВнутренниеДанные); + Контекст.Вставить("ЭтоУсловиеСоединения", Истина); + Контекст.Вставить("ЭтоУсловиеКогда", Ложь); + Контекст.Вставить("ЭтоЗначениеТогдаИначе", Ложь); + Контекст.Вставить("КорневойУзел", ОписаниеСоединения.УсловиеСоединения); + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(ОписаниеСоединения.УсловиеСоединения, + ДоступныеУзлы, Контекст); + + УдалитьСвойствоИсточник(ОписаниеСоединения.УсловиеСоединения); + +КонецПроцедуры + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +// +// Параметры: +// Список - Строка - список имен узлов через запятую. +// ЭтоСписокИсключений - Булево - если Истина, добавить узлы, кроме указанных. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - имя узла +// * Значение - Булево +// - Структура: +// ** Выразить - Булево +// ** Вложение - Булево +// ** ЕстьNull - Булево +// +Функция УзлыДляПроверкиДоступности(Список, ЭтоСписокИсключений) Экспорт + + ВсеУзлы = Новый Соответствие; + ВсеУзлы.Вставить("Поле", Новый Структура("Выразить, Вложение, ЕстьNull", Истина, Истина, Истина)); + ВсеУзлы.Вставить("Значение", Истина); + ВсеУзлы.Вставить("Константа", Истина); + ВсеУзлы.Вставить("И", Истина); + ВсеУзлы.Вставить("Или", Истина); + ВсеУзлы.Вставить("Не", Истина); + ВсеУзлы.Вставить("=", Истина); + ВсеУзлы.Вставить("<>", Истина); + ВсеУзлы.Вставить("В", Истина); + ВсеУзлы.Вставить("ЕстьNull", Истина); + ВсеУзлы.Вставить("Тип", Истина); + ВсеУзлы.Вставить("ТипЗначения", Истина); + ВсеУзлы.Вставить("Выбор", Истина); + ВсеУзлы.Вставить("ЗначениеРазрешено", Истина); + ВсеУзлы.Вставить("ЭтоАвторизованныйПользователь", Истина); + ВсеУзлы.Вставить("ЧтениеОбъектаРазрешено", Истина); + ВсеУзлы.Вставить("ИзменениеОбъектаРазрешено", Истина); + ВсеУзлы.Вставить("ЧтениеСпискаРазрешено", Истина); + ВсеУзлы.Вставить("ИзменениеСпискаРазрешено", Истина); + ВсеУзлы.Вставить("ДляВсехСтрок", Истина); + ВсеУзлы.Вставить("ДляОднойИзСтрок", Истина); + ВсеУзлы.Вставить("ПравоДоступа", Истина); + ВсеУзлы.Вставить("РольДоступна", Истина); + + МассивУзлов = СтрРазделить(Список, ",", Ложь); + Узлы = Новый Соответствие; + + Для Каждого Узел Из ВсеУзлы Цикл + Если ЭтоСписокИсключений Тогда + Если МассивУзлов.Найти(Узел.Ключ) = Неопределено Тогда + Узлы.Вставить(Узел.Ключ, Узел.Значение); + КонецЕсли; + Иначе + Если МассивУзлов.Найти(Узел.Ключ) <> Неопределено Тогда + Узлы.Вставить(Узел.Ключ, Узел.Значение); + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Возврат Новый ФиксированноеСоответствие(Узлы); + +КонецФункции + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +// +// Параметры: +// Условие - см. ОписаниеУзла +// ДоступныеУзлы - Структура +// Контекст - см. РасширенныеВнутренниеДанные +// Родитель - см. ОписаниеУзла +// +Процедура ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие, ДоступныеУзлы, Контекст, Родитель = Неопределено) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат; + КонецЕсли; + + Если Контекст.ЭтоУсловиеКогда Тогда + ТекущиеДоступныеУзлы = ДоступныеУзлы.УзлыКогда; + + ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда + ТекущиеДоступныеУзлы = ДоступныеУзлы.УзлыТогдаИначе; + Иначе + ТекущиеДоступныеУзлы = ДоступныеУзлы.Общие; + КонецЕсли; + + ДоступностьУзла = ТекущиеДоступныеУзлы.Получить(Условие.Узел); + + Если ДоступностьУзла = Неопределено Тогда + УстановитьОшибкуУзелЗапрещен(Условие.Источник, Контекст); + КонецЕсли; + + Если Условие.Узел = "Поле" Тогда + + Если Не Контекст.ЭтоУсловиеСоединения Тогда + ПолеКлючаДоступа = НовоеПолеКлючаДоступа(); + ПолеКлючаДоступа.Вставить("Поле", Условие); + ПолеКлючаДоступа.Вставить("Чтение", Контекст.Чтение); + ПолеКлючаДоступа.Вставить("Изменение", Контекст.Изменение); + Контекст.ПоляКлючаДоступа.Добавить(ПолеКлючаДоступа); + КонецЕсли; + + ВыделитьПсевдонимПоля(Условие, Контекст); + + Если Не ДоступностьУзла.Выразить + И Условие.Выразить <> Неопределено Тогда + + УстановитьОшибкуУзелЗапрещен(Условие.Источник, Контекст); + + ИначеЕсли Не ДоступностьУзла.Вложение + И Условие.Вложение <> Неопределено Тогда + + УстановитьОшибкуУзелЗапрещен(Условие.Вложение.Источник, Контекст); + + ИначеЕсли Не ДоступностьУзла.ЕстьNull + И Условие.ЕстьNull <> Неопределено Тогда + + УстановитьОшибкуУзелЗапрещен(Условие.ЕстьNullИсточник, Контекст); + КонецЕсли; + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + Для Каждого Аргумент Из Условие.Аргументы Цикл + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Аргумент, ДоступныеУзлы, Контекст); + КонецЦикла; + + ИначеЕсли Условие.Узел = "Не" + Или Условие.Узел = "ЕстьNull" + Или Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + // Проверка корректности параметра. + Если Условие.Узел = "ЕстьNull" + И ( Условие.Аргумент = Неопределено + Или Условие.Аргумент.Узел <> "Поле" ) Тогда + + УстановитьОшибкуВСтроке(Условие.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Операция ""%1"" допустима только после поля'"), + Условие.Источник.Символы)); + КонецЕсли; + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Аргумент, ДоступныеУзлы, Контекст); + + ИначеЕсли Условие.Узел = "=" + Или Условие.Узел = "<>" Тогда + + СочетанияУзлов = Новый Соответствие; + СочетанияУзлов.Вставить("Значение", ",Поле,"); + СочетанияУзлов.Вставить("Константа", ",Поле,Константа,"); + + Если Контекст.ЭтоУсловиеСоединения Тогда + СочетанияУзлов.Вставить("Поле", ",Поле,Значение,Константа,"); + Иначе + СочетанияУзлов.Вставить("Поле", ",Значение,Константа,"); + СочетанияУзлов.Вставить("Тип", ",ТипЗначения,"); + СочетанияУзлов.Вставить("ТипЗначения", ",Тип,"); + КонецЕсли; + + СочетанияПервогоАргумента = СочетанияУзлов.Получить(Условие.ПервыйАргумент.Узел); + СочетанияВторогоАргумента = СочетанияУзлов.Получить(Условие.ВторойАргумент.Узел); + + ОшибкаВПервомАргументе = СочетанияПервогоАргумента = Неопределено; + ОшибкаВоВторомАргументе = СочетанияВторогоАргумента = Неопределено + Или СочетанияПервогоАргумента <> Неопределено + И СтрНайти(СочетанияПервогоАргумента, "," + Условие.ВторойАргумент.Узел + ",") = 0; + + Если ОшибкаВПервомАргументе Или ОшибкаВоВторомАргументе Тогда + Если Контекст.ЭтоУсловиеСоединения Тогда + ТекстОшибки = + НСтр("ru = 'Операция ""%1"" допустима только для поля с полем, значением или константой'"); + Иначе + ТекстОшибки = + НСтр("ru = 'Операция ""%1"" допустима только для поля со значением или константой, + |а также для типа значения с типом'"); + КонецЕсли; + Если ОшибкаВПервомАргументе Тогда + УсловиеПервыйАргумент = Условие.ПервыйАргумент; // См. ОписаниеУзла + УстановитьОшибкуВСтроке(УсловиеПервыйАргумент.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ТекстОшибки, Условие.Источник.Символы), + Истина); + КонецЕсли; + Если ОшибкаВоВторомАргументе Тогда + УсловиеВторойАргумент = Условие.ВторойАргумент; // См. ОписаниеУзла + УстановитьОшибкуВСтроке(УсловиеВторойАргумент.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ТекстОшибки, Условие.Источник.Символы)); + КонецЕсли; + КонецЕсли; + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.ПервыйАргумент, ДоступныеУзлы, Контекст, Условие); + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.ВторойАргумент, ДоступныеУзлы, Контекст, Условие); + + ИначеЕсли Условие.Узел = "В" Тогда + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Искомое, ДоступныеУзлы, Контекст); + Для Каждого Значение Из Условие.Значения Цикл + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Значение, ДоступныеУзлы, Контекст); + КонецЦикла; + + ИначеЕсли Условие.Узел = "ТипЗначения" + Или Условие.Узел = "Тип" Тогда + + Если Родитель = Неопределено + Или Родитель.Узел <> "=" + И Родитель.Узел <> "<>" Тогда + + УстановитьОшибкуВСтроке(Условие.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Функция ""%1"" допустима только в операциях ""="" и ""<>""'"), + Условие.Источник.Символы)); + КонецЕсли; + + Если Условие.Узел = "ТипЗначения" Тогда + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Аргумент, ДоступныеУзлы, Контекст); + КонецЕсли; + + ИначеЕсли Условие.Узел = "Выбор" Тогда + Если Условие.Выбор <> Неопределено Тогда + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Выбор, ДоступныеУзлы, Контекст); + КонецЕсли; + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(Контекст); + КонтекстКогда = Новый Структура(ФиксированныйКонтекст); + КонтекстКогда.ЭтоУсловиеКогда = Истина; + КонтекстТогдаИначе = Новый Структура(ФиксированныйКонтекст); + КонтекстТогдаИначе.ЭтоЗначениеТогдаИначе = Истина; + + Для Каждого Когда Из Условие.Когда Цикл + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Когда.Условие, ДоступныеУзлы, КонтекстКогда); + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Когда.Значение, ДоступныеУзлы, КонтекстТогдаИначе); + КонецЦикла; + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Иначе, ДоступныеУзлы, КонтекстТогдаИначе); + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Поле, ДоступныеУзлы, Контекст); + ОтметитьПовторыТиповСредиПроверяемыхИУточняемых(Условие, Контекст); + + // Добавление типов, наличие которых нужно проверить у полей. + Поле = Условие.Поле; // См. ОписаниеУзла + Уточнения = Новый Соответствие; + Для Каждого УточнениеСравнения Из Условие.УточненияСравнения Цикл + Если ТипЗнч(УточнениеСравнения.Ключ) <> Тип("СтрокаТаблицыЗначений") Тогда + Уточнения.Вставить(УточнениеСравнения.Ключ, УточнениеСравнения.Значение); + Продолжить; + КонецЕсли; + Уточнения.Вставить(УточнениеСравнения.Ключ.Символы, УточнениеСравнения.Значение); + ДобавитьТребуемоеПолеТаблицы(Контекст, Поле.Таблица, Поле.Имя, Поле.ИмяИсточник, + УточнениеСравнения.Ключ.Символы, УточнениеСравнения.Ключ); + КонецЦикла; + + // Удаление источников типов. + Условие.УточненияСравнения = Уточнения; + + Типы = Новый Массив; + Для Каждого Тип Из Условие.Типы Цикл + Типы.Добавить(Тип.Символы); + КонецЦикла; + Условие.Типы = Типы; + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Поле - см. ОписаниеУзла +// * Чтение - Булево +// * Родители - Массив из см. ОписаниеУзла +// +Функция НовоеПолеКлючаДоступа() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. +Процедура ВыделитьПсевдонимПоля(УзелПоле, Контекст) + + Если УзелПоле.Вложение <> Неопределено Тогда + Вложение = УзелПоле.Вложение; + ВыделитьПсевдонимПоля(Вложение, Контекст); + Если ЗначениеЗаполнено(Вложение.Выразить) Тогда + УзелПоле.Таблица = Вложение.Выразить; + КонецЕсли; + + ИначеЕсли Не ЗначениеЗаполнено(УзелПоле.Имя) Тогда + Возврат; + Иначе + СоставИмени = СтрРазделить(УзелПоле.Имя, "."); + Если СоставИмени.Количество() > 1 Тогда + Свойства = Контекст.Псевдонимы.Получить(ВРег(СоставИмени[0])); + Если Свойства <> Неопределено Тогда + УзелПоле.Псевдоним = Свойства.Псевдоним; + СоставИмени.Удалить(0); + УзелПоле.Имя = СтрСоединить(СоставИмени, "."); + Если ЗначениеЗаполнено(Свойства.Таблица) Тогда + УзелПоле.Таблица = Свойства.Таблица; + КонецЕсли; + КонецЕсли; + КонецЕсли; + Если Контекст.ЭтоУсловиеСоединения Тогда + Если Не ЗначениеЗаполнено(УзелПоле.Псевдоним) Тогда + УстановитьОшибкуВСтроке(УзелПоле.ИмяИсточник, + НСтр("ru = 'В условии соединения перед именем поля требуется псевдоним'")); + ИначеЕсли Контекст.ДоступныеПсевдонимы.Получить(ВРег(УзелПоле.Псевдоним)) = Неопределено Тогда + УстановитьОшибкуВСтроке(УзелПоле.ИмяИсточник, + НСтр("ru = 'Нельзя указывать псевдоним из следующего соединения'")); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, УзелПоле.Выразить, УзелПоле.ВыразитьИсточник); + КонецЕсли; + + ДобавитьТребуемоеПолеТаблицы(Контекст, УзелПоле.Таблица, УзелПоле.Имя, УзелПоле.ИмяИсточник, + УзелПоле.Выразить, УзелПоле.ВыразитьИсточник, УзелПоле); + +КонецПроцедуры + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +Процедура УдалитьСвойствоИсточник(Условие) + + Если ТипЗнч(Условие) = Тип("СтрокаТаблицыЗначений") Тогда + ТекстОшибки = НСтр("ru = 'Не все источники наборов символов удалены'"); + ВызватьИсключение ТекстОшибки; + + ИначеЕсли ТипЗнч(Условие) <> Тип("Структура") Тогда + Возврат; + КонецЕсли; + + Если Условие.Свойство("Источник") Тогда + Условие.Удалить("Источник"); + КонецЕсли; + + Если Условие.Свойство("ИмяИсточник") Тогда + Условие.Удалить("ИмяИсточник"); + КонецЕсли; + + Если Условие.Свойство("ВыразитьИсточник") Тогда + Условие.Удалить("ВыразитьИсточник"); + КонецЕсли; + + Если Условие.Свойство("ЕстьNullИсточник") Тогда + Условие.Удалить("ЕстьNullИсточник"); + КонецЕсли; + + Для Каждого КлючИЗначение Из Условие Цикл + Значение = КлючИЗначение.Значение; + + Если ТипЗнч(Значение) = Тип("Массив") Тогда + Для Каждого Элемент Из Значение Цикл + УдалитьСвойствоИсточник(Элемент); + КонецЦикла; + + ИначеЕсли ТипЗнч(Значение) = Тип("Соответствие") Тогда + Для Каждого КлючИЗначение Из Значение Цикл + УдалитьСвойствоИсточник(КлючИЗначение.Ключ); + УдалитьСвойствоИсточник(КлючИЗначение.Значение); + КонецЦикла; + Иначе + УдалитьСвойствоИсточник(Значение); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. +Процедура УстановитьОшибкуУзелЗапрещен(Строка, Контекст) + + Если Строка.Тип = "Функция" Тогда + Если Контекст.ЭтоУсловиеСоединения Тогда + ШаблонОшибки = НСтр("ru = 'Функция ""%1"" запрещена в условии соединения'"); + + ИначеЕсли Контекст.ЭтоУсловиеКогда Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Функция ""%3"" запрещена в условии ограничения в операции ""%1"" в предложении ""%2""'"), + "Выбор,Когда", Строка.Символы); + + ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Функция ""%4"" запрещена в условии ограничения в операции ""%1"" в предложениях ""%2"" и ""%3""'"), + "Выбор,Тогда,Иначе", Строка.Символы); + Иначе + ШаблонОшибки = НСтр("ru = 'Функция ""%1"" запрещена в условии ограничения'"); + КонецЕсли; + Иначе + Если Контекст.ЭтоУсловиеСоединения Тогда + ШаблонОшибки = НСтр("ru = 'Операция ""%1"" запрещена в условии соединения'"); + + ИначеЕсли Контекст.ЭтоУсловиеКогда Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Операция ""%3"" запрещена в условии ограничения в операции ""%1"" в предложении ""%2""'"), + "Выбор,Когда", Строка.Символы); + + ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Операция ""%4"" запрещена в условии ограничения в операции ""%1"" в предложениях ""%2"" и ""%3""'"), + "Выбор,Тогда,Иначе", Строка.Символы); + Иначе + ШаблонОшибки = НСтр("ru = 'Операция ""%1"" запрещена в условии ограничения'"); + КонецЕсли; + КонецЕсли; + + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ШаблонОшибки, Строка.Символы)); + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. +Процедура ОтметитьПовторыТиповСредиПроверяемыхИУточняемых(Узел, Контекст) + + ТипыВСписке = Новый Соответствие; + + Для Каждого ТипВСписке Из Узел.Типы Цикл + Если ТипыВСписке.Получить(ВРег(ТипВСписке.Символы)) = Неопределено Тогда + ТипыВСписке.Вставить(ВРег(ТипВСписке.Символы), Истина); + Иначе + УстановитьОшибкуВСтроке(ТипВСписке, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Тип ""%1"" уже указан'"), ТипВСписке.Символы)); + КонецЕсли; + КонецЦикла; + + УточняемыеТипы = Новый Соответствие; + + Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл + Если ТипЗнч(УточнениеСравнения.Ключ) <> Тип("СтрокаТаблицыЗначений") Тогда + Продолжить; + КонецЕсли; + ИсточникТипа = УточнениеСравнения.Ключ; + + Если Не Узел.ПроверятьТипыКромеУказанных + И ТипыВСписке.Получить(ВРег(ИсточникТипа.Символы)) <> Неопределено Тогда + + УстановитьОшибкуВСтроке(ИсточникТипа, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Тип ""%2"" уже указан среди типов ключевого слова ""%1""'"), + "Только", + ИсточникТипа.Символы)); + + ИначеЕсли Узел.ПроверятьТипыКромеУказанных + И ТипыВСписке.Получить(ВРег(ИсточникТипа.Символы)) = Неопределено Тогда + + УстановитьОшибкуВСтроке(ИсточникТипа, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Тип ""%2"" не указан среди типов ключевого слова ""%1""'"), + "Кроме", + ИсточникТипа.Символы)); + + ИначеЕсли УточняемыеТипы.Получить(ВРег(ИсточникТипа.Символы)) <> Неопределено Тогда + УстановитьОшибкуВСтроке(ИсточникТипа, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Уточнение типа ""%1"" уже указано'"), ИсточникТипа.Символы)); + Иначе + УточняемыеТипы.Вставить(ВРег(ИсточникТипа.Символы), Истина); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьЧастьОграничения. +// +// Параметры: +// СвойстваЧасти - см. НовыеСвойстваЧасти +// ВнутренниеДанные - см. НовыеВнутренниеДанные +// +Процедура РазобратьУсловиеОграничения(СвойстваЧасти, ВнутренниеДанные) + + СтрокиЧасти = СвойстваЧасти.Строки; + ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти); + + Если СтрокиЧасти.Количество() < 2 + Или СтрокиЧасти[1].Вид <> "КлючевоеСлово" + Или СтрокиЧасти[1].Уточнение <> "Где" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 2, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[1]), + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет + |ключевого слова ""%2""'"), + СвойстваЧасти.Представление, + КлючевоеСловоСУчетомЯзыка("Где", ВнутренниеДанные))); + Возврат; + КонецЕсли; + + Условие = Новый Массив(Новый ФиксированныйМассив(СтрокиЧасти)); + Для Индекс = 0 По 1 Цикл + Условие.Удалить(0); + КонецЦикла; + + РазобратьУсловие(Условие, СвойстваЧасти.Состав, ВнутренниеДанные); + + // Отметка некорректных параметров операций и неподдерживаемого функционала. + ОбщиеУзлы = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности("", Истина); + + УзлыКогда = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( + "Поле,Значение,Константа,И,Или,Не,=,<>,В,ЕстьNull,Тип,ТипЗначения", Ложь); + + УзлыТогдаИначе = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( + "Выбор,ДляВсехСтрок,ДляОднойИзСтрок", Истина); + + ДоступныеУзлы = Новый Структура; + ДоступныеУзлы.Вставить("Общие", ОбщиеУзлы); + ДоступныеУзлы.Вставить("УзлыКогда", УзлыКогда); + ДоступныеУзлы.Вставить("УзлыТогдаИначе", УзлыТогдаИначе); + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ВнутренниеДанные); + Контекст = Новый Структура(ФиксированныйКонтекст); + Контекст.Вставить("ЭтоУсловиеСоединения", Ложь); + Контекст.Вставить("ЭтоУсловиеКогда", Ложь); + Контекст.Вставить("ЭтоЗначениеТогдаИначе", Ложь); + Контекст.Вставить("КорневойУзел", СвойстваЧасти.Состав); + Контекст.Вставить("Чтение", + СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" + Или СвойстваЧасти.Имя = "РазрешитьЧтение"); + Контекст.Вставить("Изменение", + СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" + Или СвойстваЧасти.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение"); + + ДобавитьПсевдонимыПоУмолчанию(Контекст); + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(СвойстваЧасти.Состав, ДоступныеУзлы, Контекст); + + УдалитьСвойствоИсточник(СвойстваЧасти.Состав); + +КонецПроцедуры + +// Для процедур ЧастиОграничения, РазобратьУсловиеОграничения. +Процедура ДобавитьПсевдонимыПоУмолчанию(Контекст); + + Если Контекст.Псевдонимы.Количество() > 0 Тогда + Возврат; + КонецЕсли; + + Контекст.Псевдонимы.Вставить(ВРег("ЭтотСписок"), Новый Структура("Псевдоним, Таблица", "ЭтотСписок")); + Контекст.Псевдонимы.Вставить(ВРег("ThisList"), Новый Структура("Псевдоним, Таблица", "ThisList")); + +КонецПроцедуры + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +// +// Параметры: +// Условие - Массив из СтрокаТаблицыЗначений +// Состав - см. ОписаниеУзла +// ВнутренниеДанные - см. НовыеВнутренниеДанные +// +Процедура РазобратьУсловие(Условие, Состав, ВнутренниеДанные) + + ВыраженияВСкобкахВоВложениях = ВыраженияВСкобкахВоВложениях(Условие, ВнутренниеДанные); + + ФункцииСВыражениямиВСкобках = ФункцииСВыражениямиВСкобках( + ВыраженияВСкобкахВоВложениях, ВнутренниеДанные); + + ВыраженияВыборКогдаТогдаВоВложениях = ВыраженияВыборКогдаТогдаВоВложениях( + ФункцииСВыражениямиВСкобках, ВнутренниеДанные); + + Условие = ВыраженияВыборКогдаТогдаВоВложениях; + + РазобратьВыражение(Условие, Состав, ВнутренниеДанные, Ложь); + + ОбъединитьВложенныеЛогическиеОперации(Состав); + +КонецПроцедуры + +// Для процедуры РазобратьУсловие. +Процедура ОбъединитьВложенныеЛогическиеОперации(Состав) + + Если Состав = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Состав.Узел = "И" + Или Состав.Узел = "Или" Тогда + + Индекс = Состав.Аргументы.Количество() - 1; + Пока Индекс >= 0 Цикл + + Аргумент = Состав.Аргументы[Индекс]; + ОбъединитьВложенныеЛогическиеОперации(Аргумент); + + Если Аргумент.Узел = Состав.Узел Тогда + Состав.Аргументы.Удалить(Индекс); + ВложенныйИндекс = Аргумент.Аргументы.Количество() - 1; + Пока ВложенныйИндекс >= 0 Цикл + Состав.Аргументы.Вставить(Индекс, Аргумент.Аргументы[ВложенныйИндекс]); + ВложенныйИндекс = ВложенныйИндекс - 1; + КонецЦикла; + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + + +// Для процедур РазобратьУсловие, РазобратьФункцию, РазобратьВыбор. +// +// Параметры: +// Условие - Массив из см. СтрокаТаблицы.ОписаниеСтроки +// +Процедура РазобратьВыражение(Условие, Состав, ТекущийКонтекст, ВложенноеВыражение = Истина) + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ТекущийКонтекст); + Контекст = Новый Структура(ФиксированныйКонтекст); + Контекст.Вставить("Вложения", Новый Массив); + Контекст.Вставить("Описание"); + Контекст.Вставить("Строка"); + + Для Каждого ОписаниеСтроки Из Условие Цикл + Строка = СтрокаТаблицы(ОписаниеСтроки, ТекущийКонтекст); + Контекст.Строка = Строка; + + Если Строка.Вид = "Имя" + Или Строка.Вид = "Число" + Или Строка.Вид = "ПроизвольнаяСтрока" + Или Строка.Вид = "КлючевоеСлово" + И ( Строка.Уточнение = "Истина" + Или Строка.Уточнение = "Ложь" + Или Строка.Уточнение = "Неопределено" ) Тогда + + НовоеОписание = ОписаниеУзлаПолеИлиУзлаКонстанта(Строка); + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + + ИначеЕсли Строка.Вид = "КлючевоеСлово" Тогда + + Если Строка.Тип = "Функция" + Или Строка.Уточнение = "В" Тогда + + Если Строка.Тип = "Функция" Тогда + РазобратьФункцию(Контекст); + Иначе + РазобратьСоединительВ(Контекст); + КонецЕсли; + + ИначеЕсли Строка.Тип = "Соединитель" Тогда + РазобратьСоединитель(Контекст); + + ИначеЕсли Строка.Тип = "Оператор" Тогда + РазобратьОператор(Контекст); + + ИначеЕсли Строка.Тип = "СловоВыбора" Тогда + РазобратьВыбор(Контекст); + Иначе + РазобратьОшибочноеКлючевоеСлово(Контекст); + КонецЕсли; + + ИначеЕсли Строка.Вид = "Операция" Тогда + РазобратьСоединитель(Контекст, Истина); + + ИначеЕсли Строка.Вид = "Разделитель" Тогда + Если Строка.Символы = "(" Тогда + НовоеОписание = Неопределено; // См. ОписаниеУзла + РазобратьВыражение(Строка.Строки, НовоеОписание, Контекст); + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + Если НовоеОписание <> Неопределено Тогда + НовоеОписание.Источник.Приоритет = 99; + КонецЕсли; + Иначе + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, + НСтр("ru = 'Запятая может использоваться только для разделения параметров функций'")); + КонецЕсли; + Иначе + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); + КонецЕсли; + + Если Контекст.Описание = Неопределено Тогда + // Возникала ошибка, останавливающая дальнейший разбор (предотвращение ложных срабатываний). + Прервать; + КонецЕсли; + КонецЦикла; + + Если Контекст.Описание = Неопределено Тогда + Если ВложенноеВыражение Тогда + Состав = Новый Структура("Источник, Узел, Значение", Строка, "Константа", Ложь); + Иначе + Состав = Неопределено; + КонецЕсли; + + ИначеЕсли Контекст.Вложения.Количество() = 0 Тогда + Состав = Контекст.Описание; + Иначе + Состав = Контекст.Вложения[Контекст.Вложения.Количество() - 1]; + КонецЕсли; + +КонецПроцедуры + +// Для процедур РазобратьВыражение, РазобратьПервыйПараметрПроверочнойФункции, +// РазобратьПараметрыФункцииТипЗначения, РазобратьВыбор и +// для функции ОписаниеУзлаПолеИзФункцииЕстьNull. +// +Функция ОписаниеУзлаПолеИлиУзлаКонстанта(Строка) + + // <Имя поля>, <Число>, <Произвольная строка>, Истина, Ложь, Неопределено. + + Если Строка.Вид = "Имя" Тогда + НовоеОписание = ОписаниеУзлаПоле(Строка); + НовоеОписание.Имя = Строка.Символы; + НовоеОписание.ИмяИсточник = Строка; + Иначе + СвойстваУзла = "Источник, Узел, Значение"; + НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Константа"); + + Если Строка.Вид = "КлючевоеСлово" Тогда + Если Строка.Уточнение = "Истина" Тогда + НовоеОписание.Значение = Истина; + + ИначеЕсли Строка.Уточнение = "Ложь" Тогда + НовоеОписание.Значение = Ложь; + + Иначе // Строка.Вид = "Неопределено". + НовоеОписание.Значение = Неопределено; + КонецЕсли; + Иначе // "Число" или "ПроизвольнаяСтрока". + НовоеОписание.Значение = Строка.Уточнение; + КонецЕсли; + КонецЕсли; + + Возврат НовоеОписание; + +КонецФункции + +// Для функций ОписаниеУзлаПолеИлиУзлаКонстанта, ОписаниеУзлаПолеИзФункцииВыразить, ОписаниеУзлаПолеИзФункцииЕстьNull. +Функция ОписаниеУзлаПоле(Строка) + + СвойстваУзла = "Источник, Узел, Имя, Таблица, Псевдоним, Выразить, Вложение, ЕстьNull"; + НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Поле"); + + НовоеОписание.Вставить("ИмяИсточник", Неопределено); + НовоеОписание.Вставить("ВыразитьИсточник", Неопределено); + НовоеОписание.Вставить("ЕстьNullИсточник", Неопределено); + + Возврат НовоеОписание; + +КонецФункции + +// Для процедуры РазобратьВыражение. +Процедура РазобратьСоединитель(Контекст, ЭтоОперация = Ложь) + + // И, Или, Как, Кроме, Только, Есть и любая операция =, <>, ... + // Ключевое слово В разбирается отдельно в процедуре "РазобратьСоединительВ". + + Строка = Контекст.Строка; // СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов + + НовоеОписание = Новый Структура("Источник, Узел", Строка, + ?(Строка.Вид = "Операция", Строка.Символы, Строка.Уточнение)); + + Если Строка.Уточнение = "И" + Или Строка.Уточнение = "Или" Тогда + + НовоеОписание.Вставить("Аргументы", Новый Массив); + НовоеОписание.Аргументы.Добавить(Неопределено); + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Аргументы[0]); + + ИначеЕсли Строка.Уточнение = "Есть" Тогда + НовоеОписание.Узел = "ЕстьNull"; + НовоеОписание.Вставить("Аргумент", Неопределено); + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Аргумент); + // Проверка корректности параметров выполняется + // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. + + ИначеЕсли Строка.Вид = "Операция" Тогда + НовоеОписание.Вставить("ПервыйАргумент", Неопределено); + НовоеОписание.Вставить("ВторойАргумент", Неопределено); + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.ПервыйАргумент); + // Проверка корректности аргументов выполняется + // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. + + ИначеЕсли Строка.Уточнение = "Как" + Или Строка.Уточнение = "Кроме" + Или Строка.Уточнение = "Только" Тогда + + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ключевое слово ""%1"" может использоваться только в параметрах функций'"), Строка.Символы)); + Иначе + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьВыражение. +Процедура РазобратьСоединительВ(Контекст) + + Строка = Контекст.Строка; + + НовоеОписание = Новый Структура("Источник, Узел", Строка, Строка.Уточнение); + НовоеОписание.Вставить("Искомое", Неопределено); + НовоеОписание.Вставить("Значения", Новый Массив); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + + Для Каждого ОписаниеПараметра Из СоставПараметров Цикл + СтрокиОписанияПараметра = ОписаниеПараметра.Строки; // Массив Из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + Для Каждого Подстрока Из СтрокиОписанияПараметра Цикл + + РазобратьЗначениеСоединителяВ(Контекст, Подстрока, НовоеОписание); + + Если ОписаниеПараметра.Строки[0] <> Подстрока Тогда + УстановитьОшибкуВСтроке(Подстрока, НСтр("ru = 'Перед параметром не указана запятая'")); + КонецЕсли; + + КонецЦикла; + КонецЦикла; + + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Искомое); + + Если НовоеОписание.Искомое.Узел <> "Поле" Тогда + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Операцию ""%1"" можно указывать только после имени поля'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьСоединительВ. +Процедура РазобратьЗначениеСоединителяВ(Контекст, Подстрока, НовоеОписание) + + Строка = Контекст.Строка; + + Если Подстрока.Вид = "Число" + Или Подстрока.Вид = "ПроизвольнаяСтрока" Тогда + + ОписаниеКонстанты = Новый Структура("Источник, Узел", Подстрока, "Константа"); + ОписаниеКонстанты.Вставить("Значение", Подстрока.Уточнение); + НовоеОписание.Значения.Добавить(ОписаниеКонстанты); + + ИначеЕсли Подстрока.Вид = "КлючевоеСлово" Тогда + + Если Подстрока.Уточнение = "Значение" Тогда + НовыйКонтекст = НовыйКонтекст(Контекст, Подстрока, Неопределено); + РазобратьФункцию(НовыйКонтекст); + Если НовыйКонтекст.Описание <> Неопределено Тогда + НовоеОписание.Значения.Добавить(НовыйКонтекст.Описание); + КонецЕсли; + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" ключевое слово ""%2"" недопустимо'"), + Строка.Символы, Подстрока.Символы)); + КонецЕсли; + + ИначеЕсли Подстрока.Вид = "Имя" Тогда + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" имя поля недопустимо'"), Строка.Символы)); + + ИначеЕсли Подстрока.Символы = "(" Тогда + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" скобки допустимы только для параметров функции'"), Строка.Символы)); + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" можно указывать только значения'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьЗначениеСоединителяВ. +Функция НовыйКонтекст(Контекст, Строка = null, Описание = null) + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(Контекст); + НовыйКонтекст = Новый Структура(ФиксированныйКонтекст); + + Если Строка <> null Тогда + НовыйКонтекст.Строка = Строка; + КонецЕсли; + + Если Описание <> null Тогда + НовыйКонтекст.Описание = Описание; + КонецЕсли; + + Возврат НовыйКонтекст; + +КонецФункции + +// Для процедур РазобратьСоединитель, РазобратьСоединительВ, ВставитьСоединительСУчетомПриоритета. +Процедура ДобавитьСоединитель(Контекст, НовоеОписание, ПервыйАргумент); + + // Добавляемый соединитель: И, Или, В, Есть и любая операция (=, <>, ...). + + Описание = Контекст.Описание; // См. ОписаниеУзла + + Если Описание = Неопределено Тогда + Контекст.Описание = НовоеОписание; + + ИначеЕсли Описание.Узел = "И" + Или Описание.Узел = "Или" Тогда + + Если Описание.Аргументы.Количество() = 1 Тогда + Описание.Аргументы.Добавить(Неопределено); + ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.Аргументы[1]); + КонецЕсли; + ВставитьСоединительСУчетомПриоритета(Контекст, + Описание.Аргументы[1], НовоеОписание, ПервыйАргумент); + + ИначеЕсли Описание.Узел = "Не" Тогда + Если Не ЗначениеЗаполнено(Описание.Аргумент) Тогда + ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.Аргумент); + КонецЕсли; + ВставитьСоединительСУчетомПриоритета(Контекст, + Описание.Аргумент, НовоеОписание, ПервыйАргумент); + + ИначеЕсли Описание.Источник.Вид = "Операция" Тогда + Если Не ЗначениеЗаполнено(Описание.ВторойАргумент) Тогда + ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.ВторойАргумент, Ложь); + КонецЕсли; + ВставитьСоединительСУчетомПриоритета(Контекст, + Описание.ВторойАргумент, НовоеОписание, ПервыйАргумент); + + ИначеЕсли СтрНайти(",Поле,Значение,Константа,В,ЕстьNull,Выбор,", "," + Описание.Узел + ",") > 0 + Или Описание.Источник.Тип = "Функция" Тогда + // Второй аргумент операции В уже разобран в процедуре РазобратьСоединительВ. + // Второй аргумент Null операции Есть уже разобран в функции ФункцииСВыражениямиВСкобках. + // Остальные узлы не имеют второго аргумента. + ВставитьСоединительСУчетомПриоритета(Контекст, Неопределено, НовоеОписание, ПервыйАргумент); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка узла ""%1""'"), Описание.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьСоединитель. +Процедура ОбработатьПропущенныйАргументПослеСоединителя(Контекст, ВторойАргумент, ЛогическаяОперация = Истина) + + Описание = Контекст.Описание; // См. ОписаниеУзла + + УстановитьОшибкуВСтроке(Описание.Источник, + ?(ЛогическаяОперация, + НСтр("ru = 'Не указан аргумент после логической операции'"), + НСтр("ru = 'Не указан аргумент после операции'")), + Истина); + + ВторойАргумент = Новый Структура("Источник, Узел, Значение", Контекст.Строка, "Константа", Истина); + +КонецПроцедуры + +// Для процедур ДобавитьСоединитель, ОбработатьПропущеннуюЛогическуюОперацию. +Процедура ВставитьСоединительСУчетомПриоритета(Контекст, + ПоследнийАргументОписания, НовоеОписание, ПервыйАргументНовогоОписания) + + Вложения = Контекст.Вложения; + Описание = Контекст.Описание; // См. ОписаниеУзла + + Если ПоследнийАргументОписания <> Неопределено + И Контекст.Строка.Приоритет >= Описание.Источник.Приоритет Тогда + + // Замена аргумента текущего узла на соединитель (случай "А Или Б И ..."). + ПервыйАргументНовогоОписания = ПоследнийАргументОписания; + ПоследнийАргументОписания = НовоеОписание; + + Вложения.Вставить(0, Контекст.Описание); + Контекст.Описание = НовоеОписание; + Возврат; + КонецЕсли; + + Если Вложения.Количество() = 0 Тогда + // Вложение текущего узла, как первого аргумента соединителя (случай "А И Б Или ..."). + ПервыйАргументНовогоОписания = Контекст.Описание; + Контекст.Описание = НовоеОписание; + Возврат; + КонецЕсли; + + // Вложение предыдущего узла, как первого аргумента соединителя (случай "А И Не Б Или ..."). + Контекст.Описание = Вложения[0]; + Вложения.Удалить(0); + + ДобавитьСоединитель(Контекст, НовоеОписание, ПервыйАргументНовогоОписания); + +КонецПроцедуры + +// Для процедуры РазобратьВыражение. +Процедура РазобратьОператор(Контекст) + + // Оператор Не. + + НовоеОписание = Новый Структура("Источник, Узел, Аргумент", + Контекст.Строка, Контекст.Строка.Уточнение); + + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + + Контекст.Вложения.Вставить(0, Контекст.Описание); + Контекст.Описание = НовоеОписание; + +КонецПроцедуры + +// Для процедур РазобратьВыражение, РазобратьЗначениеСоединителяВ. +Процедура РазобратьФункцию(Контекст) + + Строка = Контекст.Строка; + + НовоеОписание = Новый Структура("Источник, Узел", Строка, Строка.Уточнение); + + Если Строка.Уточнение = "ЗначениеРазрешено" + Или Строка.Уточнение = "ЧтениеОбъектаРазрешено" + Или Строка.Уточнение = "ИзменениеОбъектаРазрешено" + Или Строка.Уточнение = "ЧтениеСпискаРазрешено" + Или Строка.Уточнение = "ИзменениеСпискаРазрешено" + Или Строка.Уточнение = "ЭтоАвторизованныйПользователь" Тогда + + РазобратьПараметрыПроверочнойФункции(Контекст, НовоеОписание); + + ИначеЕсли Строка.Уточнение = "ДляВсехСтрок" + Или Строка.Уточнение = "ДляОднойИзСтрок" Тогда + + ОписаниеВыражения = Неопределено; + РазобратьВыражение(Строка.Строки, ОписаниеВыражения, Контекст); + НовоеОписание.Вставить("Аргумент", ОписаниеВыражения); + + ИначеЕсли Строка.Уточнение = "Значение" Тогда + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, Истина, Контекст); + + ИначеЕсли Строка.Уточнение = "Тип" Тогда + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, Ложь, Контекст); + + ИначеЕсли Строка.Уточнение = "ТипЗначения" Тогда + РазобратьПараметрыФункцииТипЗначения(Контекст, НовоеОписание); + + ИначеЕсли Строка.Уточнение = "ЕстьNull" Тогда + НовоеОписание = ОписаниеУзлаПолеИзФункцииЕстьNull(Контекст.Строка, Контекст); + + ИначеЕсли Строка.Уточнение = "Выразить" Тогда + НовоеОписание = ОписаниеУзлаПолеИзФункцииВыразить(Контекст.Строка, Контекст); + + ИначеЕсли Строка.Уточнение = "ПравоДоступа" Тогда + РазобратьПараметрыФункцииПравоДоступа(Строка, НовоеОписание, Контекст); + + ИначеЕсли Строка.Уточнение = "РольДоступна" Тогда + РазобратьПараметрыФункцииРольДоступна(Строка, НовоеОписание, Контекст); + + ИначеЕсли Не Строка.ЭтоРезерв Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка функции ""%1""'"), Строка.Уточнение); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыПроверочнойФункции(Контекст, НовоеОписание) + + Строка = Контекст.Строка; + + НовоеОписание.Вставить("Поле", Неопределено); + НовоеОписание.Вставить("Типы", Новый Массив); + НовоеОписание.Вставить("ПроверятьТипыКромеУказанных", Ложь); + НовоеОписание.Вставить("УточненияСравнения", Новый Соответствие); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + РазобратьПервыйПараметрПроверочнойФункции(Контекст, СоставПараметров[0], НовоеОписание); + + Для Индекс = 1 По СоставПараметров.Количество() - 1 Цикл + РазобратьДополнительныйПараметрПроверочнойФункции(Контекст, + СоставПараметров[Индекс], НовоеОписание); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыПроверочнойФункции. +// +// Параметры: +// ПервыйПараметр - Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьПервыйПараметрПроверочнойФункции(Контекст, ПервыйПараметр, НовоеОписание) + + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Поле = ОписаниеУзлаПолеИлиУзлаКонстанта(ПервыйПараметр.Строки[0]); + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "Выразить" Тогда + + НовоеОписание.Поле = ОписаниеУзлаПолеИзФункцииВыразить(ПервыйПараметр.Строки[0], Контекст); + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "ЕстьNull" Тогда + + НовоеОписание.Поле = ОписаниеУзлаПолеИзФункцииЕстьNull(ПервыйПараметр.Строки[0], Контекст); + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Первым параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), + "Выразить,ЕстьNull")); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 2 Тогда + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "Выразить" + И НовоеОписание.Поле.Вложение = Неопределено Тогда + + УстановитьОшибкуВСтроке(СтрокаТаблицы(ПервыйПараметр.Строки[0].КонечнаяСтрока, Контекст), + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После вложенной функции ""%3"" должно быть указано имя поля через точку, + |если в параметре функции ""%4"" используется ключевое слово ""%1"" или ""%2""'"), + "Только,Кроме", + ПервыйПараметр.Строки[0].Символы, + Контекст.Строка.Символы), + Истина); + КонецЕсли; + + Если ПервыйПараметр.Строки[1].Вид <> "КлючевоеСлово" + Или ( ПервыйПараметр.Строки[1].Уточнение <> "Только" + И ПервыйПараметр.Строки[1].Уточнение <> "Кроме" ) Тогда + + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После описания поля может быть указано, либо ключевое слово ""%1"", либо ""%2""'"), + "Только,Кроме")); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки[1].Уточнение = "Кроме" Тогда + НовоеОписание.ПроверятьТипыКромеУказанных = Истина; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" не указан тип (имя таблицы)'"), ПервыйПараметр.Строки[1].Символы)); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки[2].Вид <> "Имя" + И ПервыйПараметр.Строки[2].Символы <> "(" Тогда + + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[2], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" должен быть указан, либо тип (имя таблицы), либо список типов в скобках'"), + ПервыйПараметр.Строки[1].Символы)); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[3], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед параметром функции ""%1"" не указана запятая'"), Контекст.Строка.Символы)); + КонецЕсли; + + Если ПервыйПараметр.Строки[2].Вид = "Имя" Тогда + НовоеОписание.Типы.Добавить(ПервыйПараметр.Строки[2]); + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, ПервыйПараметр.Строки[2].Символы, ПервыйПараметр.Строки[2]); + Возврат; + КонецЕсли; + + СоставПараметров = ПараметрыРазделенныеЗапятыми(ПервыйПараметр.Строки[2], Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Для Каждого Параметр Из СоставПараметров Цикл + + Если Параметр.Строки[0].Вид = "Имя" + И Параметр.Строки.Количество() < 2 Тогда + + НовоеОписание.Типы.Добавить(Параметр.Строки[0]); + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[?(Параметр.Строки.Количество() < 2, 0, 1)], + НСтр("ru = 'В списке типов могут быть указаны только имена таблицы через запятую'")); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыПроверочнойФункции. +// +// Параметры: +// Параметр - Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьДополнительныйПараметрПроверочнойФункции(Контекст, Параметр, НовоеОписание) + + Если Параметр.Строки[0].Вид = "Имя" + Или Параметр.Строки[0].Вид = "КлючевоеСлово" + И ( Параметр.Строки[0].Тип = "ЗначениеСравнения" + Или Параметр.Строки[0].Тип = "ИмяТипа" ) Тогда + + Если Параметр.Строки[0].Вид = "Имя" Тогда + ЗначениеСравнения = Параметр.Строки[0]; + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, Параметр.Строки[0].Символы, Параметр.Строки[0]); + Иначе + ЗначениеСравнения = Параметр.Строки[0].Уточнение; + КонецЕсли; + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Дополнительным параметром может быть тип (имя таблицы), + |""%1"", ""%2"", ""%3"", ""%4"", ""%5"", ""%6"" и ""%7""'"), + "ПустаяСсылка,Неопределено,Null,Число,Строка,Дата,Булево")); + Возврат; + КонецЕсли; + + Если Параметр.Строки.Количество() < 2 Тогда + Если Параметр.Строки[0].Вид = "Имя" Тогда + Шаблон = НСтр("ru = 'После типа (имени таблицы) ""%2"" должно быть указано ключевое слово ""%1""'"); + Иначе + Шаблон = НСтр("ru = 'После ключевого слова ""%2"" должно быть указано ключевое слово ""%1""'"); + КонецЕсли; + УстановитьОшибкуВСтроке(Параметр.Строки[0], ПодставитьКлючевыеСловаВСтроку(Контекст, + Шаблон, "Как", Параметр.Строки[0].Символы), + Истина); + Возврат; + КонецЕсли; + + Если Параметр.Строки[1].Вид <> "КлючевоеСлово" + Или Параметр.Строки[1].Уточнение <> "Как" Тогда + + Если Параметр.Строки[0].Вид = "Имя" Тогда + Шаблон = НСтр("ru = 'После типа (имени таблицы) ""%2"" должно быть указано ключевое слово ""%1""'"); + Иначе + Шаблон = НСтр("ru = 'После ключевого слова ""%2"" должно быть указано ключевое слово ""%1""'"); + КонецЕсли; + УстановитьОшибкуВСтроке(Параметр.Строки[1], ПодставитьКлючевыеСловаВСтроку(Контекст, + Шаблон, "Как", Параметр.Строки[0].Символы)); + Возврат; + КонецЕсли; + + Если Параметр.Строки.Количество() < 3 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%4"" не указано значение уточнения ""%1"", ""%2"" или ""%3""'"), + "Ложь,Истина,Пусто", + Параметр.Строки[1].Символы), + Истина); + Возврат; + КонецЕсли; + + Если Параметр.Строки[2].Вид <> "КлючевоеСлово" + Или Параметр.Строки[2].Тип <> "ЗначениеУточнения" Тогда + + УстановитьОшибкуВСтроке(Параметр.Строки[2], ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%4"" должно быть указано значение уточнения ""%1"", ""%2"" или ""%3""'"), + "Ложь,Истина,Пусто", + Параметр.Строки[1].Символы)); + Иначе + НовоеОписание.УточненияСравнения.Вставить(ЗначениеСравнения, Параметр.Строки[2].Уточнение); + КонецЕсли; + + Если Параметр.Строки.Количество() > 3 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[3], + НСтр("ru = 'Перед параметром не указана запятая или лишний параметр'")); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, ЭтоФункцияЗначение, Контекст) + + НовоеОписание.Вставить("Имя", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Параметр = СоставПараметров[0]; + Если Параметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Имя = Параметр.Строки[0].Символы; + + Если ЭтоФункцияЗначение Тогда + ДобавитьТребуемыйПредопределенныйЭлемент(Контекст, НовоеОписание.Имя, Параметр.Строки[0]); + Иначе + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, НовоеОписание.Имя, Параметр.Строки[0]); + КонецЕсли; + + ИначеЕсли ЭтоФункцияЗначение Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" можно указать только имя предопределенного значения'"), Строка.Символы)); + + ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Тип = "ИмяТипа" Тогда + + НовоеОписание.Имя = Параметр.Строки[0].Уточнение; + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'В функции ""%5"" можно указать имя таблицы или ""%1"", ""%2"", ""%3"" и ""%4""'"), + "Число,Строка,Дата,Булево", + Строка.Символы)); + КонецЕсли; + + Если Параметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииРольДоступна(Строка, НовоеОписание, Контекст) + + НовоеОписание.Вставить("ИмяРоли", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Параметр = СоставПараметров[0]; + Если Параметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.ИмяРоли = Параметр.Строки[0].Символы; + + ПроверитьИмяРоли(НовоеОписание.ИмяРоли, Параметр.Строки[0]); + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" можно указать только имя роли'"), Строка.Символы)); + КонецЕсли; + + Если Параметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииПравоДоступа(Строка, НовоеОписание, Контекст) + + НовоеОписание.Вставить("ИмяПрава", Неопределено); + НовоеОписание.Вставить("ПолноеИмяОбъектаМетаданных", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + ПервыйПараметр = СоставПараметров[0]; + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.ИмяПрава = ПервыйПараметр.Строки[0].Символы; + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" в первом параметре можно указать только имя права'"), Строка.Символы)); + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед параметром ""%1"" функции ""%2"" не указана запятая'"), + ПервыйПараметр.Строки[1].Символы, + Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() < 2 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" должно быть два параметра'"), Строка.Символы)); + Возврат; + КонецЕсли; + + ВторойПараметр = СоставПараметров[1]; + Если ВторойПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.ПолноеИмяОбъектаМетаданных = ВторойПараметр.Строки[0].Символы; + + ПроверитьИмяПраваОбъектаМетаданных(НовоеОписание.ИмяПрава, ПервыйПараметр.Строки[0], + НовоеОписание.ПолноеИмяОбъектаМетаданных, ВторойПараметр.Строки[0]); + Иначе + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" во втором параметре можно указать только полное имя объекта метаданных'"), + Строка.Символы)); + КонецЕсли; + + Если ВторойПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 2 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[2].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииТипЗначения(Контекст, НовоеОписание) + + Строка = Контекст.Строка; + НовоеОписание.Вставить("Аргумент", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Параметр = СоставПараметров[0]; + + Если Параметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Аргумент = ОписаниеУзлаПолеИлиУзлаКонстанта(Параметр.Строки[0]); + + ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Уточнение = "Выразить" Тогда + + НовоеОписание.Аргумент = ОписаниеУзлаПолеИзФункцииВыразить(Параметр.Строки[0], Контекст); + + ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Уточнение = "ЕстьNull" Тогда + + НовоеОписание.Аргумент = ОписаниеУзлаПолеИзФункцииЕстьNull(Параметр.Строки[0], Контекст); + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), + "Выразить,ЕстьNull")); + Возврат; + КонецЕсли; + + Если Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Уточнение = "Выразить" + И НовоеОписание.Аргумент.Вложение = Неопределено Тогда + + УстановитьОшибкуВСтроке(СтрокаТаблицы(Параметр.Строки[0].КонечнаяСтрока, Контекст), + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После вложенной функции ""%1"" должно быть указано имя поля через точку'"), + Параметр.Строки[0].Символы), + Истина); + КонецЕсли; + + Если Параметр.Строки.Количество() < 2 Тогда + Возврат; + КонецЕсли; + + Если Параметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедур РазобратьФункцию, РазобратьПервыйПараметрПроверочнойФункции, РазобратьПараметрыФункцииТипЗначения. +Функция ОписаниеУзлаПолеИзФункцииВыразить(Строка, Контекст) + + НовоеОписание = ОписаниеУзлаПоле(Строка); + + Если Строка.Строки.Количество() > 0 Тогда + ПоследняяСтрока = СтрокаТаблицы(Строка.Строки[Строка.Строки.Количество() - 1], Контекст); + Если ПоследняяСтрока.Тип = "ДополнениеКВыразить" Тогда + Строка.Строки.Удалить(Строка.Строки.Количество() - 1); + НовоеОписание.Имя = Сред(ПоследняяСтрока.Символы, 2); + НовоеОписание.ИмяИсточник = ПоследняяСтрока; + НовоеОписание.Вложение = ОписаниеУзлаПолеИзФункцииВыразить(Строка, Контекст); + Возврат НовоеОписание; + КонецЕсли; + КонецЕсли; + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + Возврат НовоеОписание; + КонецЕсли; + + ПервыйПараметр = СоставПараметров[0]; + + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Имя = ПервыйПараметр.Строки[0].Символы; + НовоеОписание.ИмяИсточник = ПервыйПараметр.Строки[0]; + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "Выразить" Тогда + + НовоеОписание.Вложение = ОписаниеУзлаПолеИзФункцииВыразить(ПервыйПараметр.Строки[0], Контекст); + Если НовоеОписание.Вложение.Вложение = Неопределено Тогда + УстановитьОшибкуВСтроке(СтрокаТаблицы(ПервыйПараметр.Строки[0].КонечнаяСтрока, Контекст), + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После вложенной функции ""%1"" должно быть указано имя поля через точку'"), + ПервыйПараметр.Строки[0].Символы), + Истина); + Иначе + НовоеОписание = НовоеОписание.Вложение; + КонецЕсли; + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "ЕстьNull" Тогда + + НовоеОписание = ОписаниеУзлаПолеИзФункцииЕстьNull(ПервыйПараметр.Строки[0], Контекст); + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Первым параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), + "Выразить,ЕстьNull")); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 2 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После описания поля должно быть указано ключевое слово ""%1""'"), "Как"), Истина); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки[1].Вид <> "КлючевоеСлово" + Или ПервыйПараметр.Строки[1].Уточнение <> "Как" Тогда + + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После описания поля должно быть указано ключевое слово ""%1""'"), "Как")); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" не указан тип (имя таблицы)'"), ПервыйПараметр.Строки[1].Символы)); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки[2].Вид <> "Имя" Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[2], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" должен быть указан тип (имя таблицы)'"), + ПервыйПараметр.Строки[1].Символы)); + Иначе + НовоеОписание.Выразить = ПервыйПараметр.Строки[2].Символы; + НовоеОписание.ВыразитьИсточник = ПервыйПараметр.Строки[2]; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[3], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Возврат НовоеОписание; + +КонецФункции + +// Для процедур РазобратьФункцию, РазобратьПервыйПараметрПроверочнойФункции, +// РазобратьПараметрыФункцииТипЗначения и +// для функции ОписаниеУзлаПолеИзФункцииВыразить. +// +Функция ОписаниеУзлаПолеИзФункцииЕстьNull(Строка, Контекст) + + НовоеОписание = ОписаниеУзлаПоле(Строка); + НовоеОписание.ЕстьNullИсточник = Строка; + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + Возврат НовоеОписание; + КонецЕсли; + + ПервыйПараметр = СоставПараметров[0]; + + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Имя = ПервыйПараметр.Строки[0].Символы; + НовоеОписание.ИмяИсточник = ПервыйПараметр.Строки[0]; + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Первым параметром функции ""%1"" может быть только имя поля'"), Строка.Символы)); + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед параметром функции ""%1"" не указана запятая'"), Строка.Символы)); + Возврат НовоеОписание; + КонецЕсли; + + Если СоставПараметров.Количество() < 2 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" должно быть два параметра'"), Строка.Символы)); + Возврат НовоеОписание; + КонецЕсли; + + ВторойПараметр = СоставПараметров[1]; + + Если ВторойПараметр.Строки[0].Вид = "Число" + Или ВторойПараметр.Строки[0].Вид = "ПроизвольнаяСтрока" + Или ВторойПараметр.Строки[0].Вид = "КлючевоеСлово" + И ( ВторойПараметр.Строки[0].Уточнение = "Истина" + Или ВторойПараметр.Строки[0].Уточнение = "Ложь" + Или ВторойПараметр.Строки[0].Уточнение = "Неопределено" + Или ВторойПараметр.Строки[0].Уточнение = "Значение" ) Тогда + + Если ВторойПараметр.Строки[0].Уточнение = "Значение" Тогда + НовоеОписание.ЕстьNull = Новый Структура("Источник, Узел", + ВторойПараметр.Строки[0], ВторойПараметр.Строки[0].Уточнение); + + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(ВторойПараметр.Строки[0], НовоеОписание.ЕстьNull, Истина, Контекст); + Иначе + НовоеОписание.ЕстьNull = ОписаниеУзлаПолеИлиУзлаКонстанта(ВторойПараметр.Строки[0]); + КонецЕсли; + Иначе + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" второй параметр может быть, либо предопределенным значением, либо константой'"), + Строка.Символы)); + КонецЕсли; + + Если ВторойПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 2 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[2].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" должно быть только два параметра'"), Строка.Символы)); + КонецЕсли; + + Возврат НовоеОписание; + +КонецФункции + +// Для процедур РазобратьСоединительВ, РазобратьПараметрыПроверочнойФункции, +// РазобратьПараметрыФункцииЗначениеИлиФункцииТип, РазобратьПараметрыФункцииТипЗначения и +// для функций ОписаниеУзлаПолеИзФункцииВыразить, ОписаниеУзлаПолеИзФункцииЕстьNull. +// +// Параметры: +// ОписаниеСтроки - см. СтрокаТаблицы.ОписаниеСтроки +// +// Возвращаемое значение: +// Массив из Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Функция ПараметрыРазделенныеЗапятыми(ОписаниеСтроки, Контекст) + + СоставПараметров = Новый Массив; + Строка = СтрокаТаблицы(ОписаниеСтроки, Контекст); + + Если Строка.Строки.Количество() = 0 Тогда + Возврат СоставПараметров; + КонецЕсли; + + ОписаниеПараметра = Новый Структура("Строки, КонечнаяСтрока", Новый Массив); + ПредыдущаяПодстрокаЭтоЧастьАргумента = Ложь; + + Для Каждого ОписаниеПодстроки Из Строка.Строки Цикл + Подстрока = СтрокаТаблицы(ОписаниеПодстроки, Контекст); + Если Подстрока.Символы = "," Тогда + Если Не ПредыдущаяПодстрокаЭтоЧастьАргумента Тогда + Если Строка.Строки[0] = ОписаниеПодстроки Тогда + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед запятой не указан параметр'"), Подстрока.Символы)); + ОписаниеПараметра.Строки.Добавить(ДополнительнаяСтрока(Подстрока, "")); + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Пропущен параметр или лишняя запятая'"), Подстрока.Символы)); + КонецЕсли; + КонецЕсли; + Если ОписаниеПараметра.Строки.Количество() > 0 Тогда + СоставПараметров.Добавить(ОписаниеПараметра); + ОписаниеПараметра.КонечнаяСтрока = Подстрока; + КонецЕсли; + ОписаниеПараметра = Новый Структура("Строки, КонечнаяСтрока", Новый Массив); + ПредыдущаяПодстрокаЭтоЧастьАргумента = Ложь; + Продолжить; + КонецЕсли; + + ПредыдущаяПодстрокаЭтоЧастьАргумента = Истина; + + ОписаниеПараметра.Строки.Добавить(Подстрока); + КонецЦикла; + + Если ОписаниеПараметра.Строки.Количество() > 0 Тогда + СоставПараметров.Добавить(ОписаниеПараметра); + ОписаниеПараметра.КонечнаяСтрока = СтрокаТаблицы(Строка.КонечнаяСтрока, Контекст); + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Лишняя запятая или после запятой не указан параметр'"), Подстрока.Символы), Истина); + КонецЕсли; + + Возврат СоставПараметров; + +КонецФункции + +// Для процедуры РазобратьВыражение. +// +// Параметры: +// Контекст - Структура: +// * Строка - Структура: +// ** Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьВыбор(Контекст) + + Строка = Контекст.Строка; + + СвойстваУзла = "Источник, Узел, Выбор, Когда, Иначе"; + НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Выбор"); + НовоеОписание.Когда = Новый Массив; + + ПропуститьАнализКогда = Ложь; + + Выбор = СтрокаТаблицы(Строка.Строки[0], Контекст); + Если Выбор.Строки.Количество() > 0 Тогда + ПерваяСтрокаВыбора = СтрокаТаблицы(Выбор.Строки[0], Контекст); + Если ПерваяСтрокаВыбора.Вид = "Имя" Тогда + НовоеОписание.Выбор = ОписаниеУзлаПолеИлиУзлаКонстанта(ПерваяСтрокаВыбора); + Иначе + ПропуститьАнализКогда = Истина; + УстановитьОшибкуВСтроке(ПерваяСтрокаВыбора, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Когда аргумент ключевого слова ""%1"" указан, то это может быть только имя поля'"), + Строка.Символы)); + КонецЕсли; + КонецЕсли; + + Индекс = 1; + Пока Истина Цикл + СледующаяСтрока = СтрокаТаблицы(Строка.Строки[Индекс], Контекст); + Если СледующаяСтрока.Уточнение <> "Когда" Тогда + Прервать; + КонецЕсли; + ОписаниеКогдаТогда = Новый Структура("Условие, Значение"); + НовоеОписаниеКогда = НовоеОписание.Когда; // Массив + НовоеОписаниеКогда.Добавить(ОписаниеКогдаТогда); + + Когда = СледующаяСтрока; + + Если Не ПропуститьАнализКогда Тогда + ПерваяПодстрокаКогда = ?(Когда.Строки.Количество() = 0, Неопределено, + СтрокаТаблицы(Когда.Строки[0], Контекст)); + + Если НовоеОписание.Выбор = Неопределено Тогда + РазобратьВыражение(Когда.Строки, ОписаниеКогдаТогда.Условие, Контекст); + + ИначеЕсли Когда.Строки.Количество() = 0 Тогда + Если ЗначениеЗаполнено(Когда.Символы) Тогда + УстановитьОшибкуВСтроке(Когда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Так как после ключевого слова ""%1"" указано поле, то после ключевого слова ""%2"" + |должно быть указано, либо предопределенное значение, либо константа'"), + Строка.Символы, + Когда.Символы)); + КонецЕсли; + + ИначеЕсли ПерваяПодстрокаКогда.Вид = "Число" + Или ПерваяПодстрокаКогда.Вид = "ПроизвольнаяСтрока" + Или ПерваяПодстрокаКогда.Вид = "КлючевоеСлово" + И ( ПерваяПодстрокаКогда.Уточнение = "Истина" + Или ПерваяПодстрокаКогда.Уточнение = "Ложь" + Или ПерваяПодстрокаКогда.Уточнение = "Неопределено" + Или ПерваяПодстрокаКогда.Уточнение = "Значение" ) Тогда + + Если ПерваяПодстрокаКогда.Уточнение = "Значение" Тогда + ОписаниеКогдаТогда.Условие = Новый Структура("Источник, Узел", + ПерваяПодстрокаКогда, ПерваяПодстрокаКогда.Уточнение); + + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(ПерваяПодстрокаКогда, + ОписаниеКогдаТогда.Условие, Истина, Контекст); + Иначе + ОписаниеКогдаТогда.Условие = ОписаниеУзлаПолеИлиУзлаКонстанта(ПерваяПодстрокаКогда); + КонецЕсли; + ИначеЕсли ЗначениеЗаполнено(Когда.Символы) Тогда + УстановитьОшибкуВСтроке(ПерваяПодстрокаКогда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Так как после ключевого слова ""%1"" указано поле, то после ключевого слова ""%2"" + |должно быть указано, либо предопределенное значение, либо константа'"), + Строка.Символы, + Когда.Символы)); + КонецЕсли; + КонецЕсли; + + СоставТогда = СтрокаТаблицы(Строка.Строки[Индекс + 1], Контекст); + Если СоставТогда.Строки.Количество() > 0 Тогда + РазобратьВыражение(СоставТогда.Строки, ОписаниеКогдаТогда.Значение, Контекст); + + ИначеЕсли ЗначениеЗаполнено(СоставТогда.Символы) Тогда + УстановитьОшибкуВСтроке(ПерваяПодстрокаКогда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" должно быть указано логическое выражение'"), СоставТогда.Символы)); + КонецЕсли; + + Индекс = Индекс + 2; + КонецЦикла; + + РазобратьВыражение(СледующаяСтрока.Строки, НовоеОписание.Иначе, Контекст); + + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + +КонецПроцедуры + +// Для процедуры РазобратьВыражение. +Процедура РазобратьОшибочноеКлючевоеСлово(Контекст) + + Строка = Контекст.Строка; + Контекст.Описание = Неопределено; + + Если Строка.Тип = "Неопределен" Тогда + // Для зарезервированных слов ошибка уже установлена. + Возврат; + КонецЕсли; + + Если Строка.Тип = "ЗначениеСравнения" Тогда + Если Строка.Уточнение = "Отключено" Тогда + // "Отключено". + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Значение ""%1"" может использоваться только как уточняемое значение + |в параметрах функции ""%2""'"), + Строка.Символы, + КлючевоеСловоСУчетомЯзыка("ЗначениеРазрешено", Контекст))); + Иначе + // "ПустаяСсылка" или "Null". + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Значение ""%1"" может использоваться только как уточняемое значение + |в параметрах функций проверки разрешений'"), + Строка.Символы)); + КонецЕсли; + + ИначеЕсли Строка.Тип = "ИмяТипа" Тогда + // "Число", "Строка", "Дата", "Булево". + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Имя типа ""%1"" может использоваться только, как параметр функции ""%2"" или + |как уточняемое значение в параметрах функций проверки разрешений'"), + Строка.Символы, + "Тип")); + Иначе + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедур РазобратьВыражение, РазобратьОператор, РазобратьФункцию, РазобратьВыбор. +Процедура ДобавитьАргументФункциюВыборОператор(Контекст, ДобавляемоеОписание) + + // Текущий узел: Любой. + // Добавляемое описание: Поле, Значение, Константа, Не, Выбор, любая функция. + + Описание = Контекст.Описание; // См. ОписаниеУзла + + Если Описание = Неопределено Тогда + Контекст.Описание = ДобавляемоеОписание; + + ИначеЕсли Описание.Узел = "И" + Или Описание.Узел = "Или" Тогда + + Если Описание.Аргументы.Количество() = 1 Тогда + Описание.Аргументы.Добавить(ДобавляемоеОписание); + Иначе + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.Аргументы[1], ДобавляемоеОписание); + КонецЕсли; + + ИначеЕсли Описание.Узел = "Не" Тогда + + Если Не ЗначениеЗаполнено(Описание.Аргумент) Тогда + Описание.Аргумент = ДобавляемоеОписание; + Иначе + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.Аргумент, ДобавляемоеОписание); + КонецЕсли; + + ИначеЕсли Описание.Источник.Вид = "Операция" Тогда + + Если Не ЗначениеЗаполнено(Описание.ВторойАргумент) Тогда + Описание.ВторойАргумент = ДобавляемоеОписание; + // Проверка корректности аргументов выполняется + // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. + Иначе + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.ВторойАргумент, ДобавляемоеОписание); + КонецЕсли; + + ИначеЕсли СтрНайти(",Поле,Значение,Константа,В,ЕстьNull,Выбор,", "," + Описание.Узел + ",") > 0 + Или Описание.Источник.Тип = "Функция" Тогда + // Второй аргумент операции В уже разобран в процедуре РазобратьСоединительВ. + // Второй аргумент Null операции Есть уже разобран в функции ФункцииСВыражениямиВСкобках. + // Остальные узлы не имеют второго аргумента. + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Неопределено, ДобавляемоеОписание); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка узла ""%1""'"), Описание.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьАргументФункциюВыборОператор +Процедура ОбработатьПропущеннуюЛогическуюОперацию(Контекст, ПоследнийАргументОписания, ДобавляемоеОписание) + + УстановитьОшибкуВСтроке(Контекст.Строка, НСтр("ru = 'Не указана логическая операция'")); + + // Восстановление. + ДополнительнаяСтрока = ДополнительнаяСтрока(Контекст.Строка, "И", Контекст); + + НовоеОписание = Новый Структура("Источник, Узел, Аргументы", ДополнительнаяСтрока, "И", Новый Массив); + НовоеОписание.Аргументы.Добавить(); + + ТекущаяСтрока = Контекст.Строка; + Контекст.Строка = ДополнительнаяСтрока; + + ВставитьСоединительСУчетомПриоритета(Контекст, + ПоследнийАргументОписания, НовоеОписание, НовоеОписание.Аргументы[0]); + + Контекст.Строка = ТекущаяСтрока; + + НовоеОписание.Аргументы.Добавить(ДобавляемоеОписание); + +КонецПроцедуры + +// Для процедуры РазобратьУсловие. +// +// Возвращаемое значение: +// Массив из СтрокаТаблицыЗначений +// +Функция ВыраженияВСкобкахВоВложениях(Строки, Контекст) + + Результат = Новый Массив; + + ТекущееВложение = Новый Структура("Строки", Результат); + Вложения = Новый Массив; + Вложения.Добавить(ТекущееВложение); + + Для Каждого Строка Из Строки Цикл + Если Строка.Символы = "(" Тогда + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + ИначеЕсли Строка.Символы = ")" Тогда + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, + НСтр("ru = 'Указана закрывающаяся скобка до открывающейся скобки'")); + Иначе + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст, Строка); + КонецЕсли; + Иначе + СтрокаДобавить(ТекущееВложение, Строка, Контекст); + КонецЕсли; + КонецЦикла; + + Пока Вложения.Количество() > 1 Цикл + ИндексПоследнегоВложения = Вложения.Количество() - 1; + Вложение = Вложения[ИндексПоследнегоВложения]; + Вложение.КонечнаяСтрока = Строка; + Вложения.Удалить(ИндексПоследнегоВложения); + УстановитьОшибкуВСтроке(Вложение, + НСтр("ru = 'Указана открывающаяся скобка без закрывающейся скобки'"), Истина); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для процедуры РазобратьУсловие. +// +// Параметры: +// Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Функция ВыраженияВыборКогдаТогдаВоВложениях(Строки, Контекст) + + Результат = Новый Массив; + + ТекущееВложение = Новый Структура("Строки, Уточнение", Результат, ""); + Вложения = Новый Массив; + Вложения.Добавить(ТекущееВложение); + + Для Каждого ОписаниеСтроки Из Строки Цикл + Строка = СтрокаТаблицы(ОписаниеСтроки, Контекст); + + Если Строка.Вид <> "КлючевоеСлово" + Или Строка.Тип <> "СловоВыбора" Тогда + + Если ТекущееВложение.Уточнение = "Выбор" Тогда + СтрокаДобавить(СтрокаТаблицы(ТекущееВложение.Строки[0], Контекст), Строка, Контекст); + Иначе + СтрокаДобавить(ТекущееВложение, Строка, Контекст); + Если Строка.Символы = "(" Тогда + Строка.Строки = ВыраженияВыборКогдаТогдаВоВложениях(Строка.Строки, Контекст); + КонецЕсли; + КонецЕсли; + ИначеЕсли Строка.Уточнение = "Выбор" Тогда + Если Вложения.Количество() = 1 Тогда + // Стандартная обработка после условия. + Иначе + Если ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Выбор,Когда"), Истина); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда", Контекст); + КонецЕсли; + КонецЕсли; + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + ТекущееВложение.Строки.Добавить(ДополнительнаяСтрока(ТекущееВложение, "Выбор", Контекст)); + + ИначеЕсли Строка.Уточнение = "Когда" Тогда + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Когда,Выбор")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + // Стандартная обработка после условия. + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Когда,Тогда"), Истина); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе" + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" должно быть до ключевого слова ""%2""'"), "Когда,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + КонецЕсли; + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + ИначеЕсли Строка.Уточнение = "Тогда" Тогда + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Тогда,Выбор,Когда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Тогда,Когда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + // Стандартная обработка после условия. + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Тогда,Когда"), Истина); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда", Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе" + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" должно быть до ключевого слова ""%2""'"), "Тогда,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда", Контекст); + КонецЕсли; + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + ИначеЕсли Строка.Уточнение = "Иначе" Тогда + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"" и ""%4""'"), "Иначе,Выбор,Когда,Тогда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда,Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Иначе,Когда,Тогда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда,Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Иначе,Тогда")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + // Стандартная обработка после условия. + + Иначе // ТекущееВложение.Уточнение = "Иначе" + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано повторно'"), "Иначе")); + КонецЕсли; + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + Иначе // Строка.Уточнение = "Конец" + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"", ""%4"" и ""%5""'"), "Конец,Выбор,Когда,Тогда,Иначе")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда,Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"" и ""%4""'"), "Конец,Когда,Тогда,Иначе")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда,Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Конец,Тогда,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Конец,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Иначе", Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе". + // Стандартная обработка после условия. + КонецЕсли; + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + КонецЕсли; + КонецЦикла; + + Пока Вложения.Количество() > 1 Цикл + ТекущееВложение = Вложения[Вложения.Количество() - 1]; + + Если ТекущееВложение.Уточнение = "Выбор" Тогда + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"", ""%3"", ""%4"" и ""%5""'"), "Выбор,Когда,Тогда,Иначе,Конец"); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда,Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"", ""%3"", ""%4""'"), "Когда,Тогда,Иначе,Конец"); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"" и ""%3""'"), "Тогда,Иначе,Конец"); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Иначе", Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе" + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слово ""%2""'"), "Иначе,Конец"); + КонецЕсли; + УстановитьОшибкуВСтроке(ТекущееВложение, ТекстОшибки, Истина); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для процедуры РазобратьУсловие. +// +// Параметры: +// Строки - Массив из см. СтрокаТаблицы.ОписаниеСтроки +// +Функция ФункцииСВыражениямиВСкобках(Строки, ВнутренниеДанные) + + Результат = Новый Массив; + СтрокаРезультата = Новый Структура("Строки", Результат); + + КоличествоСтрок = Строки.Количество(); + + Строка = Неопределено; + Индекс = 0; + Пока Индекс < КоличествоСтрок Цикл + ПредыдущаяСтрока = Строка; // СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов + Строка = СтрокаТаблицы(Строки[Индекс], ВнутренниеДанные); + + Если Строка.Символы = "(" Тогда + Строка.Строки = ФункцииСВыражениямиВСкобках(Строка.Строки, ВнутренниеДанные); + + ИначеЕсли Строка.Вид = "КлючевоеСлово" + И ( Строка.Тип = "Функция" + Или Строка.Уточнение = "В" ) Тогда + + СледующаяСтрока = ?(Индекс + 1 < Строки.Количество(), + СтрокаТаблицы(Строки[Индекс + 1], ВнутренниеДанные), Неопределено); + + Если Индекс + 1 < Строки.Количество() + И СледующаяСтрока.Символы = "(" Тогда + + Индекс = Индекс + 1; + Строка.Строки = ФункцииСВыражениямиВСкобках(СледующаяСтрока.Строки, ВнутренниеДанные); + Строка.КонечнаяСтрока = СледующаяСтрока.КонечнаяСтрока; + + Если Строка.Строки.Количество() = 0 Тогда + Если Строка.Тип = "Функция" Тогда + УстановитьОшибкуВСтроке(Строки[Индекс], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" не указано ни одного параметра'"), Строка.Символы), Истина); + Иначе + УстановитьОшибкуВСтроке(Строки[Индекс], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" не указано ни одного значения'"), Строка.Символы), Истина); + КонецЕсли; + КонецЕсли; + Иначе + Строка.Строки = Новый Массив; + Если Строка.Тип = "Функция" Тогда + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После функции ""%1"" не указаны параметры в скобках'"), Строка.Символы), Истина); + Иначе + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" не указаны значения в скобках'"), Строка.Символы), Истина); + КонецЕсли; + КонецЕсли; + + ИначеЕсли Строка.Вид = "КлючевоеСлово" + И Строка.Уточнение = "Есть" Тогда + + СледующаяСтрока = ?(Индекс + 1 < Строки.Количество(), + СтрокаТаблицы(Строки[Индекс + 1], ВнутренниеДанные), Неопределено); + + Если Индекс + 1 < Строки.Количество() + И СледующаяСтрока.Вид = "КлючевоеСлово" + И СледующаяСтрока.Уточнение = "Null" Тогда + + Индекс = Индекс + 1; + СтрокаДобавить(Строка, СледующаяСтрока, ВнутренниеДанные); + Иначе + Строка.Строки = Новый Массив; + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%2"" не указано ключевое слово ""%1""'"), + "Null", + Строка.Символы), + Истина); + КонецЕсли; + + ИначеЕсли Строка.Вид = "Имя" + И СтрНачинаетсяС(Строка.Символы, ".") + И ПредыдущаяСтрока <> Неопределено Тогда + + Если ПредыдущаяСтрока <> Неопределено + И ПредыдущаяСтрока.Вид = "КлючевоеСлово" + И ПредыдущаяСтрока.Уточнение = "Выразить" Тогда + + Строка.Тип = "ДополнениеКВыразить"; + СтрокаДобавить(ПредыдущаяСтрока, Строка, ВнутренниеДанные); + Индекс = Индекс + 1; + Продолжить; + Иначе + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Имя поля не может начинаться с символа "".""'"), Строка.Символы)); + КонецЕсли; + КонецЕсли; + + СтрокаДобавить(СтрокаРезультата, Строка, ВнутренниеДанные); + Индекс = Индекс + 1; + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для функций ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. +Процедура ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст) + + СтрокаДобавить(ТекущееВложение, Строка, Контекст); + ТекущееВложение = Строка; + Вложения.Добавить(ТекущееВложение); + +КонецПроцедуры + +// Для функций ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. +Процедура УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст, КонечнаяСтрока = Неопределено) + + Если КонечнаяСтрока = Неопределено Тогда + Если ТекущееВложение.Строки.Количество() = 0 Тогда + КонечнаяСтрока = ТекущееВложение; + Иначе + КонечнаяСтрока = СтрокаТаблицы(ТекущееВложение.Строки[ТекущееВложение.Строки.Количество() - 1], Контекст); + Если КонечнаяСтрока.КонечнаяСтрока <> Неопределено Тогда + КонечнаяСтрока = СтрокаТаблицы(КонечнаяСтрока.КонечнаяСтрока, Контекст); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ТекущееВложение.КонечнаяСтрока = Контекст.ТаблицаНаборовСимволов.Индекс(КонечнаяСтрока); + + ИндексПоследнегоВложения = Вложения.Количество() - 1; + Вложения.Удалить(ИндексПоследнегоВложения); + ТекущееВложение = Вложения[ИндексПоследнегоВложения - 1]; + +КонецПроцедуры + +// Для функции ВыраженияВыборКогдаТогдаВоВложениях. +Процедура ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, СписокНедостающихСлов, Контекст) + + НедостающиеСлова = СтрРазделить(СписокНедостающихСлов, ",", Ложь); + + Для Каждого НедостающееСлово Из НедостающиеСлова Цикл + НоваяСтрока = ДополнительнаяСтрока(Строка, НедостающееСлово, Контекст); + ТекущееВложение.Строки.Добавить(НоваяСтрока); + + Если НедостающееСлово = "Выбор" Тогда + ТекущееВложение = НоваяСтрока; + Вложения.Добавить(ТекущееВложение); + КонецЕсли; + КонецЦикла; + + Если НедостающееСлово <> "Выбор" Тогда + ТекущееВложение = НоваяСтрока; + Вложения.Добавить(ТекущееВложение); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбработатьПропущеннуюЛогическуюОперацию, ВыраженияВыборКогдаТогдаВоВложениях, +// ВосстановитьСтруктуруВыбора и для функции ПараметрыРазделенныеЗапятыми. +// +// Возвращаемое значение: +// Структура: +// * Символы - Строка +// * Вид - Строка +// * Тип - Строка +// * Приоритет - Число +// * Уточнение - Строка +// * Строки - Массив из Число - индексы строк ТаблицаНаборовСимволов +// * КонечнаяСтрока - Число - индекс строки ТаблицаНаборовСимволов +// * ПозицияОшибки - Число +// * ТекстОшибки - Строка +// +Функция ДополнительнаяСтрока(Строка, Уточнение = "", Контекст = Неопределено) + + НоваяСтрока = Новый Структура; + НоваяСтрока.Вставить("Символы"); + НоваяСтрока.Вставить("Вид"); + НоваяСтрока.Вставить("Тип"); + НоваяСтрока.Вставить("Приоритет"); + НоваяСтрока.Вставить("Уточнение", Уточнение); + НоваяСтрока.Вставить("Строки", Новый Массив); + НоваяСтрока.Вставить("КонечнаяСтрока"); + НоваяСтрока.Вставить("ПозицияОшибки"); + НоваяСтрока.Вставить("ТекстОшибки"); + + СвойстваСлова = ?(Контекст = Неопределено, + Неопределено, Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(Уточнение))); + + Если СвойстваСлова <> Неопределено Тогда + НоваяСтрока.Вид = "КлючевоеСлово"; + НоваяСтрока.Тип = СвойстваСлова.Тип; + НоваяСтрока.Приоритет = СвойстваСлова.Приоритет; + КонецЕсли; + + Возврат НоваяСтрока; + +КонецФункции + +// Для процедур РазобратьДополнительныеТаблицы, РазобратьУсловиеОграничения. +// +// Параметры: +// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти, ИсключаемаяСтрока = Неопределено) + + Для Каждого Строка Из СтрокиЧасти Цикл + Если Строка = ИсключаемаяСтрока + Или Строка.Вид <> "КлючевоеСлово" + Или Строка.Уточнение <> "ЭтотСписок" Тогда + Продолжить; + КонецЕсли; + Строка.Вид = "Имя"; + Строка.Уточнение = ""; + КонецЦикла; + +КонецПроцедуры + +// Для процедур РазобратьДополнительныеТаблицы, РазобратьСоединение. +// +// Параметры: +// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура УстановитьПсевдоним(СтрокаЧасти, ОписаниеСоединения, ВнутренниеДанные) + + Если ЗначениеЗаполнено(СтрокаЧасти.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + ПозицияТочки = СтрНайти(СтрокаЧасти.Символы, "."); + Если ПозицияТочки > 0 Тогда + СтрокаЧасти.ПозицияОшибки = ПозицияТочки - 1; + СтрокаЧасти.ТекстОшибки = + НСтр("ru = 'Псевдоним не может содержать символа "".""'"); + + ИначеЕсли ТипЗнч(ОписаниеСоединения) = Тип("Строка") Тогда + ОписаниеСоединения = СтрокаЧасти.Символы; + ВнутренниеДанные.Псевдонимы.Вставить(ВРег(СтрокаЧасти.Символы), + Новый Структура("Псевдоним, Таблица", СтрокаЧасти.Символы)); + Иначе + ОписаниеСоединения.Псевдоним = СтрокаЧасти.Символы + "Псевдоним"; + Если ВнутренниеДанные.Псевдонимы.Получить(ВРег(СтрокаЧасти.Символы)) = Неопределено Тогда + Если ЗначениеЗаполнено(ОписаниеСоединения.Таблица) Тогда + ВнутренниеДанные.Псевдонимы.Вставить(ВРег(СтрокаЧасти.Символы), + Новый Структура("Псевдоним, Таблица", + ОписаниеСоединения.Псевдоним, ОписаниеСоединения.Таблица)); + КонецЕсли; + Иначе + СтрокаЧасти.ТекстОшибки = НСтр("ru = 'Псевдоним повторяется'"); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьСоединение. +// +// Параметры: +// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура УстановитьИмяТаблицы(СтрокаЧасти, ОписаниеСоединения, ВнутренниеДанные) + + Если ЗначениеЗаполнено(СтрокаЧасти.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если СтрНачинаетсяС(СтрокаЧасти.Символы, ".") Тогда + СтрокаЧасти.ТекстОшибки = + НСтр("ru = 'Имя таблицы не может начинаться с символа "".""'"); + Возврат; + КонецЕсли; + + Если СтрЧислоВхождений(СтрокаЧасти.Символы, ".") > 2 Тогда + + ПозицияТочки = СтрНайти(СтрокаЧасти.Символы, "."); + ПозицияТочки = ПозицияТочки + СтрНайти(Сред(СтрокаЧасти.Символы, ПозицияТочки + 1), "."); + + ПозицияТочки = ПозицияТочки + СтрНайти(Сред(СтрокаЧасти.Символы, ПозицияТочки + 1), "."); + СтрокаЧасти.ТекстОшибки = + НСтр("ru = 'Полное имя таблицы не может содержать более двух символов "".""'"); + + СтрокаЧасти.ПозицияОшибки = ПозицияТочки - 1; + Возврат; + КонецЕсли; + + ОписаниеСоединения.Таблица = СтрокаЧасти.Символы; + + ДобавитьТребуемуюТаблицуКакИсточникДанных(ВнутренниеДанные, ОписаниеСоединения.Таблица, СтрокаЧасти); + +КонецПроцедуры + +// Для процедуры УстановитьИмяТаблицы. +Процедура ДобавитьТребуемуюТаблицуКакИсточникДанных(Контекст, Таблица, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); + + Если СвойстваИмени.ЧислоЧастейИмени < 2 + Или СвойстваИмени.ЧислоЧастейИмени > 3 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени присоединяемой таблицы должна быть одна или две точки'")); + Возврат; + КонецЕсли; + + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), СвойстваИмени.ИмяТипа, Таблица)); + Возврат; + КонецЕсли; + + Если СвойстваИмени.ЧислоЧастейИмени = 3 Тогда + СвойстваУточнения = СвойстваИмени.СвойстваТипаТаблиц.УточнениеТаблиц.Получить( + ВРег(СвойстваИмени.Расширение)); + + Если СвойстваУточнения <> Неопределено + И СвойстваУточнения.Использование <> "Разрешено" Тогда + + Если СвойстваУточнения.Использование = "Недопустимо" Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимо использовать таблицы ""%1"" группы таблиц ""%2""'"), + СвойстваИмени.Расширение, СвойстваИмени.ИмяТипа)); + Иначе + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Запрещено присоединять таблицы ""%1"" группы таблиц ""%2""'"), + СвойстваИмени.Расширение, СвойстваИмени.ИмяТипа)); + КонецЕсли; + Возврат; + КонецЕсли; + КонецЕсли; + + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); + Свойства.Источники.Добавить(Источник); + +КонецПроцедуры + +// Для процедур ВыделитьПсевдонимПоля, РазобратьПервыйПараметрПроверочнойФункции, +// РазобратьДополнительныйПараметрПроверочнойФункции, РазобратьПараметрыФункцииЗначениеИлиФункцииТип. +// +Процедура ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, Таблица, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); + + Если СвойстваИмени.ЧислоЧастейИмени <> 2 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени таблицы, указанной в качестве типа, должна быть одна точка'")); + Возврат; + КонецЕсли; + + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), СвойстваИмени.ИмяТипа, Таблица)); + Возврат; + КонецЕсли; + + Если Не СвойстваИмени.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Группа таблиц ""%1"" не входит в состав ссылочных типов'"), СвойстваИмени.ИмяТипа, Таблица)); + Возврат; + КонецЕсли; + + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); + Свойства.Источники.Добавить(Источник); + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыФункцииЗначениеИлиФункцииТип. +Процедура ДобавитьТребуемыйПредопределенныйЭлемент(Контекст, ПолноеИмяПредопределенного, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, ПолноеИмяПредопределенного); + + Если СвойстваИмени.ЧислоЧастейИмени <> 3 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени предопределенного значения должно быть две точки'")); + Возврат; + КонецЕсли; + + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), + СвойстваИмени.ИмяТипа, + СвойстваИмени.ИмяТипа + "." + СвойстваИмени.ИмяБезТипа)); + Возврат; + КонецЕсли; + + Если Не СвойстваИмени.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Группа таблиц ""%1"" не входит в состав ссылочных типов'"), СвойстваИмени.ИмяТипа)); + Возврат; + КонецЕсли; + + СвойстваСлова = Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(СвойстваИмени.Расширение)); // См. СвойстваСлова + + Если Не СвойстваИмени.СвойстваТипаТаблиц.ЕстьПредопределенные + И Не СвойстваИмени.ИмяТипа = "Перечисление" + И ( СвойстваСлова = Неопределено + Или СвойстваСлова.Идентификатор <> "ПустаяСсылка") Тогда + + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В группе таблиц ""%1"" нет предопределенных элементов'"), СвойстваИмени.ИмяТипа)); + Возврат; + КонецЕсли; + + СвойстваИмениТаблицы = СвойстваИмениТаблицы(Контекст, СвойстваИмени.ИмяТипа + "." + СвойстваИмени.ИмяБезТипа); + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмениТаблицы, Истина); + + СвойстваПредопределенного = Свойства.Предопределенные.Получить(ВРег(СвойстваИмени.Расширение)); + Если СвойстваПредопределенного = Неопределено Тогда + СвойстваПредопределенного = НовыеСвойстваПредопределенного(); + СвойстваПредопределенного.Вставить("ИмяСуществует", Ложь); + СвойстваПредопределенного.Вставить("Источники", Новый Массив); + Свойства.Предопределенные.Вставить(ВРег(СвойстваИмени.Расширение), СвойстваПредопределенного); + КонецЕсли; + СвойстваПредопределенного.Источники.Добавить(Источник); + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыФункцииРольДоступна. +Процедура ПроверитьИмяРоли(ИмяРоли, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если СтрНайти(ИмяРоли, ".") > 0 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени роли не должно быть точек'")); + Возврат; + КонецЕсли; + + Если Метаданные.Роли.Найти(ИмяРоли) = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Роль ""%1"" отсутствует в метаданных'"), ИмяРоли)); + Возврат; + КонецЕсли; + +КонецПроцедуры + +Процедура ПроверитьИмяПраваОбъектаМетаданных(ИмяПрава, ИсточникПрава, ИмяОбъекта, ИсточникОбъекта) + + Если ЗначениеЗаполнено(ИсточникПрава.ТекстОшибки) + Или ИсточникОбъекта <> Неопределено + И ЗначениеЗаполнено(ИсточникОбъекта.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если СтрНайти(ИмяПрава, ".") > 0 Тогда + УстановитьОшибкуВСтроке(ИсточникПрава, + НСтр("ru = 'В имени права не должно быть точек'")); + Возврат; + КонецЕсли; + + ИмяСтандартногоРеквизита = Неопределено; + ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава(ИмяОбъекта, ИмяСтандартногоРеквизита); + Если ОбъектМетаданных = Неопределено Тогда + УстановитьОшибкуВСтроке(ИсточникОбъекта, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Объект метаданных ""%1"" не существует'"), ИмяОбъекта)); + Возврат; + КонецЕсли; + + ТекстОшибки = ""; + Попытка + ПравоДоступа(ИмяПрава, ОбъектМетаданных, , ИмяСтандартногоРеквизита); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + + Если ЗначениеЗаполнено(ТекстОшибки) Тогда + УстановитьОшибкуВСтроке(ИсточникПрава, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось проверить право ""%1"" объекта метаданных ""%2"" по причине: + |%3'"), ИмяПрава, ИмяОбъекта, ТекстОшибки)); + Возврат; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьИмяПраваОбъектаМетаданных +Функция ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава(ПолноеИмя, ИмяСтандартногоРеквизита = Неопределено) + + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); + Если ОбъектМетаданных <> Неопределено Тогда + Возврат ОбъектМетаданных; + КонецЕсли; + + ЧастиИмени = СтрРазделить(ПолноеИмя, "."); + Если ЧастиИмени.Количество() < 4 Тогда + Возврат Неопределено; + КонецЕсли; + + ИмяОсновногоОбъектаМетаданных = ЧастиИмени[0] + "." + ЧастиИмени[1]; + ОсновнойОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОсновногоОбъектаМетаданных); + Если ОсновнойОбъектМетаданных = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Если ВРег(ЧастиИмени[2]) = ВРег("СтандартнаяТабличнаяЧасть") + Или ВРег(ЧастиИмени[2]) = ВРег("StandardTabularSection") Тогда // @Non-NLS + + Свойства = Новый Структура("СтандартныеТабличныеЧасти"); + ЗаполнитьЗначенияСвойств(Свойства, ОсновнойОбъектМетаданных); + Если Свойства.СтандартныеТабличныеЧасти = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + ИмяСтандартнойТабличнойЧасти = ЧастиИмени[3]; + Для Каждого СтандартнаяТабличнаяЧасть Из Свойства.СтандартныеТабличныеЧасти Цикл + Если ВРег(СтандартнаяТабличнаяЧасть.Имя) = ВРег(ИмяСтандартнойТабличнойЧасти) Тогда + СтандартныеРеквизиты = СтандартнаяТабличнаяЧасть.СтандартныеРеквизиты; + Прервать; + КонецЕсли; + КонецЦикла; + Если СтандартныеРеквизиты = Неопределено + Или ЧастиИмени.Количество() <> 6 Тогда + Возврат Неопределено; + КонецЕсли; + ЧастиИмени.Удалить(0); + ЧастиИмени.Удалить(0); + ВладелецСтандартныхРеквизитов = СтандартнаяТабличнаяЧасть; + Иначе + ВладелецСтандартныхРеквизитов = ОсновнойОбъектМетаданных; + КонецЕсли; + + Если ВРег(ЧастиИмени[2]) <> ВРег("СтандартныйРеквизит") + И ВРег(ЧастиИмени[2]) <> ВРег("StandardAttribute") Тогда // @Non-NLS + Возврат Неопределено; + КонецЕсли; + + Свойства = Новый Структура("СтандартныеРеквизиты"); + ЗаполнитьЗначенияСвойств(Свойства, ВладелецСтандартныхРеквизитов); + Если Свойства.СтандартныеРеквизиты = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + ИмяСтандартногоРеквизита = ЧастиИмени[3]; + СтандартныеРеквизиты = Свойства.СтандартныеРеквизиты; // ОписанияСтандартныхРеквизитов + + Для Каждого СтандартныйРеквизит Из СтандартныеРеквизиты Цикл + Если ВРег(СтандартныйРеквизит.Имя) = ВРег(ИмяСтандартногоРеквизита) Тогда + Если ЗначениеЗаполнено(ИмяСтандартнойТабличнойЧасти) Тогда + ИмяСтандартногоРеквизита = ИмяСтандартнойТабличнойЧасти + "." + ИмяСтандартногоРеквизита; + КонецЕсли; + Возврат ОсновнойОбъектМетаданных; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +// Для процедур ОтметитьНекорректныеАргументыИЗапрещенныеУзлы, ВыделитьПсевдонимПоля, +// ДобавитьТипыВидовДоступаПользователиИВнешниеПользователиДляПроверкиОтсутствия. +// +Процедура ДобавитьТребуемоеПолеТаблицы(Контекст, Таблица, ИмяПоля, Источник, + ТипПоля = "", ИсточникТипаПоля = Неопределено, УзелПоле = Неопределено) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + + Если СвойстваИмени.ЭтоОсновнаяТаблица + И Не Контекст.Свойство("ОшибкаНаПервоеПолеОсновнойТаблицыУстановлена") Тогда + + Контекст.Вставить("ОшибкаНаПервоеПолеОсновнойТаблицыУстановлена"); + УстановитьОшибкуВСтрокеИмениПоля(Контекст, Источник, + НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , + Контекст.ОсновнаяТаблица); + КонецЕсли; + + Возврат; + КонецЕсли; + + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); + + СвойстваПоля = Свойства.Поля.Получить(ВРег(ИмяПоля)); + Если СвойстваПоля = Неопределено Тогда + СвойстваПоля = НовыеСвойстваПоля(); + СвойстваПоля.Вставить("ПолеСОшибкой", 0); + СвойстваПоля.Вставить("ВидОшибки", ""); + СвойстваПоля.Вставить("Коллекция", ""); + СвойстваПоля.Вставить("СодержитТипы", Новый Соответствие); + СвойстваПоля.Вставить("Источники", Новый Соответствие); + СвойстваПоля.Вставить("УзлыПоле", Новый Массив); + Свойства.Поля.Вставить(ВРег(ИмяПоля), СвойстваПоля); + + Если Свойства.Свойство("ПервоеПоле") + И Свойства.ПервоеПоле = Неопределено + И Источник <> Неопределено Тогда + + СвойстваПоля.Вставить("ПервыйИсточник", Новый Структура("Ключ,Значение", Источник, Таблица)); + Свойства.ПервоеПоле = СвойстваПоля; + КонецЕсли; + КонецЕсли; + СвойстваПоля.Источники.Вставить(Источник, Таблица); + Если УзелПоле <> Неопределено Тогда + СвойстваПоля.УзлыПоле.Добавить(УзелПоле); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ТипПоля) Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ИсточникТипаПоля) = Тип("СтрокаТаблицыЗначений") + И ЗначениеЗаполнено(ИсточникТипаПоля.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваТипа = СвойстваПоля.СодержитТипы.Получить(ВРег(ТипПоля)); + Если СвойстваТипа = Неопределено Тогда + СоставИмени = СтрРазделить(ТипПоля, "."); + СвойстваТипаТаблиц = Контекст.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0])); + Если СвойстваТипаТаблиц = Неопределено Тогда + ИмяТипа = ТипПоля; + ИмяКоллекцииТипа = ""; + ИмяОбъектаКоллекцииТипа = ""; + Иначе + ИмяТипа = СвойстваТипаТаблиц.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS + ИмяКоллекцииТипа = СвойстваТипаТаблиц.ИмяКоллекции; + ИмяОбъектаКоллекцииТипа = СоставИмени[1]; + КонецЕсли; + СвойстваТипа = Новый Структура; + СвойстваТипа.Вставить("СодержитТип", Ложь); + СвойстваТипа.Вставить("ИмяТипа", ИмяТипа); + СвойстваТипа.Вставить("ИмяКоллекцииТипа", ИмяКоллекцииТипа); + СвойстваТипа.Вставить("ИмяОбъектаКоллекцииТипа", ИмяОбъектаКоллекцииТипа); + СвойстваТипа.Вставить("Источники", Новый Соответствие); + СвойстваПоля.СодержитТипы.Вставить(ВРег(ТипПоля), СвойстваТипа); + КонецЕсли; + СвойстваТипа.Источники.Вставить(ИсточникТипаПоля, Источник); + +КонецПроцедуры + +// Для процедур ДобавитьТребуемуюТаблицуКакИсточникДанных, ДобавитьТребуемуюТаблицуКакСсылочныйТип, +// ДобавитьТребуемыйПредопределенныйЭлемент, ДобавитьТребуемоеПолеТаблицы. +// +Функция СвойстваИмениТаблицы(Контекст, ПолноеИмя) + + Если ЗначениеЗаполнено(ПолноеИмя) Тогда + Таблица = ПолноеИмя; + Иначе + Таблица = Контекст.ОсновнаяТаблица; + КонецЕсли; + + СоставИмени = СтрРазделить(Таблица, ".", Ложь); + + Свойства = Новый Структура; + Свойства.Вставить("ЧислоЧастейИмени", СоставИмени.Количество()); + Свойства.Вставить("ИмяТипа", СоставИмени[0]); + Свойства.Вставить("ИмяБезТипа", ?(СоставИмени.Количество() > 1, СоставИмени[1], Неопределено)); + Свойства.Вставить("Расширение", ?(СоставИмени.Количество() = 3, СоставИмени[2], Неопределено)); + Свойства.Вставить("ЭтоОсновнаяТаблица", ВРег(Таблица) = ВРег(Контекст.ОсновнаяТаблица)); + Свойства.Вставить("СвойстваТипаТаблиц", + Контекст.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0]))); + + Возврат Свойства; + +КонецФункции + +// Для процедур ДобавитьТребуемуюТаблицуКакИсточникДанных, ДобавитьТребуемуюТаблицуКакСсылочныйТип, +// ДобавитьТребуемыйПредопределенныйЭлемент, ДобавитьТребуемоеПолеТаблицы. +// +Функция СвойстваТребуемойТаблицы(Контекст, СвойстваИмени, БезРасширения = Ложь) + + ИмяКоллекции = СвойстваИмени.СвойстваТипаТаблиц.ИмяКоллекции; + + СоставКоллекции = Контекст.ПоляТаблиц.Получить(ИмяКоллекции); + Если СоставКоллекции = Неопределено Тогда + СоставКоллекции = НовыйСоставКоллекции(); + Контекст.ПоляТаблиц.Вставить(ИмяКоллекции, СоставКоллекции); + КонецЕсли; + + Свойства = СоставКоллекции.Получить(ВРег(СвойстваИмени.ИмяБезТипа)); + Если Свойства = Неопределено Тогда + Свойства = НовыеСвойстваТаблицы(); + Свойства.Вставить("ТаблицаСуществует", Ложь); + Свойства.Вставить("ЭтоОсновнаяТаблица", СвойстваИмени.ЭтоОсновнаяТаблица); + Свойства.Вставить("Источники", Новый Массив); + Свойства.Вставить("Поля", Новый Соответствие); + Свойства.Вставить("Предопределенные", Новый Соответствие); + Свойства.Вставить("Расширения", Новый Соответствие); + Если СвойстваИмени.ЭтоОсновнаяТаблица И СвойстваИмени.Расширение = Неопределено Тогда + Свойства.Вставить("ПервоеПоле"); + КонецЕсли; + СоставКоллекции.Вставить(ВРег(СвойстваИмени.ИмяБезТипа), Свойства); + КонецЕсли; + + Если СвойстваИмени.Расширение = Неопределено Или БезРасширения Тогда + Возврат Свойства; + КонецЕсли; + + СвойстваРасширения = Свойства.Расширения.Получить(ВРег(СвойстваИмени.Расширение)); + Если СвойстваРасширения = Неопределено Тогда + СвойстваРасширения = НовыеСвойстваРасширения(); + СвойстваРасширения.Вставить("ТаблицаСуществует", Ложь); + СвойстваРасширения.Вставить("Источники", Новый Массив); + СвойстваРасширения.Вставить("Поля", Новый Соответствие); + Если СвойстваИмени.ЭтоОсновнаяТаблица Тогда + СвойстваРасширения.Вставить("ПервоеПоле"); + КонецЕсли; + Свойства.Расширения.Вставить(ВРег(СвойстваИмени.Расширение), СвойстваРасширения); + КонецЕсли; + + Возврат СвойстваРасширения; + +КонецФункции + +// Для процедур и функций ЧастиОграничения, РазобратьДополнительныеТаблицы, РазобратьСоединение, +// РазобратьУсловиеОграничения, ВыраженияВыборКогдаТогдаВоВложениях. +// +Функция ПодставитьКлючевыеСловаВСтроку(Контекст, Строка, СписокСлов, ПараметрОдин = "", ПараметрДва = "", ПараметрТри = "") + + Слова = СтрРазделить(СписокСлов, ",", Ложь); + СловаДляПодстановки = Новый Соответствие; + + Для Каждого Слово Из Слова Цикл + СловаДляПодстановки.Вставить(Слова.Найти(Слово), + КлючевоеСловоСУчетомЯзыка(СокрЛП(Слово), Контекст)); + КонецЦикла; + + Индекс = СловаДляПодстановки.Количество(); + СловаДляПодстановки.Вставить(Индекс, ПараметрОдин); + СловаДляПодстановки.Вставить(Индекс + 1, ПараметрДва); + СловаДляПодстановки.Вставить(Индекс + 2, ПараметрТри); + + Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Строка, + СловаДляПодстановки[0], СловаДляПодстановки[1], СловаДляПодстановки[2], + СловаДляПодстановки[3], СловаДляПодстановки[4], СловаДляПодстановки[5], + СловаДляПодстановки[6], СловаДляПодстановки[7], СловаДляПодстановки[8]); + +КонецФункции + +// Для процедур РазобратьДополнительныеТаблицы, РазобратьСоединение, РазобратьУсловиеОграничения. +Функция КлючевоеСловоСУчетомЯзыка(ИдентификаторСлова, Контекст) + + СвойстваСлова = Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(ИдентификаторСлова)); + + Если ВариантВстроенногоЯзыкаРусский() Тогда + Слово = СвойстваСлова.ЯзыкРусский; + Иначе + Слово = СвойстваСлова.ЯзыкАнглийский; + КонецЕсли; + + Если СвойстваСлова.ВерхнийРегистр Тогда + Слово = ВРег(Слово); + КонецЕсли; + + Возврат Слово; + +КонецФункции + +#КонецОбласти + +#Область АнализИменТаблицИПолейТаблиц + +// Проверка таблиц, полей таблиц и типов полей, найденных при разборе текста ограничения. +// Аналогичная процедура реализуется в СППР. +// +// Параметры: +// РазобранноеОграничение - см. РазобранноеОграничение +// +Процедура ПроверитьТаблицыПоляИТипыПолей(РазобранноеОграничение) + + Контекст = Новый Структура; + Контекст.Вставить("ТипыТаблиц", УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц); + + Для Каждого ТипТаблиц Из РазобранноеОграничение.ПоляТаблиц Цикл + КоллекцияТаблиц = Метаданные[ТипТаблиц.Ключ]; // КоллекцияОбъектовМетаданных + + Для Каждого ПоляТаблицы Из ТипТаблиц.Значение Цикл + + МетаданныеТаблицы = КоллекцияТаблиц.Найти(ПоляТаблицы.Ключ); + Если МетаданныеТаблицы = Неопределено Тогда + Продолжить; + КонецЕсли; + ПоляТаблицы.Значение.ТаблицаСуществует = Истина; + + Контекст.Вставить("МетаданныеТаблицы", МетаданныеТаблицы); + Контекст.Вставить("СвойстваТипаТаблиц", Контекст.ТипыТаблиц.ПоКоллекциям.Получить(ТипТаблиц.Ключ)); + Контекст.Вставить("ЭтоОсновнаяТаблица", ПоляТаблицы.Значение.ЭтоОсновнаяТаблица); + + Для Каждого ПолеТаблицы Из ПоляТаблицы.Значение.Поля Цикл + ОписаниеПоля = Новый Структура; + ОписаниеПоля.Вставить("СоставИмени", СтрРазделить(ПолеТаблицы.Ключ, ".")); + ОписаниеПоля.Вставить("Свойства", ПолеТаблицы.Значение); + ОписаниеПоля.Вставить("ТипПоля", Новый ОписаниеТипов); + ПроверитьПолеТаблицы(ОписаниеПоля, Контекст); + Если ОписаниеПоля.Свойства.ПолеСОшибкой = 0 Тогда + ПроверитьТипыПоля(ОписаниеПоля, Контекст); + КонецЕсли; + КонецЦикла; + + ПроверитьРасширенияТаблицы(ПоляТаблицы, Контекст); + ПроверитьПредопределенныеЗначенияТаблицы(ПоляТаблицы, Контекст); + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ПроверитьТаблицыПоляИТипыПолей, ПроверитьСледующееПолеЧерезТочку. +Процедура ПроверитьПолеТаблицы(ОписаниеПоля, Контекст, Индекс = 0, ПервыйВызов = Истина) + + СоставИмени = ОписаниеПоля.СоставИмени; + СвойстваПоля = ОписаниеПоля.Свойства; + + УточнениеПоля = Контекст.СвойстваТипаТаблиц.УточнениеПолей.Получить(ВРег(СоставИмени[Индекс])); + + Если УточнениеПоля <> Неопределено + И УточнениеПоля.Использование <> "Разрешено" Тогда + + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = УточнениеПоля; + Возврат; + КонецЕсли; + + Свойства = СвойстваПоляИлиТабличнойЧасти(СоставИмени[Индекс], Контекст, Индекс = 0); + Если Свойства = Неопределено Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "НеНайдено"; + Возврат; + КонецЕсли; + Если Индекс = 0 Тогда + СвойстваПоля.Коллекция = Свойства.Коллекция; + КонецЕсли; + + Если Свойства.ЭтоТабличнаяЧасть Тогда + Если Индекс > 0 Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "ТабличнаяЧастьПослеТочки"; + Возврат; + КонецЕсли; + Если Не Контекст.ЭтоОсновнаяТаблица Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "ТабличнаяЧастьДополнительнойТаблицы"; + Возврат; + КонецЕсли; + Если Индекс + 1 = СоставИмени.Количество() Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "ТабличнаяЧастьБезПоля"; + Возврат; + КонецЕсли; + Индекс = Индекс + 1; + Свойства = СвойстваПоляТабличнойЧасти(СоставИмени[Индекс], + Свойства.Метаданные, Свойства.Коллекция, Контекст.МетаданныеТаблицы); + Если Свойства = Неопределено Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "НеНайдено"; + Возврат; + КонецЕсли; + КонецЕсли; + + ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, Свойства, Контекст); + + Если ПервыйВызов Тогда + ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПроверитьПолеТаблицы и ПроверитьРасширенияТаблицы. +Процедура ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст) + + ДобавитьТипыПоляДополнительно(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст); + + Индекс = Индекс + 1; + Если Индекс = ОписаниеПоля.СоставИмени.Количество() Тогда + ОписаниеПоля.ТипПоля = Новый ОписаниеТипов(ОписаниеПоля.ТипПоля, СвойстваТекущегоПоля.Тип.Типы()); + Возврат; + КонецЕсли; + + СвойстваПоля = ОписаниеПоля.Свойства; + ПолеНайдено = Ложь; + + Если ОписаниеПоля.Свойство("ТаблицыСледующегоПоля") Тогда + // См. процедуру ДобавитьТипыПоляДополнительно. + Если ОписаниеПоля.ТаблицыСледующегоПоля.Количество() < Индекс + 1 Тогда + ТаблицыСледующегоПоля = Новый Массив; + ОписаниеПоля.ТаблицыСледующегоПоля.Добавить(ТаблицыСледующегоПоля); + Иначе + ТаблицыСледующегоПоля = ОписаниеПоля.ТаблицыСледующегоПоля[Индекс]; + КонецЕсли; + КонецЕсли; + + Для Каждого Тип Из СвойстваТекущегоПоля.Тип.Типы() Цикл + Если Не ОбщегоНазначения.ЭтоСсылка(Тип) Тогда + Продолжить; + КонецЕсли; + СвойстваПоля.ПолеСОшибкой = 0; + СвойстваПоля.ВидОшибки = ""; + + // Сохранение текущего контекста. + ТекущиеМетаданныеТаблицы = Контекст.МетаданныеТаблицы; + ТекущиеСвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + Контекст.МетаданныеТаблицы = Метаданные.НайтиПоТипу(Тип); + ПолноеИмя = Контекст.МетаданныеТаблицы.ПолноеИмя(); + СоставПолногоИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Контекст.СвойстваТипаТаблиц = Контекст.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставПолногоИмени[0])); + + ТекущийИндекс = Индекс; + ПроверитьПолеТаблицы(ОписаниеПоля, Контекст, ТекущийИндекс, Ложь); + + // Восстановление текущего контекста. + Контекст.МетаданныеТаблицы = ТекущиеМетаданныеТаблицы; + Контекст.СвойстваТипаТаблиц = ТекущиеСвойстваТипаТаблиц; + + Если СвойстваПоля.ПолеСОшибкой = 0 Тогда + ПолеНайдено = Истина; + Если ТаблицыСледующегоПоля <> Неопределено Тогда + // См. процедуру ДобавитьТипыПоляДополнительно. + ТаблицыСледующегоПоля.Добавить(ПолноеИмя); + КонецЕсли; + ИначеЕсли СвойстваПоля.ВидОшибки <> "НеНайдено" Тогда + Возврат; + КонецЕсли; + КонецЦикла; + + Если ПолеНайдено Тогда + СвойстваПоля.ПолеСОшибкой = 0; + СвойстваПоля.ВидОшибки = ""; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьПолеТаблицы. +Функция СвойстваПоляИлиТабличнойЧасти(ИмяПоляИлиТабличнойЧасти, Контекст, ЭтоПервоеПоле) + + Результат = Новый Структура; + Результат.Вставить("ЭтоТабличнаяЧасть", Ложь); + Результат.Вставить("Коллекция"); + Результат.Вставить("Метаданные"); + Результат.Вставить("Тип"); + + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; + СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + Для Каждого КоллекцияТабличныхЧастей Из СвойстваТипаТаблиц.КоллекцииТабличныхЧастей Цикл + Если КоллекцияТабличныхЧастей.Ключ = "СтандартныеТабличныеЧасти" Тогда + СтандартныеТабличныеЧасти = МетаданныеТаблицы.СтандартныеТабличныеЧасти; // ОписанияСтандартныхТабличныхЧастей + Для Каждого СтандартнаяТабличнаяЧасть Из СтандартныеТабличныеЧасти Цикл + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег(СтандартнаяТабличнаяЧасть.Имя) Тогда + Результат.Метаданные = СтандартнаяТабличнаяЧасть; + Прервать; + КонецЕсли; + КонецЦикла; + Иначе + Результат.Метаданные = МетаданныеТаблицы[КоллекцияТабличныхЧастей.Ключ].Найти(ИмяПоляИлиТабличнойЧасти); + КонецЕсли; + Если Результат.Метаданные <> Неопределено Тогда + Результат.ЭтоТабличнаяЧасть = Истина; + Результат.Коллекция = КоллекцияТабличныхЧастей.Ключ; + Возврат Результат; + КонецЕсли; + КонецЦикла; + + Для Каждого КоллекцияПолей Из СвойстваТипаТаблиц.КоллекцииПолей Цикл + Если КоллекцияПолей.Ключ = "СтандартныеРеквизиты" Тогда + Номер = 0; + СтандартныеРеквизиты = МетаданныеТаблицы.СтандартныеРеквизиты; // ОписанияСтандартныхРеквизитов + Для Каждого СтандартныйРеквизит Из СтандартныеРеквизиты Цикл + Номер = Номер + 1; + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Метаданные = СтандартныйРеквизит; + Прервать; + КонецЕсли; + КонецЦикла; + Иначе + Результат.Метаданные = МетаданныеТаблицы[КоллекцияПолей.Ключ].Найти(ИмяПоляИлиТабличнойЧасти); + КонецЕсли; + Если Результат.Метаданные <> Неопределено Тогда + Результат.Коллекция = КоллекцияПолей.Ключ; + Если Результат.Коллекция = "Графы" Тогда + Результат.Тип = Новый ОписаниеТипов; + МетаданныеГрафыЖурнала = Результат.Метаданные; // ОбъектМетаданныхГрафа + Для Каждого МетаданныеСсылки Из МетаданныеГрафыЖурнала.Ссылки Цикл + Результат.Тип = Новый ОписаниеТипов(Результат.Тип, МетаданныеСсылки.Тип.Типы()); + КонецЦикла; + Иначе + Результат.Тип = Результат.Метаданные.Тип; + КонецЕсли; + Возврат Результат; + КонецЕсли; + КонецЦикла; + + Если СвойстваТипаТаблиц.ОбщиеРеквизиты <> "Отсутствуют" Тогда + Результат.Метаданные = Метаданные.ОбщиеРеквизиты.Найти(ИмяПоляИлиТабличнойЧасти); + Если Результат.Метаданные <> Неопределено Тогда + Результат.Коллекция = "ОбщиеРеквизиты"; + Результат.Тип = Результат.Метаданные.Тип; + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Если СвойстваТипаТаблиц.ИмяКоллекции = "Константы" Тогда + + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Значение") + Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Value") Тогда + + Результат.Коллекция = "СпециальныеПоля"; + Результат.Тип = МетаданныеТаблицы.Тип; + Результат.Вставить("ОсновнойПорядок", "001"); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + + ИначеЕсли СвойстваТипаТаблиц.ИмяКоллекции = "Последовательности" Тогда + + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Период") + Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Period") Тогда + + Результат.Коллекция = "СпециальныеПоля"; + Результат.Тип = Новый ОписаниеТипов("Дата"); + Результат.Вставить("ОсновнойПорядок", "001"); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Регистратор") + Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Recorder") Тогда + + Результат.Коллекция = "СпециальныеПоля"; + Результат.Тип = Новый ОписаниеТипов; + МетаданныеПоследовательности = МетаданныеТаблицы; // ОбъектМетаданныхПоследовательность + Для Каждого ДокументМетаданные Из МетаданныеПоследовательности.Документы Цикл + Результат.Тип = Новый ОписаниеТипов(Результат.Тип, "ДокументСсылка." + ДокументМетаданные.Имя); + КонецЦикла; + Результат.Вставить("ОсновнойПорядок", "002"); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедур ПроверитьРасширенияТаблицы, ПроверитьПолеТаблицы. +Функция СвойстваПоляТабличнойЧасти(ИмяПоляТабличнойЧасти, МетаданныеТабличнойЧасти, ИмяКоллекции, МетаданныеТаблицы) + + Результат = Новый Структура; + Результат.Вставить("Тип"); + Результат.Вставить("ИмяТабличнойЧасти", МетаданныеТабличнойЧасти.Имя); + + Если ВРег(ИмяПоляТабличнойЧасти) = ВРег("Ссылка") + Или ВРег(ИмяПоляТабличнойЧасти) = ВРег("Ref") Тогда + + Для Каждого СтандартныйРеквизит Из МетаданныеТаблицы.СтандартныеРеквизиты Цикл + Если ВРег(ИмяПоляТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Тип = СтандартныйРеквизит.Тип; + Возврат Результат; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Для Каждого СтандартныйРеквизит Из МетаданныеТабличнойЧасти.СтандартныеРеквизиты Цикл + Если ВРег(ИмяПоляТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Тип = СтандартныйРеквизит.Тип; + Возврат Результат; + КонецЕсли; + КонецЦикла; + + Если ИмяКоллекции = "ТабличныеЧасти" Тогда + МетаданныеПоля = МетаданныеТабличнойЧасти.Реквизиты.Найти(ИмяПоляТабличнойЧасти); + Если МетаданныеПоля <> Неопределено Тогда + Результат.Тип = МетаданныеПоля.Тип; + Результат.Вставить("МетаданныеТабличнойЧасти", МетаданныеТабличнойЧасти); + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедур ПроверитьРасширенияТаблицы, ПроверитьПолеТаблицы. +Функция СвойстваПоляПерерасчета(ИмяПоляПерерасчета, МетаданныеПерерасчета, МетаданныеТаблицы) + + Результат = Новый Структура; + Результат.Вставить("Тип"); + Результат.Вставить("Коллекция"); + Результат.Вставить("Метаданные"); + + Если ВРег(ИмяПоляПерерасчета) = ВРег("ОбъектПерерасчета") + Или ВРег(ИмяПоляПерерасчета) = ВРег("RecalculationObject") Тогда + + ИмяПоля = "Регистратор"; + + ИначеЕсли ВРег(ИмяПоляПерерасчета) = ВРег("ВидРасчета") + Или ВРег(ИмяПоляПерерасчета) = ВРег("CalculationType") Тогда + + ИмяПоля = "ВидРасчета"; + КонецЕсли; + + МетаданныеРегистра = МетаданныеТаблицы; // ОбъектМетаданныхРегистрРасчета + Если ЗначениеЗаполнено(ИмяПоля) Тогда + Для Каждого СтандартныйРеквизит Из МетаданныеРегистра.СтандартныеРеквизиты Цикл + Если ВРег(ИмяПоля) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Коллекция = "СтандартныеРеквизиты"; + Результат.Метаданные = СтандартныйРеквизит; + Результат.Тип = СтандартныйРеквизит.Тип; + Возврат Результат; + КонецЕсли; + КонецЦикла; + Возврат Неопределено; + КонецЕсли; + + МетаданныеПоля = МетаданныеПерерасчета.Измерения.Найти(ИмяПоляПерерасчета); + Если МетаданныеПоля <> Неопределено Тогда + Результат.Тип = МетаданныеПоля.ИзмерениеРегистра.Тип; + Результат.Коллекция = "СпециальныеПоля"; + Номер = 200 + МетаданныеРегистра.Измерения.Индекс(МетаданныеПоля) + 1; + Результат.Вставить("ОсновнойПорядок", Номер); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ПроверитьПолеТаблицы. +Процедура ДобавитьТипыПоляДополнительно(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст) + + // Дополнительный сбор типов для использования в служебных процедурах. + + // Расширение свойств узла Поле для использования в служебных процедурах. + Если Индекс = 0 Или Индекс = 1 И СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда + Если ОписаниеПоля.СоставИмени.Количество() > 1 Тогда + ОписаниеПоля.Вставить("ТаблицыСледующегоПоля", Новый Массив); + Если Индекс = 1 Тогда + ОписаниеПоля.ТаблицыСледующегоПоля.Добавить(Неопределено); + КонецЕсли; + КонецЕсли; + Если Индекс = 0 И Не Контекст.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда + ДобавитьОсновнойПорядокПоля(СвойстваТекущегоПоля, Контекст); + КонецЕсли; + КонецЕсли; + + Для Каждого УзелПоле Из ОписаниеПоля.Свойства.УзлыПоле Цикл + Если СвойстваТекущегоПоля.Свойство("ОсновнойПорядок") + И Не УзелПоле.Свойство("ОсновнойПорядок") Тогда + УзелПоле.Вставить("ОсновнойПорядок", СвойстваТекущегоПоля.ОсновнойПорядок); + КонецЕсли; + Если ОписаниеПоля.Свойство("ТаблицыСледующегоПоля") + И Не УзелПоле.Свойство("ТаблицыСледующегоПоля") Тогда + УзелПоле.Вставить("ТаблицыСледующегоПоля", ОписаниеПоля.ТаблицыСледующегоПоля); + КонецЕсли; + Если Не УзелПоле.Свойство("ТипыПоля") Тогда + УзелПоле.Вставить("ТипыПоля", Новый Массив); + УстановитьПолеСодержитNull(УзелПоле, СвойстваТекущегоПоля, Контекст); + КонецЕсли; + Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") + И ВРег(СвойстваТекущегоПоля.ИмяТабличнойЧасти) = ВРег(ОписаниеПоля.СоставИмени[0]) Тогда + + УзелПоле.ТипыПоля.Добавить(СвойстваТекущегоПоля.ИмяТабличнойЧасти); + КонецЕсли; + Если Индекс > УзелПоле.ТипыПоля.Количество() - 1 Тогда + УзелПоле.ТипыПоля.Добавить(СвойстваТекущегоПоля.Тип); + КонецЕсли; + УзелПоле.ТипыПоля[Индекс] = Новый ОписаниеТипов(УзелПоле.ТипыПоля[Индекс], + СвойстваТекущегоПоля.Тип.Типы()); + КонецЦикла; + + // Добавление типов поля строкой для проверки изменения в служебных процедурах. + ПолноеИмяПоля = Контекст.СвойстваТипаТаблиц.ЯзыкРусский + "." + ВРег(Контекст.МетаданныеТаблицы.Имя); + + Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда + ПолноеИмяПоля = ПолноеИмяПоля + "." + ВРег(СвойстваТекущегоПоля.ИмяТабличнойЧасти); + КонецЕсли; + + ПолноеИмяПоля = ПолноеИмяПоля + "." + ОписаниеПоля.СоставИмени[Индекс]; + + Если Не ОписаниеПоля.Свойство("ВсеПоля") Тогда + ОписаниеПоля.Вставить("ВсеПоля", Новый Соответствие); + ОписаниеПоля.Вставить("ТипыВсехПолей", Новый СписокЗначений); + КонецЕсли; + Если ОписаниеПоля.ВсеПоля.Получить(ПолноеИмяПоля) <> Неопределено Тогда + Возврат; + КонецЕсли; + ОписаниеПоля.ВсеПоля.Вставить(ПолноеИмяПоля, Истина); + + ТипыСтрокой = СтрокаДанныхДляХеширования(СвойстваТекущегоПоля.Тип); + ОписаниеПоля.ТипыВсехПолей.Добавить(ТипыСтрокой, ПолноеИмяПоля); + +КонецПроцедуры + +// Для процедуры ПроверитьПолеТаблицы. +Процедура ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля) + + Если ОписаниеПоля.ТипыВсехПолей.Количество() > 1 Тогда + ОписаниеПоля.ТипыВсехПолей.СортироватьПоПредставлению(); + КонецЕсли; + ТипыСтрокой = СтрСоединить(ОписаниеПоля.ТипыВсехПолей.ВыгрузитьЗначения(), Символы.ПС); + УзлыПоле = ОписаниеПоля.Свойства.УзлыПоле; + + Для Каждого УзелПоле Из УзлыПоле Цикл + УзелПоле.Вставить("ТипыСтрокой", ТипыСтрокой); + КонецЦикла; + + ОписаниеПоля.Удалить("ВсеПоля"); + ОписаниеПоля.Удалить("ТипыВсехПолей"); + +КонецПроцедуры + +// Для процедуры ДобавитьТипыПоляДополнительно. +Процедура ДобавитьОсновнойПорядокПоля(СвойстваТекущегоПоля, Контекст) + + Если СвойстваТекущегоПоля.Коллекция = "СпециальныеПоля" Тогда + Возврат; // Установлен в функции СвойстваПоляИлиТабличнойЧасти. + КонецЕсли; + + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; // ОбъектМетаданныхРегистрСведений + МетаданныеПоля = СвойстваТекущегоПоля.Метаданные; + + Если СвойстваТекущегоПоля.Коллекция = "СтандартныеРеквизиты" Тогда + Индекс = 0; + Для Каждого СтандартныйРеквизит Из МетаданныеТаблицы.СтандартныеРеквизиты Цикл + Если СтандартныйРеквизит = МетаданныеПоля Тогда + Прервать; + КонецЕсли; + Индекс = Индекс + 1; + КонецЦикла; + Номер = 100 + Индекс + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Измерения" Тогда + Номер = 200 + МетаданныеТаблицы.Измерения.Индекс(МетаданныеПоля) + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Ресурсы" Тогда + Номер = 300 + МетаданныеТаблицы.Ресурсы.Индекс(МетаданныеПоля) + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Реквизиты" Тогда + Номер = 400 + МетаданныеТаблицы.Реквизиты.Индекс(МетаданныеПоля) + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "ОбщиеРеквизиты" Тогда + Номер = 500 + Метаданные.ОбщиеРеквизиты.Индекс(МетаданныеПоля) + 1; + КонецЕсли; + + СвойстваТекущегоПоля.Вставить("ОсновнойПорядок", Строка(Номер)); + +КонецПроцедуры + +// Для процедуры ДобавитьТипыПоляДополнительно. +Процедура УстановитьПолеСодержитNull(УзелПоле, СвойстваТекущегоПоля, Контекст) + + Если Контекст.СвойстваТипаТаблиц.ИмяКоллекции <> "Справочники" + И Контекст.СвойстваТипаТаблиц.ИмяКоллекции <> "ПланыВидовХарактеристик" + Или Не Контекст.МетаданныеТаблицы.Иерархический Тогда + + Возврат; + КонецЕсли; + + Если Контекст.СвойстваТипаТаблиц.ИмяКоллекции = "Справочники" + И Контекст.МетаданныеТаблицы.ВидИерархии + <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда + + Возврат; + КонецЕсли; + + Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда + Если СвойстваТекущегоПоля.Свойство("МетаданныеТабличнойЧасти") + И СвойстваТекущегоПоля.МетаданныеТабличнойЧасти.Использование + <> Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда + + УзелПоле.Вставить("ПолеСодержитNull"); + КонецЕсли; + + Возврат; + КонецЕсли; + + Если СвойстваТекущегоПоля.Коллекция = "Реквизиты" + И СвойстваТекущегоПоля.Метаданные.Использование + <> Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда + + УзелПоле.Вставить("ПолеСодержитNull"); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьТаблицыПоляИТипыПолей. +Процедура ПроверитьРасширенияТаблицы(ПоляТаблицы, Контекст) + + СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + Если СвойстваТипаТаблиц.КоллекцииТабличныхЧастей.Количество() = 0 + И СвойстваТипаТаблиц.ИмяКоллекции <> "РегистрыРасчета" Тогда + Возврат; + КонецЕсли; + + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; + + Для Каждого РасширениеТаблицы Из ПоляТаблицы.Значение.Расширения Цикл + + Если СвойстваТипаТаблиц.ИмяКоллекции = "РегистрыРасчета" Тогда + МетаданныеРасширения = МетаданныеТаблицы.Перерасчеты.Найти(РасширениеТаблицы.Ключ); + Иначе + Для Каждого КоллекцияТабличныхЧастей Из СвойстваТипаТаблиц.КоллекцииТабличныхЧастей Цикл + Если КоллекцияТабличныхЧастей.Ключ = "СтандартныеТабличныеЧасти" Тогда + СтандартныеТабличныеЧасти = МетаданныеТаблицы.СтандартныеТабличныеЧасти; // ОписанияСтандартныхТабличныхЧастей + Для Каждого СтандартнаяТабличнаяЧасть Из СтандартныеТабличныеЧасти Цикл + Если ВРег(РасширениеТаблицы.Ключ) = ВРег(СтандартнаяТабличнаяЧасть.Имя) Тогда + МетаданныеРасширения = СтандартнаяТабличнаяЧасть; + Прервать; + КонецЕсли; + КонецЦикла; + Иначе + МетаданныеРасширения = МетаданныеТаблицы[КоллекцияТабличныхЧастей.Ключ].Найти(РасширениеТаблицы.Ключ); + КонецЕсли; + Если МетаданныеРасширения <> Неопределено Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если МетаданныеРасширения = Неопределено Тогда + Продолжить; + КонецЕсли; + РасширениеТаблицы.Значение.ТаблицаСуществует = Истина; + + Для Каждого ПолеТаблицы Из РасширениеТаблицы.Значение.Поля Цикл + ОписаниеПоля = Новый Структура; + ОписаниеПоля.Вставить("СоставИмени", СтрРазделить(ПолеТаблицы.Ключ, ".")); + ОписаниеПоля.Вставить("Свойства", ПолеТаблицы.Значение); + ОписаниеПоля.Вставить("ТипПоля", Новый ОписаниеТипов); + + Индекс = 0; + Если СвойстваТипаТаблиц.ИмяКоллекции = "РегистрыРасчета" Тогда + СвойстваПоля = СвойстваПоляПерерасчета(ОписаниеПоля.СоставИмени[Индекс], + МетаданныеРасширения, МетаданныеТаблицы); + Иначе + СвойстваПоля = СвойстваПоляТабличнойЧасти(ОписаниеПоля.СоставИмени[Индекс], + МетаданныеРасширения, КоллекцияТабличныхЧастей.Ключ, МетаданныеТаблицы); + КонецЕсли; + + Если СвойстваПоля = Неопределено Тогда + ОписаниеПоля.Свойства.ПолеСОшибкой = Индекс + 1; + ОписаниеПоля.Свойства.ВидОшибки = "НеНайдено"; + Продолжить; + КонецЕсли; + ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, СвойстваПоля, Контекст); + ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля); + Если ОписаниеПоля.Свойства.ПолеСОшибкой = 0 Тогда + ПроверитьТипыПоля(ОписаниеПоля, Контекст); + КонецЕсли; + КонецЦикла; + + КонецЦикла; + +КонецПроцедуры + +// Для процедур ПроверитьТаблицыПоляИТипыПолей и ПроверитьРасширенияТаблицы. +Процедура ПроверитьТипыПоля(ОписаниеПоля, Контекст) + + ОписаниеТиповПоля = ОписаниеПоля.ТипПоля; + + Для Каждого ОписаниеТипа Из ОписаниеПоля.Свойства.СодержитТипы Цикл + СвойстваТипа = ОписаниеТипа.Значение; + Если ЗначениеЗаполнено(СвойстваТипа.ИмяКоллекцииТипа) + И Метаданные[СвойстваТипа.ИмяКоллекцииТипа].Найти(СвойстваТипа.ИмяОбъектаКоллекцииТипа) = Неопределено Тогда + Продолжить; + КонецЕсли; + Тип = Тип(ОписаниеТипа.Значение.ИмяТипа); + СвойстваТипа.СодержитТип = ОписаниеТиповПоля.СодержитТип(Тип); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ПроверитьТаблицыПоляИТипыПолей. +// +// Параметры: +// ПоляТаблицы - см. НовыйСоставКоллекции +// +Процедура ПроверитьПредопределенныеЗначенияТаблицы(ПоляТаблицы, Контекст) + + СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + СвойстваТаблицы = ПоляТаблицы.Значение; // см. НовыеСвойстваТаблицы + Если СвойстваТаблицы.Предопределенные.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если СвойстваТипаТаблиц.ЕстьПредопределенные Тогда + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; + + Если СвойстваТипаТаблиц.ИмяКоллекции = "Перечисления" Тогда + ИменаПредопределенных = Новый Массив; + Для Каждого ЗначениеПеречисления Из МетаданныеТаблицы.ЗначенияПеречисления Цикл + ТекущееЗначениеПеречисления = ЗначениеПеречисления; // ОбъектМетаданныхЗначениеПеречисления + ИменаПредопределенных.Добавить(ТекущееЗначениеПеречисления.Имя); + КонецЦикла; + Иначе + ИменаПредопределенных = Новый Массив(МетаданныеТаблицы.ПолучитьИменаПредопределенных()); + КонецЕсли; + Иначе + ИменаПредопределенных = Новый Массив; + КонецЕсли; + + ИменаПредопределенных.Добавить("ПустаяСсылка"); + ИменаПредопределенных.Добавить("EmptyRef"); + + Для Каждого Предопределенный Из СвойстваТаблицы.Предопределенные Цикл + Для Каждого ИмяПредопределенного Из ИменаПредопределенных Цикл + Если ВРег(ИмяПредопределенного) = Предопределенный.Ключ Тогда + Предопределенный.Значение.ИмяСуществует = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + + +// Для функции СтруктураОграничения. +Процедура ОтметитьНекорректныеИменаТаблицПолейИТиповПолей(ПоляТаблиц, Контекст) + + Для Каждого ТипТаблиц Из ПоляТаблиц Цикл + Для Каждого ОписаниеТаблицы Из ТипТаблиц.Значение Цикл + СвойстваТаблицы = ОписаниеТаблицы.Значение; // см. НовыеСвойстваТаблицы + + Если Не СвойстваТаблицы.ТаблицаСуществует Тогда + Для Каждого Источник Из СвойстваТаблицы.Источники Цикл + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица ""%1""'"), Источник.Символы), , 2); + КонецЦикла; + Если СвойстваТаблицы.Свойство("ПервоеПоле") + И СвойстваТаблицы.ПервоеПоле.ПервыйИсточник <> Неопределено Тогда + + УстановитьОшибкуВСтрокеИмениПоля(Контекст, СвойстваТаблицы.ПервоеПоле.ПервыйИсточник.Ключ, + НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , + СвойстваТаблицы.ПервоеПоле.ПервыйИсточник.Значение); + КонецЕсли; + Для Каждого ОписаниеПредопределенного Из СвойстваТаблицы.Предопределенные Цикл + Для Каждого Источник Из ОписаниеПредопределенного.Значение.Источники Цикл + СоставИмени = СтрРазделить(Источник.Символы, "."); + + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Предопределенное значение не существует, так как указана несуществующая таблица ""%1""'"), + СоставИмени[0] + "." + СоставИмени[1]), , 2); + КонецЦикла; + КонецЦикла; + Продолжить; + КонецЕсли; + + Для Каждого ОписаниеПредопределенного Из СвойстваТаблицы.Предопределенные Цикл + СвойстваПредопределенного = ОписаниеПредопределенного.Значение; + Если СвойстваПредопределенного.ИмяСуществует Тогда + Продолжить; + КонецЕсли; + Для Каждого Источник Из СвойстваПредопределенного.Источники Цикл + СоставИмени = СтрРазделить(Источник.Символы, "."); + Источник.ПозицияОшибки = СтрДлина(СоставИмени[0] + "." + СоставИмени[1]) + 1; + Источник.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует предопределенное значение ""%1""'"), СоставИмени[2]); + КонецЦикла; + КонецЦикла; + + Для Каждого ОписаниеПоля Из СвойстваТаблицы.Поля Цикл + ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст); + КонецЦикла; + + Для Каждого ОписаниеРасширения Из СвойстваТаблицы.Расширения Цикл + СвойстваРасширения = ОписаниеРасширения.Значение; + Если Не СвойстваРасширения.ТаблицаСуществует Тогда + Для Каждого Источник Из СвойстваРасширения.Источники Цикл + УстановитьОшибкуВСтроке(Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица ""%1""'"), Источник.Символы), , 2); + КонецЦикла; + Если СвойстваРасширения.Свойство("ПервоеПоле") + И СвойстваРасширения.ПервоеПоле.ПервыйИсточник <> Неопределено Тогда + + УстановитьОшибкуВСтрокеИмениПоля(Контекст, СвойстваРасширения.ПервоеПоле.ПервыйИсточник.Ключ, + НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , + СвойстваРасширения.ПервоеПоле.ПервыйИсточник.Значение); + КонецЕсли; + Продолжить; + КонецЕсли; + Для Каждого ОписаниеПоля Из СвойстваРасширения.Поля Цикл + ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст); + КонецЦикла; + КонецЦикла; + + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеИменаТаблицПолейИТиповПолей. +Процедура ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст) + + СвойстваПоля = ОписаниеПоля.Значение; + Если СвойстваПоля.ПолеСОшибкой = 1 Тогда + Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл + ВКонце = Ложь; + Если СвойстваПоля.ВидОшибки = "ТабличнаяЧастьБезПоля" Тогда + ВКонце = Истина; + ШаблонОшибки = НСтр("ru = 'Не указано поле после табличной части ""%1"" таблицы ""%2""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "ТабличнаяЧастьДополнительнойТаблицы" Тогда + ШаблонОшибки = НСтр("ru = 'Табличная часть ""%1"" не поддерживается для дополнительной таблицы ""%2""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Недопустимо" Тогда + ШаблонОшибки = НСтр("ru = 'Недопустимо использовать поле ""%1"" таблицы ""%2""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Запрещено" Тогда + ШаблонОшибки = НСтр("ru = 'Запрещено использовать поле ""%1"" таблицы ""%2""'"); + Иначе + ШаблонОшибки = НСтр("ru = 'Не существует поле ""%1"" таблицы ""%2""'"); + КонецЕсли; + УстановитьОшибкуВСтрокеИмениПоля(Контекст, + ОписаниеИсточника.Ключ, ШаблонОшибки, 1, Истина, ОписаниеИсточника.Значение, ВКонце); + КонецЦикла; + Возврат; + КонецЕсли; + + Если СвойстваПоля.ПолеСОшибкой > 1 Тогда + Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл + Если СвойстваПоля.ВидОшибки = "ТабличнаяЧастьПослеТочки" Тогда + ШаблонОшибки = НСтр("ru = 'Табличная часть ""%1"" не поддерживается ""через точку"" от поля'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Недопустимо" Тогда + ШаблонОшибки = НСтр("ru = 'Недопустимо использовать поле ""%1""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Запрещено" Тогда + ШаблонОшибки = НСтр("ru = 'Запрещено использовать поле ""%1""'"); + Иначе + ШаблонОшибки = НСтр("ru = 'Не существует поле ""%1""'"); + КонецЕсли; + УстановитьОшибкуВСтрокеИмениПоля(Контекст, + ОписаниеИсточника.Ключ, ШаблонОшибки, СвойстваПоля.ПолеСОшибкой, Истина); + КонецЦикла; + Возврат; + КонецЕсли; + + СоставИмени = СтрРазделить(ОписаниеПоля.Ключ, "."); + Если СоставИмени.Количество() > 1 + И ( СоставИмени[1] = ВРег("Ссылка") + Или СоставИмени[1] = ВРег("Ref") ) + И СвойстваПоля.Коллекция <> "ТабличныеЧасти" + И СвойстваПоля.Коллекция <> "СтандартныеТабличныеЧасти" Тогда + + Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл + ШаблонОшибки = НСтр("ru = 'Поле ""%1"" избыточно указывать ""через точку"" от любого поля'"); + УстановитьОшибкуВСтрокеИмениПоля(Контекст, + ОписаниеИсточника.Ключ, ШаблонОшибки, 2, Истина); + КонецЦикла; + Возврат; + КонецЕсли; + + Для Каждого ОписаниеТипа Из СвойстваПоля.СодержитТипы Цикл + СвойстваТипа = ОписаниеТипа.Значение; + Для Каждого ОписаниеИсточника Из ОписаниеТипа.Значение.Источники Цикл + Если ТипЗнч(ОписаниеИсточника.Ключ) = Тип("СтрокаТаблицыЗначений") Тогда + Если Не СвойстваТипа.СодержитТип Тогда + УстановитьОшибкуВСтроке(ОписаниеИсточника.Ключ, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У поля ""%1"" не существует тип ""%2""'"), + ОписаниеИсточника.Значение.Символы, + ОписаниеИсточника.Ключ.Символы), + , 2); + КонецЕсли; + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеИменаТаблицПолейИТиповПолей. +Процедура УстановитьОшибкуВСтрокеИмениПоля(Контекст, Строка, ШаблонОшибки, ПолеСОшибкой, + ВставитьИмя = Ложь, Таблица = Null, ВКонце = Ложь) + + Если ЗначениеЗаполнено(Строка.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ВставитьИмя) = Тип("Строка") Тогда + СоставИмени = СтрРазделить(ВставитьИмя, "."); + ВставитьИмя = Истина; + Иначе + СоставИмени = СтрРазделить(Строка.Символы, "."); + КонецЕсли; + + Если СоставИмени.Количество() > 1 + И Контекст.Псевдонимы.Получить(ВРег(СоставИмени[0])) <> Неопределено Тогда + + Строка.ПозицияОшибки = СтрДлина(СоставИмени[0]) + 1; + СоставИмени.Удалить(0); + КонецЕсли; + + Для Номер = 1 По ПолеСОшибкой - 1 Цикл + Строка.ПозицияОшибки = Строка.ПозицияОшибки + СтрДлина(СоставИмени[0]) + 1; + СоставИмени.Удалить(0); + КонецЦикла; + Если ВКонце Тогда + Строка.ПозицияОшибки = Строка.ПозицияОшибки + СтрДлина(СоставИмени[0]); + КонецЕсли; + ИмяПоля = СоставИмени[0]; + + Если ВставитьИмя И Таблица <> Null Тогда + Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + ИмяПоля, ?(ЗначениеЗаполнено(Таблица), Таблица, Контекст.ОсновнаяТаблица)); + + ИначеЕсли ВставитьИмя Тогда + Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, ИмяПоля); + + ИначеЕсли Таблица <> Null Тогда + Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + ?(ЗначениеЗаполнено(Таблица), Таблица, Контекст.ОсновнаяТаблица)); + Иначе + Строка.ТекстОшибки = ШаблонОшибки; + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область ОбновлениеПрогрессаОбновленияДоступа + +// Возвращаемое значение: +// Структура: +// * СтрокиСписков - Соответствие +// * СвойстваСписков - Соответствие +// * КоличествоКлючей - Число +// * ДатаПоследнегоОбновления - Дата +// +Функция НовыеХранимыеДанныеОбновленияПрогресса() Экспорт + + ХранимыеДанные = Новый Структура; + ХранимыеДанные.Вставить("СтрокиСписков", Новый Соответствие); + ХранимыеДанные.Вставить("СвойстваСписков", Новый Соответствие); + ХранимыеДанные.Вставить("КоличествоКлючей", 0); + ХранимыеДанные.Вставить("ДатаПоследнегоОбновления", '00010101'); + + Возврат ХранимыеДанные; + +КонецФункции + +// Параметры: +// Контекст - Структура: +// * Версия - Число +// * ХранимыеДанные - см. НовыеХранимыеДанныеОбновленияПрогресса +// * РассчитыватьПоКоличествуДанных - Булево +// * ПоказыватьОбработанныеСписки - Булево +// * ЭтоПовторноеОбновлениеПрогресса - Булево +// * ВсегоОбновлено - Число +// * ПериодОбновленияПрогресса - Число +// * АвтообновлениеПрогресса - Булево +// * ДобавленныеСтроки - Массив +// * УдаленныеСтроки - Соответствие +// * ИзмененныеСтроки - Соответствие +// * ОбновлениеДоступаВыполняется - Булево +// +// АдресРезультата - Строка +// +Процедура ОбновитьПрогрессВФоне(Контекст, АдресРезультата) Экспорт + + ТекстОшибки = Неопределено; + + Если Контекст.Свойство("Версия") И Контекст.Версия = 1 Тогда + Попытка + ОбновитьПрогресс(Контекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если Не СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + ВызватьИсключение; + КонецЕсли; + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Иначе + ТекстОшибки = НСтр("ru = 'Версия приложения обновлена, перезапустите клиентский сеанс.'"); + КонецЕсли; + + Если ТекстОшибки <> Неопределено Тогда + Контекст.Вставить("ИнформацияОбОшибке", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить прогресс по причине: + |%1'"), ТекстОшибки)); + КонецЕсли; + + ПоместитьВоВременноеХранилище(Контекст, АдресРезультата); + +КонецПроцедуры + +Процедура ОбновитьПрогресс(Контекст) + + ДатаНачалаОбновленияПрогресса = ТекущаяДатаСеанса(); + ДлительныеОперации.СообщитьПрогресс(0); // Обновление прогресса выполняется. + + СтрокиСписков = Контекст.ХранимыеДанные.СтрокиСписков; + СвойстваСписков = Контекст.ХранимыеДанные.СвойстваСписков; + Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = '00010101'; + КонецЕсли; + + ДействующиеПараметры = Неопределено; // См. ДействующиеПараметрыОграниченияДоступа + ИдентификаторыТаблиц = ИдентификаторыСписковСОграничением(ДействующиеПараметры); + + Если Контекст.ПоказыватьОбработанныеСписки Тогда + Для Каждого КлючИЗначение Из ИдентификаторыТаблиц Цикл + Если СтрокиСписков.Получить(КлючИЗначение.Значение) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавитьНовуюСтрокуСписка(Контекст, КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЦикла; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДатаПриПродолжении()); + Запрос.УстановитьПараметр("ДатаПоследнегоОбновления", Контекст.ХранимыеДанные.ДатаПоследнегоОбновления); + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = ДатаНачалаОбновленияПрогресса; + + ТекстыЗапросов = Новый Массив; + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ + | ВсеСпискиОбновления.Список КАК Список, + | МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеЭлементов) КАК ОбновлениеЭлементов, + | МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеКлючейДоступа) КАК ОбновлениеКлючейДоступа + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаКДанным.Список КАК Список, + | ИСТИНА КАК ОбновлениеЭлементов, + | ЛОЖЬ КАК ОбновлениеКлючейДоступа + | ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаПользователей.Список, + | ЛОЖЬ, + | ИСТИНА + | ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей) КАК ВсеСпискиОбновления + | + |СГРУППИРОВАТЬ ПО + | ВсеСпискиОбновления.Список"); + + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючей.Список КАК Список + |ПОМЕСТИТЬ ИзмененныеСпискиКлючейДоступаКДанным + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей + |ГДЕ + | ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления + | И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО + | + |ИНДЕКСИРОВАТЬ ПО + | Список + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ОбновлениеКлючей.Список КАК Список, + | ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей, + | ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор КАК ЭтоОсновнаяЗапись, + | МАКСИМУМ(ОбновлениеКлючей.РазмерЗадания) КАК РазмерЗадания, + | МАКСИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МаксимальнаяДатаИзменения, + | МИНИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МинимальнаяДатаИзменения + |ИЗ + | ИзмененныеСпискиКлючейДоступаКДанным КАК ИзмененныеСписки + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей + | ПО (ОбновлениеКлючей.Список = ИзмененныеСписки.Список) + | + |СГРУППИРОВАТЬ ПО + | ОбновлениеКлючей.Список, + | ОбновлениеКлючей.ДляВнешнихПользователей, + | ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор + |ИТОГИ ПО + | Список, + | ДляВнешнихПользователей"); + + ТекстыЗапросов.Добавить(СтрЗаменить(СтрЗаменить(ТекстыЗапросов[1], + "ИзмененныеСпискиКлючейДоступаКДанным", + "ИзмененныеСпискиКлючейДоступаПользователей"), + "РегистрСведений.ОбновлениеКлючейДоступаКДанным", + "РегистрСведений.ОбновлениеКлючейДоступаПользователей")); + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ + | ОбновлениеКлючей.Список КАК Список, + | ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей, + | ОбновлениеКлючей.ПараметрыЗадания КАК ПараметрыЗадания + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей + |ГДЕ + | ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления + | И ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор + | И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО + |ИТОГИ ПО + | Список"); + + ТекстыЗапросов.Добавить(СтрЗаменить(ТекстыЗапросов[3], + "РегистрСведений.ОбновлениеКлючейДоступаКДанным", + "РегистрСведений.ОбновлениеКлючейДоступаПользователей")); + + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа"); + КонецЕсли; + + Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + ВсеСпискиОбновления = РезультатыЗапроса[0].Выгрузить(); + НовыеСписки = Новый Массив; + + Для Каждого СписокОбновления Из ВсеСпискиОбновления Цикл + Если Не ЗначениеЗаполнено(СписокОбновления.Список) Тогда + Продолжить; + КонецЕсли; + Строка = СтрокиСписков.Получить(СписокОбновления.Список); + Если Строка = Неопределено Тогда + НовыеСписки.Добавить(СписокОбновления.Список); + КонецЕсли; + КонецЦикла; + + Если НовыеСписки.Количество() > 0 Тогда + ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(НовыеСписки, Ложь); + Для Каждого НовыйСписок Из НовыеСписки Цикл + ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(НовыйСписок); + Если ОбъектМетаданных = Неопределено Тогда + Продолжить; + ИначеЕсли ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда + ИмяТаблицы = ОбъектМетаданных.ПолноеИмя(); + Иначе + ИмяТаблицы = ""; + КонецЕсли; + ДобавитьНовуюСтрокуСписка(Контекст, НовыйСписок, ИмяТаблицы); + КонецЦикла; + КонецЕсли; + + СтрокиОбновленияКоличестваЭлементов = Новый Массив; + СтрокиОбновленияКоличестваКлючейДоступа = Новый Массив; + УдаляемыеСтроки = Новый Массив; + Для Каждого КлючИЗначение Из СтрокиСписков Цикл + Строка = КлючИЗначение.Значение; + СписокОбновления = ВсеСпискиОбновления.Найти(Строка.Список, "Список"); + Если СписокОбновления = Неопределено И Не Контекст.ПоказыватьОбработанныеСписки Тогда + УдаляемыеСтроки.Добавить(Строка); + Продолжить; + КонецЕсли; + СвойстваСписка = СвойстваСписков.Получить(Строка.Список); + Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеЭлементов Тогда + СвойстваСписка.РазмерЗаданияОбновленияЭлементов = 0; + СвойстваСписка.ПоследнийОбновленныйЭлемент = Null; + СвойстваСписка.РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей = 0; + СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей = Null; + Строка.ДоляОбработанныхЭлементовДляПользователей = 1; + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = 1; + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + Если Строка.ОбработаноЭлементов <> 100 Тогда + СтрокиОбновленияКоличестваЭлементов.Добавить(Строка); + КонецЕсли; + Иначе + ОбнулитьКоличествоЭлементов(Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст); + КонецЕсли; + Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеКлючейДоступа Тогда + СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступа = 0; + СвойстваСписка.ПоследнийОбновленныйКлючДоступа = Null; + СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей = 0; + СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей = Null; + Строка.ДоляОбработанныхКлючейДоступаДляПользователей = 1; + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = 1; + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + Если Строка.ОбработаноКлючейДоступа <> 100 Тогда + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка); + КонецЕсли; + Иначе + ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст); + КонецЕсли; + Если СписокОбновления = Неопределено Тогда + ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, '00010101', Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, МаксимальнаяДата(), Строка, Контекст); + КонецЕсли; + КонецЦикла; + + Для Каждого УдаляемаяСтрока Из УдаляемыеСтроки Цикл + СтрокиСписков.Удалить(УдаляемаяСтрока.Список); + СвойстваСписков.Удалить(УдаляемаяСтрока.Список); + Индекс = Контекст.ДобавленныеСтроки.Найти(УдаляемаяСтрока); + Если Индекс <> Неопределено Тогда + Контекст.ДобавленныеСтроки.Удалить(Индекс); + Продолжить; + КонецЕсли; + Контекст.УдаленныеСтроки.Вставить(УдаляемаяСтрока.Список, Истина); + КонецЦикла; + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + ВыборкаПоСпискам = РезультатыЗапроса[5].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); + Пока ВыборкаПоСпискам.Следующий() Цикл + СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список); + Если СвойстваСписка = Неопределено Тогда + Продолжить; + КонецЕсли; + ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать(); + Пока ВыборкаПоВидамПользователей.Следующий() Цикл + Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлементДляВнешнихПользователей"; + Иначе + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлемент"; + КонецЕсли; + Если СвойстваСписка[ИмяПоляПараметровЗадания] <> Истина Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = ВыборкаПоВидамПользователей.ПараметрыЗадания; + КонецЕсли; + КонецЦикла; + КонецЦикла; + ВыборкаПоСпискам = РезультатыЗапроса[6].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); + Пока ВыборкаПоСпискам.Следующий() Цикл + СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список); + Если СвойстваСписка = Неопределено Тогда + Продолжить; + КонецЕсли; + ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать(); + Пока ВыборкаПоВидамПользователей.Следующий() Цикл + Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей"; + Иначе + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступа"; + КонецЕсли; + Если СвойстваСписка[ИмяПоляПараметровЗадания] <> Истина Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = ВыборкаПоВидамПользователей.ПараметрыЗадания; + КонецЕсли; + КонецЦикла; + КонецЦикла; + КонецЕсли; + + СпискиОбновленияЭлементов = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого ОписаниеОбновления Из СпискиОбновленияЭлементов.Строки Цикл + Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список); + Если Строка = Неопределено Тогда + Продолжить; + КонецЕсли; + СвойстваСписка = СвойстваСписков.Получить(Строка.Список); + ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Истина, Контекст); + Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда + Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхЭлементовДляПользователей, + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры); + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, Обработано, Строка, Контекст); + ОбнулитьКоличествоЭлементов(Строка, Контекст); + + ИначеЕсли Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + СтрокиОбновленияКоличестваЭлементов.Добавить(Строка); + КонецЕсли; + КонецЦикла; + + СпискиОбновленияКлючейДоступа = РезультатыЗапроса[4].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого ОписаниеОбновления Из СпискиОбновленияКлючейДоступа.Строки Цикл + Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список); + Если Строка = Неопределено Тогда + Продолжить; + КонецЕсли; + СвойстваСписка = СвойстваСписков.Получить(Строка.Список); + ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Ложь, Контекст); + Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда + Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхКлючейДоступаДляПользователей, + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры); + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, Обработано, Строка, Контекст); + ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + + ИначеЕсли Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка); + КонецЕсли; + КонецЦикла; + + Индекс = Контекст.ДобавленныеСтроки.Количество() - 1; + Пока Индекс >= 0 Цикл + Если Не ЗначениеЗаполнено(Контекст.ДобавленныеСтроки[Индекс].ИмяТаблицы) Тогда + Контекст.ДобавленныеСтроки.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + КоличествоКлючей = РезультатыЗапроса[7].Выгрузить()[0].Количество; + Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл + СтрокиОбновленияКоличестваЭлементов.Добавить(ОписаниеСтроки.Значение); + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение); + КонецЦикла; + ИначеЕсли Контекст.ХранимыеДанные.КоличествоКлючей <> КоличествоКлючей Тогда + Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл + Если СтрокиОбновленияКоличестваКлючейДоступа.Найти(ОписаниеСтроки.Значение) = Неопределено Тогда + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Контекст.ХранимыеДанные.КоличествоКлючей = КоличествоКлючей; + Иначе + Контекст.ХранимыеДанные.КоличествоКлючей = 0; + КонецЕсли; + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + ТекущийКонтекст = Новый Структура; + ТекущийКонтекст.Вставить("ДобавленныеСтроки", Контекст.ДобавленныеСтроки); + ТекущийКонтекст.Вставить("ИзмененныеСтроки", Контекст.ИзмененныеСтроки); + ТекущийКонтекст.Вставить("СвойстваСписков", СвойстваСписков); + ТекущийКонтекст.Вставить("СтрокиСписков", СтрокиСписков); + ТекущийКонтекст.Вставить("ДействующиеПараметры", ДействующиеПараметры); + ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваЭлементов", СтрокиОбновленияКоличестваЭлементов); + ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваКлючейДоступа", СтрокиОбновленияКоличестваКлючейДоступа); + ТекущийКонтекст.Вставить("ИдентификаторыТаблиц", ИдентификаторыТаблиц); + ТекущийКонтекст.Вставить("ХранимыеДанные", Контекст.ХранимыеДанные); + ВсегоОбновлено = 100; + РассчитатьВсегоОбновленоПоКоличествуДанных(ТекущийКонтекст, ВсегоОбновлено); + Иначе + Если Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда + Контекст.ХранимыеДанные.Удалить("КоличествоЭлементовПоСпискам"); + Контекст.ХранимыеДанные.Удалить("КоличествоКлючейДоступаПоСпискам"); + КонецЕсли; + ВсегоКоличество = ИдентификаторыТаблиц.Количество(); + Если СтрокиСписков.Количество() > ВсегоКоличество Тогда + ВсегоКоличество = СтрокиСписков.Количество(); + КонецЕсли; + ВсегоОбновлено = (100 + 100) * (ВсегоКоличество - СтрокиСписков.Количество()); + Для Каждого КлючИЗначение Из СтрокиСписков Цикл + Строка = КлючИЗначение.Значение; + ВсегоОбновлено = ВсегоОбновлено + Строка.ОбработаноЭлементов + Строка.ОбработаноКлючейДоступа; + КонецЦикла; + ВсегоОбновлено = ВсегоОбновлено / 2 / ВсегоКоличество; + КонецЕсли; + Если ВсегоОбновлено > 100 Тогда + ВсегоОбновлено = 100; + КонецЕсли; + Контекст.ВсегоОбновлено = Цел(ВсегоОбновлено); + + ВремяОбновления = ТекущаяДатаСеанса() - ДатаНачалаОбновленияПрогресса; + + Если Контекст.ЭтоПовторноеОбновлениеПрогресса + И ВремяОбновления > Контекст.ПериодОбновленияПрогресса Тогда + + Контекст.ПериодОбновленияПрогресса = ВремяОбновления; + Иначе + Контекст.Удалить("ПериодОбновленияПрогресса"); + КонецЕсли; + + Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса И ВремяОбновления > 60 Тогда + Контекст.АвтообновлениеПрогресса = Ложь; + Иначе + Контекст.Удалить("АвтообновлениеПрогресса"); + КонецЕсли; + +КонецПроцедуры + +Процедура ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, ЭтоОбработкаЭлементов, Контекст) + + Для Каждого СвойстваОбновления Из ОписаниеОбновления.Строки Цикл + Если ЭтоОбработкаЭлементов Тогда + Если СвойстваОбновления.ДляВнешнихПользователей Тогда + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлементДляВнешнихПользователей"; + ИмяПоляДоли = "ДоляОбработанныхЭлементовДляВнешнихПользователей"; + Иначе + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияЭлементов"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлемент"; + ИмяПоляДоли = "ДоляОбработанныхЭлементовДляПользователей"; + КонецЕсли; + Иначе + Если СвойстваОбновления.ДляВнешнихПользователей Тогда + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей"; + ИмяПоляДоли = "ДоляОбработанныхКлючейДоступаДляВнешнихПользователей"; + Иначе + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияКлючейДоступа"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступа"; + ИмяПоляДоли = "ДоляОбработанныхКлючейДоступаДляПользователей"; + КонецЕсли; + КонецЕсли; + РазмерЗаданияОсновнаяЗапись = СвойстваСписка[ИмяПоляРазмераЗадания]; + РазмерЗаданияНовыеЗаписи = 0; + Для Каждого СвойстваЗадания Из СвойстваОбновления.Строки Цикл + Если СвойстваЗадания.ЭтоОсновнаяЗапись Тогда + Если СвойстваЗадания.МаксимальнаяДатаИзменения > Строка.ПоследнееОбновление Тогда + ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, + СвойстваЗадания.МаксимальнаяДатаИзменения, Строка, Контекст); + КонецЕсли; + РазмерЗаданияОсновнаяЗапись = СвойстваЗадания.РазмерЗадания; + Иначе + Если СвойстваЗадания.МинимальнаяДатаИзменения < Строка.ПервоеПланированиеОбновления Тогда + ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, + СвойстваЗадания.МинимальнаяДатаИзменения, Строка, Контекст); + КонецЕсли; + РазмерЗаданияНовыеЗаписи = СвойстваЗадания.РазмерЗадания; + КонецЕсли; + КонецЦикла; + СвойстваСписка[ИмяПоляРазмераЗадания] = РазмерЗаданияОсновнаяЗапись; + Если РазмерЗаданияНовыеЗаписи >= РазмерЗаданияОсновнаяЗапись Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = Истина; + ТекущийРазмерЗадания = РазмерЗаданияНовыеЗаписи; + Иначе + ТекущийРазмерЗадания = РазмерЗаданияОсновнаяЗапись; + Если СвойстваСписка[ИмяПоляПараметровЗадания] = Истина Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = Null; + КонецЕсли; + КонецЕсли; + Если ТекущийРазмерЗадания = 1 Тогда + Строка[ИмяПоляДоли] = 0.99; + ИначеЕсли ТекущийРазмерЗадания = 2 Тогда + Строка[ИмяПоляДоли] = 0.90; + Иначе + Строка[ИмяПоляДоли] = 0.00; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Функция ОбработаноПоДолям(ДоляОбработанныхДляПользователей, ДоляОбработанныхДляВнешнихПользователей, ИмяТаблицы, ДействующиеПараметры) + + ЕстьКлючиДляПользователей = Ложь; + ЕстьКлючиДляВнешнихПользователей = Ложь; + Версии = ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ИмяТаблицы); + Если ЗначениеЗаполнено(Версии) Тогда + ЕстьКлючиДляПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 1)); + ЕстьКлючиДляВнешнихПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 2)); + КонецЕсли; + + Если ДоляОбработанныхДляПользователей < 1 Тогда + ЕстьКлючиДляПользователей = Истина; + КонецЕсли; + Если ДоляОбработанныхДляВнешнихПользователей < 1 Тогда + ЕстьКлючиДляВнешнихПользователей = Истина; + КонецЕсли; + + Если ЕстьКлючиДляПользователей И ЕстьКлючиДляВнешнихПользователей Тогда + Обработано = Цел((ДоляОбработанныхДляПользователей + + ДоляОбработанныхДляВнешнихПользователей) / 2 * 100); + + ИначеЕсли ЕстьКлючиДляПользователей Тогда + Обработано = Цел(ДоляОбработанныхДляПользователей * 100); + Иначе + Обработано = Цел(ДоляОбработанныхДляВнешнихПользователей * 100); + КонецЕсли; + + Возврат Обработано; + +КонецФункции + +Процедура ОбнулитьКоличествоЭлементов(Строка, Контекст); + + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементов, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементовДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементовДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяЭлементовДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяЭлементовДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей, 0, Строка, Контекст); + +КонецПроцедуры + +Процедура ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступа, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступаДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяКлючейДоступаДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяКлючейДоступаДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); + +КонецПроцедуры + +Процедура ДобавитьНовуюСтрокуСписка(Контекст, Список, ИмяТаблицы) + + Строка = Новый Структура; + Строка.Вставить("Список", Список); + Строка.Вставить("СписокПредставление", Строка(Список)); + Строка.Вставить("ИмяТаблицы", ИмяТаблицы); + Строка.Вставить("ОбработаноЭлементов", 0); + Строка.Вставить("ОбработаноКлючейДоступа", 0); + Строка.Вставить("КоличествоЭлементов", 0); + Строка.Вставить("КоличествоКлючейДоступа", 0); + Строка.Вставить("КоличествоОбработанныхЭлементов", 0); + Строка.Вставить("КоличествоОбработанныхКлючейДоступа", 0); + Строка.Вставить("ПоследнееОбновление", '00010101'); + Строка.Вставить("ПервоеПланированиеОбновления", МаксимальнаяДата()); + + Строка.Вставить("КоличествоЭлементовДляПользователей", 0); + Строка.Вставить("ДоляОбработанныхЭлементовДляПользователей", 1); + Строка.Вставить("КоличествоЭлементовДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОбработанныхЭлементовДляВнешнихПользователей", 1); + Строка.Вставить("КоличествоКлючейДоступаДляПользователей", 0); + Строка.Вставить("ДоляОбработанныхКлючейДоступаДляПользователей", 1); + Строка.Вставить("КоличествоКлючейДоступаДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОбработанныхКлючейДоступаДляВнешнихПользователей", 1); + + Строка.Вставить("КоличествоОставшихсяЭлементовДляПользователей", 0); + Строка.Вставить("ДоляОставшихсяЭлементовДляПользователей", 0); + Строка.Вставить("КоличествоОставшихсяЭлементовДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОставшихсяЭлементовДляВнешнихПользователей", 0); + Строка.Вставить("КоличествоОставшихсяКлючейДоступаДляПользователей", 0); + Строка.Вставить("ДоляОставшихсяКлючейДоступаДляПользователей", 0); + Строка.Вставить("КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОставшихсяКлючейДоступаДляВнешнихПользователей", 0); + + Контекст.ХранимыеДанные.СтрокиСписков.Вставить(Список, Строка); + ДобавленныеСтроки = Контекст.ДобавленныеСтроки; // Массив + ДобавленныеСтроки.Добавить(Строка); + + Свойства = Новый Структура; + Свойства.Вставить("РазмерЗаданияОбновленияЭлементов", 0); + Свойства.Вставить("ПоследнийОбновленныйЭлемент", Null); + Свойства.Вставить("РазмерЗаданияОбновленияКлючейДоступа", 0); + Свойства.Вставить("ПоследнийОбновленныйКлючДоступа", Null); + + Свойства.Вставить("РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей", 0); + Свойства.Вставить("ПоследнийОбновленныйЭлементДляВнешнихПользователей", Null); + Свойства.Вставить("РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей", 0); + Свойства.Вставить("ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей", Null); + + Контекст.ХранимыеДанные.СвойстваСписков.Вставить(Список, Свойства); + +КонецПроцедуры + +// Параметры: +// Контекст - Структура: +// * ДобавленныеСтроки - Массив +// * ИзмененныеСтроки - Соответствие +// * СвойстваСписков - Соответствие +// * СтрокиСписков - Соответствие +// * ДействующиеПараметры - см. ДействующиеПараметрыОграниченияДоступа +// * СтрокиОбновленияКоличестваЭлементов - Массив +// * СтрокиОбновленияКоличестваКлючейДоступа - Массив +// * ИдентификаторыТаблиц - см. ОбщегоНазначения.ИдентификаторыОбъектовМетаданных +// * ХранимыеДанные - см. НовыеХранимыеДанныеОбновленияПрогресса +// * ТипыТаблицПоИменам - Соответствие +// +// ВсегоОбновлено - Число +// +Процедура РассчитатьВсегоОбновленоПоКоличествуДанных(Контекст, ВсегоОбновлено) + + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + Контекст.Вставить("ТипыТаблицПоИменам", ТипыТаблицПоИменам); + + Если Не Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда + ЗаполнитьКоличествоЭлементовИКлючейДоступаПоСпискам(Контекст); + КонецЕсли; + + ОбновитьКоличествоЭлементовИКлючейДоступа(Контекст); + + КоличествоЭлементовПоСпискам = Контекст.ХранимыеДанные.КоличествоЭлементовПоСпискам; + КоличествоКлючейДоступаПоСпискам = Контекст.ХранимыеДанные.КоличествоКлючейДоступаПоСпискам; + + ОбщееКоличествоЭлементов = 0; + Для Каждого КлючИЗначение Из КоличествоЭлементовПоСпискам Цикл + ОбщееКоличествоЭлементов = ОбщееКоличествоЭлементов + КлючИЗначение.Значение; + КонецЦикла; + ОбщееКоличествоЭлементов = ?(ОбщееКоличествоЭлементов = 0, 100, ОбщееКоличествоЭлементов); + + ОбщееКоличествоКлючейДоступа = 0; + Для Каждого КлючИЗначение Из КоличествоКлючейДоступаПоСпискам Цикл + ОбщееКоличествоКлючейДоступа = ОбщееКоличествоКлючейДоступа + КлючИЗначение.Значение; + КонецЦикла; + ОбщееКоличествоКлючейДоступа = ?(ОбщееКоличествоКлючейДоступа = 0, 100, ОбщееКоличествоКлючейДоступа); + + ВсегоОбновленоЭлементов = 0; + ВсегоОбновленоКлючейДоступа = 0; + + ДобавкаОбщегоКоличестваЭлементов = 0; + ДобавкаОбщегоКоличестваКлючейДоступа = 0; + + ИменаТаблицСОбновлениемЭлементов = Новый Соответствие; + ИменаТаблицСОбновлениемКлючейДоступа = Новый Соответствие; + + Для Каждого КлючИЗначение Из Контекст.СтрокиСписков Цикл + Строка = КлючИЗначение.Значение; + + КоличествоЭлементов = КоличествоЭлементовПоСпискам.Получить(КлючИЗначение.Значение.ИмяТаблицы); + Если КоличествоЭлементов = Неопределено Тогда + Если КоличествоЭлементовПоСпискам.Количество() = 0 Тогда + Добавка = 1; + Иначе + Добавка = Цел(ОбщееКоличествоЭлементов / КоличествоЭлементовПоСпискам.Количество() / 10); + Добавка = ?(Добавка = 0, 1, Добавка); + КонецЕсли; + ДобавкаОбщегоКоличестваЭлементов = ДобавкаОбщегоКоличестваЭлементов + Добавка; + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + 100 * Добавка; + Иначе + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + Строка.ОбработаноЭлементов * КоличествоЭлементов; + ИменаТаблицСОбновлениемЭлементов.Вставить(КлючИЗначение.Значение.ИмяТаблицы, Истина); + КонецЕсли; + + КоличествоКлючейДоступа = КоличествоКлючейДоступаПоСпискам.Получить(КлючИЗначение.Значение.ИмяТаблицы); + Если КоличествоКлючейДоступа = Неопределено Тогда + Если КоличествоКлючейДоступаПоСпискам.Количество() = 0 Тогда + Добавка = 1; + Иначе + Добавка = Цел(ОбщееКоличествоКлючейДоступа / КоличествоКлючейДоступаПоСпискам.Количество() / 10); + Добавка = ?(Добавка = 0, 1, Добавка); + КонецЕсли; + ДобавкаОбщегоКоличестваКлючейДоступа = ДобавкаОбщегоКоличестваКлючейДоступа + Добавка; + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + 100 * Добавка; + Иначе + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + Строка.ОбработаноКлючейДоступа * КоличествоКлючейДоступа; + ИменаТаблицСОбновлениемКлючейДоступа.Вставить(КлючИЗначение.Значение.ИмяТаблицы, Истина); + КонецЕсли; + КонецЦикла; + + КоличествоОбновленныхЭлементов = 0; + Для Каждого КлючИЗначение Из КоличествоЭлементовПоСпискам Цикл + Если ИменаТаблицСОбновлениемЭлементов.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + КоличествоОбновленныхЭлементов = КоличествоОбновленныхЭлементов + КлючИЗначение.Значение; + КонецЕсли; + КонецЦикла; + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + КоличествоОбновленныхЭлементов * 100; + + КоличествоОбновленныхКлючейДоступа = 0; + Для Каждого КлючИЗначение Из КоличествоКлючейДоступаПоСпискам Цикл + Если ИменаТаблицСОбновлениемКлючейДоступа.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + КоличествоОбновленныхКлючейДоступа = КоличествоОбновленныхКлючейДоступа + КлючИЗначение.Значение; + КонецЕсли; + КонецЦикла; + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + КоличествоОбновленныхКлючейДоступа * 100; + + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + / (ОбщееКоличествоЭлементов + ДобавкаОбщегоКоличестваЭлементов); + + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + / (ОбщееКоличествоКлючейДоступа + ДобавкаОбщегоКоличестваКлючейДоступа); + + ВсегоОбновлено = (ВсегоОбновленоЭлементов + ВсегоОбновленоКлючейДоступа) / 2; + +КонецПроцедуры + +Процедура ЗаполнитьКоличествоЭлементовИКлючейДоступаПоСпискам(Контекст) + + КоличествоЭлементовПоСпискам = Новый Соответствие; + КоличествоКлючейДоступаПоСпискам = Новый Соответствие; + Контекст.ХранимыеДанные.Вставить("КоличествоЭлементовПоСпискам", КоличествоЭлементовПоСпискам); + Контекст.ХранимыеДанные.Вставить("КоличествоКлючейДоступаПоСпискам", КоличествоКлючейДоступаПоСпискам); + + ОписаниеЗапроса = Новый Структура("Запрос, ТекстыПакетаЗапросов", Новый Запрос, Новый Массив); + + ОбновляемыеТаблицы = Новый Соответствие; + ИдентификаторыТаблиц = Контекст.ИдентификаторыТаблиц; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл + Если ИдентификаторыТаблиц.Получить(Строка.ИмяТаблицы) = Строка.Список Тогда + ОбновляемыеТаблицы.Вставить(Строка.ИмяТаблицы, Строка.Список); + КонецЕсли; + КонецЦикла; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл + Если ИдентификаторыТаблиц.Получить(Строка.ИмяТаблицы) = Строка.Список Тогда + ОбновляемыеТаблицы.Вставить(Строка.ИмяТаблицы, Строка.Список); + КонецЕсли; + КонецЦикла; + + Индекс = 0; + ИменаТаблиц = Новый Массив; + Для Каждого КлючИЗначение Из Контекст.ИдентификаторыТаблиц Цикл + Если ОбновляемыеТаблицы.Получить(КлючИЗначение.Ключ) = КлючИЗначение.Значение Тогда + Продолжить; + КонецЕсли; + ИменаТаблиц.Добавить(КлючИЗначение.Ключ); + Строка = Новый Структура("Список, ИмяТаблицы", КлючИЗначение.Значение, КлючИЗначение.Ключ); + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Ложь); + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Истина); + КонецЦикла; + + Если ОписаниеЗапроса.ТекстыПакетаЗапросов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + РезультатыЗапроса = ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса); + + Индекс = 0; + Для Каждого ИмяТаблицы Из ИменаТаблиц Цикл + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоЭлементовДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоЭлементовДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоЭлементовПоСпискам[ИмяТаблицы] = КоличествоЭлементовДляПользователей + + КоличествоЭлементовДляВнешнихПользователей; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоКлючейДоступаДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоКлючейДоступаДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоКлючейДоступаПоСпискам[ИмяТаблицы] = КоличествоКлючейДоступаДляПользователей + + КоличествоКлючейДоступаДляВнешнихПользователей; + КонецЦикла; + +КонецПроцедуры + +Процедура ОбновитьКоличествоЭлементовИКлючейДоступа(Контекст) + + ОписаниеЗапроса = Новый Структура("Запрос, ТекстыПакетаЗапросов", Новый Запрос, Новый Массив); + Индекс = 0; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + КонецЦикла; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Ложь); + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Истина); + ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + КонецЦикла; + + Если ОписаниеЗапроса.ТекстыПакетаЗапросов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + РезультатыЗапроса = ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса); + + КоличествоЭлементовПоСпискам = Контекст.ХранимыеДанные.КоличествоЭлементовПоСпискам; + КоличествоКлючейДоступаПоСпискам = Контекст.ХранимыеДанные.КоличествоКлючейДоступаПоСпискам; + ВерсииОграниченийСписков = Контекст.ДействующиеПараметры.ВерсииОграниченийСписков; + ТипыТаблицПоИменам = Контекст.ТипыТаблицПоИменам; + + Индекс = 0; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоЭлементовДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоЭлементовДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоЭлементов = Строка.КоличествоЭлементовДляПользователей + Строка.КоличествоЭлементовДляВнешнихПользователей; + Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда + КоличествоЭлементовПоСпискам.Вставить(Строка.ИмяТаблицы, КоличествоЭлементов); + КонецЕсли; + + Если КоличествоЭлементов = 0 Тогда + ОбнулитьКоличествоЭлементов(Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст); + Индекс = Индекс + 2; + Иначе + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + ЕстьКлючиДляПользователей = Ложь; + ЕстьКлючиДляВнешнихПользователей = Ложь; + Версии = ВерсииОграниченийСписков.Получить(Строка.ИмяТаблицы); + Если ЗначениеЗаполнено(Версии) Тогда + ЕстьКлючиДляПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 1)); + ЕстьКлючиДляВнешнихПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 2)); + КонецЕсли; + СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); + СвойстваТипа = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйЭлемент, + Строка.КоличествоОставшихсяЭлементовДляПользователей, + Строка.КоличествоЭлементовДляПользователей, + Строка.ДоляОставшихсяЭлементовДляПользователей, + Строка.ДоляОбработанныхЭлементовДляПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхЭлементов = + Строка.КоличествоЭлементовДляПользователей + - Строка.КоличествоОставшихсяЭлементовДляПользователей; + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей, + Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей, + Строка.КоличествоЭлементовДляВнешнихПользователей, + Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей, + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхЭлементов = КоличествоОбработанныхЭлементов + + Строка.КоличествоЭлементовДляВнешнихПользователей + - Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей; + + КоличествоЭлементов = Строка.КоличествоЭлементовДляПользователей + Строка.КоличествоЭлементовДляВнешнихПользователей; + Если ЕстьКлючиДляПользователей И ЕстьКлючиДляВнешнихПользователей И СвойстваТипа.ЭтоСсылочныйТип Тогда + КоличествоЭлементов = КоличествоЭлементов / 2; + КоличествоОбработанныхЭлементов = КоличествоОбработанныхЭлементов / 2; + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементов, КоличествоЭлементов, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, + Цел(КоличествоОбработанныхЭлементов), Строка, Контекст); + Если Строка.КоличествоОбработанныхЭлементов > Строка.КоличествоЭлементов Тогда + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, + Строка.КоличествоЭлементов, Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, ?(Строка.КоличествоЭлементов = 0, 100, + Цел(Строка.КоличествоОбработанныхЭлементов / Строка.КоличествоЭлементов * 100)), Строка, Контекст); + КонецЕсли; + КонецЦикла; + + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоКлючейДоступаДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоКлючейДоступаДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоКлючейДоступа = Строка.КоличествоКлючейДоступаДляПользователей + + Строка.КоличествоКлючейДоступаДляВнешнихПользователей; + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступа, КоличествоКлючейДоступа, Строка, Контекст); + Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда + КоличествоКлючейДоступаПоСпискам.Вставить(Строка.ИмяТаблицы, КоличествоКлючейДоступа); + КонецЕсли; + + Если Строка.КоличествоКлючейДоступа = 0 Тогда + ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст); + Индекс = Индекс + 2; + Иначе + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйКлючДоступа, + Строка.КоличествоОставшихсяКлючейДоступаДляПользователей, + Строка.КоличествоКлючейДоступаДляПользователей, + Строка.ДоляОставшихсяКлючейДоступаДляПользователей, + Строка.ДоляОбработанныхКлючейДоступаДляПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхКлючейДоступа = + Строка.КоличествоКлючейДоступаДляПользователей + - Строка.КоличествоОставшихсяКлючейДоступаДляПользователей; + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей, + Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей, + Строка.КоличествоКлючейДоступаДляВнешнихПользователей, + Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей, + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхКлючейДоступа = КоличествоОбработанныхКлючейДоступа + + Строка.КоличествоКлючейДоступаДляВнешнихПользователей + - Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей; + + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, + Цел(КоличествоОбработанныхКлючейДоступа), Строка, Контекст); + Если Строка.КоличествоОбработанныхКлючейДоступа > Строка.КоличествоКлючейДоступа Тогда + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, + Строка.КоличествоКлючейДоступа, Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, + Цел(Строка.КоличествоОбработанныхКлючейДоступа / Строка.КоличествоКлючейДоступа * 100), Строка, Контекст); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьКоличествоЭлементовИКлючейДоступа. +Процедура ОбновитьКоличество(РезультатЗапроса, ПоследнийОбновленный, + КоличествоОставшихся, Количество, ДоляОставшихся, ДоляОбработанных) + + Если ПоследнийОбновленный = Null Или ПоследнийОбновленный = Истина Тогда + НовоеКоличествоОставшихся = -1; + Иначе + Выборка = РезультатЗапроса.Выбрать(); + НовоеКоличествоОставшихся = ?(Выборка.Следующий(), Выборка.Количество, 0); + КонецЕсли; + + Если НовоеКоличествоОставшихся = -1 Тогда + ДоляОставшихся = 0; + НовоеКоличествоОставшихся = 0; + КонецЕсли; + + Если ТипЗнч(НовоеКоличествоОставшихся) = Тип("Число") Тогда + КоличествоОставшихся = Цел(Количество * (1 - ДоляОбработанных - ДоляОставшихся) + 0.99) + + Цел(НовоеКоличествоОставшихся * ДоляОставшихся); + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Массив из РезультатЗапроса +// +Функция ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса) + + РезультатыПакетаЗапросов = Новый Массив; + + ТекстыПорцииЗапросов = Новый Массив; + Для Каждого ТекстЗапроса Из ОписаниеЗапроса.ТекстыПакетаЗапросов Цикл + Если ТекстыПорцииЗапросов.Количество() = 200 Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса); + ТекстыПорцииЗапросов = Новый Массив; + КонецЕсли; + ТекстыПорцииЗапросов.Добавить(ТекстЗапроса); + КонецЦикла; + ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса); + + Возврат РезультатыПакетаЗапросов; + +КонецФункции + +Процедура ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса) + + Запрос = ОписаниеЗапроса.Запрос; + + Запрос.Текст = СтрСоединить(ТекстыПорцииЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Запрос.Текст = ""; + + Для Каждого РезультатЗапроса Из РезультатыЗапроса Цикл + РезультатыПакетаЗапросов.Добавить(РезультатЗапроса); + КонецЦикла; + +КонецПроцедуры + +Процедура ОбновитьЗначениеВСтроке(СтароеЗначение, НовоеЗначение, Строка, Контекст) + + Если СтароеЗначение = НовоеЗначение Тогда + Возврат; + КонецЕсли; + СтароеЗначение = НовоеЗначение; + + Если Контекст.ДобавленныеСтроки.Найти(Строка) = Неопределено + И Контекст.ИзмененныеСтроки.Получить(Строка) = Неопределено Тогда + + Контекст.ИзмененныеСтроки.Вставить(Строка.Список, Строка); + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) + + Версии = Контекст.ДействующиеПараметры.ВерсииОграниченийСписков.Получить(Строка.ИмяТаблицы); + + Если ЗначениеЗаполнено(Версии) + И ЗначениеЗаполнено(Строка.ИмяТаблицы) + Или Строка.ИмяТаблицы = "Справочник.НаборыГруппДоступа" Тогда + + СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); + СвойстваТипа = Контекст.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + Если СвойстваТипа.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица"; + Иначе + ТекстЗапроса = ТекстЗапросаКоличестваЭлементовРегистра(Контекст, Строка, Индекс, ДляВнешнихПользователей); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", Строка.ИмяТаблицы); + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | 0 КАК Количество"; + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Функция ТекстЗапросаКоличестваЭлементовРегистра(Контекст, Строка, Индекс, ДляВнешнихПользователей) + + Если ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + Свойства = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Строка.ИмяТаблицы); + + Если Свойства = Неопределено + Или Свойства.ОпорныеПоля = Неопределено + Или Свойства.ОпорныеПоля.Используемые.Количество() = 0 Тогда + + Возврат + "ВЫБРАТЬ + | 0 КАК Количество"; + КонецЕсли; + + ПоляВыбора = ""; + Для Каждого ИмяПоля Из Свойства.ОпорныеПоля.Используемые Цикл + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", ", + | ") + "ТекущаяТаблица." + ИмяПоля; + КонецЦикла; + + Если Свойства.ОпорныеПоля.Используемые.Количество() = 1 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ &ПоляВыбора) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ПоляВыбора КАК ПоляВыбора + | ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица) КАК Комбинации"; + ПоляВыбора = ТекстСОтступом(ПоляВыбора, " "); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляВыбора", ПоляВыбора); + + Возврат ТекстЗапроса; + +КонецФункции + +Процедура ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) + + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + СпискиСДатой = Контекст.ДействующиеПараметры.СпискиСДатой; + + Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда + СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); + СвойстваТипа = Контекст.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + Иначе + СвойстваСписка = Неопределено; + КонецЕсли; + + Если СвойстваСписка = Неопределено Тогда + ПараметрыЗадания = Неопределено; + + ИначеЕсли ДляВнешнихПользователей Тогда + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей; + Иначе + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйЭлемент; + КонецЕсли; + + Если ТипЗнч(ПараметрыЗадания) <> Тип("ХранилищеЗначения") Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | НЕОПРЕДЕЛЕНО КАК Количество"; + Иначе + ДолиКоличестваЭлементов = Новый Структура("Обработанных, Оставшихся", 0, 1); + ПараметрыЗадания = ПараметрыЗадания.Получить(); + + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") + И ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") + И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент) = Тип("Структура") + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ВидКлючаДанных") + И ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных) <> Неопределено + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("КлючДанных") + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ОбработатьУстаревшиеЭлементы") + И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы) = Тип("Булево") Тогда + + ПоследнийОбновленныйЭлемент = ПараметрыЗадания.ПоследнийОбновленныйЭлемент; + Иначе + ПоследнийОбновленныйЭлемент = Новый Структура; + ПоследнийОбновленныйЭлемент.Вставить("ВидКлючаДанных", "ЭлементыДанныхСУстаревшимиКлючами"); + ПоследнийОбновленныйЭлемент.Вставить("КлючДанных"); + КонецЕсли; + + УсловиеОтбора = ""; + Если СвойстваТипа.ЭтоСсылочныйТип Тогда + КлючДанных = ПоследнийОбновленныйЭлемент.КлючДанных; + Если СпискиСДатой.Получить(Строка.ИмяТаблицы) <> Неопределено Тогда + + Если ПоследнийОбновленныйЭлемент.Свойство("Дата") + И ТипЗнч(ПоследнийОбновленныйЭлемент.Дата) = Тип("Дата") Тогда + + ИмяПараметра = "ПоследняяДата" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "ТекущаяТаблица.Дата <= &" + ИмяПараметра; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийОбновленныйЭлемент.Дата); + КонецЕсли; + + ИначеЕсли ЗначениеЗаполнено(КлючДанных) Тогда + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(КлючДанных)); + Если ОбъектМетаданных <> Неопределено + И ОбъектМетаданных.ПолноеИмя() = Строка.ИмяТаблицы Тогда + + ИмяПараметра = "ПоследняяСсылка" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "ТекущаяТаблица.Ссылка > &" + ИмяПараметра; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, КлючДанных); + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(УсловиеОтбора) Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &УсловиеОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | -1 КАК Количество"; + КонецЕсли; + ЗаполнитьДолиКоличествоЭлементовСсылочногоТипа(ДолиКоличестваЭлементов, + ПоследнийОбновленныйЭлемент, Строка.ИмяТаблицы); + Иначе + Если ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + СвойстваОграничения = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Строка.ИмяТаблицы); + + Если СвойстваОграничения <> Неопределено Тогда + ИспользуемыеВариантыДоступа = ДополнительныйКонтекст.ОсновныеВариантыДоступа.Получить(Строка.ИмяТаблицы); + Если ИспользуемыеВариантыДоступа = Неопределено Тогда + СвойстваОграничения = Неопределено; + Иначе + СвойстваОграничения = Новый Структура(СвойстваОграничения); + СвойстваОграничения.Вставить("ВариантДоступа", ИспользуемыеВариантыДоступа[0].ВариантДоступа); + КонецЕсли; + КонецЕсли; + + ЗаполнитьДолиКоличестваЭлементовРегистра(ДолиКоличестваЭлементов, + ПоследнийОбновленныйЭлемент, СвойстваОграничения); + + ТекстЗапроса = ТекстЗапросаКоличестваОставшихсяЭлементовРегистра(ОписаниеЗапроса, Строка, Индекс, + ДляВнешнихПользователей, ПоследнийОбновленныйЭлемент, СвойстваОграничения, СвойстваТипа); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", Строка.ИмяТаблицы); + + Если ДляВнешнихПользователей Тогда + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = ДолиКоличестваЭлементов.Обработанных; + Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей = ДолиКоличестваЭлементов.Оставшихся; + Иначе + Строка.ДоляОбработанныхЭлементовДляПользователей = ДолиКоличестваЭлементов.Обработанных; + Строка.ДоляОставшихсяЭлементовДляПользователей = ДолиКоличестваЭлементов.Оставшихся; + КонецЕсли; + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Процедура ЗаполнитьДолиКоличествоЭлементовСсылочногоТипа(ДолиКоличестваЭлементов, Элемент, ИмяТаблицы) + + Если ИмяТаблицы = "Справочник.НаборыГруппДоступа" Тогда + Если Элемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.0; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.1; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.2; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.3; + ДолиКоличестваЭлементов.Оставшихся = 0.2; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.5; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.6; + ДолиКоличестваЭлементов.Оставшихся = 0.3; + + Иначе // УстаревшиеЭлементы. + ДолиКоличестваЭлементов.Обработанных = 0.9; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда + ДолиКоличестваЭлементов.Обработанных = 0.0; + ДолиКоличестваЭлементов.Оставшихся = 0.9; + Иначе // УстаревшиеЭлементы. + ДолиКоличестваЭлементов.Обработанных = 0.9; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + КонецЕсли; + +КонецПроцедуры + +Функция ТекстЗапросаКоличестваОставшихсяЭлементовРегистра(ОписаниеЗапроса, Строка, Индекс, + ДляВнешнихПользователей, ПоследнийОбновленныйЭлемент, СвойстваОграничения, СвойстваТипа) + + ВидКлючаДанных = ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + КлючДанных = ПоследнийОбновленныйЭлемент.КлючДанных; + + Если СвойстваОграничения = Неопределено + Или СвойстваОграничения.ОпорныеПоля = Неопределено + Или СвойстваОграничения.ОпорныеПоля.Используемые.Количество() = 0 + Или ТипЗнч(КлючДанных) <> Тип("Структура") + Или ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" + И (Не ПоследнийОбновленныйЭлемент.Свойство("Дата") + Или ТипЗнч(ПоследнийОбновленныйЭлемент.Дата) <> Тип("Дата")) + Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" + И СвойстваОграничения.ОпорныеПоля.Используемые.Количество() <> КлючДанных.Количество() + Или ВидКлючаДанных <> "ЭлементыБезКлючейПоПериоду" + И ВидКлючаДанных <> "ЭлементыБезКлючейПоЗначениямПолей" + И СвойстваОграничения.ОпорныеПоля.Используемые.Количество() > КлючДанных.Количество() Тогда + + Возврат + "ВЫБРАТЬ + | -1 КАК Количество"; + КонецЕсли; + + ПоляВыбора = ""; + УсловиеОтбора = ""; + УсловиеСоединения = ""; + + Если ЗначениеЗаполнено(СвойстваОграничения.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистраКлючей = СвойстваОграничения.ИмяОтдельногоРегистраКлючей; + Иначе + ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; + ИмяПараметра = "ИдентификаторРегистра" + Формат(Индекс, "ЧГ="); + УсловиеСоединения = "(КлючиДоступаКРегистрам.Регистр = &" + ИмяПараметра + ")"; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); + КонецЕсли; + + ОпорныеПоля = СвойстваОграничения.ОпорныеПоля; + ОтборПоТипуПользователей = XMLСтрока(СвойстваОграничения.ВариантДоступа); + УсловиеСоединения = УсловиеСоединения + ?(УсловиеСоединения = "", "", " + | И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = " + ОтборПоТипуПользователей + ")"; // @query-part-3 + + НомерПоля = 1; + Для Каждого ИмяПоля Из ОпорныеПоля.Используемые Цикл + ИмяПоляВКлючеДанных = СтрШаблон("Поле%1", НомерПоля); + ИмяПараметра = ИмяПоля + Формат(Индекс, "ЧГ="); + + УсловиеСоединения = УсловиеСоединения + ?(УсловиеСоединения = "", "", " + | И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ТекущаяТаблица.%2)", НомерПоля, ИмяПоля); // @query-part-3 + + Отбор = ""; + Для ТекущийИндекс = 0 По НомерПоля - 2 Цикл + ТекущееИмяПоля = ОпорныеПоля.Используемые[ТекущийИндекс]; + ТекущееИмяПараметра = ТекущееИмяПоля + Формат(Индекс, "ЧГ="); + Отбор = Отбор + ?(Отбор = "", "", " + | И ") + "ТекущаяТаблица." + ТекущееИмяПоля + " = &" + ТекущееИмяПараметра; // @query-part-3 + КонецЦикла; + Отбор = Отбор + ?(Отбор = "", "", " + | И ") + "ТекущаяТаблица." + ИмяПоля + " > &" + ИмяПараметра; // @query-part-3 + + УсловиеОтбора = УсловиеОтбора + ?(НомерПоля = 1, ?(ОпорныеПоля.Используемые.Количество() > 1, "(", "") + Отбор, " + | ИЛИ " + ТекстСОтступом(Отбор, " ")); // @query-part-3 + + Если КлючДанных.Свойство(ИмяПоляВКлючеДанных) Тогда + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, КлючДанных[ИмяПоляВКлючеДанных]); + Иначе + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Неопределено); + КонецЕсли; + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", ", + | ") + "ТекущаяТаблица." + ИмяПоля; + НомерПоля = НомерПоля + 1; + КонецЦикла; + + Если ОпорныеПоля.Используемые.Количество() > 1 Тогда + УсловиеОтбора = УсловиеОтбора + ")"; + КонецЕсли; + + Если ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + ИмяПоляПериода = ?(СвойстваТипа.ИмяКоллекции = "РегистрыРасчета", "ПериодРегистрации", "Период"); + ИмяПараметра = ИмяПоляПериода + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "(ТекущаяТаблица." + ИмяПоляПериода + " < &" + ИмяПараметра + " + | ИЛИ ТекущаяТаблица." + + ИмяПоляПериода + " = &" + ИмяПараметра + " + | И " + ТекстСОтступом(УсловиеОтбора, " ") + ")"; // @query-part-3, @query-part-5 + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийОбновленныйЭлемент.Дата); + КонецЕсли; + + Если СвойстваОграничения.ОпорныеПоля.Используемые.Количество() = 1 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ &ПоляВыбора) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО (&УсловиеСоединения) + |ГДЕ + | &УсловиеОтбора + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ПоляВыбора КАК ПоляВыбора + | ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО (&УсловиеСоединения) + | ГДЕ + | &УсловиеОтбора + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL) КАК Комбинации"; + ПоляВыбора = ТекстСОтступом(ПоляВыбора, " "); + УсловиеОтбора = ТекстСОтступом(УсловиеОтбора, " "); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "(&УсловиеСоединения)", УсловиеСоединения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляВыбора", ПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок", "РегистрСведений." + ИмяРегистраКлючей); + + Возврат ТекстЗапроса; + +КонецФункции + +Процедура ЗаполнитьДолиКоличестваЭлементовРегистра(ДолиКоличестваЭлементов, Элемент, СвойстваОграничения) + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.0; + ДолиКоличестваЭлементов.Оставшихся = 0.5; + + ИначеЕсли Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" + Или Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.5; + ДолиКоличестваЭлементов.Оставшихся = 0.4; + + ИначеЕсли Элемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда + + Если СвойстваОграничения <> Неопределено + И ЗначениеЗаполнено(СвойстваОграничения.ИмяОтдельногоРегистраКлючей) Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.90; + ДолиКоличестваЭлементов.Оставшихся = 0.09; + Иначе + ДолиКоличестваЭлементов.Обработанных = 0.9; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + КонецЕсли; + + Иначе // НекорректныеЭлементы или НекорректныеЭлементыОбщегоРегистра. + ДолиКоличестваЭлементов.Обработанных = 0.99; + ДолиКоличестваЭлементов.Оставшихся = 0.01; + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, ДляВнешнихПользователей) + + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(КлючиДоступа.Ссылка) КАК Количество + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = ЛОЖЬ"; + + ИмяПараметра = "СписокКлючей" + Формат(Индекс, "ЧГ="); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Список", "&" + ИмяПараметра); + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); + + Если ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ЛОЖЬ", "ИСТИНА"); + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Процедура ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) + + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + + Если СвойстваСписка = Неопределено Тогда + ПараметрыЗадания = Неопределено; + + ИначеЕсли ДляВнешнихПользователей Тогда + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей; + Иначе + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйКлючДоступа; + КонецЕсли; + + Если ТипЗнч(ПараметрыЗадания) <> Тип("ХранилищеЗначения") Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | НЕОПРЕДЕЛЕНО КАК Количество"; + Иначе + ДолиКоличестваКлючейДоступа = Новый Структура("Обработанных, Оставшихся", 0, 1); + ПараметрыЗадания = ПараметрыЗадания.Получить(); + + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") + И ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") + И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент) = Тип("Структура") + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ВидКлючаДанных") + И ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных) <> Неопределено + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("КлючДанных") Тогда + + ПоследнийКлючДоступа = ПараметрыЗадания.ПоследнийОбновленныйЭлемент.КлючДанных; + ЗаполнитьДолиКоличестваКлючейДоступа(ДолиКоличестваКлючейДоступа, + ПараметрыЗадания.ПоследнийОбновленныйЭлемент); + КонецЕсли; + УсловиеОтбора = ""; + Если ТипЗнч(ПоследнийКлючДоступа) = Тип("СправочникСсылка.КлючиДоступа") Тогда + ИмяПараметра = "СписокОбработанныхКлючей" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "КлючиДоступа.Список = &" + ИмяПараметра; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); + + УсловиеОтбора = УсловиеОтбора + " + | И КлючиДоступа.ДляВнешнихПользователей = " + ?(ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ"); // @query-part-1 + + ИмяПараметра = "ПоследнийКлючДоступа" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = УсловиеОтбора + " + | И КлючиДоступа.Ссылка > &" + ИмяПараметра; // @query-part-1 + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийКлючДоступа); + КонецЕсли; + + Если ЗначениеЗаполнено(УсловиеОтбора) Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | &УсловиеОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | -1 КАК Количество"; + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = ДолиКоличестваКлючейДоступа.Обработанных; + Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей = ДолиКоличестваКлючейДоступа.Оставшихся; + Иначе + Строка.ДоляОбработанныхКлючейДоступаДляПользователей = ДолиКоличестваКлючейДоступа.Обработанных; + Строка.ДоляОставшихсяКлючейДоступаДляПользователей = ДолиКоличестваКлючейДоступа.Оставшихся; + КонецЕсли; + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Процедура ЗаполнитьДолиКоличестваКлючейДоступа(ДолиКоличестваКлючейДоступа, Элемент) + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиПравами" Тогда + ДолиКоличестваКлючейДоступа.Обработанных = 0.0; + ДолиКоличестваКлючейДоступа.Оставшихся = 0.9; + Иначе // УстаревшиеЭлементы. + ДолиКоличестваКлючейДоступа.Обработанных = 0.9; + ДолиКоличестваКлючейДоступа.Оставшихся = 0.1; + КонецЕсли; + +КонецПроцедуры + +// Параметры: +// ДействующиеПараметры - см. ДействующиеПараметрыОграниченияДоступа +// +// Возвращаемое значение: +// см. ОбщегоНазначения.ИдентификаторыОбъектовМетаданных +// +Функция ИдентификаторыСписковСОграничением(ДействующиеПараметры) + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + + Списки = Новый Массив; + Для Каждого ОписаниеВерсии Из ДействующиеПараметры.ВерсииОграниченийСписков Цикл + Списки.Добавить(ОписаниеВерсии.Ключ); + КонецЦикла; + + Возврат ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки, Ложь); + +КонецФункции + +Функция ТекущаяДатаНаСервере() Экспорт + + // АПК:143-выкл - №643.2.1 Требуется ТекущаяДата сервера, а не ТекущаяДатаСеанса, + // так как именно ТекущаяДата записывается в журнал регистрации. + Возврат ТекущаяДата(); + // АПК:143-вкл. + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#КонецОбласти \ No newline at end of file From 181b3451ab72a268831d897e67e76cf8196a5044 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:40:01 +0000 Subject: [PATCH 5/9] Initial plan From 2a3c6b1074a33a5c610f4015a1db29f4006f9baa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:44:57 +0000 Subject: [PATCH 6/9] Initial exploration of the codebase Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- src/jmh/resources/Module.bsl | 94720 ++++++++++++++++----------------- 1 file changed, 47360 insertions(+), 47360 deletions(-) diff --git a/src/jmh/resources/Module.bsl b/src/jmh/resources/Module.bsl index 7767d748..96d85ea3 100644 --- a/src/jmh/resources/Module.bsl +++ b/src/jmh/resources/Module.bsl @@ -1,47361 +1,47361 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2024, ООО 1С-Софт -// Все права защищены. Эта программа и сопроводительные материалы предоставляются -// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0) -// Текст лицензии доступен по ссылке: -// https://creativecommons.org/licenses/by/4.0/legalcode -/////////////////////////////////////////////////////////////////////////////////////////////////////// - -#Область СлужебныйПрограммныйИнтерфейс - -#Область ОсновныеПроцедурыИФункции - -// Добавляет пользователя в группу доступа, соответствующую поставляемому профилю. -// Группа доступа определяется по идентификатору ссылки поставляемого профиля. -// Если группа доступа не будет найдена, она будет создана. -// -// Параметры: -// Пользователь - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ГруппыВнешнихПользователей - участник, которого нужно включить в группу доступа. -// -// ПоставляемыйПрофиль - Строка - строка идентификатора поставляемого профиля. -// - СправочникСсылка.ПрофилиГруппДоступа - ссылка на профиль, который -// создан по описанию в модуле УправлениеДоступомПереопределяемый -// в процедуре ПриЗаполненииПоставляемыхПрофилейГруппДоступа. -// Профили с непустым списком видов доступа не поддерживаются. -// Профиль групп доступа Администратор не поддерживается. -// -Процедура ВключитьПользователяВГруппуДоступа(Пользователь, ПоставляемыйПрофиль) Экспорт - - ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( - "УправлениеДоступомСлужебный.ВключитьПользователяВГруппуДоступа"); - - ОбработатьСвязьПользователяСГруппойДоступа(Пользователь, ПоставляемыйПрофиль, Истина); - -КонецПроцедуры - -// Обновляет состав пользователей указанных групп исполнителей. -// -// Требуется вызывать при изменении состава пользователей у групп исполнителей, -// например, у групп исполнителей задач. -// -// В качестве значений параметра передается группы исполнителей, состав которых изменился. -// -// Параметры: -// ГруппыИсполнителей - СправочникСсылка.ГруппыИсполнителейЗадач - одна группа, -// - Массив из СправочникСсылка.ГруппыИсполнителейЗадач - несколько групп, -// - Неопределено - без отбора. -// -Процедура ОбновитьПользователейГруппИсполнителей(ГруппыИсполнителей = Неопределено) Экспорт - - Если ТипЗнч(ГруппыИсполнителей) = Тип("Массив") И ГруппыИсполнителей.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Параметры = Новый Структура; - Параметры.Вставить("ГруппыИсполнителей", ГруппыИсполнителей); - - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); - -КонецПроцедуры - -// Проверяет существование вида доступа с указанным именем. -// Применяется для автоматизации условного встраивания подсистем. -// -// Параметры: -// ИмяВидаДоступа - Строка - имя вида доступа. -// -// Возвращаемое значение: -// Структура: -// -Функция ВидДоступаСуществует(ИмяВидаДоступа) Экспорт - - Возврат СвойстваВидаДоступа(ИмяВидаДоступа) <> Неопределено; - -КонецФункции - -// Возвращает вид интерфейса пользователя для настройки доступа. -// -// Возвращаемое значение: -// Булево -// -Функция УпрощенныйИнтерфейсНастройкиПравДоступа() Экспорт - - УпрощенныйИнтерфейс = Ложь; - УправлениеДоступомПереопределяемый.ПриОпределенииИнтерфейсаНастройкиДоступа(УпрощенныйИнтерфейс); - - Возврат УпрощенныйИнтерфейс = Истина; - -КонецФункции - -// Возвращает массив разрешенных значений указанных типов в рамках всех групп доступа. -// Используется в процедуре НастроитьОтборыДинамическогоСписка для ускорения открытия динамических списков. -// -// Параметры: -// Таблица - Строка - полное имя объекта метаданных, например, "Документ.РасходнаяНакладная". -// ТипЗначений - Тип - тип значений доступа, разрешенные значения которых нужно вернуть. -// - Массив - массив указанных выше типов. -// -// Значения - Неопределено - не учитывать. -// - Массив - массив значений типов, указанных в параметре ТипЗначений. -// -// Пользователь - Неопределено - вернуть разрешенные значения для авторизованного пользователя. -// - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи - вернуть -// разрешенные значения для указанного пользователя. -// -// ВернутьВсе - Булево - если установить Истина, тогда будут возвращены все значение даже тогда, -// когда их более 100. -// -// Возвращаемое значение: -// Неопределено - либо все значения разрешены для типов, указанных в параметре ТипЗначений, -// либо (когда ВернутьВсе = Ложь) количество разрешенных значений превышает 100. -// Массив - ссылки разрешенных значений указанных типов. -// -Функция РазрешенныеЗначенияДляДинамическогоСписка(Таблица, ТипЗначений, Значения = Неопределено, Пользователь = Неопределено, ВернутьВсе = Ложь) Экспорт - - Если ТипЗнч(ТипЗначений) <> Тип("Массив") Тогда - ТипыЗначений = Новый Массив; - ТипыЗначений.Добавить(ТипЗначений); - - ИначеЕсли ТипЗначений.Количество() = 0 Тогда - Возврат Неопределено; - Иначе - ТипыЗначений = ТипЗначений; - КонецЕсли; - - УстановитьПривилегированныйРежим(Истина); - - ТекстЗапросаЗначенийБезГрупп = - "ВЫБРАТЬ ПЕРВЫЕ 101 - | ЗначенияБезГрупп.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | &ЗначениеПустойСсылки КАК Ссылка - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | ЗначенияБезПустойСсылки.Ссылка - | ИЗ - | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ЗначенияБезГрупп - |ГДЕ - | ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | ГруппыДоступаПользователя КАК ГруппыДоступа - | ГДЕ - | ВЫБОР - | КОГДА ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.ЗначенияГруппДоступа КАК Значения - | ГДЕ - | Значения.ГруппаДоступа = ГруппыДоступа.Ссылка - | И Значения.ЗначениеДоступа = ЗначенияБезГрупп.Ссылка) - | ТОГДА ИСТИНА - | ИНАЧЕ ЛОЖЬ - | КОНЕЦ = ВЫБОР - | КОГДА ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию - | ГДЕ - | ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступа.Ссылка - | И ТИПЗНАЧЕНИЯ(ЗначенияПоУмолчанию.ТипЗначенийДоступа) = ТИПЗНАЧЕНИЯ(ЗначенияБезГрупп.Ссылка) - | И ЗначенияПоУмолчанию.ВсеРазрешены = ЛОЖЬ) - | ТОГДА ИСТИНА - | ИНАЧЕ ЛОЖЬ - | КОНЕЦ) - | И ЗначенияБезГрупп.Ссылка В(&Значения)"; - - Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда - ТекстЗапросаЗначенийБезГрупп = СтрЗаменить(ТекстЗапросаЗначенийБезГрупп, "ПЕРВЫЕ 101", ""); // @query-part-1 - КонецЕсли; - Если ТипЗнч(Значения) <> Тип("Массив") Тогда - ТекстЗапросаЗначенийБезГрупп = СтрЗаменить(ТекстЗапросаЗначенийБезГрупп, "ЗначенияБезГрупп.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 - КонецЕсли; - - ТекстЗапросаЗначенийСГруппами = - "ВЫБРАТЬ ПЕРВЫЕ 101 - | ЗначенияСГруппами.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | &ЗначениеПустойСсылки КАК Ссылка - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | ЗначенияБезПустойСсылки.Ссылка - | ИЗ - | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ЗначенияСГруппами - |ГДЕ - | ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | ГруппыДоступаПользователя КАК ГруппыДоступа - | ГДЕ - | ВЫБОР - | КОГДА ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.ЗначенияГруппДоступа КАК Значения - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначений - | ПО - | Значения.ГруппаДоступа = ГруппыДоступа.Ссылка - | И Значения.ЗначениеДоступа = ГруппыЗначений.ГруппаЗначенийДоступа - | И ГруппыЗначений.ЗначениеДоступа = ЗначенияСГруппами.Ссылка) - | ТОГДА ИСТИНА - | ИНАЧЕ ЛОЖЬ - | КОНЕЦ = ВЫБОР - | КОГДА ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию - | ГДЕ - | ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступа.Ссылка - | И ТИПЗНАЧЕНИЯ(ЗначенияПоУмолчанию.ТипЗначенийДоступа) = ТИПЗНАЧЕНИЯ(ЗначенияСГруппами.Ссылка) - | И ЗначенияПоУмолчанию.ВсеРазрешены = ЛОЖЬ) - | ТОГДА ИСТИНА - | ИНАЧЕ ЛОЖЬ - | КОНЕЦ) - | И ЗначенияСГруппами.Ссылка В(&Значения)"; - - Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда - ТекстЗапросаЗначенийСГруппами = СтрЗаменить(ТекстЗапросаЗначенийСГруппами, "ПЕРВЫЕ 101", ""); // @query-part-1 - КонецЕсли; - Если ТипЗнч(Значения) <> Тип("Массив") Тогда - ТекстЗапросаЗначенийСГруппами = СтрЗаменить(ТекстЗапросаЗначенийСГруппами, "ЗначенияСГруппами.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 - КонецЕсли; - - ТекстЗапросаВсеЗначения = - "ВЫБРАТЬ ПЕРВЫЕ 101 - | ВсеЗначения.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | &ЗначениеПустойСсылки КАК Ссылка - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | ЗначенияБезПустойСсылки.Ссылка - | ИЗ - | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ВсеЗначения - |ГДЕ - | ВсеЗначения.Ссылка В(&Значения)"; - - Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда - ТекстЗапросаВсеЗначения = СтрЗаменить(ТекстЗапросаВсеЗначения, "ПЕРВЫЕ 101", ""); // @query-part-1 - КонецЕсли; - Если ТипЗнч(Значения) <> Тип("Массив") Тогда - ТекстЗапросаВсеЗначения = СтрЗаменить(ТекстЗапросаВсеЗначения, "ВсеЗначения.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 - КонецЕсли; - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ТекстЗапроса = ""; - Если Пользователь <> Неопределено Тогда - АвторизованныйПользователь = Пользователь; - Иначе - АвторизованныйПользователь = Пользователи.АвторизованныйПользователь(); - КонецЕсли; - ДобавитьТекущегоПользователя = Ложь; - ЕстьИспользуемыеВидыДоступа = Ложь; - ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); - - Для Каждого ТекущийТип Из ТипыЗначений Цикл - Свойства = СвойстваВидовДоступа.ПоТипамЗначений.Получить(ТекущийТип); // См. СвойстваВидаДоступа - Если Свойства = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Тип ""%1"" не является типом значений доступа'"), Строка(ТекущийТип)); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Если ИспользуемыеВидыДоступа.Получить(Свойства.Ссылка) = Неопределено Тогда - ТекущийТекстЗапроса = ТекстЗапросаВсеЗначения; - Иначе - Если СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами.Получить(ТекущийТип) = Неопределено Тогда - ТекущийТекстЗапроса = ТекстЗапросаЗначенийБезГрупп; - Иначе - ТекущийТекстЗапроса = ТекстЗапросаЗначенийСГруппами; - КонецЕсли; - ЕстьИспользуемыеВидыДоступа = Истина; - КонецЕсли; - ТаблицаЗначенийДоступа = Метаданные.НайтиПоТипу(ТекущийТип).ПолноеИмя(); - ТекущийТекстЗапроса = СтрЗаменить(ТекущийТекстЗапроса, "&ТаблицаЗначенийДоступа", ТаблицаЗначенийДоступа); - ТекущийТекстЗапроса = СтрЗаменить(ТекущийТекстЗапроса, "&ЗначениеПустойСсылки", - "ЗНАЧЕНИЕ(" + ТаблицаЗначенийДоступа + ".ПустаяСсылка)"); // @query-part-2 - Если ЗначениеЗаполнено(ТекстЗапроса) Тогда - ОбъединитьЗапросСЗапросом(ТекстЗапроса, ТекущийТекстЗапроса); - Иначе - ТекстЗапроса = ТекущийТекстЗапроса; - КонецЕсли; - Если ТекущийТип = ТипЗнч(АвторизованныйПользователь) Тогда - ДобавитьТекущегоПользователя = Истина; - КонецЕсли; - КонецЦикла; - - Если Не ЕстьИспользуемыеВидыДоступа Тогда - Возврат Неопределено; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИмяОсновнойТаблицыСписка", Таблица); - Запрос.УстановитьПараметр("АвторизованныйПользователь", АвторизованныйПользователь); - Запрос.Текст = ТекстЗапросаГруппДоступа(); - Если ТипЗнч(Значения) = Тип("Массив") Тогда - Запрос.УстановитьПараметр("Значения", Значения); - КонецЕсли; - - ДобавитьЗапросВПакет(Запрос.Текст, ТекстЗапроса); - - Выгрузка = Запрос.Выполнить().Выгрузить(); - - Если ТипЗнч(Значения) <> Тип("Массив") - И Не ВернутьВсе - И Выгрузка.Количество() > 100 Тогда - - Возврат Неопределено; - КонецЕсли; - - РазрешенныеЗначения = Выгрузка.ВыгрузитьКолонку("Ссылка"); - - Если ДобавитьТекущегоПользователя Тогда - РазрешенныеЗначения.Добавить(АвторизованныйПользователь); - КонецЕсли; - - Возврат РазрешенныеЗначения; - -КонецФункции - -// Добавляет администраторов системы в группу доступа, -// связанную с предопределенным профилем ОткрытиеВнешнихОтчетовИОбработок. -// -Процедура УстановитьПравоОткрытияВнешнихОтчетовИОбработок(ОткрытиеРазрешено) Экспорт - - ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( - "УправлениеДоступомСлужебный.УстановитьПравоОткрытияВнешнихОтчетовИОбработок"); - - СвойстваПрофиля = ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок(); - СвойстваПрофиля.Вставить("Ссылка", Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( - СвойстваПрофиля.Имя, Истина)); - - ИдентификаторРоли = ОбщегоНазначения.ИдентификаторОбъектаМетаданных( - Метаданные.Роли.ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок); - - // В упрощенном интерфейсе группу доступа создавать не требуется (только профиль). - УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); - Если Не УпрощенныйИнтерфейс Тогда - ГруппаПрофиля = ГруппаДоступаОткрытиеВнешнихОтчетовИОбработок(СвойстваПрофиля); - КонецЕсли; - - Если ОткрытиеРазрешено Тогда - // Включение администраторов в группы доступа с этим профилем. - РольАдминистратора = Метаданные.Роли.АдминистраторСистемы; - ПользователиИБ = ПользователиИнформационнойБазы.ПолучитьПользователей(); - СоставПользователей = Новый Массив; - Для Каждого ПользовательИБ Из ПользователиИБ Цикл - Если ПользовательИБ.Роли.Содержит(РольАдминистратора) Тогда - Пользователь = Справочники.Пользователи.НайтиПоРеквизиту( - "ИдентификаторПользователяИБ", - ПользовательИБ.УникальныйИдентификатор); - Если Пользователь = Неопределено Тогда - Продолжить; - КонецЕсли; - Если УпрощенныйИнтерфейс Тогда - // В упрощенном интерфейсе каждый администратор включаются в отдельную группу. - УправлениеДоступом.ВключитьПрофильПользователю(Пользователь, СвойстваПрофиля.Ссылка); - Иначе - // В расширенном интерфейсе администраторы включаются в одну группу, связанную с предопределенным профилем. - СоставПользователей.Добавить(Пользователь); - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если Не УпрощенныйИнтерфейс Тогда - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаПрофиля); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ГруппаДоступаОбъект = ГруппаПрофиля.ПолучитьОбъект(); - Для Каждого Пользователь Из СоставПользователей Цикл - Если ГруппаДоступаОбъект.Пользователи.Найти(Пользователь, "Пользователь") = Неопределено Тогда - ГруппаДоступаОбъект.Пользователи.Добавить().Пользователь = Пользователь; - КонецЕсли; - КонецЦикла; - Если ГруппаДоступаОбъект.Модифицированность() Тогда - ГруппаДоступаОбъект.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - Иначе - // Удаление роли из всех профилей, за исключением предопределенного. - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ПрофилиГруппДоступаРоли.Ссылка - |ИЗ - | Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиГруппДоступаРоли - |ГДЕ - | ПрофилиГруппДоступаРоли.Роль = &Роль - | И ПрофилиГруппДоступаРоли.Ссылка <> &ИсключаемыйПрофиль"; - Запрос.УстановитьПараметр("Роль", ИдентификаторРоли); - Запрос.УстановитьПараметр("ИсключаемыйПрофиль", СвойстваПрофиля.Ссылка); - МассивПрофилей = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - Для Каждого Профиль Из МассивПрофилей Цикл - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", Профиль); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ПрофильОбъект = Профиль.ПолучитьОбъект(); - Найденные = ПрофильОбъект.Роли.НайтиСтроки(Новый Структура("Роль", ИдентификаторРоли)); - Для Каждого СтрокаТаблицы Из Найденные Цикл - ПрофильОбъект.Роли.Удалить(СтрокаТаблицы); - КонецЦикла; - ПрофильОбъект.Записать(); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - - // Очистка состава групп доступа, связанных с предопределенным профилем. - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ГруппыДоступа.Ссылка - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль = &Профиль"; - Запрос.УстановитьПараметр("Профиль", СвойстваПрофиля.Ссылка); - МассивГрупп = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - Для Каждого ГруппаДоступа Из МассивГрупп Цикл - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступа); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ГруппаДоступаОбъект = ГруппаДоступа.ПолучитьОбъект(); - ГруппаДоступаОбъект.Пользователи.Очистить(); - ГруппаДоступаОбъект.Записать(); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Только для внутреннего использования. -Процедура ПриРегистрацииИспользованияВерсииРасширенийВНеразделенномСеансе() Экспорт - - Если ТекущийРежимЗапуска() = Неопределено - Или ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда - Возврат; - КонецЕсли; - - ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей(); - -КонецПроцедуры - -// Только для внутреннего использования. -// -// Возвращаемое значение: -// Булево -// -Функция ВариантВстроенногоЯзыкаРусский() Экспорт - - Возврат Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский; - -КонецФункции - -// Обновляет список ролей пользователей информационной базы -// по их текущим принадлежностям к группам доступа. -// Пользователи с ролью "ПолныеПрава" игнорируется. -// -// Параметры: -// ОписаниеПользователей - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// - Массив - значений указанных выше типов. -// - Неопределено - обновить роли всех пользователей. -// - Тип - по которому будет найден объект метаданных: -// если будет найден Справочник.ВнешниеПользователи, -// то будут обновлены роли всех внешних пользователей, -// иначе будут обновлены роли всех пользователей. -// -// ПарольПользователяСервиса - Строка - пароль для авторизации в менеджере сервиса. -// -// ЕстьИзменения - Булево - возвращаемое значение. В этот параметр возвращается -// значение Истина, если производилась запись, иначе не изменяется. -// -Процедура ОбновитьРолиПользователей(Знач ОписаниеПользователей = Неопределено, - Знач ПарольПользователяСервиса = Неопределено, - ЕстьИзменения = Ложь) Экспорт - - Если НЕ ПользователиСлужебный.ЗапретРедактированияРолей() Тогда - // Роли устанавливаются механизмами подсистем Пользователи и ВнешниеПользователи. - Возврат; - КонецЕсли; - - Если ОписаниеПользователей = Неопределено Тогда - МассивПользователей = Неопределено; - Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); - - ИначеЕсли ТипЗнч(ОписаниеПользователей) = Тип("Массив") Тогда - МассивПользователей = ОписаниеПользователей; - Если МассивПользователей.Количество() = 0 Тогда - Возврат; - ИначеЕсли МассивПользователей.Количество() = 1 Тогда - Пользователи.НайтиНеоднозначныхПользователейИБ(МассивПользователей[0]); - Иначе - Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); - КонецЕсли; - - ИначеЕсли ТипЗнч(ОписаниеПользователей) = Тип("Тип") Тогда - МассивПользователей = ОписаниеПользователей; - Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); - Иначе - МассивПользователей = Новый Массив; - МассивПользователей.Добавить(ОписаниеПользователей); - Пользователи.НайтиНеоднозначныхПользователейИБ(ОписаниеПользователей); - КонецЕсли; - - УстановитьПривилегированныйРежим(Истина); - - ТекущиеСвойстваПользователей = ТекущиеСвойстваПользователей(МассивПользователей); - - // Параметры проверки в цикле. - ВсеРоли = ПользователиСлужебный.ВсеРоли().Соответствие; - ИдентификаторыПользователейИБ = ТекущиеСвойстваПользователей.ИдентификаторыПользователейИБ; - НовыеРолиПользователей = ТекущиеСвойстваПользователей.РолиПользователей; - ИдентификаторыРолей = ТекущиеСвойстваПользователей.ИдентификаторыРолей; - ИменаРолей = ТекущиеСвойстваПользователей.ИменаРолей; - ОбязательныеРолиАдминистратора = ТекущиеСвойстваПользователей.ОбязательныеРолиАдминистратора; - ДополнительныеРолиАдминистратора = ТекущиеСвойстваПользователей.ДополнительныеРолиАдминистратора; - Администраторы = ТекущиеСвойстваПользователей.Администраторы; - РазделениеВключено = ОбщегоНазначения.РазделениеВключено(); - НеобходимоОбновлениеИБ = ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы(); - ИдентификаторТекущегоПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор; - - // Будущий итог после цикла. - НовыеАдминистраторыИБ = Новый Соответствие; - ОбновляемыеПользователиИБ = Новый Соответствие; - НекорректныеРоли = НовыеНекорректныеРоли(НовыеРолиПользователей); - - Для Каждого ОписаниеПользователя Из ИдентификаторыПользователейИБ Цикл - - ТекущийПользователь = ОписаниеПользователя.Пользователь; - ИдентификаторПользователяИБ = ОписаниеПользователя.ИдентификаторПользователяИБ; - НовыйАдминистраторИБ = Ложь; - - // Поиск пользователя ИБ. - Если ТипЗнч(ИдентификаторПользователяИБ) = Тип("УникальныйИдентификатор") Тогда - ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( - ИдентификаторПользователяИБ); - Иначе - ПользовательИБ = Неопределено; - КонецЕсли; - - Если ПользовательИБ = Неопределено - Или Не ЗначениеЗаполнено(ПользовательИБ.Имя) Тогда - Продолжить; - КонецЕсли; - - Если НеобходимоОбновлениеИБ - И ИдентификаторПользователяИБ = ИдентификаторТекущегоПользователяИБ Тогда - Продолжить; - КонецЕсли; - - Отказ = Ложь; - ИнтеграцияПодсистемБСП.ПриОбновленииРолейПользователяИБ(ИдентификаторПользователяИБ, Отказ); - Если Отказ Тогда - Продолжить; - КонецЕсли; - - Отбор = Новый Структура("Пользователь", ТекущийПользователь); - НовыеРоли = НовыеРолиПользователей.Скопировать( - НовыеРолиПользователей.НайтиСтроки(Отбор), "Роль, РольСсылка"); - - НовыеРоли.Индексы.Добавить("РольСсылка"); - - Если Администраторы[ТекущийПользователь] <> Неопределено Тогда - ТекущиеНовыеРоли = НовыеРоли; - НовыеРоли = ТекущиеНовыеРоли.Скопировать(Новый Массив); - Для Каждого КлючИЗначение Из ОбязательныеРолиАдминистратора Цикл - НовыеРоли.Добавить().РольСсылка = КлючИЗначение.Значение; - КонецЦикла; - Для Каждого КлючИЗначение Из ДополнительныеРолиАдминистратора Цикл - Если ТекущиеНовыеРоли.Найти(КлючИЗначение.Значение, "РольСсылка") = Неопределено Тогда - Продолжить; - КонецЕсли; - НовыеРоли.Добавить().РольСсылка = КлючИЗначение.Значение; - КонецЦикла; - КонецЕсли; - - НедоступныеРоли = ПользователиСлужебный.НедоступныеРолиПоТипуПользователя( - ТипЗнч(ТекущийПользователь) = Тип("СправочникСсылка.ВнешниеПользователи")); - - // Проверка старых ролей. - РолиДляДобавления = Новый Соответствие; - РолиДляУдаления = Новый Соответствие; - - Для Каждого Роль Из ПользовательИБ.Роли Цикл - ИмяРоли = Роль.Имя; - РольСсылка = ИдентификаторыРолей.Получить(ИмяРоли); - Если РольСсылка = Неопределено Тогда - КлючРоли = Справочники.ИдентификаторыОбъектовМетаданных.КлючОбъектаМетаданныхРоль(Роль); - РольСсылка = ИдентификаторыРолей.Получить(КлючРоли); - КонецЕсли; - Строка = НовыеРоли.Найти(РольСсылка, "РольСсылка"); - Если Строка = Неопределено Тогда - РолиДляУдаления.Вставить(ИмяРоли, Роль); - Иначе - Если РазделениеВключено И НедоступныеРоли.Получить(ИмяРоли) <> Неопределено Тогда - Строка.Роль = ИмяРоли; - ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Ложь); - РолиДляУдаления.Вставить(ИмяРоли, Роль); - КонецЕсли; - НовыеРоли.Удалить(Строка); - КонецЕсли; - КонецЦикла; - - // Проверка новых ролей. - Для Каждого Строка Из НовыеРоли Цикл - Строка.Роль = ИменаРолей.Получить(Строка.РольСсылка); - - Если ВсеРоли.Получить(Строка.Роль) = Неопределено Тогда - ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Истина); - Продолжить; - КонецЕсли; - - Если НедоступныеРоли.Получить(Строка.Роль) <> Неопределено Тогда - ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Ложь); - Продолжить; - КонецЕсли; - - РолиДляДобавления.Вставить(Строка.Роль, Истина); - - Если Строка.Роль = "АдминистраторСистемы" Тогда - НовыйАдминистраторИБ = Истина; - КонецЕсли; - КонецЦикла; - - // Завершение обработки текущего пользователя. - Если РолиДляДобавления.Количество() = 0 - И РолиДляУдаления.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - - ИзмененияРолей = Новый Структура; - ИзмененияРолей.Вставить("ПользовательСсылка", ТекущийПользователь); - ИзмененияРолей.Вставить("ПользовательИБ", ПользовательИБ); - ИзмененияРолей.Вставить("РолиДляДобавления", РолиДляДобавления); - ИзмененияРолей.Вставить("РолиДляУдаления", РолиДляУдаления); - - Если НовыйАдминистраторИБ Тогда - НовыеАдминистраторыИБ.Вставить(ТекущийПользователь, ИзмененияРолей); - Иначе - ОбновляемыеПользователиИБ.Вставить(ТекущийПользователь, ИзмененияРолей); - КонецЕсли; - - ЕстьИзменения = Истина; - КонецЦикла; - - ЗарегистрироватьНекорректныеРоли(НекорректныеРоли); - - // Добавление новых администраторов. - Если НовыеАдминистраторыИБ.Количество() > 0 Тогда - ОбновитьРолиПользователейИБ(НовыеАдминистраторыИБ, ПарольПользователяСервиса); - КонецЕсли; - - // Удаление старых администраторов и обновление остальных пользователей. - Если ОбновляемыеПользователиИБ.Количество() > 0 Тогда - ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса); - КонецЕсли; - - ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей(); - -КонецПроцедуры - -// Только для внутреннего использования. -// -// Возвращаемое значение: -// Булево -// -Функция ПоддерживаетсяРегистрацияИзмененийПраваДоступа() Экспорт - Возврат Истина; -КонецФункции - -// Возвращаемое значение: -// Строка -// -Функция ИмяСобытияИзменениеУчастниковГруппДоступаДляЖурналаРегистрации() Экспорт - - Возврат НСтр("ru = 'Управление доступом.Изменение участников групп доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()); - -КонецФункции - -// Возвращаемое значение: -// Строка -// -Функция ИмяСобытияИзменениеРазрешенныхЗначенийДляЖурналаРегистрации() Экспорт - - Возврат НСтр("ru = 'Управление доступом.Изменение разрешенных значений'", - ОбщегоНазначения.КодОсновногоЯзыка()); - -КонецФункции - -// Возвращаемое значение: -// Строка -// -Функция ИмяСобытияИзменениеРолейПрофилейДляЖурналаРегистрации() Экспорт - - Возврат НСтр("ru = 'Управление доступом.Изменение ролей профилей'", - ОбщегоНазначения.КодОсновногоЯзыка()); - -КонецФункции - -// См. СвойстваВидовДоступа -Функция СвойстваВсехВидовДоступа() Экспорт - Возврат СвойстваВидовДоступа(); -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ПолноеИмяФормыСпискаГруппДоступа - Строка -// * ПолноеИмяФормыЭлементаГруппДоступа - Строка -// * ПолноеИмяФормыСпискаПрофилей - Строка -// * ПолноеИмяФормыЭлементаПрофилей - Строка -// * ТипСправочникСсылкаГруппыДоступа - Тип -// * ТипСправочникСсылкаПрофилиГруппДоступа - Тип -// * ТипыЗначенийДоступа - Массив из Тип -// -Функция ПараметрыДляОтчетов() Экспорт - - Результат = Новый Структура; - Результат.Вставить("ПолноеИмяФормыСпискаГруппДоступа", "Справочник.ГруппыДоступа.Форма.ФормаСписка"); - Результат.Вставить("ПолноеИмяФормыЭлементаГруппДоступа", "Справочник.ГруппыДоступа.Форма.ФормаЭлемента"); - Результат.Вставить("ПолноеИмяФормыСпискаПрофилей", "Справочник.ПрофилиГруппДоступа.Форма.ФормаСписка"); - Результат.Вставить("ПолноеИмяФормыЭлементаПрофилей", "Справочник.ПрофилиГруппДоступа.Форма.ФормаЭлемента"); - Результат.Вставить("ТипСправочникСсылкаГруппыДоступа", Тип("СправочникСсылка.ГруппыДоступа")); - Результат.Вставить("ТипСправочникСсылкаПрофилиГруппДоступа", Тип("СправочникСсылка.ПрофилиГруппДоступа")); - Результат.Вставить("ТипыЗначенийДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип.Типы()); - - Возврат Результат; - -КонецФункции - -#КонецОбласти - -#Область УниверсальноеОграничение - -Функция ОграничиватьДоступНаУровнеЗаписейУниверсально(СУчетомКонстантыОграничениеДоступаНаУровнеЗаписей = Истина, - КогдаПервоеОбновлениеДоступаЗавершилось = Ложь, ОбновлятьПараметрыСеансаКогдаТребуется = Истина) Экспорт - - Если СУчетомКонстантыОграничениеДоступаНаУровнеЗаписей Тогда - Значение = КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); - - Если ОбновлятьПараметрыСеансаКогдаТребуется - И (Значение <> УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() - Или Значение - И Не ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально - И КонстантаПервоеОбновлениеДоступаЗавершилось()) Тогда - - ОбновитьПараметрыСеанса(); - Значение = УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); - КонецЕсли; - - Возврат Значение - И (Не КогдаПервоеОбновлениеДоступаЗавершилось - Или КонстантаПервоеОбновлениеДоступаЗавершилось()); - КонецЕсли; - - Если ОбновлятьПараметрыСеансаКогдаТребуется - И Не ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа.Полное - И Не ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально Тогда - - ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); - Если ПоследняяПроверка.Дата + 3 <= ТекущаяДатаСеанса() Тогда - - Значение = КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); - Если Значение И КонстантаПервоеОбновлениеДоступаЗавершилось() - Или Значение <> УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - - ОбновитьПараметрыСеанса(); - Значение = УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); - ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); - КонецЕсли; - ПоследняяПроверка.Дата = ТекущаяДатаСеанса(); - КонецЕсли; - КонецЕсли; - - Если Не КогдаПервоеОбновлениеДоступаЗавершилось Тогда - Возврат УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); - КонецЕсли; - - Возврат ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально; - -КонецФункции - -Функция КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() Экспорт - - Значение = Константы.ОграничиватьДоступНаУровнеЗаписейУниверсально.Получить(); - - Если Не Значение И Не ВариантВстроенногоЯзыкаРусский() Тогда - Значение = Истина; - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - МенеджерЗначения = СлужебныйМенеджерЗначения( - Константы.ОграничиватьДоступНаУровнеЗаписейУниверсально); - МенеджерЗначения.Значение = Значение; - МенеджерЗначения.Записать(); - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - КонецЕсли; - - Возврат Значение; - -КонецФункции - -// Устанавливает использование регламентного задания ОбновлениеДоступа. -// -// Параметры: -// Использование - Булево - Истина, если задание нужно включить, иначе Ложь. -// БезПроверкиВыполненияОбновленияИБ - Булево -// -Процедура УстановитьОбновлениеДоступа(Использование, БезПроверкиВыполненияОбновленияИБ = Ложь) Экспорт - - Если Использование - И Не БезПроверкиВыполненияОбновленияИБ - И ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда - - Возврат; // После обновления ИБ задание включается безусловно. - КонецЕсли; - - Если Использование Тогда - ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(); - Если ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда - Возврат; - КонецЕсли; - КонецЕсли; - - Если Использование Тогда - ВключитьЗадание = ?(ОбщегоНазначения.ИнформационнаяБазаФайловая(), - ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь, Ложь, Ложь), - ОграничиватьДоступНаУровнеЗаписейУниверсально()); - Иначе - ВключитьЗадание = Ложь; - КонецЕсли; - - Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); - Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); - - ТребуетсяИзменение = Ложь; - Для Каждого Задание Из Задания Цикл - Если ВключитьЗадание <> Задание.Использование Тогда - ТребуетсяИзменение = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Если Не ТребуетсяИзменение Тогда - Возврат; - КонецЕсли; - - Если ВключитьЗадание И ЭтоСеансФоновогоОбновленияДоступа() Тогда - Возврат; - КонецЕсли; - - Если МонопольныйРежим() - Или Не ТранзакцияАктивна() - Или ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - - ИзменитьРегламентноеЗаданиеОбновленияДоступа(ВключитьЗадание); - - ИначеЕсли ВключитьЗадание Тогда - ФоновыеЗадания.Выполнить("УправлениеДоступомСлужебный.ВключитьРегламентноеЗаданиеОбновленияДоступа",,, - НСтр("ru = 'Управление доступом: Включение регламентного задания обновления доступа'", - ОбщегоНазначения.КодОсновногоЯзыка())); - Иначе - ФоновыеЗадания.Выполнить("УправлениеДоступомСлужебный.ОтключитьРегламентноеЗаданиеОбновленияДоступа",,, - НСтр("ru = 'Управление доступом: Отключение регламентного задания обновления доступа'", - ОбщегоНазначения.КодОсновногоЯзыка())); - КонецЕсли; - -КонецПроцедуры - -// Возвращает ошибки текстов ограничений доступа объектов без учета зависимостей между объектами. -// Тексты проверяются в режиме максимальных ограничений (как будто включены все виды ограничений). -// Функция должна вызываться перед функцией НастройкиВнедрения, чтобы собрать весь пакет ошибок. -// -// Возвращаемое значение: -// Массив из Структура: -// * ПолноеИмя - Строка - полное имя объекта метаданных. -// * ТекстОшибки - Строка - текст ошибки в ограничении доступа. -// -Функция ОшибкиОграниченийДоступа() Экспорт - - Ошибки = Новый Массив; - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Истина, Ложь); - - Попытка - СпискиСОграничением = УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением(); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Списки с ограничением доступа некорректно указаны - |в процедуре %1 - |общего модуля %2 по причине: - | - |%3'"), - "ПриЗаполненииСписковСОграничениемДоступа", - "УправлениеДоступомПереопределяемый", - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - ОбъектОшибки = "ОбщийМодуль.УправлениеДоступомПереопределяемый"; - Ошибки.Добавить(Новый Структура("ПолноеИмя, ТекстОшибки", ОбъектОшибки, ТекстОшибки)); - Возврат Ошибки; - КонецПопытки; - - ТекстыОшибок = Новый Соответствие; - ОбщийКонтекст.Вставить("СпискиСОграничением", СпискиСОграничением); - ОбщийКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); - - Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл - ПолноеИмя = ОписаниеСписка.Ключ; - Попытка - ТекстОшибки = ОшибкаОграниченияДоступа(ОбщийКонтекст, ПолноеИмя); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - КонецПопытки; - Если ЗначениеЗаполнено(ТекстОшибки) И ТекстыОшибок.Получить(ТекстОшибки) = Неопределено Тогда - ТекстыОшибок.Вставить(ТекстОшибки, Истина); - Ошибки.Добавить(Новый Структура("ПолноеИмя, ТекстОшибки", ПолноеИмя, ТекстОшибки)); - КонецЕсли; - КонецЦикла; - - Возврат Ошибки; - -КонецФункции - -// Возвращает настройки внедрения для инструментов разработчика. -// -// Параметры: -// ДействующиеПараметры - Неопределено - значение по умолчанию. -// - Структура - только для вызова из функции РезультатПроверкиОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * ОграниченияВРолях - Структура: -// ** ДляПользователей - Соответствие из КлючИЗначение: -// *** Ключ - Строка - полное имя объекта метаданных (списка). Имя коллекции на английском. -// В форме объекта должна вставка ПриЧтенииНаСервере. -// *** Значение - Структура: -// **** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, -// если Ложь, тогда используется шаблон #ДляРегистра. -// **** Параметры - Массив из Строка - параметры шаблона (для объекта 1, для регистра 6). -// Например, имя поля "Владелец" или опорного поля регистра "Организация". -// ** ДляВнешнихПользователей - Соответствие из КлючИЗначение - как для пользователей выше: -// *** Ключ - Строка - полное имя объекта метаданных (списка). Имя коллекции на английском. -// В форме объекта должна вставка ПриЧтенииНаСервере. -// *** Значение - Структура: -// **** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, -// если Ложь, тогда используется шаблон #ДляРегистра. -// **** Параметры - Массив из Строка - параметры шаблона (для объекта 1, для регистра 6). -// Например, имя поля "Владелец" или опорного поля регистра "Организация". -// -// * ПредопределенныеИдентификаторы - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя требуемого предопределенного элемента справочника -// ИдентификаторыОбъектовМетаданных или ИдентификаторыОбъектовРасширений -// в формате "<ИмяСправочника>.<ИмяПредопределенного>". -// ** Значение - Строка - полное имя соответствующего объекта метаданных. -// -// * ВладельцыЗначенийКлючейДоступа - Структура - для группы определяемых типов: -// ** Ссылки - Массив из Строка - полные имена типов ссылки (имя коллекции на английском). -// ** Документы - Массив из Строка - полные имена типов объекта (имя коллекции на английском). -// ** Объекты - Массив из Строка - то же, что в предыдущем пункте. -// ** НаборыЗаписей - Массив из Строка - то же, что в предыдущем пункте. -// ** НаборыЗаписейРегистраРасчета - Массив из Строка - то же, что в предыдущем пункте. -// -// * ЗначенияДоступа - Массив из Строка - полные имена типов ссылки (имя коллекции на английском). -// Для дополнения определяемого типа ЗначениеДоступа. -// -// * ТипыИзмеренийРегистровКлючей - Соответствие из КлючИЗначение: -// Для измерений с именем Поле регистра КлючиДоступаКРегистрам и регистров КлючиДоступаКРегистру<*>: -// ** Ключ - Строка - имя регистра. -// ** Значение - Структура: -// *** ИменаТипов - Массив из Строка - полные имена типов (на английском). -// *** ПоляРегистров - Соответствие из КлючИЗначение: -// **** Ключ - Строка - полное имя регистра, который ограничивается. -// **** Значение - Массив из Структура: -// ***** Поле - Строка - имя поля регистра. -// ***** Тип - ОписаниеТипов - типы поля регистра. -// Порядок полей в массиве соответствуют -// служебным полям Поле1, Поле2, ... -// *** ПоляРегистровПоТипам - Соответствие из КлючИЗначение: -// **** Ключ - Строка - полное имя типа (на английском). -// **** Значение - Массив из Строка - полные имена полей, например, -// "РегистрСведений.ДополнительныеСведения.Свойство". -// -Функция НастройкиВнедрения(ДействующиеПараметры = Неопределено) Экспорт - - ОграниченияВРолях = Новый Структура; - ОграниченияВРолях.Вставить("ДляПользователей", Новый Соответствие); - ОграниченияВРолях.Вставить("ДляВнешнихПользователей", Новый Соответствие); - - ВладельцыЗначенийКлючейДоступа = Новый Структура; - ВладельцыЗначенийКлючейДоступа.Вставить("Ссылки", Новый Массив); - ВладельцыЗначенийКлючейДоступа.Вставить("Документы", Новый Массив); - ВладельцыЗначенийКлючейДоступа.Вставить("Объекты", Новый Массив); - ВладельцыЗначенийКлючейДоступа.Вставить("НаборыЗаписей", Новый Массив); - ВладельцыЗначенийКлючейДоступа.Вставить("НаборыЗаписейРегистраРасчета", Новый Массив); - - ПредопределенныеИдентификаторы = Новый Соответствие; - ЗначенияДоступа = Новый Массив; - ТипыИзмеренийРегистровКлючей = Новый Соответствие; - ТипыИзмеренийРегистраКлючей(ТипыИзмеренийРегистровКлючей, "КлючиДоступаКРегистрам"); - - ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; - ЗначенияДоступа.Добавить(ИмяТипаСсылкиXML(Метаданные.Справочники.КлючиДоступа.ПолноеИмя(), ТипыТаблицПоИменам)); - - ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); - Для Каждого ОписаниеВозможныхПрав Из ВозможныеПрава.ПоПолнымИменам Цикл - ЗначенияДоступа.Добавить(ИмяТипаСсылкиXML(ОписаниеВозможныхПрав.Ключ, ТипыТаблицПоИменам)); - КонецЦикла; - - Если ДействующиеПараметры = Неопределено Тогда - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Истина); - НовыеХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст); - ДействующиеПараметры = Новый Структура(НовыеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); // см. НоваяСтруктураХранимыхПараметровЗаписи - КонецЕсли; - - Контекст = Новый Структура; - Контекст.Вставить("ПредопределенныеИдентификаторы", ПредопределенныеИдентификаторы); - Контекст.Вставить("ТипыИзмеренийРегистровКлючей", ТипыИзмеренийРегистровКлючей); - Контекст.Вставить("ТипыТаблицПоИменам", ТипыТаблицПоИменам); - - ДобавленныеСписки = Новый Соответствие; - Для Каждого ОписаниеВерсии Из ДействующиеПараметры.ВерсииОграниченийСписков Цикл - ПолноеИмя = ОписаниеВерсии.Ключ; - ПолноеИмяXML = ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам); - ИмяТипаСсылкиXML = ИмяТипаСсылкиXML(ПолноеИмя, ТипыТаблицПоИменам); - ИмяТипаОбъектаXML = ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам); - - Если ЗначениеЗаполнено(ИмяТипаСсылкиXML) Тогда - ВладельцыЗначенийКлючейДоступа.Ссылки.Добавить(ИмяТипаСсылкиXML); - КонецЕсли; - - ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа); - ДобавленныеСписки.Вставить(ВРег(ПолноеИмя), Истина); - - Если ОписаниеВерсии.Значение = Неопределено Тогда - Продолжить; - КонецЕсли; - - ДобавитьОграниченияВРолях(ПолноеИмяXML, - ПолноеИмя, - ОграниченияВРолях.ДляПользователей, - ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков, - Контекст); - - ДобавитьОграниченияВРолях(ПолноеИмяXML, - ПолноеИмя, - ОграниченияВРолях.ДляВнешнихПользователей, - ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков, - Контекст); - КонецЦикла; - - Для Каждого ВедущийСписок Из ДействующиеПараметры.ВедущиеСписки Цикл - ПолноеИмя = ВедущийСписок.Ключ; - Если ДобавленныеСписки.Получить(ВРег(ПолноеИмя)) <> Неопределено Тогда - Продолжить; - КонецЕсли; - ИмяТипаОбъектаXML = ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам); - ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа); - КонецЦикла; - - Настройки = Новый Структура; - Настройки.Вставить("ОграниченияВРолях", ОграниченияВРолях); - Настройки.Вставить("ПредопределенныеИдентификаторы", ПредопределенныеИдентификаторы); - Настройки.Вставить("ВладельцыЗначенийКлючейДоступа", ВладельцыЗначенийКлючейДоступа); - Настройки.Вставить("ЗначенияДоступа", ЗначенияДоступа); - Настройки.Вставить("ТипыИзмеренийРегистровКлючей", ТипыИзмеренийРегистровКлючей); - - Возврат Настройки; - -КонецФункции - -// Возвращает результат проверки ограничения доступа для инструмента разработчика. -// -// Параметры: -// ПолноеИмя - Строка - полное имя объекта метаданных. -// ДополнительныеПараметры - Неопределено - проверить и вернуть текущее ограничение. -// - Структура: -// * Текст - Строка - новый текст ограничения для пользователей. -// * ТекстДляВнешнихПользователей - Строка - новый текст ограничения для внешних пользователей. -// * УчитыватьЗависимости - Булево - учитывать зависимости между ограничениями объектов. -// * ВсеВидыДоступаИспользуются - Неопределено - вычислить по текущим настройками. -// - Булево - Истина (по умолчанию) - используются все, -// Ложь - не используется ни одного. -// -// Возвращаемое значение: -// Структура: -// * ОшибкаОписанияОграничения - Строка - если не пустая, то описание ограничения не удалось получить. -// Если при этом УчитыватьЗависимости = Истина, то это текст первой ошибки при получении всех описаний. -// -// * ТекстВМодулеМенеджера - Неопределено - когда заполнена ОшибкаОписанияОграничения. -// - Булево - возвращает место размещения текста ограничения, -// когда Истина - в модуле менеджера, иначе в переопределяемом модуле. -// -// * ДляПользователей - Структура: -// ** ПроверяемоеОграничение - Неопределено -// - Строка - проверенный текст ограничения. -// ** ОписаниеОшибок - см. ОписаниеОшибок -// ** ОшибкаФормированияПараметровОграничения - Неопределено -// - Строка - текст ошибки. -// ** ОшибкаФормированияТекстовЗапросов - Неопределено -// - Строка - текст ошибки. -// ** ОграничениеПоВладельцуВозможно - Неопределено -// - Булево - свойство проверенного ограничения. -// ** ОграничениеПоВладельцуИспользуется - Неопределено -// - Булево - когда УчитыватьЗависимости указано Истина. -// ** ОграниченияВРолях - Неопределено -// - Структура: -// *** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, -// если Ложь, тогда используется шаблон #ДляРегистра. -// *** Параметры - Массив - параметры шаблона (для объекта 1, для регистра 6): -// **** Значение - Строка - например, имя поля "Владелец" или -// опорного поля регистра "Организация". -// ** ОграничениеВМодуле - Неопределено -// - Строка - текст ограничения, который установлен в конфигурации. -// ** ПоВладельцуБезЗаписиКлючейДоступа - Неопределено -// - Булево - настройка ограничения, -// установленная в конфигурации. -// -// * ДляВнешнихПользователей - Структура - со свойствами, как ДляПользователей. -// -// * ВладелецЗначенийКлючейДоступа - Строка - типы для одноименного определяемого типа. -// * ВладелецЗначенийКлючейДоступаОбъект - Строка - типы для одноименного определяемого типа. -// * ВладелецЗначенийКлючейДоступаНаборЗаписей - Строка - типы для одноименного определяемого типа. -// * ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета - Строка - типы для одноименного определяемого типа. -// * ПолеРегистраКлючейДоступаКРегистрам - Строка - типы для одноименного определяемого типа. -// * ЗначениеДоступа - Строка - типы для одноименного определяемого типа. -// -// * ТипыИзмеренийОтдельногоРегистраКлючей - Неопределено -// - Структура: -// ** ИмяРегистраСведений - Строка - имя регистра ключей доступа. -// ** ТипыИзмерений - Строка - типы для соответствующих измерений регистра. -// -// * ПредопределенныйИдентификатор - Неопределено -// - Структура: -// ** ИмяСправочника - Строка - имя справочника идентификаторы объектов метаданных (или расширений). -// ** ИмяПредопределенного - Строка - имя предопределенного в справочнике. -// -Функция РезультатПроверкиОграниченияДоступа(ПолноеИмя, ДополнительныеПараметры = Неопределено) Экспорт - - Возврат РезультатПроверкиОграниченияДоступаОбъекта(ПолноеИмя, ДополнительныеПараметры); - -КонецФункции - -// Добавляет обновление доступа для указанных списков или всех списков. -// -// Параметры: -// Списки - Неопределено - запланировать полное обновление доступа. -// - Строка - полное имя объекта метаданных. -// - СправочникСсылка.ИдентификаторыОбъектовМетаданных - идентификатор. -// - Массив -// - ФиксированныйМассив - значения типов указанные выше, кроме Неопределено. -// -// ПараметрыПланирования - см. ПараметрыПланированияОбновленияДоступа -// -Процедура ЗапланироватьОбновлениеДоступа(Списки = Неопределено, ПараметрыПланирования = Неопределено) Экспорт - - Если ПараметрыПланирования = Неопределено Тогда - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Если Не ПараметрыПланирования.КлючиДоступаКДанным - И Не ПараметрыПланирования.РазрешенныеКлючиДоступа Тогда - - Возврат; - КонецЕсли; - - ИдентификаторыРегистров = Новый Массив; - ИдентификаторыСписковКлючей = Новый Массив; - - Если Списки = Неопределено Тогда - Если ПараметрыПланирования.ВерсииОграниченийСписков = Неопределено Тогда - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - ВерсииОграниченийСписков = Новый Соответствие(ДействующиеПараметры.ВерсииОграниченийСписков); - Иначе - ВерсииОграниченийСписков = Новый Соответствие(Новый ФиксированноеСоответствие( - ПараметрыПланирования.ВерсииОграниченийСписков)); - КонецЕсли; - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("РазрешенныйКлючДоступа", - УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа()); - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) КАК ТипСсылки - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступаКДанным.Регистр КАК Регистр - |ИЗ - | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКДанным - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступа.Список КАК Список - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Ссылка <> &РазрешенныйКлючДоступа"; - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - ИдентификаторыРегистров = РезультатыЗапроса[1].Выгрузить().ВыгрузитьКолонку("Регистр"); - ИдентификаторыСписковКлючей = РезультатыЗапроса[2].Выгрузить().ВыгрузитьКолонку("Список"); - - Выборка = РезультатыЗапроса[0].Выбрать(); - ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповСсылокДопустимыхОбъектов(); - ЕстьНедопустимыйТип = Ложь; - Пока Выборка.Следующий() Цикл - Если ТипЗнч(Выборка.ТипСсылки) <> Тип("Тип") Тогда - Продолжить; - ИначеЕсли Выборка.ТипСсылки = Тип("Неопределено") - Или Не ДопустимыеТипы.СодержитТип(Выборка.ТипСсылки) Тогда - ЕстьНедопустимыйТип = Истина; - Продолжить; - КонецЕсли; - ОбъектМетаданных = Метаданные.НайтиПоТипу(Выборка.ТипСсылки); - Если ОбъектМетаданных = Неопределено Тогда - Продолжить; - КонецЕсли; - ВерсииОграниченийСписков.Вставить(ОбъектМетаданных.ПолноеИмя(), Истина); - КонецЦикла; - ВерсииОграниченийСписков.Вставить("Справочник.НаборыГруппДоступа", Истина); - Если ЕстьНедопустимыйТип Тогда - ИдентификаторыРегистров.Добавить(Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка()); - КонецЕсли; - - СпискиДляОбновления = Новый Массив; - Для Каждого КлючИЗначение Из ВерсииОграниченийСписков Цикл - СпискиДляОбновления.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - - // При планировании полного обновления добавляются: - // а) списки с ограничением, - // б) списки, которые пишут ключи доступа для ограничений по полю-владельцу, - // в) списки без ограничения, для которых есть записи в регистрах ключей доступа к данным, - // в) списки, для которых рассчитываются разрешенные ключи доступа, - // г) списки без расчета разрешенных ключей доступа, для которых есть записи в регистрах - // разрешенных ключей доступа. - - ИначеЕсли ТипЗнч(Списки) <> Тип("Массив") - И ТипЗнч(Списки) <> Тип("ФиксированныйМассив") Тогда - - СпискиДляОбновления = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Списки); - Иначе - СпискиДляОбновления = Списки; - КонецЕсли; - - Если СпискиДляОбновления.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - СпискиПоИдентификаторам = Новый Соответствие; - Если ТипЗнч(СпискиДляОбновления[0]) = Тип("Строка") Тогда - ИдентификаторыСписков = ?(ПараметрыПланирования.ИдентификаторыВсехСписков = Неопределено, - ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(СпискиДляОбновления, Списки <> Неопределено), - ПараметрыПланирования.ИдентификаторыВсехСписков); - Для Каждого ПолноеИмя Из СпискиДляОбновления Цикл - Идентификатор = ИдентификаторыСписков.Получить(ПолноеИмя); - Если Идентификатор <> Неопределено И Идентификатор <> Null Тогда - СпискиПоИдентификаторам.Вставить(Идентификатор, ПолноеИмя); - ИначеЕсли Списки <> Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не найден идентификатор объекта метаданных ""%1"".'"), ПолноеИмя); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - КонецЦикла; - Иначе - Для Каждого Идентификатор Из СпискиДляОбновления Цикл - СпискиПоИдентификаторам.Вставить(Идентификатор, ""); - КонецЦикла; - КонецЕсли; - - Если ЗначениеЗаполнено(ИдентификаторыРегистров) - Или ЗначениеЗаполнено(ИдентификаторыСписковКлючей) Тогда - - Для Каждого ИдентификаторРегистра Из ИдентификаторыРегистров Цикл - Если ИдентификаторРегистра = Неопределено Тогда - СпискиПоИдентификаторам.Вставить( - Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка(), ""); - КонецЕсли; - СпискиПоИдентификаторам.Вставить(ИдентификаторРегистра, ""); - КонецЦикла; - Для Каждого ИдентификаторРазрешенных Из ИдентификаторыСписковКлючей Цикл - СпискиПоИдентификаторам.Вставить(ИдентификаторРазрешенных, ""); - КонецЦикла; - КонецЕсли; - - ИдентификаторСправочникаНаборыГруппДоступа = - СлужебныйИдентификатор("Справочник.НаборыГруппДоступа"); - - ТекущаяДатаСеанса = ТекущаяДатаСеанса(); - КлючУникальностиЗаписей = Новый УникальныйИдентификатор; - - ЭтоТочечноеЗадание = Ложь; - ПараметрыЗадания = Новый Структура; - РазмерЗадания = 3; - - Если ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов Тогда - ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; - УстановитьВидКлючаДанных(ПараметрыЗадания, "УстаревшиеЭлементы"); - ДатаПоследнегоОбновленногоЭлемента = '00010101'; - РазмерЗадания = 2; - Иначе - ВедущийОбъект = ПараметрыПланирования.ВедущийОбъект; // См. ОписаниеВедущегоОбъекта - Если ВедущийОбъект <> Неопределено - И Не ( ВедущийОбъект.Свойство("ПоДаннымКэшаРасчетаПрав") - Или ВедущийОбъект.Свойство("ПоКлючамДоступа") - Или ВедущийОбъект.Свойство("ПоЗначениямСГруппами") - Или ВедущийОбъект.Свойство("ПоЗначениямПолей") - И ТипЗнч(ВедущийОбъект.ПоЗначениямПолей.СоставИзменений) = Тип("ТаблицаЗначений") ) Тогда - ВедущийОбъект = Неопределено; - КонецЕсли; - Если ВедущийОбъект <> Неопределено Тогда - ЭтоТочечноеЗадание = Истина; - ПараметрыПланирования = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыПланирования)); - ПараметрыПланирования.Вставить("ЭтоТочечноеЗадание"); - РазмерЗадания = 1; - ПараметрыЗадания.Вставить("ТочечноеЗадание", ВедущийОбъект); - КонецЕсли; - ДатаПоследнегоОбновленногоЭлемента = ?(ПараметрыПланирования.ЭтоПродолжениеОбновления, - МаксимальнаяДатаПриПродолжении(), МаксимальнаяДата()); - КонецЕсли; - Если ПараметрыЗадания.Количество() = 0 Тогда - ПараметрыЗадания = Неопределено; - КонецЕсли; - ХранилищеПараметровЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); - - ОбновлениеКлючейДоступаКДанным = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); - ОбновлениеКлючейДоступаПользователей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаПользователей); - - Для Каждого ОписаниеСписка Из СпискиПоИдентификаторам Цикл - ИдентификаторСписка = ОписаниеСписка.Ключ; - - Если ПараметрыПланирования.КлючиДоступаКДанным Тогда - Если ПараметрыПланирования.ДляПользователей Тогда - НоваяЗапись = ОбновлениеКлючейДоступаКДанным.Добавить(); - НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; - НоваяЗапись.Список = ИдентификаторСписка; - НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; - НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = ДатаПоследнегоОбновленногоЭлемента; - НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; - НоваяЗапись.РазмерЗадания = РазмерЗадания; - НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; - КонецЕсли; - Если ПараметрыПланирования.ДляВнешнихПользователей Тогда - НоваяЗапись = ОбновлениеКлючейДоступаКДанным.Добавить(); - НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; - НоваяЗапись.Список = ИдентификаторСписка; - НоваяЗапись.ДляВнешнихПользователей = Истина; - НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; - НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = ДатаПоследнегоОбновленногоЭлемента; - НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; - НоваяЗапись.РазмерЗадания = РазмерЗадания; - НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; - КонецЕсли; - КонецЕсли; - - Если ИдентификаторСписка = ИдентификаторСправочникаНаборыГруппДоступа Тогда - Продолжить; - КонецЕсли; - - Если ПараметрыПланирования.РазрешенныеКлючиДоступа Тогда - Если ПараметрыПланирования.ДляПользователей Тогда - НоваяЗапись = ОбновлениеКлючейДоступаПользователей.Добавить(); - НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; - НоваяЗапись.Список = ИдентификаторСписка; - НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; - НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; - НоваяЗапись.РазмерЗадания = РазмерЗадания; - НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; - КонецЕсли; - Если ПараметрыПланирования.ДляВнешнихПользователей Тогда - НоваяЗапись = ОбновлениеКлючейДоступаПользователей.Добавить(); - НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; - НоваяЗапись.Список = ИдентификаторСписка; - НоваяЗапись.ДляВнешнихПользователей = Истина; - НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; - НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; - НоваяЗапись.РазмерЗадания = РазмерЗадания; - НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; - КонецЕсли; - КонецЕсли; - КонецЦикла; - - Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); - КонецЕсли; - - Если ОбновлениеКлючейДоступаКДанным.Количество() > 0 Тогда - ОбновлениеКлючейДоступаКДанным.Записать(Ложь); - КонецЕсли; - - Если ОбновлениеКлючейДоступаПользователей.Количество() > 0 Тогда - ОбновлениеКлючейДоступаПользователей.Записать(Ложь); - КонецЕсли; - - ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, - ПараметрыПланирования, Списки = Неопределено); - - Если ОбновлениеКлючейДоступаКДанным.Количество() > 0 - Или ОбновлениеКлючейДоступаПользователей.Количество() > 0 Тогда - - УстановитьОбновлениеДоступа(Истина); - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Конструктор структуры дополнительных параметров для процедуры ЗапланироватьОбновлениеДоступа. -// -// Возвращаемое значение: -// Структура: -// * КлючиДоступаКДанным - Булево - по умолчанию Истина - запланировать обновление ключей доступа -// к данным. -// * РазрешенныеКлючиДоступа - Булево - по умолчанию Истина - запланировать обновление ключей доступа -// пользователей и групп доступа. -// * ДляПользователей - Булево - по умолчанию Истина - запланировать обновление для пользователей. -// * ДляВнешнихПользователей - Булево - по умолчанию значение константы ИспользоватьВнешнихПользователей -// запланировать обновление для внешних пользователей. -// -Функция ПараметрыПланированияОбновленияДоступа(ВычислитьДляВнешнихПользователей = Истина) Экспорт - - ДляВнешнихПользователей = ?(ВычислитьДляВнешнихПользователей, - Константы.ИспользоватьВнешнихПользователей.Получить(), Истина); - - Результат = Новый Структура; - Результат.Вставить("КлючиДоступаКДанным", Истина); - Результат.Вставить("РазрешенныеКлючиДоступа", Истина); - Результат.Вставить("ДляПользователей", Истина); - Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); - Результат.Вставить("ВедущийОбъект", Неопределено); - Результат.Вставить("ВерсииОграниченийСписков", Неопределено); - Результат.Вставить("ИдентификаторыВсехСписков", Неопределено); - Результат.Вставить("Описание", ""); - Результат.Вставить("ЭтоПродолжениеОбновления", Ложь); - Результат.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); - - Возврат Результат; - -КонецФункции - -// Параметры: -// Описание - Строка - имя процедуры, которая вызвала планирование, -// используемое для расширенной регистрации в журнале. -// ЗапуститьОбновление - Булево - если Истина, то планирование будет -// негарантированным, так как при наличии транзакции -// выполняется в фоне "как есть" для возможности запуска обновления. -// -Процедура ЗапланироватьОбновлениеПараметровОграниченияДоступа(Описание, ЗапуститьОбновление = Ложь) Экспорт - - Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - Возврат; - КонецЕсли; - - Если Не ТранзакцияАктивна() Или Не ЗапуститьОбновление Тогда - ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа(Описание, ЗапуститьОбновление); - Возврат; - КонецЕсли; - - ПараметрыПроцедуры = Новый Массив; - ПараметрыПроцедуры.Добавить(Описание); - ПараметрыПроцедуры.Добавить(ЗапуститьОбновление); - - ФоновыеЗадания.Выполнить( - "УправлениеДоступомСлужебный.ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа", - ПараметрыПроцедуры,, НСтр("ru = 'Управление доступом: планирование обновления доступа'", - ОбщегоНазначения.КодОсновногоЯзыка())); - -КонецПроцедуры - -// Только для процедуры ЗапланироватьОбновлениеПараметровОграниченияДоступа. -Процедура ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа(Описание, ЗапуститьОбновление) Экспорт - - Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - Возврат; - КонецЕсли; - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); - ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; - ПараметрыПланирования.Описание = Описание; - - Идентификатор = СлужебныйИдентификатор("РегистрСведений.ПараметрыОграниченияДоступа"); - Если Идентификатор <> Null Тогда - ЗапланироватьОбновлениеДоступа(Идентификатор, ПараметрыПланирования); - Если ЗапуститьОбновление Тогда - ЗапуститьОбновлениеДоступа(); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Запускает обновление доступа, если оно запланировано и еще не запущено. -Процедура ЗапуститьОбновлениеДоступа() Экспорт - - Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь) - Или МонопольныйРежим() - Или ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(Истина) - И Не ЕстьЗапланированныеТочечныеЗадания() Тогда - Возврат; - КонецЕсли; - - ЗапуститьОбновлениеДоступаНаУровнеЗаписей(,, Истина); - -КонецПроцедуры - -// Только для внутреннего использования. -Процедура ОбновитьДоступПослеОбновленияИнформационнойБазы(ВыполнитьОтложенноеОбновлениеСейчас) Экспорт - - Если ОбщегоНазначения.РазделениеВключено() - И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда - Возврат; - КонецЕсли; - - Если ВыполнитьОтложенноеОбновлениеСейчас - И ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - - ВыполнитьОбновлениеДоступаНаУровнеЗаписей(Истина, Ложь, 0, Истина); - КонецЕсли; - -КонецПроцедуры - -// Для функции ПраваРолейРасширений и функции ЗаполнитьВсеПараметрыРаботыРасширений -// модуля менеджера регистра сведений ПараметрыРаботыВерсийРасширений. -// -Процедура УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Включить) Экспорт - - УстановитьПривилегированныйРежим(Истина); - - ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; - ИмяСвойства = "ЗаписьПараметровОграниченияДоступаВТекущемСеансе"; - - Если Не Включить И Не ТекущиеПараметры.Свойство(ИмяСвойства) Тогда - Возврат; - КонецЕсли; - - НовыеПараметры = Новый Структура(ТекущиеПараметры); - - Если Включить Тогда - Если Не НовыеПараметры.Свойство(ИмяСвойства) Тогда - НовыеПараметры.Вставить(ИмяСвойства, 0); - КонецЕсли; - НовыеПараметры[ИмяСвойства] = НовыеПараметры[ИмяСвойства] + 1; - Иначе - НовыеПараметры[ИмяСвойства] = НовыеПараметры[ИмяСвойства] - 1; - Если НовыеПараметры[ИмяСвойства] < 1 Тогда - НовыеПараметры.Удалить(ИмяСвойства); - КонецЕсли; - КонецЕсли; - - ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(НовыеПараметры); - - УстановитьПривилегированныйРежим(Ложь); - -КонецПроцедуры - -#КонецОбласти - -#Область ОбработчикиСобытийПодсистемКонфигурации - -// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами. -Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт - Объекты.Вставить(Метаданные.Справочники.ГруппыДоступа.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке"); - Объекты.Вставить(Метаданные.Справочники.ПрофилиГруппДоступа.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке"); -КонецПроцедуры - -// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса. -Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт - - Обработчики.Вставить("ОграничениеДоступаНаУровнеЗаписейИспользуется", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ВидыДоступаБезГруппДляЗначенияДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ВидыДоступаСОднойГруппойДляЗначенияДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ВидыДоступаСОтключеннымИспользованием", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ВсеВидыДоступаКромеСпециальных", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ТаблицыСОтдельнымиНастройкамиПрав", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ТипыЗначенийДоступаСГруппами", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ТипыВладельцевНастроекПрав", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ТаблицыРасширенийСОграничениемДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - -#Область УниверсальноеОграничение - - Обработчики.Вставить("ОграничениеДоступаНаУровнеЗаписейУниверсально", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ОтключениеОбновленияКлючейДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ВерсииШаблоновОграниченияДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("РазрешенныйНаборГруппДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("РазрешенныйПустойНаборГруппДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("РазрешенныйНаборГруппПользователей", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("РазрешенныйПользователь", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ОбщиеПараметрыШаблоновОграниченияДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("СпискиСОграничениемПоПолям", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("СпискиСОграничениемЧерезКлючиДоступаПользователей", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("СпискиСОтключеннымОграничениемЧтения", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - - Обработчики.Вставить("ПараметрыОграниченияДоступа", - "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); - -#КонецОбласти - -КонецПроцедуры - -// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий -Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт - - Настройка = Настройки.Добавить(); - Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа; - Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ОграничиватьДоступНаУровнеЗаписей; - - Настройка = Настройки.Добавить(); - Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей; - Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ОграничиватьДоступНаУровнеЗаписейУниверсально; - -КонецПроцедуры - -// Обновляет вспомогательные данные, которые зависят только от конфигурации. -// Записывает изменения этих данных по версиям конфигурации(если изменения есть), -// чтобы использовать эти изменения при обновлении остальных вспомогательных данных, -// например, в обработчике ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации. -// -Процедура ОбновитьПараметрыОграниченияДоступа(ЕстьИзменения = Неопределено) Экспорт - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". - РегистрыСведений.ПраваРолей.ОбновитьДанныеРегистра(ЕстьИзменения); - - // ЗависимостиПравДоступа - РегистрыСведений.ЗависимостиПравДоступа.ОбновитьДанныеРегистра(ЕстьИзменения); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". - ОбновитьОписаниеСвойствВидовДоступа(ЕстьИзменения); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". - РегистрыСведений.НастройкиПравОбъектов.ОбновитьВозможныеПраваДляНастройкиПравОбъектов(ЕстьИзменения); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". - Справочники.ПрофилиГруппДоступа.ОбновитьОписаниеПоставляемыхПрофилей(ЕстьИзменения); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". - Справочники.ПрофилиГруппДоступа.ОбновитьСоставПредопределенныхПрофилей(ЕстьИзменения); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". - РегистрыСведений.ПараметрыОграниченияДоступа.ОбновитьВерсиюТекстовОграниченияДоступа(ЕстьИзменения); - -КонецПроцедуры - -// Обновляет описание свойств видов доступа в параметрах работы программы. -// -// Параметры: -// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, -// устанавливается Истина, иначе не изменяется. -// -Процедура ОбновитьОписаниеСвойствВидовДоступа(ЕстьИзменения = Ложь) Экспорт - - УстановитьПривилегированныйРежим(Истина); - - Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); - НовоеЗначение = Кэш.ХешСуммы; - - НачатьТранзакцию(); - Попытка - ЕстьТекущиеИзменения = Ложь; - СтароеЗначение = Неопределено; - - СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы( - "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа", - НовоеЗначение, ЕстьТекущиеИзменения, СтароеЗначение); - - СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); - - ЕстьИзмененияТиповГруппИЗначенийДоступа = - НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа - <> СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа; - - СтандартныеПодсистемыСервер.ДобавитьИзмененияПараметраРаботыПрограммы( - "СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа", - ?(ЕстьИзмененияТиповГруппИЗначенийДоступа, - Новый ФиксированнаяСтруктура("ЕстьИзменения", Истина), - Новый ФиксированнаяСтруктура()) ); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ЕстьТекущиеИзменения Тогда - ЕстьИзменения = Истина; - КонецЕсли; - -КонецПроцедуры - -// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления. -Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт - - // Обработчики обновления неразделенных данных. - Обработчик = Обработчики.Добавить(); - Обработчик.ОбщиеДанные = Истина; - Обработчик.УправлениеОбработчиками = Истина; - Обработчик.Приоритет = 1; - Обработчик.Версия = "*"; - Обработчик.РежимВыполнения = "Оперативно"; - Обработчик.Процедура = "УправлениеДоступомСлужебный.ЗаполнитьОбработчикиРазделенныхДанных"; - - // Обработчики обновления разделенных данных. - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "*"; - Обработчик.РежимВыполнения = "Оперативно"; - Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации"; - - // Должен выполнятся после обработчика ЗаполнитьИдентификаторыПоставляемыхДанных. - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "1.0.0.1"; - Обработчик.НачальноеЗаполнение = Истина; - Обработчик.Процедура = "Справочники.ГруппыДоступа.ЗаполнитьПрофильГруппыДоступаАдминистраторы"; - Обработчик.РежимВыполнения = "Монопольно"; - Обработчик.ВыполнятьВГруппеОбязательных = Истина; - Обработчик.Приоритет = 1; - - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "2.4.1.1"; - Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьДанныеПрофиляОткрытиеВнешнихОтчетовИОбработок"; - Обработчик.РежимВыполнения = "Оперативно"; - Обработчик.ВыполнятьВГруппеОбязательных = Истина; - Обработчик.Приоритет = 1; - - Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда - Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика(); - НоваяСтрока = Обработчик.ПриоритетыВыполнения.Добавить(); - НоваяСтрока.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию"; - НоваяСтрока.Порядок = "До"; - КонецЕсли; - - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "3.1.3.135"; - Обработчик.Процедура = "РегистрыСведений.ГруппыЗначенийДоступа.ОбработатьДанныеДляПереходаНаНовуюВерсию"; - Обработчик.РежимВыполнения = "Отложенно"; - Обработчик.Комментарий = НСтр("ru = 'Обновление вспомогательных данных.'"); - Обработчик.Идентификатор = Новый УникальныйИдентификатор("b3cb643e-d5cf-40b7-9db3-6315a88c063d"); - Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.ГруппыЗначенийДоступа.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; - Обработчик.ЧитаемыеОбъекты = "РегистрСведений.ГруппыЗначенийДоступа"; - Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ГруппыЗначенийДоступа"; - - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "3.0.2.174"; - Обработчик.Процедура = "РегистрыСведений.НастройкиПравОбъектов.ОбработатьДанныеДляПереходаНаНовуюВерсию"; - Обработчик.РежимВыполнения = "Отложенно"; - Обработчик.Комментарий = НСтр("ru = 'Обновление вспомогательных данных настроек прав.'"); - Обработчик.Идентификатор = Новый УникальныйИдентификатор("40d1c62f-c3f1-4608-8985-2dc618c3d758"); - Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.НастройкиПравОбъектов.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; - Обработчик.ЧитаемыеОбъекты = "РегистрСведений.НастройкиПравОбъектов"; - Обработчик.ИзменяемыеОбъекты = "РегистрСведений.НастройкиПравОбъектов"; - - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "3.1.10.80"; - Обработчик.Процедура = "Справочники.ГруппыДоступа.ОбработатьДанныеДляПереходаНаНовуюВерсию"; - Обработчик.РежимВыполнения = "Отложенно"; - Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина; - Обработчик.Комментарий = НСтр("ru = 'Удаляет служебных пользователей из групп доступа.'"); - Обработчик.Идентификатор = Новый УникальныйИдентификатор("4795e622-6115-4abc-a8de-cf2e838b7ea2"); - Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы"; - Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ГруппыДоступа.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; - Обработчик.ЧитаемыеОбъекты = "Справочник.ГруппыДоступа"; - Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ТаблицыГруппДоступа,РегистрСведений.ЗначенияГруппДоступа,РегистрСведений.ЗначенияГруппДоступаПоУмолчанию"; - - // Должен выполнятся до прикладных обработчиков обновления. - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "3.1.11.49"; - Обработчик.Процедура = "РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра"; - Обработчик.РежимВыполнения = "Оперативно"; - Обработчик.ВыполнятьВГруппеОбязательных = Истина; - Обработчик.Приоритет = 1; - -КонецПроцедуры - -// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек -// -// Параметры: -// Объекты - Массив из ОбъектМетаданных -// -Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт - - Объекты.Добавить(Метаданные.Справочники.ПрофилиГруппДоступа); - Объекты.Добавить(Метаданные.Справочники.ГруппыДоступа); - -КонецПроцедуры - -// См. ОбновлениеИнформационнойБазыБСП.ПослеОбновленияИнформационнойБазы. -Процедура ПослеОбновленияИнформационнойБазы(Знач ПредыдущаяВерсия, Знач ТекущаяВерсия, - Знач ВыполненныеОбработчики, ВыводитьОписаниеОбновлений, МонопольныйРежим) Экспорт - - Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда - Возврат; - КонецЕсли; - - ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); - - РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); - УстановитьОбновлениеДоступа(Истина, Истина); - -КонецПроцедуры - -// См. ОбновлениеИнформационнойБазыПереопределяемый.ПриЗаполненииОбъектовПланируемыхКУдалению. -Процедура ПриЗаполненииОбъектовПланируемыхКУдалению(Объекты) Экспорт - - // РегистрСведений.ЗависимостиПравДоступа.ТипВедущейТаблицы - ЗависимостиПравДоступа = РегистрыСведений.ЗависимостиПравДоступа.ЗависимостиПравДоступа(); - ТипыВедущихТаблиц = Новый Массив; - Для Каждого Строка Из ЗависимостиПравДоступа Цикл - ТипыВедущихТаблиц.Добавить(ТипЗнч(Строка.ТипВедущейТаблицы)); - КонецЦикла; - ТребуемыйТипВедущейТаблицы = Новый ОписаниеТипов(ТипыВедущихТаблиц); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВедущейТаблицы, - Метаданные.РегистрыСведений.ЗависимостиПравДоступа.Измерения.ТипВедущейТаблицы); - - Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда - Возврат; - КонецЕсли; - - НастройкиВнедрения = НастройкиВнедрения(); - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - СлужебныеТипы = Новый Массив; - СлужебныеТипы.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); - СлужебныеТипы.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); - СлужебныеТипы.Добавить(Тип("ПеречислениеСсылка.ДополнительныеЗначенияДоступа")); - - // ОпределяемыйТип.ЗначениеДоступа - ТипыГруппИЗначений = Новый Массив; - Для Каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамГруппИЗначений Цикл - ТипыГруппИЗначений.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов( - СтрСоединить(НастройкиВнедрения.ЗначенияДоступа, ",")); - ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов(ТребуемыйТипЗначенияДоступа, ТипыГруппИЗначений); - ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов(ТребуемыйТипЗначенияДоступа, СлужебныеТипы); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.ЗначенияГруппДоступа.Измерения.ЗначениеДоступа); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию.Измерения.ТипЗначенийДоступа); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.ГруппыЗначенийДоступа.Измерения.ЗначениеДоступа); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.ГруппыЗначенийДоступа.Измерения.ГруппаЗначенийДоступа); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.ИспользуемыеВидыДоступа.Измерения.ТипЗначенийДоступа); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.ИспользуемыеВидыДоступаПоТаблицам.Измерения.ТипЗначенийДоступа); - - // ОпределяемыйТип.ВладелецНастроекПрав - ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); - ТипыВладельцевНастроекПрав = Новый Массив; - Для Каждого ВладелецПрав Из ВозможныеПрава.ТипыВладельцев Цикл - ТипыВладельцевНастроекПрав.Добавить(ТипЗнч(ВладелецПрав)); - КонецЦикла; - ТребуемыйТипВладельцаНастроекПрав = Новый ОписаниеТипов(ТипыВладельцевНастроекПрав); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, - Метаданные.РегистрыСведений.НастройкиПравОбъектов.Измерения.Объект); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, - Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.Измерения.Объект); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, - Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.Измерения.Родитель); - - // ОпределяемыйТип.ВладелецЗначенийКлючейДоступа - ДобавитьОбъектПланируемыйКУдалению(Объекты, - Новый ОписаниеТипов(СтрСоединить(НастройкиВнедрения.ВладельцыЗначенийКлючейДоступа.Ссылки, ",")), - Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект); - - // ОпределяемыйТип.ПолеРегистраКлючейДоступаКРегистрам - Для Каждого ОписаниеРегистровКлючей Из НастройкиВнедрения.ТипыИзмеренийРегистровКлючей Цикл - ИмяРегистраКлючей = ОписаниеРегистровКлючей.Ключ; - МетаданныеРегистраКлючей = Метаданные.РегистрыСведений[ИмяРегистраКлючей]; - КоличествоПолей = УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистраКлючей); - ТребуемыйТипПоля = Новый ОписаниеТипов(СтрСоединить(ОписаниеРегистровКлючей.Значение.ИменаТипов, ",")); - ТребуемыйТипПоля = Новый ОписаниеТипов(ТребуемыйТипПоля, СлужебныеТипы); - Для НомерПоля = 1 По КоличествоПолей Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипПоля, - МетаданныеРегистраКлючей.Измерения[ИмяПоля]); - КонецЦикла; - КонецЦикла; - - // РегистрСведений.НаборыЗначенийДоступа.Объект - ТипыОбъектовПодписок = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( - "ЗаписатьНаборыЗначенийДоступа"); - ТипыСсылокОбъектовПодписок = Новый Массив; - Для Каждого КлючИЗначение Из ТипыОбъектовПодписок Цикл - МетаданныеОбъекта = Метаданные.НайтиПоТипу(КлючИЗначение.Ключ); - МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъекта.ПолноеИмя()); - ПустаяСсылка = МенеджерОбъекта.ПустаяСсылка(); - ТипыСсылокОбъектовПодписок.Добавить(ТипЗнч(ПустаяСсылка)); - КонецЦикла; - ТребуемыйТипТаблицСЗаписьюНаборовЗначенийДоступа = Новый ОписаниеТипов( - Новый ОписаниеТипов(ТипыСсылокОбъектовПодписок),, СлужебныеТипы); - - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипТаблицСЗаписьюНаборовЗначенийДоступа, - Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект); - - // РегистрСведений.НаборыЗначенийДоступа.ЗначениеДоступа - ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, - Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.ЗначениеДоступа); - -КонецПроцедуры - -// Параметры: -// ИзменениеЯзыков - см. МультиязычностьСервер.ОписаниеСтарыхИНовыхНастроекЯзыков -// -Процедура ПриИзмененииЯзыкаИнформационнойБазы(ИзменениеЯзыков) Экспорт - - Справочники.ПрофилиГруппДоступа.ПриИзмененииЯзыкаИнформационнойБазы(ИзменениеЯзыков); - -КонецПроцедуры - -// Заполняет структуру параметров, необходимых для работы клиентского кода -// конфигурации. -// -// Параметры: -// Параметры - Структура - структура параметров. -// -Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт - - Параметры.Вставить("УпрощенныйИнтерфейсНастройкиПравДоступа", - УпрощенныйИнтерфейсНастройкиПравДоступа()); - -КонецПроцедуры - -// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок. -Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт - - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ГруппыЗначенийДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗависимостиПравДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗначенияГруппДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.НаборыЗначенийДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ПраваРолей); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ТаблицыГруппДоступа); - - ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(ИсключенияПоискаСсылок); - -КонецПроцедуры - -// Объекты с отложенным удалением. -// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок -// -// Параметры: -// ИсключенияПоискаСсылок - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.ИсключенияПоискаСсылок -// -Процедура ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(ИсключенияПоискаСсылок) Экспорт - - ИсключенияПоискаСсылок.Добавить(Метаданные.Справочники.КлючиДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.Справочники.НаборыГруппДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаВнешнихПользователей); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаГруппДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаНаборовГруппДоступа); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаКОбъектам); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаКРегистрам); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаПользователей); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ОбновлениеКлючейДоступаКДанным); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ОбновлениеКлючейДоступаПользователей); - ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа); - - Для Каждого РегистрСведений Из Метаданные.РегистрыСведений Цикл - Если СтрНачинаетсяС(ВРег(РегистрСведений.Имя), ВРег("КлючиДоступаКРегистру")) Тогда - ИсключенияПоискаСсылок.Добавить(РегистрСведений); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Вызывается при загрузке ссылок предопределенных элементов в процессе загрузки важных данных. -// Позволяет выполнить действия по исправлению или регистрации сведений о не уникальности -// предопределенных элементов, а также позволяет отказаться от продолжения, если это недопустимо. -// -// Параметры: -// Объект - СправочникОбъект -// - ПланВидовХарактеристикОбъект -// - ПланСчетовОбъект -// - ПланВидовРасчетаОбъект - -// объект предопределенного элемента после записи которого обнаружено наличие не уникальности. -// ЗаписатьВЖурнал - Булево - возвращаемое значение. Если указать Ложь, тогда сведения о не уникальности не будут -// добавлены в журнал регистрации в общем сообщении. -// Нужно установить Ложь, если не уникальность была устранена автоматически. -// Отказ - Булево - возвращаемое значение. Если указать Истина, будет вызвано общее исключение, -// содержащее все причины отказа. -// ОписаниеОтказа - Строка - возвращаемое значение. Если Отказ установлен в Истина, то описание будет добавлено -// в список причин невозможности продолжения. -// -Процедура ПриОбнаруженииНеУникальностиПредопределенного(Объект, ЗаписатьВЖурнал, Отказ, ОписаниеОтказа) Экспорт - - Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") - И Объект.ИмяПредопределенныхДанных = "Администратор" Тогда - - ЗаписатьВЖурнал = Ложь; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка); - Запрос.УстановитьПараметр("ИмяПредопределенныхДанных", "Администратор"); - Запрос.Текст = - "ВЫБРАТЬ - | ПрофилиГруппДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа - |ГДЕ - | ПрофилиГруппДоступа.Ссылка <> &Ссылка - | И ПрофилиГруппДоступа.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; - - Выборка = Запрос.Выполнить().Выбрать(); - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); - - Пока Выборка.Следующий() Цикл - ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект(); - ТекущийОбъект.ИмяПредопределенныхДанных = ""; - ТекущийОбъект.ИдентификаторПоставляемыхДанных = ""; - ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - - ИначеЕсли ТипЗнч(Объект) = Тип("СправочникОбъект.ГруппыДоступа") - И Объект.ИмяПредопределенныхДанных = "Администраторы" Тогда - - ЗаписатьВЖурнал = Ложь; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИмяПредопределенныхДанных", "Администраторы"); - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ГруппыДоступаПользователи.Пользователь - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - |ГДЕ - | ГруппыДоступаПользователи.Ссылка.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; - ВсеПользователи = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Пользователь"); - - Записать = Ложь; - Для каждого Пользователь Из ВсеПользователи Цикл - Если Объект.Пользователи.Найти(Пользователь, "Пользователь") = Неопределено Тогда - Объект.Пользователи.Добавить().Пользователь = Пользователь; - Записать = Истина; - КонецЕсли; - КонецЦикла; - - Если Записать Тогда - ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); - КонецЕсли; - - Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка); - Запрос.Текст = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Ссылка <> &Ссылка - | И ГруппыДоступа.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; - - Выборка = Запрос.Выполнить().Выбрать(); - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - - Пока Выборка.Следующий() Цикл - ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект(); - ТекущийОбъект.ИмяПредопределенныхДанных = ""; - ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// См. ОбменДаннымиПереопределяемый.ПриНастройкеПодчиненногоУзлаРИБ. -Процедура ПриНастройкеПодчиненногоУзлаРИБ() Экспорт - - // Роли расширений назначаются независимо во всех РИБ-узлах. - Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширенийВоВсехПрофиляхГруппДоступа(); - - // Администраторы назначаются независимо во всех РИБ-узлах. - Справочники.ГруппыДоступа.УдалитьУчастниковГруппыДоступаАдминистраторыБезПользователяИБ(); - - Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); - Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); - - Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); - ПараметрыПланирования.Описание = "ПриНастройкеПодчиненногоУзлаРИБ"; - ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); - КонецЕсли; - -КонецПроцедуры - -// См. ПользователиСлужебный.ПриЗаполненииВидовРегистрируемыхСсылок. -Процедура ПриЗаполненииВидовРегистрируемыхСсылок(ВидыСсылок) Экспорт - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ОграничиватьДоступНаУровнеЗаписей"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("Булево"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписейИзменениеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ИспользуемыеВидыДоступа"; - ВидСсылок.ДопустимыеТипы = Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип; - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ИспользуемыеВидыДоступаИзмененныеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ПрофилиГруппДоступа"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ПрофилиГруппДоступа"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ПрофилиИзмененныеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ПрофилиГруппДоступаРоли"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( - "СправочникСсылка.ИдентификаторыОбъектовМетаданных,СправочникСсылка.ИдентификаторыОбъектовРасширений"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ПрофилиГруппДоступаРолиИзмененныеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ГруппыДоступа"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ГруппыДоступа"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаИзмененныеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ГруппыДоступаРоли"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( - "СправочникСсылка.ИдентификаторыОбъектовМетаданных,СправочникСсылка.ИдентификаторыОбъектовРасширений"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаРолиИзмененныеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ГруппыДоступаПользователи"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( - "СправочникСсылка.Пользователи,СправочникСсылка.ВнешниеПользователи"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаПользователиИзмененныеПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ГруппыДоступаЗначенийСИерархией"; - ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ГруппыДоступа"); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаЗначенийСИерархиейИзмененныхПриЗагрузке"; - - ВидСсылок = ВидыСсылок.Добавить(); - ВидСсылок.Имя = "ЗначенияДоступа"; - ВидСсылок.ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ТипыСсылокИзЗначениеДоступаОбъект(); - ВидСсылок.ИмяПараметраРаботыРасширений = - "СтандартныеПодсистемы.УправлениеДоступом.ЗначенияДоступаИзмененныеПриЗагрузке"; - -КонецПроцедуры - -// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхГлавному. -Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель) Экспорт - - ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Ложь, Ложь); - -КонецПроцедуры - -// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному. -Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель) Экспорт - - ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Истина, СозданиеНачальногоОбраза); - -КонецПроцедуры - -// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного. -Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт - - ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Ложь); - -КонецПроцедуры - -// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтПодчиненного. -Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт - - ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Истина); - -КонецПроцедуры - -// См. СтандартныеПодсистемыСервер.ПослеПолученияДанных. -Процедура ПослеПолученияДанных(Отправитель, Отказ, ПолучениеИзГлавногоУзла) Экспорт - - Если ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда - Возврат; - КонецЕсли; - - ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); - -КонецПроцедуры - -// См. описание в процедуре ЗаполнитьВсеПараметрыРаботыРасширений -// модуля менеджера регистра сведений ПараметрыРаботыВерсийРасширений. -// -Процедура ПриЗаполненииВсехПараметровРаботыРасширений() Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". - ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); - - Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда - // Обновление выполняется в процедуре - // ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации - // или ПриНастройкеПодчиненногоУзлаРИБ. - Возврат; - КонецЕсли; - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". - РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); - ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". - РегистрыСведений.НастройкиПравОбъектов.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". - Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); - Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". - Справочники.ГруппыДоступа.ПометитьНаУдалениеГруппыДоступаПомеченныхПрофилей(); - - // Если были нештатные ситуации и обновление не завершилось. - ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); - - // Обновление ролей пользователей ИБ после таких изменений расширений, - // которые приводят к рассогласованию ролей между пользователями ИБ и профилями, - // но не меняют состав ролей профилей. - ОбновитьРолиПользователей(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". - ЗапланироватьОбновлениеПараметровОграниченияДоступа( - "ПриЗаполненииВсехПараметровРаботыРасширений"); - -КонецПроцедуры - -// Параметры: -// * Задание - РегламентноеЗадание -// -Процедура ПередЗапускомРегламентногоЗаданияНеВФоне(Задание) Экспорт - - Если Задание.Метаданные <> Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей Тогда - Возврат; - КонецЕсли; - - Задание.Параметры.Добавить(Истина); - Задание.Параметры.Добавить(Истина); - -КонецПроцедуры - -// Обработчики событий подсистемы Пользователи. - -// См. ПользователиПереопределяемый.ПриОпределенииНастроек. -Процедура ПриОпределенииНастроек(Настройки) Экспорт - - // Роли устанавливаются автоматически по данным групп доступа - // через связь: ПользователиГруппыДоступа -> Профиль -> РолиПрофиля. - Настройки.РедактированиеРолей = Ложь; - -КонецПроцедуры - -// См. ПользователиПереопределяемый.ИзменитьДействияВФорме. -Процедура ПриОпределенииДействийВФорме(Знач ПользовательИлиГруппа, Знач ДействияВФорме) Экспорт - - ДействияВФорме.Роли = ""; - -КонецПроцедуры - -// См. ИнтеграцияПодсистемБСП.ПослеЗаписиАдминистратораПриАвторизации. -Процедура ПослеЗаписиАдминистратораПриАвторизации(Комментарий) Экспорт - - Комментарий = - НСтр("ru = 'Выполнен запуск от имени пользователя с ролью ""Полные права"", - |который не зарегистрирован в списке пользователей. - |Выполнена автоматическая регистрация в списке пользователей. - |Пользователь добавлен в группу доступа Администраторы. - | - |Для ведения списка и настройки прав пользователей предназначен список Пользователи, - |режим конфигурирования 1С:Предприятия для этого использовать не следует.'"); - -КонецПроцедуры - -// См. ИнтеграцияПодсистемБСП.ПослеУстановкиПользователяИБ. -Процедура ПослеУстановкиПользователяИБ(Ссылка, ПарольПользователяСервиса) Экспорт - - ОбновитьРолиПользователей(Ссылка, ПарольПользователяСервиса); - - Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); - КонецЕсли; - ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа( - ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Ссылка),, Истина); - КонецЕсли; - -КонецПроцедуры - -// См. ИнтеграцияПодсистемБСП.ПриОпределенииТекстаВопросаПередЗаписьюПервогоАдминистратора. -Процедура ПриОпределенииТекстаВопросаПередЗаписьюПервогоАдминистратора(ТекстВопроса) Экспорт - - ТекстВопроса = - НСтр("ru = 'В список пользователей приложения добавляется первый пользователь, - |поэтому он будет автоматически включен в группу доступа Администраторы. - |Продолжить?'") - -КонецПроцедуры - -// См. ИнтеграцияПодсистемБСП.ПриСозданииАдминистратора. -Процедура ПриСозданииИлиАвторизацииАдминистратора(Администратор, Уточнение) Экспорт - - Если ТипЗнч(Администратор) <> Тип("СправочникСсылка.Пользователи") Тогда - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Пользователь", Администратор); - Запрос.УстановитьПараметр("ГруппаДоступаАдминистраторы", - УправлениеДоступом.ГруппаДоступаАдминистраторы()); - Запрос.Текст = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - |ГДЕ - | ГруппыДоступаПользователи.Ссылка = &ГруппаДоступаАдминистраторы - | И ГруппыДоступаПользователи.Пользователь = &Пользователь - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ИСТИНА - |ИЗ - | Справочник.Пользователи КАК Пользователи - |ГДЕ - | Пользователи.Служебный - | И Пользователи.Ссылка = &Пользователь"; - - Если Не Запрос.Выполнить().Пустой() Тогда - Возврат; - КонецЕсли; - - КомментарийДляЖурнала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Пользователь ""%1"" добавлен в группу доступа Администраторы по причине: - |%2'"), - Администратор, - Уточнение); - - ГруппаДоступаАдминистраторы = УправлениеДоступом.ГруппаДоступаАдминистраторы(); - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступаАдминистраторы); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = ГруппаДоступаАдминистраторы.ПолучитьОбъект(); - ЗаблокироватьДанныеДляРедактирования(Объект.Ссылка, Объект.ВерсияДанных); - Если Объект.Пользователи.Найти(Администратор, "Пользователь") = Неопределено Тогда - Объект.Пользователи.Добавить().Пользователь = Администратор; - ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Автоматическое изменение группы доступа Администраторы'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, - Метаданные.Справочники.Пользователи, - Администратор, - КомментарийДляЖурнала, - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - КонецЕсли; - РазблокироватьДанныеДляРедактирования(Объект.Ссылка); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// См. ИнтеграцияПодсистемБСП.ПослеОбновленияСоставовГруппПользователей. -Процедура ПослеОбновленияСоставовГруппПользователей(УчастникиИзменений, ИзмененныеГруппы) Экспорт - - Параметры = Новый Структура; - Параметры.Вставить("Пользователи", УчастникиИзменений); - Параметры.Вставить("ГруппыПользователей", ИзмененныеГруппы); - - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); - - ОбновитьРолиПользователей(УчастникиИзменений); - - Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(УчастникиИзменений); - ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(ИзмененныеГруппы); - КонецЕсли; - -КонецПроцедуры - -// Доопределяет действия, необходимые после изменении объекта авторизации внешнего пользователя. -// -// Параметры: -// ОбъектыАвторизации - Массив из ОпределяемыйТип.ВнешнийПользователь - новый объект авторизации и -// старый объект авторизации (если есть). -// - Неопределено - все объекты авторизации. -// -Процедура ПослеИзмененияОбъектаАвторизацииВнешнегоПользователя(ОбъектыАвторизации) Экспорт - - Параметры = Новый Структура; - Параметры.Вставить("ОбъектыАвторизации", ОбъектыАвторизации); - - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); - -КонецПроцедуры - -// Выполняет копирование прав от одного пользователя другому. -Процедура ПриКопированииПравНовомуПользователю(Источник, Приемник) Экспорт - - Если ТранзакцияАктивна() - И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("Справочник.ГруппыДоступа"); - // АПК:1320-выкл - №499, №783.1.3 Допустимо вызывать блокировку во внешней транзакции для файловой ИБ. - // Требуется для предотвращения взаимоблокировки: ниже запрос, который ставит неявную - // разделяемую блокировку и далее блокировка усиливается до исключительной явным вызовом, - // что приводит к взаимоблокировке в некоторых случаях. - Блокировка.Заблокировать(); - // АПК:1320-вкл. - КонецЕсли; - - УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Пользователь", Источник); - - Если УпрощенныйИнтерфейс Тогда - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ГруппыДоступа.Профиль КАК Профиль - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ПО - | ГруппыДоступа.Пользователь = &Пользователь - | И ГруппыДоступаПользователи.Ссылка = ГруппыДоступа.Ссылка - | И ГруппыДоступаПользователи.Пользователь = &Пользователь"; - Иначе - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - |ГДЕ - | ГруппыДоступаПользователи.Пользователь = &Пользователь"; - КонецЕсли; - - РезультатЗапроса = Запрос.Выполнить(); - Если РезультатЗапроса.Пустой() Тогда - Возврат; - КонецЕсли; - - Выборка = РезультатЗапроса.Выбрать(); - - Если Не УпрощенныйИнтерфейс Тогда - Блокировка = Новый БлокировкаДанных(); - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.ИсточникДанных = РезультатЗапроса; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "ГруппаДоступа"); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Если УпрощенныйИнтерфейс Тогда - Пока Выборка.Следующий() Цикл - УправлениеДоступом.ВключитьОтключитьПрофильПользователя(Приемник, Выборка.Профиль, Истина, Источник); - КонецЦикла; - Иначе - Блокировка.Заблокировать(); - Пока Выборка.Следующий() Цикл - ГруппаДоступаОбъект = Выборка.ГруппаДоступа.ПолучитьОбъект(); // СправочникОбъект.ГруппыДоступа - Если ГруппаДоступаОбъект.Пользователи.Найти(Приемник, "Пользователь") = Неопределено Тогда - Строка = ГруппаДоступаОбъект.Пользователи.Добавить(); - Строка.Пользователь = Приемник; - ГруппаДоступаОбъект.Записать(); - КонецЕсли; - КонецЦикла; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Обработчики событий подсистемы ВариантыОтчетов. - -// См. ВариантыОтчетовПереопределяемый.НастроитьВариантыОтчетов. -Процедура ПриНастройкеВариантовОтчетов(Настройки) Экспорт - - МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов"); - МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПраваДоступа); - МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.АнализПравДоступа); - МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПраваРолей); - МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.УчастникиГруппДоступа); - -КонецПроцедуры - -// См. ВариантыОтчетовПереопределяемый.ПередДобавлениемКомандОтчетов. -Процедура ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка) Экспорт - - Отчеты.АнализПравДоступа.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); - Отчеты.ПраваРолей.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); - Отчеты.УчастникиГруппДоступа.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); - -КонецПроцедуры - -// Обработчики событий подсистемы РассылкаОтчетов. - -// См. РассылкаОтчетовПереопределяемый.ОпределитьИсключаемыеОтчеты -Процедура ПриОпределенииИсключаемыхОтчетов(ИсключаемыеОтчеты) Экспорт - - ИсключаемыеОтчеты.Добавить(Метаданные.Отчеты.ПраваДоступа); - -КонецПроцедуры - -// Обработчики событий подсистемы КонтрольВеденияУчета. - -// См. ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовИсключаемыхИзПроверки -Процедура ПриОпределенииОбъектовИсключаемыхИзПроверки(Объекты) Экспорт - ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(Объекты); -КонецПроцедуры - -// Обработчики событий подсистемы УправлениеДоступом. - -// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа. -Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт - - Списки.Вставить(Метаданные.Справочники.ПрофилиГруппДоступа, Истина); - Списки.Вставить(Метаданные.Справочники.ГруппыДоступа, Истина); - -КонецПроцедуры - -// Обработчики событий библиотеки ТехнологияСервиса. - -// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных -Процедура ПриРегистрацииОбработчиковВыгрузкиДанных(ТаблицаОбработчиков) Экспорт - - Обработчик = ТаблицаОбработчиков.Добавить(); - Обработчик.ОбъектМетаданных = Метаданные.Справочники.ПрофилиГруппДоступа; - Обработчик.Обработчик = Справочники.ПрофилиГруппДоступа; - Обработчик.ПередВыгрузкойОбъекта = Истина; - Обработчик.Версия = "1.0.0.1"; - - Обработчик = ТаблицаОбработчиков.Добавить(); - Обработчик.ОбъектМетаданных = Метаданные.Справочники.ГруппыДоступа; - Обработчик.Обработчик = Справочники.ГруппыДоступа; - Обработчик.ПередВыгрузкойОбъекта = Истина; - Обработчик.Версия = "1.0.0.1"; - - Обработчик = ТаблицаОбработчиков.Добавить(); - Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ЗначенияГруппДоступа; - Обработчик.Обработчик = РегистрыСведений.ЗначенияГруппДоступа; - Обработчик.ПередВыгрузкойОбъекта = Истина; - Обработчик.Версия = "1.0.0.1"; - - Обработчик = ТаблицаОбработчиков.Добавить(); - Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию; - Обработчик.Обработчик = РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию; - Обработчик.ПередВыгрузкойОбъекта = Истина; - Обработчик.Версия = "1.0.0.1"; - -КонецПроцедуры - -// Процедуры и функция для подсистемы Пользователи. - -Функция ТекстЗапросаГруппДоступаПриИзмененииУчастниковГруппПользователей() Экспорт - - Возврат - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | УчастникиГруппДоступа.Ссылка КАК ГруппаДоступа, - | УчастникиГруппДоступа.Пользователь КАК Участник, - | УчастникиГруппДоступа.СрокДействия КАК СрокДействия - |ПОМЕСТИТЬ УчастникиГруппДоступа - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа - | ЛЕВОЕ СОЕДИНЕНИЕ ИзмененияСоставов КАК ИзмененияСоставовГрупп - | ПО (ИзмененияСоставовГрупп.ГруппаПользователей = УчастникиГруппДоступа.Пользователь) - | ЛЕВОЕ СОЕДИНЕНИЕ ИзмененияСоставов КАК ИзмененияАктивностиПользователей - | ПО (ИзмененияАктивностиПользователей.Пользователь = УчастникиГруппДоступа.Пользователь) - | И (ИзмененияАктивностиПользователей.ГруппаПользователей = &ГруппаВсеПользователи) - |ГДЕ - | (НЕ ИзмененияСоставовГрупп.ГруппаПользователей ЕСТЬ NULL - | ИЛИ НЕ ИзмененияАктивностиПользователей.Пользователь ЕСТЬ NULL) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | УчастникиГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, - | УчастникиГруппДоступа.Участник КАК Участник, - | УчастникиГруппДоступа.СрокДействия КАК СрокДействия - |ИЗ - | УчастникиГруппДоступа КАК УчастникиГруппДоступа - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК ГруппаДоступа, - | ПРЕДСТАВЛЕНИЕ(ГруппыДоступа.Ссылка) КАК Представление, - | ГруппыДоступа.ПометкаУдаления КАК ПометкаУдаления, - | ГруппыДоступа.Профиль КАК Профиль, - | ПРЕДСТАВЛЕНИЕ(ГруппыДоступа.Профиль) КАК ПредставлениеПрофиля, - | ЕСТЬNULL(ГруппыДоступа.Профиль.ПометкаУдаления, ИСТИНА) КАК ПометкаУдаленияПрофиля - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Ссылка В - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | УчастникиГруппДоступа.ГруппаДоступа - | ИЗ - | УчастникиГруппДоступа КАК УчастникиГруппДоступа)"; - -КонецФункции - -// Процедуры и функции подсистемы ЦентрМониторинга. - -// Возвращает текст запроса для сбора статистической информации об использовании профилей групп доступа и ролей. -// -// Возвращаемое значение: -// Строка -// -Функция ТекстЗапросаИспользованияРолей() Экспорт - - Возврат - "ВЫБРАТЬ - | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, - | СведенияОПользователях.Пользователь КАК Пользователь, - | ВЫБОР - | КОГДА РАЗНОСТЬДАТ(СведенияОПользователях.ДатаПоследнейАктивности, &ТекущаяДата, ДЕНЬ) <= 7 - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ КАК АктивныхЗаНеделю, - | ВЫБОР - | КОГДА РАЗНОСТЬДАТ(СведенияОПользователях.ДатаПоследнейАктивности, &ТекущаяДата, ДЕНЬ) <= 30 - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ КАК АктивныхЗаМесяц - |ПОМЕСТИТЬ ВТСоставыГруппИАктивность - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОПользователях КАК СведенияОПользователях - | ПО СоставыГруппПользователей.Пользователь = СведенияОПользователях.Пользователь - |ГДЕ - | СоставыГруппПользователей.Используется - | И НЕ СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ = &ПустойУИД - | - |ИНДЕКСИРОВАТЬ ПО - | ГруппаПользователей, - | Пользователь - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ПрофилиГруппДоступа.Ссылка КАК Профиль, - | ПрофилиГруппДоступа.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, - | ПрофилиГруппДоступа.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен, - | ПрофилиГруппДоступа.Наименование КАК Наименование, - | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа, - | ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка) - | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = НЕОПРЕДЕЛЕНО КАК ОбщаяГруппаДоступа, - | ГруппыДоступаПользователи.Пользователь КАК ПользовательТЧ, - | СоставыГруппПользователей.Пользователь КАК ПользовательРС, - | СоставыГруппПользователей.АктивныхЗаНеделю КАК АктивныхЗаНеделю, - | СоставыГруппПользователей.АктивныхЗаМесяц КАК АктивныхЗаМесяц - |ПОМЕСТИТЬ ВТДанныеПрофилей - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТСоставыГруппИАктивность КАК СоставыГруппПользователей - | ПО ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа - | ПО (ПрофилиГруппДоступа.Ссылка = ГруппыДоступаПользователи.Ссылка.Профиль) - | И (НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления) - |ГДЕ - | НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления - | - |СГРУППИРОВАТЬ ПО - | ПрофилиГруппДоступа.Ссылка, - | ПрофилиГруппДоступа.Наименование, - | ГруппыДоступаПользователи.Пользователь, - | СоставыГруппПользователей.Пользователь, - | СоставыГруппПользователей.АктивныхЗаНеделю, - | СоставыГруппПользователей.АктивныхЗаМесяц, - | ГруппыДоступаПользователи.Ссылка, - | ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка) - | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = НЕОПРЕДЕЛЕНО, - | ПрофилиГруппДоступа.ИдентификаторПоставляемыхДанных, - | ПрофилиГруппДоступа.ПоставляемыйПрофильИзменен - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ВТДанныеПрофилей.Профиль КАК Профиль, - | ВТДанныеПрофилей.Наименование КАК Наименование, - | ВТДанныеПрофилей.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, - | ВТДанныеПрофилей.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен - |ПОМЕСТИТЬ Профили - |ИЗ - | ВТДанныеПрофилей КАК ВТДанныеПрофилей - | - |ИНДЕКСИРОВАТЬ ПО - | Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | Профили.Профиль КАК Профиль, - | СУММА(ВЫБОР - | КОГДА НЕ ПрофилиГруппДоступаВидыДоступа.ВидДоступа ЕСТЬ NULL - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК ВсегоВидовДоступа, - | СУММА(ВЫБОР - | КОГДА ЕСТЬNULL(ПрофилиГруппДоступаВидыДоступа.Предустановленный, ЛОЖЬ) - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК ПредустановленныхВидовДоступа - |ПОМЕСТИТЬ ВидыДоступа - |ИЗ - | Профили КАК Профили - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.ВидыДоступа КАК ПрофилиГруппДоступаВидыДоступа - | ПО Профили.Профиль = ПрофилиГруппДоступаВидыДоступа.Ссылка - | - |СГРУППИРОВАТЬ ПО - | Профили.Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | Вложенный.Профиль КАК Профиль, - | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Вложенный.ГруппаДоступа) КАК ГруппаДоступа, - | СУММА(ВЫБОР - | КОГДА НЕ Вложенный.ОбщаяГруппаДоступа - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК ПерсональнаяГруппа - |ПОМЕСТИТЬ ГруппыДоступа - |ИЗ - | (ВЫБРАТЬ - | ВТДанныеПрофилей.Профиль КАК Профиль, - | ВТДанныеПрофилей.ГруппаДоступа КАК ГруппаДоступа, - | ВТДанныеПрофилей.ОбщаяГруппаДоступа КАК ОбщаяГруппаДоступа - | ИЗ - | ВТДанныеПрофилей КАК ВТДанныеПрофилей - | - | СГРУППИРОВАТЬ ПО - | ВТДанныеПрофилей.Профиль, - | ВТДанныеПрофилей.ГруппаДоступа, - | ВТДанныеПрофилей.ОбщаяГруппаДоступа) КАК Вложенный - | - |СГРУППИРОВАТЬ ПО - | Вложенный.Профиль - | - |ИНДЕКСИРОВАТЬ ПО - | Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | Вложенный.Профиль КАК Профиль, - | СУММА(ВЫБОР - | КОГДА Вложенный.ПользовательТЧ ССЫЛКА Справочник.ГруппыПользователей - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК ГруппПользователей, - | СУММА(ВЫБОР - | КОГДА Вложенный.ПользовательТЧ ССЫЛКА Справочник.ГруппыВнешнихПользователей - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК ГруппВнешнихПользователей - |ПОМЕСТИТЬ ГруппыПользователей - |ИЗ - | (ВЫБРАТЬ - | ВТДанныеПрофилей.Профиль КАК Профиль, - | ВТДанныеПрофилей.ПользовательТЧ КАК ПользовательТЧ - | ИЗ - | ВТДанныеПрофилей КАК ВТДанныеПрофилей - | - | СГРУППИРОВАТЬ ПО - | ВТДанныеПрофилей.Профиль, - | ВТДанныеПрофилей.ПользовательТЧ) КАК Вложенный - | - |СГРУППИРОВАТЬ ПО - | Вложенный.Профиль - | - |ИНДЕКСИРОВАТЬ ПО - | Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | Вложенный.Профиль КАК Профиль, - | СУММА(ВЫБОР - | КОГДА Вложенный.ПользовательРС ССЫЛКА Справочник.Пользователи - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК Пользователи, - | СУММА(ВЫБОР - | КОГДА Вложенный.ПользовательРС ССЫЛКА Справочник.ВнешниеПользователи - | ТОГДА 1 - | ИНАЧЕ 0 - | КОНЕЦ) КАК ВнешниеПользователи, - | СУММА(Вложенный.АктивныхЗаНеделю) КАК АктивныхЗаНеделю, - | СУММА(Вложенный.АктивныхЗаМесяц) КАК АктивныхЗаМесяц - |ПОМЕСТИТЬ ПользователиПрофиля - |ИЗ - | (ВЫБРАТЬ - | ВТДанныеПрофилей.Профиль КАК Профиль, - | ВТДанныеПрофилей.ПользовательРС КАК ПользовательРС, - | СУММА(ВТДанныеПрофилей.АктивныхЗаНеделю) КАК АктивныхЗаНеделю, - | СУММА(ВТДанныеПрофилей.АктивныхЗаМесяц) КАК АктивныхЗаМесяц - | ИЗ - | ВТДанныеПрофилей КАК ВТДанныеПрофилей - | - | СГРУППИРОВАТЬ ПО - | ВТДанныеПрофилей.Профиль, - | ВТДанныеПрофилей.ПользовательРС) КАК Вложенный - | - |СГРУППИРОВАТЬ ПО - | Вложенный.Профиль - | - |ИНДЕКСИРОВАТЬ ПО - | Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | Профили.Профиль КАК Профиль, - | Профили.Наименование КАК Наименование, - | Профили.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, - | Профили.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен, - | ЕСТЬNULL(ГруппыДоступа.ГруппаДоступа, 0) КАК ГруппаДоступа, - | ЕСТЬNULL(ГруппыДоступа.ПерсональнаяГруппа, 0) КАК ПерсональнаяГруппа, - | ЕСТЬNULL(ГруппыПользователей.ГруппПользователей, 0) КАК ГруппПользователей, - | ЕСТЬNULL(ГруппыПользователей.ГруппВнешнихПользователей, 0) КАК ГруппВнешнихПользователей, - | ЕСТЬNULL(ПользователиПрофиля.Пользователи, 0) КАК Пользователи, - | ЕСТЬNULL(ПользователиПрофиля.ВнешниеПользователи, 0) КАК ВнешниеПользователи, - | ЕСТЬNULL(ПользователиПрофиля.АктивныхЗаНеделю, 0) КАК АктивныхЗаНеделю, - | ЕСТЬNULL(ПользователиПрофиля.АктивныхЗаМесяц, 0) КАК АктивныхЗаМесяц, - | ЕСТЬNULL(ВидыДоступа.ВсегоВидовДоступа, 0) КАК ВсегоВидовДоступа, - | ЕСТЬNULL(ВидыДоступа.ПредустановленныхВидовДоступа, 0) КАК ПредустановленныхВидовДоступа - |ИЗ - | Профили КАК Профили - | ЛЕВОЕ СОЕДИНЕНИЕ ПользователиПрофиля КАК ПользователиПрофиля - | ПО Профили.Профиль = ПользователиПрофиля.Профиль - | ЛЕВОЕ СОЕДИНЕНИЕ ГруппыПользователей КАК ГруппыПользователей - | ПО Профили.Профиль = ГруппыПользователей.Профиль - | ЛЕВОЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа - | ПО Профили.Профиль = ГруппыДоступа.Профиль - | ЛЕВОЕ СОЕДИНЕНИЕ ВидыДоступа КАК ВидыДоступа - | ПО Профили.Профиль = ВидыДоступа.Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | Профили.Профиль КАК Профиль, - | ЕСТЬNULL(ПрофилиГруппДоступаРоли.Роль.Имя, """") КАК РольИмя - |ИЗ - | Профили КАК Профили - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиГруппДоступаРоли - | ПО Профили.Профиль = ПрофилиГруппДоступаРоли.Ссылка - | И (Профили.ИдентификаторПоставляемыхДанных = &ПустойУИД - | ИЛИ Профили.ПоставляемыйПрофильИзменен) - | - |УПОРЯДОЧИТЬ ПО - | Профиль"; - -КонецФункции - -// Проверяет доступность общей команды НастроитьПрава. -// -// Возвращаемое значение: -// Булево -// -Функция ДоступнаКомандаНастройкиПрав() Экспорт - Возврат ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.НастроитьПрава); -КонецФункции - -#КонецОбласти - -#КонецОбласти - -#Область СлужебныеПроцедурыИФункции - -// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных. -Процедура ПередВыгрузкойОбъекта(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт - - // Роли расширений назначаются независимо в коробке и в сервисе. - Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда - Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширений(Объект); - КонецЕсли; - - // В модели сервиса право открытия внешних отчетов и обработок не используется для пользователей областей данных, - // поэтому проверка применяется только при переходе Коробка -> Сервис. - Если ОбщегоНазначения.РазделениеВключено() Тогда - Возврат; - КонецЕсли; - - Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда - Профиль = Объект; - - ИначеЕсли ТипЗнч(Объект) = Тип("СправочникОбъект.ГруппыДоступа") И Не Объект.ЭтоГруппа Тогда - Профиль = Объект.Профиль; - Иначе - Возврат; - КонецЕсли; - - Если ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(Профиль) Тогда - Отказ = Истина; - КонецЕсли; - -КонецПроцедуры - -// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных. -Процедура ПередВыгрузкойНабораЗаписей(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт - - // В модели сервиса право открытия внешних отчетов и обработок не используется для пользователей областей данных, - // поэтому проверка применяется только при переходе Коробка -> Сервис. - Если ОбщегоНазначения.РазделениеВключено() Тогда - Возврат; - КонецЕсли; - - ГруппыДоступа = ГруппыДоступаПрофиляОткрытиеВнешнихОтчетовИОбработок(); - - Индекс = Объект.Количество() - 1; - Пока Индекс >= 0 Цикл - Если ГруппыДоступа.Найти(Объект[Индекс].ГруппаДоступа) <> Неопределено Тогда - Объект.Удалить(Индекс); - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - -КонецПроцедуры - -// Параметры: -// ИмяПараметра - Строка -// УстановленныеПараметры - Массив из Строка -// -Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт - -#Область УниверсальноеОграничение - Если ИмяПараметра = "ПараметрыОграниченияДоступа" Тогда - ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(Новый Структура); - УстановленныеПараметры.Добавить("ПараметрыОграниченияДоступа"); - Возврат; - КонецЕсли; - - Если ИмяПараметра = "ОтключениеОбновленияКлючейДоступа" Тогда - ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа = НовоеОтключениеОбновленияКлючейДоступа(); - УстановленныеПараметры.Добавить("ОтключениеОбновленияКлючейДоступа"); - Возврат; - КонецЕсли; - - УниверсальноеОграничение = ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина, Ложь); - - Если ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально" - Или ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально <> УниверсальноеОграничение Тогда - - ПередИзменениемПараметровСеансаДляШаблонов( - Новый Структура("ОграничениеДоступаНаУровнеЗаписейУниверсально", УниверсальноеОграничение), - ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально"); - - ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально = УниверсальноеОграничение; - КонецЕсли; - - УстановленныеПараметры.Добавить("ОграничениеДоступаНаУровнеЗаписейУниверсально"); - Если ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально" Тогда - Возврат; - КонецЕсли; -#КонецОбласти - - // Для корректной работы препроцессора в ограничениях доступа, требуется инициализации всех - // параметров сеанса, которые могут быть востребованы в работе препроцессора. - ОграничиватьДоступНаУровнеЗаписей = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); - ИнформационнаяБазаЗаблокированаДляОбновления = ЗначениеЗаполнено( - ОбновлениеИнформационнойБазыСлужебный.ИнформационнаяБазаЗаблокированаДляОбновления(Ложь)); - -#Область УниверсальноеОграничение - Если Не ОграничиватьДоступНаУровнеЗаписей - Или Не УниверсальноеОграничение - Или ИнформационнаяБазаЗаблокированаДляОбновления Тогда - - ПараметрыСеанса.СпискиСОтключеннымОграничениемЧтения = - ?(ИнформационнаяБазаЗаблокированаДляОбновления - Или Не УниверсальноеОграничение, "Неопределено", "Все"); - - ПустойНаборГруппДоступа = Справочники.НаборыГруппДоступа.ПустаяСсылка(); - - ПараметрыСеанса.ВерсииШаблоновОграниченияДоступа = ВерсииШаблоновОграниченияДоступа(); - ПараметрыСеанса.РазрешенныйНаборГруппДоступа = ПустойНаборГруппДоступа; - ПараметрыСеанса.РазрешенныйПустойНаборГруппДоступа = ПустойНаборГруппДоступа; - ПараметрыСеанса.РазрешенныйНаборГруппПользователей = ПустойНаборГруппДоступа; - ПараметрыСеанса.РазрешенныйПользователь = ПустойНаборГруппДоступа; - ПараметрыСеанса.ОбщиеПараметрыШаблоновОграниченияДоступа = ""; - ПараметрыСеанса.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = ""; - ПараметрыСеанса.СпискиСОграничениемЧерезКлючиДоступаПользователей = ""; - ПараметрыСеанса.СпискиСОграничениемПоПолям = ""; - - УстановленныеПараметры.Добавить("СпискиСОтключеннымОграничениемЧтения"); - УстановленныеПараметры.Добавить("ВерсииШаблоновОграниченияДоступа"); - УстановленныеПараметры.Добавить("РазрешенныйНаборГруппДоступа"); - УстановленныеПараметры.Добавить("РазрешенныйПустойНаборГруппДоступа"); - УстановленныеПараметры.Добавить("РазрешенныйНаборГруппПользователей"); - УстановленныеПараметры.Добавить("РазрешенныйПользователь"); - УстановленныеПараметры.Добавить("ОбщиеПараметрыШаблоновОграниченияДоступа"); - УстановленныеПараметры.Добавить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа"); - УстановленныеПараметры.Добавить("СпискиСОграничениемЧерезКлючиДоступаПользователей"); - УстановленныеПараметры.Добавить("СпискиСОграничениемПоПолям"); - КонецЕсли; -#КонецОбласти - - Если Не ОграничиватьДоступНаУровнеЗаписей - Или УниверсальноеОграничение - Или ИнформационнаяБазаЗаблокированаДляОбновления Тогда - - ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейИспользуется = - ?(ИнформационнаяБазаЗаблокированаДляОбновления - Или УниверсальноеОграничение, "", Ложь); - - ПараметрыСеанса.ВсеВидыДоступаКромеСпециальных = ""; - ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием = ""; - ПараметрыСеанса.ВидыДоступаБезГруппДляЗначенияДоступа = ""; - ПараметрыСеанса.ВидыДоступаСОднойГруппойДляЗначенияДоступа = ""; - - ПараметрыСеанса.ТипыЗначенийДоступаСГруппами - = Новый ФиксированныйМассив(Новый Массив); - - ПараметрыСеанса.ТаблицыСОтдельнымиНастройкамиПрав = ""; - - ПараметрыСеанса.ИдентификаторыТаблицСОтдельнымиНастройкамиПрав - = Новый ФиксированныйМассив(Новый Массив); - - ПараметрыСеанса.ТипыВладельцевНастроекПрав - = Новый ФиксированныйМассив(Новый Массив); - - ПараметрыСеанса.ТаблицыРасширенийСОграничениемДоступа = ""; - - УстановленныеПараметры.Добавить("ОграничениеДоступаНаУровнеЗаписейИспользуется"); - УстановленныеПараметры.Добавить("ВсеВидыДоступаКромеСпециальных"); - УстановленныеПараметры.Добавить("ВидыДоступаСОтключеннымИспользованием"); - УстановленныеПараметры.Добавить("ВидыДоступаБезГруппДляЗначенияДоступа"); - УстановленныеПараметры.Добавить("ВидыДоступаСОднойГруппойДляЗначенияДоступа"); - УстановленныеПараметры.Добавить("ТипыЗначенийДоступаСГруппами"); - УстановленныеПараметры.Добавить("ТаблицыСОтдельнымиНастройкамиПрав"); - УстановленныеПараметры.Добавить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав"); - УстановленныеПараметры.Добавить("ТипыВладельцевНастроекПрав"); - УстановленныеПараметры.Добавить("ТаблицыРасширенийСОграничениемДоступа"); - КонецЕсли; - - Если ИнформационнаяБазаЗаблокированаДляОбновления Тогда - Возврат; - КонецЕсли; - -#Область УниверсальноеОграничение - Если УниверсальноеОграничение Тогда - ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь, Истина); - Возврат; - КонецЕсли; -#КонецОбласти - - Если Не ОграничиватьДоступНаУровнеЗаписей Тогда - Возврат; - КонецЕсли; - - ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейИспользуется = Истина; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.АвторизованныйПользователь()); - Запрос.Текст = - "ВЫБРАТЬ - | ЗначенияПоУмолчанию.ТипЗначенийДоступа КАК ТипЗначений - |ИЗ - | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ПО (ГруппыДоступаПользователи.Ссылка = ЗначенияПоУмолчанию.ГруппаДоступа) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) - | И (СоставыГруппПользователей.Пользователь = &ТекущийПользователь) - | - |СГРУППИРОВАТЬ ПО - | ЗначенияПоУмолчанию.ТипЗначенийДоступа - | - |ИМЕЮЩИЕ - | МИНИМУМ(ЗначенияПоУмолчанию.ВсеРазрешеныБезИсключений) = ИСТИНА"; - - ТипыЗначенийВсеРазрешеныБезИсключений = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ТипЗначений"); - - // Установка параметров ВсеВидыДоступаКромеСпециальных, ВидыДоступаСОтключеннымИспользованием. - ВсеВидыДоступаКромеСпециальных = Новый Массив; - ВидыДоступаСОтключеннымИспользованием = Новый Массив; - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); - - Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл - ВсеВидыДоступаКромеСпециальных.Добавить(СвойстваВидаДоступа.Имя); - - Если ИспользуемыеВидыДоступа.Получить(СвойстваВидаДоступа.Ссылка) = Неопределено - Или ТипыЗначенийВсеРазрешеныБезИсключений.Найти(СвойстваВидаДоступа.Ссылка) <> Неопределено Тогда - - ВидыДоступаСОтключеннымИспользованием.Добавить(СвойстваВидаДоступа.Имя); - КонецЕсли; - КонецЦикла; - - ПараметрыСеанса.ВсеВидыДоступаКромеСпециальных = ВсеКомбинацииВидовДоступа(ВсеВидыДоступаКромеСпециальных); - - УстановленныеПараметры.Добавить("ВсеВидыДоступаКромеСпециальных"); - - ВсеВидыДоступаКромеСпециальныхОтключены = (ВсеВидыДоступаКромеСпециальных.Количество() - = ВидыДоступаСОтключеннымИспользованием.Количество()); - - Если ВсеВидыДоступаКромеСпециальныхОтключены Тогда - ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием = "Все"; - Иначе - ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием - = ВсеКомбинацииВидовДоступа(ВидыДоступаСОтключеннымИспользованием); - КонецЕсли; - - УстановленныеПараметры.Добавить("ВидыДоступаСОтключеннымИспользованием"); - - // Установка параметров ВидыДоступаБезГруппДляЗначенияДоступа, - // ВидыДоступаСОднойГруппойДляЗначенияДоступа, ТипыЗначенийДоступаСГруппами. - ПараметрыСеанса.ВидыДоступаБезГруппДляЗначенияДоступа = - ВсеКомбинацииВидовДоступа(СвойстваВидовДоступа.БезГруппДляЗначенияДоступа); - ПараметрыСеанса.ВидыДоступаСОднойГруппойДляЗначенияДоступа = - ВсеКомбинацииВидовДоступа(СвойстваВидовДоступа.СОднойГруппойДляЗначенияДоступа); - - ТипыЗначенийДоступаСГруппами = Новый Массив; - Для каждого КлючИЗначение Из СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами Цикл - ТипыЗначенийДоступаСГруппами.Добавить(КлючИЗначение.Значение); - КонецЦикла; - ПараметрыСеанса.ТипыЗначенийДоступаСГруппами = Новый ФиксированныйМассив(ТипыЗначенийДоступаСГруппами); - - УстановленныеПараметры.Добавить("ВидыДоступаБезГруппДляЗначенияДоступа"); - УстановленныеПараметры.Добавить("ВидыДоступаСОднойГруппойДляЗначенияДоступа"); - УстановленныеПараметры.Добавить("ТипыЗначенийДоступаСГруппами"); - - // Установка параметров ТаблицыСОтдельнымиНастройкамиПрав, - // ИдентификаторыТаблицСОтдельнымиНастройкамиПрав, ТипыВладельцевНастроекПрав. - ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); - ОтдельныеТаблицы = ВозможныеПрава.ОтдельныеТаблицы; - ТаблицыСОтдельнымиНастройкамиПрав = ""; - ИдентификаторыТаблицСОтдельнымиНастройкамиПрав = Новый Массив; - Для каждого КлючИЗначение Из ОтдельныеТаблицы Цикл - ТаблицыСОтдельнымиНастройкамиПрав = ТаблицыСОтдельнымиНастройкамиПрав - + "|" + КлючИЗначение.Значение + ";" + Символы.ПС; - ИдентификаторыТаблицСОтдельнымиНастройкамиПрав.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - - ПараметрыСеанса.ТаблицыСОтдельнымиНастройкамиПрав = ТаблицыСОтдельнымиНастройкамиПрав; - - ПараметрыСеанса.ИдентификаторыТаблицСОтдельнымиНастройкамиПрав = - Новый ФиксированныйМассив(ИдентификаторыТаблицСОтдельнымиНастройкамиПрав); - - ПараметрыСеанса.ТипыВладельцевНастроекПрав = ВозможныеПрава.ТипыВладельцев; - - ПолныеИмена = Справочники.ИдентификаторыОбъектовРасширений.ПолныеИменаТаблицСДанными(); - ТаблицыРасширений = СтрСоединить(ПолныеИмена, ";" + Символы.ПС + "|"); - ТаблицыРасширений = ?(ТаблицыРасширений = "", "", "|" + ТаблицыРасширений + ";" + Символы.ПС); - - ПараметрыСеанса.ТаблицыРасширенийСОграничениемДоступа = ТаблицыРасширений; - - УстановленныеПараметры.Добавить("ТаблицыСОтдельнымиНастройкамиПрав"); - УстановленныеПараметры.Добавить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав"); - УстановленныеПараметры.Добавить("ТипыВладельцевНастроекПрав"); - УстановленныеПараметры.Добавить("ТаблицыРасширенийСОграничениемДоступа"); - -КонецПроцедуры - -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * Стандартное - Булево -// * Полное - Булево -// * ВложенныеОтключения - ФиксированныйМассив -// * ИзмененныеСписки - ХранилищеЗначения -// -Функция НовоеОтключениеОбновленияКлючейДоступа() Экспорт - - Свойства = Новый Структура; - Свойства.Вставить("Стандартное", Ложь); - Свойства.Вставить("Полное", Ложь); - Свойства.Вставить("ВложенныеОтключения", Новый ФиксированныйМассив(Новый Массив)); - Свойства.Вставить("ИзмененныеСписки", Новый ХранилищеЗначения(Новый Соответствие)); - - Возврат Новый ФиксированнаяСтруктура(Свойства); - -КонецФункции - -// Только для внутреннего использования. -Процедура ОбновитьПараметрыСеанса() Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - УстановленныеПараметры = Новый Массив; - УстановкаПараметровСеанса("", УстановленныеПараметры); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - ОбновитьПовторноИспользуемыеЗначения(); - -КонецПроцедуры - -// Проверка группы доступа Администраторы перед записью. -Процедура ПроверитьНаличиеПользователяИБВГруппеДоступаАдминистраторы(ПользователиГруппы, ОписаниеОшибки) Экспорт - - Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); - - // Проверка пустого списка пользователей ИБ в группе доступа Администраторы. - УстановитьПривилегированныйРежим(Истина); - НайденДействующийАдминистратор = Ложь; - - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - - Если Не ЗначениеЗаполнено(ОписаниеПользователя.Пользователь) - Или ТипЗнч(ОписаниеПользователя.Пользователь) <> Тип("СправочникСсылка.Пользователи") - И ТипЗнч(ОписаниеПользователя.Пользователь) <> Тип("СправочникСсылка.Пользователи") Тогда - Продолжить; - КонецЕсли; - - ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( - ОписаниеПользователя.Пользователь.ИдентификаторПользователяИБ); - - Если ПользовательИБ <> Неопределено - И Пользователи.ВходВПрограммуРазрешен(ПользовательИБ) Тогда - - НайденДействующийАдминистратор = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Если НЕ НайденДействующийАдминистратор Тогда - ОписаниеОшибки = - НСтр("ru = 'В группе доступа Администраторы - |должен быть хотя бы один пользователь, - |которому разрешен вход в приложение.'"); - КонецЕсли; - -КонецПроцедуры - -// См. УправлениеДоступом.ЕстьОграничениеТаблицыПоВидуДоступа -Функция ЕстьОграничениеТаблицыПоВидуДоступа(Таблица, ВидДоступа, ВсеВидыДоступа) Экспорт - - УстановитьПривилегированныйРежим(Истина); - - ВидыДоступаСОтключеннымИспользованием = ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием; - Если ВидыДоступаСОтключеннымИспользованием = "Все" - Или СтрНайти(ВидыДоступаСОтключеннымИспользованием, "," + ВидДоступа + ",") > 0 Тогда - Возврат Ложь; - КонецЕсли; - - МассивВидовДоступа = СтрРазделить(ВсеВидыДоступа, ",", Ложь); - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в функции %1 общего модуля %2.'"), - "ЕстьОграничениеТаблицыПоВидуДоступа", "УправлениеДоступом") - + Символы.ПС; - - СвойстваВидаДоступа = СвойстваВидовДоступа.ПоИменам.Получить(ВидДоступа); - Если СвойстваВидаДоступа = Неопределено Тогда - ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует вид доступа ""%1"", указанный в параметре %2.'"), - ВидДоступа, "ВидДоступа"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - ВидДоступаСсылка = СвойстваВидаДоступа.Ссылка; - - ВсеВидыДоступаТаблицыСОтключеннымИспользованием = Истина; - ИспользованиеВидовДоступа = Новый Соответствие; - ВидДоступаУказанВоВсехВидахДоступа = Ложь; - - Для Каждого ТекущийВидДоступа Из МассивВидовДоступа Цикл - ТекущийВидДоступа = СокрЛП(ТекущийВидДоступа); - СвойстваВидаДоступа = СвойстваВидовДоступа.ПоИменам.Получить(ТекущийВидДоступа); - Если СвойстваВидаДоступа = Неопределено Тогда - ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует вид доступа ""%1"", указанный в параметре - |%2: ""%3"".'"), - ТекущийВидДоступа, "ВсеВидыДоступа", ВсеВидыДоступа); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - Если СвойстваВидаДоступа.Имя = ВидДоступа Тогда - ВидДоступаУказанВоВсехВидахДоступа = Истина; - КонецЕсли; - Используется = СтрНайти(ВидыДоступаСОтключеннымИспользованием, "," + СвойстваВидаДоступа.Имя + ",") = 0; - ИспользованиеВидовДоступа.Вставить(СвойстваВидаДоступа.Ссылка, Используется); - Если Используется Тогда - ВсеВидыДоступаТаблицыСОтключеннымИспользованием = Ложь; - КонецЕсли; - КонецЦикла; - - Если Не ВидДоступаУказанВоВсехВидахДоступа Тогда - ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Вид доступа ""%1"", указанный в параметре %2 не существует в параметре - |%3: ""%4"".'"), - ВидДоступа, "ВидДоступа", "ВсеВидыДоступа", ВсеВидыДоступа); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - Если ВсеВидыДоступаТаблицыСОтключеннымИспользованием Тогда - Возврат Ложь; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИмяОсновнойТаблицыСписка", Таблица); - Запрос.УстановитьПараметр("АвторизованныйПользователь", Пользователи.АвторизованныйПользователь()); - - Запрос.Текст = ТекстЗапросаГруппДоступа(); - - ТекстЗапроса = - "ВЫБРАТЬ - | ЗначенияПоУмолчанию.ГруппаДоступа КАК ГруппаДоступа, - | ЗначенияПоУмолчанию.ТипЗначенийДоступа КАК ВидДоступа - |ИЗ - | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступаПользователя КАК ГруппыДоступаПользователя - | ПО ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступаПользователя.Ссылка - |ГДЕ - | НЕ ЗначенияПоУмолчанию.ВсеРазрешеныБезИсключений - | И ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО - | ГруппыДоступаПользователи.Ссылка = ЗначенияПоУмолчанию.ГруппаДоступа - | И ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей - | И СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь)"; - - ДобавитьЗапросВПакет(Запрос.Текст, ТекстЗапроса); - Выборка = Запрос.Выполнить().Выбрать(); - - НастроенныеВидыДоступаГруппДоступа = Новый Соответствие; - ЕстьГруппаДоступаСОграничениемПоВидуДоступа = Ложь; - - Пока Выборка.Следующий() Цикл - НастроенныеВидыДоступа = НастроенныеВидыДоступаГруппДоступа.Получить(Выборка.ГруппаДоступа); - Если НастроенныеВидыДоступа = Неопределено Тогда - НастроенныеВидыДоступа = Новый Соответствие; - НастроенныеВидыДоступаГруппДоступа.Вставить(Выборка.ГруппаДоступа, НастроенныеВидыДоступа); - КонецЕсли; - Если ИспользованиеВидовДоступа.Получить(Выборка.ВидДоступа) = Неопределено Тогда - Продолжить; - КонецЕсли; - НастроенныеВидыДоступа.Вставить(Выборка.ВидДоступа, Истина); - Если Выборка.ВидДоступа = ВидДоступаСсылка Тогда - ЕстьГруппаДоступаСОграничениемПоВидуДоступа = Истина; - КонецЕсли; - КонецЦикла; - - ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа = Ложь; - - Для Каждого ОписаниеГруппыДоступа Из НастроенныеВидыДоступаГруппДоступа Цикл - НастроенныеВидыДоступа = ОписаниеГруппыДоступа.Значение; - ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа = Истина; - Для Каждого ОписаниеИспользованияВидаДоступа Из ИспользованиеВидовДоступа Цикл - Если Не ОписаниеИспользованияВидаДоступа.Значение Тогда - Продолжить; // Не используется. - КонецЕсли; - Если НастроенныеВидыДоступа.Получить(ОписаниеИспользованияВидаДоступа.Ключ) = Неопределено Тогда - Продолжить; // ВсеРазрешеныБезИсключений или ограничения по виду доступа нет. - КонецЕсли; - ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа = Ложь; - Прервать; - КонецЦикла; - Если ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа Тогда - ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Если ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа Тогда - Возврат Ложь; - КонецЕсли; - - Возврат ЕстьГруппаДоступаСОграничениемПоВидуДоступа; - -КонецФункции - -// Параметры: -// Объекты - см. ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению.Объекты -// ПолноеИмяИзмерения - см. ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению.Объект -// ТребуемыеТипы - ОписаниеТипов -// УказанныеТипы - ОписаниеТипов -// -Процедура ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыеТипы, МетаданныеИзмерения) - - Если ТребуемыеТипы.Типы().Количество() = 0 Тогда - ЛишниеТипы = МетаданныеИзмерения.Тип; - Иначе - ЛишниеТипы = Новый ОписаниеТипов(МетаданныеИзмерения.Тип,, ТребуемыеТипы.Типы()); - КонецЕсли; - - Если ЛишниеТипы.Типы().Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ЧастиИмени = СтрРазделить(МетаданныеИзмерения.ПолноеИмя(), "."); - ЧастиИмени.Удалить(2); - - ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению(Объекты, - СтрСоединить(ЧастиИмени, "."), ЛишниеТипы); - -КонецПроцедуры - -#Область ОбработчикиПодписокНаСобытия - -// Обработчик подписки ОбновитьГруппыЗначенийДоступаПередЗаписью: -// - проверяет изменение родителя и готовит группы доступа, в которых -// нужно обновить значения доступа, выбранные с учетом иерархии. -// -Процедура ОбновитьГруппыЗначенийДоступаПередЗаписью(Знач Источник, Отказ) Экспорт - - // АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал. - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) - Или Источник.ОбменДанными.Загрузка - И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда - Возврат; - КонецЕсли; - - Если ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() - Или Не Источник.ОбменДанными.Загрузка Тогда - - Если Не ПропуститьПроверкуДоступа(Отказ, Источник) Тогда - УправлениеДоступом.УстановитьБлокировкуПередЗаписьюВФайловойИБ(, Истина); - КонецЕсли; - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - СтарыеЗначения = Новый Структура; - Если СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(ТипЗнч(Источник)) <> Неопределено Тогда - СтарыеЗначения.Вставить("Родитель", ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "Родитель")); - КонецЕсли; - Свойства = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипЗнч(Источник)); - Если Свойства <> Неопределено - И Свойства.ТипГруппЗначений <> Тип("Неопределено") - И ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() Тогда - - ИмяПоля = ?(Свойства.НесколькоГруппЗначений, "ГруппыДоступа", "ГруппаДоступа"); - Попытка - ЗначениеПоля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, ИмяПоля); - Исключение - ИменаТаблиц = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Источник.Метаданные().ПолноеИмя()); - ПоТипамСсылокДляОбновления = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления; - РегистрыСведений.ГруппыЗначенийДоступа.ПроверитьМетаданныеТаблиц(ИменаТаблиц, ПоТипамСсылокДляОбновления); - ВызватьИсключение; - КонецПопытки; - СтарыеЗначения.Вставить(ИмяПоля, ЗначениеПоля); - КонецЕсли; - Если ЗначениеЗаполнено(СтарыеЗначения) Тогда - Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомСтарыеЗначения", СтарыеЗначения); - КонецЕсли; - КонецЕсли; - // АПК:75-вкл - - Если Источник.ОбменДанными.Загрузка Тогда - Возврат; - КонецЕсли; - - Если Свойства <> Неопределено Тогда - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(Источник); - КонецЕсли; - -КонецПроцедуры - -// Обработчик подписки ОбновитьГруппыЗначенийДоступаПриЗаписи: -// - вызывает метод записи групп значений доступа в -// регистр сведений ГруппыЗначенийДоступа для требуемых объектов метаданных, -// - обновляет значения групп доступа, выбранные с учетом иерархии. -// -Процедура ОбновитьГруппыЗначенийДоступаПриЗаписи(Источник) Экспорт - - // АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал. - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) - Или Источник.ОбменДанными.Загрузка - И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда - Возврат; - КонецЕсли; - - Если ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() - И Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомСтарыеЗначения") Тогда - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеРазрешенныхЗначений(Источник, - Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - КонецЕсли; - // АПК:75-вкл - - Если Источник.ОбменДанными.Загрузка Тогда - Возврат; - КонецЕсли; - - Если Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомСтарыеЗначения") - И Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения.Свойство("Родитель") - И Источник.Родитель <> Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения.Родитель Тогда - - ГруппыДоступа = ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипЗнч(Источник.Ссылка)); - РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(ГруппыДоступа); - КонецЕсли; - -КонецПроцедуры - -// Обработчик подписки ОбновитьГруппыВладельцевНастроекПрав на событие ПередЗаписью: -// - вызывает метод записи иерархии владельцев настроек прав объектов в -// регистр сведений НаследованиеНастроекПравОбъектов для требуемых объектов метаданных. -// -Процедура ОбновитьГруппыВладельцевНастроекПрав(Знач Объект, Отказ) Экспорт - - Если Объект.ОбменДанными.Загрузка Тогда - Возврат; - КонецЕсли; - - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда - Возврат; - КонецЕсли; - - ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); - ВозможныеПраваПоТипам = ВозможныеПрава.ПоТипам; - - Если ВозможныеПраваПоТипам.Получить(ТипЗнч(Объект)) <> Неопределено Тогда - РегистрыСведений.НаследованиеНастроекПравОбъектов.ОбновитьДанныеРегистра(Объект); - КонецЕсли; - -КонецПроцедуры - -// Обработчик подписки ЗаписатьНаборыЗначенийДоступа на событие ПриЗаписи -// вызывает метод записи значений доступа объекта в РегистрСведений.НаборыЗначенийДоступа. -// Возможен случай использования подсистемы "УправлениеДоступом", когда -// указанной подписки не существует, если наборы значений доступа не применяются. -// -Процедура ЗаписатьНаборыЗначенийДоступаПриЗаписи(Знач Объект, Отказ) Экспорт - - // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, - // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. - // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная - // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. - Если Объект.ОбменДанными.Загрузка - И НЕ Объект.ДополнительныеСвойства.Свойство("ЗаписатьНаборыЗначенийДоступа") Тогда - - Возврат; - КонецЕсли; - - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда - Возврат; - КонецЕсли; - - ЗаписатьНаборыЗначенийДоступа(Объект, , Объект.ДополнительныеСвойства.Свойство( - "ЗаписьНаборовЗначенийДоступаПриОбновленииИБ")); - -КонецПроцедуры - -// Обработчик подписки ЗаписатьЗависимыеНаборыЗначенийДоступа события ПриЗаписи -// вызывает перезапись зависимых наборов значений доступа в регистре сведений НаборыЗначенийДоступа. -// -// Возможен случай использования подсистемы "УправлениеДоступом", когда -// указанной подписки не существует, если зависимые наборы значений доступа не применяются. -// -Процедура ЗаписатьЗависимыеНаборыЗначенийДоступаПриЗаписи(Знач Объект, Отказ) Экспорт - - // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, - // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. - // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная - // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. - Если Объект.ОбменДанными.Загрузка - И НЕ Объект.ДополнительныеСвойства.Свойство("ЗаписатьЗависимыеНаборыЗначенийДоступа") Тогда - - Возврат; - КонецЕсли; - - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда - Возврат; - КонецЕсли; - - ЗаписатьЗависимыеНаборыЗначенийДоступа(Объект, Объект.ДополнительныеСвойства.Свойство( - "ЗаписьНаборовЗначенийДоступаПриОбновленииИБ")); - -КонецПроцедуры - -// Обработчик подписок ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей* на событие ПередЗаписью -// вызывает заполнение значений доступа табличной части объекта НаборыЗначенийДоступа, -// когда для ограничения доступа к самому объекту используется шаблон #ПоНаборамЗначений. -// Возможен случай использования подсистемы Управление доступом, когда -// указанной подписки не существует, если для указанной цели наборы не применяются. -// -// Параметры: -// Источник - СправочникОбъект -// - ДокументОбъект -// - ПланВидовХарактеристикОбъект -// - ПланСчетовОбъект -// - ПланВидовРасчетаОбъект -// - БизнесПроцессОбъект -// - ЗадачаОбъект -// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередЗаписью. -// -// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. -// -// РежимЗаписи - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда тип параметра Источник - ДокументОбъект. -// -// РежимПроведения - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда тип параметра Источник - ДокументОбъект. -// -Процедура ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей(Источник, Отказ = Неопределено, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт - - // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, - // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. - // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная - // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. - Если Источник.ОбменДанными.Загрузка - И НЕ Источник.ДополнительныеСвойства.Свойство("ЗаписатьНаборыЗначенийДоступа") Тогда - Возврат; - КонецЕсли; - - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда - Возврат; - КонецЕсли; - - Если НЕ ( ПривилегированныйРежим() - И Источник.ДополнительныеСвойства.Свойство( - "НаборыЗначенийДоступаТабличнойЧастиЗаполнены")) Тогда - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() - И Не ПропуститьПроверкуДоступа(Отказ, Источник) Тогда - - Если Источник.ЭтоНовый() Тогда - ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); - Иначе - ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); - КонецЕсли; - КонецЕсли; - - Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Источник); - ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); - Источник.НаборыЗначенийДоступа.Загрузить(Таблица); - КонецЕсли; - -КонецПроцедуры - -#КонецОбласти - -#Область ОбработчикиРегламентныхЗаданий - -// Обработчик регламентного задания ЗаполнениеДанныхДляОграниченияДоступа. -Процедура ЗаполнениеДанныхДляОграниченияДоступаОбработчикЗадания() Экспорт - - ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания( - Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа); - - ЗаполнениеДанныхДляОграниченияДоступа(); - -КонецПроцедуры - -// Выполняет последовательное заполнение и обновление данных, необходимых для работы -// подсистемы УправленияДоступом в режиме ограничения доступа на уровне записей. -// -// При включенном режиме ограничения доступа на уровне записей заполняет наборы -// значений доступа. Заполнение выполняется частями при каждом запуске, пока все -// наборы значений доступа не будут заполнены. -// При отключении режима ограничения доступа на уровне записей наборы значений доступа -// (заполненные ранее) удаляются при перезаписи объектов, а не все сразу. -// Независимо от режима ограничения доступа на уровне записей обновляет кэш-реквизиты. -// После завершения всех обновлений и заполнений отключает использование регламентного задания. -// -// Сведения о состоянии работы записываются в журнал регистрации. -// -// Возможно вызывать программно, например, при обновлении информационной базы. -// Также для целей обновления есть форма Справочник.ГруппыДоступа.ОбновлениеДанныхОграниченияДоступа, -// с помощью которой можно сделать интерактивное обновление данных ограничения доступа -// при обновлении информационной базы. -// -Процедура ЗаполнениеДанныхДляОграниченияДоступа(КоличествоДанных = 0, ТолькоКэшРеквизиты = Ложь, ЕстьИзменения = Неопределено) Экспорт - - ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( - "УправлениеДоступомСлужебный.ЗаполнениеДанныхДляОграниченияДоступа"); - - УстановитьПривилегированныйРежим(Истина); - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами; - - Если Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() И НЕ ТолькоКэшРеквизиты Тогда - - // Заполнение групп значений доступа в регистре сведений ГруппыЗначенийДоступа. - Для Каждого ИмяТаблицы Из ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления Цикл - - Пока КоличествоДанных < 10000 Цикл - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1000 - | ТекущаяТаблица.Ссылка - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа - | ПО ТекущаяТаблица.Ссылка = ГруппыЗначенийДоступа.ЗначениеДоступа - | И (ГруппыЗначенийДоступа.ГруппаДанных = 0) - |ГДЕ - | ГруппыЗначенийДоступа.ЗначениеДоступа ЕСТЬ NULL"; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", ИмяТаблицы); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", ИмяТаблицы); - // @skip-check query-in-loop - Порционная обработка данных - Значения = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - Если Не ЗначениеЗаполнено(Значения) Тогда - Прервать; - КонецЕсли; - // @skip-check query-in-loop - Порционная обработка данных - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(Значения, ЕстьИзменения); - КоличествоДанных = КоличествоДанных + Значения.Количество(); - Если Значения.Количество() < 1000 Тогда - Прервать; - КонецЕсли; - КонецЦикла; - - Если КоличествоДанных < 10000 Тогда - Продолжить; - КонецЕсли; - - Прервать; - - КонецЦикла; - - Если КоличествоДанных < 10000 Тогда - // Обновление оставшихся неактуальных записей, если есть. - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьДанныеРегистра(ЕстьИзменения); - КонецЕсли; - - Если КоличествоДанных < 10000 И Не УправлениеДоступом.ПроизводительныйВариант() Тогда - - // Заполнение регистра сведений НаборыЗначенийДоступа. - ТипыОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( - "ЗаписатьНаборыЗначенийДоступа"); - - Для каждого ОписаниеТипа Из ТипыОбъектов Цикл - Тип = ОписаниеТипа.Ключ; - - Если КоличествоДанных < 10000 И Тип <> Тип("Строка") Тогда - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 10000 - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НаборыЗначенийДоступа КАК РегистрСведенийНаборыЗначенийДоступа - | ПО ТекущаяТаблица.Ссылка = РегистрСведенийНаборыЗначенийДоступа.Объект - |ГДЕ - | РегистрСведенийНаборыЗначенийДоступа.Объект ЕСТЬ NULL "; - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Метаданные.НайтиПоТипу(Тип).ПолноеИмя()); - // @skip-check query-in-loop - Порционная обработка данных - Выборка = Запрос.Выполнить().Выбрать(); - КоличествоДанных = КоличествоДанных + Выборка.Количество(); - - Пока Выборка.Следующий() Цикл - // @skip-check query-in-loop - Порционная обработка данных - ОбновитьНаборыЗначенийДоступа(Выборка.Ссылка, ЕстьИзменения); - КонецЦикла; - КонецЕсли; - КонецЦикла; - КонецЕсли; - КонецЕсли; - - // Обновление кэш-реквизитов в наборах значений доступа. - Если КоличествоДанных < 10000 И Не УправлениеДоступом.ПроизводительныйВариант() Тогда - - ТипыЗначенийДоступа = СвойстваВидовДоступа.ПоТипамЗначений; - ТипыЗначенийДоступаСГруппами = СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами; - - ТаблицаТиповЗначений = Новый ТаблицаЗначений; - ТаблицаТиповЗначений.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - Для каждого КлючИЗначение Из ТипыЗначенийДоступа Цикл - ТаблицаТиповЗначений.Добавить().ТипЗначений = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); - КонецЦикла; - - ТаблицаТиповЗначенийСГруппами = Новый ТаблицаЗначений; - ТаблицаТиповЗначенийСГруппами.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - Для каждого КлючИЗначение Из ТипыЗначенийДоступаСГруппами Цикл - ТаблицаТиповЗначенийСГруппами.Добавить().ТипЗначений = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); - КонецЦикла; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ТаблицаТиповЗначений", ТаблицаТиповЗначений); - Запрос.УстановитьПараметр("ТаблицаТиповЗначенийСГруппами", ТаблицаТиповЗначенийСГруппами); - Запрос.Текст = - "ВЫБРАТЬ - | ТаблицаТипов.ТипЗначений - |ПОМЕСТИТЬ ТаблицаТиповЗначений - |ИЗ - | &ТаблицаТиповЗначений КАК ТаблицаТипов - | - |ИНДЕКСИРОВАТЬ ПО - | ТаблицаТипов.ТипЗначений - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ТаблицаТипов.ТипЗначений - |ПОМЕСТИТЬ ТаблицаТиповЗначенийСГруппами - |ИЗ - | &ТаблицаТиповЗначенийСГруппами КАК ТаблицаТипов - | - |ИНДЕКСИРОВАТЬ ПО - | ТаблицаТипов.ТипЗначений - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 10000 - | НаборыЗначенийДоступа.Объект, - | НаборыЗначенийДоступа.НомерНабора, - | НаборыЗначенийДоступа.ЗначениеДоступа, - | НаборыЗначенийДоступа.Уточнение, - | НаборыЗначенийДоступа.Чтение, - | НаборыЗначенийДоступа.Изменение - |ИЗ - | РегистрСведений.НаборыЗначенийДоступа КАК НаборыЗначенийДоступа - |ГДЕ - | ВЫБОР - | КОГДА НаборыЗначенийДоступа.СтандартноеЗначение <> ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | ТаблицаТиповЗначений КАК ТаблицаТиповЗначений - | ГДЕ - | ТИПЗНАЧЕНИЯ(ТаблицаТиповЗначений.ТипЗначений) = ТИПЗНАЧЕНИЯ(НаборыЗначенийДоступа.ЗначениеДоступа)) - | ТОГДА ИСТИНА - | КОГДА НаборыЗначенийДоступа.СтандартноеЗначение = ИСТИНА - | ТОГДА НаборыЗначенийДоступа.ЗначениеБезГрупп = ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | ТаблицаТиповЗначенийСГруппами КАК ТаблицаТиповЗначенийСГруппами - | ГДЕ - | ТИПЗНАЧЕНИЯ(ТаблицаТиповЗначенийСГруппами.ТипЗначений) = ТИПЗНАЧЕНИЯ(НаборыЗначенийДоступа.ЗначениеДоступа)) - | ИНАЧЕ НаборыЗначенийДоступа.ЗначениеБезГрупп = ИСТИНА - | КОНЕЦ"; - Выборка = Запрос.Выполнить().Выбрать(); - КоличествоДанных = КоличествоДанных + Выборка.Количество(); - - Пока Выборка.Следующий() Цикл - МенеджерЗаписи = РегистрыСведений.НаборыЗначенийДоступа.СоздатьМенеджерЗаписи(); - ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка); - - ТипЗначенияДоступа = ТипЗнч(Выборка.ЗначениеДоступа); - - Если ТипыЗначенийДоступа.Получить(ТипЗначенияДоступа) <> Неопределено Тогда - МенеджерЗаписи.СтандартноеЗначение = Истина; - Если ТипыЗначенийДоступаСГруппами.Получить(ТипЗначенияДоступа) = Неопределено Тогда - МенеджерЗаписи.ЗначениеБезГрупп = Истина; - КонецЕсли; - КонецЕсли; - - МенеджерЗаписи.Записать(); - ЕстьИзменения = Истина; - КонецЦикла; - КонецЕсли; - - Если КоличествоДанных < 10000 Тогда - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, - , - , - НСтр("ru = 'Завершено заполнение данных для ограничения доступа.'"), - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - - УстановитьЗаполнениеДанныхДляОграниченияДоступа(Ложь); - Иначе - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, - , - , - НСтр("ru = 'Выполнена запись части данных для ограничения доступа.'"), - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - КонецЕсли; - -КонецПроцедуры - -// Устанавливает использование регламентного задания заполнения данных управления доступом. -// -// Параметры: -// Использование - Булево - Истина, если задание нужно включить, иначе Ложь. -// -Процедура УстановитьЗаполнениеДанныхДляОграниченияДоступа(Знач Использование) Экспорт - - РегламентныеЗаданияСервер.УстановитьИспользованиеПредопределенногоРегламентногоЗадания( - Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа, Использование); - -КонецПроцедуры - -#КонецОбласти - -#Область ПроцедурыИФункцииДляРаботыСВидамиДоступа - -// Возвращает Истина, если вид доступа включен по функциональным опциям для всех сеансов. -// -// Параметры: -// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. -// - Строка - имя вида доступа. -// -// Возвращаемое значение: -// Булево -// -Функция ВидДоступаИспользуется(Знач ВидДоступа) Экспорт - - Если Не УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда - Возврат Ложь; - КонецЕсли; - - СвойстваВидаДоступа = СвойстваВидаДоступа(ВидДоступа); - Если СвойстваВидаДоступа = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ТипЗначенийДоступа", СвойстваВидаДоступа.Ссылка); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа - |ГДЕ - | ИспользуемыеВидыДоступа.ТипЗначенийДоступа = &ТипЗначенийДоступа - | И ИспользуемыеВидыДоступа.Используется = ИСТИНА"; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Используется = Не Запрос.Выполнить().Пустой(); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - Возврат Используется; - -КонецФункции - -// Параметры: -// БезУчетаОграниченияДоступа - Булево -// -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. -// * Значение - Булево - значение Истина. -// -Функция ИспользуемыеВидыДоступа(БезУчетаОграниченияДоступа = Ложь) Экспорт - - Результат = Новый Соответствие; - - Если Не БезУчетаОграниченияДоступа - И Не УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда - Возврат Результат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | ИспользуемыеВидыДоступа.ТипЗначенийДоступа КАК ТипЗначенийДоступа - |ИЗ - | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа - |ГДЕ - | ИспользуемыеВидыДоступа.Используется = ИСТИНА"; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Выборка = Запрос.Выполнить().Выбрать(); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - Пока Выборка.Следующий() Цикл - Если СвойстваВидовДоступа.ПоСсылкам.Получить(Выборка.ТипЗначенийДоступа) = Неопределено Тогда - Продолжить; - КонецЕсли; - Результат.Вставить(Выборка.ТипЗначенийДоступа, Истина); - КонецЦикла; - - Возврат Результат; - -КонецФункции - -// Возвращает свойства вида доступа или всех видов доступа. -// -// Параметры: -// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. -// - Строка - имя вида доступа. -// -// Возвращаемое значение: -// Структура: -// * Имя - Строка -// * Ссылка - ОпределяемыйТип.ЗначениеДоступа -// * ТипЗначений - Тип -// * ТипГруппЗначений - Тип -// * НесколькоГруппЗначений - Булево -// * ДополнительныеТипы - ФиксированныйМассив из см. ДополнительныйТипВидаДоступа -// * ТипыВыбираемыхЗначений - ФиксированныйМассив из Тип -// Неопределено -// -Функция СвойстваВидаДоступа(ВидДоступа) Экспорт - - Свойства = СвойстваВидовДоступа(); - - Если ТипЗнч(ВидДоступа) = Тип("Строка") Тогда - СвойстваВидаДоступа = Свойства.ПоИменам.Получить(ВидДоступа); - Иначе - СвойстваВидаДоступа = Свойства.ПоСсылкам.Получить(ВидДоступа); - КонецЕсли; - - Возврат СвойстваВидаДоступа; - -КонецФункции - -#КонецОбласти - -#Область ПроцедурыИФункцииДляРаботыСНаборамиЗначенийДоступа - -// Возвращает новые наборы для заполнения табличной части. -// -// Параметры: -// Объект - ОпределяемыйТип.ВладелецСОграничениемПоНаборамЗначенийДоступаОбъект -// - ОпределяемыйТип.ВладелецСОграничениемПоНаборамЗначенийДоступаДокумент -// -// Возвращаемое значение: -// см. УправлениеДоступом.ТаблицаНаборыЗначенийДоступа -// -Функция ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект) - - ТипЗначенияОбъект = ТипЗнч(Объект); - - Если Объект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Неверные параметры. - |У объекта типа ""%1"" - |не существует табличная часть %2.'"), - ТипЗначенияОбъект, "НаборыЗначенийДоступа"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Таблица = УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(); - - Если НЕ УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда - Возврат Таблица; - КонецЕсли; - - УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(Объект, Таблица); - - УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( - Таблица, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); - - Возврат Таблица; - -КонецФункции - -// Выполняет обновление наборов значений доступа объекта, если они изменились. -// Наборы обновляются в табличной части (если используется) и -// в регистре сведений НаборыЗначенийДоступа. -// -// Параметры: -// СсылкаИлиОбъект - ЛюбаяСсылка -// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - ссылка или объект, -// для которого записываются наборы значений доступа. -// -// ЕстьИзменения - Булево -// - Неопределено -// -// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, -// не выполняя лишних, избыточных действий с данными. -// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. -// -Процедура ОбновитьНаборыЗначенийДоступа(СсылкаИлиОбъект, ЕстьИзменения = Неопределено, ОбновлениеИБ = Ложь) Экспорт - - УстановитьПривилегированныйРежим(Истина); - - Объект = ?(СсылкаИлиОбъект = СсылкаИлиОбъект.Ссылка, СсылкаИлиОбъект.ПолучитьОбъект(), СсылкаИлиОбъект); - СсылкаНаОбъект = Объект.Ссылка; - ТипЗначенияОбъект = ТипЗнч(Объект); - - НаборыЗаписываются = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( - "ЗаписатьНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; - - Если НЕ НаборыЗаписываются Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Неверные параметры. - |Тип объекта ""%1"" - |не существует в подписке на событие %2.'"), - ТипЗначенияОбъект, - "ЗаписатьНаборыЗначенийДоступа"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - Если Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип.Типы().Найти(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка при записи наборов значений доступа: - |в регистре сведений %1 в измерении %2 - |не задан тип ""%3""'"), - "НаборыЗначенийДоступа", - "Объект", - ТипЗнч(СсылкаНаОбъект)); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - Если СсылкаНаОбъект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") <> Неопределено Тогда - // Обновление объекта требуется. - Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект); - - Если НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаОбъект, Таблица) Тогда - ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); - - Объект.ДополнительныеСвойства.Вставить("ЗаписатьНаборыЗначенийДоступа"); - Объект.ДополнительныеСвойства.Вставить("ЗаписатьЗависимыеНаборыЗначенийДоступа"); - Объект.ДополнительныеСвойства.Вставить("НаборыЗначенийДоступаТабличнойЧастиЗаполнены"); - Объект.НаборыЗначенийДоступа.Загрузить(Таблица); - Если ОбновлениеИБ Тогда - Объект.ДополнительныеСвойства.Вставить("ЗаписьНаборовЗначенийДоступаПриОбновленииИБ"); - ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); - Иначе - Объект.ОбменДанными.Загрузка = Истина; - // АПК:1327-выкл - №783.1.4.1 Допустимо оставить запись без - // предварительной управляемой блокировки объекта, так как только - // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. - Объект.Записать(); - // АПК:1327-вкл. - КонецЕсли; - ЕстьИзменения = Истина; - КонецЕсли; - КонецЕсли; - - // Обновление объекта не требуется или объект уже обновлен. - ЗаписатьНаборыЗначенийДоступа(Объект, ЕстьИзменения, ОбновлениеИБ); - -КонецПроцедуры - -// Заполняет вспомогательные данные, ускоряющие работу шаблонов ограничений доступа. -// Выполняется перед записью в регистр НаборыЗначенийДоступа. -// -// Параметры: -// СсылкаНаОбъект - ЛюбаяСсылка - ссылка на объект для которого заполняются наборы значений доступа. -// Таблица - ТаблицаЗначений -// ДобавитьКэшРеквизиты - Булево -// -Процедура ПодготовитьНаборыЗначенийДоступаКЗаписи(СсылкаНаОбъект, Таблица, ДобавитьКэшРеквизиты = Ложь) Экспорт - - Если ДобавитьКэшРеквизиты Тогда - - Таблица.Колонки.Добавить("Объект", Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип); - Таблица.Колонки.Добавить("СтандартноеЗначение", Новый ОписаниеТипов("Булево")); - Таблица.Колонки.Добавить("ЗначениеБезГрупп", Новый ОписаниеТипов("Булево")); - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - ТипыЗначенийДоступаСГруппами = СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами; - ТипыЗначенийДоступа = СвойстваВидовДоступа.ПоТипамЗначений; - КонецЕсли; - - // Нормализация ресурсов Чтение, Изменение. - НомерНабора = -1; - Для каждого Строка Из Таблица Цикл - - Если ДобавитьКэшРеквизиты Тогда - // Установка значения измерения Объект. - Строка.Объект = СсылкаНаОбъект; - - ТипЗначенияДоступа = ТипЗнч(Строка.ЗначениеДоступа); - - Если ТипыЗначенийДоступа.Получить(ТипЗначенияДоступа) <> Неопределено Тогда - Строка.СтандартноеЗначение = Истина; - Если ТипыЗначенийДоступаСГруппами.Получить(ТипЗначенияДоступа) = Неопределено Тогда - Строка.ЗначениеБезГрупп = Истина; - КонецЕсли; - КонецЕсли; - - КонецЕсли; - - // Очистка флажков прав и соответствующих им вторичных данных - // для всех строк каждого набора, кроме первой строки. - Если НомерНабора = Строка.НомерНабора Тогда - Строка.Чтение = Ложь; - Строка.Изменение = Ложь; - Иначе - НомерНабора = Строка.НомерНабора; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -#КонецОбласти - -#Область ПроцедурыИФункцииДляДействийПриИзмененийНастроекПодсистемы - -// Если необходимо, включает заполнение данных для ограничения доступа и -// обновляет некоторые данные сразу. -// -// Вызывается из обработчика ПриЗаписи константы ОграничиватьДоступаНаУровнеЗаписей. -// -Процедура ПриИзмененииОграниченияДоступаНаУровнеЗаписей(ОграничениеДоступаНаУровнеЗаписейВключено) Экспорт - - УстановитьПривилегированныйРежим(Истина); - - РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(, Истина); - РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); - - Если ОграничениеДоступаНаУровнеЗаписейВключено Тогда - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, - , - , - НСтр("ru = 'Начато заполнение данных для ограничения доступа.'"), - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - - УстановитьЗаполнениеДанныхДляОграниченияДоступа(Истина); - КонецЕсли; - - Если ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина) Тогда - - ЗапланироватьОбновлениеПараметровОграниченияДоступа( - "ПриИзмененииОграниченияДоступаНаУровнеЗаписей"); - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); - ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; - ПараметрыПланирования.Описание = "ОграничиватьДоступНаУровнеЗаписейПриЗаписи"; - ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); - - УстановитьОбновлениеДоступа(Истина); - КонецЕсли; - - ОбновитьПараметрыСеанса(); - -КонецПроцедуры - -#КонецОбласти - -#Область ОбслуживаниеТаблицВидыДоступаИЗначенияДоступаВФормахРедактирования - -// Заполняет вспомогательные данные, требуемые для работы формы, -// которые не зависят от содержания объекта или заполняются для нового объекта. -// -// Форма должна содержать реквизиты, указанные ниже. -// Реквизиты отмеченные символом & заполняются автоматически, но их нужно создать в форме. -// Реквизиты отмеченные символом # должны быть созданы в форме, если -// в форме будет создан реквизит ТекущаяГруппаДоступа (см. ниже). -// Реквизиты отмеченные символом @ будут созданы автоматически. -// -// ТекущаяГруппаДоступа - необязательный реквизит, -// если не создан в форме, тогда не используется. -// -// ВидыДоступа - Таблица с полями: -// #ГруппаДоступа - СправочникСсылка.ГруппыДоступа, -// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, -// Предустановленный - Булево (только для профиля), -// ВсеРазрешены - Булево, -// &ВидДоступаПредставление - Строка - представление настройки, -// &ВсеРазрешеныПредставление - Строка - представление настройки, -// @Используется - Булево. -// -// ЗначенияДоступа - Таблица с полями: -// #ГруппаДоступа - СправочникСсылка.ГруппыДоступа, -// &ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, -// ЗначениеДоступа - ОпределяемыйТип.ЗначениеДоступа, -// &НомерСтрокиПоВиду - Число. -// -// &ИспользоватьВнешнихПользователей - Булево - реквизит будет создан, если нет в форме. -// &НадписьВидДоступа - Строка - представление текущего вида доступа в форме. -// @ЭтоПрофильГруппДоступа - Булево. -// @ТекущийВидДоступа - ОпределяемыйТип.ЗначениеДоступа. -// @ТекущиеТипыВыбираемыхЗначений - СписокЗначений. -// @ТекущийТипВыбираемыхЗначений - ОпределяемыйТип.ЗначениеДоступа. -// @ИмяРеквизитаХранилищаТаблиц - Строка. -// @ВидДоступаПользователи - ОпределяемыйТип.ЗначениеДоступа. -// @ВидДоступаВнешниеПользователи - ОпределяемыйТип.ЗначениеДоступа. -// -// @ВсеВидыДоступа - Таблица с полями: -// @Ссылка - ОпределяемыйТип.ЗначениеДоступа, -// @Представление - Строка, -// @Используется - Булево. -// -// @ПредставленияВсеРазрешены - Таблица с полями: -// @Имя - Строка, -// @Представление - Строка. -// -// @ВсеТипыВыбираемыхЗначений - Таблица с полями: -// @ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, -// @ТипЗначений - ОпределяемыйТип.ЗначениеДоступа, -// @ПредставлениеТипа - Строка, -// @ИмяТаблицы - Строка, -// @ИерархияЭлементов - Булево. -// -// Параметры: -// Форма - см. УправлениеДоступомСлужебныйКлиентСервер.ПараметрыФормыРедактированияРазрешенныхЗначений -// -// ЭтоПрофиль - Булево - указывает, что возможна настройка видов доступа -// в том числе представление настройки содержит 4 значения, а не 2. -// -// ИмяРеквизитаХранилищаТаблиц - Строка - содержащая, например, строку "Объект", которая -// содержит таблицы ВидыДоступа и ЗначенияДоступа (см. ниже). -// Если указана пустая строка, тогда считается, -// что таблицы хранятся в реквизитах формы. -// -Процедура ПриСозданииНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ЭтоПрофиль = Ложь, ИмяРеквизитаХранилищаТаблиц = "Объект") Экспорт - - ДобавитьРеквизитыВспомогательныхДанныхВФорму(Форма, ИмяРеквизитаХранилищаТаблиц); - - Форма.ИмяРеквизитаХранилищаТаблиц = ИмяРеквизитаХранилищаТаблиц; - Форма.ЭтоПрофильГруппДоступа = ЭтоПрофиль; - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - // Заполнение типов значений доступа всех видов доступа. - Для каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл - Для каждого Тип Из СвойстваВидаДоступа.ТипыВыбираемыхЗначений Цикл - МассивТипов = Новый Массив; - МассивТипов.Добавить(Тип); - ОписаниеТипа = Новый ОписаниеТипов(МассивТипов); - - МетаданныеТипа = Метаданные.НайтиПоТипу(Тип); - Если Метаданные.Перечисления.Найти(МетаданныеТипа.Имя) = МетаданныеТипа Тогда - ПредставлениеТипа = МетаданныеТипа.Представление(); - Иначе - ПредставлениеТипа = ?(ЗначениеЗаполнено(МетаданныеТипа.ПредставлениеОбъекта), - МетаданныеТипа.ПредставлениеОбъекта, - МетаданныеТипа.Представление()); - КонецЕсли; - - НоваяСтрока = Форма.ВсеТипыВыбираемыхЗначений.Добавить(); - НоваяСтрока.ВидДоступа = СвойстваВидаДоступа.Ссылка; - НоваяСтрока.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); - НоваяСтрока.ПредставлениеТипа = ПредставлениеТипа; - НоваяСтрока.ИмяТаблицы = МетаданныеТипа.ПолноеИмя(); - НоваяСтрока.ИерархияЭлементов = СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(Тип) <> Неопределено; - КонецЦикла; - КонецЦикла; - - Форма.ВидДоступаПользователи = Справочники.Пользователи.ПустаяСсылка(); - Форма.ВидДоступаВнешниеПользователи = Справочники.ВнешниеПользователи.ПустаяСсылка(); - Форма.ИспользоватьВнешнихПользователей = ВнешниеПользователи.ИспользоватьВнешнихПользователей(); - - ЗаполнитьТаблицуВсеВидыДоступаВФорме(Форма); - - ЗаполнитьТаблицуПредставленияВсеРазрешеныВФорме(Форма, ЭтоПрофиль); - - ОформитьТаблицуВидыДоступаВФорме(Форма); - - ОформитьТаблицуЗначенияДоступаВФорме(Форма); - - УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); - УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); - - ОбновитьОтображениеНеиспользуемыхВидовДоступа(Форма, Истина); - - // Настройка параметров выбора значения доступа. - ПараметрыВыбора = Новый Массив; - ПараметрыВыбора.Добавить(Новый ПараметрВыбора("ЭтоВыборЗначенияДоступа", Истина)); - Форма.Элементы.ЗначенияДоступаЗначениеДоступа.ПараметрыВыбора = Новый ФиксированныйМассив(ПараметрыВыбора); - -КонецПроцедуры - -// При повторном чтении заполняет или обновляет вспомогательные данные, -// требуемые для работы формы, которые зависят от содержания объекта. -// -Процедура ПриПовторномЧтенииНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект) Экспорт - - УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект); - УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); - - УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); - - УправлениеДоступомСлужебныйКлиентСервер.ПриИзмененииТекущегоВидаДоступа(Форма, Ложь); - -КонецПроцедуры - -// Удаляет лишние значения доступа перед записью. -// Лишние значения доступа могут появиться, если заменить или удалить вид доступа, -// для которого введены значения доступа. -// -Процедура ПередЗаписьюНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект) Экспорт - - УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект); - УдалитьЛишниеЗначенияДоступа(Форма); - -КонецПроцедуры - -// Обновляет свойства видов доступа. -Процедура ПослеЗаписиНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект, ПараметрыЗаписи) Экспорт - - УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект); - УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); - - УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); - -КонецПроцедуры - -// Скрывает или показывает неиспользуемые виды доступа. -Процедура ОбновитьОтображениеНеиспользуемыхВидовДоступа(Форма, ПриСозданииНаСервере = Ложь) Экспорт - - Элементы = Форма.Элементы; - - Если Не ПриСозданииНаСервере Тогда - Элементы.ПоказыватьНеИспользуемыеВидыДоступа.Пометка = - НЕ Элементы.ПоказыватьНеИспользуемыеВидыДоступа.Пометка; - КонецЕсли; - - Отбор = УправлениеДоступомСлужебныйКлиентСервер.ОтборВТаблицахФормыРедактированияРазрешенныхЗначений( - Форма); - - Если Не Элементы.ПоказыватьНеиспользуемыеВидыДоступа.Пометка Тогда - Отбор.Вставить("Используется", Истина); - КонецЕсли; - - Элементы.ВидыДоступа.ОтборСтрок = Новый ФиксированнаяСтруктура(Отбор); - - Элементы.ВидыДоступаВидДоступаПредставление.СписокВыбора.Очистить(); - - Для каждого Строка Из Форма.ВсеВидыДоступа Цикл - - Если Не Элементы.ПоказыватьНеиспользуемыеВидыДоступа.Пометка - И Не Строка.Используется Тогда - - Продолжить; - КонецЕсли; - - Элементы.ВидыДоступаВидДоступаПредставление.СписокВыбора.Добавить(Строка.Представление); - КонецЦикла; - -КонецПроцедуры - -#КонецОбласти - -#Область УниверсальныеПроцедурыИФункции - -// Только для внутреннего использования. -Процедура УстановитьУсловиеОтбораВЗапросе(Знач Запрос, Знач Значения, Знач ИмяПараметраЗначений, Знач ИмяПараметраУсловияОтбораИмяПоля) Экспорт - - Если Значения = Неопределено Тогда - - ИначеЕсли ТипЗнч(Значения) <> Тип("Массив") - И ТипЗнч(Значения) <> Тип("ФиксированныйМассив") Тогда - - Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения); - - ИначеЕсли Значения.Количество() = 1 Тогда - Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения[0]); - Иначе - Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения); - КонецЕсли; - - Для НомерСтроки = 1 По СтрЧислоСтрок(ИмяПараметраУсловияОтбораИмяПоля) Цикл - ТекущаяСтрока = СтрПолучитьСтроку(ИмяПараметраУсловияОтбораИмяПоля, НомерСтроки); - Если НЕ ЗначениеЗаполнено(ТекущаяСтрока) Тогда - Продолжить; - КонецЕсли; - ИндексРазделителя = СтрНайти(ТекущаяСтрока, ":"); - Если ИндексРазделителя = 0 Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка при выполнении процедуры %1. - | - |В параметре %2 не существует разделитель (двоеточие) - |в следующей строке формата ""%3"" - |""%4"".'"), - "УправлениеДоступом.УстановитьУсловиеОтбораВЗапросе", - "ИмяПараметраУсловияОтбораИмяПоля", - "<ИмяПараметраУсловия>:<ИмяПоля>", - ТекущаяСтрока); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - ИмяПараметраУсловияОтбора = Лев(ТекущаяСтрока, ИндексРазделителя-1); - ИмяПоля = Сред(ТекущаяСтрока, ИндексРазделителя+1); - Если Значения = Неопределено Тогда - УсловиеОтбора = "Истина"; - - ИначеЕсли ТипЗнч(Значения) <> Тип("Массив") - И ТипЗнч(Значения) <> Тип("ФиксированныйМассив") Тогда - - УсловиеОтбора = ИмяПоля + " = &" + ИмяПараметраЗначений; - - ИначеЕсли Значения.Количество() = 1 Тогда - УсловиеОтбора = ИмяПоля + " = &" + ИмяПараметраЗначений; - Иначе - УсловиеОтбора = ИмяПоля + " В (&" + ИмяПараметраЗначений + ")"; - КонецЕсли; - Запрос.Текст = СтрЗаменить(Запрос.Текст, ИмяПараметраУсловияОтбора, УсловиеОтбора); - КонецЦикла; - -КонецПроцедуры - -// Обновляет набор записей в базе данных, -// если записи набора отличаются от записей в базе данных. -// -// Параметры: -// Данные - Структура: -// * НаборЗаписей - РегистрСведенийНаборЗаписей - пустой или прочитанный с заданным отбором или без. -// - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. -// -// * НовыеЗаписи - ТаблицаЗначений - в формате регистра. -// -// * ПоляСравнения - Строка - содержит список полей по значениям которых требуется вычислять -// отличие записей набора. Например, "Измерение1, Измерение2, Ресурс1", -// а реквизит ДатаИзмерения не входит в список. -// -// * ПолеОтбора - Неопределено - записывается весь регистр или -// отбор уже задан в наборе записей. -// Строка - имя поля по которому нужно установить отбор. -// -// * ЗначениеОтбора - Отбор - значение, которое будет установлено в качестве отбора -// по полю отбора, если поле отбора задано. -// -// * НаборЗаписейПрочитан - Булево - если Истина, тогда не заданный набор записей уже содержит -// прочитанные записи блокировка данных этих записей установлена и -// транзакция открыта. -// -// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, -// а лишь выявить необходимость записи и установить -// свойство ЕстьИзменения. -// -// * ДополнительныеСвойства - Структура -// - Неопределено - если Структура, тогда в -// объекты <Регистр*>НаборЗаписей в свойство ДополнительныеСвойства -// будут вставлены все параметры структуры. -// -// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, -// не выполняя лишних, избыточных действий с данными. -// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. -// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций -// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления -// общего модуля ОбновлениеИнформационнойБазы. -// -// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, -// устанавливается Истина, иначе не изменяется. -// -// ИзмененныеЗаписи - Неопределено - никаких действий, иначе -// возвращает таблицу значений в формате регистра с полем ВидИзмененияСтроки -// типа Число (-1 запись удалена, 1 запись добавлена). -// -Процедура ОбновитьНаборЗаписей(Знач Данные, ЕстьИзменения = Неопределено, ИзмененныеЗаписи = Неопределено) Экспорт - - ВсеПараметры = Новый Структура; - ВсеПараметры.Вставить("НаборЗаписей"); - ВсеПараметры.Вставить("НовыеЗаписи"); - ВсеПараметры.Вставить("ПоляСравнения"); - ВсеПараметры.Вставить("ПолеОтбора"); - ВсеПараметры.Вставить("ЗначениеОтбора"); - ВсеПараметры.Вставить("НаборЗаписейПрочитан", Ложь); - ВсеПараметры.Вставить("БезПерезаписи", Ложь); - ВсеПараметры.Вставить("ТолькоПроверка", Ложь); - ВсеПараметры.Вставить("ДополнительныеСвойства"); - ВсеПараметры.Вставить("ОбновлениеИБ", - ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() - Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); - - ЗаполнитьПараметры(Данные, ВсеПараметры, "НаборЗаписей, НовыеЗаписи"); - - ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(Данные.НаборЗаписей)).ПолноеИмя(); - МенеджерРегистра = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяРегистра); - Если Данные.НаборЗаписей = МенеджерРегистра Тогда - НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей(); // РегистрСведенийНаборЗаписей - Иначе - НаборЗаписей = Данные.НаборЗаписей; // РегистрСведенийНаборЗаписей - КонецЕсли; - НовыеЗаписи = Данные.НовыеЗаписи; - ПолеОтбора = Данные.ПолеОтбора; - ЗначениеОтбора = Данные.ЗначениеОтбора; - - Если ЗначениеЗаполнено(ПолеОтбора) Тогда - УстановитьОтбор(НаборЗаписей.Отбор[ПолеОтбора], ЗначениеОтбора); - КонецЕсли; - - Если НЕ Данные.НаборЗаписейПрочитан Тогда - ЗаблокироватьОбластьНабораЗаписей(НаборЗаписей, ПолноеИмяРегистра); - НаборЗаписей.Прочитать(); - КонецЕсли; - - Данные.ПоляСравнения = ?(Данные.ПоляСравнения = Неопределено, - ПоляНабораЗаписей(НаборЗаписей), Данные.ПоляСравнения); - - Если Данные.БезПерезаписи Тогда - НаборЗаписи = МенеджерРегистра.СоздатьНаборЗаписей(); - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); - ОтборЗаписи = Новый Структура(ОписаниеКлючаЗаписи.СписокПолей); - ПоляОстальныхИзмерений = Новый Массив; - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - Если ОписаниеПоля.Имя <> ПолеОтбора Тогда - ПоляОстальныхИзмерений.Добавить(ОписаниеПоля.Имя); - КонецЕсли; - КонецЦикла; - УдаляемыеЗаписи = Новый ТаблицаЗначений; - Для каждого Поле Из ПоляОстальныхИзмерений Цикл - УдаляемыеЗаписи.Колонки.Добавить(Поле); - КонецЦикла; - Данные.НовыеЗаписи = НовыеЗаписи.Скопировать(); - НовыеЗаписи = Данные.НовыеЗаписи; - КонецЕсли; - - ЕстьТекущиеИзменения = Ложь; - Если ИзмененныеЗаписи = Неопределено Тогда - Если НаборЗаписей.Количество() = НовыеЗаписи.Количество() ИЛИ Данные.БезПерезаписи Тогда - Отбор = Новый Структура(Данные.ПоляСравнения); - НовыеЗаписи.Индексы.Добавить(Данные.ПоляСравнения); - Для Каждого Запись Из НаборЗаписей Цикл - ЗаполнитьЗначенияСвойств(Отбор, Запись); - НайденныеСтроки = НовыеЗаписи.НайтиСтроки(Отбор); - Если НайденныеСтроки.Количество() = 0 Тогда - ЕстьТекущиеИзменения = Истина; - ЕстьИзменения = Истина; - Если Данные.БезПерезаписи Тогда - ЗаполнитьЗначенияСвойств(ОтборЗаписи, Запись); - Если НовыеЗаписи.НайтиСтроки(ОтборЗаписи).Количество() = 0 Тогда - ЗаполнитьЗначенияСвойств(УдаляемыеЗаписи.Добавить(), ОтборЗаписи); - КонецЕсли; - Иначе - Прервать; - КонецЕсли; - ИначеЕсли Данные.БезПерезаписи Тогда - НовыеЗаписи.Удалить(НайденныеСтроки[0]); - КонецЕсли; - КонецЦикла; - Если Данные.БезПерезаписи И НовыеЗаписи.Количество() > 0 Тогда - ЕстьТекущиеИзменения = Истина; - ЕстьИзменения = Истина; - КонецЕсли; - Иначе - ЕстьТекущиеИзменения = Истина; - ЕстьИзменения = Истина; - КонецЕсли; - Иначе - Если НаборЗаписей.Количество() <> НовыеЗаписи.Количество() Тогда - ЕстьТекущиеИзменения = Истина; - ЕстьИзменения = Истина; - КонецЕсли; - Если НаборЗаписей.Количество() > НовыеЗаписи.Количество() Тогда - ИзмененныеЗаписи = НаборЗаписей.Выгрузить(); - ИскомыеЗаписи = НовыеЗаписи; - ВидИзмененияСтроки = -1; - Иначе - ИзмененныеЗаписи = НовыеЗаписи.Скопировать(); - ИскомыеЗаписи = НаборЗаписей.Выгрузить(); - ВидИзмененияСтроки = 1; - КонецЕсли; - ИзмененныеЗаписи.Колонки.Добавить("ВидИзмененияСтроки", Новый ОписаниеТипов("Число")); - ИзмененныеЗаписи.ЗаполнитьЗначения(ВидИзмененияСтроки, "ВидИзмененияСтроки"); - ВидИзмененияСтроки = ?(ВидИзмененияСтроки = 1, -1, 1); - Отбор = Новый Структура(Данные.ПоляСравнения); - - Для каждого Строка Из ИскомыеЗаписи Цикл - ЗаполнитьЗначенияСвойств(Отбор, Строка); - Строки = ИзмененныеЗаписи.НайтиСтроки(Отбор); - Если Строки.Количество() = 0 Тогда - НоваяСтрока = ИзмененныеЗаписи.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, Отбор); - НоваяСтрока.ВидИзмененияСтроки = ВидИзмененияСтроки; - ЕстьТекущиеИзменения = Истина; - ЕстьИзменения = Истина; - Иначе - ИзмененныеЗаписи.Удалить(Строки[0]); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Если ЕстьТекущиеИзменения Тогда - Если Данные.ТолькоПроверка Тогда - Возврат; - КонецЕсли; - Если Данные.БезПерезаписи Тогда - УстановитьДополнительныеСвойства(НаборЗаписи, Данные.ДополнительныеСвойства); - Для каждого Строка Из УдаляемыеЗаписи Цикл - Если ЗначениеЗаполнено(ПолеОтбора) Тогда - УстановитьОтбор(НаборЗаписи.Отбор[ПолеОтбора], ЗначениеОтбора); - КонецЕсли; - Для каждого Поле Из ПоляОстальныхИзмерений Цикл - УстановитьОтбор(НаборЗаписи.Отбор[Поле], Строка[Поле]); - КонецЦикла; - ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписи); - КонецЦикла; - НаборЗаписи.Добавить(); - Для каждого Строка Из НовыеЗаписи Цикл - Если ЗначениеЗаполнено(ПолеОтбора) Тогда - УстановитьОтбор(НаборЗаписи.Отбор[ПолеОтбора], ЗначениеОтбора); - КонецЕсли; - Для каждого Поле Из ПоляОстальныхИзмерений Цикл - УстановитьОтбор(НаборЗаписи.Отбор[Поле], Строка[Поле]); - КонецЦикла; - ЗаполнитьЗначенияСвойств(НаборЗаписи[0], Строка); - ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписи); - КонецЦикла; - Иначе - УстановитьДополнительныеСвойства(НаборЗаписей, Данные.ДополнительныеСвойства); - НаборЗаписей.Загрузить(НовыеЗаписи); - ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписей); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Обновляет строки регистра с отбором по нескольким значениям для одного или -// для двух измерений регистра, выполняется проверка наличия изменений, -// если изменений нет, перезапись не производится. -// -// Параметры: -// Данные - Структура: -// * МенеджерРегистра - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. -// -// * НовыеЗаписи - ТаблицаЗначений - в формате регистра. -// -// * ПоляСравнения - Строка - содержит список полей по значениям которых требуется -// вычислять отличие записей набора, например, "Измерение1, Измерение2, -// Ресурс1", а реквизит ДатаИзменения не входит в список. -// -// * ИмяПервогоИзмерения - Неопределено - нет отбора по измерению. -// - Строка - содержит имя первого измерения, для которого задано -// несколько значений. -// -// * ЗначенияПервогоИзмерения - Неопределено - нет отбора по измерению, аналогично, -// ИмяПервогоИзмерения = Неопределено. -// - ЛюбаяСсылка - содержит одно значение отбора регистра для -// обновляемых записей. -// - Массив - содержит массив значений отбора регистра для -// обновляемых записей, пустой массив - значит -// действий не требуется. -// -// * ИмяВторогоИзмерения - Неопределено -// - Строка - аналогично ИмяПервогоИзмерения. -// * ЗначенияВторогоИзмерения - Неопределено -// - ЛюбаяСсылка -// - Массив - аналогично ЗначенияПервогоИзмерения. -// * ИмяТретьегоИзмерения - Неопределено -// - Строка - аналогично ИмяПервогоИзмерения. -// * ЗначенияТретьегоИзмерения - Неопределено -// - ЛюбаяСсылка -// - Массив - аналогично ЗначенияПервогоИзмерения. -// -// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, -// а лишь выявить необходимость записи и установить -// свойство ЕстьИзменения. -// -// * ДополнительныеСвойства - Неопределено -// - Структура - если Структура, тогда в -// объекты <Регистр*>НаборЗаписей в свойство -// ДополнительныеСвойства будут вставлены все параметры структуры. -// -// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, -// не выполняя лишних, избыточных действий с данными. -// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. -// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций -// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления -// общего модуля ОбновлениеИнформационнойБазы. -// -// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, -// устанавливается Истина, иначе не изменяется. -// -Процедура ОбновитьНаборыЗаписей(Знач Данные, ЕстьИзменения) - - ВсеПараметры = Новый Структура; - ВсеПараметры.Вставить("МенеджерРегистра"); - ВсеПараметры.Вставить("НовыеЗаписи"); - ВсеПараметры.Вставить("ПоляСравнения"); - ВсеПараметры.Вставить("ИмяПервогоИзмерения"); - ВсеПараметры.Вставить("ЗначенияПервогоИзмерения"); - ВсеПараметры.Вставить("ИмяВторогоИзмерения"); - ВсеПараметры.Вставить("ЗначенияВторогоИзмерения"); - ВсеПараметры.Вставить("ИмяТретьегоИзмерения"); - ВсеПараметры.Вставить("ЗначенияТретьегоИзмерения"); - ВсеПараметры.Вставить("НовыеЗаписиСодержатТолькоРазличия", Ложь); - ВсеПараметры.Вставить("ФиксированныйОтбор"); - ВсеПараметры.Вставить("ТолькоПроверка", Ложь); - ВсеПараметры.Вставить("ДополнительныеСвойства"); - ВсеПараметры.Вставить("ОбновлениеИБ", - ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() - Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); - - ЗаполнитьПараметры(Данные, ВсеПараметры, "МенеджерРегистра, НовыеЗаписи"); - - // Предварительная обработка параметров. - - Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяПервогоИзмерения, Данные.ЗначенияПервогоИзмерения) Тогда - ЕстьИзменения = Истина; - Возврат; - КонецЕсли; - Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяВторогоИзмерения, Данные.ЗначенияВторогоИзмерения) Тогда - ЕстьИзменения = Истина; - Возврат; - КонецЕсли; - Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяТретьегоИзмерения, Данные.ЗначенияТретьегоИзмерения) Тогда - ЕстьИзменения = Истина; - Возврат; - КонецЕсли; - - УпорядочитьГруппыПараметровИзмерений(Данные); - - // Проверка и обновление данных. - Данные.Вставить("НаборЗаписей", Данные.МенеджерРегистра.СоздатьНаборЗаписей()); - Данные.Вставить("МетаданныеРегистра", Метаданные.НайтиПоТипу(ТипЗнч(Данные.НаборЗаписей))); - Данные.Вставить("ПолноеИмяРегистра", Данные.МетаданныеРегистра.ПолноеИмя()); - - Если Данные.НовыеЗаписиСодержатТолькоРазличия Тогда - Данные.Вставить("НаборДляОднойЗаписи", Данные.МенеджерРегистра.СоздатьНаборЗаписей()); - КонецЕсли; - - Если Данные.ФиксированныйОтбор <> Неопределено Тогда - Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл - УстановитьОтбор(Данные.НаборЗаписей.Отбор[КлючИЗначение.Ключ], КлючИЗначение.Значение); - КонецЦикла; - КонецЕсли; - - Если Данные.НовыеЗаписиСодержатТолькоРазличия Тогда - - Если Данные.ИмяПервогоИзмерения = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректные параметры в процедуре %1.'"), - "ОбновитьНаборыЗаписей"); - ВызватьИсключение ТекстОшибки; - Иначе - Если Данные.ИмяВторогоИзмерения = Неопределено Тогда - ЗаписьНесколькимиНаборами = Ложь; - Иначе - ЗаписьНесколькимиНаборами = ЗаписьНесколькимиНаборами(Данные, - Новый Структура, Данные.ИмяПервогоИзмерения, Данные.ЗначенияПервогоИзмерения); - КонецЕсли; - - Если ЗаписьНесколькимиНаборами Тогда - СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения; - Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); - - КоличествоПоЗначениямПервогоИзмерения = Данные.КоличествоПоЗначениям; - - Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл - Отбор = Новый Структура(Данные.ИмяПервогоИзмерения, ПервоеЗначение); - УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); - - Если Данные.ИмяТретьегоИзмерения = Неопределено Тогда - ЗаписьНесколькимиНаборами = Ложь; - Иначе - // @skip-check query-in-loop - Порционная обработка данных - ЗаписьНесколькимиНаборами = ЗаписьНесколькимиНаборами(Данные, - Отбор, Данные.ИмяВторогоИзмерения, Данные.ЗначенияВторогоИзмерения); - КонецЕсли; - - Если ЗаписьНесколькимиНаборами Тогда - Для каждого ВтороеЗначение Из Данные.ЗначенияВторогоИзмерения Цикл - Отбор.Вставить(Данные.ИмяВторогоИзмерения, ВтороеЗначение); - УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения], ВтороеЗначение); - - // Обновление по трем измерениям. - ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Отбор, ЕстьИзменения); - КонецЦикла; - Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения].Использование = Ложь; - Иначе - // Обновление по двум измерениям. - Данные.Вставить("КоличествоПоЗначениям", КоличествоПоЗначениямПервогоИзмерения); - ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Отбор, ЕстьИзменения); - КонецЕсли; - КонецЦикла; - Иначе - // Обновление по одному измерению. - ПрочитатьКоличествоДляЧтения(Данные); - ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Новый Структура, ЕстьИзменения); - КонецЕсли; - КонецЕсли; - Иначе - Если Данные.ИмяПервогоИзмерения = Неопределено Тогда - // Обновление всех записей. - - ТекущиеДанные = Новый Структура("НаборЗаписей, НовыеЗаписи, ПоляСравнения, - |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); - ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); - ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); - - ИначеЕсли Данные.ИмяВторогоИзмерения = Неопределено Тогда - // Обновление по одному измерению. - Отбор = Новый Структура(Данные.ИмяПервогоИзмерения); - Для каждого Значение Из Данные.ЗначенияПервогоИзмерения Цикл - - УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], Значение); - Отбор[Данные.ИмяПервогоИзмерения] = Значение; - - Если Данные.ЗначенияПервогоИзмерения.Количество() <> 1 Тогда - НовыеЗаписиНабора = Данные.НовыеЗаписи; - Иначе - НовыеЗаписиНабора = Данные.НовыеЗаписи.Скопировать(Отбор); - КонецЕсли; - - ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, - |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); - ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); - ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); - - ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); - КонецЦикла; - - ИначеЕсли Данные.ИмяТретьегоИзмерения = Неопределено Тогда - // Обновление по двум измерениям. - СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения; - Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); - Отбор = Новый Структура(СписокПолей); - - Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл - УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); - Отбор[Данные.ИмяПервогоИзмерения] = ПервоеЗначение; - - ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям( - Данные, - Отбор, - СписокПолей, - Данные.ИмяВторогоИзмерения, - Данные.ЗначенияВторогоИзмерения, - ЕстьИзменения); - КонецЦикла; - Иначе - // Обновление по трем измерениям. - СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения + ", " + Данные.ИмяТретьегоИзмерения; - Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); - Отбор = Новый Структура(СписокПолей); - - Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл - УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); - Отбор[Данные.ИмяПервогоИзмерения] = ПервоеЗначение; - - Для каждого ВтороеЗначение Из Данные.ЗначенияВторогоИзмерения Цикл - УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения], ВтороеЗначение); - Отбор[Данные.ИмяВторогоИзмерения] = ВтороеЗначение; - - ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям( - Данные, - Отбор, - СписокПолей, - Данные.ИмяВторогоИзмерения, - Данные.ЗначенияВторогоИзмерения, - ЕстьИзменения); - КонецЦикла; - КонецЦикла; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Обновляет регистр сведений по данным в таблице значений ИзмененияСтрок. -// -// Параметры: -// Данные - Структура: -// -// * МенеджерРегистра - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. -// -// * ИзмененияСоставаСтрок - ТаблицаЗначений - содержащей поля регистра и -// поле ВидИзмененияСтроки (Число): -// " 1" - значит, что строку нужно добавить, -// "-1" - значит, что строку нужно удалить. -// -// * ФиксированныйОтбор - Структура - содержащая имя измерения в ключе и значение -// отбора в значении. Может быть указана, когда измерений -// более 3-х и заранее известно, что по измерениям сверх 3-х -// будет единственное значение. Измерения указанные в -// фиксированном отборе не используются при формировании -// наборов записей для выполнения обновления. -// -// * ИзмеренияОтбора - Строка - измерений перечисленных через запятую, которые -// нужно использовать при формировании наборов записей -// для выполнения обновления (не более 3-х). Не указанные -// измерения будут превращены в фиксированный отбор, -// если по ним все значения совпадают. -// -// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, -// а лишь выявить необходимость записи и установить -// свойство ЕстьИзменения. -// -// * ДополнительныеСвойства - Неопределено -// - Структура - если Структура, тогда в -// объекты <Регистр*>НаборЗаписей в свойство -// ДополнительныеСвойства будут вставлены все параметры структуры. -// -// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, -// не выполняя лишних, избыточных действий с данными. -// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. -// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций -// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления -// общего модуля ОбновлениеИнформационнойБазы. -// -// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, -// устанавливается Истина, иначе не изменяется. -// -Процедура ОбновитьРегистрСведений(Знач Данные, ЕстьИзменения = Неопределено) Экспорт - - Если Данные.ИзмененияСоставаСтрок.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ВсеПараметры = Новый Структура; - ВсеПараметры.Вставить("МенеджерРегистра"); - ВсеПараметры.Вставить("ИзмененияСоставаСтрок"); - ВсеПараметры.Вставить("ФиксированныйОтбор", Новый Структура); - ВсеПараметры.Вставить("ИзмеренияОтбора"); - ВсеПараметры.Вставить("ТолькоПроверка", Ложь); - ВсеПараметры.Вставить("ДополнительныеСвойства"); - ВсеПараметры.Вставить("ОбновлениеИБ", - ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() - Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); - - ЗаполнитьПараметры(Данные, ВсеПараметры, "МенеджерРегистра, ИзмененияСоставаСтрок"); - - МетаданныеРегистра = Метаданные.НайтиПоТипу(ТипЗнч(Данные.МенеджерРегистра.ПустойКлюч())); - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(МетаданныеРегистра.ПолноеИмя()); - - Если Данные.ИзмеренияОтбора <> Неопределено Тогда - Данные.ИзмеренияОтбора = Новый Структура(Данные.ИзмеренияОтбора); - КонецЕсли; - - МассивИзмеренийОтбора = Новый Массив; - ЗначенияИзмеренийОтбора = Новый Структура; - ИзмерениеБезФиксированногоОтбора = Новый Структура; - - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - Поле = ОписаниеПоля.Имя; - Если Не Данные.ФиксированныйОтбор.Свойство(Поле) Тогда - Значения = ЗначенияКолонкиТаблицы(Данные.ИзмененияСоставаСтрок, Поле); - - Если Значения.Количество() = 1 Тогда - Данные.ФиксированныйОтбор.Вставить(Поле, Значения[0]); - Продолжить; - КонецЕсли; - - Если Данные.ИзмеренияОтбора = Неопределено - Или Данные.ИзмеренияОтбора.Свойство(Поле) Тогда - - МассивИзмеренийОтбора.Добавить(Поле); - ЗначенияИзмеренийОтбора.Вставить(Поле, Значения); - - ИначеЕсли Не ЗначениеЗаполнено(ИзмерениеБезФиксированногоОтбора) Тогда - ИзмерениеБезФиксированногоОтбора.Вставить("Поле", Поле); - ИзмерениеБезФиксированногоОтбора.Вставить("Значения", Значения); - КонецЕсли; - КонецЕсли; - КонецЦикла; - - Если МассивИзмеренийОтбора.Количество() = 0 Тогда - Если ЗначениеЗаполнено(ИзмерениеБезФиксированногоОтбора) Тогда - Поле = ИзмерениеБезФиксированногоОтбора.Поле; - Значения = ИзмерениеБезФиксированногоОтбора.Значения; - КонецЕсли; - МассивИзмеренийОтбора.Добавить(Поле); - ЗначенияИзмеренийОтбора.Вставить(Поле, Значения); - КонецЕсли; - - Данные.Вставить("ИмяПервогоИзмерения", МассивИзмеренийОтбора[0]); - Данные.Вставить("ЗначенияПервогоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяПервогоИзмерения]); - - Если МассивИзмеренийОтбора.Количество() > 1 Тогда - Данные.Вставить("ИмяВторогоИзмерения", МассивИзмеренийОтбора[1]); - Данные.Вставить("ЗначенияВторогоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяВторогоИзмерения]); - Иначе - Данные.Вставить("ИмяВторогоИзмерения", Неопределено); - Данные.Вставить("ЗначенияВторогоИзмерения", Неопределено); - КонецЕсли; - - Если МассивИзмеренийОтбора.Количество() > 2 Тогда - Данные.Вставить("ИмяТретьегоИзмерения", МассивИзмеренийОтбора[2]); - Данные.Вставить("ЗначенияТретьегоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяТретьегоИзмерения]); - Иначе - Данные.Вставить("ИмяТретьегоИзмерения", Неопределено); - Данные.Вставить("ЗначенияТретьегоИзмерения", Неопределено); - КонецЕсли; - - Данные.Вставить("ПоляСравнения", ОписаниеКлючаЗаписи.СписокПолей); - Данные.Вставить("НовыеЗаписиСодержатТолькоРазличия", Истина); - Данные.Вставить("НовыеЗаписи", Данные.ИзмененияСоставаСтрок); - Данные.Удалить("ИзмененияСоставаСтрок"); - Данные.Удалить("ИзмеренияОтбора"); - - ОбновитьНаборыЗаписей(Данные, ЕстьИзменения); - -КонецПроцедуры - -// Возвращает пустую ссылку объекта метаданных ссылочного типа. -// -// Параметры: -// ОписаниеОбъектаМетаданных - ОбъектМетаданных, -// - Тип - по которому можно найти объект метаданных, -// - Строка - полное имя объекта метаданных. -// Возвращаемое значение: -// ЛюбаяСсылка -// -Функция ПустаяСсылкаОбъектаМетаданных(ОписаниеОбъектаМетаданных) Экспорт - - Если ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("ОбъектМетаданных") Тогда - ОбъектМетаданных = ОписаниеОбъектаМетаданных; - - ИначеЕсли ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("Тип") Тогда - ОбъектМетаданных = Метаданные.НайтиПоТипу(ОписаниеОбъектаМетаданных); - Иначе - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ОписаниеОбъектаМетаданных); - КонецЕсли; - - Если ОбъектМетаданных = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в функции %1 - |общего модуля %2. - | - |Неверный параметр %3.'"), - "ПустаяСсылкаОбъектаМетаданных", - "УправлениеДоступомСлужебный", - "ОписаниеОбъектаМетаданных"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - ПустаяСсылка = Неопределено; - Попытка - МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя()); - ПустаяСсылка = МенеджерОбъекта.ПустаяСсылка(); - Исключение - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в функции %1 - |общего модуля %2. - | - |Не удалось получить пустую ссылка для объекта метаданных - |""%3"".'"), - "ПустаяСсылкаОбъектаМетаданных", - "УправлениеДоступомСлужебный", - ОбъектМетаданных.ПолноеИмя()); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецПопытки; - - Возврат ПустаяСсылка; - -КонецФункции - -#КонецОбласти - -#Область ПрочиеПроцедурыИФункции - -// Создает запрос выбора различий между строками регистра в заданной области данных -// (на основе отборов в параметре ПоляИОтбор). -// -// Параметры: -// ТекстЗапросаВыбораНовых - Строка. -// -// ПоляИОтбор - Массив из Структура - со свойствами "ИмяПоля", ИмяПараметраУсловияОтбора. -// -// ПолноеИмяРегистра - Строка - запрос старых формируется автоматически. -// - Неопределено - запрос старых берется из следующего параметра. -// -// ТекстЗапросовВременныхТаблиц - Строка - запрос временных таблиц, если требуется. -// -// ТекстЗапросаВыбораСтарых - Строка - запрос старых, с учетом нестандартных отборов. -// - Неопределено - когда полное имя регистра определено. -// -// Возвращаемое значение: -// Строка - текст запроса -// -Функция ТекстЗапросаВыбораИзменений(ТекстЗапросаВыбораНовых, - ПоляИОтбор, - ПолноеИмяРегистра = Неопределено, - ТекстЗапросовВременныхТаблиц = Неопределено, - ТекстЗапросаВыбораСтарых = Неопределено) Экспорт - - // Подготовка текста запроса старых данных. - Если ПолноеИмяРегистра <> Неопределено Тогда - ТекстЗапросаВыбораСтарых = - "ВЫБРАТЬ - | &ВыбираемыеПоля, - | &ПодстановкаПоляВидИзмененияСтроки - |ИЗ - | ПолноеИмяРегистра КАК СтарыеДанные - |ГДЕ - | &УсловияОтбора"; - КонецЕсли; - - ВыбираемыеПоля = ""; - УсловияОтбора = "ИСТИНА"; - Для Каждого ОписаниеПоля Из ПоляИОтбор Цикл - // Сборка выбираемых полей. - ВыбираемыеПоля = ВыбираемыеПоля + СтрЗаменить( - " - | СтарыеДанные.Поле,", - "Поле", - КлючИЗначение(ОписаниеПоля).Ключ); - - // Сборка условий отбора. - Если ЗначениеЗаполнено(КлючИЗначение(ОписаниеПоля).Значение) Тогда - УсловияОтбора = УсловияОтбора + СтрЗаменить( - " - | И &ИмяПараметраУсловияОтбора", "&ИмяПараметраУсловияОтбора", // @query-part-1 - КлючИЗначение(ОписаниеПоля).Значение); - КонецЕсли; - КонецЦикла; - - ТекстЗапросаВыбораСтарых = - СтрЗаменить(ТекстЗапросаВыбораСтарых, "&ВыбираемыеПоля,", ВыбираемыеПоля); - - ТекстЗапросаВыбораСтарых = - СтрЗаменить(ТекстЗапросаВыбораСтарых, "&УсловияОтбора", УсловияОтбора); - - ТекстЗапросаВыбораСтарых = - СтрЗаменить(ТекстЗапросаВыбораСтарых, "ПолноеИмяРегистра", ПолноеИмяРегистра); - - Если СтрНайти(ТекстЗапросаВыбораСтарых, "&ПодстановкаПоляВидИзмененияСтроки") = 0 Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в значении параметра %1 - |процедуры %2 модуля %3. - | - |В тексте запроса отсутствует строка ""%4"".'"), - "ТекстЗапросаВыбораСтарых", - "ТекстЗапросаВыбораИзменений", - "УправлениеДоступомСлужебный", - "&ПодстановкаПоляВидИзмененияСтроки"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - ТекстЗапросаВыбораСтарых = СтрЗаменить( - ТекстЗапросаВыбораСтарых, "&ПодстановкаПоляВидИзмененияСтроки", "-1 КАК ВидИзмененияСтроки"); - - Если СтрНайти(ТекстЗапросаВыбораНовых, "&ПодстановкаПоляВидИзмененияСтроки") = 0 Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в значении параметра %1 - |процедуры %2 модуля %3. - | - |В тексте запроса отсутствует строка ""%1"".'"), - "ТекстЗапросаВыбораНовых", - "ТекстЗапросаВыбораИзменений", - "УправлениеДоступомСлужебный", - "&ПодстановкаПоляВидИзмененияСтроки"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - ТекстЗапросаВыбораНовых = СтрЗаменить( - ТекстЗапросаВыбораНовых, "&ПодстановкаПоляВидИзмененияСтроки", "1 КАК ВидИзмененияСтроки"); - - // Подготовка текста запроса выбора изменений. - ТекстЗапроса = - "ВЫБРАТЬ - | &ВыбираемыеПоля, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | ТекстЗапросаВыбораНовыхИСтарыхСтрок КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | &ПоляГруппировки - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0"; - - ТекстЗапросаВыбораНовыхИСтарыхСтрок = - " (" + ТекстЗапросаВыбораНовых + " - | - | ОБЪЕДИНИТЬ ВСЕ - | - | " + ТекстЗапросаВыбораСтарых + ")"; // @query-part-2 - - ВыбираемыеПоля = ""; - ПоляГруппировки = ""; - Для Каждого ОписаниеПоля Из ПоляИОтбор Цикл - // Сборка выбираемых полей. - ВыбираемыеПоля = ВыбираемыеПоля + СтрЗаменить( - " - | ВсеСтроки.Поле,", - "Поле", - КлючИЗначение(ОписаниеПоля).Ключ); - - // Сборка полей соединения. - ПоляГруппировки = ПоляГруппировки + СтрЗаменить( - " - | ВсеСтроки.Поле,", - "Поле", - КлючИЗначение(ОписаниеПоля).Ключ); - КонецЦикла; - ПоляГруппировки = Лев(ПоляГруппировки, СтрДлина(ПоляГруппировки)-1); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВыбираемыеПоля,", ВыбираемыеПоля); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляГруппировки", ПоляГруппировки); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "ТекстЗапросаВыбораНовыхИСтарыхСтрок", ТекстЗапросаВыбораНовыхИСтарыхСтрок); - - Если ЗначениеЗаполнено(ТекстЗапросовВременныхТаблиц) Тогда - ТекстЗапроса = ТекстЗапросовВременныхТаблиц + - " - |; - |" + ТекстЗапроса; - КонецЕсли; - - Возврат ТекстЗапроса; - -КонецФункции - -Функция ПоддерживаетсяУправлениеДоступомВМоделиСервиса() Экспорт - - Возврат ОбщегоНазначения.ПодсистемаСуществует( - "СтандартныеПодсистемы.РаботаВМоделиСервиса.УправлениеДоступомВМоделиСервиса"); - -КонецФункции - -Функция ПоддерживаетсяНастройкаПравПользователейБТС() Экспорт - - Если Не ПоддерживаетсяУправлениеДоступомВМоделиСервиса() Тогда - Возврат Ложь; - КонецЕсли; - - МодульУправлениеДоступомСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль( - "УправлениеДоступомСлужебныйВМоделиСервиса"); - - Возврат МодульУправлениеДоступомСлужебныйВМоделиСервиса.ПоддерживаетсяНастройкаПравПользователейБТС(); - -КонецФункции - -#КонецОбласти - -#Область ОбновлениеИнформационнойБазы - -// Заполняет обработчик разделенных данных, зависимый от изменения неразделенных данных. -// -// Параметры: -// Параметры - Структура - структура параметров обработчиков: -// * РазделенныеОбработчики - см. ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления -// -Процедура ЗаполнитьОбработчикиРазделенныхДанных(Параметры = Неопределено) Экспорт - - Если Параметры <> Неопределено И ЕстьИзмененияПараметровОграниченияДоступа() Тогда - Обработчики = Параметры.РазделенныеОбработчики; - Обработчик = Обработчики.Добавить(); - Обработчик.Версия = "*"; - Обработчик.РежимВыполнения = "Оперативно"; - Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации"; - КонецЕсли; - -КонецПроцедуры - -// Обновляет вспомогательные данные, которые зависят от конфигурации частично. -// -// Обновляется при наличии изменений конфигурации, записанных в параметры -// ограничения доступа при обновлении базы данных на текущую версию конфигурации. -// -Процедура ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации(Параметры = Неопределено) Экспорт - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". - РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистраПоИзменениямКонфигурации(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". - РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); - ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". - РегистрыСведений.НастройкиПравОбъектов.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". - Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); - Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". - Справочники.ГруппыДоступа.ПометитьНаУдалениеГруппыДоступаПомеченныхПрофилей(); - - // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". - РегистрыСведений.ПараметрыОграниченияДоступа.ЗапланироватьОбновлениеДоступаПоИзменениямКонфигурации(); - -КонецПроцедуры - -// Обновляет настройки и включает регламентное задание. -Процедура ВключитьЗаполнениеДанныхДляОграниченияДоступа() Экспорт - - Использование = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); - - Если ОбщегоНазначения.РазделениеВключено() Тогда - УстановитьЗаполнениеДанныхДляОграниченияДоступа(Использование); - Иначе - Расписание = Новый РасписаниеРегламентногоЗадания; - Расписание.ПериодНедель = 1; - Расписание.ПериодПовтораДней = 1; - Расписание.ПериодПовтораВТечениеДня = 300; - Расписание.ПаузаПовтора = 90; - - ЗаданиеМетаданные = Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа; - Задание = РегламентныеЗаданияСервер.ПолучитьРегламентноеЗадание(ЗаданиеМетаданные); - - Задание.Использование = Использование; - Задание.Расписание = Расписание; - - Задание.ИнтервалПовтораПриАварийномЗавершении - = ЗаданиеМетаданные.ИнтервалПовтораПриАварийномЗавершении; - - Задание.КоличествоПовторовПриАварийномЗавершении - = ЗаданиеМетаданные.КоличествоПовторовПриАварийномЗавершении; - - Задание.Записать(); - КонецЕсли; - -КонецПроцедуры - -// Обновляет данные профиля "ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок". -Процедура ОбновитьДанныеПрофиляОткрытиеВнешнихОтчетовИОбработок() Экспорт - - УникальныйИдентификаторПрофиля = Новый УникальныйИдентификатор( - ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок()); - - Ссылка = Справочники.ПрофилиГруппДоступа.ПолучитьСсылку(УникальныйИдентификаторПрофиля); - Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ссылка") = Неопределено Тогда - Возврат; - КонецЕсли; - СсылкаПометитьНаУдаление = Ложь; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка); - - Если ОбщегоНазначения.РазделениеВключено() Тогда - СсылкаПометитьНаУдаление = Истина; - Иначе - ОписаниеПрофиля = ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок(); - ПоставляемыйПрофильСсылка = Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( - ОписаниеПрофиля.Имя); - - Если Ссылка <> ПоставляемыйПрофильСсылка Тогда - Если ПоставляемыйПрофильСсылка <> Неопределено Тогда - СсылкаПометитьНаУдаление = Истина; - Иначе - // Установка идентификатора поставляемых данных. - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ПрофильОбъект = Ссылка.ПолучитьОбъект(); - ПрофильОбъект.ИдентификаторПоставляемыхДанных = УникальныйИдентификаторПрофиля; - ПрофильОбъект.Комментарий = ""; - ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ПрофильОбъект, Ложь); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если СсылкаПометитьНаУдаление Тогда - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ПрофильОбъект = Ссылка.ПолучитьОбъект(); - ПрофильОбъект.ПометкаУдаления = Истина; - ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ПрофильОбъект, Ложь); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - ГруппыПрофиля = ГруппыПрофиля(Ссылка, Ложь); - Для Каждого СсылкаГруппы Из ГруппыПрофиля Цикл - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаГруппы); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ГруппаОбъект = СсылкаГруппы.ПолучитьОбъект(); - ГруппаОбъект.ПометкаУдаления = Истина; - ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ГруппаОбъект, Ложь); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Только для внутреннего использования. -Процедура ОбновитьВспомогательныеДанныеГруппДоступа(Параметры) Экспорт - - Справочники.ГруппыДоступа.ОбновитьВспомогательныеДанныеГруппДоступа(Параметры); - -КонецПроцедуры - -#КонецОбласти - -#Область ВспомогательныеПроцедурыИФункции - -// Возвращаемое значение: -// см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей -// -Функция ПраваРолейРасширений() Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ПраваРолейРасширений = Неопределено; - - УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Истина); - Попытка - ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(ПраваРолейРасширений); - Исключение - УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Ложь); - ВызватьИсключение; - КонецПопытки; - УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Ложь); - - Возврат ПраваРолейРасширений; - -КонецФункции - -// Параметры: -// ПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей -// -Процедура ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(ПраваРолейРасширений = Неопределено) - - ПустыеПраваРолейРасширений = РегистрыСведений.ПраваРолей.ТаблицаПравРолей(Истина, Истина, Истина); - - Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда - МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер"); - Если МодульОбменДаннымиСервер.НастройкаПодчиненногоУзлаРИБ() Тогда - ПраваРолейРасширений = ПустыеПраваРолейРасширений; - Возврат; - КонецЕсли; - КонецЕсли; - - // Заполнение прав ролей расширений, которые состоят - // из изменений прав на объекты конфигурации и прав на объекты расширений. - УстановитьНовыеПраваРолейРасширений = Ложь; - Если ЗначениеЗаполнено(ПараметрыСеанса.ПодключенныеРасширения) Тогда - ХранилищеПравРолейРасширений = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения( - "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей"); // ХранилищеЗначения - - Если ХранилищеПравРолейРасширений = Неопределено Тогда - ПраваРолейРасширений = Неопределено; - Иначе - ПраваРолейРасширений = ЗначениеИзХранилища(ХранилищеПравРолейРасширений); - Если Не ЭтоПраваРолейРасширений(ПраваРолейРасширений, ПустыеПраваРолейРасширений) Тогда - ПраваРолейРасширений = Неопределено; - КонецЕсли; - КонецЕсли; - Если ПраваРолейРасширений = Неопределено Тогда - Запрос = РегистрыСведений.ПраваРолей.ЗапросИзменений(Истина); - ПраваРолейРасширений = Запрос.Выполнить().Выгрузить(); - УстановитьНовыеПраваРолейРасширений = Истина; - КонецЕсли; - Иначе - ПраваРолейРасширений = ПустыеПраваРолейРасширений; - КонецЕсли; - - // Проверка необходимости обновления регистра ТаблицыГруппДоступа. - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ПараметрыОбновленияТаблицГруппДоступа"; - ПараметрыОбновления = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - - Если ТипЗнч(ПараметрыОбновления) <> Тип("Структура") - Или Не ПараметрыОбновления.Свойство("ПоследниеПраваРолейРасширений") - Или Не ЭтоПраваРолейРасширений(ПараметрыОбновления.ПоследниеПраваРолейРасширений, ПустыеПраваРолейРасширений) Тогда - - ТребуетсяОбновление = Истина; - ПоследниеПраваРолейРасширений = Неопределено; - Иначе - ПоследниеПраваРолейРасширений = ПараметрыОбновления.ПоследниеПраваРолейРасширений; - ТребуетсяОбновление = ПраваРолейРасширенийИзменились(ПраваРолейРасширений, ПоследниеПраваРолейРасширений); - КонецЕсли; - - Если Не ТребуетсяОбновление Тогда - Если УстановитьНовыеПраваРолейРасширений Тогда; - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения( - "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей", - Новый ХранилищеЗначения(ПраваРолейРасширений)); - КонецЕсли; - Возврат; - КонецЕсли; - - Если ПоследниеПраваРолейРасширений = Неопределено Тогда - // Так как последние права ролей расширений недоступны, требуется обновить весь регистр. - ОбъектыСИзменениемПравДляОбновления = Неопределено; - Иначе - ТекущиеОбъектыСИзменениемПрав = РегистрыСведений.ПраваРолей.ИзмененныеОбъектыМетаданных( - ПраваРолейРасширений.Скопировать()); - - ПоследниеОбъектыСИзменениемПрав = РегистрыСведений.ПраваРолей.ИзмененныеОбъектыМетаданных( - ПоследниеПраваРолейРасширений.Скопировать()); - - ОбъектыСИзменениемПравДляОбновления = Новый Массив(ТекущиеОбъектыСИзменениемПрав); - Для Каждого Идентификатор Из ПоследниеОбъектыСИзменениемПрав Цикл - ОбъектыСИзменениемПравДляОбновления.Добавить(Идентификатор); - КонецЦикла; - КонецЕсли; - - НовыеПараметрыОбновления = Новый Структура; - НовыеПараметрыОбновления.Вставить("ПоследниеПраваРолейРасширений", ПраваРолейРасширений); - - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); - ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); - - Если Не ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - // Предварительное кэширование в файловой ИБ вне транзакции для предотвращения конфликтов блокировок. - УправлениеДоступомСлужебныйПовтИсп.ПрофильАдминистратор(); - ПроверитьОбъектыНастроекДоступа(); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); - КонецЕсли; - Блокировка.Заблокировать(); - УжеИзменен = Ложь; - СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); - Если УжеИзменен Тогда - ПроверитьАктуальностьМетаданных(); - КонецЕсли; - Если УстановитьНовыеПраваРолейРасширений Тогда; - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения( - "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей", - Новый ХранилищеЗначения(ПраваРолейРасширений)); - КонецЕсли; - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, - НовыеПараметрыОбновления, Истина); - РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра(, ОбъектыСИзменениемПравДляОбновления); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. -// -// Параметры: -// ПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей -// ПустыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей -// -Функция ЭтоПраваРолейРасширений(ПраваРолейРасширений, ПустыеПраваРолейРасширений) - - Если ТипЗнч(ПраваРолейРасширений) <> Тип("ТаблицаЗначений") Тогда - Возврат Ложь; - КонецЕсли; - - Если ПраваРолейРасширений.Колонки.Количество() <> ПустыеПраваРолейРасширений.Колонки.Количество() Тогда - Возврат Ложь; - КонецЕсли; - - Для Каждого Колонка Из ПустыеПраваРолейРасширений.Колонки Цикл - НайденнаяКолонка = ПраваРолейРасширений.Колонки.Найти(Колонка.Имя); - Если НайденнаяКолонка = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - Если Колонка.ТипЗначения <> НайденнаяКолонка.ТипЗначения Тогда - Возврат Ложь; - КонецЕсли; - КонецЦикла; - - Возврат Истина; - -КонецФункции - -// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. -// -// Параметры: -// НовыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей -// СтарыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей -// -Функция ПраваРолейРасширенийИзменились(НовыеПраваРолейРасширений, СтарыеПраваРолейРасширений) - - Если НовыеПраваРолейРасширений.Количество() <> СтарыеПраваРолейРасширений.Количество() Тогда - Возврат Истина; - КонецЕсли; - - Отбор = Новый Структура; - Поля = Новый Массив; - Для Каждого Колонка Из НовыеПраваРолейРасширений.Колонки Цикл - Поля.Добавить(Колонка.Имя); - Отбор.Вставить(Колонка.Имя); - КонецЦикла; - СтарыеПраваРолейРасширений.Индексы.Добавить(СтрСоединить(Поля, ",")); - - Для Каждого Строка Из НовыеПраваРолейРасширений Цикл - ЗаполнитьЗначенияСвойств(Отбор, Строка); - Если СтарыеПраваРолейРасширений.НайтиСтроки(Отбор).Количество() <> 1 Тогда - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -Процедура ПриИзмененииНаборовЗначенийДоступа(Знач СсылкаНаОбъект, ОбновлениеИБ = Ложь) - - СсылкиНаЗависимыеОбъекты = Новый Массив; - - УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа( - СсылкаНаОбъект, СсылкиНаЗависимыеОбъекты); - - Для каждого СсылкаНаЗависимыйОбъект Из СсылкиНаЗависимыеОбъекты Цикл - - Если СсылкаНаЗависимыйОбъект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда - // Изменение объекта не требуется. - // @skip-check query-in-loop - Порционная обработка данных - ЗаписатьНаборыЗначенийДоступа(СсылкаНаЗависимыйОбъект, , ОбновлениеИБ); - Иначе - // Изменение объекта требуется. - Объект = СсылкаНаЗависимыйОбъект.ПолучитьОбъект(); - Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект); - Если НЕ НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаЗависимыйОбъект, Таблица) Тогда - Продолжить; - КонецЕсли; - ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); - Попытка - ЗаблокироватьДанныеДляРедактирования(СсылкаНаЗависимыйОбъект, Объект.ВерсияДанных); - Объект.ДополнительныеСвойства.Вставить("ЗаписатьНаборыЗначенийДоступа"); - Объект.ДополнительныеСвойства.Вставить("ЗаписатьЗависимыеНаборыЗначенийДоступа"); - Объект.ДополнительныеСвойства.Вставить("НаборыЗначенийДоступаТабличнойЧастиЗаполнены"); - Объект.НаборыЗначенийДоступа.Загрузить(Таблица); - Если ОбновлениеИБ Тогда - Объект.ДополнительныеСвойства.Вставить("ЗаписьНаборовЗначенийДоступаПриОбновленииИБ"); - ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); - Иначе - Объект.ОбменДанными.Загрузка = Истина; - // АПК:1327-выкл - №783.1.4.1 Допустимо оставить запись без - // предварительной управляемой блокировки объекта, так как только - // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. - Объект.Записать(); - // АПК:1327-вкл. - КонецЕсли; - РазблокироватьДанныеДляРедактирования(СсылкаНаЗависимыйОбъект); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить зависимый набор значений доступа объекта - |""%1"" по причине: - | - |%2'"), - Строка(СсылкаНаЗависимыйОбъект), - ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)); - ВызватьИсключение ТекстОшибки; - КонецПопытки; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -Функция ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок() - - Возврат "1b3472f6-4d87-11e6-8264-5404a6a6895d"; - -КонецФункции - -Функция ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(Профиль) Экспорт - - Если ТипЗнч(Профиль) = Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда - ИдентификаторПрофиля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Профиль, "ИдентификаторПоставляемыхДанных"); - - ИначеЕсли Не Профиль.ЭтоГруппа Тогда - ИдентификаторПрофиля = Профиль.ИдентификаторПоставляемыхДанных; - Иначе - Возврат Ложь; - КонецЕсли; - - Возврат ВРег(Строка(ИдентификаторПрофиля)) = ВРег(ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок()); - -КонецФункции - -Функция ГруппыДоступаПрофиляОткрытиеВнешнихОтчетовИОбработок() - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИдентификаторПоставляемыхДанных", - Новый УникальныйИдентификатор(ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок())); - - Запрос.Текст = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль.ИдентификаторПоставляемыхДанных = &ИдентификаторПоставляемыхДанных"; - - Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - -КонецФункции - -Функция ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок() Экспорт - - ОписаниеПрофиля = УправлениеДоступом.НовоеОписаниеПрофиляГруппДоступа(); - ОписаниеПрофиля.Имя = "ОткрытиеВнешнихОтчетовИОбработок"; - ОписаниеПрофиля.Родитель = "ДополнительныеПрофили"; - ОписаниеПрофиля.Идентификатор = ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок(); - - ОписаниеПрофиля.Наименование = - НСтр("ru = 'Открытие внешних отчетов и обработок'", ОбщегоНазначения.КодОсновногоЯзыка()); - - ОписаниеПрофиля.Описание = - НСтр("ru = 'Предоставляет право открытия внешних отчетов и обработок из меню ""Файл - Открыть"". - |Состав ролей профиля не рекомендуется изменять.'"); - - ОписаниеПрофиля.Роли.Добавить("ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок"); - - Возврат ОписаниеПрофиля; - -КонецФункции - -Функция ГруппаДоступаОткрытиеВнешнихОтчетовИОбработок(СвойстваПрофиля) - - // Поиск по идентификатору. - УникальныйИдентификатор = Новый УникальныйИдентификатор("f6929bcb-532f-11e6-a20f-5404a6a6895d"); - Ссылка = Справочники.ГруппыДоступа.ПолучитьСсылку(УникальныйИдентификатор); - СсылкаСуществует = (ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ссылка") <> Неопределено); - Если СсылкаСуществует Тогда - Возврат Ссылка; - КонецЕсли; - - // Поиск по профилю. - ГруппыПрофиля = ГруппыПрофиля(СвойстваПрофиля.Ссылка, Неопределено); - Если ГруппыПрофиля.Количество() > 0 Тогда - Возврат ГруппыПрофиля[0]; - КонецЕсли; - - // Создание группы. - ГруппаДоступаОбъект = Справочники.ГруппыДоступа.СоздатьЭлемент(); - ГруппаДоступаОбъект.УстановитьСсылкуНового(Ссылка); - ГруппаДоступаОбъект.Наименование = СвойстваПрофиля.Наименование; - ГруппаДоступаОбъект.Профиль = СвойстваПрофиля.Ссылка; - ГруппаДоступаОбъект.Комментарий = - НСтр("ru = 'Предоставляет право открытия внешних отчетов и обработок из меню ""Файл - Открыть"".'", - ОбщегоНазначения.КодОсновногоЯзыка()); - - ГруппаДоступаОбъект.Записать(); // Важно, чтобы созданная группа "уехала" в подчиненный узел. - - Возврат ГруппаДоступаОбъект.Ссылка; - -КонецФункции - -Функция ГруппыПрофиля(СсылкаПрофиля, ПометкаУдаления) - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль = &Профиль - | И ГруппыДоступа.ПометкаУдаления = &ПометкаУдаления - | - |УПОРЯДОЧИТЬ ПО - | ГруппыДоступа.ПометкаУдаления"; - - Запрос.УстановитьПараметр("Профиль", СсылкаПрофиля); - - Если ПометкаУдаления = Неопределено Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, "И ГруппыДоступа.ПометкаУдаления = &ПометкаУдаления", ""); // @query-part-1 - Иначе - Запрос.УстановитьПараметр("ПометкаУдаления", ПометкаУдаления); - КонецЕсли; - - Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - -КонецФункции - -// Для функция РазрешенныеЗначенияДляДинамическогоСписка, ЕстьОграничениеПоВидуДоступа. -Функция ТекстЗапросаГруппДоступа() - - Возврат - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ГруппыДоступаПользователя - |ИЗ - | Справочник.ИдентификаторыОбъектовМетаданных КАК СвойстваТекущейТаблицы - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа - | ПО (СвойстваТекущейТаблицы.ПолноеИмя = &ИмяОсновнойТаблицыСписка) - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ГДЕ - | ТаблицыГруппДоступа.Таблица = СвойстваТекущейТаблицы.Ссылка - | И ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступа.Ссылка)) - | И (ГруппыДоступа.Ссылка В - | (ВЫБРАТЬ - | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа - | ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО - | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь - | И СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь))"; - -КонецФункции - -// Для процедур ОбновитьНаборЗаписей, ОбновитьНаборыЗаписей, ОбновитьРегистрСведений. -Процедура ЗаполнитьПараметры(ВходныеПараметры, Знач ВсеПараметры, Знач ОбязательныеПараметры = "") - - Если ТипЗнч(ВходныеПараметры) = Тип("Структура") Тогда - Параметры = ВходныеПараметры; - ИначеЕсли ВходныеПараметры = Неопределено Тогда - Параметры = Новый Структура; - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректный тип набора свойств ""%1"". - |Допустимые типы: %2, %3.'"), - ТипЗнч(ВходныеПараметры), "Структура", "Неопределено"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Для каждого КлючИЗначение Из Параметры Цикл - Если Не ВсеПараметры.Свойство(КлючИЗначение.Ключ) Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Указан несуществующий параметр %1'"), - КлючИЗначение.Ключ); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ВсеПараметры[КлючИЗначение.Ключ] = Параметры[КлючИЗначение.Ключ]; - КонецЦикла; - - Если ЗначениеЗаполнено(ОбязательныеПараметры) Тогда - ОбязательныеПараметры = Новый Структура(ОбязательныеПараметры); - - Для каждого КлючИЗначение Из ОбязательныеПараметры Цикл - Если Не Параметры.Свойство(КлючИЗначение.Ключ) Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не указан обязательный параметр %1'"), - КлючИЗначение.Ключ); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - ВходныеПараметры = ВсеПараметры; - -КонецПроцедуры - -// Для процедур ПриОтправкеДанныхГлавному, ПриОтправкеДанныхПодчиненному, -// ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного. -// -Функция ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) - - Возврат ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ПраваРолей") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗависимостиПравДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ТаблицыГруппДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗначенияГруппДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗначенияГруппДоступаПоУмолчанию") - Или ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.КлючиДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.НаборыГруппДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаВнешнихПользователей") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаГруппДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаНаборовГруппДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаКОбъектам") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаКРегистрам") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаПользователей") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ОбновлениеКлючейДоступаКДанным") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ОбновлениеКлючейДоступаПользователей") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ПараметрыОграниченияДоступа") - Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступаПоТаблицам") - Или ТипЗнч(ЭлементДанных) = Тип("КонстантаМенеджерЗначения.ПервоеОбновлениеДоступаЗавершилось"); - -КонецФункции - -// Для процедур ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного -Процедура ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Подчиненному, СозданиеНачальногоОбраза) - - Если СозданиеНачальногоОбраза Тогда // Отправка подчиненному узлу. - // Частичное изменение объектов при создании начального образа не поддерживается, - // обработку смотри в процедуре ПриНастройкеПодчиненногоУзлаРИБ. - // - // Роли расширений назначаются независимо во всех РИБ-узлах. - // Администраторы назначаются независимо во всех РИБ-узлах. - Возврат; - КонецЕсли; - - // Стандартная обработка не переопределяется. - Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить - Или ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда - Возврат; - КонецЕсли; - - Если ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) Тогда - ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать; - Возврат; - КонецЕсли; - - Если Подчиненному Тогда - Возврат; - КонецЕсли; - - ТипЭлемента = ТипЗнч(ЭлементДанных); - - // Профиль и группа доступа открытия внешних отчетов и обработок - // недоступны в сервисе, но доступны в автономном рабочем месте. - Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() - И ( ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") - И ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(ЭлементДанных) - Или ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") - И Не ЭлементДанных.ЭтоГруппа - И ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(ЭлементДанных.Профиль) ) Тогда - - ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать; - КонецЕсли; - - // Роли расширений назначаются независимо во всех РИБ-узлах. - Если ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда - Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширений(ЭлементДанных); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного -Процедура ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, ОтПодчиненного) - - // Стандартная обработка не переопределяется. - Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда - Возврат; - КонецЕсли; - - Если ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) Тогда - ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; - Возврат; - КонецЕсли; - - ТипЭлемента = ТипЗнч(ЭлементДанных); - - Если ОтПодчиненного И ОбщегоНазначения.РазделениеВключено() Тогда - Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") - Или ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписейУниверсально") - Или ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") - Или ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") - Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ГруппыЗначенийДоступа") - Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НаборыЗначенийДоступа") - Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НаследованиеНастроекПравОбъектов") - Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НастройкиПравОбъектов") - Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступа") Тогда - // Получение данных из автономного рабочего места пропускается, а для соответствия - // данных в узлах, текущие данные отправляются обратно в автономное рабочее место. - ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; - ОтправкаНазад = Истина; - Возврат; - КонецЕсли; - - ИначеЕсли ОтПодчиненного Тогда - Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") - Или ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписейУниверсально") Тогда - // Получение данных из подчиненного узла пропускается, а для соответствия - // данных в узлах, текущие данные отправляются обратно в автономное рабочее место. - ОтправкаНазад = Истина; - ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; - Возврат; - КонецЕсли; - КонецЕсли; - - Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") Тогда - Константы.ОграничиватьДоступНаУровнеЗаписей.СоздатьМенеджерЗначения().ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); - - ИначеЕсли ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступа") Тогда - РегистрыСведений.ИспользуемыеВидыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); - - ИначеЕсли ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда - // Роли расширений назначаются независимо во всех РИБ-узлах. - Справочники.ПрофилиГруппДоступа.ВосстановитьСоставРолейРасширений(ЭлементДанных); - // Регистрация измененного профиля для обновления вспомогательных данных. - Справочники.ПрофилиГруппДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); - - ИначеЕсли ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") Тогда - // Администраторы назначаются независимо во всех РИБ-узлах. - Справочники.ГруппыДоступа.ВосстановитьСоставУчастниковГруппыДоступаАдминистраторы(ЭлементДанных); - // Регистрация измененной группы доступа для обновления вспомогательных данных. - Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); - - ИначеЕсли Метаданные.ОпределяемыеТипы.ЗначениеДоступаОбъект.Тип.СодержитТип(ТипЭлемента) Тогда - // Регистрация измененных значений доступа для обновления вспомогательных данных после загрузки. - ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных); - КонецЕсли; - - Если ТипЭлемента <> Тип("УдалениеОбъекта") Тогда - Возврат; - КонецЕсли; - - ЭлементДанных = ЭлементДанных; // УдалениеОбъекта - ТипСсылки = ТипЗнч(ЭлементДанных.Ссылка); - - Если ТипСсылки = Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда - // Регистрация измененного профиля для обновления вспомогательных данных после загрузки. - Справочники.ПрофилиГруппДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); - - ИначеЕсли ТипСсылки = Тип("СправочникСсылка.ГруппыДоступа") Тогда - // Регистрация измененной группы доступа для обновления вспомогательных данных после загрузки. - Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); - КонецЕсли; - - // Регистрация измененных значений доступа для обновления вспомогательных данных после загрузки. - Если УправлениеДоступомСлужебныйПовтИсп.ТипыСсылокИзЗначениеДоступаОбъект().СодержитТип(ТипСсылки) Тогда - ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПриПолученииДанныхОтГлавногоИлиОтПодчиненного. -Процедура ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных) - - УстановитьПривилегированныйРежим(Истина); - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами; - ТипСсылки = ТипЗнч(ЭлементДанных.Ссылка); - - Если ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипСсылки) = Неопределено Тогда - Возврат; - КонецЕсли; - - Если ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта") Тогда - РегистрироватьГруппыДоступа = Истина; - СсылкаОбъекта = ЭлементДанных.Ссылка; - Иначе - РегистрироватьГруппыДоступа = ЭлементДанных.ЭтоНовый(); - СсылкаОбъекта = ПользователиСлужебный.СсылкаОбъекта(ЭлементДанных); - КонецЕсли; - - ПользователиСлужебный.ЗарегистрироватьСсылки("ЗначенияДоступа", СсылкаОбъекта); - - Если СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(ТипСсылки) <> Неопределено Тогда - Если Не РегистрироватьГруппыДоступа Тогда - СтарыйРодитель = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЭлементДанных.Ссылка, "Родитель"); - Если ЭлементДанных.Родитель <> СтарыйРодитель Тогда - РегистрироватьГруппыДоступа = Истина; - КонецЕсли; - КонецЕсли; - Если РегистрироватьГруппыДоступа Тогда - ГруппыДоступа = ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипСсылки); - ПользователиСлужебный.ЗарегистрироватьСсылки("ГруппыДоступаЗначенийСИерархией", ГруппыДоступа); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедур ПослеПолученияДанных, ПослеОбновленияИнформационнойБазы. -Процедура ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных() - - РегистрыСведений.ПараметрыРаботыВерсийРасширений.ЗаблокироватьДляИзмененияВФайловойИБ(); - - УстановитьПривилегированныйРежим(Истина); - Константы.ОграничиватьДоступНаУровнеЗаписей.СоздатьМенеджерЗначения().ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); - РегистрыСведений.ИспользуемыеВидыДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); - Справочники.ПрофилиГруппДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); - Справочники.ГруппыДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); - ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных(); - -КонецПроцедуры - -// Для процедуры ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных. -Процедура ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных() - - ОчисткаРегистрации = Новый Массив; - - ОбработатьЗарегистрированноеИзменениеЗначенийДоступа("ЗначенияДоступа", ОчисткаРегистрации); - ОбработатьЗарегистрированноеИзменениеИерархииЗначенийДоступа("ГруппыДоступаЗначенийСИерархией", - ОчисткаРегистрации); - - Для Каждого ИмяВидаСсылок Из ОчисткаРегистрации Цикл - ПользователиСлужебный.ЗарегистрироватьСсылки(ИмяВидаСсылок, Null); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных. -Процедура ОбработатьЗарегистрированноеИзменениеЗначенийДоступа(ИмяВидаСсылок, ОчисткаРегистрации) - - ЗначенияДоступа = ПользователиСлужебный.ЗарегистрированныеСсылки(ИмяВидаСсылок); - - Если ЗначенияДоступа.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Если ЗначенияДоступа.Количество() = 1 И ЗначенияДоступа[0] = Неопределено Тогда - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(); - Иначе - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(ЗначенияДоступа); - КонецЕсли; - - ОчисткаРегистрации.Добавить(ИмяВидаСсылок); - -КонецПроцедуры - -// Для процедуры ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных. -Процедура ОбработатьЗарегистрированноеИзменениеИерархииЗначенийДоступа(ИмяВидаСсылок, ОчисткаРегистрации) - - ГруппыДоступа = ПользователиСлужебный.ЗарегистрированныеСсылки(ИмяВидаСсылок); - - Если ГруппыДоступа.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Если ГруппыДоступа.Количество() = 1 И ГруппыДоступа[0] = Неопределено Тогда - РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(); - Иначе - РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(ГруппыДоступа); - КонецЕсли; - - ОчисткаРегистрации.Добавить(ИмяВидаСсылок); - -КонецПроцедуры - -// Для процедур ВключитьПользователяВГруппуДоступа. -Функция ОбработатьСвязьПользователяСГруппойДоступа(Пользователь, ПоставляемыйПрофиль, Включить = Неопределено) - - Если ТипЗнч(Пользователь) <> Тип("СправочникСсылка.Пользователи") - И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ГруппыПользователей") - И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ВнешниеПользователи") - И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ГруппыВнешнихПользователей") Тогда - - Возврат Ложь; - КонецЕсли; - - ИдентификаторПоставляемогоПрофиля = Неопределено; - - Если ТипЗнч(ПоставляемыйПрофиль) = Тип("Строка") Тогда - Если СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(ПоставляемыйПрофиль) Тогда - - ИдентификаторПоставляемогоПрофиля = ПоставляемыйПрофиль; - - ПоставляемыйПрофиль = Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( - ИдентификаторПоставляемогоПрофиля,, Истина); - Иначе - Возврат Ложь; - КонецЕсли; - КонецЕсли; - - Если ТипЗнч(ПоставляемыйПрофиль) <> Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда - Возврат Ложь; - КонецЕсли; - - Если ИдентификаторПоставляемогоПрофиля = Неопределено Тогда - ИдентификаторПоставляемогоПрофиля = - Справочники.ПрофилиГруппДоступа.ИдентификаторПоставляемогоПрофиля(ПоставляемыйПрофиль); - КонецЕсли; - - Если ИдентификаторПоставляемогоПрофиля = Справочники.ПрофилиГруппДоступа.ИдентификаторПрофиляАдминистратор() Тогда - Возврат Ложь; - КонецЕсли; - - СвойстваПрофиля = Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля(ИдентификаторПоставляемогоПрофиля); - - Если СвойстваПрофиля = Неопределено - ИЛИ СвойстваПрофиля.ВидыДоступа.Количество() <> 0 Тогда - - Возврат Ложь; - КонецЕсли; - - ГруппаДоступа = Неопределено; - - Если УпрощенныйИнтерфейсНастройкиПравДоступа() Тогда - - Если ТипЗнч(Пользователь) <> Тип("СправочникСсылка.Пользователи") - И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ВнешниеПользователи") Тогда - - Возврат Ложь; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Профиль", ПоставляемыйПрофиль); - Запрос.УстановитьПараметр("Пользователь", Пользователь); - Запрос.Текст = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль = &Профиль - | И ГруппыДоступа.Пользователь = &Пользователь"; - Выборка = Запрос.Выполнить().Выбрать(); - Если Выборка.Следующий() Тогда - ГруппаДоступа = Выборка.Ссылка; - КонецЕсли; - - Если ГруппаДоступа = Неопределено Тогда - Если Включить <> Истина Тогда - Возврат Ложь; - Иначе - ГруппаДоступа = Справочники.ГруппыДоступа.СоздатьЭлемент(); - ГруппаДоступа.Наименование = СвойстваПрофиля.Наименование; - ГруппаДоступа.Профиль = ПоставляемыйПрофиль; - ГруппаДоступа.Пользователь = Пользователь; - ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; - ГруппаДоступа.Записать(); - Возврат Истина; - КонецЕсли; - КонецЕсли; - Иначе - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ПоставляемыйПрофиль", ПоставляемыйПрофиль); - Запрос.Текст = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Ссылка, - | ГруппыДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль = &ПоставляемыйПрофиль - | - |УПОРЯДОЧИТЬ ПО - | ГруппыДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля УБЫВ"; - Выборка = Запрос.Выполнить().Выбрать(); - Если Выборка.Следующий() Тогда - ГруппаДоступа = Выборка.Ссылка; // СправочникСсылка.ГруппыДоступа - - КонецЕсли; - - Если ГруппаДоступа = Неопределено Тогда - Если Включить <> Истина Тогда - Возврат Ложь; - Иначе - ГруппаДоступа = Справочники.ГруппыДоступа.СоздатьЭлемент(); - ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля = Истина; - ГруппаДоступа.Наименование = СвойстваПрофиля.Наименование; - ГруппаДоступа.Профиль = ПоставляемыйПрофиль; - ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; - ГруппаДоступа.Записать(); - Возврат Истина; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Ссылка", ГруппаДоступа); - Запрос.УстановитьПараметр("Пользователь", Пользователь); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппы - |ГДЕ - | УчастникиГруппы.Ссылка = &Ссылка - | И УчастникиГруппы.Пользователь = &Пользователь"; - ПользовательНайден = НЕ Запрос.Выполнить().Пустой(); - - Если Включить = Неопределено Тогда - Возврат ПользовательНайден; - КонецЕсли; - - Если Включить И ПользовательНайден Тогда - Возврат Истина; - КонецЕсли; - - Если НЕ Включить И НЕ ПользовательНайден Тогда - Возврат Истина; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступа); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - - ГруппаДоступа = ГруппаДоступа.ПолучитьОбъект(); - - Если НЕ УпрощенныйИнтерфейсНастройкиПравДоступа() - И НЕ ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля Тогда - - ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля = Истина; - КонецЕсли; - - Если Включить Тогда - ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; - Иначе - Отбор = Новый Структура("Пользователь", Пользователь); - Строки = ГруппаДоступа.Пользователи.НайтиСтроки(Отбор); - Для каждого Строка Из Строки Цикл - ГруппаДоступа.Пользователи.Удалить(Строка); - КонецЦикла; - КонецЕсли; - - ГруппаДоступа.Записать(); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Возврат Истина; - -КонецФункции - -// Для процедуры ЗаписатьНаборыЗначенийДоступаПриЗаписи. - -// Перезаписывает наборы значений доступа проверяемого объекта -// в РегистрСведений.НаборыЗначенийДоступа, используя процедуру -// УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(). -// -// Процедура вызывается из УправлениеДоступомСлужебный.ЗаписатьНаборыЗначенийДоступа(), -// но может быть вызвана из любого места, например, -// при включении ограничения доступа на уровне записей. -// -// Вызывает процедуру прикладного разработчика -// УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа(), -// которая используется для перезаписи зависимых наборов значений доступа. -// -// Параметры: -// Объект - ЛюбаяСсылка -// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - -// В случае вызова с клиента можно передать только ссылку, а нужен объект. -// Если получена ссылка, то по ней будет получен объект. -// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, -// не выполняя лишних, избыточных действий с данными. -// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. -// -Процедура ЗаписатьНаборыЗначенийДоступа(Знач Объект, ЕстьИзменения = Неопределено, ОбновлениеИБ = Ложь) - - УстановитьПривилегированныйРежим(Истина); - - // Если передача параметра Объект производилась с клиента на сервер, - // то передавалась ссылка, и объект требуется получить. - Объект = ?(Объект = Объект.Ссылка, Объект.ПолучитьОбъект(), Объект); - СсылкаНаОбъект = Объект.Ссылка; - ТипЗначенияОбъект = ТипЗнч(Объект); - - НаборыЗаписываются = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( - "ЗаписатьНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; - - Если НЕ НаборыЗаписываются Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Неверные параметры. - |Тип объекта ""%1"" - |не существует в подписках на события %2.'"), - ТипЗначенияОбъект, - "ЗаписатьНаборыЗначенийДоступа"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ВозможныеТипыОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы( - "РегистрСведений.НаборыЗначенийДоступа.Измерение.Объект"); - - Если ВозможныеТипыОбъектов.Получить(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка при записи наборов значений доступа: - |в регистре сведений %1 в измерении %2 - |не задан тип ""%3"".'"), - "НаборыЗначенийДоступа", - "Объект", - ТипЗнч(СсылкаНаОбъект)); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - Если УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() - И Не УправлениеДоступом.ПроизводительныйВариант() Тогда - - Если Метаданные.НайтиПоТипу(ТипЗначенияОбъект).ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда - - Таблица = УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(); - УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(Объект, Таблица); - - УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( - Таблица, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); - Иначе - ТабличнаяЧастьЗаполняется = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( - "ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей - |ЗаполнитьНаборыЗначенийДоступаТабличныхЧастейДокументов").Получить(ТипЗначенияОбъект) <> Неопределено; - - Если НЕ ТабличнаяЧастьЗаполняется Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Неверные параметры. - |Тип объекта ""%1"" - |не существует в подписках на события %2.'"), - ТипЗначенияОбъект, - "ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - // Записан объект с уже заполненной табличной частью НаборыЗначенийДоступа. - Таблица = Объект.НаборыЗначенийДоступа.Выгрузить(); - КонецЕсли; - - ПодготовитьНаборыЗначенийДоступаКЗаписи(СсылкаНаОбъект, Таблица, Истина); - - Данные = Новый Структура; - Данные.Вставить("МенеджерРегистра", РегистрыСведений.НаборыЗначенийДоступа); - Данные.Вставить("ФиксированныйОтбор", Новый Структура("Объект", СсылкаНаОбъект)); - Данные.Вставить("НовыеЗаписи", Таблица); - Данные.Вставить("ОбновлениеИБ", ОбновлениеИБ); - - НачатьТранзакцию(); - Попытка - ОбновитьНаборыЗаписей(Данные, ЕстьИзменения); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ЕстьИзменения = Истина Тогда - ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); - КонецЕсли; - Иначе - Запрос = Новый Запрос( - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.НаборыЗначенийДоступа КАК НаборыЗначенийДоступа - |ГДЕ - | НаборыЗначенийДоступа.Объект = &СсылкаНаОбъект"); - - Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект); - - // АПК:1328-выкл - №648.1.1 Допустимо чтение без предварительной - // управляемой разделяемой блокировки объекта, так как только - // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. - Если НЕ Запрос.Выполнить().Пустой() Тогда - // АПК:1328-вкл. - - // Очистка устаревшего набора. - // Запись нового набора будет выполнена регламентным заданием, - // после включения ограничения на уровне записей. - НаборЗаписей = РегистрыСведений.НаборыЗначенийДоступа.СоздатьНаборЗаписей(); - НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект); - НаборЗаписей.Записать(); - ЕстьИзменения = Истина; - - // Очистка устаревших зависимых наборов. - ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаписатьЗависимыеНаборыЗначенийДоступаПриЗаписи. - -// Перезаписывает наборы значений доступа зависимых объектов. -// -// Процедура вызывается из УправлениеДоступомСлужебный.ЗаписатьЗависимыеНаборыЗначенийДоступа(), -// состав типов подписки дополняет (без пересечения) состав типов подписки ЗаписатьНаборыЗначенийДоступа, -// теми типами, для которых выполнять запись наборов в регистр сведений НаборыЗначенийДоступа -// не требуется, но сами наборы входят в состав других наборов, например, наборы некоторых файлов -// из справочника "Файлы" могут входить в состав некоторых бизнес-процессов "Задание", созданных -// на основании файлов, при этом наборы файлов записывать в регистр не требуется. -// -// Вызывает процедуру прикладного разработчика -// УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа(), -// которая используется для перезаписи зависимых наборов значений доступа, -// то есть организуется рекурсия. -// -// Параметры: -// Объект - ЛюбаяСсылка -// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - -// В случае вызова с клиента можно передать только ссылку, а нужен объект. -// Если получена ссылка, то по ней будет получен объект. -// -// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, -// не выполняя лишних, избыточных действий с данными. -// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. -// -Процедура ЗаписатьЗависимыеНаборыЗначенийДоступа(Знач Объект, ОбновлениеИБ = Ложь) - - УстановитьПривилегированныйРежим(Истина); - - // Если передача параметра Объект производилась с клиента на сервер, - // то передавалась ссылка, и объект требуется получить. - Объект = ?(Объект = Объект.Ссылка, Объект.ПолучитьОбъект(), Объект); - СсылкаНаОбъект = Объект.Ссылка; - ТипЗначенияОбъект = ТипЗнч(Объект); - - ЭтоВедущийОбъект = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( - "ЗаписатьЗависимыеНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; - - Если НЕ ЭтоВедущийОбъект Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Неверные параметры. - |Тип объекта ""%1"" - |не существует в подписке на события %2.'"), - ТипЗначенияОбъект, - "ЗаписатьЗависимыеНаборыЗначенийДоступа"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); - -КонецПроцедуры - -// Для процедур ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации и -// ЗаполнитьОбработчикиРазделенныхДанных. - -// Проверяет были ли изменения неразделенных данных для какой-нибудь области данных. -Функция ЕстьИзмененияПараметровОграниченияДоступа() - - УстановитьПривилегированныйРежим(Истина); - - Параметры = Новый Массив; - Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ОбъектыМетаданныхПравРолей"); - Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов"); - Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей"); - Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа"); - Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа"); - Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"); - - Для Каждого Параметр Из Параметры Цикл - - ПоследниеИзменения = СтандартныеПодсистемыСервер.ИзмененияПараметраРаботыПрограммы(Параметр); - - Если ПоследниеИзменения = Неопределено - ИЛИ ПоследниеИзменения.Количество() > 0 Тогда - - Возврат Истина; - КонецЕсли; - - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для процедуры ОбновитьРолиПользователей. - -// Для тестирования. -// -// Параметры: -// ДополнительныеРоли - Соответствие из КлючИЗначение: -// * Ключ - Строка - имя роли, которую можно назначить администратору. -// * Значение - Булево - Истина. -// -Процедура ПриПодготовкеДополнительныхРолейАдминистратора(ДополнительныеРоли) - Возврат; -КонецПроцедуры - -Функция ТекущиеСвойстваПользователей(МассивПользователей) - - Запрос = Новый Запрос; - - Запрос.УстановитьПараметр("ГруппаДоступаАдминистраторы", - УправлениеДоступом.ГруппаДоступаАдминистраторы()); - - Запрос.УстановитьПараметр("ПустойИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - Если МассивПользователей = Неопределено Тогда - Запрос.Текст = - "ВЫБРАТЬ - | Пользователи.Ссылка КАК Пользователь, - | Пользователи.ИдентификаторПользователяИБ - |ПОМЕСТИТЬ ПроверяемыеПользователи - |ИЗ - | Справочник.Пользователи КАК Пользователи - |ГДЕ - | Пользователи.Служебный = ЛОЖЬ - | И Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ВнешниеПользователи.Ссылка, - | ВнешниеПользователи.ИдентификаторПользователяИБ - |ИЗ - | Справочник.ВнешниеПользователи КАК ВнешниеПользователи - |ГДЕ - | ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь"; - - ИначеЕсли ТипЗнч(МассивПользователей) = Тип("Тип") Тогда - Если Метаданные.НайтиПоТипу(МассивПользователей) = Метаданные.Справочники.ВнешниеПользователи Тогда - Запрос.Текст = - "ВЫБРАТЬ - | ВнешниеПользователи.Ссылка КАК Пользователь, - | ВнешниеПользователи.ИдентификаторПользователяИБ - |ПОМЕСТИТЬ ПроверяемыеПользователи - |ИЗ - | Справочник.ВнешниеПользователи КАК ВнешниеПользователи - |ГДЕ - | ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь"; - Иначе - Запрос.Текст = - "ВЫБРАТЬ - | Пользователи.Ссылка КАК Пользователь, - | Пользователи.ИдентификаторПользователяИБ - |ПОМЕСТИТЬ ПроверяемыеПользователи - |ИЗ - | Справочник.Пользователи КАК Пользователи - |ГДЕ - | Пользователи.Служебный = ЛОЖЬ - | И Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь"; - КонецЕсли; - Иначе - ИсходныеПользователи = Новый ТаблицаЗначений; - ИсходныеПользователи.Колонки.Добавить("Пользователь", Новый ОписаниеТипов( - "СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи")); - - Для каждого Пользователь Из МассивПользователей Цикл - ИсходныеПользователи.Добавить().Пользователь = Пользователь; - КонецЦикла; - - Запрос.УстановитьПараметр("ИсходныеПользователи", ИсходныеПользователи); - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ИсходныеПользователи.Пользователь - |ПОМЕСТИТЬ ИсходныеПользователи - |ИЗ - | &ИсходныеПользователи КАК ИсходныеПользователи - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | Пользователи.Ссылка КАК Пользователь, - | Пользователи.ИдентификаторПользователяИБ - |ПОМЕСТИТЬ ПроверяемыеПользователи - |ИЗ - | Справочник.Пользователи КАК Пользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсходныеПользователи КАК ИсходныеПользователи - | ПО Пользователи.Ссылка = ИсходныеПользователи.Пользователь - | И (Пользователи.Служебный = ЛОЖЬ) - | И (Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор) - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ВнешниеПользователи.Ссылка, - | ВнешниеПользователи.ИдентификаторПользователяИБ - |ИЗ - | Справочник.ВнешниеПользователи КАК ВнешниеПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсходныеПользователи КАК ИсходныеПользователи - | ПО ВнешниеПользователи.Ссылка = ИсходныеПользователи.Пользователь - | И (ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор) - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь"; - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ - | Пользователи.Ссылка КАК Пользователь, - | Пользователи.ИдентификаторПользователяИБ - |ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи - | ПО (ГруппыДоступаПользователи.Ссылка = &ГруппаДоступаАдминистраторы) - | И ГруппыДоступаПользователи.Пользователь = Пользователи.Ссылка - | И (НЕ Пользователи.ПометкаУдаления) - | И (НЕ Пользователи.Недействителен) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ПроверяемыеПользователи.Пользователь, - | ПроверяемыеПользователи.ИдентификаторПользователяИБ - |ИЗ - | ПроверяемыеПользователи КАК ПроверяемыеПользователи - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ПроверяемыеПользователи.Пользователь КАК Пользователь, - | ГруппыДоступаПользователи.Ссылка.Профиль КАК Профиль - |ПОМЕСТИТЬ ПрофилиПользователей - |ИЗ - | ПроверяемыеПользователи КАК ПроверяемыеПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО ПроверяемыеПользователи.Пользователь = СоставыГруппПользователей.Пользователь - | И (СоставыГруппПользователей.Используется) - | И (&ИсключитьВнешнихПользователей) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь) - | И (НЕ ГруппыДоступаПользователи.Ссылка.ПометкаУдаления) - | И (НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ПрофилиПользователей.Пользователь, - | Роли.Роль КАК РольСсылка - |ИЗ - | ПрофилиПользователей КАК ПрофилиПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК Роли - | ПО (Роли.Ссылка = ПрофилиПользователей.Профиль) - |ГДЕ - | Роли.Роль <> НЕОПРЕДЕЛЕНО"; - - Запрос.Текст = Запрос.Текст + " - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |" + ТекстЗапроса; - - Если Константы.ИспользоватьВнешнихПользователей.Получить() Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИсключитьВнешнихПользователей", "ИСТИНА"); - Иначе - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИсключитьВнешнихПользователей", - "ТИПЗНАЧЕНИЯ(ПроверяемыеПользователи.Пользователь) = ТИП(Справочник.Пользователи)"); // @query-part-2 - КонецЕсли; - - РезультатыЗапросов = Запрос.ВыполнитьПакет(); - ПоследнийРезультат = РезультатыЗапросов.Количество()-1; - Итог = Новый Структура; - - Итог.Вставить("Администраторы", Новый Соответствие); - - Для каждого Строка Из РезультатыЗапросов[ПоследнийРезультат-3].Выгрузить() Цикл - Итог.Администраторы.Вставить(Строка.Пользователь, Истина); - КонецЦикла; - - Итог.Вставить("ИдентификаторыПользователейИБ", РезультатыЗапросов[ПоследнийРезультат-2].Выгрузить()); - - Если ПользователиСлужебный.СостояниеДоВызоваАвторизоватьТекущегоПользователя(Истина) Тогда - Отбор = Новый Структура("ИдентификаторПользователяИБ", - ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор); - НайденныеСтроки = Итог.ИдентификаторыПользователейИБ.НайтиСтроки(Отбор); - Если ЗначениеЗаполнено(НайденныеСтроки) Тогда - Итог.Администраторы.Вставить(НайденныеСтроки[0].Пользователь, Истина); - КонецЕсли; - КонецЕсли; - - Итог.Вставить("РолиПользователей", РезультатыЗапросов[ПоследнийРезультат].Выгрузить()); - Итог.РолиПользователей.Колонки.Добавить("Роль", Новый ОписаниеТипов("Строка")); - Итог.РолиПользователей.Индексы.Добавить("Пользователь"); - - РолиВсехПользователей = Итог.РолиПользователей.Скопировать(, "РольСсылка"); - РолиВсехПользователей.Свернуть("РольСсылка"); - ИдентификаторыРолей = РолиВсехПользователей.ВыгрузитьКолонку("РольСсылка"); - ПроверитьАктуальностьНовыхРолейПользователейВСеансе(ИдентификаторыРолей); - МетаданныеРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИдентификаторыРолей, Ложь); - - ИдентификаторыРолей = Новый Соответствие; - ИменаРолей = Новый Соответствие; - БезОбъектовМетаданных = Новый Массив; - Для Каждого ОписаниеРоли Из МетаданныеРолей Цикл - Если ТипЗнч(ОписаниеРоли.Значение) = Тип("ОбъектМетаданных") Тогда - ИмяРоли = ОписаниеРоли.Значение.Имя; - ИдентификаторыРолей.Вставить(ИмяРоли, ОписаниеРоли.Ключ); - ИменаРолей.Вставить(ОписаниеРоли.Ключ, ИмяРоли); - Иначе - БезОбъектовМетаданных.Добавить(ОписаниеРоли.Ключ); - КонецЕсли; - КонецЦикла; - - Если ЗначениеЗаполнено(БезОбъектовМетаданных) Тогда - ДобавитьИдентификаторыРолейБезОбъектовМетаданных(БезОбъектовМетаданных, ИдентификаторыРолей); - КонецЕсли; - - ОбязательныеРолиАдминистратора = Новый Соответствие; - ОбязательныеРолиАдминистратора.Вставить("ПолныеПрава"); - Если Не ОбщегоНазначения.РазделениеВключено() Тогда - ОбязательныеРолиАдминистратора.Вставить("АдминистраторСистемы"); - КонецЕсли; - СтандартныеРолиРасширений = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСтандартныхРолейРасширенийСеанса().РолиСеанса; - ДополнительныеРолиАдминистратора = Новый Соответствие(СтандартныеРолиРасширений.ДополнительныеРолиАдминистратора); - ПриПодготовкеДополнительныхРолейАдминистратора(ДополнительныеРолиАдминистратора); - ДополнительныеРолиАдминистратора.Вставить("ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок"); - - ПолныеИменаРолей = Новый Массив; - ДобавитьИменаРолей(ОбязательныеРолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей); - ДобавитьИменаРолей(ДополнительныеРолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей); - Если ЗначениеЗаполнено(ПолныеИменаРолей) Тогда - ДобавитьИдентификаторыРолей(ПолныеИменаРолей, ИдентификаторыРолей, ИменаРолей); - КонецЕсли; - - ЗаполнитьИдентификаторыРолей(ОбязательныеРолиАдминистратора, ИдентификаторыРолей, ИменаРолей); - ЗаполнитьИдентификаторыРолей(ДополнительныеРолиАдминистратора, ИдентификаторыРолей); - - Итог.Вставить("ИдентификаторыРолей", ИдентификаторыРолей); - Итог.Вставить("ИменаРолей", ИменаРолей); - - Итог.Вставить("ОбязательныеРолиАдминистратора", ОбязательныеРолиАдминистратора); - Итог.Вставить("ДополнительныеРолиАдминистратора", ДополнительныеРолиАдминистратора); - - Возврат Итог; - -КонецФункции - -// Для функции ТекущиеСвойстваПользователей. -Процедура ПроверитьАктуальностьНовыхРолейПользователейВСеансе(ИдентификаторыРолей) - - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ИдентификаторыРолей"; - ЗначениеСеанса = УправлениеДоступомСлужебныйПовтИсп.ИдентификаторыРолейСеанса(); - - ТекущееЗначение = ПоследниеИдентификаторыРолей(ИмяПараметра); - - Если ТекущееЗначение.ХешСумма = ЗначениеСеанса.ХешСумма Тогда - Возврат; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); - ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - УжеИзменен = Ложь; - ТекущееЗначение = ПоследниеИдентификаторыРолей(ИмяПараметра, УжеИзменен); - Если ТекущееЗначение.ХешСумма <> ЗначениеСеанса.ХешСумма Тогда - ПропуститьОбновление = Ложь; - Если УжеИзменен Тогда - Попытка - ПроверитьАктуальностьМетаданных(); - Исключение - ИдентификаторыСеанса = ЗначениеСеанса.ИдентификаторыРолей; - ТекущиеИдентификаторы = ТекущееЗначение.ИдентификаторыРолей; - Для Каждого ИдентификаторРоли Из ИдентификаторыРолей Цикл - ЕстьВТекущих = ТекущиеИдентификаторы.Получить(ИдентификаторРоли) <> Неопределено; - ЕстьВСеансе = ИдентификаторыСеанса.Получить(ИдентификаторРоли) <> Неопределено; - Если ЕстьВТекущих <> ЕстьВСеансе Тогда - ВызватьИсключение; - КонецЕсли; - КонецЦикла; - ПропуститьОбновление = Истина; - КонецПопытки; - КонецЕсли; - Если Не ПропуститьОбновление Тогда - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ЗначениеСеанса, Истина); - КонецЕсли; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для функции ТекущиеСвойстваПользователей. -Процедура ДобавитьИменаРолей(РолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей) - - Для Каждого КлючИЗначение Из РолиАдминистратора Цикл - Если ИдентификаторыРолей.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда - Продолжить; - КонецЕсли; - МетаданныеРоли = Метаданные.Роли.Найти(КлючИЗначение.Ключ); - Если МетаданныеРоли = Неопределено Тогда - Продолжить; - КонецЕсли; - ПолноеИмяРоли = МетаданныеРоли.ПолноеИмя(); - Если ПолныеИменаРолей.Найти(ПолноеИмяРоли) = Неопределено Тогда - ПолныеИменаРолей.Добавить(ПолноеИмяРоли); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для функции ТекущиеСвойстваПользователей. -Процедура ДобавитьИдентификаторыРолей(ПолныеИменаРолей, ИдентификаторыРолей, ИменаРолей) - - ДополнительныеИдентификаторыРолей = - ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИменаРолей, Ложь); - - Для Каждого КлючИЗначение Из ДополнительныеИдентификаторыРолей Цикл - ИдентификаторРоли = КлючИЗначение.Значение; - Если ИдентификаторРоли = Неопределено Тогда - Продолжить; - КонецЕсли; - ИмяРоли = СтрРазделить(КлючИЗначение.Ключ, ".")[1]; - ИдентификаторыРолей.Вставить(ИмяРоли, ИдентификаторРоли); - ИменаРолей.Вставить(ИдентификаторРоли, ИмяРоли); - КонецЦикла; - -КонецПроцедуры - -// Для функции ТекущиеСвойстваПользователей. -Процедура ДобавитьИдентификаторыРолейБезОбъектовМетаданных(БезОбъектовМетаданных, ИдентификаторыРолей) - - КлючиРолей = Справочники.ИдентификаторыОбъектовМетаданных.КлючиРолей(БезОбъектовМетаданных); - - Для Каждого КлючИЗначение Из КлючиРолей Цикл - Если ЗначениеЗаполнено(КлючИЗначение.Значение) Тогда - ИдентификаторыРолей.Вставить(КлючИЗначение.Значение, КлючИЗначение.Ключ); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для функции ТекущиеСвойстваПользователей. -Процедура ЗаполнитьИдентификаторыРолей(РолиАдминистратора, ИдентификаторыРолей, ИменаРолей = Неопределено) - - НовыеРолиАдминистратора = Новый Соответствие; - - Для Каждого КлючИЗначение Из РолиАдминистратора Цикл - ИмяРоли = КлючИЗначение.Ключ; - ИдентификаторРоли = ИдентификаторыРолей.Получить(ИмяРоли); - Если ИдентификаторРоли = Неопределено Тогда - Если ИменаРолей <> Неопределено Тогда - ИдентификаторРоли = Справочники.ИдентификаторыОбъектовМетаданных.ПолучитьСсылку(); - ИдентификаторыРолей.Вставить(ИмяРоли, ИдентификаторРоли); - ИменаРолей.Вставить(ИдентификаторРоли, ИмяРоли); - Иначе - Продолжить; - КонецЕсли; - КонецЕсли; - НовыеРолиАдминистратора.Вставить(ИмяРоли, ИдентификаторРоли); - КонецЦикла; - - РолиАдминистратора = НовыеРолиАдминистратора; - -КонецПроцедуры - -// См. УправлениеДоступомСлужебныйПовтИсп.ИдентификаторыРолейСеанса -Функция ПоследниеИдентификаторыРолей(ИмяПараметра, УжеИзменен = Ложь) - - Значение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); - Если ТипЗнч(Значение) <> Тип("ФиксированнаяСтруктура") - Или Не Значение.Свойство("ХешСумма") - Или Не Значение.Свойство("ИдентификаторыРолей") - Или ТипЗнч(Значение.ИдентификаторыРолей) <> Тип("ФиксированноеСоответствие") Тогда - - Значение = Новый Структура("ХешСумма, ИдентификаторыРолей", "", Новый Соответствие); - КонецЕсли; - - Возврат Значение; - -КонецФункции - -// Параметры: -// НовыеРолиПользователей - ТаблицаЗначений -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * Пользователь - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// * РольСсылка - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// * Роль - Строка - имя роли. -// -Функция НовыеНекорректныеРоли(НовыеРолиПользователей) - - Результат = НовыеРолиПользователей.Скопировать( - Новый Массив, "Пользователь, Роль, РольСсылка"); - - Результат.Колонки.Добавить("ЭтоНенайденнаяРоль", Новый ОписаниеТипов("Булево")); - - Возврат Результат; - -КонецФункции - -// Параметры: -// НекорректныеРоли - см. НовыеНекорректныеРоли -// ОписаниеРоли - СтрокаТаблицыЗначений -// Пользователь - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// -Процедура ДобавитьНекорректнуюРоль(НекорректныеРоли, ОписаниеРоли, Пользователь, ЭтоНенайденнаяРоль) - - НоваяСтрока = НекорректныеРоли.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, ОписаниеРоли); - НоваяСтрока.Пользователь = Пользователь; - НоваяСтрока.ЭтоНенайденнаяРоль = ЭтоНенайденнаяРоль; - -КонецПроцедуры - -// Параметры: -// НекорректныеРоли - см. НовыеНекорректныеРоли -// -Процедура ЗарегистрироватьНекорректныеРоли(НекорректныеРоли) - - Если Не ЗначениеЗаполнено(НекорректныеРоли) Тогда - Возврат; - КонецЕсли; - - ЗаполнитьИменаНенайденныхРолей(НекорректныеРоли); - - ПрофилиНекорректныхРолей = ПрофилиПользователейСРолями(НекорректныеРоли); - ПрофилиНекорректныхРолей.Индексы.Добавить("Пользователь, РольСсылка"); - Отбор = Новый Структура("Пользователь, РольСсылка"); - - Для Каждого НекорректнаяРоль Из НекорректныеРоли Цикл - ЗаполнитьЗначенияСвойств(Отбор, НекорректнаяРоль); - Строки = ПрофилиНекорректныхРолей.НайтиСтроки(Отбор); - Для Каждого Строка Из Строки Цикл - Если НекорректнаяРоль.ЭтоНенайденнаяРоль Тогда - ЗарегистрироватьНенайденнуюРоль(НекорректнаяРоль, Строка.Профиль); - Иначе - ЗарегистрироватьНедоступнуюРоль(НекорректнаяРоль, Строка.Профиль); - КонецЕсли; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ЗарегистрироватьНекорректныеРоли. -Процедура ЗаполнитьИменаНенайденныхРолей(НекорректныеРоли) - - Отбор = Новый Структура("ЭтоНенайденнаяРоль", Истина); - Строки = НекорректныеРоли.НайтиСтроки(Отбор); - Если Не ЗначениеЗаполнено(Строки) Тогда - Возврат; - КонецЕсли; - НенайденныеРоли = НекорректныеРоли.Скопировать(Строки, "РольСсылка"); - Ссылки = НенайденныеРоли.ВыгрузитьКолонку("РольСсылка"); - - Результат = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(Ссылки, - Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.Имя.Имя); - - Для Каждого Строка Из Строки Цикл - Строка.Роль = Результат.Получить(Строка.РольСсылка); - Если Не ЗначениеЗаполнено(Строка.Роль) Тогда - Строка.Роль = Строка(Строка.РольСсылка); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -Процедура ЗарегистрироватьНедоступнуюРоль(ОписаниеРоли, Профиль) - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Роль недоступна пользователю'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Ошибка, - Метаданные.Справочники.ПрофилиГруппДоступа, - Профиль, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При обновлении ролей пользователя ""%1"" - |роль ""%2"" - |%3 - |профиля групп доступа ""%4"" - |%5 - |недоступна пользователю.'"), - Строка(ОписаниеРоли.Пользователь), - ОписаниеРоли.Роль, - ПолучитьНавигационнуюСсылку(ОписаниеРоли.РольСсылка), - Строка(Профиль), - ПолучитьНавигационнуюСсылку(Профиль)), - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - -КонецПроцедуры - -Процедура ЗарегистрироватьНенайденнуюРоль(ОписаниеРоли, Профиль) - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Роль не найдена в метаданных'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Ошибка, - Метаданные.Справочники.ПрофилиГруппДоступа, - Профиль, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При обновлении ролей пользователя ""%1"" - |роль ""%2"" - |%3 - |профиля групп доступа ""%4"" - |%5 - |не существует в метаданных.'"), - Строка(ОписаниеРоли.Пользователь), - ОписаниеРоли.Роль, - ПолучитьНавигационнуюСсылку(ОписаниеРоли.РольСсылка), - Строка(Профиль), - ПолучитьНавигационнуюСсылку(Профиль)), - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - -КонецПроцедуры - -Процедура ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса) - - ВнешняяТранзакцияАктивна = ТранзакцияАктивна(); - ИзмененныеПользователи = Новый Массив; - СообщатьВМенеджерСервиса = ОбщегоНазначения.РазделениеВключено() - И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ПользователиВМоделиСервиса"); - - Для Каждого КлючИЗначение Из ОбновляемыеПользователиИБ Цикл - РолиДляДобавления = КлючИЗначение.Значение.РолиДляДобавления; - РолиДляУдаления = КлючИЗначение.Значение.РолиДляУдаления; - ПользовательИБ = КлючИЗначение.Значение.ПользовательИБ; - ПользовательСсылка = КлючИЗначение.Значение.ПользовательСсылка; - ИзмененныеПользователи.Добавить(ПользовательСсылка); - - Если СообщатьВМенеджерСервиса Тогда - БылиПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава); - БылиПраваНаВход = Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь); - КонецЕсли; - - Для Каждого КлючИЗначение Из РолиДляДобавления Цикл - ПользовательИБ.Роли.Добавить(Метаданные.Роли[КлючИЗначение.Ключ]); - КонецЦикла; - - Для Каждого КлючИЗначение Из РолиДляУдаления Цикл - ПользовательИБ.Роли.Удалить(КлючИЗначение.Значение); - КонецЦикла; - - НачатьТранзакцию(); - Попытка - ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, - ПользовательИБ, БылиПолныеПрава, БылиПраваНаВход, ПарольПользователяСервиса, ВнешняяТранзакцияАктивна); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - - Если ВнешняяТранзакцияАктивна Тогда - РегистрыСведений.СведенияОПользователях.ОбновитьДанныеРегистра(ИзмененныеПользователи); - КонецЕсли; - -КонецПроцедуры - -Процедура ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей() - - Отбор = Новый Структура("ИспользоватьОсновныеРолиДляВсехПользователей", Истина); - Расширения = РасширенияКонфигурации.Получить(Отбор); - РазделениеВключено = ОбщегоНазначения.РазделениеВключено(); - ТекущаяОбластьДействия = ?(ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных(), - ОбластьДействияРасширенияКонфигурации.РазделениеДанных, - ОбластьДействияРасширенияКонфигурации.ИнформационнаяБаза); - - Для Каждого Расширение Из Расширения Цикл - Если Не Расширение.ИспользоватьОсновныеРолиДляВсехПользователей - Или РазделениеВключено - И Расширение.ОбластьДействия <> ТекущаяОбластьДействия Тогда - Продолжить; - КонецЕсли; - Справочники.ВерсииРасширений.ОтключитьПредупрежденияБезопасности(Расширение); - Справочники.ВерсииРасширений.ОтключитьИспользованиеОсновныхРолейДляВсехПользователей(Расширение); - // АПК:280-выкл - №499.3.4 Допустимо пропустить обработку исключения, так как - // это не останавливающая операция и будет выполнена успешно при очередном обновлении ролей. - // Запись расширения не является транзакционной операцией, поэтому не создает ошибок в транзакции. - Попытка - Расширение.Записать(); - Исключение - // Обработка не требуется. - КонецПопытки; - // АПК:280-вкл. - КонецЦикла; - -КонецПроцедуры - -// Параметры: -// НекорректныеРоли - см. НовыеНекорректныеРоли -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * Пользователь - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// * РольСсылка - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// * Профиль - СправочникСсылка.ПрофилиГруппДоступа -// -Функция ПрофилиПользователейСРолями(НекорректныеРоли) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("НекорректныеРоли", НекорректныеРоли); - Запрос.УстановитьПараметр("ПустойИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | НекорректныеРоли.Пользователь КАК Пользователь, - | НекорректныеРоли.РольСсылка КАК РольСсылка - |ПОМЕСТИТЬ НекорректныеРоли - |ИЗ - | &НекорректныеРоли КАК НекорректныеРоли - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь, - | РольСсылка - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | НекорректныеРоли.Пользователь КАК Пользователь, - | НекорректныеРоли.РольСсылка КАК РольСсылка, - | Роли.Ссылка КАК Профиль - |ИЗ - | НекорректныеРоли КАК НекорректныеРоли - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.Пользователь = НекорректныеРоли.Пользователь) - | И (СоставыГруппПользователей.Используется) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) - | И (НЕ ГруппыДоступаПользователи.Ссылка.ПометкаУдаления) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК Роли - | ПО (Роли.Ссылка = ГруппыДоступаПользователи.Ссылка.Профиль) - | И (НЕ Роли.Ссылка.ПометкаУдаления) - | И (Роли.Роль = НекорректныеРоли.РольСсылка)"; - - Возврат Запрос.Выполнить().Выгрузить(); - -КонецФункции - -// Для процедуры ОбновитьРолиПользователейИБ. -Процедура ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, ПользовательИБ, - БылиПолныеПрава, БылиПраваНаВход, ПарольПользователяСервиса, ВнешняяТранзакцияАктивна) - - ПользователиСлужебный.ЗаписатьПользователяИнформационнойБазы(ПользовательИБ, - ТипЗнч(ПользовательСсылка) = Тип("СправочникСсылка.ВнешниеПользователи"), - ПользовательСсылка, - ?(ВнешняяТранзакцияАктивна, Null, Ложь)); - - Если БылиПолныеПрава = Неопределено Тогда - Возврат; - КонецЕсли; - - ЕстьПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава); - ЕстьПраваНаВход = Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь); - - Если ЕстьПолныеПрава = БылиПолныеПрава - И ЕстьПраваНаВход = БылиПраваНаВход - Или Не Пользователи.ВходВПрограммуРазрешен(ПользовательИБ) Тогда - Возврат; - КонецЕсли; - - МодульПользователиСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ПользователиСлужебныйВМоделиСервиса"); - - Если ЕстьПолныеПрава <> БылиПолныеПрава Тогда - Если ПарольПользователяСервиса = Неопределено Тогда - Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда - МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса"); - СеансЗапущенБезРазделителей = МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей(); - Иначе - СеансЗапущенБезРазделителей = Истина; - КонецЕсли; - Если Не СеансЗапущенБезРазделителей Тогда - УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); - - Если БылиПолныеПрава Тогда - Шаблон = НСтр("ru = 'Для отключения административного доступа пользователю ""%1"" требуется пароль текущего пользователя сервиса ""%2"".'"); - Иначе - Шаблон = НСтр("ru = 'Для установки административного доступа пользователю ""%1"" требуется пароль текущего пользователя сервиса ""%2"".'"); - КонецЕсли; - - Если БылиПолныеПрава И УпрощенныйИнтерфейс Тогда - Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке пользователя при отключении ему профиля Администратор.'"); - ИначеЕсли Не БылиПолныеПрава И УпрощенныйИнтерфейс Тогда - Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке пользователя при включении ему профиля Администратор.'"); - ИначеЕсли БылиПолныеПрава Тогда - Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке группы доступа Администраторы или в карточке пользователя при исключении его из группы доступа Администраторы.'"); - Иначе - Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке группы доступа Администраторы или в карточке пользователя при включении его в группу доступа Администраторы.'"); - КонецЕсли; - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, - ПользовательИБ.Имя, ПользователиИнформационнойБазы.ТекущийПользователь().Имя); - ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + Уточнение; - - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Иначе - МодульПользователиСлужебныйВМоделиСервиса.ЗаписатьПользователяСервиса(ПользовательСсылка, - Ложь, ПарольПользователяСервиса); - Возврат; - КонецЕсли; - КонецЕсли; - - Если ЕстьПраваНаВход <> БылиПраваНаВход Тогда - МодульПользователиСлужебныйВМоделиСервиса.СообщитьИзмененЗапускПриложения(ПользовательСсылка, - ПользовательИБ); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ТекстЗапросаВыбораИзменений. - -Функция КлючИЗначение(Структура) - - Для Каждого КлючИЗначение Из Структура Цикл - Возврат КлючИЗначение; - КонецЦикла; - - Возврат ""; - -КонецФункции - -// Для процедур ОбновитьНаборЗаписей, ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям. - -Процедура ЗаписатьОбъектИлиНаборЗаписей(Данные, ОбъектИлиНаборЗаписей) - - Если Данные.ОбновлениеИБ Тогда - ОбновлениеИнформационнойБазы.ЗаписатьДанные(ОбъектИлиНаборЗаписей); - Иначе - ОбъектИлиНаборЗаписей.Записать(); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ОбновитьНаборЗаписей и ОбновитьНаборыЗаписей. - -Функция ГруппаПараметровИзмеренияОбработана(ИмяИзмерения, ЗначенияИзмерения) - - Если ИмяИзмерения = Неопределено Тогда - ЗначенияИзмерения = Неопределено; - - ИначеЕсли ЗначенияИзмерения = Неопределено Тогда - ИмяИзмерения = Неопределено; - - ИначеЕсли ТипЗнч(ЗначенияИзмерения) <> Тип("Массив") - И ТипЗнч(ЗначенияИзмерения) <> Тип("ФиксированныйМассив") Тогда - - ЗначениеИзмерения = ЗначенияИзмерения; - ЗначенияИзмерения = Новый Массив; - ЗначенияИзмерения.Добавить(ЗначениеИзмерения); - - ИначеЕсли ЗначенияИзмерения.Количество() = 0 Тогда - Возврат Ложь; - КонецЕсли; - - Возврат Истина; - -КонецФункции - -Процедура УпорядочитьГруппыПараметровИзмерений(Данные) - - Если Данные.ИмяВторогоИзмерения = Неопределено Тогда - Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; - Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; - Данные.ИмяТретьегоИзмерения = Неопределено; - Данные.ЗначенияТретьегоИзмерения = Неопределено; - КонецЕсли; - - Если Данные.ИмяПервогоИзмерения = Неопределено Тогда - Данные.ИмяПервогоИзмерения = Данные.ИмяВторогоИзмерения; - Данные.ЗначенияПервогоИзмерения = Данные.ЗначенияВторогоИзмерения; - Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; - Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; - Данные.ИмяТретьегоИзмерения = Неопределено; - Данные.ЗначенияТретьегоИзмерения = Неопределено; - КонецЕсли; - - Если Данные.ЗначенияВторогоИзмерения <> Неопределено - И Данные.ЗначенияТретьегоИзмерения <> Неопределено - И Данные.ЗначенияВторогоИзмерения.Количество() - > Данные.ЗначенияТретьегоИзмерения.Количество() Тогда - - ИмяИзмерения = Данные.ИмяВторогоИзмерения; - ЗначенияИзмерения = Данные.ЗначенияВторогоИзмерения; - - Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; - Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; - Данные.ИмяТретьегоИзмерения = ИмяИзмерения; - Данные.ЗначенияТретьегоИзмерения = ЗначенияИзмерения; - КонецЕсли; - - Если Данные.ЗначенияПервогоИзмерения <> Неопределено - И Данные.ЗначенияВторогоИзмерения <> Неопределено - И Данные.ЗначенияПервогоИзмерения.Количество() - > Данные.ЗначенияВторогоИзмерения.Количество() Тогда - - ИмяИзмерения = Данные.ИмяПервогоИзмерения; - ЗначенияИзмерения = Данные.ЗначенияПервогоИзмерения; - - Данные.ИмяПервогоИзмерения = Данные.ИмяВторогоИзмерения; - Данные.ЗначенияПервогоИзмерения = Данные.ЗначенияВторогоИзмерения; - Данные.ИмяВторогоИзмерения = ИмяИзмерения; - Данные.ЗначенияВторогоИзмерения = ЗначенияИзмерения; - КонецЕсли; - -КонецПроцедуры - -Функция ПоляНабораЗаписей(НаборЗаписей) - - ПоляСравнения = ""; - Таблица = НаборЗаписей.Выгрузить(Новый Массив); - Для каждого Колонка Из Таблица.Колонки Цикл - ПоляСравнения = ПоляСравнения + "," + Колонка.Имя; - КонецЦикла; - ПоляСравнения = Сред(ПоляСравнения, 2); - - Возврат ПоляСравнения; - -КонецФункции - -Процедура ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям(Знач Данные, Знач Отбор, Знач СписокПолей, - Знач ИмяИзмерения, Знач ЗначенияИзмерения, ЕстьИзменения) - - ЗаблокироватьОбластьНабораЗаписей(Данные.НаборЗаписей, Данные.ПолноеИмяРегистра); - - Данные.НаборЗаписей.Прочитать(); - НовыеЗаписиНабора = Данные.НаборЗаписей.Выгрузить(); - НовыеЗаписиНабора.Индексы.Добавить(СписокПолей); - - Для каждого Значение Из ЗначенияИзмерения Цикл - Отбор[ИмяИзмерения] = Значение; - Для каждого НайденнаяЗапись Из НовыеЗаписиНабора.НайтиСтроки(Отбор) Цикл - НовыеЗаписиНабора.Удалить(НайденнаяЗапись); - КонецЦикла; - Для каждого НайденнаяЗапись Из Данные.НовыеЗаписи.НайтиСтроки(Отбор) Цикл - ЗаполнитьЗначенияСвойств(НовыеЗаписиНабора.Добавить(), НайденнаяЗапись); - КонецЦикла; - КонецЦикла; - - ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, - |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); - ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); - ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); - ТекущиеДанные.Вставить("НаборЗаписейПрочитан", Истина); - - ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); - -КонецПроцедуры - -Процедура ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Знач Данные, Знач Отбор, ЕстьИзменения) - - // Получение количества записей для чтения. - - Если Отбор.Количество() = 0 Тогда - ТекущиеНовыеЗаписи = Данные.НовыеЗаписи.Скопировать(); // ТаблицаЗначений - КоличествоДляЧтения = Данные.КоличествоДляЧтения; - Иначе - ТекущиеНовыеЗаписи = Данные.НовыеЗаписи.Скопировать(Отбор); // ТаблицаЗначений - - КоличествоПоЗначениям = Данные.КоличествоПоЗначениям; // ТаблицаЗначений - ИмяПоля = КоличествоПоЗначениям.Колонки[0].Имя; - СтрокаКоличества = Данные.КоличествоПоЗначениям.Найти(Отбор[ИмяПоля], ИмяПоля); - КоличествоДляЧтения = ?(СтрокаКоличества = Неопределено, 0, СтрокаКоличества.Количество); - КонецЕсли; - - ОтборНовойЗаписи = Новый Структура("ВидИзмененияСтроки, " + Данные.ПоляСравнения, 1); - ТекущиеНовыеЗаписи.Индексы.Добавить("ВидИзмененияСтроки, " + Данные.ПоляСравнения); - - КлючиЗаписей = ТекущиеНовыеЗаписи.Скопировать(, "ВидИзмененияСтроки, " + Данные.ПоляСравнения); - КлючиЗаписей.Свернуть("ВидИзмененияСтроки, " + Данные.ПоляСравнения); - КлючиЗаписей.Свернуть(Данные.ПоляСравнения, "ВидИзмененияСтроки"); - - ОтборПоКлючуЗаписи = Новый Структура(Данные.ПоляСравнения); - - Если ОбновлятьНаборЗаписейЦеликом(КоличествоДляЧтения, КлючиЗаписей) Тогда - - ЗаблокироватьОбластьНабораЗаписей(Данные.НаборЗаписей, Данные.ПолноеИмяРегистра); - Данные.НаборЗаписей.Прочитать(); - НовыеЗаписиНабора = Данные.НаборЗаписей.Выгрузить(); // ТаблицаЗначений - НовыеЗаписиНабора.Индексы.Добавить(Данные.ПоляСравнения); - - Для каждого Строка Из КлючиЗаписей Цикл - ЗаполнитьЗначенияСвойств(ОтборПоКлючуЗаписи, Строка); - НайденныеСтроки = НовыеЗаписиНабора.НайтиСтроки(ОтборПоКлючуЗаписи); - Если Строка.ВидИзмененияСтроки = -1 Тогда - Если НайденныеСтроки.Количество() > 0 Тогда - // Удаление старой строки. - НовыеЗаписиНабора.Удалить(НайденныеСтроки[0]); - КонецЕсли; - Иначе - // Добавление новой или обновление старой строки. - Если НайденныеСтроки.Количество() = 0 Тогда - ЗаполняемаяСтрока = НовыеЗаписиНабора.Добавить(); - Иначе - ЗаполняемаяСтрока = НайденныеСтроки[0]; - КонецЕсли; - ЗаполнитьЗначенияСвойств(ОтборНовойЗаписи, ОтборПоКлючуЗаписи); - НайденныеЗаписи = ТекущиеНовыеЗаписи.НайтиСтроки(ОтборНовойЗаписи); - Если НайденныеЗаписи.Количество() = 1 Тогда - НоваяЗапись = НайденныеЗаписи[0]; - Иначе // Ошибка в параметре НовыеЗаписи. - ИсключениеПриОшибкеПоискаЗаписи(Данные); - КонецЕсли; - ЗаполнитьЗначенияСвойств(ЗаполняемаяСтрока, НоваяЗапись); - КонецЕсли; - КонецЦикла; - // Изменение набора записей, чтобы он отличался от новых записей набора. - Если Данные.НаборЗаписей.Количество() = НовыеЗаписиНабора.Количество() Тогда - Данные.НаборЗаписей.Добавить(); - КонецЕсли; - - ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, - |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); - ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); - ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); - ТекущиеДанные.Вставить("НаборЗаписейПрочитан", Истина); - - ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); - Иначе - // Построчное обновление. - УстановитьДополнительныеСвойства(Данные.НаборДляОднойЗаписи, Данные.ДополнительныеСвойства); - Для каждого Строка Из КлючиЗаписей Цикл - Данные.НаборДляОднойЗаписи.Очистить(); - ЗаполнитьЗначенияСвойств(ОтборПоКлючуЗаписи, Строка); - Для каждого КлючИЗначение Из ОтборПоКлючуЗаписи Цикл - УстановитьОтбор( - Данные.НаборДляОднойЗаписи.Отбор[КлючИЗначение.Ключ], КлючИЗначение.Значение); - КонецЦикла; - ЗаблокироватьОбластьНабораЗаписей(Данные.НаборДляОднойЗаписи, Данные.ПолноеИмяРегистра); - Если Строка.ВидИзмененияСтроки > -1 Тогда - // Добавление новой или обновление существующей строки. - ЗаполнитьЗначенияСвойств(ОтборНовойЗаписи, ОтборПоКлючуЗаписи); - НайденныеЗаписи = ТекущиеНовыеЗаписи.НайтиСтроки(ОтборНовойЗаписи); - Если НайденныеЗаписи.Количество() = 1 Тогда - НоваяЗапись = НайденныеЗаписи[0]; - Иначе // Ошибка в параметре НовыеЗаписи. - ИсключениеПриОшибкеПоискаЗаписи(Данные); - КонецЕсли; - ЗаполнитьЗначенияСвойств(Данные.НаборДляОднойЗаписи.Добавить(), НоваяЗапись); - КонецЕсли; - ЕстьИзменения = Истина; - Если Данные.ТолькоПроверка Тогда - Возврат; - КонецЕсли; - ЗаписатьОбъектИлиНаборЗаписей(Данные, Данные.НаборДляОднойЗаписи); - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям. -Функция ОбновлятьНаборЗаписейЦеликом(КоличествоДляЧтения, КлючиЗаписей) - - Если КоличествоДляЧтения > 10000 Тогда - Возврат Ложь; // Слишком большой набор записей. - КонецЕсли; - - КоличествоУдаляемых = КлючиЗаписей.НайтиСтроки( - Новый Структура("ВидИзмененияСтроки", -1)).Количество(); - - КоличествоДобавляемых = КлючиЗаписей.НайтиСтроки( - Новый Структура("ВидИзмененияСтроки", 1)).Количество(); - - КоличествоДляЗаписи = КоличествоДляЧтения - КоличествоУдаляемых - + КоличествоДобавляемых; - - Если КоличествоДляЗаписи > 10000 Тогда - Возврат Ложь; // Слишком большой набор записей. - КонецЕсли; - - КоличествоИзменяемых = КлючиЗаписей.Количество() - - (КоличествоУдаляемых + КоличествоДобавляемых); - - КоличествоНеизменных = КоличествоДляЧтения - - (КоличествоУдаляемых + КоличествоИзменяемых); - - ЗатратыНаПерезаписьЦеликом = - // Операции: |Чтение|Удаление|Вставка| - КоличествоУдаляемых * ( 0.05 + 0.1 ) - + КоличествоИзменяемых * ( 0.05 + 0.1 + 1 ) - + КоличествоДобавляемых * ( 1 ) - + КоличествоНеизменных * ( 0.05 + 0.1 + 1 ); - - ЗатратыНаПерезаписьПоОднойЗаписи = - // Операции: |Удаление|Вставка| - КоличествоУдаляемых * ( 0.5 ) - + КоличествоИзменяемых * ( 0.5 + 1.2 ) - + КоличествоДобавляемых * ( 0.5 + 1.2 ); - - Возврат ЗатратыНаПерезаписьЦеликом < ЗатратыНаПерезаписьПоОднойЗаписи; - -КонецФункции - -Процедура ИсключениеПриОшибкеПоискаЗаписи(Параметры) - - Для каждого СтрокаИзменений Из Параметры.НовыеЗаписи Цикл - Если СтрокаИзменений.ВидИзмененияСтроки <> 1 - И СтрокаИзменений.ВидИзмененияСтроки <> -1 Тогда - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в процедуре %1 - |общего модуля %2. - | - |Неверное значение параметра %3 - колонка - |%4 содержит недопустимое значение ""%5"". - | - |Допустимо только 2 значения: ""1"" и ""-1"".'"), - "ОбновитьНаборыЗаписей", - "УправлениеДоступомСлужебный", - "НовыеЗаписи", - "ВидИзмененияСтроки", - Строка(СтрокаИзменений.ВидИзмененияСтроки)); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - КонецЦикла; - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в процедуре %1 - |общего модуля %2. - | - |Не удалось найти требуемую в строку - |в значении параметра %3.'"), - "ОбновитьНаборыЗаписей", - "УправлениеДоступомСлужебный", - "НовыеЗаписи"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - -КонецПроцедуры - -Процедура ЗаблокироватьОбластьНабораЗаписей(НаборЗаписей, ПолноеИмяРегистра = Неопределено) - - Если НЕ ТранзакцияАктивна() Тогда - Возврат; - КонецЕсли; - - Если ПолноеИмяРегистра = Неопределено Тогда - ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(НаборЗаписей)).ПолноеИмя(); - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); - Для каждого ЭлементОтбора Из НаборЗаписей.Отбор Цикл - Если ЭлементОтбора.Использование Тогда - ЭлементБлокировки.УстановитьЗначение(ЭлементОтбора.ПутьКДанным, ЭлементОтбора.Значение); - КонецЕсли; - КонецЦикла; - Блокировка.Заблокировать(); - -КонецПроцедуры - -Процедура УстановитьОтбор(ЭлементОтбора, ЗначениеОтбора) - - Попытка - ЭлементОтбора.Значение = ЗначениеОтбора; - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ВсеТипы = Новый Массив; - Для Каждого Тип Из ЭлементОтбора.ТипЗначения.Типы() Цикл - ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); - ВсеТипы.Добавить(Строка(Тип) + ?(ОбъектМетаданных = Неопределено, - "", " (" + ОбъектМетаданных.ПолноеИмя() + ")")); - КонецЦикла; - СвойстваОтбора = Новый Массив; - СвойстваОтбора.Добавить("Имя" + " = " + ЭлементОтбора.Имя); - СвойстваОтбора.Добавить("ПутьКДанным" + " = " + ЭлементОтбора.ПутьКДанным); - СвойстваОтбора.Добавить("ТипЗначения" + " = " + Символы.ПС + Символы.Таб - + СтрСоединить(ВсеТипы, Символы.ПС + Символы.Таб)); - МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеОтбора)); - Попытка - Если МетаданныеЗначения <> Неопределено Тогда - НавигационнаяСсылка = ПолучитьНавигационнуюСсылку(ЗначениеОтбора); - Иначе - НавигационнаяСсылка = ""; - КонецЕсли; - Исключение - НавигационнаяСсылка = ""; - КонецПопытки; - Попытка - ВнутренняяСтрока = ЗначениеВСтрокуВнутр(ЗначениеОтбора); - Исключение - ВнутренняяСтрока = ""; - КонецПопытки; - ДляАдминистратора = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось установить значение ""%1"" тип ""%2"" - | Навигационная ссылка: %3 - | Внутренняя строка: %4 - |в элемент отбора со свойствами: - |%5'"), - Строка(ЗначениеОтбора), - Строка(ТипЗнч(ЗначениеОтбора)) + ?(МетаданныеЗначения = Неопределено, - "", " (" + МетаданныеЗначения.ПолноеИмя() + ")"), - НавигационнаяСсылка, - ВнутренняяСтрока, - СтрСоединить(СвойстваОтбора, Символы.ПС)); - Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке); - Попытка - ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,, ДляАдминистратора, ИнформацияОбОшибке); - Исключение - ЗаписьЖурналаРегистрации(НСтр("ru = 'Ошибка выполнения'", ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Ошибка,,, - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); - ВызватьИсключение; - КонецПопытки; - КонецПопытки; - - ЭлементОтбора.Использование = Истина; - -КонецПроцедуры - -Функция ЗаписьНесколькимиНаборами(Данные, Отбор, ИмяПоля, ЗначенияПоля) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ЗначенияПоля", ЗначенияПоля); - Запрос.Текст = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | &УсловиеОтбора - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | ТекущаяТаблица.ИмяПоля В(&ЗначенияПоля) - | И &УсловиеОтбора - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ТекущаяТаблица.ИмяПоля КАК ИмяПоля, - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | ТекущаяТаблица.ИмяПоля В(&ЗначенияПоля) - | И &УсловиеОтбора - | - |СГРУППИРОВАТЬ ПО - | ТекущаяТаблица.ИмяПоля"; - - УсловиеОтбора = "ИСТИНА"; - Если Данные.ФиксированныйОтбор <> Неопределено Тогда - Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл - УсловиеОтбора = УсловиеОтбора + " - | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 - Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - КонецЕсли; - - ОтборДобавляемых = Новый Структура; - ОтборДобавляемых.Вставить("ВидИзмененияСтроки", 1); - ОтборУдаляемых = Новый Структура; - ОтборУдаляемых.Вставить("ВидИзмененияСтроки", -1); - - Для каждого КлючИЗначение Из Отбор Цикл - УсловиеОтбора = УсловиеОтбора + " - | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 - Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); - ОтборДобавляемых.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - ОтборУдаляемых.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "ИмяПоля", ИмяПоля); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Данные.ПолноеИмяРегистра); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", УсловиеОтбора); - - РезультатыЗапросов = Запрос.ВыполнитьПакет(); - - // Количество всех без отбора. - КоличествоВсех = РезультатыЗапросов[0].Выгрузить()[0].Количество; - Данные.Вставить("КоличествоДляЧтения", КоличествоВсех); - - // Количество обновляемых с отбором. - КоличествоОбновляемых = РезультатыЗапросов[1].Выгрузить()[0].Количество; - - КоличествоДобавляемых = Данные.НовыеЗаписи.НайтиСтроки(ОтборДобавляемых).Количество(); - Если КоличествоДобавляемых > КоличествоОбновляемых Тогда - КоличествоОбновляемых = КоличествоДобавляемых; - КонецЕсли; - - КоличествоУдаляемых = Данные.НовыеЗаписи.НайтиСтроки(ОтборУдаляемых).Количество(); - Если КоличествоУдаляемых > КоличествоОбновляемых Тогда - КоличествоОбновляемых = КоличествоУдаляемых; - КонецЕсли; - - // Количество для чтения по значениям отбора. - КоличествоПоЗначениям = РезультатыЗапросов[2].Выгрузить(); - КоличествоПоЗначениям.Индексы.Добавить(ИмяПоля); - Данные.Вставить("КоличествоПоЗначениям", КоличествоПоЗначениям); - - Возврат КоличествоВсех * 0.7 > КоличествоОбновляемых; - -КонецФункции - -Процедура ПрочитатьКоличествоДляЧтения(Данные) - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | &УсловиеОтбора"; - - УсловиеОтбора = "ИСТИНА"; - Если Данные.ФиксированныйОтбор <> Неопределено Тогда - Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл - УсловиеОтбора = УсловиеОтбора + " - | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 - Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - КонецЕсли; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Данные.ПолноеИмяРегистра); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", УсловиеОтбора); - - Данные.Вставить("КоличествоДляЧтения", Запрос.Выполнить().Выгрузить()[0].Количество); - -КонецПроцедуры - -Процедура УстановитьДополнительныеСвойства(НаборЗаписей, ДополнительныеСвойства) - - Если ТипЗнч(ДополнительныеСвойства) = Тип("Структура") Тогда - Для каждого КлючИЗначение Из ДополнительныеСвойства Цикл - НаборЗаписей.ДополнительныеСвойства.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбновитьРегистрСведений. - -Функция ЗначенияКолонкиТаблицы(Таблица, ИмяКолонки) - - НоваяТаблица = Таблица.Скопировать(, ИмяКолонки); - - НоваяТаблица.Свернуть(ИмяКолонки); - - Возврат НоваяТаблица.ВыгрузитьКолонку(ИмяКолонки); - -КонецФункции - -// Обслуживание таблиц ВидыДоступа и ЗначенияДоступа в формах редактирования. - -Процедура ДобавитьРеквизитыВспомогательныхДанныхВФорму(Форма, ИмяРеквизитаХранилищаТаблиц) - - ДобавляемыеРеквизиты = Новый Массив; - ОписаниеТиповЗначенийДоступа = Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип; - - ПутьКОбъекту = ?(ЗначениеЗаполнено(ИмяРеквизитаХранилищаТаблиц), ИмяРеквизитаХранилищаТаблиц + ".", ""); - - // Добавление реквизитов в таблицу ВидыДоступа. - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "Используется", Новый ОписаниеТипов("Булево"), ПутьКОбъекту + "ВидыДоступа")); - - // Добавление отдельных реквизитов. - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ТекущийВидДоступа", ОписаниеТиповЗначенийДоступа)); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ТекущиеТипыВыбираемыхЗначений", Новый ОписаниеТипов("СписокЗначений"))); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ТекущийТипВыбираемыхЗначений", ОписаниеТиповЗначенийДоступа)); - - Если НЕ РеквизитФормыСуществует(Форма, "ИспользоватьВнешнихПользователей") Тогда - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ИспользоватьВнешнихПользователей", Новый ОписаниеТипов("Булево"))); - КонецЕсли; - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ИмяРеквизитаХранилищаТаблиц", Новый ОписаниеТипов("Строка"))); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ЭтоПрофильГруппДоступа", Новый ОписаниеТипов("Булево"))); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ВидДоступаПользователи", ОписаниеТиповЗначенийДоступа)); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ВидДоступаВнешниеПользователи", ОписаниеТиповЗначенийДоступа)); - - // Добавление таблицы ВсеВидыДоступа. - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ВсеВидыДоступа", Новый ОписаниеТипов("ТаблицаЗначений"))); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "Ссылка", ОписаниеТиповЗначенийДоступа, "ВсеВидыДоступа")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "Представление", Новый ОписаниеТипов("Строка"), "ВсеВидыДоступа")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "Используется", Новый ОписаниеТипов("Булево"), "ВсеВидыДоступа")); - - // Добавление таблицы ПредставленияВсеРазрешены. - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ПредставленияВсеРазрешены", Новый ОписаниеТипов("ТаблицаЗначений"))); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "Имя", Новый ОписаниеТипов("Строка"), "ПредставленияВсеРазрешены")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "Представление", Новый ОписаниеТипов("Строка"), "ПредставленияВсеРазрешены")); - - // Добавление таблицы ВсеТипыВыбираемыхЗначений. - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ВсеТипыВыбираемыхЗначений", Новый ОписаниеТипов("ТаблицаЗначений"))); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ВидДоступа", ОписаниеТиповЗначенийДоступа, "ВсеТипыВыбираемыхЗначений")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ТипЗначений", ОписаниеТиповЗначенийДоступа, "ВсеТипыВыбираемыхЗначений")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ПредставлениеТипа", Новый ОписаниеТипов("Строка"), "ВсеТипыВыбираемыхЗначений")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ИмяТаблицы", Новый ОписаниеТипов("Строка"), "ВсеТипыВыбираемыхЗначений")); - - ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( - "ИерархияЭлементов", Новый ОписаниеТипов("Булево"), "ВсеТипыВыбираемыхЗначений")); - - Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты); - -КонецПроцедуры - -Процедура ЗаполнитьТаблицуВсеВидыДоступаВФорме(Форма) - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ВсеВидыДоступа = Форма.ВсеВидыДоступа; - ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); - - Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл - Строка = ВсеВидыДоступа.Добавить(); - Строка.Ссылка = СвойстваВидаДоступа.Ссылка; - Строка.Используется = ИспользуемыеВидыДоступа.Получить(Строка.Ссылка) <> Неопределено; - // Обеспечение уникальности представлений. - Представление = ПредставлениеВидаДоступа(СвойстваВидаДоступа); - Отбор = Новый Структура("Представление", Представление); - Пока ВсеВидыДоступа.НайтиСтроки(Отбор).Количество() > 0 Цикл - Отбор.Представление = Отбор.Представление + " "; - КонецЦикла; - Строка.Представление = Отбор.Представление; - КонецЦикла; - -КонецПроцедуры - -Процедура ЗаполнитьТаблицуПредставленияВсеРазрешеныВФорме(Форма, ЭтоПрофиль) - - ПредставленияВсеРазрешены = Форма.ПредставленияВсеРазрешены; - - Если ЭтоПрофиль Тогда - Строка = ПредставленияВсеРазрешены.Добавить(); - Строка.Имя = "ВначалеВсеЗапрещены"; - Строка.Представление = НСтр("ru = 'Все запрещены, исключения назначаются в группах доступа'"); - - Строка = ПредставленияВсеРазрешены.Добавить(); - Строка.Имя = "ВначалеВсеРазрешены"; - Строка.Представление = НСтр("ru = 'Все разрешены, исключения назначаются в группах доступа'"); - - Строка = ПредставленияВсеРазрешены.Добавить(); - Строка.Имя = "ВсеЗапрещены"; - Строка.Представление = НСтр("ru = 'Все запрещены, исключения назначаются в профиле'"); - - Строка = ПредставленияВсеРазрешены.Добавить(); - Строка.Имя = "ВсеРазрешены"; - Строка.Представление = НСтр("ru = 'Все разрешены, исключения назначаются в профиле'"); - Иначе - Строка = ПредставленияВсеРазрешены.Добавить(); - Строка.Имя = "ВсеЗапрещены"; - Строка.Представление = НСтр("ru = 'Все запрещены'"); - - Строка = ПредставленияВсеРазрешены.Добавить(); - Строка.Имя = "ВсеРазрешены"; - Строка.Представление = НСтр("ru = 'Все разрешены'"); - КонецЕсли; - - СписокВыбора = Форма.Элементы.ВидыДоступаВсеРазрешеныПредставление.СписокВыбора; // СписокЗначений - - Для каждого Строка Из ПредставленияВсеРазрешены Цикл - СписокВыбора.Добавить(Строка.Представление); - КонецЦикла; - -КонецПроцедуры - -Процедура ОформитьТаблицуВидыДоступаВФорме(Форма) - - Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма); - - // Оформление отображения неиспользуемых видов доступа. - ЭлементУсловногоОформления = Форма.УсловноеОформление.Элементы.Добавить(); - - ЭлементЦветаОформления = ЭлементУсловногоОформления.Оформление.Элементы.Найти("TextColor"); - ЭлементЦветаОформления.Значение = WebЦвета.Серый; - ЭлементЦветаОформления.Использование = Истина; - - ГруппаЭлементовОтбораДанных = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных")); - ГруппаЭлементовОтбораДанных.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ; - ГруппаЭлементовОтбораДанных.Использование = Истина; - - ЭлементОтбораДанных = ГруппаЭлементовОтбораДанных.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); - ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ВидыДоступа.ВидДоступа"); - ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.НеРавно; - ЭлементОтбораДанных.ПравоеЗначение = Неопределено; - ЭлементОтбораДанных.Использование = Истина; - - ЭлементОтбораДанных = ГруппаЭлементовОтбораДанных.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); - ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ВидыДоступа.Используется"); - ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; - ЭлементОтбораДанных.ПравоеЗначение = Ложь; - ЭлементОтбораДанных.Использование = Истина; - - ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить(); - ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("ВидыДоступа"); - ЭлементОформляемогоПоля.Использование = Истина; - -КонецПроцедуры - -Процедура ОформитьТаблицуЗначенияДоступаВФорме(Форма) - - Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма); - ПустыеСсылкиЗначенийДоступа = ПустыеСсылкиЗначенийДоступа(); - - // Оформление отображения пустых ссылок значений доступа. - Для Каждого Строка Из ПустыеСсылкиЗначенийДоступа Цикл - ЭлементУсловногоОформления = Форма.УсловноеОформление.Элементы.Добавить(); - - ЭлементОформленияТекст = ЭлементУсловногоОформления.Оформление.Элементы.Найти("Text"); - ЭлементОформленияТекст.Значение = Строка.Представление; - ЭлементОформленияТекст.Использование = Истина; - - ЭлементОтбораДанных = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); - ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ЗначенияДоступа.ЗначениеДоступа"); - ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; - ЭлементОтбораДанных.ПравоеЗначение = Строка.ПустаяСсылка; - ЭлементОтбораДанных.Использование = Истина; - - ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить(); - ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("ЗначенияДоступаЗначениеДоступа"); - ЭлементОформляемогоПоля.Использование = Истина; - КонецЦикла; - -КонецПроцедуры - -Процедура УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект = Неопределено) - - Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект); - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ПоТипамГруппИЗначений = СвойстваВидовДоступа.ПоТипамГруппИЗначений; - - Отбор = УправлениеДоступомСлужебныйКлиентСервер.ОтборВТаблицахФормыРедактированияРазрешенныхЗначений( - Форма, ""); - - Индекс = Параметры.ЗначенияДоступа.Количество()-1; - Пока Индекс >= 0 Цикл - ЗначениеДоступа = Параметры.ЗначенияДоступа[Индекс].ЗначениеДоступа; - - СвойстваВидаДоступа = ПоТипамГруппИЗначений.Получить(ТипЗнч(ЗначениеДоступа)); // См. СвойстваВидаДоступа - Если СвойстваВидаДоступа <> Неопределено Тогда - ЗаполнитьЗначенияСвойств(Отбор, Параметры.ЗначенияДоступа[Индекс]); - Отбор.Вставить("ВидДоступа", СвойстваВидаДоступа.Ссылка); - КонецЕсли; - - Если СвойстваВидаДоступа = Неопределено - ИЛИ Параметры.ЗначенияДоступа[Индекс].ВидДоступа <> Отбор.ВидДоступа - ИЛИ Параметры.ВидыДоступа.НайтиСтроки(Отбор).Количество() = 0 Тогда - - Параметры.ЗначенияДоступа.Удалить(Индекс); - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - -КонецПроцедуры - -Процедура УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект = Неопределено) - - Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект); - - Индекс = Параметры.ВидыДоступа.Количество()-1; - Пока Индекс >= 0 Цикл - ВидДоступа = Параметры.ВидыДоступа[Индекс].ВидДоступа; - Если СвойстваВидаДоступа(ВидДоступа) = Неопределено Тогда - Параметры.ВидыДоступа.Удалить(Индекс); - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - - УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект); - -КонецПроцедуры - -Функция ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект = Неопределено) - - Возврат УправлениеДоступомСлужебныйКлиентСервер.ПараметрыФормыРедактированияРазрешенныхЗначений( - Форма, ТекущийОбъект); - -КонецФункции - -Функция РеквизитФормыСуществует(Форма, ИмяРеквизита) - - Структура = Новый Структура(ИмяРеквизита, Null); - - ЗаполнитьЗначенияСвойств(Структура, Форма); - - Возврат Структура[ИмяРеквизита] <> Null; - -КонецФункции - -Функция ПустыеСсылкиЗначенийДоступа() Экспорт - - Таблица = Новый ТаблицаЗначений; - Таблица.Колонки.Добавить("ПустаяСсылка", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - Таблица.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка", - ,,, Новый КвалификаторыСтроки(150, ДопустимаяДлина.Переменная))); - - Для Каждого Тип Из Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип.Типы() Цикл - Типы = Новый Массив; - Типы.Добавить(Тип); - ОписаниеТипа = Новый ОписаниеТипов(Типы); - НоваяСтрока = Таблица.Добавить(); - НоваяСтрока.ПустаяСсылка = ОписаниеТипа.ПривестиЗначение(Неопределено); - НоваяСтрока.Представление = "<" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Пустая ссылка %1'"), Строка(Тип)) + ">"; - КонецЦикла; - - Возврат Таблица; - -КонецФункции - -// Для процедуры УстановкаПараметровСеанса. - -Функция ВсеКомбинацииВидовДоступа(НеупорядоченныйМассивИмен) - - // Ограничение на максимальную длину комбинации, чтобы не допустить - // перегрузку параметров сеанса и препроцессора шаблонов ОДД. - МаксимальнаяДлинаКомбинации = 4; - - Список = Новый СписокЗначений; - Если ТипЗнч(НеупорядоченныйМассивИмен) = Тип("ФиксированныйМассив") Тогда - Список.ЗагрузитьЗначения(Новый Массив(НеупорядоченныйМассивИмен)); - Иначе - Список.ЗагрузитьЗначения(НеупорядоченныйМассивИмен); - КонецЕсли; - Список.СортироватьПоЗначению(); - МассивИмен = Список.ВыгрузитьЗначения(); - - ИтогСтроки = Новый Массив; - ИтогСтрока = Новый Массив; - - // Полный список поддерживается всегда. - Для каждого Имя Из МассивИмен Цикл - ИтогСтрока.Добавить(Имя); - КонецЦикла; - - ИтогСтроки.Добавить(ИтогСтрока); - - Если МассивИмен.Количество() < 3 Тогда - Возврат ГруппыСтрокВСтроку(ИтогСтроки); - КонецЕсли; - - ПервоеИмя = МассивИмен[0]; - МассивИмен.Удалить(0); - - ПоследнееИмя = МассивИмен[МассивИмен.Количество()-1]; - МассивИмен.Удалить(МассивИмен.Количество()-1); - - КоличествоИменВКомбинации = МассивИмен.Количество(); - - Если КоличествоИменВКомбинации > 1 Тогда - - Если (КоличествоИменВКомбинации-1) <= МаксимальнаяДлинаКомбинации Тогда - ДлинаКомбинации = КоличествоИменВКомбинации-1; - Иначе - ДлинаКомбинации = МаксимальнаяДлинаКомбинации; - КонецЕсли; - - ПозицииИменВКомбинации = Новый Массив; - Для Счетчик = 1 По ДлинаКомбинации Цикл - ПозицииИменВКомбинации.Добавить(Счетчик); - КонецЦикла; - - Пока ДлинаКомбинации > 0 Цикл - Пока Истина Цикл - // Добавление комбинации из текущих позиций. - ИтогСтрока = Новый Массив; - ИтогСтрока.Добавить(ПервоеИмя); - Для Индекс = 0 По ДлинаКомбинации-1 Цикл - ИтогСтрока.Добавить(МассивИмен[ПозицииИменВКомбинации[Индекс]-1]); - КонецЦикла; - ИтогСтрока.Добавить(ПоследнееИмя); - ИтогСтроки.Добавить(ИтогСтрока); - // Продвижение позиции в комбинации. - Индекс = ДлинаКомбинации-1; - Пока Индекс >= 0 Цикл - Если ПозицииИменВКомбинации[Индекс] < КоличествоИменВКомбинации - (ДлинаКомбинации - (Индекс+1)) Тогда - ПозицииИменВКомбинации[Индекс] = ПозицииИменВКомбинации[Индекс] + 1; - // Заполнение старших позиций начальными значениями. - Для ИндексСтаршейПозиции = Индекс+1 По ДлинаКомбинации-1 Цикл - ПозицииИменВКомбинации[ИндексСтаршейПозиции] = - ПозицииИменВКомбинации[Индекс] + ИндексСтаршейПозиции - Индекс; - КонецЦикла; - Прервать; - Иначе - Индекс = Индекс - 1; - КонецЕсли; - КонецЦикла; - Если Индекс < 0 Тогда - Прервать; - КонецЕсли; - КонецЦикла; - ДлинаКомбинации = ДлинаКомбинации - 1; - Для Индекс = 0 По ДлинаКомбинации - 1 Цикл - ПозицииИменВКомбинации[Индекс] = Индекс + 1; - КонецЦикла; - КонецЦикла; - КонецЕсли; - - ИтогСтрока = Новый Массив; - ИтогСтрока.Добавить(ПервоеИмя); - ИтогСтрока.Добавить(ПоследнееИмя); - ИтогСтроки.Добавить(ИтогСтрока); - - Возврат ГруппыСтрокВСтроку(ИтогСтроки); - -КонецФункции - -Функция ГруппыСтрокВСтроку(ГруппыСтрок) - - ИтогСтроки = Новый Массив; - - Для Каждого ИтогСтрока Из ГруппыСтрок Цикл - ИтогСтроки.Добавить(СтрСоединить(ИтогСтрока, ",")); - КонецЦикла; - - Строки = СтрСоединить( - ИтогСтроки, - ", - |,"); - - Шаблон = - "%2%1%2 - |"; - - Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, Строки, ","); - -КонецФункции - -// Для процедур ОбновитьНаборыЗначенийДоступа, ПриИзмененииНаборовЗначенийДоступа. - -// Проверяет, что наборы в табличной части отличаются от новых наборов. -Функция НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаОбъект, НовыеНаборы) - - СтарыеНаборы = ОбщегоНазначения.ЗначениеРеквизитаОбъекта( - СсылкаНаОбъект, "НаборыЗначенийДоступа").Выгрузить(); - - Если СтарыеНаборы.Количество() <> НовыеНаборы.Количество() Тогда - Возврат Истина; - КонецЕсли; - - СтарыеНаборы.Колонки.Добавить("ВидДоступа", Новый ОписаниеТипов("Строка")); - УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( - СтарыеНаборы, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); - - ПоляПоиска = "НомерНабора, ЗначениеДоступа, Уточнение, Чтение, Изменение"; - - НовыеНаборы.Индексы.Добавить(ПоляПоиска); - Отбор = Новый Структура(ПоляПоиска); - - Для каждого Строка Из СтарыеНаборы Цикл - ЗаполнитьЗначенияСвойств(Отбор, Строка); - Если НовыеНаборы.НайтиСтроки(Отбор).Количество() <> 1 Тогда - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для функции РазрешенныеЗначенияДляДинамическогоСписка. -Процедура ДобавитьЗапросВПакет(ТекстПакета, ТекстЗапроса) - - Разделитель = - " - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |"; - - ТекстПакета = ТекстПакета + Разделитель + ТекстЗапроса; - -КонецПроцедуры - -// Для функции РазрешенныеЗначенияДляДинамическогоСписка. -Процедура ОбъединитьЗапросСЗапросом(ТекстЗапроса, ДобавляемыйТекстЗапроса) - - Объединитель = - " - | - |ОБЪЕДИНИТЬ ВСЕ - | - |"; // @query-part-1 - - ТекстЗапроса = ТекстЗапроса + Объединитель + ДобавляемыйТекстЗапроса; - -КонецПроцедуры - -// Обновление свойств видов доступа. - -// Для функций ПроверенныеСвойстваВидовДоступаСеанса, ПредставлениеВидовДоступа. -// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * Имя - Строка -// * Представление - Строка -// * ТипЗначений - Тип -// * ТипГруппЗначений - Тип -// * НесколькоГруппЗначений - Булево -// * ДополнительныеТипы - см. НоваяТаблицаДополнительныеТипыВидаДоступа -// -Функция ЗаполненныеВидыДоступаСеанса() - - // 1. Заполнение данных, указанных при внедрении. - - ВидыДоступа = Новый ТаблицаЗначений; - ВидыДоступа.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка")); - ВидыДоступа.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка")); - ВидыДоступа.Колонки.Добавить("ТипЗначений", Новый ОписаниеТипов("Тип")); - ВидыДоступа.Колонки.Добавить("ТипГруппЗначений", Новый ОписаниеТипов("Тип")); - ВидыДоступа.Колонки.Добавить("НесколькоГруппЗначений", Новый ОписаниеТипов("Булево")); - ВидыДоступа.Колонки.Добавить("ДополнительныеТипы", Новый ОписаниеТипов("ТаблицаЗначений")); - - ИнтеграцияПодсистемБСП.ПриЗаполненииВидовДоступа(ВидыДоступа); - УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа(ВидыДоступа); - - Возврат ВидыДоступа; - -КонецФункции - -// Для функции ЗаполненныеВидыДоступаСеанса и -// процедуры ДобавитьДополнительныеТипыВидаДоступа общего модуля УправлениеДоступом. -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * ТипЗначений - Тип -// * ТипГруппЗначений - Тип -// * НесколькоГруппЗначений - Булево -// -Функция НоваяТаблицаДополнительныеТипыВидаДоступа() Экспорт - - ДополнительныеТипы = Новый ТаблицаЗначений; - ДополнительныеТипы.Колонки.Добавить("ТипЗначений", Новый ОписаниеТипов("Тип")); - ДополнительныеТипы.Колонки.Добавить("ТипГруппЗначений", Новый ОписаниеТипов("Тип")); - ДополнительныеТипы.Колонки.Добавить("НесколькоГруппЗначений", Новый ОписаниеТипов("Булево")); - - Возврат ДополнительныеТипы; - -КонецФункции - -// Для процедур ПриЗаполненииВсехПараметровРаботыРасширений и -// ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации. -// -Процедура ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений() - - Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); - НовоеЗначение = Кэш.ХешСуммы; - - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа"; - СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); - - Если СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа - = НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа Тогда - Возврат; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); - ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - УжеИзменен = Ложь; - СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); - СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); - Если СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа - <> НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа Тогда - Если УжеИзменен Тогда - ПроверитьАктуальностьМетаданных(); - КонецЕсли; - РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); - РегистрыСведений.НаборыЗначенийДоступа.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. -// Смотри также заполнение в функции ПроверенныеСвойстваВидовДоступаСеанса. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * Массив - ФиксированныйМассив из см. СвойстваВидаДоступа -// * ПоИменам - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Строка -// ** Значение - см. СвойстваВидаДоступа -// * ПоСсылкам - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка -// ** Значение - см. СвойстваВидаДоступа -// * ПоТипамЗначений - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. СвойстваВидаДоступа -// * ПоТипамГруппИЗначений - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. СвойстваВидаДоступа -// * ПоТипамЗначенийСИерархией - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. СвойстваВидаДоступа -// * ЗначенияДоступаСГруппами - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. ЗначенияДоступаСГруппами -// * БезГруппДляЗначенияДоступа - ФиксированныйМассив из Строка -// * СОднойГруппойДляЗначенияДоступа - ФиксированныйМассив из Строка -// * ТипыЗначенийДоступаСГруппами - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - СправочникСсылка -// -Функция СвойстваВидовДоступа() Экспорт - - Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); - - ТекущаяДатаСеанса = ТекущаяДатаСеанса(); - Если Кэш.Проверка.Дата + 3 > ТекущаяДатаСеанса Тогда - Возврат Кэш.СвойстваСеанса; - КонецЕсли; - - НовоеЗначение = Кэш.ХешСуммы; - - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа"; - СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); - - Если СтароеЗначение.ХешСумма <> НовоеЗначение.ХешСумма Тогда - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); - ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - УжеИзменен = Ложь; - СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); - СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); - Если СтароеЗначение.ХешСумма <> НовоеЗначение.ХешСумма Тогда - Если УжеИзменен Тогда - ПроверитьАктуальностьМетаданных(); - КонецЕсли; - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - - Кэш.Проверка.Дата = ТекущаяДатаСеанса; - - Возврат Кэш.СвойстваСеанса; - -КонецФункции - -// Для процедуры УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса. -// Возвращает свойства видов доступа, заполняемых при внедрении в процедуре ПриЗаполненииВидовДоступа -// общего модуля УправлениеДоступомПереопределяемый и одноименных обработчиках этого события. -// -// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. -// -// Параметры: -// ХешСуммы - см. НовыеХешСуммыСвойствВидовДоступа -// -// Возвращаемое значение: -// см. СвойстваВидовДоступа -// -Функция ПроверенныеСвойстваВидовДоступаСеанса(ХешСуммы) Экспорт - - ВидыДоступа = ЗаполненныеВидыДоступаСеанса(); - - // 1. Проверки: - // - тип значений доступа не указан для 2-х видов доступа - // - тип значений доступа Пользователи, ГруппыПользователей используется только для вида доступа Пользователи - // - тип значений доступа ВнешниеПользователи, ГруппыВнешнихПользователей используется только для вида доступа - // ВнешниеПользователи - // - имена видов доступа Объект, Условие, НастройкиПрав, ПравоЧтения, ПравоИзменения не указаны - // - тип групп значений не совпадает с типом значений. - // - // 2. Подготовка различных коллекций свойств видов доступа, используемых при работе программы. - - МассивСвойств = Новый Массив; // Массив из см. СвойстваВидаДоступа - ПоСсылкам = Новый Соответствие; - ПоИменам = Новый Соответствие; - ПоТипамЗначений = Новый Соответствие; - ПоТипамГруппИЗначений = Новый Соответствие; - - ЗначенияДоступаСГруппами = ЗначенияДоступаСГруппами(); - - Параметры = Новый Структура; - Параметры.Вставить("ОпределяемыеТипыЗначенийДоступа", - УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ЗначениеДоступа")); - - ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в процедуре %1 общего модуля %2.'"), - "ПриЗаполненииВидовДоступа", "УправлениеДоступомПереопределяемый") - + Символы.ПС - + Символы.ПС; - - Параметры.Вставить("ЗаголовокОшибки", ЗаголовокОшибки); - - ВсеИменаВидовДоступа = Новый Соответствие; - ВсеИменаВидовДоступа.Вставить(ВРег("Объект"), Истина); - ВсеИменаВидовДоступа.Вставить(ВРег("Условие"), Истина); - ВсеИменаВидовДоступа.Вставить(ВРег("НастройкиПрав"), Истина); - ВсеИменаВидовДоступа.Вставить(ВРег("ПравоЧтения"), Истина); - ВсеИменаВидовДоступа.Вставить(ВРег("ПравоИзменения"), Истина); - - ВсеТипыЗначений = Новый Соответствие; - ВсеТипыГруппЗначений = Новый Соответствие; - ВсеСвойства = Новый Соответствие; - - ОписаниеВерсии = Новый Структура("СвойстваВерсии", Новый Массив); - ДобавитьЭлементВерсии(ОписаниеВерсии, "Версия", "1"); - - Для Каждого ВидДоступа Из ВидыДоступа Цикл - Если ВсеИменаВидовДоступа[ВРег(ВидДоступа.Имя)] <> Неопределено Тогда - ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Имя вида доступа ""%1"" уже определено.'"), - ВидДоступа.Имя); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - // Проверка повторения типов значений и групп. - ПроверитьТип(ВидДоступа, ВидДоступа.ТипЗначений, ВсеТипыЗначений, Параметры); - ПроверитьТип(ВидДоступа, ВидДоступа.ТипГруппЗначений, ВсеТипыГруппЗначений, Параметры, Истина); - // Проверка пересечения типов значений и групп. - ПроверитьТип(ВидДоступа, ВидДоступа.ТипЗначений, ВсеТипыГруппЗначений, Параметры, , Истина); - ПроверитьТип(ВидДоступа, ВидДоступа.ТипГруппЗначений, ВсеТипыЗначений, Параметры, Истина, Истина); - - ТаблицаДополнительныеТипы = ВидДоступа.ДополнительныеТипы; // См. НоваяТаблицаДополнительныеТипыВидаДоступа - - Для Каждого Строка Из ТаблицаДополнительныеТипы Цикл - // Проверка повторения типов значений и групп. - ПроверитьТип(ВидДоступа, Строка.ТипЗначений, ВсеТипыЗначений, Параметры); - ПроверитьТип(ВидДоступа, Строка.ТипГруппЗначений, ВсеТипыГруппЗначений, Параметры, Истина); - // Проверка пересечения типов значений и групп. - ПроверитьТип(ВидДоступа, Строка.ТипЗначений, ВсеТипыГруппЗначений, Параметры, , Истина); - ПроверитьТип(ВидДоступа, Строка.ТипГруппЗначений, ВсеТипыЗначений, Параметры, Истина, Истина); - КонецЦикла; - - ПустаяСсылкаТипаЗначений = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени( - Метаданные.НайтиПоТипу(ВидДоступа.ТипЗначений).ПолноеИмя()).ПустаяСсылка(); - - Свойства = НовыеСвойстваВидаДоступа(ВидДоступа, ПустаяСсылкаТипаЗначений); - ОписаниеВерсии.СвойстваВерсии.Добавить(""); - ДобавитьСвойстваВерсии(ОписаниеВерсии, Свойства, - "Имя, ТипЗначений, ТипГруппЗначений, НесколькоГруппЗначений"); - - ТипыВыбираемыхЗначений = Новый Массив; - ЗаполнитьЗначенияДоступаСГруппами(Свойства, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений); - ДополнительныеТипы = Новый Массив; - Для Каждого Строка Из ТаблицаДополнительныеТипы Цикл - ДополнительныйТип = ДополнительныйТипВидаДоступа(Строка); - ДополнительныеТипы.Добавить(ДополнительныйТип); - ДобавитьСвойстваВерсии(ОписаниеВерсии, Свойства, - "ТипЗначений, ТипГруппЗначений, НесколькоГруппЗначений"); - ЗаполнитьЗначенияДоступаСГруппами(Строка, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений); - КонецЦикла; - - Свойства.ТипыВыбираемыхЗначений = Новый ФиксированныйМассив(ТипыВыбираемыхЗначений); - Свойства.ДополнительныеТипы = Новый ФиксированныйМассив(ДополнительныеТипы); - ВсеСвойства.Вставить(Свойства, Новый ФиксированнаяСтруктура(Свойства)); - Свойства = ВсеСвойства.Получить(Свойства); - - МассивСвойств.Добавить(Свойства); - ПоИменам.Вставить(Свойства.Имя, Свойства); - ПоСсылкам.Вставить(ПустаяСсылкаТипаЗначений, Свойства); - ПоТипамЗначений.Вставить(Свойства.ТипЗначений, Свойства); - ПоТипамГруппИЗначений.Вставить(Свойства.ТипЗначений, Свойства); - Если Свойства.ТипГруппЗначений <> Тип("Неопределено") Тогда - ПоТипамГруппИЗначений.Вставить(Свойства.ТипГруппЗначений, Свойства); - КонецЕсли; - - Для Каждого Строка Из ВидДоступа.ДополнительныеТипы Цикл - ПоТипамЗначений.Вставить(Строка.ТипЗначений, Свойства); - ПоТипамГруппИЗначений.Вставить(Строка.ТипЗначений, Свойства); - Если Строка.ТипГруппЗначений <> Тип("Неопределено") Тогда - ПоТипамГруппИЗначений.Вставить(Строка.ТипГруппЗначений, Свойства); - КонецЕсли; - КонецЦикла; - - КонецЦикла; - - БезГруппДляЗначенияДоступа = Новый Массив; - СОднойГруппойДляЗначенияДоступа = Новый Массив; - ТипыЗначенийДоступаСГруппами = Новый Соответствие; - - ВидыДоступаСГруппами = Новый Соответствие; - - Для Каждого КлючИЗначение Из ЗначенияДоступаСГруппами.ПоТипамСсылок Цикл - ВидДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа - ИмяВидаДоступа = ВидДоступа.Имя; - ВидыДоступаСГруппами.Вставить(ИмяВидаДоступа, Истина); - - ПустаяСсылка = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); - ТипыЗначенийДоступаСГруппами.Вставить(ТипЗнч(ПустаяСсылка), ПустаяСсылка); - - Если НЕ КлючИЗначение.Значение.НесколькоГруппЗначений - И СОднойГруппойДляЗначенияДоступа.Найти(ИмяВидаДоступа) = Неопределено Тогда - - СОднойГруппойДляЗначенияДоступа.Добавить(ИмяВидаДоступа); - КонецЕсли; - КонецЦикла; - - ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.Пользователи"), - Справочники.Пользователи.ПустаяСсылка()); - - ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ГруппыПользователей"), - Справочники.ГруппыПользователей.ПустаяСсылка()); - - ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ВнешниеПользователи"), - Справочники.ВнешниеПользователи.ПустаяСсылка()); - - ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ГруппыВнешнихПользователей"), - Справочники.ГруппыВнешнихПользователей.ПустаяСсылка()); - - ПоТипамЗначенийСИерархией = Новый Соответствие; - Для Каждого КлючИЗначение Из ПоТипамЗначений Цикл - ТипСсылка = КлючИЗначение.Ключ; - Если ТипыЗначенийДоступаСГруппами[ТипСсылка] <> Неопределено Тогда - Продолжить; - КонецЕсли; - - ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипСсылка); - Если ОбъектМетаданных <> Неопределено - И (ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) - Или ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)) - И ОбъектМетаданных.Иерархический Тогда - - ТипОбъект = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных(ОбъектМетаданных); - ПоТипамЗначенийСИерархией.Вставить(ТипСсылка, КлючИЗначение.Значение); - ПоТипамЗначенийСИерархией.Вставить(ТипОбъект, КлючИЗначение.Значение); - КонецЕсли; - КонецЦикла; - - Для Каждого СвойстваВидаДоступа Из МассивСвойств Цикл - Если ВидыДоступаСГруппами.Получить(СвойстваВидаДоступа.Имя) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Если СвойстваВидаДоступа.Имя = "Пользователи" - ИЛИ СвойстваВидаДоступа.Имя = "ВнешниеПользователи" Тогда - Продолжить; - КонецЕсли; - БезГруппДляЗначенияДоступа.Добавить(СвойстваВидаДоступа.Имя); - КонецЦикла; - - ПроверитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ЗначенияДоступаСГруппами); - - // Окончательная фиксация данных. - - ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления = - Новый ФиксированныйМассив(ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления); - - ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления = - Новый ФиксированноеСоответствие(ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления); - - Для Каждого ОписаниеСвойства Из ЗначенияДоступаСГруппами Цикл - ТекущееСоответствие = ОписаниеСвойства.Значение; - Если ТипЗнч(ТекущееСоответствие) <> Тип("Соответствие") Тогда - Продолжить; - КонецЕсли; - Для Каждого КлючИЗначение Из ТекущееСоответствие Цикл - ТекущееСоответствие.Вставить(КлючИЗначение.Ключ, - ВсеСвойства.Получить(КлючИЗначение.Значение)); - КонецЦикла; - ЗначенияДоступаСГруппами[ОписаниеСвойства.Ключ] = - Новый ФиксированноеСоответствие(ТекущееСоответствие); - КонецЦикла; - - СвойстваВидовДоступа = Новый Структура; - СвойстваВидовДоступа.Вставить("Массив", - Новый ФиксированныйМассив(МассивСвойств)); - - СвойстваВидовДоступа.Вставить("ПоИменам", - Новый ФиксированноеСоответствие(ПоИменам)); - - СвойстваВидовДоступа.Вставить("ПоСсылкам", - Новый ФиксированноеСоответствие(ПоСсылкам)); - - СвойстваВидовДоступа.Вставить("ПоТипамЗначений", - Новый ФиксированноеСоответствие(ПоТипамЗначений)); - - СвойстваВидовДоступа.Вставить("ПоТипамЗначенийСИерархией", - Новый ФиксированноеСоответствие(ПоТипамЗначенийСИерархией)); - - СвойстваВидовДоступа.Вставить("ПоТипамГруппИЗначений", - Новый ФиксированноеСоответствие(ПоТипамГруппИЗначений)); - - СвойстваВидовДоступа.Вставить("ЗначенияДоступаСГруппами", - Новый ФиксированнаяСтруктура(ЗначенияДоступаСГруппами)); - - СвойстваВидовДоступа.Вставить("БезГруппДляЗначенияДоступа", - Новый ФиксированныйМассив(БезГруппДляЗначенияДоступа)); - - СвойстваВидовДоступа.Вставить("СОднойГруппойДляЗначенияДоступа", - Новый ФиксированныйМассив(СОднойГруппойДляЗначенияДоступа)); - - СвойстваВидовДоступа.Вставить("ТипыЗначенийДоступаСГруппами", - Новый ФиксированноеСоответствие(ТипыЗначенийДоступаСГруппами)); - - Результат = Новый ФиксированнаяСтруктура(СвойстваВидовДоступа); - - ХешСуммы.ХешСуммаТиповГруппИЗначенийДоступа = - ХешСуммаТиповГруппИЗначенийДоступа(СвойстваВидовДоступа); - - СтрокаВерсии = СтрСоединить(ОписаниеВерсии.СвойстваВерсии, Символы.ПС); - ХешСуммы.ХешСумма = ХешСуммаДанных(СтрокаВерсии); - - Возврат Результат; - -КонецФункции - -// Для функции СвойстваВидовДоступа. -// -// Возвращаемое значение: -// см. СвойстваВидаДоступа -// -Функция НовыеСвойстваВидаДоступа(ВидДоступа, ПустаяСсылкаТипаЗначений) - - Свойства = Новый Структура; - Свойства.Вставить("Имя", ВидДоступа.Имя); - Свойства.Вставить("Ссылка", ПустаяСсылкаТипаЗначений); - Свойства.Вставить("ТипЗначений", ВидДоступа.ТипЗначений); - Свойства.Вставить("ТипГруппЗначений", ВидДоступа.ТипГруппЗначений); - Свойства.Вставить("НесколькоГруппЗначений", ВидДоступа.НесколькоГруппЗначений); - Свойства.Вставить("ДополнительныеТипы"); - Свойства.Вставить("ТипыВыбираемыхЗначений"); - - Возврат Свойства; - -КонецФункции - -// Для функции СвойстваВидовДоступа. -// -// Возвращаемое значение: -// Структура: -// * ПоТипам - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. СвойстваВидаДоступа -// * ПоТипамСсылок - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. СвойстваВидаДоступа -// * ИменаТаблицДляОбновления - ФиксированныйМассив из Строка -// * ТипыГруппЗначенийДляОбновления - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - СправочникСсылка -// * ПоТипамСсылокДляОбновления - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - см. СвойстваВидаДоступа -// -Функция ЗначенияДоступаСГруппами() - - ЗначенияДоступаСГруппами = Новый Структура; - ЗначенияДоступаСГруппами.Вставить("ПоТипам", Новый Соответствие); - ЗначенияДоступаСГруппами.Вставить("ПоТипамСсылок", Новый Соответствие); - ЗначенияДоступаСГруппами.Вставить("ИменаТаблицДляОбновления", Новый Массив); - ЗначенияДоступаСГруппами.Вставить("ТипыГруппЗначенийДляОбновления", Новый Соответствие); - ЗначенияДоступаСГруппами.Вставить("ПоТипамДляОбновления", Новый Соответствие); - ЗначенияДоступаСГруппами.Вставить("ПоТипамСсылокДляОбновления", Новый Соответствие); - - Возврат ЗначенияДоступаСГруппами; - -КонецФункции - -// Для функции СвойстваВидовДоступа. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ТипЗначений - Тип -// * ТипГруппЗначений - Тип -// * НесколькоГруппЗначений - Булево -// -Функция ДополнительныйТипВидаДоступа(Строка) - - Элемент = Новый Структура; - Элемент.Вставить("ТипЗначений", Строка.ТипЗначений); - Элемент.Вставить("ТипГруппЗначений", Строка.ТипГруппЗначений); - Элемент.Вставить("НесколькоГруппЗначений", Строка.НесколькоГруппЗначений); - - Возврат Новый ФиксированнаяСтруктура(Элемент); - -КонецФункции - -// Для функции СвойстваВидовДоступа. -Процедура ЗаполнитьЗначенияДоступаСГруппами(Строка, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений) - - Если Свойства.Имя = "Пользователи" Тогда - ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.Пользователи")); - ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ГруппыПользователей")); - Возврат; - КонецЕсли; - - Если Свойства.Имя = "ВнешниеПользователи" Тогда - ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ВнешниеПользователи")); - ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ГруппыВнешнихПользователей")); - Возврат; - КонецЕсли; - - ТипСсылки = Строка.ТипЗначений; - - МетаданныеТипаЗначений = Метаданные.НайтиПоТипу(Строка.ТипЗначений); - Если ОбщегоНазначения.ЭтоПеречисление(МетаданныеТипаЗначений) Тогда - ТипОбъекта = ТипСсылки; - Иначе - ТипОбъекта = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных( - МетаданныеТипаЗначений); - КонецЕсли; - - Если Строка.ТипГруппЗначений = Тип("Неопределено") Тогда - ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, - ТипОбъекта, МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, Неопределено); - ДобавитьВМассив(ТипыВыбираемыхЗначений, Строка.ТипЗначений); - Возврат; - КонецЕсли; - - Если Строка.ТипГруппЗначений <> Тип("Неопределено") Тогда - ДобавитьВМассив(ТипыВыбираемыхЗначений, Строка.ТипГруппЗначений); - КонецЕсли; - - ЗначенияДоступаСГруппами.ПоТипам.Вставить(ТипСсылки, Свойства); - ЗначенияДоступаСГруппами.ПоТипам.Вставить(ТипОбъекта, Свойства); - ЗначенияДоступаСГруппами.ПоТипамСсылок.Вставить(ТипСсылки, Свойства); - - МетаданныеТипаГруппЗначений = Метаданные.НайтиПоТипу(Строка.ТипГруппЗначений); - - ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, - ТипОбъекта, МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, МетаданныеТипаГруппЗначений); - -КонецПроцедуры - -// Для функции СвойстваВидовДоступа и процедуры ЗаполнитьЗначенияДоступаСГруппами. -Процедура ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, ТипОбъекта, - МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, МетаданныеТипаГруппЗначений) - - ПустаяСсылкаТипаЗначений = ПредопределенноеЗначение(МетаданныеТипаЗначений.ПолноеИмя() + ".ПустаяСсылка"); - - Если МетаданныеТипаГруппЗначений = Неопределено Тогда - ПустаяСсылкаТипаГруппЗначений = ПустаяСсылкаТипаЗначений; - Иначе - ПустаяСсылкаТипаГруппЗначений = ПустаяСсылкаОбъектаМетаданных(МетаданныеТипаГруппЗначений); - КонецЕсли; - - ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления.Добавить(МетаданныеТипаЗначений.ПолноеИмя()); - - ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления.Вставить(ТипСсылки, - ПустаяСсылкаТипаГруппЗначений); - - ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления.Вставить(ПустаяСсылкаТипаЗначений, - ПустаяСсылкаТипаГруппЗначений); - - ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Вставить(ТипСсылки, Свойства); - ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Вставить(ТипСсылки, Свойства); - ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Вставить(ТипОбъекта, Свойства); - -КонецПроцедуры - -// Для функции СвойстваВидовДоступа. -Процедура ПроверитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ЗначенияДоступаСГруппами) - - ТекущиеТипыПодписки = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы( - "ОпределяемыйТип.ЗначениеДоступаОбъект"); - - ТребуемыеТипыПодписки = Новый Соответствие; - Для Каждого КлючИЗначение Из ЗначенияДоступаСГруппами.ПоТипамДляОбновления Цикл - Если ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда - Продолжить; - КонецЕсли; - ТребуемыеТипыПодписки.Вставить(КлючИЗначение.Ключ, Истина); - КонецЦикла; - - НедостающиеТипы = Новый Массив; - - Для Каждого КлючИЗначение Из ТребуемыеТипыПодписки Цикл - Если ТекущиеТипыПодписки.Получить(КлючИЗначение.Ключ) = Неопределено Тогда - НедостающиеТипы.Добавить(КлючИЗначение.Ключ); - КонецЕсли; - КонецЦикла; - - Если НедостающиеТипы.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'По данным, полученным из процедуры %1 - |общего модуля %2, - |в определяемом типе %3 не указаны требуемые типы: - |- %4'"), - "ПриЗаполненииВидовДоступа", - "УправлениеДоступомПереопределяемый", - "ЗначениеДоступаОбъект", - СтрСоединить(НедостающиеТипы, "," + Символы.ПС + "- ")); - - ВызватьИсключение ТекстОшибки; - -КонецПроцедуры - -// Для функции СвойстваВидовДоступа. -Процедура ПроверитьТип(ВидДоступа, Тип, ВсеТипы, Параметры, ПроверкаТиповГрупп = Ложь, ПроверкаПересечения = Ложь) - - Если Тип = Тип("Неопределено") Тогда - Если ПроверкаТиповГрупп Тогда - Возврат; - КонецЕсли; - ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Для вида доступа ""%1"" не указан тип значений доступа.'"), - ВидДоступа.Имя); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - // Проверка, что указан тип ссылки. - Если НЕ ОбщегоНазначения.ЭтоСсылка(Тип) Тогда - Если ПроверкаТиповГрупп Тогда - ОписаниеОшибки = - НСтр("ru = 'Тип ""%1"" указан, как тип групп значений, для вида доступа ""%2"". - |Однако это не тип ссылки.'"); - Иначе - ОписаниеОшибки = - НСтр("ru = 'Тип ""%1"" указан, как тип значений, для вида доступа ""%2"". - |Однако это не тип ссылки.'"); - КонецЕсли; - ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - ОписаниеОшибки, Тип, ВидДоступа.Имя); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - // Проверка повторения и пересечения типов значений и групп значений. - ДляТогоЖеВидаДоступаОшибкиНет = Ложь; - - Если ПроверкаТиповГрупп Тогда - Если ПроверкаПересечения Тогда - ОписаниеОшибки = - НСтр("ru = 'Тип ""%1"" указан, как тип значений, для вида доступа ""%2"". - |Для вида доступа ""%3"" его нельзя указать, как тип групп значений.'"); - Иначе - ДляТогоЖеВидаДоступаОшибкиНет = Истина; - ОписаниеОшибки = - НСтр("ru = 'Тип групп значений ""%1"" уже указан для вида доступа ""%2"". - |Для вида доступа ""%3"" его нельзя указать.'"); - КонецЕсли; - Иначе - Если ПроверкаПересечения Тогда - ОписаниеОшибки = - НСтр("ru = 'Тип ""%1"" указан, как тип групп значений, для вида доступа ""%2"". - |Для вида доступа ""%3"" его нельзя указать, как тип значений.'"); - Иначе - ОписаниеОшибки = - НСтр("ru = 'Тип значений ""%1"" уже указан для вида доступа ""%2"". - |Для вида доступа ""%3"" его нельзя указать.'"); - КонецЕсли; - КонецЕсли; - - Если ВсеТипы.Получить(Тип) <> Неопределено Тогда - Если НЕ (ДляТогоЖеВидаДоступаОшибкиНет И ВидДоступа.Имя = ВсеТипы.Получить(Тип)) Тогда - ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - ОписаниеОшибки, Тип, ВсеТипы.Получить(Тип), ВидДоступа.Имя); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ИначеЕсли НЕ ПроверкаПересечения Тогда - ВсеТипы.Вставить(Тип, ВидДоступа.Имя); - КонецЕсли; - - // Проверка состава определяемых типов. - ОписаниеОшибки = ""; - Если Параметры.ОпределяемыеТипыЗначенийДоступа.Получить(Тип) = Неопределено Тогда - Если ПроверкаТиповГрупп Тогда - ОписаниеОшибки = - НСтр("ru = 'Тип групп значений доступа ""%1"" вида доступа ""%2"" - |не указан в определяемом типе %3.'"); - Иначе - ОписаниеОшибки = - НСтр("ru = 'Тип значений доступа ""%1"" вида доступа ""%2"" - |не указан в определяемом типе %3.'"); - КонецЕсли; - КонецЕсли; - - Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда - ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - ОписаниеОшибки, Тип, ВидДоступа.Имя, "ЗначениеДоступа"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - -КонецПроцедуры - -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - Тип -// * Значение - Строка -// -Функция ПредставлениеВидовДоступа() Экспорт - - ВидыДоступа = ЗаполненныеВидыДоступаСеанса(); - - ПредставлениеВидовДоступа = Новый Соответствие; - - Для Каждого ВидДоступа Из ВидыДоступа Цикл - ПредставлениеВидовДоступа.Вставить(ВидДоступа.ТипЗначений, ВидДоступа.Представление); - КонецЦикла; - - Возврат Новый ФиксированноеСоответствие(ПредставлениеВидовДоступа); - -КонецФункции - -Функция ПредставлениеВидаДоступа(СвойстваВидаДоступа) Экспорт - - ПредставлениеВидовДоступа = УправлениеДоступомСлужебныйПовтИсп.ПредставлениеВидовДоступа(); - - Представление = ПредставлениеВидовДоступа.Получить(СвойстваВидаДоступа.ТипЗначений); - - Если Не ЗначениеЗаполнено(Представление) Тогда - Представление = СвойстваВидаДоступа.Имя; - КонецЕсли; - - Возврат Представление; - -КонецФункции - -// Для процедуры ЗаполнитьЗначенияДоступаСГруппами. -Процедура ДобавитьВМассив(Массив, Значение) - - Если Массив.Найти(Значение) = Неопределено Тогда - Массив.Добавить(Значение); - КонецЕсли; - -КонецПроцедуры - -// Для функций УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса, -// СвойстваВидовДоступа и процедур ОбновитьОписаниеСвойствВидовДоступа, -// ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений. -// -// Параметры: -// Значение - Неопределено -// - ФиксированнаяСтруктура -// -// Возвращаемое значение: -// Структура: -// * ХешСумма - Строка -// * ХешСуммаТиповГруппИЗначенийДоступа - Строка -// -Функция НовыеХешСуммыСвойствВидовДоступа(Значение = Неопределено) Экспорт - - Результат = Новый Структура; - Результат.Вставить("ХешСумма", ""); - Результат.Вставить("ХешСуммаТиповГруппИЗначенийДоступа", ""); - - Если ТипЗнч(Значение) = Тип("ФиксированнаяСтруктура") Тогда - ЗаполнитьЗначенияСвойств(Результат, Значение); - КонецЕсли; - - Возврат Результат; - -КонецФункции - -// Для процедуры ПроверенныеСвойстваВидовДоступаСеанса. -Функция ХешСуммаТиповГруппИЗначенийДоступа(СвойстваВидовДоступа) - - Данные = Новый Массив; - Данные.Добавить(ОписаниеТиповИзКлючейСоответствия(СвойстваВидовДоступа.ПоТипамЗначений)); - Данные.Добавить(ОписаниеТиповИзКлючейСоответствия(СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами)); - - ИменаТаблицДляОбновления = Новый СписокЗначений; - ИменаТаблицДляОбновления.ЗагрузитьЗначения(Новый Массив( - СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления)); - ИменаТаблицДляОбновления.СортироватьПоЗначению(); - - Данные.Добавить(ИменаТаблицДляОбновления.ВыгрузитьЗначения()); - - Данные.Добавить(Метаданные.ОпределяемыеТипы.ВладелецНаборовЗначенийДоступаОбъект.Тип); - - Возврат ХешСуммаДанных(Данные); - -КонецФункции - -// Для функции ХешСуммаТиповГруппИЗначенийДоступа. -Функция ОписаниеТиповИзКлючейСоответствия(Данные) - - Типы = Новый Массив; - Для Каждого КлючИЗначение Из Данные Цикл - Типы.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - - Возврат Новый ОписаниеТипов(Типы); - -КонецФункции - -Функция ХешСуммаДанных(Данные) Экспорт - - СтрокаДляХеширования = СтрокаДанныхДляХеширования(Данные); - - Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); - Хеширование.Добавить(СтрокаДляХеширования); - ХешСумма = Хеширование.ХешСумма; - СтрокаХешСуммы = Base64Строка(ХешСумма); - - Возврат СтрокаХешСуммы; - -КонецФункции - -Функция ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипЗначенияВидаДоступа) - - УстановитьПривилегированныйРежим(Истина); - - ТекстЗапроса = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Ссылка, - | ГруппыДоступа.Профиль КАК Профиль - |ПОМЕСТИТЬ ГруппыДоступа - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа - | ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка - | И (ГруппыДоступа.Профиль <> &ПрофильАдминистратор) - | И (НЕ ГруппыДоступа.ПометкаУдаления) - | И (НЕ ПрофилиГруппДоступа.ПометкаУдаления) - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - | ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа - | ГДЕ - | УчастникиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка)) - | - |ИНДЕКСИРОВАТЬ ПО - | Ссылка, - | ГруппыДоступа.Профиль - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ГруппыДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.ГруппыДоступа.ЗначенияДоступа КАК ГруппыДоступаЗначенияДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа - | ПО ГруппыДоступаЗначенияДоступа.Ссылка = ГруппыДоступа.Ссылка - |ГДЕ - | ГруппыДоступаЗначенияДоступа.ВключаяНижестоящие - | И ТИПЗНАЧЕНИЯ(ГруппыДоступаЗначенияДоступа.ЗначениеДоступа) = &ТипЗначенияВидаДоступа - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ГруппыДоступа.Ссылка - |ИЗ - | Справочник.ПрофилиГруппДоступа.ЗначенияДоступа КАК ПрофилиГруппДоступаЗначенияДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа - | ПО ПрофилиГруппДоступаЗначенияДоступа.Ссылка = ГруппыДоступа.Профиль - |ГДЕ - | ПрофилиГруппДоступаЗначенияДоступа.ВключаяНижестоящие - | И ТИПЗНАЧЕНИЯ(ПрофилиГруппДоступаЗначенияДоступа.ЗначениеДоступа) = &ТипЗначенияВидаДоступа"; - - Запрос = Новый Запрос(ТекстЗапроса); - Запрос.УстановитьПараметр("ТипЗначенияВидаДоступа", ТипЗначенияВидаДоступа); - Запрос.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); - - Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - -КонецФункции - -// Возвращает таблицу значений, содержащую вид ограничений доступа по каждому праву -// объектов метаданных. -// Если записи по праву нет, значит ограничений по праву нет. -// Таблица содержит только виды доступа, заданные разработчиком, -// исходя из их применения в текстах ограничений. -// В стандартном варианте ограничения доступа для получения видов доступа объектов, -// которые ограничиваются с помощью шаблона ПоНаборамЗначений, используется текущее -// состояние регистра сведений НаборыЗначенийДоступа. Признаком такого ограничения -// является строка, в которой таблица ограничивается по виду ограничения Объект -// с той же ведущей таблицей (кроме случая, когда таблица является владельцем настроек прав). -// -// Параметры: -// ДляПроверки - Булево - вернуть текстовое описание ограничений прав, заполненное -// в переопределяемых модулях без проверки. -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * ДляВнешнихПользователей - Булево - если Ложь, тогда ограничение для пользователей, -// если Истина, тогда для внешних пользователей. -// Колонка присутствует только для универсального ограничения. -// * ПолноеИмя - Строка - полное имя таблицы. -// * Таблица - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы. -// * Право - Строка - "Чтение", "Изменение". -// * ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа значений вида доступа. -// Неопределено если ограничение с помощью стандартного шаблона ПоНаборамЗначений. -// Перечисление.ДополнительныеЗначенияДоступа.Неопределено для -// специальных ограничений Объект и НастройкиПрав. -// * ЭтоАвторизованныйПользователь - Булево - Истина, если вид доступа Пользователи или ВнешниеПользователи, -// но проверка только с помощью ограничения ФункцияЭтоАвторизованныйПользователь. -// * ТаблицаОбъекта - ЛюбаяСсылка - пустая ссылка объекта, который ограничивается с помощью -// стандартного шаблона ПоНаборамЗначений. -// - Неопределено - если ВидДоступа <> Неопределено. -// Колонка присутствует только для стандартного ограничения. -// -// Строка - когда ДляПроверки равно Истина, тогда ограничения прав, как они добавлены в переопределяемом модуле. -// -Функция ПостоянныеВидыОграниченийПравОбъектовМетаданных(ДляПроверки = Ложь) Экспорт - - УстановитьПривилегированныйРежим(Истина); - - УниверсальноеОграничение = ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина); - - Если ДляПроверки Или Не УниверсальноеОграничение Тогда - ОграниченияПрав = ""; - ИнтеграцияПодсистемБСП.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(ОграниченияПрав); - УправлениеДоступомПереопределяемый.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(ОграниченияПрав); - Если ДляПроверки Тогда - Возврат ОграниченияПрав; - КонецЕсли; - КонецЕсли; - - ТипыИдентификаторов = Новый Массив; - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); - - ВидыОграниченийПрав = Новый ТаблицаЗначений; - ВидыОграниченийПрав.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); - ВидыОграниченийПрав.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(430))); - ВидыОграниченийПрав.Колонки.Добавить("Таблица", Новый ОписаниеТипов(ТипыИдентификаторов)); - ВидыОграниченийПрав.Колонки.Добавить("Право", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))); - ВидыОграниченийПрав.Колонки.Добавить("ВидДоступа", УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); - ВидыОграниченийПрав.Колонки.Добавить("ЭтоАвторизованныйПользователь", Новый ОписаниеТипов("Булево")); - ВидыОграниченийПрав.Колонки.Добавить("ТаблицаОбъекта", - Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип); - ВидыОграниченийПрав.Колонки.Добавить("ВедущееПраво", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))); - - ВидыДоступаПоИменам = СвойстваВидовДоступа().ПоИменам; - - Если УниверсальноеОграничение Тогда - ВсеВидыОграничений = ВсеВидыОграниченийПравДляОтчетаПраваДоступа(); - ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, - ВсеВидыОграничений.ДляПользователей, ВидыДоступаПоИменам, Истина, Ложь); - ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, - ВсеВидыОграничений.ДляВнешнихПользователей, ВидыДоступаПоИменам, Истина, Истина); - Иначе - ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, - ОграниченияПрав, ВидыДоступаПоИменам, Ложь); - КонецЕсли; - - ВидыОграниченийПрав.Индексы.Добавить("ПолноеИмя"); - ПолныеИмена = ВидыОграниченийПрав.ВыгрузитьКолонку("ПолноеИмя"); - ИдентификаторыИмен = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена); - Для Каждого Строка Из ВидыОграниченийПрав Цикл - Строка.Таблица = ИдентификаторыИмен.Получить(Строка.ПолноеИмя); - КонецЦикла; - - ВидыОграниченийПрав.Колонки.Удалить("ВедущееПраво"); - Если УниверсальноеОграничение Тогда - ВидыОграниченийПрав.Колонки.Удалить("ТаблицаОбъекта"); - Иначе - ВидыОграниченийПрав.Колонки.Удалить("ДляВнешнихПользователей"); - КонецЕсли; - - Возврат ВидыОграниченийПрав; - -КонецФункции - -// Для функции ПостоянныеВидыОграниченийПравОбъектовМетаданных. -Процедура ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, ОграниченияПрав, ВидыДоступаПоИменам, - УниверсальноеОграничение, ДляВнешнихПользователей = Неопределено) - - Для НомерСтроки = 1 По СтрЧислоСтрок(ОграниченияПрав) Цикл - ТекущаяСтрока = СокрЛП(СтрПолучитьСтроку(ОграниченияПрав, НомерСтроки)); - Если ЗначениеЗаполнено(ТекущаяСтрока) Тогда - ПояснениеОшибки = ""; - ЧастиСтроки = СтрРазделить(ТекущаяСтрока, "."); - Если Не УниверсальноеОграничение - И ЧастиСтроки.Количество() <> 4 - И ЧастиСтроки.Количество() <> 6 Тогда - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Строка должна быть в формате %1.'"), - "<ПолноеИмяТаблицы>.<ИмяПрава>.<ИмяВидаДоступа>[.<ПолноеИмяТаблицыОбъекта>]"); - ИначеЕсли УниверсальноеОграничение - И ЧастиСтроки.Количество() <> 4 - И ЧастиСтроки.Количество() <> 7 Тогда - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Строка должна быть в формате %1.'"), - "<ПолноеИмяТаблицы>.<ИмяПрава>.<ИмяВидаДоступа>[.<ПолноеИмяТаблицыОбъекта>.<ИмяВедущегоПрава>]"); - Иначе - Таблица = ЧастиСтроки[0] + "." + ЧастиСтроки[1]; - Право = ЧастиСтроки[2]; - ВидДоступа = ЧастиСтроки[3]; - Если ЧастиСтроки.Количество() = 4 Тогда - ТаблицаОбъекта = ""; - ВедущееПраво = ""; - Иначе - ТаблицаОбъекта = ЧастиСтроки[4] + "." + ЧастиСтроки[5]; - ВедущееПраво = ?(УниверсальноеОграничение, ЧастиСтроки[6], ""); - КонецЕсли; - - ОбъектМетаданныхТаблицы = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Таблица); - Если ОбъектМетаданныхТаблицы = Неопределено Тогда - Если УниверсальноеОграничение Тогда - Продолжить; - КонецЕсли; - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует таблица ""%1"".'"), Таблица); - - ИначеЕсли Право <> "Чтение" И Право <> "Изменение" Тогда - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует право ""%1"".'"), Право); - - ИначеЕсли ВРег(ВидДоступа) = ВРег("Объект") Тогда - ОбъектМетаданныхТаблицыОбъекта = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ТаблицаОбъекта); - Если ОбъектМетаданныхТаблицыОбъекта = Неопределено Тогда - Если УниверсальноеОграничение Тогда - Продолжить; - КонецЕсли; - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует таблица объекта ""%1"".'"), - ТаблицаОбъекта); - Иначе - Если ОбъектМетаданныхТаблицы = ОбъектМетаданныхТаблицыОбъекта Тогда - ВидДоступаСсылка = Неопределено; - ТаблицаОбъектаСсылка = ПустаяСсылкаОбъектаМетаданных(ТаблицаОбъекта); - Иначе - ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; - ТаблицаОбъектаСсылка = Неопределено; - КонецЕсли; - Если УниверсальноеОграничение - И ВедущееПраво <> "Чтение" - И ВедущееПраво <> "Изменение" Тогда - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует ведущее право ""%1"".'"), ВедущееПраво); - КонецЕсли; - КонецЕсли; - - ИначеЕсли ВРег(ВидДоступа) = ВРег("НастройкиПрав") Тогда - Если ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ТаблицаОбъекта) = Неопределено Тогда - Если УниверсальноеОграничение Тогда - Продолжить; - КонецЕсли; - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует таблица владельца настроек прав ""%1"".'"), - ТаблицаОбъекта); - Иначе - ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; - ТаблицаОбъектаСсылка = Неопределено; - КонецЕсли; - - ИначеЕсли ВРег(ВидДоступа) = ВРег("ПравоЧтения") - Или ВРег(ВидДоступа) = ВРег("ПравоИзменения") - Или ВРег(ВидДоступа) = ВРег("ФункцияЭтоАвторизованныйПользователь") - Или ВРег(ВидДоступа) = ВРег("ФункцияПравоДоступаИлиРольДоступна") Тогда - - ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; - ТаблицаОбъектаСсылка = Неопределено; - - ИначеЕсли ВидыДоступаПоИменам.Получить(ВидДоступа) = Неопределено Тогда - Если УниверсальноеОграничение Тогда - Продолжить; - КонецЕсли; - ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует вид доступа ""%1"".'"), ВидДоступа); - Иначе - СвойстваВидаДоступа = ВидыДоступаПоИменам.Получить(ВидДоступа); // См. СвойстваВидаДоступа - ВидДоступаСсылка = СвойстваВидаДоступа.Ссылка; - ТаблицаОбъектаСсылка = Неопределено; - КонецЕсли; - КонецЕсли; - - Если ЗначениеЗаполнено(ПояснениеОшибки) Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка в строке описания вида ограничений права объекта метаданных: - |""%1"".'") - + Символы.ПС - + Символы.ПС, - ТекущаяСтрока) - + ПояснениеОшибки; - - Если Не УниверсальноеОграничение Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректное внедрение подсистемы %1 - |в процедуре %2 - |общего модуля %3. - | - |%4'"), - "УправлениеДоступом", - "ПриЗаполненииВидовОграниченийПравОбъектовМетаданных", - "УправлениеДоступомПереопределяемый", - ТекстОшибки); - КонецЕсли; - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - Иначе - НовоеОписание = ВидыОграниченийПрав.Добавить(); - НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; - НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); - НовоеОписание.Право = Право; - НовоеОписание.ВидДоступа = ВидДоступаСсылка; - НовоеОписание.ТаблицаОбъекта = ТаблицаОбъектаСсылка; - НовоеОписание.ВедущееПраво = ВедущееПраво; - Если ВРег(ВидДоступа) = ВРег("ФункцияЭтоАвторизованныйПользователь") Тогда - Если ДляВнешнихПользователей <> Истина Тогда - НовоеОписание = ВидыОграниченийПрав.Добавить(); - НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; - НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); - НовоеОписание.Право = Право; - НовоеОписание.ВидДоступа = Справочники.Пользователи.ПустаяСсылка(); - НовоеОписание.ЭтоАвторизованныйПользователь = Истина; - КонецЕсли; - Если ДляВнешнихПользователей <> Ложь Тогда - НовоеОписание = ВидыОграниченийПрав.Добавить(); - НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; - НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); - НовоеОписание.Право = Право; - НовоеОписание.ВидДоступа = Справочники.ВнешниеПользователи.ПустаяСсылка(); - НовоеОписание.ЭтоАвторизованныйПользователь = Истина; - КонецЕсли; - КонецЕсли; - КонецЕсли; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Только для внутреннего использования. -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка -// * ТипГруппИЗначений - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка -// -Функция ТипыГруппИЗначенийВидовДоступа() Экспорт - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - ТипыГруппИЗначенийВидовДоступа = Новый ТаблицаЗначений; - ТипыГруппИЗначенийВидовДоступа.Колонки.Добавить("ВидДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - ТипыГруппИЗначенийВидовДоступа.Колонки.Добавить("ТипГруппИЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - - Для Каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамГруппИЗначений Цикл - Строка = ТипыГруппИЗначенийВидовДоступа.Добавить(); - СвойстваВидаДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа - Строка.ВидДоступа = СвойстваВидаДоступа.Ссылка; - - Типы = Новый Массив; - Типы.Добавить(КлючИЗначение.Ключ); - ОписаниеТипа = Новый ОписаниеТипов(Типы); - - Строка.ТипГруппИЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); - КонецЦикла; - - Возврат ТипыГруппИЗначенийВидовДоступа; - -КонецФункции - -// Только для внутреннего использования. -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * ВидДоступа - ЛюбаяСсылка -// * ТипЗначений - ЛюбаяСсылка -// -Функция ТипыЗначенийВидовДоступаИВладельцевНастроекПрав() Экспорт - - ТипыЗначенийВидовДоступаИВладельцевНастроекПрав = Новый ТаблицаЗначений; - - ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Колонки.Добавить("ВидДоступа", - УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); - - ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Колонки.Добавить("ТипЗначений", - УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); - - ТипыЗначенийВидовДоступа = ТипыЗначенийВидовДоступа(); - - Для Каждого Строка Из ТипыЗначенийВидовДоступа Цикл - ЗаполнитьЗначенияСвойств(ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Добавить(), Строка); - КонецЦикла; - - ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); - ВладельцыПрав = ВозможныеПрава.ПоТипамСсылок; - - Для Каждого КлючИЗначение Из ВладельцыПрав Цикл - - Типы = Новый Массив; - Типы.Добавить(КлючИЗначение.Ключ); - ОписаниеТипа = Новый ОписаниеТипов(Типы); - - Строка = ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Добавить(); - Строка.ВидДоступа = ОписаниеТипа.ПривестиЗначение(Неопределено); - Строка.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); - КонецЦикла; - - Возврат ТипыЗначенийВидовДоступаИВладельцевНастроекПрав; - -КонецФункции - -// Для функции ТипыЗначенийВидовДоступаИВладельцевНастроекПрав. -Функция ТипыЗначенийВидовДоступа() - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - ТипыЗначенийВидовДоступа = Новый ТаблицаЗначений; - ТипыЗначенийВидовДоступа.Колонки.Добавить("ВидДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - ТипыЗначенийВидовДоступа.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); - - Для каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамЗначений Цикл - Строка = ТипыЗначенийВидовДоступа.Добавить(); - СвойстваВидаДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа - Строка.ВидДоступа = СвойстваВидаДоступа.Ссылка; - - Типы = Новый Массив; - Типы.Добавить(КлючИЗначение.Ключ); - ОписаниеТипа = Новый ОписаниеТипов(Типы); - - Строка.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); - КонецЦикла; - - Возврат ТипыЗначенийВидовДоступа; - -КонецФункции - -// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов. -// Смотри также заполнение в функции РегистрыСведений.НастройкиПравОбъектов.ВозможныеПраваСеанса. -// -// Возвращаемое значение: -// Структура: -// * ПоТипам - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип - тип ссылки или объекта из ОпределяемыйТип.ВладельцыНастроекПрав -// ** Значение - ФиксированноеСоответствие из КлючИЗначение: -// *** Ключ - Строка - имя возможного права -// *** Значение - см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава -// * ПоТипамСсылок - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип - тип ссылки из ОпределяемыйТип.ВладельцыНастроекПрав -// ** Значение - ФиксированныйМассив из см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава -// * ПоПолнымИменам - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Строка - владелец прав (полное имя таблицы) -// ** Значение - см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава -// * ТипыВладельцев - ФиксированныйМассив из ОпределяемыйТип.ВладелецНастроекПрав -// * ОтдельныеТаблицы - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы -// ** Значение - Строка - полное имя таблицы -// * ИерархическиеТаблицы - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Тип - тип ссылки или объекта из ОпределяемыйТип.ВладельцыНастроекПрав -// ** Значение - Булево - Истина. -// -Функция ВозможныеПраваДляНастройкиПравОбъектов() Экспорт - - Возврат РегистрыСведений.НастройкиПравОбъектов.ВозможныеПраваДляНастройкиПравОбъектов(); - -КонецФункции - -// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииПоставляемыхПрофилейГруппДоступа. -// Смотри также заполнение в функции Справочники.ПрофилиГруппДоступа.ПроверенныеПоставляемыеПрофилиСеанса. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ОписанияПрофилей - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Строка -// ** Значение - см. Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля -// * ОписанияПрофилейМассив - ФиксированныйМассив из см. Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля -// * ПапкиПоРодителям - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Строка -// ** Значение - ФиксированноеСоответствие из КлючИЗначение: -// *** Ключ - Строка -// *** Значение - Булево -// * ПараметрыОбновления - ФиксированнаяСтруктура: -// ** ОбновлятьИзмененныеПрофили - Булево -// ** ЗапретитьИзменениеПрофилей - Булево -// ** ОбновлятьГруппыДоступа - Булево -// ** ОбновлятьГруппыДоступаСУстаревшимиНастройками - Булево -// -Функция ПоставляемыеПрофили() Экспорт - - Возврат Справочники.ПрофилиГруппДоступа.ПоставляемыеПрофили(); - -КонецФункции - -// Смотри заполнение в функции Справочники.ПрофилиГруппДоступа.ПодготовленныеСтандартныеРолиРасширенийСеанса. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ОбщиеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>ОбщиеПрава -// * ПолныеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>ПолныеПрава -// * БазовыеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>БазовыеПрава -// * БазовыеПраваВнешнихПользователей - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>БазовыеПраваВнешнихПользователей -// * АдминистраторСистемы - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>АдминистраторСистемы -// * Все - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Строка - имя роли расширений, из указанных выше. -// ** Значение - Строка - имя вида ролей (имя свойства структуры). -// * ДополнительныеРолиАдминистратора - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - Строка - имя ролей расширений, которые можно назначить администратору. -// ** Значение - Булево - Истина. -// -Функция СтандартныеРолиРасширений() Экспорт - - Возврат Справочники.ПрофилиГруппДоступа.СтандартныеРолиРасширений(); - -КонецФункции - -#КонецОбласти - -#Область УниверсальноеОграничение - -#Область ОбработчикиПодписокНаСобытия - -// Обработчик подписок ПроверитьДоступПередЗаписью* проверяет доступ к старой версии объекта, проверяет -// изменение полей объектов дополнительных таблиц, присоединенных в ограничениях доступа списков. -// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа -// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. -// -// Параметры: -// Источник - СправочникОбъект -// - ДокументОбъект -// - ПланВидовХарактеристикОбъект -// - ПланСчетовОбъект -// - ПланВидовРасчетаОбъект -// - БизнесПроцессОбъект -// - ЗадачаОбъект -// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередЗаписью. -// -// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. -// -// РежимЗаписи - РежимЗаписиДокумента - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда Источник это ДокументОбъект. -// -// РежимПроведения - РежимПроведенияДокумента - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда Источник это ДокументОбъект. -// -Процедура ПроверитьДоступПередЗаписью(Источник, Отказ, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт - - // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). - ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, Ложь, Ложь); - -КонецПроцедуры - -// Обработчик подписок ПроверитьДоступПередЗаписьюНабораЗаписей* проверяет доступ к старой версии набора записей, -// проверяет изменение полей наборов записей дополнительных таблиц, присоединенных в ограничениях доступа списков. -// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа -// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. -// -// Параметры: -// Источник - РегистрСведенийНаборЗаписей -// - РегистрНакопленияНаборЗаписей -// - РегистрБухгалтерииНаборЗаписей -// - РегистрРасчетаНаборЗаписей -// - ПерерасчетНаборЗаписей - набор записей, передаваемый в подписку -// на событие ПередЗаписью. -// -// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. -// Замещение - РежимЗамещения, Булево - параметр, передаваемый в подписку на событие ПередЗаписью. -// -// ТолькоЗапись - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда Источник это РегистрРасчетаНаборЗаписей. -// -// ЗаписьФактическогоПериодаДействия - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда Источник это РегистрРасчетаНаборЗаписей. -// -// ЗаписьПерерасчетов - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, -// когда Источник это РегистрРасчетаНаборЗаписей. -// -Процедура ПроверитьДоступПередЗаписьюНабораЗаписей(Источник, Отказ, Замещение, - ТолькоЗапись = Неопределено, - ЗаписьФактическогоПериодаДействия = Неопределено, - ЗаписьПерерасчетов = Неопределено) Экспорт - - // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). - ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, Истина, Замещение); - -КонецПроцедуры - -// Обработчик подписок ПроверитьДоступПриЗаписи* проверяет устаревание ключа доступа -// новой версии объекта. Обновляет устаревший ключ доступа и, в этом случае, -// выполняет проверку прав Чтение и Изменение новой версии объекта. -// -// Параметры: -// Источник - СправочникОбъект -// - ДокументОбъект -// - ПланВидовХарактеристикОбъект -// - ПланСчетовОбъект -// - ПланВидовРасчетаОбъект -// - БизнесПроцессОбъект -// - ЗадачаОбъект -// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПриЗаписи. -// -// Отказ - Булево - параметр, передаваемый в подписку на событие ПриЗаписи. -// -Процедура ПроверитьДоступПриЗаписи(Источник, Отказ) Экспорт - - // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). - ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, Ложь, Ложь); - -КонецПроцедуры - -// Обработчик подписок ПроверитьДоступПриЗаписиНабораЗаписей* проверяет устаревание ключей доступа -// новой версии набора записей. Обновляет устаревшие ключи доступа и, в этом случае, -// выполняет проверку прав Чтение и Изменение новой версии набора записей. -// -// Параметры: -// Источник - РегистрСведенийНаборЗаписей -// - РегистрНакопленияНаборЗаписей -// - РегистрБухгалтерииНаборЗаписей -// - РегистрРасчетаНаборЗаписей -// - ПерерасчетНаборЗаписей - набор записей, передаваемый в подписку -// на событие ПриЗаписи. -// -// Отказ - Булево - параметр, передаваемый в подписку на событие ПриЗаписи. -// Замещение - РежимЗамещения, Булево - параметр, передаваемый в подписку на событие ПриЗаписи. -// -// ТолькоЗапись - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, -// когда Источник это РегистрРасчетаНаборЗаписей. -// -// ЗаписьФактическогоПериодаДействия - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, -// когда Источник это РегистрРасчетаНаборЗаписей. -// -// ЗаписьПерерасчетов - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, -// когда Источник это РегистрРасчетаНаборЗаписей. -// -Процедура ПроверитьДоступПриЗаписиНабораЗаписей(Источник, Отказ, Замещение, - ТолькоЗапись = Неопределено, - ЗаписьФактическогоПериодаДействия = Неопределено, - ЗаписьПерерасчетов = Неопределено) Экспорт - - // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). - ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, Истина, Замещение); - -КонецПроцедуры - -// Обработчик подписок ПроверитьДоступПередУдалением* проверяет -// изменение полей объектов дополнительных таблиц, присоединенных в ограничениях доступа списков. -// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа -// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. -// -// Параметры: -// Источник - СправочникОбъект -// - ДокументОбъект -// - ПланВидовХарактеристикОбъект -// - ПланСчетовОбъект -// - ПланВидовРасчетаОбъект -// - БизнесПроцессОбъект -// - ЗадачаОбъект -// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередУдалением. -// -// Отказ - Булево - параметр, передаваемый в подписку на событие ПередУдалением. -// -Процедура ПроверитьДоступПередУдалением(Источник, Отказ) Экспорт - - // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). - ПроверитьДоступПередУдалениемИсточника(Источник, Отказ); - -КонецПроцедуры - -#КонецОбласти - -#Область УниверсальноеОграничениеДоступа - -// Параметры: -// ОписаниеДанных - см. УправлениеДоступом.ИзменениеРазрешено.ОписаниеДанных -// ПравоИзменение - Булево -// ВызыватьИсключение - Булево -// ПроверитьТолькоСтаруюВерсию - Булево -// Пользователь - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// - Неопределено - проверить для текущего пользователя. -// -// Возвращаемое значение: -// Булево -// -Функция ДоступРазрешен(ОписаниеДанных, ПравоИзменение, ВызыватьИсключение = Ложь, - ПроверитьТолькоСтаруюВерсию = Ложь, Знач Пользователь = Неопределено) Экспорт - - УчитыватьПривилегированныйРежим = Истина; - ПользовательИБ = Неопределено; - - Если Пользователь <> Неопределено - И Пользователь = Пользователи.АвторизованныйПользователь() Тогда - - Пользователь = Неопределено; - УчитыватьПривилегированныйРежим = Ложь; - ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь(); - КонецЕсли; - - Если Пользователь = Неопределено - И Пользователи.ЭтоПолноправныйПользователь(,, УчитыватьПривилегированныйРежим) Тогда - Возврат Истина; - КонецЕсли; - - ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ОписаниеДанных)); - Если ОбъектМетаданных = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недопустимое значение параметра %1 в %2. - |Ожидалась ссылка, объект, ключ записи или набор записей. - |Передано значение: %3 (тип %4).'"), - "ОписаниеДанных", - ?(ВызыватьИсключение, - ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", - "УправлениеДоступом.ПроверитьЧтениеРазрешено"), - ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", - "УправлениеДоступом.ЧтениеРазрешено")), - Строка(ОписаниеДанных), - Строка(ТипЗнч(ОписаниеДанных))); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ПроизводительныйВариант = УправлениеДоступом.ПроизводительныйВариант(); - - Если Пользователь <> Неопределено Тогда - ОбщегоНазначенияКлиентСервер.ПроверитьПараметр( - ?(ВызыватьИсключение, - ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", - "УправлениеДоступом.ПроверитьЧтениеРазрешено"), - ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", - "УправлениеДоступом.ЧтениеРазрешено")), - "Пользователь", - Пользователь, - Новый ОписаниеТипов("СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи")); - - Если Не ПроизводительныйВариант Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недопустимое значение параметра %1 в %2. - |В стандартном варианте ограничения доступа поддерживается только %3. - |Передано значение: %4 (тип %5).'"), - "Пользователь", - ?(ВызыватьИсключение, - ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", - "УправлениеДоступом.ПроверитьЧтениеРазрешено"), - ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", - "УправлениеДоступом.ЧтениеРазрешено")), - "Неопределено", - Строка(Пользователь), - Строка(ТипЗнч(Пользователь))); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если ВызыватьИсключение Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Вызов исключения поддерживается только для текущего пользователя. - |В %1 - |- либо недопустимое значение параметра %2 - |передано значение: %3 (тип %4), - |- либо недопустимое значение параметра %5 - |передано значение: %6 (тип %7).'"), - "УправлениеДоступом.ДоступРазрешен", - "ВызыватьИсключение", - Строка(ВызыватьИсключение), - Строка(ТипЗнч(ВызыватьИсключение)), - "Пользователь", - Строка(Пользователь), - Строка(ТипЗнч(Пользователь))); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если Пользователи.ЭтоПолноправныйПользователь(Пользователь,, УчитыватьПривилегированныйРежим) Тогда - Возврат Истина; - КонецЕсли; - - ИдентификаторПользователяИБ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователь, - "ИдентификаторПользователяИБ"); - - Если ТипЗнч(ИдентификаторПользователяИБ) <> Тип("УникальныйИдентификатор") Тогда - Возврат Ложь; - КонецЕсли; - - ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( - ИдентификаторПользователяИБ); - - Если ПользовательИБ = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - КонецЕсли; - - ЛюбойОбъект = ОписаниеДанных; // СправочникОбъект - - Если Не ПравоИзменение Тогда - ИмяПраваДоступа = "Чтение"; - - ИначеЕсли ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ОбъектМетаданных) - И Не ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ЛюбойОбъект)) - И ЛюбойОбъект.ЭтоНовый() Тогда - - ИмяПраваДоступа = "Добавление"; - Иначе - ИмяПраваДоступа = "Изменение"; - КонецЕсли; - - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - СписокПолей = УправлениеДоступомСлужебныйПовтИсп.СписокВсехПолейОграниченияДоступа(ПолноеИмя); - - Если ВызыватьИсключение Тогда - ВыполнитьПроверкуПравДоступа(ИмяПраваДоступа, ОбъектМетаданных); - ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей); - - ИначеЕсли ПользовательИБ = Неопределено Тогда - ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей); - - ИначеЕсли Пользователь = Неопределено Тогда - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей, ПользовательИБ); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - Иначе - ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей, ПользовательИБ); - КонецЕсли; - Если Не ПараметрыДоступа.Доступность Тогда - Возврат Ложь; - ИначеЕсли Не ПараметрыДоступа.ОграничениеУсловием Тогда - Возврат Истина; - КонецЕсли; - - Если УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа(Пользователь) Тогда - Возврат Истина; - КонецЕсли; - - Если Не ПроизводительныйВариант Тогда - Возврат ЧтениеДоступно(ПолноеИмя, ОбъектМетаданных, ОписаниеДанных, ВызыватьИсключение); - КонецЕсли; - - Если ЗначениеЗаполнено(Пользователь) Тогда - ДляВнешнихПользователей = ТипЗнч(Пользователь) = Тип("СправочникСсылка.ВнешниеПользователи"); - Иначе - ДляВнешнихПользователей = Неопределено; - КонецЕсли; - Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); - КонецЕсли; - - ИдентификаторТранзакции = Новый УникальныйИдентификатор; - ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, ДляВнешнихПользователей); - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ОбновитьРазрешенныеНаборыВПараметрахСеанса(); - - Если ПараметрыОграничения.ОграничениеОтключено - Или Не ПравоИзменение - И ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда - - Возврат Истина; - КонецЕсли; - - СтараяВерсия = Истина; - ПравоИзменения = Ложь; - ЭтоНовый = Ложь; - - Если ПараметрыОграничения.ДоступЗапрещен Тогда - ДоступРазрешен = Ложь; - Иначе - Запрос = Новый Запрос; - УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос, Пользователь); - - Запрос.Текст = ?(ПравоИзменение, ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение, - ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение); - - Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда - СсылкаНаОбъект = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеДанных)), - ОписаниеДанных, ОписаниеДанных.Ссылка); - Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект); - Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", - ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); - КонецЕсли; - Если ОписаниеДанных = СсылкаНаОбъект Или ЗначениеЗаполнено(СсылкаНаОбъект) Тогда - ДоступРазрешен = Не Запрос.Выполнить().Пустой(); - Иначе - ДоступРазрешен = Истина; - КонецЕсли; - - Если Не ДоступРазрешен Тогда - ДанныеДляПредставления = СсылкаНаОбъект; - - ИначеЕсли ОписаниеДанных <> СсылкаНаОбъект И Не ПроверитьТолькоСтаруюВерсию Тогда - СтараяВерсия = Ложь; - Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - ПоляЧерезТочку = СтрРазделить(ПараметрыОграничения.ПолеВладельца.Имя, ".", Ложь); - ПолеОбъекта = ПоляЧерезТочку[0]; - ЗначениеПоляОбъекта = ОписаниеДанных[ПолеОбъекта]; - Если ПоляЧерезТочку.Количество() = 1 Тогда - ПараметрИзПамяти = "&Владелец"; - Иначе - ОбъектМетаданныхПоТипу = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеПоляОбъекта)); - Если ОбъектМетаданныхПоТипу = Неопределено Тогда - ПараметрИзПамяти = "&Владелец"; - ЗначениеПоляОбъекта = Null; - Иначе - ПоляЧерезТочку.Удалить(0); - ПараметрИзПамяти = "ВЫРАЗИТЬ(&Владелец КАК " + ОбъектМетаданныхПоТипу.ПолноеИмя() - + ")." + СтрСоединить(ПоляЧерезТочку, "."); // @query-part-1 - КонецЕсли; - КонецЕсли; - Запрос.Текст = СтрЗаменить(Запрос.Текст, - ПараметрыОграничения.ПолеОбъектаВладельцаВЗапросеПроверкиПрав, ПараметрИзПамяти); - Запрос.УстановитьПараметр("Владелец", ЗначениеПоляОбъекта); - Иначе - МодельОбъектовВПамяти = МодельОбъектовВПамяти(ОписаниеДанных, ПараметрыОграничения); - ПараметрыОбновления = Новый Структура(ПараметрыОграничения); - ПараметрыОбновления.Вставить("МодельОбъектовВПамяти", МодельОбъектовВПамяти); - ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); - ПараметрыОбновления.Вставить("ИдентификаторСписка", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); - ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(МодельОбъектовВПамяти.ЭлементыДанных, ПараметрыОбновления); - Запрос.УстановитьПараметр("КлючиДоступаКОбъектам", МодельОбъектовВПамяти.КлючиДоступаКОбъектам); - Запрос.УстановитьПараметр("Объект", МодельОбъектовВПамяти.ЭлементыДанных[0].ТекущаяСсылка); - ТекстЗапроса = - "ВЫБРАТЬ - | КлючиДоступаКОбъектам.Объект КАК Объект, - | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, - | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей - |ПОМЕСТИТЬ РегистрСведений_КлючиДоступаКОбъектам - |ИЗ - | &КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам"; - Запрос.Текст = СтрЗаменить(Запрос.Текст, "РегистрСведений.КлючиДоступаКОбъектам", - "РегистрСведений_КлючиДоступаКОбъектам"); - Запрос.Текст = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; - КонецЕсли; - ПроверкаДобавления = Ложь; - ТекстЗапросаИзменения = Запрос.Текст; - ЭтоНовый = ОписаниеДанных.ЭтоНовый(); - УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления); - ДоступРазрешен = Не Запрос.Выполнить().Пустой(); - Если Не ДоступРазрешен И ПроверкаДобавления Тогда - Запрос.Текст = ТекстЗапросаИзменения; - ПравоИзменения = Не Запрос.Выполнить().Пустой(); - КонецЕсли; - ДанныеДляПредставления = ОписаниеДанных; - КонецЕсли; - Иначе - НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); - ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей); - - Замещение = Неопределено; - ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос, Замещение); - ТекстЗапроса = Запрос.Текст; - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборПоИзмерениям", ОтборПоИзмерениям); - ДоступРазрешен = Запрос.Выполнить().Пустой(); - - Если ДоступРазрешен - И ТипЗнч(ОписаниеДанных) = ТипЗнч(НаборЗаписей) - И Не ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) - И Не ПроверитьТолькоСтаруюВерсию Тогда - - СтараяВерсия = Ложь; - Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - ПолеВладельца = ПараметрыОграничения.ПолеВладельца.Имя; - Комбинации = ОписаниеДанных.Выгрузить(, ПолеВладельца); // ТаблицаЗначений - Комбинации.Свернуть(ПолеВладельца); - Запрос.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", Комбинации); - ТекстЗапросаПодготовкиКомбинаций = "ВЫБРАТЬ ТекущаяТаблица." + ПолеВладельца + " - |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей - |ИЗ &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"; // @query-part-1, @query-part-2 - Иначе - ТекстЗапросаПодготовкиКомбинаций = "ВЫБРАТЬ ТекущаяТаблица." - + СтрСоединить(ПараметрыОграничения.ОпорныеПоля.Используемые, ", - | ТекущаяТаблица.") + " - |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей - |ИЗ &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"; // @query-part-1, @query-part-2, @query-part-3 - ОписаниеДанных.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", - ИдентификаторТранзакции); - ОбновитьКлючиДоступаКНаборуЗаписей(ОписаниеДанных, Ложь, Ложь, - ИдентификаторТранзакции, ПараметрыОграничения, "", Запрос); - ОписаниеДанных.ДополнительныеСвойства.Удалить("УправлениеДоступомИдентификаторТранзакции"); - КонецЕсли; - Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", "ИСТИНА"); - ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(ОписаниеДанных)).ПолноеИмя(); - Запрос.Текст = ТекстЗапросаПодготовкиКомбинаций + ОбщегоНазначения.РазделительПакетаЗапросов() - + СтрЗаменить(Запрос.Текст, ПолноеИмяРегистра + " КАК ТекущаяТаблица", - "КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"); // @query-part-1 @query-part-2 - - ДоступРазрешен = Запрос.Выполнить().Пустой(); - КонецЕсли; - ДанныеДляПредставления = НаборЗаписей; - КонецЕсли; - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - Если ДоступРазрешен Или Не ВызыватьИсключение Тогда - Возврат ДоступРазрешен; - КонецЕсли; - - Если ПравоИзменение Тогда - ПравоЧтения = ДоступРазрешен(ОписаниеДанных, Ложь); - Иначе - ПравоЧтения = Ложь; - КонецЕсли; - - СообщитьОбОшибкеДоступа(ДанныеДляПредставления, СтараяВерсия, ПравоЧтения, ПравоИзменения, ЭтоНовый); - - Возврат Ложь; - -КонецФункции - -// Для функции ДоступРазрешен. -Функция ЧтениеДоступно(ПолноеИмя, ОбъектМетаданных, ОписаниеДанных, ВызыватьИсключение) - - Запрос = Новый Запрос; - - Если ЭтоСсылочныйТипТаблицы(ПолноеИмя) Тогда - СсылкаНаОбъект = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеДанных)), - ОписаниеДанных, ОписаниеДанных.Ссылка); - - Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект); - ТекстЗапроса = - "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | ТекущаяТаблица.Ссылка = &Ссылка"; - Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя); - Если Не Запрос.Выполнить().Пустой() Тогда - Возврат Истина; - КонецЕсли; - ДанныеДляПредставления = СсылкаНаОбъект; - Иначе - НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); - ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей); - - ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос); - ТекстЗапроса = - "ВЫБРАТЬ РАЗРЕШЕННЫЕ - | КОЛИЧЕСТВО(1) КАК КоличествоДанных - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | &ОтборПоИзмерениям"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", ОтборПоИзмерениям); - Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя); - - УстановитьПривилегированныйРежим(Истина); - Выборка = Запрос.Выполнить().Выбрать(); - УстановитьПривилегированныйРежим(Ложь); - ВсегоДанных = ?(Выборка.Следующий(), Выборка.КоличествоДанных, 0); - - Выборка = Запрос.Выполнить().Выбрать(); - ДоступноДанных = ?(Выборка.Следующий(), Выборка.КоличествоДанных, 0); - - Если ВсегоДанных = ДоступноДанных Тогда - Возврат Истина; - КонецЕсли; - ДанныеДляПредставления = НаборЗаписей; - КонецЕсли; - - Если Не ВызыватьИсключение Тогда - Возврат Ложь; - КонецЕсли; - - СообщитьОбОшибкеДоступа(ДанныеДляПредставления, Истина, Ложь, Ложь, Ложь); - - Возврат Ложь; - -КонецФункции - -// См. УправлениеДоступом.ПраваДоступаКДанным -Функция ПраваДоступаКДанным(ОписаниеДанных, ДляВнешнихПользователей, СоставПользователей) Экспорт - - Если ТипЗнч(ДляВнешнихПользователей) <> Тип("Булево") Тогда - Результат1 = ПраваДоступаКДанным(ОписаниеДанных, Ложь, СоставПользователей); - Результат2 = ПраваДоступаКДанным(ОписаниеДанных, Истина, СоставПользователей); - Для Каждого СтрокаТЗ Из Результат2 Цикл - ЗаполнитьЗначенияСвойств(Результат1.Добавить(), СтрокаТЗ); - КонецЦикла; - Возврат Результат1; - КонецЕсли; - - Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда - ТекстОшибки = НСтр("ru = 'Недостаточно прав доступа.'"); - ДляАдминистратора = НСтр("ru = 'Нужны полные права или привилегированный режим.'"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа,, ДляАдминистратора); - КонецЕсли; - - Если Не УправлениеДоступом.ПроизводительныйВариант() Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Функция %1 не поддерживается в стандартном варианте ограничения доступа.'"), - "УправлениеДоступом.ПраваДоступаКДанным"); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда - ЭлементДанных = ?(ОписаниеДанных.Количество() > 0, ОписаниеДанных[0], - "<" + НСтр("ru = 'Пустой массив'") + ">"); - Иначе - ЭлементДанных = ОписаниеДанных; - КонецЕсли; - - ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ЭлементДанных)); - Если ОбъектМетаданных = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недопустимое значение параметра %1 в %2. - |Ожидалась ссылка, ключ записи, набор записей или непустой массив ссылок одного типа. - |Передано значение: %3 (тип %4).'"), - "ОписаниеДанных", - "УправлениеДоступом.ПраваДоступаКДанным", - Строка(ЭлементДанных), - Строка(ТипЗнч(ОписаниеДанных))); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, - Новый УникальныйИдентификатор, ДляВнешнихПользователей); - - Если ДляВнешнихПользователей - И Не Константы.ИспользоватьВнешнихПользователей.Получить() Тогда - - Возврат ПодготовленныйРезультат(ПараметрыОграничения); - КонецЕсли; - - Запрос = Новый Запрос; - ДобавитьЗапросПроверяемыхПользователей(Запрос, ДляВнешнихПользователей, СоставПользователей); - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - Запрос.УстановитьПараметр("ИдентификаторОбъектаМетаданных", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных)); - - Если ПараметрыОграничения.ДоступЗапрещен - Или ПараметрыОграничения.ОграничениеОтключено Тогда - - ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, - ?(ПараметрыОграничения.ДоступЗапрещен, "ТолькоПраваБезОграничения", "ПраваСОграничением"), - ?(СоставПользователей = Неопределено, "", "ПроверяемыеПользователи"), - "ПользователиСПравамиНаТаблицу"); - - ТекстЗапросаПравСДанными = Неопределено; - ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, ТекстЗапросаПравСДанными); - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаПравСДанными; - - Возврат ПодготовленныйРезультат(ПараметрыОграничения, Запрос); - КонецЕсли; - - ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, - ?(ПараметрыОграничения.ОграничениеЧтенияОтключено, "ОграничениеЧтенияОтключено", "ТолькоПраваБезОграничения"), - ?(СоставПользователей = Неопределено, "", "ПроверяемыеПользователи"), - "ПользователиСПравамиБезОграниченияНаТаблицу"); - - ТекстЗапросаПравСДанными = ""; - ОтборПоИзмерениям = ""; - ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, - ТекстЗапросаПравСДанными, ОтборПоИзмерениям); - - ТекстЗапроса = ПараметрыОграничения.ТекстЗапросаПравПользователей; - - Если СоставПользователей <> Неопределено Тогда - ОтборПользователей = СтрШаблон( - "ВЫРАЗИТЬ(НаборыПользователей.Пользователь КАК %1) В - | (ВЫБРАТЬ - | ПроверяемыеПользователи.ПользовательСПравом - | ИЗ - | ПроверяемыеПользователи КАК ПроверяемыеПользователи)", - ?(ДляВнешнихПользователей, "Справочник.ВнешниеПользователи", "Справочник.Пользователи")); - Иначе - ОтборПользователей = "ИСТИНА"; - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПользователей1", - ТекстСОтступом(ОтборПользователей, " ")); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПользователей2", ТекстСОтступом( - СтрЗаменить(ОтборПользователей, "НаборыПользователей.Пользователь", "СоставыГруппПользователей.Пользователь"), - " ")); - - Если Не ПараметрыОграничения.ЭтоСсылочныйТип - И Не ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", - ТекстСОтступом(ОтборПоИзмерениям, " ")); - КонецЕсли; - - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; - - Запрос.УстановитьПараметр("РазрешенныйПустойНаборГруппДоступа", - УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); - - Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", - ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); - КонецЕсли; - - ДобавитьЗапросПользователейИзПравНаЭлементыДанных(Запрос, ПараметрыОграничения, СоставПользователей); - - ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, - "ПраваСОграничением", - "ПользователиИзПравНаЭлементыДанных", - "ПользователиСПравамиСОграничениемНаТаблицу"); - - ДобавитьИтоговыйЗапросПравПользователей(Запрос, ПараметрыОграничения, ТекстЗапросаПравСДанными, ОтборПоИзмерениям); - - Возврат ПодготовленныйРезультат(ПараметрыОграничения, Запрос); - -КонецФункции - -// Для функций ДоступРазрешен, ЧтениеРазрешено, ПраваДоступаКДанным. -Функция ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмяРегистра, НовыйПустойНаборЗаписей, - ПраваДоступаКДанным = Ложь) - - Если ТипЗнч(ОписаниеДанных) <> ТипЗнч(НовыйПустойНаборЗаписей) Тогда - // КлючЗаписи. - ОтборЗаписей = Новый Массив; - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - ОтборЗаписей.Добавить(Новый Структура("Имя, Значение, Использование", - ОписаниеПоля.Имя, ОписаниеДанных[ОписаниеПоля.Имя], Истина)); - КонецЦикла; - Возврат ОтборЗаписей; - КонецЕсли; - - Если Не ПраваДоступаКДанным Тогда - Возврат ОписаниеДанных; - КонецЕсли; - - ЕстьОтбор = Ложь; - Для Каждого ЭлементОтбора Из ОписаниеДанных.Отбор Цикл - Если ЭлементОтбора.Использование Тогда - ЕстьОтбор = Истина; - КонецЕсли; - КонецЦикла; - - Возврат ?(ЕстьОтбор, ОписаниеДанных.Отбор, Неопределено); - -КонецФункции - -// Для функции ПраваДоступаКДанным. -Функция ПодготовленныйРезультат(ПараметрыОграничения, Запрос = Неопределено); - - ПолноеИмя = ПараметрыОграничения.Список; - - Если Запрос = Неопределено Тогда - ТипПользователь = Новый ОписаниеТипов("СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи"); - Результат = Новый ТаблицаЗначений; - Результат.Колонки.Добавить("ПользовательСПравом", ТипПользователь); - Результат.Колонки.Добавить("ПравоИзменение", Новый ОписаниеТипов("Булево")); - Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда - ТипСсылки = ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); - Результат.Колонки.Добавить("Ссылка", - Новый ОписаниеТипов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки))); - Иначе - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - Результат.Колонки.Добавить(ОписаниеПоля.Имя, ОписаниеПоля.Тип); - КонецЦикла; - КонецЕсли; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) КАК ПользовательСПравом, - | ЛОЖЬ КАК ПравоИзменение, - | НЕОПРЕДЕЛЕНО КАК Ссылка - |ГДЕ - | ЛОЖЬ - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка), - | ЛОЖЬ, - | НЕОПРЕДЕЛЕНО КАК Ссылка - |ГДЕ - | ЛОЖЬ"; - Если Не ПараметрыОграничения.ЭтоСсылочныйТип Тогда - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); - ИзмеренияДляВыбора = Новый Массив; - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - ИзмеренияДляВыбора.Добавить("НЕОПРЕДЕЛЕНО"); // @query-part-1 - КонецЦикла; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "НЕОПРЕДЕЛЕНО КАК Ссылка", - СтрСоединить(ИзмеренияДляВыбора, ", - | ")); // @query-part-1 - КонецЕсли; - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.ТекстОбъединитьВсе() + ТекстЗапроса; - Результат = Запрос.Выполнить().Выгрузить(); - КонецЕсли; - - Возврат Результат; - -КонецФункции - -Процедура ДобавитьЗапросПроверяемыхПользователей(Запрос, ДляВнешнихПользователей, СоставПользователей) - - Если СоставПользователей = Неопределено Тогда - Возврат; - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ПроверяемыеПользователи.Пользователь КАК ПользовательСПравом - |ПОМЕСТИТЬ ПроверяемыеПользователи - |ИЗ - | &ПроверяемыеПользователи КАК ПроверяемыеПользователи - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь"; - - ПроверяемыеПользователи = Новый ТаблицаЗначений; - ТипПользователя = ?(ДляВнешнихПользователей, Тип("СправочникСсылка.ВнешниеПользователи"), - Тип("СправочникСсылка.Пользователи")); - ПроверяемыеПользователи.Колонки.Добавить("Пользователь", Новый ОписаниеТипов( - ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипПользователя))); - - Для Каждого Пользователь Из СоставПользователей Цикл - Если ТипЗнч(Пользователь) = ТипПользователя И ЗначениеЗаполнено(Пользователь) Тогда - ПроверяемыеПользователи.Добавить().Пользователь = Пользователь; - КонецЕсли; - КонецЦикла; - - Запрос.УстановитьПараметр("ПроверяемыеПользователи", ПроверяемыеПользователи); - Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(Запрос.Текст), - ОбщегоНазначения.РазделительПакетаЗапросов(), "") + ТекстЗапроса; - -КонецПроцедуры - -Процедура ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, ВариантПрав, - ИмяВременнойТаблицыПроверяемыхПользователей = "", ИмяВременнойТаблицыРезультата = "") - - Если ИмяВременнойТаблицыПроверяемыхПользователей = "" Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | СписокПользователей.Ссылка КАК ПользовательСПравом, - | МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение) КАК ПравоИзменение - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ПО (ГруппыДоступаПользователи.Ссылка = ТаблицыГруппДоступа.ГруппаДоступа) - | И (ТаблицыГруппДоступа.Таблица = &ИдентификаторОбъектаМетаданных) - | И (&ОтборПрав) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь) - | И (СоставыГруппПользователей.Используется) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей - | ПО (СписокПользователей.Ссылка = СоставыГруппПользователей.Пользователь) - | И (СписокПользователей.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | И (НЕ СписокПользователей.ПометкаУдаления) - | И (НЕ СписокПользователей.Недействителен) - | И (НЕ СписокПользователей.Служебный) - | - |СГРУППИРОВАТЬ ПО - | СписокПользователей.Ссылка"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ПроверяемыеПользователи.ПользовательСПравом КАК ПользовательСПравом, - | МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение) КАК ПравоИзменение - |ИЗ - | ПроверяемыеПользователи КАК ПроверяемыеПользователи - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей - | ПО (СписокПользователей.Ссылка = ПроверяемыеПользователи.ПользовательСПравом) - | И (СписокПользователей.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | И (НЕ СписокПользователей.ПометкаУдаления) - | И (НЕ СписокПользователей.Недействителен) - | И (НЕ СписокПользователей.Служебный) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.Пользователь = СписокПользователей.Ссылка) - | И (СоставыГруппПользователей.Используется) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи - | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ПО (ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступаПользователи.Ссылка) - | И (ТаблицыГруппДоступа.Таблица = &ИдентификаторОбъектаМетаданных) - | И (&ОтборПрав) - | - |СГРУППИРОВАТЬ ПО - | ПроверяемыеПользователи.ПользовательСПравом"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПроверяемыеПользователи КАК", - ИмяВременнойТаблицыПроверяемыхПользователей + " КАК"); // @query-part-1, @query-part-2 - КонецЕсли; - - Если ИмяВременнойТаблицыРезультата <> "" Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КАК ПравоИзменение", - "КАК ПравоИзменение - |ПОМЕСТИТЬ " + ИмяВременнойТаблицыРезультата); // @query-part-1, @query-part-2 - КонецЕсли; - - Если ПараметрыОграничения.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СписокПользователей.Недействителен", "ЛОЖЬ"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СписокПользователей.Служебный", "ЛОЖЬ"); - КонецЕсли; - - Если ВариантПрав = "ПраваСОграничением" Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", "ИСТИНА"); - Иначе - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение)", - "МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменениеБезОграничения)"); // @query-part-1, @query-part-2 - - Если ВариантПрав = "ОграничениеЧтенияОтключено" Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", "ИСТИНА"); - Иначе // ТолькоПраваБезОграничения - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", - "ТаблицыГруппДоступа.ПравоЧтениеБезОграничения"); - КонецЕсли; - КонецЕсли; - - Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(Запрос.Текст), - ОбщегоНазначения.РазделительПакетаЗапросов(), "") + ТекстЗапроса; - -КонецПроцедуры - -Процедура ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, - ТекстЗапросаПравСДанными = Неопределено, ОтборПоИзмерениям = Неопределено) - - ТекущаяТаблица = Новый ТаблицаЗначений; - ПолноеИмя = ПараметрыОграничения.Список; - - Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущаяТаблица.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ТекущаяТаблица - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица"; - - ТипСсылки = ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); - ТекущаяТаблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов( - ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки))); - - Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда - Для Счетчик = 1 По ОписаниеДанных.Количество() Цикл - ТекущаяТаблица.Добавить(); - КонецЦикла; - ТекущаяТаблица.ЗагрузитьКолонку(ОписаниеДанных, "Ссылка"); - Иначе - ТекущаяТаблица.Добавить().Ссылка = ОписаниеДанных; - КонецЕсли; - Запрос.УстановитьПараметр("ТекущаяТаблица", ТекущаяТаблица); - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; - - Если ТекстЗапросаПравСДанными = Неопределено Тогда - ТекстЗапросаПравСДанными = - "ВЫБРАТЬ - | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, - | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | ПользователиСПравамиНаТаблицу КАК ПраваПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица - | ПО ИСТИНА"; - КонецЕсли; - - Возврат; - - КонецЕсли; - - НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); - ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей, Истина); - - ОтборПоИзмерениям = ?(ОтборЗаписей = Неопределено, "ИСТИНА", - ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос)); - - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); - - Если ЗначениеЗаполнено(ОписаниеДанных) И ОтборЗаписей = Неопределено Тогда - ИзмеренияДляВыбора = Новый Массив; - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %1", ОписаниеПоля.Имя)); // @query-part-1 - КонецЦикла; - ТекстЗапросаКлючейЗаписей = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущаяТаблица.Поле1 КАК Поле1 - |ПОМЕСТИТЬ КлючиЗаписейРегистра - |ИЗ - | &КлючиЗаписейРегистра КАК ТекущаяТаблица"; - ТекстЗапросаКлючейЗаписей = СтрЗаменить(ТекстЗапросаКлючейЗаписей, - "ТекущаяТаблица.Поле1 КАК Поле1", - СтрСоединить(ИзмеренияДляВыбора, ", - | ")); // @query-part-1 - Запрос.УстановитьПараметр("КлючиЗаписейРегистра", - ОписаниеДанных.Выгрузить(, ОписаниеКлючаЗаписи.СписокПолей)); - - ОтборПоИзмерениям = - "ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | КлючиЗаписейРегистра КАК КлючиЗаписейРегистра - | ГДЕ - | КлючиЗаписейРегистра.Поле1 = ТекущаяТаблица.Поле1)"; // @query-part-1 - УсловияОтбора = Новый Массив; - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - УсловияОтбора.Добавить(СтрШаблон("КлючиЗаписейРегистра.%1 = ТекущаяТаблица.%1", ОписаниеПоля.Имя)); - КонецЦикла; - ОтборПоИзмерениям = СтрЗаменить(ОтборПоИзмерениям, - "КлючиЗаписейРегистра.Поле1 = ТекущаяТаблица.Поле1", - СтрСоединить(УсловияОтбора, " - | И ")); // @query-part-1, @query-part-2 - КонецЕсли; - - Если ТекстЗапросаПравСДанными = Неопределено Тогда - ТекстЗапросаПравСДанными = - "ВЫБРАТЬ - | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, - | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Поле1 КАК Поле1 - |ИЗ - | ПользователиСПравамиНаТаблицу КАК ПраваПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаРегистра КАК ТекущаяТаблица - | ПО (&ОтборПоИзмерениям)"; - - ИначеЕсли ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - ОпорноеПолеВладельца = СтрРазделить(ПараметрыОграничения.ПолеВладельца.Имя, ".").Получить(0); - ТекстЗапросаВладельца = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущаяТаблица.ОпорноеПолеВладельца КАК Ссылка - |ПОМЕСТИТЬ ТекущаяТаблица - |ИЗ - | &ТаблицаРегистра КАК ТекущаяТаблица - |ГДЕ - | &ОтборПоИзмерениям"; - ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "ОпорноеПолеВладельца", ОпорноеПолеВладельца); - ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "&ТаблицаРегистра", ПолноеИмя); - ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "&ОтборПоИзмерениям", ОтборПоИзмерениям); - - ТекстЗапросаПравСДанными = - "ВЫБРАТЬ - | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, - | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Поле1 КАК Поле1 - |ИЗ - | ПраваПользователейНаЗаписиРегистраПоВладельцу КАК ПраваПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаРегистра КАК ТекущаяТаблица - | ПО (ТекущаяТаблица.ОпорноеПолеВладельца = ПраваПользователей.Ссылка) - | И (&ОтборПоИзмерениям)"; - ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, - "ОпорноеПолеВладельца", ОпорноеПолеВладельца); - КонецЕсли; - - Если ЗначениеЗаполнено(ТекстЗапросаПравСДанными) Тогда - ИзмеренияДляВыбора = Новый Массив; - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - УточненноеИмя = УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ОписаниеПоля.Имя); - ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %2", ОписаниеПоля.Имя, УточненноеИмя)); // @query-part-1 - КонецЦикла; - ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, "&ТаблицаРегистра", ПолноеИмя); - ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, "&ОтборПоИзмерениям", - ТекстСОтступом(ОтборПоИзмерениям, " ")); - ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, - "ТекущаяТаблица.Поле1 КАК Поле1", - СтрСоединить(ИзмеренияДляВыбора, ", - | ")); // @query-part-1 - КонецЕсли; - - Если ЗначениеЗаполнено(ТекстЗапросаКлючейЗаписей) Тогда - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаКлючейЗаписей; - КонецЕсли; - - Если ЗначениеЗаполнено(ТекстЗапросаВладельца) Тогда - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаВладельца; - КонецЕсли; - -КонецПроцедуры - -Процедура ДобавитьЗапросПользователейИзПравНаЭлементыДанных(Запрос, ПараметрыОграничения, СоставПользователей) - - Если СоставПользователей = Неопределено Тогда - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ВсеПользователиИзПрав.ПользовательСПравом КАК ПользовательСПравом - |ПОМЕСТИТЬ ПользователиИзПравНаЭлементыДанных - |ИЗ - | (ВЫБРАТЬ - | ВЫРАЗИТЬ(ПользователиСПравами.ПользовательСПравом КАК Справочник.Пользователи) КАК ПользовательСПравом - | ИЗ - | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами - | ГДЕ - | ТИПЗНАЧЕНИЯ(ПользователиСПравами.ПользовательСПравом) = ТИП(Справочник.Пользователи) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СписокПользователей.Ссылка - | ИЗ - | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей - | ПО (ПользователиСПравами.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ВсеПользователиИзПрав"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ВсеПользователиИзПрав.ПользовательСПравом КАК ПользовательСПравом - |ПОМЕСТИТЬ ПользователиИзПравНаЭлементыДанных - |ИЗ - | (ВЫБРАТЬ - | ВЫРАЗИТЬ(ПользователиСПравами.ПользовательСПравом КАК Справочник.Пользователи) КАК ПользовательСПравом - | ИЗ - | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами - | ГДЕ - | ТИПЗНАЧЕНИЯ(ПользователиСПравами.ПользовательСПравом) = ТИП(Справочник.Пользователи) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | ПроверяемыеПользователи.ПользовательСПравом - | ИЗ - | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПроверяемыеПользователи КАК ПроверяемыеПользователи - | ПО (ПользователиСПравами.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ВсеПользователиИзПрав"; - КонецЕсли; - - Если ПараметрыОграничения.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; - -КонецПроцедуры - -Процедура ДобавитьИтоговыйЗапросПравПользователей(Запрос, ПараметрыОграничения, - ТекстЗапросаПравСДанными, ОтборПоИзмерениям) - - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, - | МАКСИМУМ(ПраваПользователей.ПравоИзменение) КАК ПравоИзменение, - | ПраваПользователей.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | ПраваНаТаблицу.ПользовательСПравом КАК ПользовательСПравом, - | ПраваНаТаблицу.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - | ИЗ - | ТекущаяТаблица КАК ТекущаяТаблица - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиБезОграниченияНаТаблицу КАК ПраваНаТаблицу - | ПО (&ОтборПоИзмерениям) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | ПраваНаТаблицу.ПользовательСПравом, - | ПраваНаТаблицу.ПравоИзменение - | И ТекущаяТаблица.ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - | ИЗ - | ПользователиСПравамиСОграничениемНаТаблицу КАК ПраваНаТаблицу - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиНаЭлементыДанных КАК ТекущаяТаблица - | ПО (ТекущаяТаблица.ПользовательСПравом = ПраваНаТаблицу.ПользовательСПравом) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | ПраваНаТаблицу.ПользовательСПравом, - | ПраваНаТаблицу.ПравоИзменение - | И ТекущаяТаблица.ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - | ИЗ - | ПользователиСПравамиСОграничениемНаТаблицу КАК ПраваНаТаблицу - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиНаЭлементыДанных КАК ТекущаяТаблица - | ПО (ТекущаяТаблица.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ПраваПользователей - | - |СГРУППИРОВАТЬ ПО - | ПраваПользователей.Ссылка, - | ПраваПользователей.ПользовательСПравом"; - - Если Не ПараметрыОграничения.ЭтоСсылочныйТип - И ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка КАК Ссылка", - "ПраваПользователей.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ПраваПользователейНаЗаписиРегистраПоВладельцу"); // @query-part-1, @query-part-2 - - ТекстЗапроса = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаПравСДанными; - - ИначеЕсли Не ПараметрыОграничения.ЭтоСсылочныйТип Тогда - - УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, ПараметрыОграничения.Список); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "ТекущаяТаблица КАК ТекущаяТаблица", - ПараметрыОграничения.Список + " КАК ТекущаяТаблица"); // @query-part-1, @query-part-2 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", - ТекстСОтступом(ОтборПоИзмерениям, " ")); - КонецЕсли; - - Если ПараметрыОграничения.ЭтоСсылочныйТип - Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", "ИСТИНА"); - КонецЕсли; - - Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; - -КонецПроцедуры - -// Требуется, как начальная максимальная дата при планировании начального обновления доступа. -// -// Возвращаемое значение: -// Дата -// -Функция МаксимальнаяДата() Экспорт - - Возврат '39991231235959'; - -КонецФункции - -// Требуется, как начальная максимальная дата при планировании продолжения обновления доступа. -Функция МаксимальнаяДатаПриПродолжении() - - Возврат '39990101000000'; - -КонецФункции - -// Для функции НастройкиВнедрения. -Функция ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам) - - СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - - Возврат Свойства.ЯзыкАнглийский + "." + СоставИмени[1]; - -КонецФункции - -// Для процедуры ДобавитьТипыТребуемыеВОпределяемомТипе. -Функция ИмяТипаСсылки(ПолноеИмя, ТипыТаблицПоИменам) - - СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - - Если Не Свойства.ЭтоСсылочныйТип Тогда - Возврат ""; - КонецЕсли; - - Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда - ИмяТипа = Свойства.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS - Иначе - ИмяТипа = Свойства.ЯзыкАнглийский + "Ref." + СоставИмени[1]; - КонецЕсли; - - Возврат ИмяТипа; - -КонецФункции - -// Для функции НастройкиВнедрения. -Функция ИмяТипаСсылкиXML(ПолноеИмя, ТипыТаблицПоИменам) - - СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - - Если Свойства.ЭтоСсылочныйТип Тогда - Возврат Свойства.ЯзыкАнглийский + "Ref." + СоставИмени[1]; - КонецЕсли; - - Возврат ""; - -КонецФункции - -// Для функции ДобавитьТипыТребуемыеВОпределяемомТипе. -Функция ИмяТипаОбъектаИлиНабораЗаписей(ПолноеИмя, ТипыТаблицПоИменам) - - СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - ИмяТипа = ""; - - Если Свойства.ЭтоСсылочныйТип Тогда - Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда - ИмяТипа = Свойства.ЯзыкРусский + "Объект." + СоставИмени[1]; // @Non-NLS - Иначе - ИмяТипа = Свойства.ЯзыкАнглийский + "Object." + СоставИмени[1]; - КонецЕсли; - КонецЕсли; - - Если СтрНачинаетсяС(Свойства.ИмяКоллекции, "Регистры") Тогда - Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда - ИмяТипа = Свойства.ЯзыкРусский + "НаборЗаписей." + СоставИмени[1]; // @Non-NLS - Иначе - ИмяТипа = Свойства.ЯзыкАнглийский + "RecordSet." + СоставИмени[1]; - КонецЕсли; - КонецЕсли; - - Возврат ИмяТипа; - -КонецФункции - -// Для функции НастройкиВнедрения. -Функция ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам) - - СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - - Если Свойства.ЭтоСсылочныйТип Тогда - Возврат Свойства.ЯзыкАнглийский + "Object." + СоставИмени[1]; - КонецЕсли; - - Если СтрНачинаетсяС(Свойства.ИмяКоллекции, "Регистры") Тогда - Возврат Свойства.ЯзыкАнглийский + "RecordSet." + СоставИмени[1]; - КонецЕсли; - - Возврат ""; - -КонецФункции - -// Для функции НастройкиВнедрения. -Процедура ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа) - - Если СтрНачинаетсяС(ИмяТипаОбъектаXML, "DocumentObject.") Тогда - ВладельцыЗначенийКлючейДоступа.Документы.Добавить(ИмяТипаОбъектаXML); - - ИначеЕсли СтрНачинаетсяС(ИмяТипаОбъектаXML, "CalculationRegisterRecordSet.") Тогда - ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета.Добавить(ИмяТипаОбъектаXML); - - ИначеЕсли СтрНайти(ИмяТипаОбъектаXML, "RecordSet.") > 0 Тогда - ВладельцыЗначенийКлючейДоступа.НаборыЗаписей.Добавить(ИмяТипаОбъектаXML); - - ИначеЕсли СтрНайти(ИмяТипаОбъектаXML, "Object.") > 0 Тогда - ВладельцыЗначенийКлючейДоступа.Объекты.Добавить(ИмяТипаОбъектаXML); - КонецЕсли; - -КонецПроцедуры - -// Для функции НастройкиВнедрения. -Процедура ДобавитьОграниченияВРолях(ПолноеИмяXML, ПолноеИмя, ОграниченияВРолях, СвойстваОграничений, Контекст) - - Свойства = СвойстваОграничений.Получить(ПолноеИмя); - Если Свойства <> Неопределено И Свойства.ДоступЗапрещен Тогда - Возврат; - КонецЕсли; - - ОграничениеВРоли = Новый Структура("ШаблонДляОбъекта, Параметры", Истина, Новый Массив); - ОграниченияВРолях.Вставить(ПолноеИмяXML, ОграничениеВРоли); - - Если Свойства = Неопределено Тогда - Возврат; - КонецЕсли; - - Если Свойства.ПолеВладельца <> Неопределено Тогда - ПолеВладельца = Свойства.ПолеВладельца; // См. НовоеПолеВладельца - ОграничениеВРоли.Параметры.Добавить(ПолеВладельца.Имя); - Возврат; - КонецЕсли; - - Если Свойства.ОпорныеПоля = Неопределено - Или Не ЗначениеЗаполнено(Свойства.ОпорныеПоля) Тогда - Возврат; - КонецЕсли; - - ОграничениеВРоли.ШаблонДляОбъекта = Ложь; - - Если ЗначениеЗаполнено(Свойства.ИмяОтдельногоРегистраКлючей) Тогда - ПервыйПараметр = Свойства.ИмяОтдельногоРегистраКлючей; - - ДобавитьТипыИзмерения(Свойства.ИмяОтдельногоРегистраКлючей, - Свойства.ОпорныеПоля, ПолноеИмя, Контекст); - Иначе - ПервыйПараметр = - УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных(ПолноеИмя); - - ДобавитьТипыИзмерения("КлючиДоступаКРегистрам", - Свойства.ОпорныеПоля, ПолноеИмя, Контекст); - - Контекст.ПредопределенныеИдентификаторы.Вставить(ПервыйПараметр, ПолноеИмя); - КонецЕсли; - - ОграничениеВРоли.Параметры.Добавить(ПервыйПараметр); - - Для Каждого ОпорноеПоле Из Свойства.ОпорныеПоля.Все Цикл - ОграничениеВРоли.Параметры.Добавить(ОпорноеПоле); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ДобавитьОграниченияВРолях. -Процедура ДобавитьТипыИзмерения(ИмяРегистраКлючей, ОпорныеПоля, ИмяИсходногоРегистра, Контекст) - - Если ОпорныеПоля.Все.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ТипыИзмерений = ТипыИзмеренийРегистраКлючей(Контекст.ТипыИзмеренийРегистровКлючей, ИмяРегистраКлючей); - ТипыТаблицПоИменам = Контекст.ТипыТаблицПоИменам; - - ИменаТипов = ТипыИзмерений.ИменаТипов; - ПоляРегистровПоТипам = ТипыИзмерений.ПоляРегистровПоТипам; - - ПоляРегистра = Новый Массив; - ТипыИзмерений.ПоляРегистров.Вставить(ИмяИсходногоРегистра, ПоляРегистра); - - Для Каждого ИмяПоля Из ОпорныеПоля.Все Цикл - ХранилищеТиповПоля = ОпорныеПоля.ТипыВсех[ОпорныеПоля.Все.Найти(ИмяПоля)]; // ХранилищеЗначения - ТипыПоля = ХранилищеТиповПоля.Получить(); - ПоляРегистра.Добавить(Новый Структура("Поле, Тип", ИмяПоля, ТипыПоля)); - Для Каждого Тип Из ТипыПоля.Типы() Цикл - ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); - Если ОбъектМетаданных = Неопределено Тогда - СинтаксисЯзыка = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка(); - ИмяТипа = СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(Тип)).ЯзыкАнглийский; - Иначе - ИмяТипа = ИмяТипаСсылкиXML(Метаданные.НайтиПоТипу(Тип).ПолноеИмя(), ТипыТаблицПоИменам); - КонецЕсли; - Если ИменаТипов.Найти(ИмяТипа) = Неопределено Тогда - ИменаТипов.Добавить(ИмяТипа); - КонецЕсли; - ПоляРегистровПоТипу = ПоляРегистровПоТипам.Получить(ИмяТипа); - Если ПоляРегистровПоТипу = Неопределено Тогда - ПоляРегистровПоТипу = Новый Массив; - ПоляРегистровПоТипам.Вставить(ИмяТипа, ПоляРегистровПоТипу); - КонецЕсли; - ПолноеИмяПоля = ИмяИсходногоРегистра + "." + ИмяПоля; - Если ПоляРегистровПоТипу.Найти(ПолноеИмяПоля) = Неопределено Тогда - ПоляРегистровПоТипу.Добавить(ПолноеИмяПоля); - КонецЕсли; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для функции НастройкиВнедрения и процедуры ДобавитьТипыИзмерения. -Функция ТипыИзмеренийРегистраКлючей(ТипыИзмеренийРегистровКлючей, ИмяРегистраКлючей) - - ТипыИзмерений = ТипыИзмеренийРегистровКлючей.Получить(ИмяРегистраКлючей); - Если ТипыИзмерений = Неопределено Тогда - ТипыИзмерений = Новый Структура; - ТипыИзмерений.Вставить("ИменаТипов", Новый Массив); - ТипыИзмерений.Вставить("ПоляРегистров", Новый Соответствие); - ТипыИзмерений.Вставить("ПоляРегистровПоТипам", Новый Соответствие); - ТипыИзмеренийРегистровКлючей.Вставить(ИмяРегистраКлючей, ТипыИзмерений); - ТипыИзмерений.ИменаТипов.Добавить("EnumRef.ДополнительныеЗначенияДоступа"); - КонецЕсли; - - Возврат ТипыИзмерений; - -КонецФункции - -// Для функции ОграничиватьДоступНаУровнеЗаписейУниверсально. -Функция КонстантаПервоеОбновлениеДоступаЗавершилось() - - Возврат Не ВариантВстроенногоЯзыкаРусский() - Или Константы.ПервоеОбновлениеДоступаЗавершилось.Получить(); - -КонецФункции - -#КонецОбласти - -#Область ПроверкаДоступаПриИзменении - -// Для процедур ПроверитьДоступПередЗаписьюИсточника и др. -Процедура ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ() - - ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); - - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); - Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); - Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); - Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); - Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); - Блокировка.Добавить("Справочник.КлючиДоступа"); - Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ГруппыЗначенийДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗначенияГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗначенияГруппДоступаПоУмолчанию"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НастройкиПравОбъектов"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НаследованиеНастроекПравОбъектов"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - Блокировка.Заблокировать(); - -КонецПроцедуры - -// Для процедур ПроверитьДоступПередЗаписьюИсточника и др. -Процедура ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ() - - Если ЭтоСеансФоновогоОбновленияДоступа() Тогда - Возврат; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Константа.КоличествоПотоковОбновленияДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - Блокировка.Заблокировать(); - -КонецПроцедуры - -// Для обработчиков подписок на событие ПередЗаписью. -Процедура ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, ЭтоНаборЗаписей, Замещение) - - Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда - Возврат; - КонецЕсли; - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - Если Не ЭтоНаборЗаписей И Источник.ЭтоНовый() Тогда - ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); - Иначе - ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); - КонецЕсли; - КонецЕсли; - - ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь() - Или УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа() - Или Не УправлениеДоступом.ПроизводительныйВариант(); - - Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", - Новый УникальныйИдентификатор); - - ЕстьСтараяВерсия = Не ЭтоНаборЗаписей И Не Источник.ЭтоНовый() - Или ЭтоНаборЗаписей - И Замещение <> Ложь - И Не ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение); - - Если ЕстьСтараяВерсия Тогда - ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, ЭтоНаборЗаписей, Замещение); - ПроверитьДоступКИсточнику(Источник, Истина, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь); - - ИначеЕсли Не ЭтоНаборЗаписей Тогда - УстановитьРазрешенныйКлючДоступаДляНовогоОбъекта(Источник, ЭтоПолноправныйПользователь); - КонецЕсли; - - Если ЭтоНаборЗаписей Тогда - ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью(Источник, Замещение, ЭтоПолноправныйПользователь); - КонецЕсли; - -КонецПроцедуры - -// Для обработчиков подписок на событие ПриЗаписи. -Процедура ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, ЭтоНаборЗаписей, Замещение) - - Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда - Возврат; - КонецЕсли; - - ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь() - Или УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа() - Или Не УправлениеДоступом.ПроизводительныйВариант(); - - // Проверка доступа к новой версии. - ПроверитьДоступКИсточнику(Источник, Ложь, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь); - - ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, ЭтоНаборЗаписей, Ложь); - -КонецПроцедуры - -// Для обработчиков подписок на событие ПередУдалением. -Процедура ПроверитьДоступПередУдалениемИсточника(Источник, Отказ) - - Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда - Возврат; - КонецЕсли; - - Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", - Новый УникальныйИдентификатор); - - ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, Ложь, Ложь); - ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, Ложь, Истина); - -КонецПроцедуры - - -// Для процедур ПроверитьДоступПередЗаписьюИсточника, ПроверитьДоступПриЗаписиИсточника. -Функция ПропуститьПроверкуДоступа(Отказ, Источник) - - Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда - Возврат Истина; - КонецЕсли; - - Если УправлениеДоступомСлужебныйПовтИсп.РазделенныеДанныеНедоступны() Тогда - Возврат Истина; - КонецЕсли; - - Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь) Тогда - Возврат Истина; - КонецЕсли; - - ОтключениеОбновления = ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа; // См. НовоеОтключениеОбновленияКлючейДоступа - Если ОтключениеОбновления.Полное Тогда - Возврат Истина; - КонецЕсли; - - Если ОтключениеОбновления.Стандартное Тогда - Кэш = УправлениеДоступомСлужебныйПовтИсп.КэшИзмененныхСписковПриОтключенномОбновленииКлючейДоступа(); - ТипИсточника = ТипЗнч(Источник); - Если Кэш.Получить(ТипИсточника) <> Неопределено Тогда - Возврат Истина; - КонецЕсли; - ОтключениеОбновления = Новый Структура(ОтключениеОбновления); - ИзмененныеСписки = ОтключениеОбновления.ИзмененныеСписки.Получить(); - ИзмененныеСписки.Вставить(ТипИсточника, Истина); - ОтключениеОбновления.ИзмененныеСписки = Новый ХранилищеЗначения(ИзмененныеСписки); - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа = Новый ФиксированнаяСтруктура(ОтключениеОбновления); - УстановитьПривилегированныйРежим(Истина); - УстановитьОтключениеБезопасногоРежима(Истина); - - Кэш.Вставить(ТипИсточника, Истина); - Возврат Истина; - КонецЕсли; - - Если Отказ Тогда - Возврат Истина; - КонецЕсли; - - Возврат Ложь; - -КонецФункции - -// Для процедуры ПроверитьДоступПередЗаписьюИсточника. -Процедура ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, ЭтоНаборЗаписей, Замещение) - - ПолноеИмя = Источник.Метаданные().ПолноеИмя(); - СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмя, - Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции); - - Если СвойстваСпискаКакВедущего = Неопределено - Или СвойстваСпискаКакВедущего.ПоЗначениямПолей = Неопределено Тогда - - Источник.ДополнительныеСвойства.Вставить( - "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи"); - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - - Если ЭтоНаборЗаписей Тогда - ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(Источник, Запрос, Замещение); - Запрос.Текст = СтрЗаменить(СвойстваСпискаКакВедущего.ПоЗначениямПолей.ТекстЗапроса, - "&ОтборПоИзмерениям", ОтборПоИзмерениям); - Иначе - Запрос.Текст = СвойстваСпискаКакВедущего.ПоЗначениямПолей.ТекстЗапроса; - Запрос.УстановитьПараметр("СсылкаНаОбъект", Источник.Ссылка); - КонецЕсли; - - Источник.ДополнительныеСвойства.Вставить( - "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи", - Запрос.ВыполнитьПакет()); - -КонецПроцедуры - -// Для процедур ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа, ОбновитьКлючиДоступаКНаборуЗаписей и -// функций ДоступРазрешен, ЧтениеДоступно. -// -Функция ОтборПоИзмерениямНабораЗаписей(НаборЗаписей, Запрос, Замещение = Неопределено, ЗапросНовыхКомбинаций = Неопределено) - - Параметры = ОбщегоНазначения.НовыеПараметрыОтбораЗаписейНабораИзБазыДанных(); - Параметры.ПрефиксИменПолейВПараметрах = "ЗначениеПоля"; - - ОтборЗаписей = ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение,, Параметры); - - Для Каждого КлючИЗначение Из ОтборЗаписей.ПараметрыЗапроса Цикл - Если Запрос <> Неопределено Тогда - Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЕсли; - Если ЗапросНовыхКомбинаций <> Неопределено Тогда - ЗапросНовыхКомбинаций.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЕсли; - КонецЦикла; - - Возврат ОтборЗаписей.УсловиеЗапроса; - -КонецФункции - -// Для процедуры ПроверитьДоступПередЗаписьюИсточника. -Процедура УстановитьРазрешенныйКлючДоступаДляНовогоОбъекта(Источник, ЭтоПолноправныйПользователь) - - Если ЭтоПолноправныйПользователь Тогда - Возврат; - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - СсылкаНового = ПользователиСлужебный.СсылкаОбъекта(Источник); - РазрешенныйКлючДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа(); - - НаборЗаписей = РегистрыСведений.КлючиДоступаКОбъектам.СоздатьНаборЗаписей(); - НаборЗаписей.Отбор.Объект.Установить(СсылкаНового); - - Запись = НаборЗаписей.Добавить(); - Запись.Объект = СсылкаНового; - Запись.КлючДоступаПользователей = РазрешенныйКлючДоступа; - Запись.КлючДоступаВнешнихПользователей = РазрешенныйКлючДоступа; - - НаборЗаписей.Записать(); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Для процедур ПроверитьДоступПередЗаписьюИсточника, ПроверитьДоступПриЗаписиИсточника. -Процедура ПроверитьДоступКИсточнику(Источник, ПередЗаписью, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь) - - Если ПередЗаписью И ЭтоПолноправныйПользователь Тогда - Возврат; - КонецЕсли; - - ПолноеИмя = Источник.Метаданные().ПолноеИмя(); - ИдентификаторТранзакции = Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции; - ВсеПараметрыОграничения = ПараметрыОграниченияПриПроверкеДоступа(Источник, ПолноеИмя, ИдентификаторТранзакции); - - Если Пользователи.ЭтоСеансВнешнегоПользователя() Тогда - ПараметрыОграничения = ВсеПараметрыОграничения.ДляВнешнихПользователей; - ПараметрыОграниченияДополнительные = ВсеПараметрыОграничения.ДляПользователей - Иначе - ПараметрыОграничения = ВсеПараметрыОграничения.ДляПользователей; - ПараметрыОграниченияДополнительные = ВсеПараметрыОграничения.ДляВнешнихПользователей - КонецЕсли; - - Если ПараметрыОграничения.ДоступЗапрещен И Не ЭтоПолноправныйПользователь Тогда - Если ПараметрыОграничения.ДляВнешнихПользователей Тогда - ШаблонОшибки = - НСтр("ru = 'Внешним пользователям запрещен доступ к данным списка - |""%1"".'"); - Иначе - ШаблонОшибки = - НСтр("ru = 'Пользователям запрещен доступ к данным списка - |""%1"".'"); - КонецЕсли; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, - Источник.Метаданные().Представление()); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если ЭтоНаборЗаписей Тогда - ПроверитьДоступКНаборуЗаписей(Источник, ПередЗаписью, Замещение, ЭтоПолноправныйПользователь, - ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные); - Иначе - ПроверитьДоступКОбъекту(Источник, ПередЗаписью, ЭтоПолноправныйПользователь, - ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПроверитьДоступКИсточнику. -// -// Возвращаемое значение: -// см. РассчитанныеПараметрыОграничения -// -Функция ПараметрыОграниченияПриПроверкеДоступа(Источник, ПолноеИмя, ИдентификаторТранзакции) - - Возврат ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Null); - -КонецФункции - -// Для процедуры ПроверитьДоступКИсточнику. -Процедура ПроверитьДоступКОбъекту(Источник, ПередЗаписью, ЭтоПолноправныйПользователь, - ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные) - - ЭтоНовый = Не Источник.ДополнительныеСвойства.Свойство( - "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи"); - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Если Не ПередЗаписью Тогда - КлючДоступаОбновлен = Ложь; - - ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, - ПараметрыОграничения, КлючДоступаОбновлен); - - ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, - ПараметрыОграниченияДополнительные); - - Если Не КлючДоступаОбновлен Тогда - Возврат; - КонецЕсли; - КонецЕсли; - - Если ПараметрыОграничения.ОграничениеОтключено Или ЭтоПолноправныйПользователь Тогда - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение; - - ПроверкаДобавления = Ложь; - Если Не ПередЗаписью Тогда - УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления); - КонецЕсли; - - ОбновитьРазрешенныеНаборыВПараметрахСеанса(); - - Запрос.УстановитьПараметр("Объект", Источник.Ссылка); - УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос); - - Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", - ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); - КонецЕсли; - - Если Не РезультатЗапросаПроверкиДоступа(Запрос, Источник).Пустой() Тогда - Возврат; // Доступ разрешен. - КонецЕсли; - - Если ПроверкаДобавления Тогда - Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение; - ПравоИзменения = Не Запрос.Выполнить().Пустой(); - Иначе - ПравоИзменения = Ложь; - КонецЕсли; - - Если ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда - ПравоЧтения = Истина; - Иначе - Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение; - ПравоЧтения = Не Запрос.Выполнить().Пустой(); - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - Данные = ?(ПередЗаписью, Источник.Ссылка, Источник); - СообщитьОбОшибкеДоступа(Данные, ПередЗаписью, ПравоЧтения, ПравоИзменения, ЭтоНовый); - -КонецПроцедуры - -// Для процедуры ПроверитьДоступКОбъекту и функции ДоступРазрешен. -Процедура УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления) - - ПроверкаДобавления = ЭтоНовый И Не ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу; - Если Не ПроверкаДобавления Тогда - Возврат; - КонецЕсли; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "РазрешенныеКлючиДоступа.ПравоИзменение", "РазрешенныеКлючиДоступа.ПравоДобавление"); - -КонецПроцедуры - -// Для процедуры ПроверитьДоступКОбъекту. -Процедура ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, - ПараметрыОграничения, КлючДоступаОбновлен = Ложь) - - Если ПараметрыОграничения.ДоступЗапрещен - Или (ПараметрыОграничения.ОграничениеОтключено - И Не ПараметрыОграничения.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей) Тогда - Возврат; - КонецЕсли; - - Если Не ЭтоНовый И Не КлючДоступаИсточникаУстарел(Источник.Ссылка, ПараметрыОграничения, Источник) Тогда - Возврат; - КонецЕсли; - - ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(Источник.Ссылка, - ПараметрыОграничения, ИдентификаторТранзакции,,, Источник); - - КлючДоступаОбновлен = Истина; - -КонецПроцедуры - -// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. -Функция РезультатЗапросаПроверкиДоступа(Запрос, Источник) - - Возврат Запрос.Выполнить(); - -КонецФункции - -// Для процедуры ПроверитьДоступКИсточнику. -Процедура ПроверитьДоступКНаборуЗаписей(Источник, ПередЗаписью, Замещение, ЭтоПолноправныйПользователь, - ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные) - - Если ПередЗаписью - И (Замещение = Ложь - Или ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение)) - Или Не ПередЗаписью - И (Источник.Количество() = 0 - Или ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение)) Тогда - - Возврат; - КонецЕсли; - - ОтборПоИзмерениям = ""; - Запрос = ?(ПараметрыОграничения.ОграничениеОтключено Или ЭтоПолноправныйПользователь, - Неопределено, Новый Запрос); - - ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, - ИдентификаторТранзакции, ПараметрыОграничения, ОтборПоИзмерениям, Запрос); - - ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, - ИдентификаторТранзакции, ПараметрыОграниченияДополнительные, "", Неопределено); - - Если Запрос = Неопределено Тогда - Возврат; - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Запрос.Текст = СтрЗаменить(ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение, - "&ОтборПоИзмерениям", ОтборПоИзмерениям); - - ОбновитьРазрешенныеНаборыВПараметрахСеанса(); - УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос); - - Если РезультатЗапросаПроверкиДоступа(Запрос, Источник).Пустой() Тогда - Возврат; // Доступ разрешен. - КонецЕсли; - - Если ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда - ПравоЧтения = Истина; - Иначе - Запрос.Текст = СтрЗаменить(ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение, - "&ОтборПоИзмерениям", ОтборПоИзмерениям); - ПравоЧтения = Запрос.Выполнить().Пустой(); - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - СообщитьОбОшибкеДоступа(Источник, ПередЗаписью, ПравоЧтения, Ложь, Ложь); - -КонецПроцедуры - -// Для процедуры ПроверитьДоступКНаборуЗаписей и для функции ДоступРазрешен. -Процедура ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, - ИдентификаторТранзакции, ПараметрыОграничения, ОтборПоИзмерениям, Запрос) - - Если ПараметрыОграничения.ДоступЗапрещен - Или ПараметрыОграничения.ОграничениеОтключено - Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу - И Запрос = Неопределено Тогда - - Возврат; - КонецЕсли; - - Если Не ПередЗаписью Тогда - ЗапросНовыхКомбинаций = Новый Запрос; - КонецЕсли; - - Если Замещение <> Ложь - И Не ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение) Тогда - - ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(Источник, Запрос, Замещение, ЗапросНовыхКомбинаций); - Иначе - КомбинацииЗначенийОпорныхПолей = КомбинацииЗначенийОпорныхПолей(Источник, - ОтборПоИзмерениям, ПараметрыОграничения); - - Если Запрос <> Неопределено Тогда - Запрос.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", КомбинацииЗначенийОпорныхПолей); - КонецЕсли; - ЗапросНовыхКомбинаций.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", КомбинацииЗначенийОпорныхПолей); - КонецЕсли; - - Если ПередЗаписью Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - Возврат; - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, - ОтборПоИзмерениям, Источник, ПараметрыОграничения); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Для процедуры ПроверитьДоступПередЗаписьюИсточника. -Процедура ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью(Источник, Замещение, ЭтоПолноправныйПользователь) - - Если ЭтоПолноправныйПользователь - Или Источник.Количество() = 0 - Или ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) Тогда - Возврат; - КонецЕсли; - - ПолноеИмя = Источник.Метаданные().ПолноеИмя(); - ИдентификаторТранзакции = Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции; - ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции); - - Если ПараметрыОграничения.ОграничениеОтключено - Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - Возврат; - КонецЕсли; - - ЗапросНовыхКомбинаций = Новый Запрос; - ОтборПоИзмерениям = ""; - - ЗапросНовыхКомбинаций.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", - КомбинацииЗначенийОпорныхПолей(Источник, ОтборПоИзмерениям, ПараметрыОграничения)); - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, - ОтборПоИзмерениям, Источник, ПараметрыОграничения); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Для процедур ПроверитьДоступКНаборуЗаписей, -// ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью. -// -Функция КомбинацииЗначенийОпорныхПолей(Источник, ОтборПоИзмерениям, ПараметрыОграничения) - - Поля = СтрСоединить(ПараметрыОграничения.ОпорныеПоля.Используемые, ","); - Поля = УправлениеДоступомСлужебныйПовтИсп.ПоляВРегистреСимволовМетаданных(ПараметрыОграничения.Список, Поля); - КомбинацииЗначенийОпорныхПолей = Источник.Выгрузить(, Поля); - КомбинацииЗначенийОпорныхПолей.Свернуть(Поля); - - ПоляОтбора = ""; - Для Каждого Поле Из ПараметрыОграничения.ОпорныеПоля.Используемые Цикл - ПоляОтбора = ПоляОтбора + ?(ПоляОтбора = "", "", ", ") + "ТекущаяТаблица." + Поле; - КонецЦикла; - ОтборПоИзмерениям = "(" + ПоляОтбора + ") В (&КомбинацииЗначенийОпорныхПолей)"; // @query-part-2 - - Возврат КомбинацииЗначенийОпорныхПолей; - -КонецФункции - -// Для процедур ПроверитьДоступКНаборуЗаписей, -// ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью. -// -Процедура ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, - ОтборПоИзмерениям, Источник, ПараметрыОграничения) - - ЭлементыДанных = ЭлементыДанныхНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, - ОтборПоИзмерениям, Источник, ПараметрыОграничения); - - Если ЭлементыДанных.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(ЭлементыДанных, ПараметрыОграничения, - Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции,,, Источник); - -КонецПроцедуры - -// Для процедуры ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей. -Функция ЭлементыДанныхНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, - ОтборПоИзмерениям, Источник, ПараметрыОграничения) - - Если ЗапросНовыхКомбинаций.Параметры.Свойство("КомбинацииЗначенийОпорныхПолей") Тогда - ЗапросНовыхКомбинаций.Текст = - ПараметрыОграничения.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей; - Иначе - ЗапросНовыхКомбинаций.Текст = СтрЗаменить( - ПараметрыОграничения.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей, - "&ОтборПоИзмерениям", - ОтборПоИзмерениям); - КонецЕсли; - - РезультатЗапросаНовыхКомбинаций = ЗапросНовыхКомбинаций.Выполнить(); - Если РезультатЗапросаНовыхКомбинаций.Пустой() Тогда - Возврат Новый Массив; - КонецЕсли; - - ЭлементыДанных = РезультатЗапросаНовыхКомбинаций.Выгрузить(); - ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов("Число")); - Индекс = 0; - - Если ПараметрыОграничения.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей Тогда - ВсеЭлементыДанных = ЭлементыДанных; - ЭлементыДанных = ВсеЭлементыДанных.Скопировать(Новый Массив); - Для Каждого ЭлементДанных Из ВсеЭлементыДанных Цикл - Если НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОграничения) Тогда - Продолжить; - КонецЕсли; - ЭлементДанных.ТекущаяСсылка = Индекс; - Индекс = Индекс + 1; - ЗаполнитьЗначенияСвойств(ЭлементыДанных.Добавить(), ЭлементДанных); - КонецЦикла; - Иначе - Для Каждого ЭлементДанных Из ЭлементыДанных Цикл - ЭлементДанных.ТекущаяСсылка = Индекс; - Индекс = Индекс + 1; - КонецЦикла; - КонецЕсли; - - Возврат ЭлементыДанных; - -КонецФункции - -// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. -Процедура СообщитьОбОшибкеДоступа(Данные, СтараяВерсия, ЕстьПравоЧтения, ЕстьПравоИзменения, ЭтоНовый) - - Если СтараяВерсия Тогда - Если ЕстьПравоЧтения Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недостаточно прав для изменения данных: - |%1'"), ПредставлениеДанных(Данные)); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недостаточно прав для чтения данных: - |%1'"), ПредставлениеДанных(Данные)); - КонецЕсли; - Иначе - Если ЕстьПравоЧтения И ЕстьПравоИзменения Тогда - Если ЭтоНовый Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недостаточно прав для добавления данных (нет права добавления): - |%1'"), ПредставлениеДанных(Данные)); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недостаточно прав для добавления данных (нет права добавления для сделанных изменений): - |%1'"), ПредставлениеДанных(Данные)); - КонецЕсли; - ИначеЕсли ЕстьПравоЧтения Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недостаточно прав для добавления данных (невозможно будет изменить): - |%1'"), ПредставлениеДанных(Данные)); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недостаточно прав для добавления данных (невозможно будет прочитать): - |%1.'"), ПредставлениеДанных(Данные)); - КонецЕсли; - КонецЕсли; - - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа); - -КонецПроцедуры - -// Для процедуры СообщитьОбОшибкеДоступа. -Функция ПредставлениеДанных(Данные) - - Если ТипЗнч(Данные) = Тип("Строка") Тогда - Возврат СокрЛП(Данные); - КонецЕсли; - - Если ТипЗнч(Данные) = Тип("Структура") Тогда - ЭтоРегистр = Истина; - Если ТипЗнч(Данные.Регистр) = Тип("Строка") Тогда - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Данные.Регистр); - Иначе - ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Данные.Регистр)); - КонецЕсли; - Иначе - ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Данные)); - ЭтоРегистр = ОбщегоНазначения.ЭтоРегистр(ОбъектМетаданных); - КонецЕсли; - - Если ОбъектМетаданных = Неопределено Тогда - Возврат ""; - КонецЕсли; - - Если ЭтоРегистр Тогда - ПредставлениеДанных = ОбъектМетаданных.Представление(); - - КоличествоПолей = 0; - Для каждого ЭлементОтбора Из Данные.Отбор Цикл - Если ЭлементОтбора.Использование Тогда - КоличествоПолей = КоличествоПолей + 1; - КонецЕсли; - КонецЦикла; - - Если КоличествоПолей = 1 Тогда - ПредставлениеДанных = ПредставлениеДанных - + " " + НСтр("ru = 'с полем'") + " " + Строка(Данные.Отбор); - - ИначеЕсли КоличествоПолей > 1 Тогда - ПредставлениеДанных = ПредставлениеДанных - + " " + НСтр("ru = 'с полями'") + " " + Строка(Данные.Отбор); - КонецЕсли; - Иначе - ПредставлениеДанных = Строка(Данные); - ПредставлениеМетаданных = ОбщегоНазначения.ПредставлениеОбъекта(ОбъектМетаданных); - - Если Не СтрЗаканчиваетсяНа(ПредставлениеДанных, "(" + ПредставлениеМетаданных + ")") - И Не СтрНачинаетсяС(ПредставлениеДанных, ПредставлениеМетаданных) Тогда - - ПредставлениеДанных = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 (%2)", - ПредставлениеДанных, ПредставлениеМетаданных); - КонецЕсли; - КонецЕсли; - - Возврат ПредставлениеДанных; - -КонецФункции - -// Для процедуры ПроверитьДоступКОбъекту и формы ОбновлениеДоступаРучноеУправление. -// -// Возвращаемое значение: -// Булево -// -Функция КлючДоступаИсточникаУстарел(СсылкаНаОбъект, ПараметрыОграничения, Источник = Неопределено) Экспорт - - Если ПараметрыОграничения.БезЗаписиКлючейДоступа Тогда - Возврат Ложь; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект); - - Если Не ЗначениеЗаполнено(ПараметрыОграничения.СоставПолей) Тогда - Запрос.УстановитьПараметр("Список", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); - КонецЕсли; - - Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиКлючаДоступаОбъекта; - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Если Запрос.Выполнить().Пустой() Тогда - Возврат Ложь; - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - Возврат Истина; - -КонецФункции - -// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей и формы ОбновлениеДоступаРучноеУправление. -Процедура ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(ОписаниеЭлементовДанных, ПараметрыОграничения, - ИдентификаторТранзакции, ОбновитьПраваНаКлючи = Ложь, ЕстьИзмененияПрав = Ложь, Источник = Неопределено) Экспорт - - Если ПараметрыОграничения.БезЗаписиКлючейДоступа Тогда - Возврат; - КонецЕсли; - - Если ТипЗнч(ОписаниеЭлементовДанных) = Тип("ТаблицаЗначений") Тогда - ЭлементыДанных = ОписаниеЭлементовДанных; - Иначе - ЭлементыДанных = Новый ТаблицаЗначений; - ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка"); - ЭлементыДанных.Добавить().ТекущаяСсылка = ОписаниеЭлементовДанных; - КонецЕсли; - - СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПараметрыОграничения.Список, - ИдентификаторТранзакции); - ИмяСвойстваВидаПользователей = ?(ПараметрыОграничения.ДляВнешнихПользователей, - "ДляВнешнихПользователей", "ДляПользователей"); - - ПараметрыОбновления = Новый Структура(ПараметрыОграничения); - ПараметрыОбновления.Вставить("ЕстьИзмененияПрав", ЕстьИзмененияПрав); - ПараметрыОбновления.Вставить("ОбновитьПраваНаКлючи", ОбновитьПраваНаКлючи); - ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); - ПараметрыОбновления.Вставить("ИдентификаторСписка", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); - - Если СвойстваСпискаКакВедущего = Неопределено - Или СвойстваСпискаКакВедущего.ПоКлючамДоступа = Неопределено - Или СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей] = Неопределено Тогда - - ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", Новый Массив); - Иначе - ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", - СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей]); - КонецЕсли; - - ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ЭлементыДанных, ПараметрыОбновления); - - ЕстьИзмененияПрав = ПараметрыОбновления.ЕстьИзмененияПрав; - -КонецПроцедуры - -// Для регистра сведений ГруппыЗначенийДоступа. -Процедура ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами(ЗначенияСИзменениямиПоТипам) Экспорт - - Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - Возврат; - КонецЕсли; - - ИдентификаторТранзакции = Новый УникальныйИдентификатор; - - СпискиДляОбновления = Новый Соответствие; - Для Каждого ОписаниеЗначений Из ЗначенияСИзменениямиПоТипам Цикл - ПолноеИмяВедущего = Метаданные.НайтиПоТипу(ОписаниеЗначений.Ключ).ПолноеИмя(); - СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмяВедущего, ИдентификаторТранзакции); - Если СвойстваСпискаКакВедущего = Неопределено - Или СвойстваСпискаКакВедущего.ПоЗначениямСГруппами = Неопределено Тогда - Продолжить; - КонецЕсли; - ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, - СвойстваСпискаКакВедущего.ПоЗначениямСГруппами, "ДляПользователей"); - - ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, - СвойстваСпискаКакВедущего.ПоЗначениямСГруппами, "ДляВнешнихПользователей"); - КонецЦикла; - - ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, - ИдентификаторТранзакции, - "ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами", - ?(ЗначенияСИзменениямиПоТипам.Количество() <> 1 Или ОписаниеЗначений.Значение = Истина, - Неопределено, Новый Структура("ПоЗначениямСГруппами", ОписаниеЗначений.Значение))); - -КонецПроцедуры - -// Для процедуры ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами. -Процедура ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, ПоЗначениямСГруппами, ИмяВидаПользователей) - - ПолныеИмена = ПоЗначениямСГруппами[ИмяВидаПользователей]; - Если ПолныеИмена = Неопределено Тогда - Возврат; - КонецЕсли; - - Для Каждого ПолноеИмя Из ПолныеИмена Цикл - СписокДляОбновления = СпискиДляОбновления.Получить(ПолноеИмя); - Если СписокДляОбновления = Неопределено Тогда - СписокДляОбновления = Новый Структура("ДляПользователей, ДляВнешнихПользователей", Ложь, Ложь); - СпискиДляОбновления.Вставить(ПолноеИмя, СписокДляОбновления); - КонецЕсли; - СписокДляОбновления[ИмяВидаПользователей] = Истина; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа, ЗаписатьКлючиДоступаОбъектов, -// ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами. -// -Процедура ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, ИдентификаторТранзакции, - Описание, ВедущийОбъект = Неопределено, ЭтоПродолжениеОбновления = Ложь) - - Если ТипЗнч(СпискиДляОбновления) = Тип("Соответствие") - И СпискиДляОбновления.Количество() = 0 - Или ТипЗнч(СпискиДляОбновления) = Тип("Структура") - И СпискиДляОбновления.ИменаСписков.Количество() = 0 Тогда - - Возврат; - КонецЕсли; - - Списки = Новый Массив; - СпискиДляПользователей = Новый Массив; - СпискиДляВнешнихПользователей = Новый Массив; - - Если ТипЗнч(СпискиДляОбновления) = Тип("Соответствие") Тогда - Для Каждого ОписаниеСписка Из СпискиДляОбновления Цикл - ПолноеИмя = ОписаниеСписка.Ключ; - Свойства = ОписаниеСписка.Значение; - - Если Свойства.ДляПользователей Тогда - ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Ложь); - - Если ПараметрыОграничения.ОграничениеОтключено - Или ПараметрыОграничения.ДоступЗапрещен - Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - - Свойства.ДляПользователей = Ложь; - КонецЕсли; - КонецЕсли; - - Если Свойства.ДляВнешнихПользователей Тогда - ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Истина); - - Если ПараметрыОграничения.ОграничениеОтключено - Или ПараметрыОграничения.ДоступЗапрещен - Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - - Свойства.ДляВнешнихПользователей = Ложь; - КонецЕсли; - КонецЕсли; - - Если Свойства.ДляПользователей И Свойства.ДляВнешнихПользователей Тогда - Списки.Добавить(ПолноеИмя); - - ИначеЕсли Свойства.ДляПользователей Тогда - СпискиДляПользователей.Добавить(ПолноеИмя); - - ИначеЕсли Свойства.ДляВнешнихПользователей Тогда - СпискиДляВнешнихПользователей.Добавить(ПолноеИмя); - КонецЕсли; - КонецЦикла; - Иначе - Для Каждого ПолноеИмя Из СпискиДляОбновления.ИменаСписков Цикл - ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, - ИдентификаторТранзакции, СпискиДляОбновления.ДляВнешнихПользователей); - - Если ПараметрыОграничения.ОграничениеОтключено - Или ПараметрыОграничения.ДоступЗапрещен - Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда - - Продолжить; - КонецЕсли; - - Если СпискиДляОбновления.ДляВнешнихПользователей Тогда - СпискиДляВнешнихПользователей.Добавить(ПолноеИмя); - Иначе - СпискиДляПользователей.Добавить(ПолноеИмя); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Если Описание = "ЗаполнитьКэшПараметровОграниченияДоступа" Тогда - Возврат; - КонецЕсли; - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; - ПараметрыПланирования.Описание = Описание; - ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; - ПараметрыПланирования.ЭтоПродолжениеОбновления = ЭтоПродолжениеОбновления; - ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); - - ПараметрыПланирования.ДляВнешнихПользователей = Ложь; - ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); - - ПараметрыПланирования.ДляПользователей = Ложь; - ПараметрыПланирования.ДляВнешнихПользователей = Истина; - ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); - -КонецПроцедуры - -// Для процедуры ПроверитьДоступПриЗаписиИсточника, ПроверитьДоступПередУдалениемИсточника. -Процедура ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, ЭтоНаборЗаписей, Удаление) - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ПолноеИмя = Источник.Метаданные().ПолноеИмя(); - СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмя, - Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции); - - Если СвойстваСпискаКакВедущего = Неопределено - Или СвойстваСпискаКакВедущего.ПоЗначениямПолей = Неопределено Тогда - Возврат; - КонецЕсли; - - Если Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи") Тогда - РезультатыЗапроса = Источник.ДополнительныеСвойства.УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи; - Иначе - РезультатыЗапроса = Неопределено; - КонецЕсли; - - ИзмененияПоЗначениямПолей = Новый Структура; - ИзмененияПоЗначениямПолей.Вставить("Описание", ?(ЭтоНаборЗаписей, Источник.Отбор, Источник.Ссылка)); - ИзмененияПоЗначениямПолей.Вставить("ИзмененнаяТаблица", ПолноеИмя); - ИзмененияПоЗначениямПолей.Вставить("СоставИзменений"); - - ВедущийОбъект = ОписаниеВедущегоОбъекта(); - ВедущийОбъект.Вставить("ПоЗначениямПолей", ИзмененияПоЗначениямПолей); - - ПоЗначениямПолей = СвойстваСпискаКакВедущего.ПоЗначениямПолей; - ПоляШапки = ПоЗначениямПолей.ПоляШапки; - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; - ПараметрыПланирования.Описание = "ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа"; - ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; - - Если ЭтоНаборЗаписей Тогда - Если ЗначениеЗаполнено(ПоляШапки.ВсеПоля) Тогда - РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[0]); - ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, - Источник, ПоляШапки.НаборыПолей, ПараметрыПланирования); - КонецЕсли; - Иначе - Если ЗначениеЗаполнено(ПоляШапки.ВсеПоля) Тогда - РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[0]); - НовыеЗначения = Новый ТаблицаЗначений; - Для Каждого ИмяПоля Из ПоляШапки.ВсеПоля Цикл - НовыеЗначения.Колонки.Добавить(ИмяПоля, ПоляШапки.ТипыВсехПолей.Получить(ИмяПоля).Получить()); - КонецЦикла; - Если Не Удаление Тогда - ЗаполнитьЗначенияСвойств(НовыеЗначения.Добавить(), Источник); - КонецЕсли; - ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, - НовыеЗначения, ПоляШапки.НаборыПолей, ПараметрыПланирования); - Индекс = 1; - Иначе - Индекс = 0; - КонецЕсли; - Для Каждого ОписаниеТабличнойЧасти Из ПоЗначениямПолей.ТабличныеЧасти Цикл - РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[Индекс]); - ИзмененияПоЗначениямПолей.ИзмененнаяТаблица = ПолноеИмя + "." + ОписаниеТабличнойЧасти.Имя; - НовыеЗначения = НовыеЗначенияТабличнойЧасти(Источник, ОписаниеТабличнойЧасти, Удаление); - // @skip-check query-in-loop - В вызываемом варианте ветка с запросом не используется - ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, - НовыеЗначения, ОписаниеТабличнойЧасти.НаборыПолей, ПараметрыПланирования); - Индекс = Индекс + 1; - КонецЦикла; - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ПоЗначениямПолей - Структура: -// ** Описание - ЛюбаяСсылка -// - Отбор -// ** ИзмененнаяТаблица - Строка - полное имя списка -// ** СоставИзменений - см. СоставИзмененийТаблицы -// * ПоКлючамДоступа - СправочникСсылка.КлючиДоступа -// * ПоЗначениямСГруппами - ОпределяемыйТип.ЗначениеДоступа - только значения доступа с группами. -// * ПоДаннымКэшаРасчетаПрав - Строка - наименование данных для кэша расчета прав. -// -Функция ОписаниеВедущегоОбъекта() - - Возврат Новый Структура; - -КонецФункции - -// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа. -Функция НовыеЗначенияТабличнойЧасти(Источник, ОписаниеТабличнойЧасти, Удаление) - - Поля = Новый Массив(ОписаниеТабличнойЧасти.ВсеПоля); - - ИмяПоляСсылка = "Ссылка"; // @Non-NLS - Индекс = Поля.Найти(ИмяПоляСсылка); - Если Индекс <> Неопределено Тогда - Поля.Удалить(Индекс); - Иначе - ИмяПоляСсылка = "Ref"; - Индекс = Поля.Найти(ИмяПоляСсылка); - Если Индекс <> Неопределено Тогда - Поля.Удалить(Индекс); - КонецЕсли; - КонецЕсли; - - НовыеЗначения = Источник[ОписаниеТабличнойЧасти.Имя].Выгрузить( - ?(Удаление, Новый Массив, Неопределено), СтрСоединить(Поля, ", ")); // ТаблицаЗначений - - Если Индекс <> Неопределено Тогда - Типы = Новый Массив; - Типы.Добавить(ТипЗнч(Источник.Ссылка)); - НовыеЗначения.Колонки.Добавить(ИмяПоляСсылка, Новый ОписаниеТипов(Типы)); - НовыеЗначения.ЗаполнитьЗначения(Источник.Ссылка, ИмяПоляСсылка); - КонецЕсли; - - Возврат НовыеЗначения; - -КонецФункции - -// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа. -Процедура ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, - Источник, НаборыПолейПоВидамПользователей, ПараметрыПланирования) - - ВидыПользователей = Новый Массив; - ВидыПользователей.Добавить("ДляПользователей"); - ВидыПользователей.Добавить("ДляВнешнихПользователей"); - - Для Каждого ВидПользователей Из ВидыПользователей Цикл - НаборыПолей = НаборыПолейПоВидамПользователей[ВидПользователей]; - Если НаборыПолей = Неопределено Тогда - Продолжить; - КонецЕсли; - Если ВидПользователей = "ДляПользователей" Тогда - ПараметрыПланирования.ДляВнешнихПользователей = Ложь; - ПараметрыПланирования.ДляПользователей = Истина; - Иначе - ПараметрыПланирования.ДляВнешнихПользователей = Истина; - ПараметрыПланирования.ДляПользователей = Ложь; - КонецЕсли; - Для Каждого ОписаниеНабораПолей Из НаборыПолей Цикл - СоставИзменений = СоставИзмененийТаблицы(РезультатЗапроса, Источник, ОписаниеНабораПолей.Ключ); - Если СоставИзменений = Null Тогда - Продолжить; - КонецЕсли; - Для Каждого ОписаниеЗависимыхТаблиц Из ОписаниеНабораПолей.Значение Цикл - Если ОписаниеЗависимыхТаблиц.Ключ = ОписаниеНабораПолей.Ключ - Или СоставИзменений = Неопределено Тогда - ТекущийСоставИзменений = СоставИзменений; - Иначе - ТекущийСоставИзменений = СоставИзменений.Скопировать(, ОписаниеЗависимыхТаблиц.Ключ); - ТекущийСоставИзменений.Свернуть(ОписаниеЗависимыхТаблиц.Ключ); - КонецЕсли; - ПараметрыПланирования.ВедущийОбъект.ПоЗначениямПолей.СоставИзменений = ТекущийСоставИзменений; - // @skip-check query-in-loop - В вызываемом варианте ветка с запросом не используется - ЗапланироватьОбновлениеДоступа(ОписаниеЗависимыхТаблиц.Значение, ПараметрыПланирования); - КонецЦикла; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей. -// -// Возвращаемое значение: -// ТаблицаЗначений -// -Функция СоставИзмененийТаблицы(РезультатЗапроса, Источник, Поля) - - МаксимумКомбинаций = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); - Если РезультатЗапроса = Неопределено Тогда - СтарыеКомбинации = Новый ТаблицаЗначений; - Иначе - СтарыеКомбинации = РезультатЗапроса.Выгрузить(); - Если СтрРазделить(Поля, ",").Количество() < СтарыеКомбинации.Колонки.Количество() Тогда - СтарыеКомбинации.Свернуть(Поля); - КонецЕсли; - КонецЕсли; - - Если СтарыеКомбинации.Количество() >= МаксимумКомбинаций Тогда - Возврат Неопределено; - КонецЕсли; - - Если ТипЗнч(Источник) = Тип("ТаблицаЗначений") Тогда - НовыеКомбинации = Источник.Скопировать(, Поля); - Иначе - НовыеКомбинации = Источник.Выгрузить(, Поля); - КонецЕсли; - НовыеКомбинации.Свернуть(Поля); - - Если НовыеКомбинации.Количество() >= МаксимумКомбинаций Тогда - Возврат Неопределено; - КонецЕсли; - - СоставИзменений = НовыеКомбинации.Скопировать(Новый Массив); - - НовыеКомбинации.Колонки.Добавить("ВидИзменения", Новый ОписаниеТипов("Число")); - НовыеКомбинации.ЗаполнитьЗначения(1, "ВидИзменения"); - Для Каждого Строка Из СтарыеКомбинации Цикл - НоваяСтрока = НовыеКомбинации.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); - НоваяСтрока.ВидИзменения = -1; - КонецЦикла; - НовыеКомбинации.Свернуть(Поля, "ВидИзменения"); - - Для Каждого Строка Из НовыеКомбинации Цикл - Если Строка.ВидИзменения <> 0 Тогда - ЗаполнитьЗначенияСвойств(СоставИзменений.Добавить(), Строка); - КонецЕсли; - КонецЦикла; - - Возврат ?(СоставИзменений.Количество() > 0, СоставИзменений, Null); - -КонецФункции - -// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. -Процедура ПроверитьОбъектыНастроекДоступа() - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - УстановитьРазделяемуюБлокировку("Справочник.ГруппыВнешнихПользователей"); - УстановитьРазделяемуюБлокировку("Справочник.ВнешниеПользователи"); - УстановитьРазделяемуюБлокировку("Справочник.ГруппыПользователей"); - УстановитьРазделяемуюБлокировку("Справочник.Пользователи"); - УстановитьРазделяемуюБлокировку("Справочник.ПрофилиГруппДоступа"); - УстановитьРазделяемуюБлокировку("Справочник.ГруппыДоступа"); - -КонецПроцедуры - -// Для процедуры ПроверитьОбъектыНастроекДоступа. -Процедура УстановитьРазделяемуюБлокировку(ИмяТаблицы) - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить(ИмяТаблицы); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// См. УправлениеДоступом.УстановитьБлокировкуПередЗаписьюВФайловойИБ -Процедура УстановитьБлокировкуПередЗаписьюВФайловойИБ(ПередЗаписьюНовогоОбъекта = Ложь, - ПередЗаписьюНастройкиДоступа = Ложь) Экспорт - - Если ПередЗаписьюНастройкиДоступа Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(,, Истина); - ИначеЕсли ПередЗаписьюНовогоОбъекта Тогда - ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); - Иначе - ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); - КонецЕсли; - -КонецПроцедуры - -Процедура ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(ЭтоОшибкаБлокировки = Ложь, - ОбновлениеПараметров = Ложь, ЭтоЗаписьОбъектаНастроекДоступа = Ложь) - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Константа.КоличествоПотоковОбновленияДоступа"); - Если Не ЭтоСеансФоновогоОбновленияДоступа() Тогда - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - КонецЕсли; - Попытка - Блокировка.Заблокировать(); - Исключение - ЭтоОшибкаБлокировки = Истина; - ВызватьИсключение; - КонецПопытки; - - Если ЭтоЗаписьОбъектаНастроекДоступа Тогда - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - Попытка - Блокировка.Заблокировать(); - Исключение - ЭтоОшибкаБлокировки = Истина; - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); - Если Не ОбновлениеПараметров Тогда - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - КонецЕсли; - Попытка - Блокировка.Заблокировать(); - Исключение - ЭтоОшибкаБлокировки = Истина; - ВызватьИсключение; - КонецПопытки; - - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаКДанным"); - Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаПользователей"); - Попытка - Блокировка.Заблокировать(); - Исключение - ЭтоОшибкаБлокировки = Истина; - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для вызова и модуля менеджера справочника ГруппыДоступа. -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа(ГруппыДоступа, - ТипыИзмененныхУчастников, ПриЗагрузке = Ложь) Экспорт - - Если Не ТипыИзмененныхУчастников.Пользователи - И Не ТипыИзмененныхУчастников.ВнешниеПользователи Тогда - Возврат; - КонецЕсли; - - Описание = ?(ПриЗагрузке, - "ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступаПриЗагрузке", - "ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа"); - - ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "УчастникиГруппДоступа"); - - Запрос = Новый Запрос; - - Если ГруппыДоступа = Неопределено Тогда - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТаблицыГруппДоступа.Таблица КАК Таблица - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа"; - Иначе - Запрос.УстановитьПараметр("ГруппыДоступа", ГруппыДоступа); - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТаблицыГруппДоступа.Таблица КАК Таблица - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - |ГДЕ - | ТаблицыГруппДоступа.ГруппаДоступа В(&ГруппыДоступа)"; - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Таблицы = Запрос.Выполнить().Выгрузить(); - - ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, Описание, - ТипыИзмененныхУчастников.Пользователи, ТипыИзмененныхУчастников.ВнешниеПользователи, Истина); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Для процедуры ПослеОбновленияСоставовГруппПользователей и -// модуля менеджера справочника ГруппыДоступа. -// -Процедура ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(ИзмененныеУчастники, - ПриЗагрузке = Ложь, ПослеУстановкиПользователяИБ = Ложь) - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Описание = ?(ПослеУстановкиПользователяИБ, - "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступаПослеУстановкиПользователяИБ", - ?(ПриЗагрузке, - "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступаПриЗагрузке", - "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа")); - - ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "СоставыГруппПользователей"); - - Если ИзмененныеУчастники = Неопределено Тогда - ДляПользователей = Истина; - ДляВнешнихПользователей = Истина; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТаблицыГруппДоступа.Таблица КАК Таблица - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа"; - Иначе - ДляПользователей = Ложь; - ДляВнешнихПользователей = Ложь; - - Для Каждого Участник Из ИзмененныеУчастники Цикл - Если ТипЗнч(Участник) = Тип("СправочникСсылка.Пользователи") - Или ТипЗнч(Участник) = Тип("СправочникСсылка.ГруппыПользователей") Тогда - - ДляПользователей = Истина; - - ИначеЕсли ТипЗнч(Участник) = Тип("СправочникСсылка.ВнешниеПользователи") - Или ТипЗнч(Участник) = Тип("СправочникСсылка.ГруппыВнешнихПользователей") Тогда - - ДляВнешнихПользователей = Истина; - КонецЕсли; - КонецЦикла; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИзмененныеУчастники", ИзмененныеУчастники); - Если ПослеУстановкиПользователяИБ Тогда - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТаблицыГруппДоступа.Таблица КАК Таблица - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа - | ПО ТаблицыГруппДоступа.ГруппаДоступа = УчастникиГруппДоступа.Ссылка - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.Пользователь В (&ИзмененныеУчастники)) - | И (СоставыГруппПользователей.ГруппаПользователей = УчастникиГруппДоступа.Пользователь)"; - Иначе - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТаблицыГруппДоступа.Таблица КАК Таблица - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа - | ПО ТаблицыГруппДоступа.ГруппаДоступа = УчастникиГруппДоступа.Ссылка - | И (УчастникиГруппДоступа.Пользователь В (&ИзмененныеУчастники))"; - КонецЕсли; - КонецЕсли; - - Таблицы = Запрос.Выполнить().Выгрузить(); - - ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, - Описание, ДляПользователей, ДляВнешнихПользователей, Истина); - - ЗапланироватьОбновлениеНаборовГруппДоступа(Описание, ДляПользователей, ДляВнешнихПользователей); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Для вызова из модуля менеджера регистра ТаблицыГруппДоступа. -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа(Таблицы) Экспорт - - Описание = "ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа"; - - ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ТаблицыГруппДоступа"); - - ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, Описание, Истина, Истина); - -КонецПроцедуры - -// Для вызова из модуля объекта и модуля менеджера справочника ПрофилиГруппДоступа. -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРолейПрофиля(Описание, ИзмененныеРоли) Экспорт - - ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "РолиПрофилейГруппДоступа"); - - Если ИзмененныеРоли = Неопределено - Или ИзмененныеРоли.Количество() > 0 Тогда - - ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли); - КонецЕсли; - -КонецПроцедуры - -// Для вызова из модуля объекта и модуля менеджера справочника ГруппыДоступа. -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииПрофиляГруппыДоступа(Описание, ИзмененныеРоли, ПрофильИзменен) Экспорт - - Если ПрофильИзменен Тогда - ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ГруппыДоступаПрофилей"); - КонецЕсли; - - Если ИзмененныеРоли = Неопределено - Или ИзмененныеРоли.Количество() > 0 Тогда - - ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииРолейПрофиля и -// ЗапланироватьОбновлениеДоступаПриИзмененииПрофиляГруппыДоступа. -// -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли) - - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - Если Не ЗначениеЗаполнено(ДействующиеПараметры.ВедущиеРоли) Тогда - Возврат; - КонецЕсли; - - Если ИзмененныеРоли <> Неопределено Тогда - МетаданныеРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИзмененныеРоли, Ложь); - ИменаРолей = Новый Соответствие; - Для Каждого КлючИЗначение Из МетаданныеРолей Цикл - Если ТипЗнч(КлючИЗначение.Значение) = Тип("ОбъектМетаданных") Тогда - ИменаРолей.Вставить(КлючИЗначение.Значение.Имя, Истина); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - СпискиДляПользователей = Новый Массив; - СпискиДляВнешнихПользователей = Новый Массив; - ДобавленныеСпискиДляПользователей = Новый Соответствие; - ДобавленныеСпискиДляВнешнихПользователей = Новый Соответствие; - - Для Каждого ОписаниеВедущейРоли Из ДействующиеПараметры.ВедущиеРоли Цикл - Если ИзмененныеРоли <> Неопределено - И ИменаРолей.Получить(ОписаниеВедущейРоли.Ключ) = Неопределено Тогда - Продолжить; - КонецЕсли; - ДобавитьСпискиВедущейРолиДляОбновленияПрав(СпискиДляПользователей, - ОписаниеВедущейРоли.Значение.ДляПользователей, ДобавленныеСпискиДляПользователей); - ДобавитьСпискиВедущейРолиДляОбновленияПрав(СпискиДляВнешнихПользователей, - ОписаниеВедущейРоли.Значение.ДляВнешнихПользователей, ДобавленныеСпискиДляВнешнихПользователей); - КонецЦикла; - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.КлючиДоступаКДанным = Ложь; - ПараметрыПланирования.Описание = Описание; - - ПараметрыПланирования.ДляВнешнихПользователей = Ложь; - ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); - - ПараметрыПланирования.ДляПользователей = Ложь; - ПараметрыПланирования.ДляВнешнихПользователей = Истина; - ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); - -КонецПроцедуры - -// Для процедуры ЗапланироватьОбновлениеДоступаПриИзмененииРолей. -Процедура ДобавитьСпискиВедущейРолиДляОбновленияПрав(Списки, СпискиВедущейРоли, ДобавленныеСписки) - - Если Не ЗначениеЗаполнено(СпискиВедущейРоли) Тогда - Возврат; - КонецЕсли; - - Для Каждого ОписаниеСписка Из СпискиВедущейРоли Цикл - Если ДобавленныеСписки.Получить(ОписаниеСписка.Ключ) <> Неопределено Тогда - Продолжить; - КонецЕсли; - ДобавленныеСписки.Вставить(ОписаниеСписка.Ключ, Истина); - Списки.Добавить(ОписаниеСписка.Ключ); - КонецЦикла; - -КонецПроцедуры - -// Для вызова из модуля менеджера регистра ЗначенияГруппДоступа. -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений(ГруппыДоступаИТипыЗначений) Экспорт - - Описание = "ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений"; - - ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ЗначенияГруппДоступа"); - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ГруппыДоступаИТипыЗначений", ГруппыДоступаИТипыЗначений); - Запрос.Текст = - "ВЫБРАТЬ - | ГруппыДоступаИТипыЗначений.ГруппаДоступа КАК ГруппаДоступа, - | ГруппыДоступаИТипыЗначений.ТипЗначенийДоступа КАК ТипЗначенийДоступа - |ПОМЕСТИТЬ ГруппыДоступаИТипыЗначений - |ИЗ - | &ГруппыДоступаИТипыЗначений КАК ГруппыДоступаИТипыЗначений - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТаблицыГруппДоступа.Таблица КАК Таблица, - | ТИПЗНАЧЕНИЯ(ГруппыДоступаИТипыЗначений.ТипЗначенийДоступа) КАК ТипЗначенийДоступа - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступаИТипыЗначений КАК ГруппыДоступаИТипыЗначений - | ПО ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступаИТипыЗначений.ГруппаДоступа - |ИТОГИ ПО - | Таблица"; - - ТаблицыИТипыЗначенийДоступа = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - - ЗапланироватьОбновлениеПользователейКлючейДоступа(ТаблицыИТипыЗначенийДоступа.Строки, - Описание, Истина, Истина); - -КонецПроцедуры - -// Для процедуры ЗапланироватьОбновлениеДоступа, ЗапланироватьОбновлениеПараметровОграниченияДоступа. -Функция СлужебныйИдентификатор(ПолноеИмя) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ПолноеИмя", ПолноеИмя); - Запрос.Текст = - "ВЫБРАТЬ - | ИдентификаторыОбъектовМетаданных.Ссылка КАК Ссылка - |ИЗ - | Справочник.ИдентификаторыОбъектовМетаданных КАК ИдентификаторыОбъектовМетаданных - |ГДЕ - | ИдентификаторыОбъектовМетаданных.ПолноеИмя = &ПолноеИмя - | - |УПОРЯДОЧИТЬ ПО - | ИдентификаторыОбъектовМетаданных.ПометкаУдаления"; - - Выборка = Запрос.Выполнить().Выбрать(); - Если Выборка.Следующий() Тогда - Возврат Выборка.Ссылка; - КонецЕсли; - - Возврат Null; - -КонецФункции - -// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа, -// ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа, -// ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа, -// ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений. -// -Процедура ЗапланироватьОбновлениеПользователейКлючейДоступа(ОписаниеСписков, Описание, ДляПользователей, - ДляВнешнихПользователей, ПриИзмененииУчастниковГруппыДоступа = Ложь, ВедущийОбъект = Неопределено) - - Если ОписаниеСписков.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Контекст = Новый Структура; - Контекст.Вставить("ПриИзмененииУчастниковГруппыДоступа", ПриИзмененииУчастниковГруппыДоступа); - Контекст.Вставить("ИдентификаторТранзакции", Новый УникальныйИдентификатор); - Контекст.Вставить("Список", Неопределено); - Контекст.Вставить("ПолноеИмя", Неопределено); - Контекст.Вставить("ТипыЗначенийДоступа", Неопределено); - - Если ТипЗнч(ОписаниеСписков) = Тип("ФиксированныйМассив") Тогда - ИдентификаторыСписковПоПолнымИменам = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ОписаниеСписков); - Иначе - ПолныеИмена = ОписаниеСписков.ВыгрузитьКолонку("Таблица"); - ОбъектыМетаданныхСписков = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ПолныеИмена, Ложь); - КонецЕсли; - - Списки = Новый Массив; - СпискиДляПользователей = Новый Массив; - СпискиДляВнешнихПользователей = Новый Массив; - - Для Каждого ОписаниеСписка Из ОписаниеСписков Цикл - Если ИдентификаторыСписковПоПолнымИменам <> Неопределено Тогда - Контекст.ПолноеИмя = ОписаниеСписка; - Контекст.Список = ИдентификаторыСписковПоПолнымИменам.Получить(Контекст.ПолноеИмя); - Иначе - ОбъектМетаданных = ОбъектыМетаданныхСписков.Получить(ОписаниеСписка.Таблица); - Контекст.ПолноеИмя = ?(ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных"), ОбъектМетаданных.ПолноеИмя(), ""); - Контекст.Список = ОписаниеСписка.Таблица; - Если ТипЗнч(ОписаниеСписка) = Тип("СтрокаДереваЗначений") Тогда - Контекст.ТипыЗначенийДоступа = ОписаниеСписка.Строки; - КонецЕсли; - КонецЕсли; - Если Не ЗначениеЗаполнено(Контекст.ПолноеИмя) Тогда - Продолжить; - КонецЕсли; - ЗапланироватьДляПользователей = ДляПользователей - И ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, Ложь); - - ЗапланироватьДляВнешнихПользователей = ДляВнешнихПользователей - И ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, Истина); - - Если ЗапланироватьДляПользователей И ЗапланироватьДляВнешнихПользователей Тогда - Списки.Добавить(Контекст.ПолноеИмя); - - ИначеЕсли ЗапланироватьДляПользователей Тогда - СпискиДляПользователей.Добавить(Контекст.ПолноеИмя); - - ИначеЕсли ЗапланироватьДляВнешнихПользователей Тогда - СпискиДляВнешнихПользователей.Добавить(Контекст.ПолноеИмя); - КонецЕсли; - КонецЦикла; - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.КлючиДоступаКДанным = Ложь; - ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; - ПараметрыПланирования.Описание = Описание; - ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); - - ПараметрыПланирования.ДляВнешнихПользователей = Ложь; - ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); - - ПараметрыПланирования.ДляПользователей = Ложь; - ПараметрыПланирования.ДляВнешнихПользователей = Истина; - ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); - -КонецПроцедуры - -// Для процедуры ЗапланироватьОбновлениеПользователейКлючейДоступа. -Функция ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, ДляВнешнихПользователей) - - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Контекст.ИдентификаторТранзакции, Неопределено, Ложь); - Если ДляВнешнихПользователей Тогда - ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; - Иначе - ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; - КонецЕсли; - - Если Не Контекст.ПриИзмененииУчастниковГруппыДоступа - И ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(Контекст.ПолноеИмя) <> Неопределено - И ДополнительныйКонтекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(Контекст.ПолноеИмя) <> Неопределено Тогда - Возврат Истина; - КонецЕсли; - - СвойстваОграничения = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Контекст.ПолноеИмя); - - Если ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(Контекст.ПолноеИмя) <> Неопределено - Или СвойстваОграничения = Неопределено - Или СвойстваОграничения.ДоступЗапрещен - Или СвойстваОграничения.ПолеВладельца <> Неопределено - И Не СвойстваОграничения.ПолеВладельца.Отключено - Или Контекст.ПриИзмененииУчастниковГруппыДоступа - И Не СвойстваОграничения.РассчитыватьПраваПользователей Тогда - - Возврат Ложь; - КонецЕсли; - - Если СвойстваОграничения <> Неопределено - И Контекст.ТипыЗначенийДоступа <> Неопределено - И Не Контекст.ПриИзмененииУчастниковГруппыДоступа Тогда - - СредиИзмененныхТиповЗначенийДоступаНетИспользуемых = Истина; - ИспользуемыеТипыЗначенийДоступа = СвойстваОграничения.ИспользуемыеТипыЗначенийДоступа.Получить(); // Массив из Тип - Для Каждого Строка Из Контекст.ТипыЗначенийДоступа Цикл - Если ИспользуемыеТипыЗначенийДоступа.Найти(Строка.ТипЗначенийДоступа) <> Неопределено Тогда - СредиИзмененныхТиповЗначенийДоступаНетИспользуемых = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Если СредиИзмененныхТиповЗначенийДоступаНетИспользуемых Тогда - Возврат Ложь; - КонецЕсли; - КонецЕсли; - - Возврат Истина; - -КонецФункции - -// Для процедуры ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа и -// модулей менеджера и объекта справочника ГруппыДоступа. -// -Процедура ЗапланироватьОбновлениеНаборовГруппДоступа(Описание, ДляПользователей = Истина, ДляВнешнихПользователей = Истина) Экспорт - - Если Не ДляПользователей И Не ДляВнешнихПользователей Тогда - Возврат; - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); - - Список = "Справочник.НаборыГруппДоступа"; - КлючУникальности = Новый УникальныйИдентификатор; - ИдентификаторСписка = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Список); - ТекущаяДата = ТекущаяДатаСеанса(); - МаксимальнаяДата = МаксимальнаяДата(); - - // Обновление только по изменениям (не полное). - ПараметрыЗадания = Новый Структура; - УстановитьВидКлючаДанных(ПараметрыЗадания, "НовыеНаборыИзОдногоПользователя"); - ХранилищеПараметровЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); - - Если ДляПользователей Тогда - НоваяЗапись = НаборЗаписей.Добавить(); - НоваяЗапись.КлючУникальности = КлючУникальности; - НоваяЗапись.Список = ИдентификаторСписка; - НоваяЗапись.ДляВнешнихПользователей = Ложь; - НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата; - НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; - НоваяЗапись.РазмерЗадания = 3; - НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДата; - КонецЕсли; - - Если ДляВнешнихПользователей Тогда - НоваяЗапись = НаборЗаписей.Добавить(); - НоваяЗапись.КлючУникальности = КлючУникальности; - НоваяЗапись.Список = ИдентификаторСписка; - НоваяЗапись.ДляВнешнихПользователей = Истина; - НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата; - НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; - НоваяЗапись.РазмерЗадания = 3; - НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДата; - КонецЕсли; - - НаборЗаписей.Записать(Ложь); - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; - ПараметрыПланирования.ДляПользователей = ДляПользователей; - ПараметрыПланирования.ДляВнешнихПользователей = ДляВнешнихПользователей; - ПараметрыПланирования.Описание = Описание; - - СпискиПоИдентификаторам = Новый Соответствие; - СпискиПоИдентификаторам.Вставить(ИдентификаторСписка, Список); - - ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования); - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - -КонецПроцедуры - -// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа, -// ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа, -// ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа, -// ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений. -// -Процедура ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, ИмяИзмененныхДанных) - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.КлючиДоступаКДанным = Ложь; - ПараметрыПланирования.ДляВнешнихПользователей = Ложь; - ПараметрыПланирования.Описание = Описание; - ПараметрыПланирования.ВедущийОбъект = Новый Структура("ПоДаннымКэшаРасчетаПрав", ИмяИзмененныхДанных); - ЗапланироватьОбновлениеДоступа(СписокДляПланированияОбновленияКэшаРасчетаПрав(), ПараметрыПланирования); - -КонецПроцедуры - -// Для процедур ПодготовитьПланОбновления, ЗапланироватьОбновлениеКэшаРасчетаПрав -// и функции ВерсияДанныхДляКэшаРасчетаПрав. -// -Функция СписокДляПланированияОбновленияКэшаРасчетаПрав() - - Возврат "РегистрСведений.ПараметрыРаботыВерсийРасширений"; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ТаблицыГруппДоступа - Строка -// - Неопределено -// * ЗначенияГруппДоступа - Строка -// - Неопределено -// * УчастникиГруппДоступа - Строка -// - Неопределено -// * СоставыГруппПользователей - Строка -// - Неопределено -// * РолиПрофилейГруппДоступа - Строка -// - Неопределено -// * ГруппыДоступаПрофилей - Строка -// - Неопределено -// -Функция НоваяВерсияДанныхДляКэшаРасчетаПрав(Версия = Неопределено) Экспорт - - НоваяВерсияДанных = Новый Структура; - НоваяВерсияДанных.Вставить("ТаблицыГруппДоступа", Версия); - НоваяВерсияДанных.Вставить("ЗначенияГруппДоступа", Версия); - НоваяВерсияДанных.Вставить("УчастникиГруппДоступа", Версия); - НоваяВерсияДанных.Вставить("СоставыГруппПользователей", Версия); - НоваяВерсияДанных.Вставить("РолиПрофилейГруппДоступа", Версия); - НоваяВерсияДанных.Вставить("ГруппыДоступаПрофилей", Версия); - - Возврат НоваяВерсияДанных; - -КонецФункции - -// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. -Функция ИмяПараметраВерсииДанныхДляКэшаРасчетаПрав() - - Возврат "СтандартныеПодсистемы.УправлениеДоступом.ВерсияДанныхДляКэшаРасчетаПрав"; - -КонецФункции - -#КонецОбласти - -#Область ОбновлениеДоступа - -// Для процедуры ЗапуститьОбновлениеДоступа. -Функция ЕстьЗапланированныеТочечныеЗадания() - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("СписокДляПланированияОбновленияКэшаРасчетаПрав", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных(СписокДляПланированияОбновленияКэшаРасчетаПрав(), Ложь)); - - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным - |ГДЕ - | ОбновлениеКлючейДоступаКДанным.ТочечноеЗадание - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей - |ГДЕ - | ОбновлениеКлючейДоступаПользователей.ТочечноеЗадание - | И ОбновлениеКлючейДоступаПользователей.Список <> &СписокДляПланированияОбновленияКэшаРасчетаПрав"; - - Возврат Не Запрос.Выполнить().Пустой(); - -КонецФункции - -// Запускает фоновое задание обновления доступа вместо регламентного задания. -// -// Параметры: -// ЭтоЗапускВручную - Булево - если передать Ложь, то наименование будет начинаться с "Автозапуск", -// в противном случае, наименование будет начинаться с "Запуск вручную", -// блокировка обновления доступа будет снята, если была установлена, -// выполнение будет продолжаться до полного завершения. -// ЭтоПерезапуск - Булево - если передать Истина, тогда текущий сеанс фонового задания не будет -// считаться незавершенным исполнителем. -// ДляУскорения - Булево - если передать Истина, тогда признак передается в процедуру обновления доступа, -// чтобы прекратить обновление, когда точечных заданий нет и функция -// ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий возвращает Истина. -// -// Возвращаемое значение: -// - Неопределено - обновление доступа не требуется или запрещено. -// - Структура: -// * УжеВыполняется - Булево - если обновление уже выполняется. -// -// * ИдентификаторФоновогоЗадания - Неопределено - если обновление не выполняется или -// выполняется не в фоновом задании. -// - УникальныйИдентификатор - идентификатор фонового задания. -// -// * СвойстваСеанса - Неопределено - если запуска не было или фоновое задание только добавлено в очередь. -// - Структура - со свойствами сеанса, если обновление уже выполняется: -// ** ИмяКомпьютера - Строка - одноименное свойства объекта СеансИнформационнойБазы. -// ** НомерСеанса - Число - одноименное свойства объекта СеансИнформационнойБазы. -// ** НачалоСеанса - Строка - одноименное свойства объекта СеансИнформационнойБазы. -// -// * ТекстПредупреждения - Неопределено - если запуска не было или запущено новое фоновое задание. -// - Строка - описание, что обновление доступа уже запущено. -// -Функция ЗапуститьОбновлениеДоступаНаУровнеЗаписей(ЭтоЗапускВручную = Ложь, ЭтоПерезапуск = Ложь, ДляУскорения = Ложь) Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина) Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Невозможно запустить обновление доступа на уровне записей, так как - |константа %1 выключена.'"), - "ОграничиватьДоступНаУровнеЗаписейУниверсально"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если ТранзакцияАктивна() Тогда - ТекстОшибки = - НСтр("ru = 'Невозможно запустить обновление доступа на уровне записей в открытой транзакции.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если Не ЭтоЗапускВручную И Не ЗапланированоОбновлениеДоступа() Тогда - Возврат Неопределено; - КонецЕсли; - - ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(); - Если Не ЭтоЗапускВручную И ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда - Возврат Неопределено; - КонецЕсли; - - ИдентификаторИсключаемогоЗадания = Неопределено; - Если ЭтоПерезапуск Тогда - ТекущееФоновоеЗадание = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание(); - Если ТекущееФоновоеЗадание <> Неопределено Тогда - ИдентификаторИсключаемогоЗадания = ТекущееФоновоеЗадание.УникальныйИдентификатор; - КонецЕсли; - КонецЕсли; - Результат = Новый Структура("УжеВыполняется, ТекстПредупреждения, ИдентификаторФоновогоЗадания, СвойстваСеанса", Истина, ""); - Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторИсключаемогоЗадания); - - Если Исполнитель = Неопределено Тогда - Результат.УжеВыполняется = Ложь; - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - Попытка - // В файловой ИБ перезапуск фонового задания с расширениями базы данных - // выполняется с той же версией динамического поколения конфигурации. - СтандартныеПодсистемыСервер.ПроверитьДинамическоеОбновлениеВерсииПрограммы(); - Исключение - Результат.ТекстПредупреждения = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); - Возврат Результат; - КонецПопытки; - КонецЕсли; - Если ЭтоЗапускВручную Тогда - УстановитьЗапретОбновленияДоступа(Ложь); - ПараметрыЗадания = Новый Массив; - ПараметрыЗадания.Добавить(Истина); - ИначеЕсли ЭтоПерезапуск Или ДляУскорения Тогда - ДополнительныеПараметры = НовыеДополнительныеПараметрыОбновленияДоступа(); - ДополнительныеПараметры.ЭтоПерезапуск = ЭтоПерезапуск; - ДополнительныеПараметры.ДляУскорения = ДляУскорения; - ПараметрыЗадания = Новый Массив; - ПараметрыЗадания.Добавить(Ложь); - ПараметрыЗадания.Добавить(Ложь); - ПараметрыЗадания.Добавить(ДополнительныеПараметры); - Иначе - ПараметрыЗадания = Неопределено; - КонецЕсли; - - ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); - НаименованиеЗадания = - ?(ЭтоЗапускВручную, - НСтр("ru = 'Запуск вручную'", ОбщегоНазначения.КодОсновногоЯзыка()), - НСтр("ru = 'Автозапуск'", ОбщегоНазначения.КодОсновногоЯзыка())) - + ": " + Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.Синоним + " (" - + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'из сеанса %1 от %2'", ОбщегоНазначения.КодОсновногоЯзыка()), - Формат(ТекущийСеанс.НомерСеанса, "ЧГ="), - Формат(ТекущийСеанс.НачалоСеанса, "ДЛФ=DT")) + ")"; - - ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных( - ИмяМетодаЗаданияОбновленияДоступа(), ПараметрыЗадания,, НаименованиеЗадания); - - Результат.ИдентификаторФоновогоЗадания = ФоновоеЗадание.УникальныйИдентификатор; - - ИначеЕсли ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") - И Исполнитель.УникальныйИдентификатор <> ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания Тогда - - Результат.ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже запущено %1 в %2'"), - Формат(Исполнитель.Начало, "ДЛФ=D"), - Формат(Исполнитель.Начало, "ДЛФ=T")); - Иначе - СвойстваСеанса = Новый Структура("ИмяКомпьютера, НомерСеанса, НачалоСеанса"); - Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") Тогда - ЗаполнитьЗначенияСвойств(СвойстваСеанса, ПоследнееОбновлениеДоступа); - Иначе - ЗаполнитьЗначенияСвойств(СвойстваСеанса, Исполнитель); - КонецЕсли; - Результат.СвойстваСеанса = СвойстваСеанса; - Результат.ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Обновление доступа уже выполняется - |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), - СвойстваСеанса.ИмяКомпьютера, - СвойстваСеанса.НомерСеанса, - Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=D"), - Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=T")); - КонецЕсли; - - Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") Тогда - Результат.ИдентификаторФоновогоЗадания = Исполнитель.УникальныйИдентификатор; - КонецЕсли; - - Возврат Результат; - -КонецФункции - -// Отменить обновление доступа, которое выполняется в фоновом задании. -Процедура ОтменитьОбновлениеДоступаНаУровнеЗаписей() Экспорт - - Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа()); - - Если ТипЗнч(Исполнитель) = Тип("СеансИнформационнойБазы") Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Невозможно отменить полное обновление доступа - |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), - Исполнитель.ИмяКомпьютера, - Исполнитель.НомерСеанса, - Формат(Исполнитель.НачалоСеанса, "ДЛФ=D"), - Формат(Исполнитель.НачалоСеанса, "ДЛФ=T")); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Выполняется = ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание"); - - ЗавершитьПотокиОбновленияДоступа(Истина); - УстановитьЗапретОбновленияДоступа(Истина, Выполняется); - - Если Выполняется Тогда - Исполнитель = Исполнитель.ОжидатьЗавершенияВыполнения(СекундОжиданияЗавершенияФоновогоЗадания()); - Если Исполнитель.Состояние = СостояниеФоновогоЗадания.Активно Тогда - Исполнитель.Отменить(); - КонецЕсли; - КонецЕсли; - - Отбор = Новый Структура; - Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно); - Отбор.Вставить("ИмяМетода", ИмяМетодаЗаданияОбновленияДоступа()); - ОсновныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); - - Для Каждого ОсновноеЗадание Из ОсновныеЗадания Цикл - ОсновноеЗадание = ОсновноеЗадание.ОжидатьЗавершенияВыполнения(1); - Если ОсновноеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда - ОсновноеЗадание.Отменить(); - КонецЕсли; - КонецЦикла; - - ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(); - -КонецПроцедуры - -// Для процедуры УстановитьОбновлениеДоступа. -Процедура ВключитьРегламентноеЗаданиеОбновленияДоступа() Экспорт - - ИзменитьРегламентноеЗаданиеОбновленияДоступа(Истина); - -КонецПроцедуры - -// Для процедуры УстановитьОбновлениеДоступа. -Процедура ОтключитьРегламентноеЗаданиеОбновленияДоступа() Экспорт - - ИзменитьРегламентноеЗаданиеОбновленияДоступа(Ложь); - -КонецПроцедуры - -// Для процедуры УстановитьОбновлениеДоступа. -Процедура ИзменитьРегламентноеЗаданиеОбновленияДоступа(ВключитьЗадание) - - Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); - - ТребуетсяИзменить = Ложь; - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ТребуетсяИзменить = Истина; - Иначе - УстановитьПривилегированныйРежим(Истина); - Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); - Для Каждого Задание Из Задания Цикл - Если ВключитьЗадание <> Задание.Использование Тогда - ТребуетсяИзменить = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - УстановитьПривилегированныйРежим(Ложь); - КонецЕсли; - - Если Не ТребуетсяИзменить Тогда - Возврат; - КонецЕсли; - - ЭтоОшибкаБлокировки = Ложь; - НомерПопыткиБлокировки = 0; - Пока Истина Цикл - НомерПопыткиБлокировки = НомерПопыткиБлокировки + 1; - НачатьТранзакцию(); - Попытка - ЭтоОшибкаБлокировки = Истина; - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - РегламентныеЗаданияСервер.ЗаблокироватьРегламентноеЗадание(Новый УникальныйИдентификатор); - КонецЕсли; - ЭтоОшибкаБлокировки = Ложь; - УстановитьПривилегированныйРежим(Истина); - Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); - Для Каждого Задание Из Задания Цикл - Если ВключитьЗадание = Задание.Использование Тогда - Продолжить; - КонецЕсли; - РегламентныеЗаданияСервер.ИзменитьЗадание(Задание, - Новый Структура("Использование", ВключитьЗадание)); - КонецЦикла; - УстановитьПривилегированныйРежим(Ложь); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - Если ЭтоОшибкаБлокировки - И НомерПопыткиБлокировки <= 3 - И Не ТранзакцияАктивна() Тогда - Продолжить; - КонецЕсли; - ВызватьИсключение; - КонецПопытки; - Прервать; - КонецЦикла; - -КонецПроцедуры - -// Включает или отключает запрет обновления доступа при запуске -// с помощью регламентного задания или при программном запуске. -// -// При вызове процедуры ОбновлениеДоступаНаУровнеЗаписей -// с признаком ОбновитьВсе запрет игнорируется. -// -// При вызове процедуры ЗапуститьОбновлениеДоступаНаУровнеЗаписей -// с признаком ЭтоЗапускВручную запрет снимается автоматически. -// -Процедура УстановитьЗапретОбновленияДоступа(Использование, ОтменитьОбновление = Ложь) Экспорт - - БлокировкаДанных = Новый БлокировкаДанных; - БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); - - ЕстьВнешняяТранзакция = ТранзакцияАктивна(); - НачатьТранзакцию(); - Попытка - БлокировкаДанных.Заблокировать(); - ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); - ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); - - Записать = Ложь; - Если ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено <> Использование Тогда - ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено = Использование; - Записать = Истина; - КонецЕсли; - - Если ОтменитьОбновление - И ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере > ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - И ( Не ПоследнееОбновлениеДоступа.ОбновлениеОтменено - Или ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения <> "") Тогда - - ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Истина; - ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ""; - ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = '00010101'; - ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере = ТекущаяДатаНаСервере(); - ПоследнееОбновлениеДоступа.ПоследнееВыполнениеСекунд = - ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере - + СекундОжиданияЗавершенияФоновогоЗадания() + 1; - Записать = Истина; - КонецЕсли; - - Если Записать Тогда - УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедур ОтменитьОбновлениеДоступаНаУровнеЗаписей, УстановитьЗапретОбновленияДоступа. -Функция СекундОжиданияЗавершенияФоновогоЗадания() - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - Возврат 3; - Иначе - Возврат 15; - КонецЕсли; - -КонецФункции - -// Обработчик регламентного задания ОбновлениеДоступаНаУровнеЗаписей. -Процедура ОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе = Ложь, ВызыватьИсключениеВместоРегистрацииОшибки = Ложь, - ДополнительныеПараметры = Неопределено) Экспорт - - // Регламентное задание должно запускаться сразу, как только было запланировано обновление доступа. - // После обработки первой порции по всем таблицам (2 мин на все) можно сделать - // небольшую паузу вместо непрерывного выполнения до конца. - // В данном случае пауза - это перезапуск через 15 секунд. - // В отличие от обычных регламентных заданий это задание самоотключаемое, - // то есть после отработки запланированного обновления, задание выключает само себя и - // запуски полностью прекращаются до того, как будет запланировано новое обновление доступа. - - ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания( - Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); - - ВыполнитьОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе, ВызыватьИсключениеВместоРегистрацииОшибки, - 0, , ДополнительныеПараметры); - -КонецПроцедуры - -// Только для внутреннего использования. -// -// Возвращаемое значение: -// Структура: -// * ДляУскорения - Булево -// * ЭтоПерезапуск - Булево -// -Функция НовыеДополнительныеПараметрыОбновленияДоступа() - - Результат = Новый Структура; - Результат.Вставить("ДляУскорения", Ложь); - Результат.Вставить("ЭтоПерезапуск", Ложь); - - Возврат Результат; - -КонецФункции - -// Выполняет обновление доступа, если запланировано. -Процедура ВыполнитьОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе, ВызыватьИсключениеВместоРегистрацииОшибки, - СекундНеБолее, ПослеОбновлениеИБ = Ложь, ДополнительныеПараметры = Неопределено) - - Если ОбновитьВсе Тогда - СекундНеБолее = 0; - КонецЕсли; - - НовыеДополнительныеПараметры = НовыеДополнительныеПараметрыОбновленияДоступа(); - Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда - ЗаполнитьЗначенияСвойств(НовыеДополнительныеПараметры, ДополнительныеПараметры); - КонецЕсли; - ДополнительныеПараметры = НовыеДополнительныеПараметры; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - УстановитьЭтоСеансФоновогоОбновленияДоступа(); - - ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); - ОписаниеОсновногоСеанса = ОписаниеОсновногоСеанса(); - ОписаниеОсновногоСеанса.Вставить("НомерСеанса", ТекущийСеанс.НомерСеанса); - ОписаниеОсновногоСеанса.Вставить("НачалоСеанса", ТекущийСеанс.НачалоСеанса); - - Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда - Если ОбновитьВсе Тогда - ИдентификаторФоновогоЗадания = ИдентификаторПроизвольногоСеанса(); - Иначе - ТекстОшибки = НСтр("ru = 'Обновление доступа может выполняться порциями только в фоновом задании.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ИдентификаторОсновногоСеанса = Строка(Новый УникальныйИдентификатор); - Иначе - ТекущееФоновоеЗадание = ТекущийСеанс.ПолучитьФоновоеЗадание(); - Если ТекущееФоновоеЗадание = Неопределено Тогда - ТекстОшибки = НСтр("ru = 'Не удалось получить фоновое задание текущего сеанса.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ИдентификаторФоновогоЗадания = ТекущееФоновоеЗадание.УникальныйИдентификатор; - ОписаниеОсновногоСеанса.ФоновоеЗадание = ТекущееФоновоеЗадание; - ОписаниеОсновногоСеанса.ИдентификаторФоновогоЗадания = ИдентификаторФоновогоЗадания; - ИдентификаторОсновногоСеанса = Строка(ИдентификаторФоновогоЗадания); - КонецЕсли; - ОписаниеОсновногоСеанса.Вставить("Идентификатор", ИдентификаторОсновногоСеанса - + " (" + НСтр("ru = 'Идентификатор основного сеанса'") + ")"); - - БлокировкаДанных = Новый БлокировкаДанных; - БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); - - ЕстьВнешняяТранзакция = ТранзакцияАктивна(); - НачатьТранзакцию(); - Попытка - БлокировкаДанных.Заблокировать(); - ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); - ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); - - Если ОбновитьВсе Или Не ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда - Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторФоновогоЗадания); - - Если Исполнитель = Неопределено Тогда - ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Ложь; - ПоследнееОбновлениеДоступа.ДляУскорения = ДополнительныеПараметры.ДляУскорения; - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере = ТекущаяДатаНаСервере(); - ПоследнееОбновлениеДоступа.НомерСеанса = ТекущийСеанс.НомерСеанса; - ПоследнееОбновлениеДоступа.НачалоСеанса = ТекущийСеанс.НачалоСеанса; - ПоследнееОбновлениеДоступа.ИмяКомпьютера = ТекущийСеанс.ИмяКомпьютера; - ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = ИдентификаторФоновогоЗадания; - - УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); - КонецЕсли; - КонецЕсли; - - Если ПоследнееОбновлениеДоступа.ДляУскорения И Не ДополнительныеПараметры.ДляУскорения Тогда - ПоследнееОбновлениеДоступа.ДляУскорения = Ложь; - УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если Не ОбновитьВсе И ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда - Если ТекущееФоновоеЗадание.РегламентноеЗадание <> Неопределено Тогда - УстановитьОбновлениеДоступа(Ложь); - КонецЕсли; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Обновление доступа запрещено. - |Чтобы разрешить нужно нажать ""Разрешить"" в форме ""Обновление доступа на уровне записей"". - |Форму можно открыть из панели ""Настройки пользователей и прав"" или перейти по навигационной ссылке: - |%1'"), - "e1cib/app/РегистрСведений.ОбновлениеКлючейДоступаКДанным.Форма.ОбновлениеДоступаНаУровнеЗаписей"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если Исполнитель <> Неопределено Тогда - Если Не ОбновитьВсе Или ПослеОбновлениеИБ Тогда - Возврат; - КонецЕсли; - - Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") - И Исполнитель.УникальныйИдентификатор <> ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания Тогда - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже запущено %1 в %2'"), - Формат(Исполнитель.Начало, "ДЛФ=D"), - Формат(Исполнитель.Начало, "ДЛФ=T")); - Иначе - СвойстваСеанса = ?(ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание"), - ПоследнееОбновлениеДоступа, Исполнитель); - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже выполняется - |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), - СвойстваСеанса.ИмяКомпьютера, - СвойстваСеанса.НомерСеанса, - Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=D"), - Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=T")); - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Ложь; - ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ""; - ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор(); - - ПерезапускВозможен = ТекущееФоновоеЗадание <> Неопределено - И Не ОбновитьВсе - И Не ВызыватьИсключениеВместоРегистрацииОшибки - И СекундНеБолее = 0 - И Не ПослеОбновлениеИБ; - - ТекстВсехОшибок = ""; - ДатаПолногоЗавершения = ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения; - - ПараметрыВыполнения = Новый Структура; - ПараметрыВыполнения.Вставить("СекундНеБолее", СекундНеБолее); - ПараметрыВыполнения.Вставить("ТекстОшибкиПланирования", ""); - ПараметрыВыполнения.Вставить("ТекстОшибкиЗавершения", ""); - ПараметрыВыполнения.Вставить("ОписаниеОсновногоСеанса", ОписаниеОсновногоСеанса); - Попытка - Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда - ВыполнитьОбновлениеДоступа(ОбновитьВсе, ПараметрыВыполнения, ПоследнееОбновлениеДоступа); - Если Не ПерезапускВозможен Тогда - СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(ТекстВсехОшибок); - КонецЕсли; - Иначе - УстановитьОбновлениеДоступа(Ложь); - КонецЕсли; - Исключение - Если ТранзакцияАктивна() Тогда - ВызватьИсключение; - КонецЕсли; - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстВсехОшибок = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - Если ПерезапускВозможен - И СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда - ТекстВсехОшибок = ""; - КонецЕсли; - КонецПопытки; - - Попытка - ЗавершитьПотокиОбновленияДоступа(); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось завершить потоки обновления доступа по причине: - |%1'"), - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке))); - КонецПопытки; - - Попытка - ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(2); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось отменить фоновые задания потоков обновления доступа по причине: - |%1'"), - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке))); - КонецПопытки; - - ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, ПараметрыВыполнения.ТекстОшибкиПланирования); - ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, ПараметрыВыполнения.ТекстОшибкиЗавершения); - - ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере = ТекущаяДатаНаСервере(); - Если ЗначениеЗаполнено(ТекстВсехОшибок) Тогда - ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = '00010101'; - КонецЕсли; - Если Не ЗначениеЗаполнено(ДатаПолногоЗавершения) - Или ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения <> ДатаПолногоЗавершения Тогда - - ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ТекстВсехОшибок; - ПоследнееОбновлениеДоступа.ПоследнееВыполнениеСекунд = - ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере; - КонецЕсли; - - НачатьТранзакцию(); - Попытка - БлокировкаДанных.Заблокировать(); - ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); - ТекущееПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); - - ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено = - ТекущееПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено; - - УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ПерезапускВозможен И СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда - ЗапуститьОбновлениеДоступаНаУровнеЗаписей(, Истина, ПоследнееОбновлениеДоступа.ДляУскорения); - КонецЕсли; - - Если Не ЗначениеЗаполнено(ТекстВсехОшибок) Тогда - Возврат; - КонецЕсли; - - ТекстВсехОшибок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось выполнить обновление доступа по причине: - |%1'"), ТекстВсехОшибок); - - Если ВызыватьИсключениеВместоРегистрацииОшибки Тогда - ВызватьИсключение ТекстВсехОшибок; - Иначе - ЗарегистрироватьОшибкуОбновленияДоступа(ТекстВсехОшибок, - Новый Структура("ОписаниеОсновногоСеанса", ОписаниеОсновногоСеанса)); - КонецЕсли; - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ИдентификаторФоновогоЗадания - УникальныйИдентификатор -// * ФоновоеЗадание - ФоновоеЗадание -// * НомерСеанса - Число -// * НачалоСеанса - Дата -// * Идентификатор - Строка - представление сеанса -// -Функция ОписаниеОсновногоСеанса() - - Возврат Новый Структура("ИдентификаторФоновогоЗадания, ФоновоеЗадание"); - -КонецФункции - -// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей. -Функция ЗапланированоОбновлениеДоступа() - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей"; - - Возврат Не Запрос.Выполнить().Пустой(); - -КонецФункции - -// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей и -// процедур ОбновлениеДоступаНаУровнеЗаписей, ОтменитьОбновлениеДоступаНаУровнеЗаписей и -// формы ОбновлениеДоступаНаУровнеЗаписей. -// -// Возвращаемое значение: -// Структура: -// * ДатаЗапускаНаСервере - Дата -// * ДатаЗавершенияНаСервере - Дата -// * ОбновлениеОтменено - Булево -// * ПоследнееВыполнениеСекунд - Число -// * ДатаПолногоЗавершения - Дата -// * ТекстОшибкиЗавершения - Строка -// * НомерСеанса - Число -// * ИмяКомпьютера - Строка -// * ОбновлениеДоступаЗапрещено - Булево -// * БалансировкаНагрузкиНаДиск - Булево -// * ИдентификаторФоновогоЗадания - УникальныйИдентификатор -// * ПоследнееПланированиеОбработкиУстаревшихЭлементов - Дата -// -Функция ПоследнееОбновлениеДоступа(ТекущееЗначение = Неопределено) Экспорт - - Если ТекущееЗначение = Неопределено Тогда - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | ПоследнееОбновлениеДоступа.Значение КАК Значение - |ИЗ - | Константа.ПоследнееОбновлениеДоступа КАК ПоследнееОбновлениеДоступа"; - - Выборка = Запрос.Выполнить().Выбрать(); - ТекущееЗначение = ?(Выборка.Следующий(), Выборка.Значение, Неопределено); - КонецЕсли; - - Свойства = Новый Структура; - Свойства.Вставить("ДатаЗапускаНаСервере", '00010101'); - Свойства.Вставить("ДатаЗавершенияНаСервере", '00010101'); - Свойства.Вставить("ОбновлениеОтменено", Ложь); - Свойства.Вставить("ПоследнееВыполнениеСекунд", 0); - Свойства.Вставить("ДатаПолногоЗавершения", '00010101'); - Свойства.Вставить("ТекстОшибкиЗавершения", ""); - Свойства.Вставить("НомерСеанса", 0); - Свойства.Вставить("НачалоСеанса", '00010101'); - Свойства.Вставить("ИмяКомпьютера", ""); - Свойства.Вставить("ОбновлениеДоступаЗапрещено", Ложь); - Свойства.Вставить("БалансировкаНагрузкиНаДиск", Истина); - Свойства.Вставить("ИдентификаторДоступа"); - Свойства.Вставить("ИдентификаторФоновогоЗадания", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - Свойства.Вставить("ПоследнееПланированиеОбработкиУстаревшихЭлементов", '00010101'); - Свойства.Вставить("ДляУскорения", Ложь); - - Если ТипЗнч(ТекущееЗначение) <> Тип("ХранилищеЗначения") Тогда - Возврат Свойства; - КонецЕсли; - - ТекущиеСвойства = ТекущееЗначение.Получить(); - - Если ТипЗнч(ТекущиеСвойства) <> Тип("Структура") Тогда - Возврат Свойства; - КонецЕсли; - - ЗаполнитьЗначенияСвойств(Свойства, ТекущиеСвойства); - - Возврат Свойства; - -КонецФункции - -// Для процедур ВыполнитьОбновлениеДоступаНаУровнеЗаписей, -// УстановитьЗапретОбновленияДоступа и УстановитьБалансировкуНагрузкиНаДиск. -// -Процедура УстановитьПоследнееОбновлениеДоступа(Свойства, ЕстьВнешняяТранзакция) - - Если Не ЗначениеЗаполнено(Свойства.ИдентификаторДоступа) И Не ЕстьВнешняяТранзакция Тогда - Свойства.ИдентификаторДоступа = Новый УникальныйИдентификатор; - КонецЕсли; - - МенеджерЗначения = СлужебныйМенеджерЗначения(Константы.ПоследнееОбновлениеДоступа); - МенеджерЗначения.Значение = Новый ХранилищеЗначения(Свойства); - МенеджерЗначения.Записать(); - -КонецПроцедуры - -// Для константы ОграничиватьДоступНаУровнеЗаписейУниверсально. -Процедура ОчиститьПоследнееОбновлениеДоступа() Экспорт - - Свойства = ПоследнееОбновлениеДоступа(Null); - ЗаполнитьЗначенияСвойств(Свойства, ПоследнееОбновлениеДоступа(), - "ИдентификаторДоступа, ОбновлениеДоступаЗапрещено, БалансировкаНагрузкиНаДиск"); - - МенеджерЗначения = СлужебныйМенеджерЗначения(Константы.ПоследнееОбновлениеДоступа); - МенеджерЗначения.Значение = Новый ХранилищеЗначения(Свойства); - МенеджерЗначения.Записать(); - -КонецПроцедуры - -// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей и -// процедур ОбновлениеДоступаНаУровнеЗаписей, ОтменитьОбновлениеДоступаНаУровнеЗаписей и -// формы ОбновлениеДоступаНаУровнеЗаписей. -// -// Параметры: -// ПоследнееОбновлениеДоступа - см. ПоследнееОбновлениеДоступа -// ИдентификаторИсключаемогоЗадания - УникальныйИдентификатор -// - Неопределено -// -// Возвращаемое значение: -// - ФоновоеЗадание -// - СеансИнформационнойБазы -// - Неопределено -// -Функция ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторИсключаемогоЗадания = Неопределено) Экспорт - - Если ЗначениеЗаполнено(ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания) Тогда - Если ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = ИдентификаторПроизвольногоСеанса() Тогда - Сеансы = ПолучитьСеансыИнформационнойБазы(); - Для Каждого Сеанс Из Сеансы Цикл - Если Сеанс.НомерСеанса = ПоследнееОбновлениеДоступа.НомерСеанса - И Сеанс.НачалоСеанса = ПоследнееОбновлениеДоступа.НачалоСеанса Тогда - Возврат Сеанс; - КонецЕсли; - КонецЦикла; - Иначе - ИсполняющееФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору( - ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания); - - Если ИсполняющееФоновоеЗадание <> Неопределено - И ИсполняющееФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда - - Возврат ИсполняющееФоновоеЗадание; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Отбор = Новый Структура("Состояние, ИмяМетода", СостояниеФоновогоЗадания.Активно, - ИмяМетодаЗаданияОбновленияДоступа()); - - НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); - Для Каждого НайденноеЗадание Из НайденныеЗадания Цикл - Если НайденноеЗадание.УникальныйИдентификатор <> ИдентификаторИсключаемогоЗадания Тогда - Возврат НайденноеЗадание; - КонецЕсли; - КонецЦикла; - - Возврат Неопределено; - -КонецФункции - -// Для процедуры ОбновлениеДоступаНаУровнеЗаписей, ИсполнительОбновленияДоступа. -Функция ИдентификаторПроизвольногоСеанса() - - Возврат Новый УникальныйИдентификатор("ba4730f7-0493-402d-b5d3-8052c80fb125"); - -КонецФункции - -// Для процедур ВыполнитьОбновлениеДоступа, ДобавитьЗаданияОбновленияДоступа и -// ОбновитьСоставИспользуемыхВерсийПараметровШаблонов. -// -// Параметры: -// Контекст - см. НовыйКонтекстОбновленияДоступа -// ПриЗапуске - Булево -// -Процедура ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст, ПриЗапуске = Ложь) - - Показатели = Контекст.Показатели; - Если Показатели <> Неопределено Тогда - НачалоПроверки = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(, Истина); - - ДатаОбновленияВерсииРасширений = Справочники.ВерсииРасширений.ПоследняяВерсияРасширений().ДатаОбновления; - - ДатаОбновленияВсехПараметровРаботыПрограммы = - РегистрыСведений.ПараметрыРаботыПрограммы.ДатаОбновленияВсехПараметровРаботыПрограммы(); - - ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений = - РегистрыСведений.ПараметрыРаботыВерсийРасширений.ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений(); - - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - ДатаСозданияПараметровОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа.ДатаСоздания; - - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; - ДатаПроверкиПараметровОграниченияДоступа = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - Если ТипЗнч(ДатаПроверкиПараметровОграниченияДоступа) <> Тип("Дата") Тогда - ДатаПроверкиПараметровОграниченияДоступа = '00010101'; - КонецЕсли; - - Если ДатаПроверкиПараметровОграниченияДоступа > ДатаСозданияПараметровОграниченияДоступа Тогда - ДатаАктуальностиПараметровОграниченияДоступа = ДатаПроверкиПараметровОграниченияДоступа; - Иначе - ДатаАктуальностиПараметровОграниченияДоступа = ДатаСозданияПараметровОграниченияДоступа; - КонецЕсли; - - Если ДатаАктуальностиПараметровОграниченияДоступа > ТекущаяДатаСеанса() Тогда - ДатаАктуальностиПараметровОграниченияДоступа = '00010101'; - КонецЕсли; - - ИспользованиеВидовДоступаИзменено = ИспользованиеВидовДоступаИзменено(ДействующиеПараметры); - - ВерсияТекстовОграниченияДоступаИзменена = Ложь; - ТекущаяВерсияТекстов = Неопределено; - Если ПриЗапуске Тогда - ТекущаяВерсияТекстов = РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(); - Если ДействующиеПараметры.ВерсияТекстовОграниченияДоступа <> ТекущаяВерсияТекстов Тогда - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; - ПоследняяВерсияТекстов = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - ВерсияТекстовОграниченияДоступаИзменена = ПоследняяВерсияТекстов <> ТекущаяВерсияТекстов; - КонецЕсли; - КонецЕсли; - - Если ДатаОбновленияВерсииРасширений > ДатаАктуальностиПараметровОграниченияДоступа - Или ДатаОбновленияВсехПараметровРаботыПрограммы > ДатаАктуальностиПараметровОграниченияДоступа - Или ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений > ДатаАктуальностиПараметровОграниченияДоступа - Или ИспользованиеВидовДоступаИзменено - Или ВерсияТекстовОграниченияДоступаИзменена - Или ПриЗапуске - И ЗапланированоОбновлениеПараметровОграниченияДоступа(ДатаАктуальностиПараметровОграниченияДоступа) Тогда - - Если Показатели <> Неопределено Тогда - НачалоОбновления = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - // Предварительное кэширование в файловой ИБ вне транзакции для предотвращения конфликтов блокировок. - ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом"); // СтандартныеПодсистемыПовтИсп.ИменаПодсистем - УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписей(); - УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); - УправлениеДоступомСлужебныйПовтИсп.ПрофильАдминистратор(); - УправлениеДоступомСлужебныйПовтИсп.ГруппаДоступаАдминистраторы(); - СвойстваВидовДоступа(); - ВозможныеПраваДляНастройкиПравОбъектов(); - КонецЕсли; - - Если ИспользованиеВидовДоступаИзменено Тогда - Попытка - РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); - Исключение - РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); - КонецПопытки; - КонецЕсли; - Попытка - ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); - Исключение - ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); - КонецПопытки; - Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия > 100000000000000 Тогда - Попытка - УменьшитьНомераВерсийПараметровОграниченияДоступа(); - Исключение - УменьшитьНомераВерсийПараметровОграниченияДоступа(); - КонецПопытки; - КонецЕсли; - НоваяДатаПроверкиПараметровОграниченияДоступа = ТекущаяДатаСеанса(); - Попытка - ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Истина); - Исключение - ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Истина); - КонецПопытки; - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; - ПоследняяДата = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - ПоследняяДата = ?(ТипЗнч(ПоследняяДата) = Тип("Дата"), ПоследняяДата, '00010101'); - Если ПоследняяДата < НоваяДатаПроверкиПараметровОграниченияДоступа Тогда - Попытка - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, - НоваяДатаПроверкиПараметровОграниченияДоступа, Истина); - Исключение - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, - НоваяДатаПроверкиПараметровОграниченияДоступа, Истина); - КонецПопытки; - КонецЕсли; - Если ТекущаяВерсияТекстов = Неопределено Тогда - ТекущаяВерсияТекстов = РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(); - КонецЕсли; - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; - ПоследняяВерсияТекстов = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - Если ПоследняяВерсияТекстов <> ТекущаяВерсияТекстов Тогда - Попытка - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, - ТекущаяВерсияТекстов, Истина); - Исключение - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, - ТекущаяВерсияТекстов, Истина); - КонецПопытки; - КонецЕсли; - Если Показатели <> Неопределено Тогда - Показатели.ВремяОбновленияПараметровОграничения = Показатели.ВремяОбновленияПараметровОграничения - + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОбновления); - КонецЕсли; - КонецЕсли; - - // Удаление устаревших параметров ограничения доступа. - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ТекущаяВерсия", ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия); - Запрос.УстановитьПараметр("ДатаУстаревания", ТекущаяДатаСеанса() - 2 * 24 * 60 *60); - Запрос.Текст = - "ВЫБРАТЬ - | ПараметрыОграниченияДоступа.Версия КАК Версия, - | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания - |ИЗ - | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа - |ГДЕ - | ПараметрыОграниченияДоступа.Версия < &ТекущаяВерсия - | И ПараметрыОграниченияДоступа.ДатаСоздания <= &ДатаУстаревания - | - |УПОРЯДОЧИТЬ ПО - | Версия УБЫВ, - | ДатаСоздания УБЫВ"; - - // АПК:1328-выкл. См. 648.1.1. Допустимо чтение без предварительной - // управляемой разделяемой блокировки, так как используется только - // для очистки и какой сеанс очистит первым не важно. - // Если установить разделяемую блокировку, то позже будет повышение - // до исключительной, что ведет к взаимоблокировке и недопустимо. - // Если установить исключительную блокировку на таблицу, то - // это вызовет избыточное замедление запуска сеансов при установке - // параметров сеанса из параметров ограничения, что недопустимо. - РезультатЗапроса = Запрос.Выполнить(); - // АПК:1328-вкл. - - Если Не РезультатЗапроса.Пустой() Тогда - НаборЗаписей = РегистрыСведений.ПараметрыОграниченияДоступа.СоздатьНаборЗаписей(); - Выборка = РезультатЗапроса.Выбрать(); - Пока Выборка.Следующий() Цикл - НаборЗаписей.Отбор.Версия.Установить(Выборка.Версия); - Попытка - НаборЗаписей.Записать(); - Исключение - НаборЗаписей.Записать(); - КонецПопытки; - КонецЦикла; - КонецЕсли; - - УстановитьПривилегированныйРежим(Ложь); - УстановитьОтключениеБезопасногоРежима(Ложь); - - Если Показатели <> Неопределено Тогда - Показатели.ВремяПроверкиИОбновленияПараметровОграничения = Показатели.ВремяПроверкиИОбновленияПараметровОграничения - + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоПроверки); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. -Функция ЗапланированоОбновлениеПараметровОграниченияДоступа(ДатаАктуальности) - - Идентификатор = СлужебныйИдентификатор("РегистрСведений.ПараметрыОграниченияДоступа"); - Если Идентификатор = Null Тогда - Возврат Ложь; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Список", Идентификатор); - Запрос.УстановитьПараметр("ДатаАктуальности", ДатаАктуальности); - Запрос.Текст = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ТекущаяТаблица - |ГДЕ - | ТекущаяТаблица.Список = &Список - | И ТекущаяТаблица.ДатаИзмененияЗаписиРегистра >= &ДатаАктуальности - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ИСТИНА - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ТекущаяТаблица - |ГДЕ - | ТекущаяТаблица.Список = &Список - | И ТекущаяТаблица.ДатаИзмененияЗаписиРегистра >= &ДатаАктуальности"; - - Возврат Не Запрос.Выполнить().Пустой(); - -КонецФункции - -// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. -Процедура УменьшитьНомераВерсийПараметровОграниченияДоступа() - - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - НаборЗаписей = РегистрыСведений.ПараметрыОграниченияДоступа.СоздатьНаборЗаписей(); - НаборЗаписей.Прочитать(); - Выгрузка = НаборЗаписей.Выгрузить(); - Выгрузка.Сортировать("Версия"); - ТекущаяВерсия = 1; - Для Каждого Строка Из Выгрузка Цикл - Строка.Версия = ТекущаяВерсия; - ТекущаяВерсия = ТекущаяВерсия + 1; - КонецЦикла; - НаборЗаписей.Загрузить(Выгрузка); - НаборЗаписей.Записать(); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. -Функция ИспользованиеВидовДоступаИзменено(ДействующиеПараметры) - - Если ДействующиеПараметры.ВнешниеПользователиВключены - <> Константы.ИспользоватьВнешнихПользователей.Получить() - Или ДействующиеПараметры.ОграничениеДоступаВключено - <> Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() Тогда - Возврат Истина; - КонецЕсли; - - СвойстваВидовДоступа = СвойстваВидовДоступа(); - ТекущиеИспользуемыеТипыЗначений = ИспользуемыеТипыЗначений(СвойстваВидовДоступа,,, Истина); - - ИспользуемыеТипыЗначений = ДействующиеПараметры.ИспользуемыеТипыЗначений.Получить(); - - Если ТипЗнч(ИспользуемыеТипыЗначений) <> Тип("Структура") - Или Не ИспользуемыеТипыЗначений.Свойство("ХешСумма") - Или ИспользуемыеТипыЗначений.ХешСумма <> ТекущиеИспользуемыеТипыЗначений.ХешСумма Тогда - Возврат Истина; - КонецЕсли; - - Возврат Ложь; - -КонецФункции - -// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступа, -// ОтменитьОбновлениеДоступаНаУровнеЗаписей, ЗавершитьОбновлениеДоступа. -// -Процедура ЗавершитьПотокиОбновленияДоступа(ОтменитьОбновление = Ложь) - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); - - Если ОтменитьОбновление Тогда - НаборЗаписей.Добавить().ИдентификаторПотока = ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей(); - Иначе - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ОбновлениеКлючейДоступаТекущиеЗадания"; - - Если Запрос.Выполнить().Пустой() Тогда - Возврат; - КонецЕсли; - КонецЕсли; - - НаборЗаписей.Записать(); - -КонецПроцедуры - -// Для процедур ОбработатьВыполненныеЗадания, ЗавершитьПотокиОбновленияДоступа. -Функция ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей() - - Возврат Новый УникальныйИдентификатор("06cc4b5f-a2f9-4622-bef0-df4870ab5dd5"); - -КонецФункции - -// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступа, -// ОтменитьОбновлениеДоступаНаУровнеЗаписей, ЗавершитьОбновлениеДоступа. -// -Процедура ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(СекундОжидания = 5) - - Отбор = Новый Структура; - Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно); - Отбор.Вставить("ИмяМетода", ИмяМетодаПотокаОбновленияДоступа()); - - ФоновыеЗаданияПотоков = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); - Если ФоновыеЗаданияПотоков.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ФоновыеЗаданияПотоков = ФоновыеЗадания.ОжидатьЗавершенияВыполнения(ФоновыеЗаданияПотоков, СекундОжидания); - Для Каждого ФоновоеЗаданиеПотока Из ФоновыеЗаданияПотоков Цикл - Если ФоновоеЗаданиеПотока.Состояние = СостояниеФоновогоЗадания.Активно Тогда - ФоновоеЗаданиеПотока.Отменить(); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Обновляет ключи доступа к данным на основе записей в регистре сведений -// ОбновлениеКлючейДоступаКДанным и ключи доступа пользователей на основе записей -// регистра сведений ОбновлениеКлючейДоступаПользователей. -// -// Обновляется порция данных для каждой таблицы, начиная с самых свежих данных. -// Процедура должна вызываться повторно, пока обработка не будет завершена, -// при этом регламентное задание выключается. -// -// Процедура предназначена для работы в единственном экземпляре, то есть без параллельной -// работы (вызов из процедуры регламентного задания ОбновлениеДоступаНаУровнеЗаписей). -// Параллельность обеспечивает сама процедура путем запуска до двух фоновых заданий -// на каждый список, но не более значения константы КоличествоПотоковОбновленияДоступа. -// -Процедура ВыполнитьОбновлениеДоступа(ОбновитьВсе, ПараметрыВыполнения, ПоследнееОбновлениеДоступа) - - Контекст = НовыйКонтекстОбновленияДоступа(); - Контекст.Вставить("Показатели", ПоказателиОбновленияОсновногоСеанса()); - Контекст.Вставить("ОписаниеОсновногоСеанса", ПараметрыВыполнения.ОписаниеОсновногоСеанса); - Контекст.Вставить("ТекущееФоновоеЗадание", ПараметрыВыполнения.ОписаниеОсновногоСеанса.ФоновоеЗадание); - Контекст.Вставить("Задания", ТаблицаЗаданийОбновления()); - Контекст.Вставить("ЗаданияДляЗапуска", Новый Массив); - Контекст.Вставить("ЗанятыеПотоки", Новый Соответствие); - Контекст.Вставить("СвободныеПотоки", Новый Массив); - Контекст.Вставить("ГраницаОбновленияЗаданий", '00010101'); - Контекст.Вставить("ОбщиеПараметрыОбновления", ОписаниеОбщихПараметровОбновления()); - Контекст.Вставить("ОбновлениеВЭтомСеансе", Ложь); - Контекст.Вставить("КоличествоПотоков", 0); - Контекст.Вставить("ДатаПолногоЗавершения", ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения); - Контекст.Вставить("ТекстОшибкиЗавершения", ""); - Контекст.Вставить("ЕстьОтложенныеЗадания", Ложь); - Контекст.Вставить("ЕстьЗапущенноеЗадание", Истина); - Контекст.Вставить("ОбработкаЗавершена", Ложь); - Контекст.Вставить("ОбновлениеОтменено", Ложь); - Контекст.Вставить("ТребуетсяПерезапускСеанса",Ложь); - Контекст.Вставить("МаксимумПорцийИзИсходной", 0); - Контекст.Вставить("МаксимумМиллисекундОбработкиПорции", 0); - Контекст.Вставить("КоличествоДополнительныхПорций", 0); - Контекст.Вставить("ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных", Ложь); - Контекст.Вставить("МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных", 0); - Контекст.Вставить("ИдентификаторыОтключенныхОбъектовМетаданных", Новый Соответствие); - Контекст.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.НаборыГруппДоступа")); - ПараметрыВыполнения.ОписаниеОсновногоСеанса.Удалить("ФоновоеЗадание"); - - ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст, Истина); - ЗапланироватьОбработкуУстаревшихЭлементов(ПараметрыВыполнения.ТекстОшибкиПланирования, - ПоследнееОбновлениеДоступа.ПоследнееПланированиеОбработкиУстаревшихЭлементов); - - Запрос = Новый Запрос; - Запрос.Текст = ТекстЗапросаЗаданий(); - Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДата()); - Запрос.УстановитьПараметр("ПустойИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - ЗавершитьПотокиОбновленияДоступа(); - ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(1); - - Задания = Контекст.Задания; - ЗанятыеПотоки = Контекст.ЗанятыеПотоки; - - Если ПараметрыВыполнения.СекундНеБолее > 0 Тогда - ОкончаниеВыполнения = ТекущаяДатаСеанса() + ПараметрыВыполнения.СекундНеБолее; - Иначе - ОкончаниеВыполнения = ТекущаяДатаСеанса() - + МаксимальноеКоличествоМинутВыполненияФоновогоЗаданияОбновленияДоступа() * 60; - КонецЕсли; - - ЗаполнитьКоличествоПотоков(Контекст); - ДобавитьПоказателиОбновленияУправляющегоПотока(Контекст); - ПовторныйЗапуск = Ложь; - - Пока Истина Цикл - Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск - Или ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда - Прервать; - КонецЕсли; - Контекст.ОбработкаЗавершена = Истина; - - ЗаполнитьКоличествоПотоков(Контекст); - // @skip-check query-in-loop - Порционная обработка данных - ОбработатьВыполненныеЗадания(Контекст); - - Если Контекст.ОбновлениеОтменено Или Контекст.ТребуетсяПерезапускСеанса Тогда - Контекст.ОбработкаЗавершена = Ложь; - Прервать; - КонецЕсли; - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - ДобавитьЗаданияОбновленияДоступа(РезультатыЗапроса, Контекст); - - Если Контекст.ТребуетсяПерезапускСеанса Тогда - Контекст.ОбработкаЗавершена = Ложь; - Прервать; - ИначеЕсли Контекст.ОбработкаЗавершена Тогда - ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст); - Если Не Контекст.ОбработкаЗавершена Тогда - Продолжить; - КонецЕсли; - Прервать; - КонецЕсли; - Контекст.ДатаПолногоЗавершения = '00010101'; - - ОкончаниеТекущегоЗапуска = ТекущаяДатаСеанса() + 5; - Контекст.Вставить("ПервыйПроход", Истина); - - Пока Истина Цикл - - Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск - Или ТекущаяДатаСеанса() > ОкончаниеТекущегоЗапуска - Или ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) - Или Задания.Количество() = 0 - Или Контекст.ОбновлениеОтменено - Или Контекст.ТребуетсяПерезапускСеанса Тогда - Прервать; - КонецЕсли; - - ПрерватьПроход = Ложь; - МоментПрерыванияПрохода = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; - ЗаполнитьОбщиеПараметрыОбновления(Контекст); - Контекст.ЕстьЗапущенноеЗадание = Ложь; - ЗаданияДляЗапуска = Контекст.ЗаданияДляЗапуска; - - Для Каждого Задание Из ЗаданияДляЗапуска Цикл - - Пока ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Цикл - // @skip-check query-in-loop - Порционная обработка данных - ОбработатьВыполненныеЗадания(Контекст); - - Если Контекст.ОбновлениеОтменено Или Контекст.ТребуетсяПерезапускСеанса Тогда - ПрерватьПроход = Истина; - Прервать; - КонецЕсли; - - Если ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Тогда - Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск - Или ТекущаяДатаСеанса() > ОкончаниеТекущегоЗапуска Тогда - ПрерватьПроход = Истина; - Прервать; - КонецЕсли; - // @skip-check query-in-loop - Порционная обработка данных - ПодождатьОсвобожденияПотока(Контекст, Истина); - Если Не Контекст.ПервыйПроход - И ТекущаяУниверсальнаяДатаВМиллисекундах() > МоментПрерыванияПрохода Тогда - ПрерватьПроход = Истина; - Прервать; - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если ПрерватьПроход Тогда - Прервать; - КонецЕсли; - Если ЗанятыеПотоки.Количество() < Контекст.КоличествоПотоков Тогда - // @skip-check query-in-loop - Порционная обработка данных - ЗапуститьОбновлениеДоступаСписка(Задание, Контекст); - ПовторныйЗапуск = Истина; - Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) - Или Контекст.ОбновлениеОтменено - Или Контекст.ТребуетсяПерезапускСеанса Тогда - Прервать; - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если Не Контекст.ЕстьЗапущенноеЗадание - И (ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков - Или Не Контекст.ЕстьОтложенныеЗадания) Тогда - // @skip-check query-in-loop - Порционная обработка данных - ПодождатьОсвобожденияПотока(Контекст, Истина); - КонецЕсли; - // @skip-check query-in-loop - Порционная обработка данных - ОбработатьВыполненныеЗадания(Контекст); - Контекст.ПервыйПроход = Ложь; - КонецЦикла; - - Если Не ОбновитьВсе - И ПоследнееОбновлениеДоступа.ДляУскорения - И ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(Ложь) - И Задания.Найти(Истина, "ЕстьТочечноеЗадание") = Неопределено Тогда - - Если ПоследнееОбновлениеДоступа().ДляУскорения Тогда - Прервать; - Иначе - ПоследнееОбновлениеДоступа.ДляУскорения = Ложь; - КонецЕсли; - КонецЕсли; - КонецЦикла; - - Если Не Контекст.ОбработкаЗавершена - И Не ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) - И Не Контекст.ОбновлениеОтменено - И Не Контекст.ТребуетсяПерезапускСеанса Тогда - - ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст); - КонецЕсли; - - ЗавершитьОбновлениеДоступа(Контекст); - - ПараметрыВыполнения.ТекстОшибкиЗавершения = Контекст.ТекстОшибкиЗавершения; - ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Контекст.ОбновлениеОтменено; - ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = Контекст.ДатаПолногоЗавершения; - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ОписаниеОсновногоСеанса - см. ОписаниеОсновногоСеанса -// * ТекущееФоновоеЗадание - ФоновоеЗадание -// * Задания - см. ТаблицаЗаданийОбновления -// * ЗаданияДляЗапуска - Массив из СтрокаТаблицыЗначений: см. ТаблицаЗаданийОбновления -// * ЗанятыеПотоки - Соответствие из КлючИЗначение: -// ** Ключ - УникальныйИдентификатор -// ** Значение - см. НовыйПоток -// * СвободныеПотоки - Массив из см. НовыйПоток -// * ГраницаОбновленияЗаданий - Дата -// * ОбщиеПараметрыОбновления - см. ОписаниеОбщихПараметровОбновления -// * ОбновлениеВЭтомСеансе - Булево -// * КоличествоПотоков - Число -// * ДатаПолногоЗавершения - Дата -// * ТекстОшибкиЗавершения - Строка -// * ЕстьОтложенныеЗадания - Булево -// * ЕстьЗапущенноеЗадание - Булево -// * ОбработкаЗавершена - Булево -// * ОбновлениеОтменено - Булево -// * ТребуетсяПерезапускСеанса - Булево -// * МаксимумПорцийИзИсходной - Число -// * КоличествоДополнительныхПорций - Число -// * ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных - Булево -// * МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных - Число -// * ИдентификаторыОтключенныхОбъектовМетаданных - Соответствие -// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// -Функция НовыйКонтекстОбновленияДоступа() - - Возврат Новый Структура; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ЗапланироватьОбработкуУстаревшихЭлементов(ТекстОшибкиПланирования, - ПоследнееПланированиеОбработкиУстаревшихЭлементов) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ПустойИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным - | ГДЕ ОбновлениеКлючейДоступаКДанным.РазмерЗадания = 2 - | И КлючУникальности <> &ПустойИдентификатор"; - - Если Не Запрос.Выполнить().Пустой() Тогда - Возврат; - КонецЕсли; - - Если Не ЗначениеЗаполнено(ПоследнееПланированиеОбработкиУстаревшихЭлементов) Тогда - ПоследнееПланированиеОбработкиУстаревшихЭлементов = ТекущаяДатаСеанса(); - КонецЕсли; - Попытка - ГраницаОжидания = ТекущаяДатаСеанса() - КоличествоЧасовМеждуПланированиемОбработкиУстаревшихЭлементов() * 60 * 60; - Если ПоследнееПланированиеОбработкиУстаревшихЭлементов < ГраницаОжидания Тогда - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; - ПараметрыПланирования.Описание = "ОбновлениеДоступаНаУровнеЗаписей"; - ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); - ПоследнееПланированиеОбработкиУстаревшихЭлементов = ТекущаяДатаСеанса(); - КонецЕсли; - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибкиПланирования = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось запланировать обработку устаревших элементов ограничения доступа по причине: - |%1'"), - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ЗапуститьОбновлениеДоступаСписка. -Функция МаксимумМиллисекундПолученияПорций(Контекст) - - Если Не ЗначениеЗаполнено(Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных) Тогда - Результат = 3000; - - ИначеЕсли Не Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных Тогда - Результат = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000 - 1000; - Иначе - Результат = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000 / 2; - КонецЕсли; - - Если Результат < 1000 Тогда - Результат = 1000; - КонецЕсли; - - Возврат Результат; - -КонецФункции - -// Для процедуры ЗаполнитьКоличествоПотоков и формы ОбновлениеДоступаНаУровнеЗаписей. -// -// Возвращаемое значение: -// Булево -// -Функция ДоступнаБалансировкаНагрузкиНаДиск() Экспорт - - Возврат МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных() > 0 - И УправлениеДоступомСлужебныйПовтИсп.ДоступнаБалансировкаНагрузкиНаДиск(); - -КонецФункции - -// Для процедуры ЗаполнитьКоличествоПотоков и формы ОбновлениеДоступаНаУровнеЗаписей. -// -// Возвращаемое значение: -// Булево -// -Функция БалансировкаНагрузкиНаДиск() Экспорт - - ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); - ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); - Возврат ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск; - -КонецФункции - -// Для формы ОбновлениеДоступаНаУровнеЗаписей. -Процедура УстановитьБалансировкуНагрузкиНаДиск(Использование) Экспорт - - БлокировкаДанных = Новый БлокировкаДанных; - БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); - - ЕстьВнешняяТранзакция = ТранзакцияАктивна(); - НачатьТранзакцию(); - Попытка - БлокировкаДанных.Заблокировать(); - ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); - ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); - - Если ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск <> Использование Тогда - ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск = Использование; - УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -// Возвращаемое значение: -// ТаблицаЗначений: -// * ЕстьТочечноеЗадание - Булево -// * ЕстьНачальноеОбновлениеТочечногоЗадания - Дата -// * ДатаПоследнегоЗапускаТочечногоЗадания - Дата -// * ДатаДобавленияТочечногоЗадания - Дата -// * УровеньЗависимости - Число -// * ЗависимыеСписки - Массив -// - Строка -// * ЕстьНачальноеОбновление - Булево -// * ЕстьПерезапуск - Булево -// * ДатаПоследнегоЗапускаОбщегоЗадания - Дата -// * ЕстьДатаПоследнегоОбновленногоЭлемента - Булево -// * ДатаПоследнегоОбновленногоЭлемента - Дата -// * ДатаДобавленияОбщегоЗадания - Дата -// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// * ДляВнешнихПользователей - Булево -// * ЭтоОбновлениеПрав - Булево -// * Запускать - Булево -// * ЗанятыеПотоки - Соответствие из КлючИЗначение: -// ** Ключ - УникальныйИдентификатор -// ** Значение - см. НовыйПоток -// * НаборПорций - Массив из см. ПорцияИзНабора -// * КоличествоПорцийДляОбработки - Число -// * ИндексСледующейПорцииДляОбработки - Число -// * Пропустить - Булево -// * Удалить - Булево -// * ПорядокВидаКлючаДанных - Число -// * ЭтоОбработкаУстаревшихЭлементов - Булево -// * ОбновитьУровеньЗависимости - Булево -// -Функция ТаблицаЗаданийОбновления() - - ТипыИдентификаторов = Новый Массив; - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); - - Задания = Новый ТаблицаЗначений; - Задания.Колонки.Добавить("ЕстьТочечноеЗадание", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ЕстьНачальноеОбновлениеТочечногоЗадания",Новый ОписаниеТипов("Дата")); - Задания.Колонки.Добавить("ДатаПоследнегоЗапускаТочечногоЗадания", Новый ОписаниеТипов("Дата")); - Задания.Колонки.Добавить("ДатаДобавленияТочечногоЗадания", Новый ОписаниеТипов("Дата")); - Задания.Колонки.Добавить("УровеньЗависимости", Новый ОписаниеТипов("Число")); - Задания.Колонки.Добавить("ЗависимыеСписки", Новый ОписаниеТипов("Массив,Строка")); - Задания.Колонки.Добавить("ЕстьНачальноеОбновление", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ЕстьПерезапуск", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ДатаПоследнегоЗапускаОбщегоЗадания", Новый ОписаниеТипов("Дата")); - Задания.Колонки.Добавить("ЕстьДатаПоследнегоОбновленногоЭлемента", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ДатаПоследнегоОбновленногоЭлемента", Новый ОписаниеТипов("Дата")); - Задания.Колонки.Добавить("ДатаДобавленияОбщегоЗадания", Новый ОписаниеТипов("Дата")); - Задания.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); - Задания.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ЭтоОбновлениеПрав", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("Запускать", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ЗанятыеПотоки", Новый ОписаниеТипов("Соответствие")); - Задания.Колонки.Добавить("НаборПорций", Новый ОписаниеТипов("Массив")); - Задания.Колонки.Добавить("КоличествоПорцийДляОбработки", Новый ОписаниеТипов("Число")); - Задания.Колонки.Добавить("ИндексСледующейПорцииДляОбработки", Новый ОписаниеТипов("Число")); - Задания.Колонки.Добавить("Пропустить", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("Удалить", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ПорядокВидаКлючаДанных", Новый ОписаниеТипов("Число")); - Задания.Колонки.Добавить("ЭтоОбработкаУстаревшихЭлементов", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("РазрешенаОбработкаУстаревшихЭлементов", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ОбновитьУровеньЗависимости", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("БылаОшибка", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ТекстОшибки", Новый ОписаниеТипов("Строка")); - Задания.Колонки.Добавить("ДлительноеЗаданиеПолученияПорцийДо", Новый ОписаниеТипов("Дата")); - - Задания.Индексы.Добавить( - "ЕстьТочечноеЗадание, - |ЕстьНачальноеОбновлениеТочечногоЗадания, - |ДатаПоследнегоЗапускаТочечногоЗадания, - |ДатаДобавленияТочечногоЗадания, - |ЕстьНачальноеОбновление, - |ДатаПоследнегоЗапускаОбщегоЗадания, - |ЕстьДатаПоследнегоОбновленногоЭлемента, - |ДатаПоследнегоОбновленногоЭлемента, - |ДатаДобавленияОбщегоЗадания"); - - Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); - Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав, ЭтоОбработкаУстаревшихЭлементов"); - Задания.Индексы.Добавить("Удалить, ЭтоОбработкаУстаревшихЭлементов"); - Задания.Индексы.Добавить("УровеньЗависимости"); - - Возврат Задания; - -КонецФункции - -// Для процедуры ДобавитьЗаданияОбновленияДоступа. -Функция ТаблицаКлючейЗаданий() - - ТипыИдентификаторов = Новый Массив; - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); - - Задания = Новый ТаблицаЗначений; - Задания.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); - Задания.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); - Задания.Колонки.Добавить("ЭтоОбновлениеПрав", Новый ОписаниеТипов("Булево")); - - Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); - - Возврат Задания; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -// -// Возвращаемое значение: -// Структура: -// * ИдентификаторПотока - УникальныйИдентификатор -// * ФоновоеЗадание - ФоновоеЗадание -// * Задание - СтрокаТаблицыЗначений из см. ТаблицаЗаданийОбновления -// * ОтменитьЗадание - Булево -// * МоментЗапускаЗадания - Число -// * ПорцияИзНабора - см. ПорцияИзНабора -// * ПолучитьПорции - Число -// * ДатаОсвобождения - Дата -// -Функция НовыйПоток() - - Поток = Новый Структура; - Поток.Вставить("ИдентификаторПотока"); - Поток.Вставить("ФоновоеЗадание"); - Поток.Вставить("Задание"); - Поток.Вставить("ОтменитьЗадание", Ложь); - Поток.Вставить("МоментЗапускаЗадания", 0); - Поток.Вставить("ПорцияИзНабора"); - Поток.Вставить("ПолучитьПорции", 0); - Поток.Вставить("ДатаОсвобождения", '00010101'); - - Возврат Поток; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -// -// Возвращаемое значение: -// Структура: -// * ЭтоОбновлениеПрав - Булево -// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// * ДляВнешнихПользователей - Булево -// * ЭтоОбработкаУстаревшихЭлементов - Булево -// * РазрешенаОбработкаУстаревшихЭлементов - Булево -// * ДатаНачала - Дата -// * ДатаОкончания - Дата -// * НачальноеОбновление - Булево -// * ОбработкаЗавершена - Булево -// * МаксимумМиллисекундОбработки - Число -// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// * Кэш - см. НовыйКэшКонтекста -// * МаксимумПорцийИзИсходной - Число -// -Функция ОписаниеОбщихПараметровОбновления(Контекст = Неопределено) - - ОбщиеПараметрыОбновления = Новый Структура; - ОбщиеПараметрыОбновления.Вставить("ЭтоОбновлениеПрав", Ложь); - ОбщиеПараметрыОбновления.Вставить("ИдентификаторСписка", Неопределено); - ОбщиеПараметрыОбновления.Вставить("ДляВнешнихПользователей", Ложь); - ОбщиеПараметрыОбновления.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); - ОбщиеПараметрыОбновления.Вставить("РазрешенаОбработкаУстаревшихЭлементов", Ложь); - ОбщиеПараметрыОбновления.Вставить("ДатаНачала", '00010101'); - ОбщиеПараметрыОбновления.Вставить("ДатаОкончания", '00010101'); - ОбщиеПараметрыОбновления.Вставить("НачальноеОбновление", Ложь); - ОбщиеПараметрыОбновления.Вставить("ОбработкаЗавершена", Истина); - ОбщиеПараметрыОбновления.Вставить("МаксимумМиллисекундОбработки", 1000); - - Если Контекст = Неопределено Тогда - ОбщиеПараметрыОбновления.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", - ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.НаборыГруппДоступа")); - Иначе - ОбщиеПараметрыОбновления.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", - Контекст.ИдентификаторСправочникаНаборыГруппДоступа); - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - ОбщиеПараметрыОбновления.Вставить("Кэш", Контекст.Кэш); - КонецЕсли; - ОбщиеПараметрыОбновления.Вставить("МаксимумПорцийИзИсходной", Контекст.МаксимумПорцийИзИсходной); - КонецЕсли; - - Возврат ОбщиеПараметрыОбновления; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -Функция ТекстЗапросаЗаданий() - - Возврат - "ВЫБРАТЬ - | ЛОЖЬ КАК ЭтоОбновлениеПрав, - | Списки.Список КАК ИдентификаторСписка, - | Списки.ДляВнешнихПользователей КАК ДляВнешнихПользователей, - | МАКСИМУМ(Списки.ТочечноеЗадание) КАК ЕстьТочечноеЗадание, - | МАКСИМУМ(Списки.ТочечноеЗадание - | И Списки.ДатаПоследнегоОбновленногоЭлемента = &МаксимальнаяДата) КАК ЕстьНачальноеОбновлениеТочечногоЗадания, - | МАКСИМУМ(ВЫБОР - | КОГДА Списки.ТочечноеЗадание - | И Списки.КлючУникальности <> &ПустойИдентификатор - | ТОГДА Списки.ДатаИзмененияЗаписиРегистра - | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) - | КОНЕЦ) КАК ДатаДобавленияТочечногоЗадания, - | МАКСИМУМ(Списки.РазмерЗадания = 2) КАК ЕстьОбработкаУстаревших, - | МАКСИМУМ(Списки.РазмерЗадания = 3) КАК ЕстьПолноеОбновление, - | МАКСИМУМ(Списки.РазмерЗадания = 3 - | И Списки.ДатаПоследнегоОбновленногоЭлемента = &МаксимальнаяДата) КАК ЕстьНачальноеОбновление, - | МАКСИМУМ(НЕ Списки.ТочечноеЗадание - | И Списки.КлючУникальности <> &ПустойИдентификатор) КАК ЕстьПерезапуск, - | МАКСИМУМ(ВЫБОР - | КОГДА НЕ Списки.ТочечноеЗадание - | ИЛИ Списки.КлючУникальности = &ПустойИдентификатор - | ТОГДА Списки.ДатаПоследнегоОбновленногоЭлемента - | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) - | КОНЕЦ) КАК ДатаПоследнегоОбновленногоЭлемента, - | МАКСИМУМ(ВЫБОР - | КОГДА НЕ Списки.ТочечноеЗадание - | И Списки.КлючУникальности <> &ПустойИдентификатор - | ТОГДА Списки.ДатаИзмененияЗаписиРегистра - | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) - | КОНЕЦ) КАК ДатаДобавленияОбщегоЗадания - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК Списки - | - |СГРУППИРОВАТЬ ПО - | Списки.Список, - | Списки.ДляВнешнихПользователей - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ИСТИНА, - | Списки.Список, - | Списки.ДляВнешнихПользователей, - | МАКСИМУМ(Списки.ТочечноеЗадание), - | ЛОЖЬ, - | МАКСИМУМ(ВЫБОР - | КОГДА Списки.ТочечноеЗадание - | И Списки.КлючУникальности <> &ПустойИдентификатор - | ТОГДА Списки.ДатаИзмененияЗаписиРегистра - | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) - | КОНЕЦ), - | МАКСИМУМ(Списки.РазмерЗадания = 2), - | МАКСИМУМ(Списки.РазмерЗадания = 3), - | ЛОЖЬ, - | МАКСИМУМ(НЕ Списки.ТочечноеЗадание - | И Списки.КлючУникальности <> &ПустойИдентификатор), - | ДАТАВРЕМЯ(1, 1, 1), - | МАКСИМУМ(ВЫБОР - | КОГДА НЕ Списки.ТочечноеЗадание - | И Списки.КлючУникальности <> &ПустойИдентификатор - | ТОГДА Списки.ДатаИзмененияЗаписиРегистра - | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) - | КОНЕЦ) - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК Списки - | - |СГРУППИРОВАТЬ ПО - | Списки.Список, - | Списки.ДляВнешнихПользователей"; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ЗаполнитьКоличествоПотоков(Контекст) - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - Возврат; - КонецЕсли; - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - КоличествоПотоков = 1; - Контекст.МаксимумПорцийИзИсходной = 5; - Иначе - КоличествоПотоков = Константы.КоличествоПотоковОбновленияДоступа.Получить(); - Контекст.МаксимумПорцийИзИсходной = 5 + (КоличествоПотоков - 1) * 2; - КонецЕсли; - - Если КоличествоПотоков < 1 Тогда - КоличествоПотоков = 1; - КонецЕсли; - - Если Контекст.КоличествоПотоков = 0 Тогда - Контекст.ОбновлениеВЭтомСеансе = КоличествоПотоков = 1; - КонецЕсли; - - Контекст.КоличествоПотоков = КоличествоПотоков; - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - Возврат; - КонецЕсли; - - Если ДоступнаБалансировкаНагрузкиНаДиск() И БалансировкаНагрузкиНаДиск() Тогда - Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных = - МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных(); - Иначе - Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных = 0; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ДобавитьЗаданияОбновленияДоступа(РезультатыЗапроса, Контекст) - - Если Контекст.Свойство("Кэш") Тогда - Кэш = Контекст.Кэш; // см. НовыйКэшКонтекста - Иначе - Кэш = НовыйКэшКонтекста(); - Контекст.Вставить("Кэш", Кэш); - Контекст.Вставить("ИдентификаторыПоПолнымИменам", Новый Соответствие); - Контекст.Вставить("ВерсияПараметровОграничения"); - Контекст.Вставить("ХешСуммаПараметровОграничения"); - КонецЕсли; - Если Не Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда - Кэш.Вставить("ОбъектыМетаданныхПоИдентификаторам", Новый Соответствие); - КонецЕсли; - - Попытка - ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст); - Исключение - Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда - Контекст.ТребуетсяПерезапускСеанса = Истина; - Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда - Возврат; - КонецЕсли; - КонецЕсли; - ВызватьИсключение; - КонецПопытки; - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - Задания = Контекст.Задания; - ИдентификаторыСписков = Новый Массив; - - Если Контекст.ВерсияПараметровОграничения <> ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия - Или Контекст.ХешСуммаПараметровОграничения <> ПараметрыСеанса.ПараметрыОграниченияДоступа.ХешСумма Тогда - - Задания.ЗаполнитьЗначения(-1, "УровеньЗависимости"); - Задания.ЗаполнитьЗначения(Неопределено, "ЗависимыеСписки"); - Контекст.Вставить("ИдентификаторыПоПолнымИменам", Новый Соответствие); - Контекст.Вставить("ВедущиеСпискиПоЗависимым", ТаблицаКлючейЗаданий()); - Контекст.ВедущиеСпискиПоЗависимым.Колонки.Добавить("ВедущиеСписки"); - - ТекущиеИдентификаторыСписка = Задания.Скопировать(, "ИдентификаторСписка"); - ТекущиеИдентификаторыСписка.Свернуть("ИдентификаторСписка"); - ИдентификаторыСписков = ТекущиеИдентификаторыСписка.ВыгрузитьКолонку("ИдентификаторСписка"); - - Контекст.ВерсияПараметровОграничения = ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия; - Контекст.ХешСуммаПараметровОграничения = ПараметрыСеанса.ПараметрыОграниченияДоступа.ХешСумма; - КонецЕсли; - - Задания.ЗаполнитьЗначения(Истина, "Удалить"); - Отбор = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); - - Выгрузка = РезультатыЗапроса[0].Выгрузить(); - - Для Каждого Строка Из Выгрузка Цикл - Если Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Получить(Строка.ИдентификаторСписка) <> Неопределено Тогда - Продолжить; - КонецЕсли; - ЗаполнитьЗначенияСвойств(Отбор, Строка); - Строки = Задания.НайтиСтроки(Отбор); - Если Строки.Количество() = 0 Тогда - Задание = Задания.Добавить(); - Задание.УровеньЗависимости = -1; // Не заполнен. - Если Строка.ИдентификаторСписка <> Неопределено - И Кэш.ОбъектыМетаданныхПоИдентификаторам.Получить(Строка.ИдентификаторСписка) = Неопределено Тогда - ИдентификаторыСписков.Добавить(Строка.ИдентификаторСписка); - КонецЕсли; - Если Строка.ЕстьОбработкаУстаревших И Не Строка.ЕстьТочечноеЗадание И Не Строка.ЕстьПолноеОбновление Тогда - Задание.ПорядокВидаКлючаДанных = ПорядокВидаКлючаДанных("УстаревшиеЭлементы"); - КонецЕсли; - Иначе - Задание = Строки[0]; - КонецЕсли; - ЗаполнитьЗначенияСвойств(Задание, Строка); - Задание.Удалить = Ложь; - ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание, Ложь); - Если Строка.ЕстьПолноеОбновление Тогда - Задание.ЭтоОбработкаУстаревшихЭлементов = Ложь; - КонецЕсли; - Задание.ЕстьДатаПоследнегоОбновленногоЭлемента - = ЗначениеЗаполнено(Задание.ДатаПоследнегоОбновленногоЭлемента); - - Если Задание.ЕстьПерезапуск Тогда - ОтменитьЗадание(Задание); - КонецЕсли; - КонецЦикла; - - Если ИдентификаторыСписков.Количество() > 0 Тогда - ОбъектыМетаданныхПоИдентификаторам = - ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИдентификаторыСписков, Ложь); - Для Каждого КлючИЗначение Из ОбъектыМетаданныхПоИдентификаторам Цикл - Кэш.ОбъектыМетаданныхПоИдентификаторам.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - Если ТипЗнч(КлючИЗначение.Значение) = Тип("ОбъектМетаданных") Тогда - Контекст.ИдентификаторыПоПолнымИменам.Вставить(КлючИЗначение.Значение.ПолноеИмя(), КлючИЗначение.Ключ); - ИначеЕсли КлючИЗначение.Значение = Неопределено Тогда - Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Вставить(КлючИЗначение.Ключ, Истина); - Строки = Задания.НайтиСтроки(Новый Структура("ИдентификаторСписка", КлючИЗначение.Ключ)); - Для Каждого Строка Из Строки Цикл - Задания.Удалить(Строка); - КонецЦикла; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Если Задания.Количество() > 0 Тогда - Контекст.ОбработкаЗавершена = Ложь; - КонецЕсли; - - ЗаполнитьУровниЗависимостиЗаданий(Контекст, ДействующиеПараметры.ВедущиеСписки); - -КонецПроцедуры - -// Для функции ДобавитьЗаданияОбновленияДоступа. -// -// Возвращаемое значение: -// Структура: -// * ОбъектыМетаданныхПоИдентификаторам - Соответствие -// -Функция НовыйКэшКонтекста() - - Возврат Новый Структура; - -КонецФункции - -// Для процедур ДобавитьЗаданияОбновленияДоступа, ОбновитьСвойстваЗадания и -// функции ЗапуститьОбновлениеДоступаСписка. -// -Процедура ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание, ТребуетсяОбновитьУровеньЗависимостиПриИзменении = Истина) - - ЭтоОбработкаУстаревшихЭлементов = Не Задание.ЕстьТочечноеЗадание - И Задание.ПорядокВидаКлючаДанных >= ПорядокВидаКлючаДанных("УстаревшиеЭлементы") - И Задание.ПорядокВидаКлючаДанных < ПорядокВидаКлючаДанных("НетДанных"); - - Если Задание.ЭтоОбработкаУстаревшихЭлементов <> ЭтоОбработкаУстаревшихЭлементов Тогда - Задание.ЭтоОбработкаУстаревшихЭлементов = ЭтоОбработкаУстаревшихЭлементов; - Задание.ОбновитьУровеньЗависимости = ТребуетсяОбновитьУровеньЗависимостиПриИзменении; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьОбщиеПараметрыОбновления. -Функция ЭтоОбновлениеСоставаНаборовГруппДоступа(Задание, Контекст) - - Возврат Задание.ИдентификаторСписка = Контекст.ИдентификаторСправочникаНаборыГруппДоступа - И Задание.ПорядокВидаКлючаДанных <= ПорядокВидаКлючаДанных("НаборыГруппРазрешенныеПользователям"); - -КонецФункции - -// Для процедуры ДобавитьЗаданияОбновленияДоступа. -Процедура ЗаполнитьУровниЗависимостиЗаданий(Контекст, СвойстваВедущихСписков) - - Задания = Контекст.Задания; - ОбъектыМетаданныхПоИдентификаторам = Контекст.Кэш.ОбъектыМетаданныхПоИдентификаторам; - ИдентификаторыПоПолнымИменам = Контекст.ИдентификаторыПоПолнымИменам; - - ЗаданияДляЗаполнения = Задания.НайтиСтроки(Новый Структура("УровеньЗависимости", -1)); - ВедущиеСпискиПоЗависимым = Контекст.ВедущиеСпискиПоЗависимым; - ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); - - Для Каждого Задание Из ЗаданияДляЗаполнения Цикл - УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, ВедущиеСпискиПоЗависимым); - - ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(Задание.ИдентификаторСписка); - Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда - Продолжить; - КонецЕсли; - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - СвойстваВедущегоСписка = СвойстваВедущихСписков.Получить(ПолноеИмя); - Если СвойстваВедущегоСписка = Неопределено - Или СвойстваВедущегоСписка.ПоКлючамДоступа = Неопределено Тогда - Продолжить; - КонецЕсли; - Если Задание.ДляВнешнихПользователей Тогда - ЗависимыеСписки = СвойстваВедущегоСписка.ПоКлючамДоступа.ДляВнешнихПользователей; - Иначе - ЗависимыеСписки = СвойстваВедущегоСписка.ПоКлючамДоступа.ДляПользователей; - КонецЕсли; - Если ЗависимыеСписки = Неопределено Тогда - Продолжить; - КонецЕсли; - ЗаполнитьЗначенияСвойств(ОтборЗадания, Задание); - Для Каждого ЗависимыйСписок Из ЗависимыеСписки Цикл - ИдентификаторЗависимого = ИдентификаторыПоПолнымИменам.Получить(ЗависимыйСписок); - Если Задание.ЗависимыеСписки = Неопределено Тогда - Задание.ЗависимыеСписки = Новый Массив; - КонецЕсли; - ЗаданиеЗависимыеСписки = Задание.ЗависимыеСписки; - ЗаданиеЗависимыеСписки.Добавить(ИдентификаторЗависимого); - ОтборЗадания.ИдентификаторСписка = ИдентификаторЗависимого; - Найденные = ВедущиеСпискиПоЗависимым.НайтиСтроки(ОтборЗадания); - Если Найденные.Количество() = 0 Тогда - ВедущиеСписки = Новый Соответствие; - НоваяСтрока = ВедущиеСпискиПоЗависимым.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, ОтборЗадания); - НоваяСтрока.ВедущиеСписки = ВедущиеСписки; - Иначе - ВедущиеСписки = Найденные[0].ВедущиеСписки; - КонецЕсли; - ВедущиеСписки.Вставить(Задание.ИдентификаторСписка, Истина); - ЗависимыеЗадания = Задания.НайтиСтроки(ОтборЗадания); - Если ЗависимыеЗадания.Количество() > 0 Тогда - УстановитьУровеньЗависимостиПоВедущим(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); - КонецЕсли; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ЗаполнитьУровниЗависимостиЗаданий, ОбновитьУровеньЗависимости. -Процедура УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, ВедущиеСпискиПоЗависимым) - - Задание.УровеньЗависимости = 0; - Если Задание.ЭтоОбработкаУстаревшихЭлементов Тогда - Возврат; - КонецЕсли; - - ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав", - Задание.ИдентификаторСписка, Задание.ДляВнешнихПользователей, Задание.ЭтоОбновлениеПрав); - - Найденные = ВедущиеСпискиПоЗависимым.НайтиСтроки(ОтборЗадания); - Если Найденные.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ОтборЗадания.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); - - Для Каждого ОписаниеВедущегоСписка Из Найденные[0].ВедущиеСписки Цикл - ОтборЗадания.ИдентификаторСписка = ОписаниеВедущегоСписка.Ключ; - ВедущиеЗадания = Задания.НайтиСтроки(ОтборЗадания); - Если ВедущиеЗадания.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - Если Задание.УровеньЗависимости < ВедущиеЗадания[0].УровеньЗависимости + 1 Тогда - Задание.УровеньЗависимости = ВедущиеЗадания[0].УровеньЗависимости + 1; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ЗаполнитьОбщиеПараметрыОбновления. -Процедура ОбновитьУровеньЗависимости(СвойстваЗадания, Задания, ВедущиеСпискиПоЗависимым) - - Если Не ЗначениеЗаполнено(СвойстваЗадания.ЗависимыеСписки) Тогда - Возврат; - КонецЕсли; - ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); - ЗаполнитьЗначенияСвойств(ОтборЗадания, СвойстваЗадания); - - Для Каждого ЗависимыйСписок Из СвойстваЗадания.ЗависимыеСписки Цикл - ОтборЗадания.ИдентификаторСписка = ЗависимыйСписок; - ЗависимыеЗадания = Задания.НайтиСтроки(ОтборЗадания); - Если ЗависимыеЗадания.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - УстановитьУровеньЗависимостиПоВедущим(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); - ОбновитьУровеньЗависимости(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ЗаполнитьОбщиеПараметрыОбновления(Контекст) - - Задания = Контекст.Задания; - Задания.Сортировать( - "ЕстьТочечноеЗадание Убыв, - |ЕстьНачальноеОбновлениеТочечногоЗадания Убыв, - |ДатаПоследнегоЗапускаТочечногоЗадания Возр, - |ДатаДобавленияТочечногоЗадания Убыв, - |ЕстьНачальноеОбновление Убыв, - |ДатаПоследнегоЗапускаОбщегоЗадания Возр, - |ЕстьДатаПоследнегоОбновленногоЭлемента Возр, - |ДатаПоследнегоОбновленногоЭлемента Убыв, - |ДатаДобавленияОбщегоЗадания Убыв"); - - ЗаданияДляУдаления = Задания.НайтиСтроки(Новый Структура("Удалить", Истина)); - Для Каждого Задание Из ЗаданияДляУдаления Цикл - Если Не Задание.Удалить Или Задание.ЗанятыеПотоки.Количество() > 0 Тогда - Продолжить; - КонецЕсли; - СвойстваЗадания = Новый Структура("ИдентификаторСписка, - |ДляВнешнихПользователей, ЭтоОбновлениеПрав, ЗависимыеСписки"); - ЗаполнитьЗначенияСвойств(СвойстваЗадания, Задание); - Задания.Удалить(Задание); - ОбновитьУровеньЗависимости(СвойстваЗадания, Задания, Контекст.ВедущиеСпискиПоЗависимым); - КонецЦикла; - ЗаданияДляОбновленияУровня = Задания.НайтиСтроки(Новый Структура("ОбновитьУровеньЗависимости", Истина)); - Для Каждого Задание Из ЗаданияДляОбновленияУровня Цикл - УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, Контекст.ВедущиеСпискиПоЗависимым); - ОбновитьУровеньЗависимости(Задание, Задания, Контекст.ВедущиеСпискиПоЗависимым); - Задание.ОбновитьУровеньЗависимости = Ложь; - КонецЦикла; - - ОтборУровней = Новый Структура("Удалить, ЭтоОбработкаУстаревшихЭлементов", Ложь, Ложь); - Уровни = Задания.Скопировать(ОтборУровней, "УровеньЗависимости"); - Уровни.Свернуть("УровеньЗависимости"); - Уровни.Сортировать("УровеньЗависимости"); - НаименьшийУровеньЗависимости = ?(Уровни.Количество() > 0, Уровни[0].УровеньЗависимости, 0); - ЭтоОбработкаУстаревшихЭлементов = Уровни.Количество() = 0; - ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания = '00010101'; - Если Уровни.Количество() > 1 Или Не ЭтоОбработкаУстаревшихЭлементов Тогда - Для Каждого Задание Из Задания Цикл - Если Задание.Удалить - Или Задание.ЕстьТочечноеЗадание Тогда - Продолжить; - КонецЕсли; - Если Задание.УровеньЗависимости > НаименьшийУровеньЗависимости - И ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания < Задание.ДатаПоследнегоЗапускаОбщегоЗадания Тогда - ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания = Задание.ДатаПоследнегоЗапускаОбщегоЗадания; - КонецЕсли; - КонецЦикла; - КонецЕсли; - ЗапускаемоеЗависимоеОбщееЗадание = - ?(ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания > ТекущаяДатаСеанса() - 10, Null, Неопределено); - - ОбщиеПараметрыОбновления = Контекст.ОбщиеПараметрыОбновления; - ОбщиеПараметрыОбновления.ЭтоОбработкаУстаревшихЭлементов = ЭтоОбработкаУстаревшихЭлементов; - ОбщиеПараметрыОбновления.НачальноеОбновление = Ложь; - ПоследняяДата = '00010101'; - ЗаданиеСправочникаНаборыГруппДоступа = Неопределено; - ГраницаОжиданияДляЗависимыхЗаданий = ТекущаяДатаСеанса() - 3; - МаксимальнаяДатаПриПродолжении = МаксимальнаяДатаПриПродолжении(); - ЕстьСписокБезПериода = Ложь; - - Для Каждого Задание Из Задания Цикл - Если Задание.Удалить Тогда - Продолжить; - КонецЕсли; - Если ЭтоОбновлениеСоставаНаборовГруппДоступа(Задание, Контекст) Тогда - ЗаданиеСправочникаНаборыГруппДоступа = Задание; - КонецЕсли; - Если Задание.БылаОшибка Тогда - Задание.Пропустить = Истина; - Продолжить; - КонецЕсли; - Задание.Пропустить = Ложь; - - Если Задание.ЕстьНачальноеОбновление Тогда - ОбщиеПараметрыОбновления.НачальноеОбновление = Истина; - - ИначеЕсли Задание.ЭтоОбработкаУстаревшихЭлементов Тогда - Задание.Пропустить = Не ЭтоОбработкаУстаревшихЭлементов - И ЭтоДлительноеЗаданиеПолученияПорций(Задание); - Продолжить; - - ИначеЕсли Не Задание.ЕстьПерезапуск Тогда - - Если Задание.УровеньЗависимости > НаименьшийУровеньЗависимости Тогда - Если Задание.ЕстьТочечноеЗадание Тогда - Если Задание.ДатаПоследнегоЗапускаТочечногоЗадания > ГраницаОжиданияДляЗависимыхЗаданий Тогда - Задание.Пропустить = Истина; - Продолжить; - КонецЕсли; - ИначеЕсли ЗапускаемоеЗависимоеОбщееЗадание <> Неопределено Тогда - Задание.Пропустить = Истина; - Продолжить; - Иначе - ЗапускаемоеЗависимоеОбщееЗадание = Задание; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если Задание.ЭтоОбновлениеПрав Тогда - Продолжить; - КонецЕсли; - Если Задание.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДатаПриПродолжении Тогда - ЕстьСписокБезПериода = Истина; - ИначеЕсли Задание.ДатаПоследнегоОбновленногоЭлемента > ПоследняяДата Тогда - ПоследняяДата = Задание.ДатаПоследнегоОбновленногоЭлемента; - КонецЕсли; - КонецЦикла; - - Если ОбщиеПараметрыОбновления.НачальноеОбновление Тогда - // Начало обновления. - ОбщиеПараметрыОбновления.ДатаНачала = НачалоДня(ТекущаяДатаСеанса()) - 7 * (60 * 60 * 24); // 7 Дней. - Иначе - // Продолжение обновления. - МаксимальныйПериод = МаксимальныйПериодПолученияПорцийЗапросом(); - - Если МаксимальныйПериод = "Неделя" Тогда - ДатаНачала = НачалоНедели(ПоследняяДата); - - ИначеЕсли МаксимальныйПериод = "Месяц" Тогда - ДатаНачала = НачалоМесяца(ПоследняяДата); - Иначе - ЭтотГод = Год(ТекущаяДатаСеанса()) - Год(ПоследняяДата) = 0; - СмещениеМесяца = Месяц(ТекущаяДатаСеанса()) - Месяц(ПоследняяДата); - - Если ЭтотГод И СмещениеМесяца = 0 Тогда - ДатаНачала = НачалоМесяца(ПоследняяДата); - - ИначеЕсли ЭтотГод И СмещениеМесяца < 3 Или МаксимальныйПериод = "Квартал" Тогда - ДатаНачала = НачалоКвартала(ПоследняяДата); - Иначе - ДатаНачала = НачалоГода(ПоследняяДата); - КонецЕсли; - КонецЕсли; - - ОбщиеПараметрыОбновления.ДатаНачала = ДатаНачала; - КонецЕсли; - ОбщиеПараметрыОбновления.ДатаОкончания = ПоследняяДата; - - ЗаданияДляЗапуска = Новый Массив; - Контекст.ЗаданияДляЗапуска = ЗаданияДляЗапуска; - Контекст.ЕстьОтложенныеЗадания = Ложь; - ЗаданийДляЗапускаСУчетомПорций = 0; - СпискиСОбработкойНеТолькоУстаревшихЭлементов = Новый Соответствие; - - Для Каждого Задание Из Задания Цикл - Задание.Запускать = Ложь; - Задание.РазрешенаОбработкаУстаревшихЭлементов = Ложь; - - Если Задание.Удалить Или Задание.Пропустить Тогда - Продолжить; - - ИначеЕсли Задание.ЕстьПерезапуск - Или Задание.ЕстьНачальноеОбновление - Или Задание.ЕстьТочечноеЗадание Тогда - - Задание.Запускать = Истина; - - ИначеЕсли Задание.ЭтоОбработкаУстаревшихЭлементов Тогда - Задание.Запускать = ЭтоОбработкаУстаревшихЭлементов; - Задание.РазрешенаОбработкаУстаревшихЭлементов = Истина; - - ИначеЕсли Задание = ЗаданиеСправочникаНаборыГруппДоступа - Или Задание.ЭтоОбновлениеПрав - Или Задание.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДатаПриПродолжении Тогда // Список без периода. - - Задание.Запускать = Истина; - Иначе - Запускать = Не ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, - Задание.ДатаПоследнегоОбновленногоЭлемента); - Задание.Пропустить = Не Запускать; // Нет смысла запускать, так как в исполняющем потоке будет возврат. - Задание.Запускать = Запускать И Не ЕстьСписокБезПериода; - КонецЕсли; - - Если Задание.Запускать Тогда - ЗаданияДляЗапуска.Добавить(Задание); - ЗаданийДляЗапускаСУчетомПорций = ЗаданийДляЗапускаСУчетомПорций + ?(Не Задание.ЕстьПерезапуск - И ЗначениеЗаполнено(Задание.НаборПорций), Задание.НаборПорций.Количество(), 1); - ИначеЕсли Не Задание.Пропустить Тогда - Контекст.ЕстьОтложенныеЗадания = Истина; - КонецЕсли; - Если Не Задание.РазрешенаОбработкаУстаревшихЭлементов Тогда - СпискиСОбработкойНеТолькоУстаревшихЭлементов.Вставить(Задание.ИдентификаторСписка, Истина); - КонецЕсли; - КонецЦикла; - - Если ЗаданийДляЗапускаСУчетомПорций >= Контекст.КоличествоПотоков - Или Не ЗагружатьСвободныеПотокиСледующимиЗаданиямиПриДлительныхЗапросах() Тогда - Контекст.ЕстьОтложенныеЗадания = Ложь; - КонецЕсли; - - Если Не Контекст.ЕстьЗапущенноеЗадание - И Контекст.ЕстьОтложенныеЗадания - И Контекст.ЗанятыеПотоки.Количество() < Контекст.КоличествоПотоков Тогда - - Контекст.ЕстьОтложенныеЗадания = Ложь; - КоличествоСвободныхПотоков = Контекст.КоличествоПотоков - Контекст.ЗанятыеПотоки.Количество(); - КоличествоДополнительныхЗаданий = 0; - - Для ДобавитьОбработкуУстаревшихЭлементов = 0 По 1 Цикл - Для Каждого Задание Из Задания Цикл - Если Задание.Удалить - Или Задание.Запускать - Или Задание.Пропустить - Или Задание.ЭтоОбработкаУстаревшихЭлементов - И (СпискиСОбработкойНеТолькоУстаревшихЭлементов.Получить(Задание.ИдентификаторСписка) <> Неопределено - Или ДобавитьОбработкуУстаревшихЭлементов = 0 - И Не ЭтоОбработкаУстаревшихЭлементов) Тогда - Продолжить; - КонецЕсли; - Если КоличествоДополнительныхЗаданий >= КоличествоСвободныхПотоков Тогда - Контекст.ЕстьОтложенныеЗадания = Истина; - Прервать; - КонецЕсли; - Задание.Запускать = Истина; - ЗаданияДляЗапуска.Добавить(Задание); - КоличествоДополнительныхЗаданий = КоличествоДополнительныхЗаданий + 1; - КонецЦикла; - Если КоличествоДополнительныхЗаданий >= КоличествоСвободныхПотоков Тогда - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - КоличествоОсновныхЗаданий = ЗаданияДляЗапуска.Количество(); - Если КоличествоОсновныхЗаданий > 0 Тогда - Контекст.КоличествоДополнительныхПорций = Цел(Контекст.КоличествоПотоков / КоличествоОсновныхЗаданий); - Иначе - Контекст.КоличествоДополнительныхПорций = 0; - КонецЕсли; - - КоличествоЗаданий = Задания.Количество(); - Если КоличествоЗаданий = 0 Тогда - ДостаточностьПотоков = 0; - ИначеЕсли Контекст.КоличествоПотоков > КоличествоЗаданий Тогда - ДостаточностьПотоков = 1; - Иначе - ДостаточностьПотоков = Контекст.КоличествоПотоков / КоличествоЗаданий; - КонецЕсли; - НагруженностьОтПотоков = Контекст.КоличествоПотоков * 0.025; - Если НагруженностьОтПотоков > 1 Тогда - НагруженностьОтПотоков = 1; - КонецЕсли; - Контекст.МаксимумМиллисекундОбработкиПорции = - Цел(МинимальноеКоличествоСекундОбработкиПорцииВОтдельномПотоке() * 1000 - * (1 + НагруженностьОтПотоков) * (1 + ДостаточностьПотоков)); - - Если КоличествоОсновныхЗаданий = 0 - И КоличествоЗаданий > 0 - И Не ЗначениеЗаполнено(Контекст.ЗанятыеПотоки) Тогда - - ОбработатьЗаданияСОшибками(Контекст); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ДобавитьЗаданияОбновленияДоступа, ЗапуститьОбновлениеДоступаСписка, -// ВыполнитьОбновлениеДоступаСписка. -// -Функция ПериодОбновленияДоПериодаДанных(ДатаНачала, ДатаПоследнегоОбновленногоЭлемента) - - // ДатаНачала - например, 01.01.2012, а дата окончания 31.12.2012, - // при этом ДатаПоследнегоОбновленногоЭлемента, например, 03.01.2013. - // В таком случае данные для обновления старее, чем период обновления. - Возврат ЗначениеЗаполнено(ДатаПоследнегоОбновленногоЭлемента) - И ДатаНачала > ДатаПоследнегоОбновленногоЭлемента; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ОбработатьЗаданияСОшибками(Контекст) - - Отбор = Новый Структура("БылаОшибка", Истина); - ЗаданияСОшибками = Контекст.Задания.НайтиСтроки(Отбор); - Если Не ЗначениеЗаполнено(ЗаданияСОшибками) Тогда - Возврат; - КонецЕсли; - Контекст.ОбработкаЗавершена = Ложь; - - ТекстыОшибок = Новый Массив; - Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда - ТекстыОшибок.Добавить(Контекст.ТекстОшибкиЗавершения); - КонецЕсли; - - Для Каждого Задание Из ЗаданияСОшибками Цикл - Контекст.ОбработкаЗавершена = Ложь; - ТекстыОшибок.Добавить(Задание.ТекстОшибки); - КонецЦикла; - Контекст.ТекстОшибкиЗавершения = СтрСоединить(ТекстыОшибок, Символы.ПС + Символы.ПС); - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст) - - Если Не Контекст.ОбработкаЗавершена - И ПараметрыСеанса.ПараметрыОграниченияДоступа.ДатаСоздания > ТекущаяДатаСеанса() - 5 * 60 Тогда - - Возврат; - КонецЕсли; - - Попытка - ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст); - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - Исключение - Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда - Контекст.ТребуетсяПерезапускСеанса = Истина; - Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда - Возврат; - КонецЕсли; - КонецЕсли; - ВызватьИсключение; - КонецПопытки; - - ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст; - - Если ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст.ДляПользователей) - И ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст.ДляВнешнихПользователей) Тогда - - Возврат; - КонецЕсли; - - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); - ОбщийКонтекст.Вставить("СпискиСУстаревшимиВариантамиДоступа", Новый Массив); - - Попытка - ДействующиеПараметрыОграниченияДоступа(Неопределено, ОбщийКонтекст, Истина); - Исключение - Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда - Контекст.ТребуетсяПерезапускСеанса = Истина; - Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда - Возврат; - КонецЕсли; - КонецЕсли; - ВызватьИсключение; - КонецПопытки; - - Если ЗначениеЗаполнено(ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа) Тогда - Контекст.ОбработкаЗавершена = Ложь; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ЗавершитьОбновлениеДоступа(Контекст) - - Если Не Контекст.ОбновлениеОтменено И Не Контекст.ТребуетсяПерезапускСеанса Тогда - Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда - ГраницаОжидания = ТекущаяДатаСеанса() + 3; - Иначе - ГраницаОжидания = ТекущаяДатаСеанса() + 15; - КонецЕсли; - Пока Контекст.ЗанятыеПотоки.Количество() > 0 Цикл - // @skip-check query-in-loop - Порционная обработка данных - ПодождатьОсвобожденияПотока(Контекст); - // @skip-check query-in-loop - Порционная обработка данных - ОбработатьВыполненныеЗадания(Контекст); - Если ТекущаяДатаСеанса() > ГраницаОжидания Тогда - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - ЗавершитьПотокиОбновленияДоступа(); - ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(); - - Попытка - Если Контекст.ОбработкаЗавершена Тогда - Контекст.Вставить("ОшибкаОжиданияБлокировкиДанных", Ложь); - Попытка - ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий(Контекст); - Исключение - Если Не Контекст.ОшибкаОжиданияБлокировкиДанных Тогда - ВызватьИсключение; - КонецЕсли; - КонецПопытки; - Если Не Константы.ПервоеОбновлениеДоступаЗавершилось.Получить() Тогда - Константы.ПервоеОбновлениеДоступаЗавершилось.Установить(Истина); - КонецЕсли; - КонецЕсли; - Исключение - ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст); - ВызватьИсключение; - КонецПопытки; - - ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст); - -КонецПроцедуры - -// Для процедуры ОбновитьСоставИспользуемыхВерсийПараметровШаблонов. -Функция ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст) - - ИспользуетсяНесколькоВариантов = Ложь; - - Для Каждого КлючИЗначение Из ДополнительныйКонтекст.ОсновныеВариантыДоступа Цикл - Если КлючИЗначение.Значение.Количество() > 1 Тогда - ИспользуетсяНесколькоВариантов = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Возврат Не ИспользуетсяНесколькоВариантов; - -КонецФункции - -// Для процедуры ЗавершитьОбновлениеДоступа. -Процедура ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий(Контекст) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("НедоступныеСпискиДляОбновленияКлючейДоступаКДанным", Новый Массив); - Запрос.УстановитьПараметр("НедоступныеСпискиДляОбновленияКлючейДоступаПользователей", Новый Массив); - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ОбновлениеКлючейДоступаКДанным.Список КАК Список - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным - |ГДЕ - | НЕ ОбновлениеКлючейДоступаКДанным.Список В (&НедоступныеСпискиДляОбновленияКлючейДоступаКДанным) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ОбновлениеКлючейДоступаПользователей.Список КАК Список - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей - |ГДЕ - | НЕ ОбновлениеКлючейДоступаПользователей.Список В (&НедоступныеСпискиДляОбновленияКлючейДоступаПользователей)"; - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - Если Не РезультатыЗапроса[0].Пустой() Тогда - УстановитьНедоступныеСписки(РезультатыЗапроса[0], - Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным); - КонецЕсли; - - Если Не РезультатыЗапроса[1].Пустой() Тогда - УстановитьНедоступныеСписки(РезультатыЗапроса[1], - Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным); - КонецЕсли; - - Если Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным.Количество() > 0 - Или Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаПользователей.Количество() > 0 Тогда - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - КонецЕсли; - - Если РезультатыЗапроса[0].Пустой() - И РезультатыЗапроса[1].Пустой() Тогда - - Блокировка = Новый БлокировкаДанных; - Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаКДанным"); - Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаПользователей"); - НачатьТранзакцию(); - Попытка - Контекст.ОшибкаОжиданияБлокировкиДанных = Истина; - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); - РегламентныеЗаданияСервер.ЗаблокироватьРегламентноеЗадание(Новый УникальныйИдентификатор); - КонецЕсли; - Блокировка.Заблокировать(); - Контекст.ОшибкаОжиданияБлокировкиДанных = Ложь; - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - Если РезультатыЗапроса[0].Пустой() - И РезультатыЗапроса[1].Пустой() Тогда - - Если ЗначениеЗаполнено(Контекст.ДатаПолногоЗавершения) Тогда - ГраницаОтключения = ТекущаяДатаСеанса() - - КоличествоСекундПередОтключениемРегламентногоЗаданияПослеПолногоЗавершенияОбновления(); - Если Контекст.ДатаПолногоЗавершения < ГраницаОтключения Тогда - УстановитьОбновлениеДоступа(Ложь); - КонецЕсли; - Иначе - Контекст.ДатаПолногоЗавершения = ТекущаяДатаСеанса(); - КонецЕсли; - Иначе - Контекст.ОбработкаЗавершена = Ложь; - Контекст.ДатаПолногоЗавершения = '00010101'; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - Контекст.ОбработкаЗавершена = Ложь; - ВызватьИсключение; - КонецПопытки; - Иначе - Контекст.ОбработкаЗавершена = Ложь; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий. -// -// Параметры: -// РезультатЗапроса - РезультатЗапроса -// НедоступныеСписки - Массив -// -Процедура УстановитьНедоступныеСписки(РезультатЗапроса, НедоступныеСписки) - - ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( - РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Список"), Ложь); - - Для Каждого КлючИЗначение Из ОбъектыМетаданныхПоИдентификаторам Цикл - Если КлючИЗначение.Значение = Неопределено Тогда - НедоступныеСписки.Добавить(КлючИЗначение.Ключ); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -Функция ЗапуститьОбновлениеДоступаСписка(Задание, Контекст) - - Показатели = Контекст.Показатели; - Если Показатели <> Неопределено Тогда - Показатели.НачалоВыдачиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - - ОбработатьВыполненныеЗадания(Контекст, Задание.ЗанятыеПотоки); - - Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда - Возврат Ложь; - КонецЕсли; - - Если Задание.ЗанятыеПотоки.Количество() > 0 И Контекст.ПервыйПроход Тогда - Возврат Истина; // Уже запущено. - КонецЕсли; - - Если ОбщееЗаданиеВыполняется(Задание) - И Не ЗапускатьОбновлениеПолученныхПорцийПриПолученииНовыхПорций() Тогда - Возврат Истина; - КонецЕсли; - - ОбщиеПараметрыОбновления = ОписаниеОбщихПараметровОбновления(Контекст); - ЗаполнитьЗначенияСвойств(ОбщиеПараметрыОбновления, Контекст.ОбщиеПараметрыОбновления); - ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав = Задание.ЭтоОбновлениеПрав; - ОбщиеПараметрыОбновления.ИдентификаторСписка = Задание.ИдентификаторСписка; - ОбщиеПараметрыОбновления.ДляВнешнихПользователей = Задание.ДляВнешнихПользователей; - ОбщиеПараметрыОбновления.РазрешенаОбработкаУстаревшихЭлементов = Задание.РазрешенаОбработкаУстаревшихЭлементов; - - НаборПорций = Задание.НаборПорций; - ПоследнийИндекс = НаборПорций.Количество() - 1; - - ИндексСледующейПорцииДляОбработки = Задание.ИндексСледующейПорцииДляОбработки; - ПорцияДляОбработки = Неопределено; - Для Индекс = ИндексСледующейПорцииДляОбработки По ПоследнийИндекс Цикл - ПорцияЭлементов = НаборПорций.Получить(Индекс); - Если Не ПорцияЭлементов.Обработана И Не ПорцияЭлементов.Обрабатывается Тогда - ПорцияДляОбработки = ПорцияЭлементов; - Задание.ИндексСледующейПорцииДляОбработки = Индекс; - ИндексСледующейПорцииДляОбработки = Индекс + 1; - Прервать; - КонецЕсли; - КонецЦикла; - - Если ПорцияДляОбработки = Неопределено Тогда - Задание.ИндексСледующейПорцииДляОбработки = ПоследнийИндекс + 1; - ПредыдущаяПорция = Неопределено; - - ИначеЕсли Индекс > 0 Тогда - ПредыдущаяПорция = НаборПорций.Получить(Индекс - 1); - Иначе - ПредыдущаяПорция = Неопределено; - КонецЕсли; - - Если Не Задание.ЕстьТочечноеЗадание И ПорцияДляОбработки <> Неопределено Тогда - Если ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, - ?(ПредыдущаяПорция = Неопределено, Задание.ДатаПоследнегоОбновленногоЭлемента, - ПредыдущаяПорция.ДатаПоследнегоЭлементаПорции)) Тогда - Возврат Истина; - КонецЕсли; - ОбщиеПараметрыОбновления.Вставить("ПорцияИзНабора", ПорцияДляОбработки); - ПорцияДляОбработки.Обрабатывается = Истина; - Задание.ИндексСледующейПорцииДляОбработки = ИндексСледующейПорцииДляОбработки; - ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки = Контекст.МаксимумМиллисекундОбработкиПорции; - Иначе - ПоследняяПорция = ?(ПоследнийИндекс > -1, НаборПорций[ПоследнийИндекс], Неопределено); - - Если ПоследняяПорция <> Неопределено - И (ПоследняяПорция.ПоследнийЭлементПорции.ВидКлючаДанных - <> ПоследняяПорция.НовыйПоследнийЭлементПорции.ВидКлючаДанных - Или ПоследняяПорция.НовыйПоследнийЭлементПорции.КлючДанных = Null - Или Не ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав - И ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, - ПоследняяПорция.ДатаПоследнегоЭлементаПорции)) Тогда - - ПолучитьПорции = 0; - Иначе - КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки; - ПолучитьПорции = (Контекст.КоличествоДополнительныхПорций + 2) * 2; - Если Задание.ЕстьТочечноеЗадание Тогда - ПолучитьПорции = ПолучитьПорции - КоличествоПорцийДляОбработки; - Если ПолучитьПорции - КоличествоПорцийДляОбработки < Цел(ПолучитьПорции / 3) Тогда - ПолучитьПорции = Цел(ПолучитьПорции / 3); - Иначе - ПолучитьПорции = ПолучитьПорции - КоличествоПорцийДляОбработки; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если Не Задание.ЕстьТочечноеЗадание И ПолучитьПорции = 0 Тогда - Возврат Истина; - КонецЕсли; - - ОбщиеПараметрыОбновления.Вставить("ПолучитьПорции", ПолучитьПорции); - Если ПоследняяПорция <> Неопределено Тогда - ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийЭлементПорции", - ПоследняяПорция.НовыйПоследнийЭлементПорции); - КонецЕсли; - Если ПолучитьПорции > 0 Тогда - ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки = МаксимумМиллисекундПолученияПорций(Контекст); - КонецЕсли; - КонецЕсли; - - Если Не ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") И ОбщееЗаданиеВыполняется(Задание) Тогда - Возврат Истина; - КонецЕсли; - - Если Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных - И Не Задание.ЭтоОбновлениеПрав - И ОбщиеПараметрыОбновления.Свойство("ПолучитьПорции") - И ОбщиеПараметрыОбновления.ПолучитьПорции > 0 Тогда - - Если Задание.ЕстьТочечноеЗадание Тогда - ОбщиеПараметрыОбновления.ПолучитьПорции = 0; - ИначеЕсли ЭтоДлительноеЗаданиеПолученияПорций(Задание) Тогда - Возврат Ложь; - КонецЕсли; - КонецЕсли; - - Если Задание.ЕстьТочечноеЗадание Тогда - Задание.ЕстьТочечноеЗадание = Ложь; - ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание); - Задание.ДатаПоследнегоЗапускаТочечногоЗадания = ТекущаяДатаСеанса(); - Иначе - Задание.ДатаПоследнегоЗапускаОбщегоЗадания = ТекущаяДатаСеанса(); - КонецЕсли; - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст); - ОбработатьРезультатЗадания(Контекст, ОбщиеПараметрыОбновления, Задание); - Иначе - Для Каждого СвободныйПоток Из Контекст.СвободныеПотоки Цикл - Прервать; - КонецЦикла; - Если СвободныйПоток = Неопределено Тогда - Если Контекст.ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Тогда - Возврат Истина; - КонецЕсли; - СвободныйПоток = НовыйПоток(); - Параметры = Новый Массив; - Параметры.Добавить(Контекст.ОписаниеОсновногоСеанса); - СвободныйПоток.ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяМетодаПотокаОбновленияДоступа(), Параметры,, - НСтр("ru = 'Управление доступом: Поток обновления доступа на уровне записей'", - ОбщегоНазначения.КодОсновногоЯзыка())); - СвободныйПоток.ИдентификаторПотока = СвободныйПоток.ФоновоеЗадание.УникальныйИдентификатор; - Контекст.СвободныеПотоки.Добавить(СвободныйПоток); - КонецЕсли; - - ИдентификаторПотока = СвободныйПоток.ИдентификаторПотока; - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); - НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока); - ЗаписьНабора = НаборЗаписей.Добавить(); - ЗаписьНабора.ИдентификаторПотока = ИдентификаторПотока; - ЗаписьНабора.ЭтоЗапуск = Истина; - ЗаписьНабора.Параметры = Новый ХранилищеЗначения(ОбщиеПараметрыОбновления); - ЗаписьНабора.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); - - НаборЗаписей.Записать(); - - СвободныйПоток.Задание = Задание; - СвободныйПоток.МоментЗапускаЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - СвободныйПоток.ПорцияИзНабора = ?(ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора"), - ОбщиеПараметрыОбновления.ПорцияИзНабора, Неопределено); - СвободныйПоток.ПолучитьПорции = ?(ОбщиеПараметрыОбновления.Свойство("ПолучитьПорции"), - ОбщиеПараметрыОбновления.ПолучитьПорции, 0); - Задание.ЗанятыеПотоки.Вставить(ИдентификаторПотока, СвободныйПоток); - Контекст.ЗанятыеПотоки.Вставить(ИдентификаторПотока, СвободныйПоток); - Контекст.СвободныеПотоки.Удалить(0); - Если Показатели <> Неопределено Тогда - СнятьПоказателиВыдачиЗаданий(Показатели); - КонецЕсли; - Контекст.ЕстьЗапущенноеЗадание = Истина; - КонецЕсли; - - Возврат Истина; - -КонецФункции - -// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ОбработатьРезультатЗадания. -Функция ОбщееЗаданиеВыполняется(Задание) - - Для Каждого ОписаниеЗанятогоПотока Из Задание.ЗанятыеПотоки Цикл - Если ОписаниеЗанятогоПотока.Значение.ПорцияИзНабора = Неопределено Тогда - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ОтменитьФоновыеЗаданияПотоковОбновленияДоступа. -Функция ИмяМетодаПотокаОбновленияДоступа() - - Возврат "УправлениеДоступомСлужебный.ВыполнитьОбновлениеДоступаСпискаВФоне"; - -КонецФункции - -// Для процедур УстановитьОбновлениеДоступа, ЗапуститьОбновлениеДоступаНаУровнеЗаписей, -// ОтменитьОбновлениеДоступаНаУровнеЗаписей и функции ИсполнительОбновленияДоступа. -// -Функция ИмяМетодаЗаданияОбновленияДоступа() - - Возврат Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.ИмяМетода; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа, ЗавершитьОбновлениеДоступа. -Процедура ПодождатьОсвобожденияПотока(Контекст, ЖдатьЗавершенияЗадания = Ложь) - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - Возврат; - КонецЕсли; - - Показатели = Контекст.Показатели; - Если Показатели <> Неопределено Тогда - НачалоОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - - Выполнять = Истина; - - Если ЖдатьЗавершенияЗадания Тогда - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИдентификаторыПотоков", ИдентификаторыПотоков(Контекст.ЗанятыеПотоки)); - Запрос.УстановитьПараметр("КоличествоПотоков", Контекст.КоличествоПотоков); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания - |ГДЕ - | ТекущиеЗадания.ИдентификаторПотока В(&ИдентификаторыПотоков) - | - |СГРУППИРОВАТЬ ПО - | ТекущиеЗадания.ИдентификаторПотока - | - |ИМЕЮЩИЕ - | (МИНИМУМ(ТекущиеЗадания.ЭтоЗапуск) = ЛОЖЬ - | ИЛИ КОЛИЧЕСТВО(ТекущиеЗадания.ЭтоЗапуск) < &КоличествоПотоков)"; - Если Не Запрос.Выполнить().Пустой() Тогда - Выполнять = Ложь; - КонецЕсли; - ГраницаОжидания = ТекущаяДатаСеанса() + 5; - КонецЕсли; - - Пока Выполнять Цикл - Если Контекст.ТекущееФоновоеЗадание <> Неопределено Тогда - ФоновоеЗадание = Контекст.ТекущееФоновоеЗадание; - Иначе - ФоновоеЗадание = Неопределено; - Для Каждого ОписаниеПотока Из Контекст.ЗанятыеПотоки Цикл - Поток = ОписаниеПотока.Значение; - ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); - Если Поток.ФоновоеЗадание <> Неопределено - И Поток.ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда - - ФоновоеЗадание = Поток.ФоновоеЗадание; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если ФоновоеЗадание = Неопределено Тогда - Прервать; - КонецЕсли; - ФоновоеЗадание.ОжидатьЗавершенияВыполнения(0.025); - Если Не ЖдатьЗавершенияЗадания - Или ТекущаяДатаСеанса() > ГраницаОжидания - Или Контекст.ЗанятыеПотоки.Количество() = 0 Тогда - Прервать; - КонецЕсли; - // @skip-check query-in-loop - Порционная обработка данных - Если Не Запрос.Выполнить().Пустой() Тогда - Прервать; - КонецЕсли; - КонецЦикла; - - Если Показатели <> Неопределено Тогда - Показатели.ВремяОжиданийСвободногоПотока = Показатели.ВремяОжиданийСвободногоПотока - + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОжидания); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ПодождатьОсвобожденияПотока, ОбработатьВыполненныеЗадания. -Функция ИдентификаторыПотоков(ЗанятыеПотоки) - - ИдентификаторыПотоков = Новый Массив; - - Для Каждого ОписаниеПотока Из ЗанятыеПотоки Цикл - ИдентификаторыПотоков.Добавить(ОписаниеПотока.Ключ); - КонецЦикла; - - Возврат ИдентификаторыПотоков; - -КонецФункции - -// Для процедур ПодождатьОсвобожденияПотока, УдалитьОстановленныеПотоки. -Процедура ОбновитьСвойстваФоновогоЗадания(Поток, Контекст) - - ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Поток.ИдентификаторПотока); - - Если ФоновоеЗадание = Неопределено Тогда - Если РегистрироватьПоказателиОбновленияДоступа() Тогда - ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( - НСтр("ru = 'Не удалось найти запущенное фоновое задание.'"), Поток.Задание, Истина), Контекст); - КонецЕсли; - Контекст.ОбработкаЗавершена = Ложь; - Возврат; - КонецЕсли; - Поток.ФоновоеЗадание = ФоновоеЗадание; - -КонецПроцедуры - -// Для процедуры ОбработатьВыполненныеЗадания. -Процедура ОтменитьФоновоеЗаданиеПотока(Поток, Контекст) - - ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); - ФоновоеЗадание = Поток.ФоновоеЗадание; - - Если ФоновоеЗадание = Неопределено - Или ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Активно Тогда - - Возврат; - КонецЕсли; - - Попытка - ФоновоеЗадание.Отменить(); - Исключение - ПредставлениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось отменить фоновое задание потока по причине: - |%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); - ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( - ПредставлениеОшибки, Поток.Задание, Истина), Контекст); - КонецПопытки; - - Контекст.ОбработкаЗавершена = Ложь; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа, ОбработатьРезультатЗадания. -Процедура ОбработатьВыполненныеЗадания(Контекст, ЗанятыеПотоки = Неопределено) - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - Если ОбновлениеДоступаОтменено() Тогда - Контекст.ОбновлениеОтменено = Истина; - КонецЕсли; - Возврат; - КонецЕсли; - - Показатели = Контекст.Показатели; - Если Показатели <> Неопределено Тогда - НачалоОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - - Если ЗанятыеПотоки = Неопределено Тогда - ЗанятыеПотоки = Контекст.ЗанятыеПотоки; - КонецЕсли; - ОписаниеПотоков = Новый Соответствие(Новый ФиксированноеСоответствие(ЗанятыеПотоки)); - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИдентификаторОтмены", ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей()); - Запрос.УстановитьПараметр("ИдентификаторыПотоков", ИдентификаторыПотоков(ОписаниеПотоков)); - Запрос.УстановитьПараметр("ГраницаОжиданияВыполнения", ТекущаяДатаСеанса() - - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()); - - Запрос.Текст = - "ВЫБРАТЬ - | ТекущиеЗадания.ИдентификаторПотока КАК ИдентификаторПотока, - | ТекущиеЗадания.Результат КАК Результат, - | ТекущиеЗадания.ЭтоЗапуск - | И &ГраницаОжиданияВыполнения > ТекущиеЗадания.ДатаИзмененияЗаписиРегистра - | ИЛИ ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторОтмены КАК ПревышеноВремяВыполнения, - | ТекущиеЗадания.ДатаИзмененияЗаписиРегистра КАК ДатаИзмененияЗаписиРегистра - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания - |ГДЕ - | (НЕ ТекущиеЗадания.ЭтоЗапуск - | И ТекущиеЗадания.ИдентификаторПотока В (&ИдентификаторыПотоков) - | ИЛИ ТекущиеЗадания.ЭтоЗапуск - | И &ГраницаОжиданияВыполнения > ТекущиеЗадания.ДатаИзмененияЗаписиРегистра - | ИЛИ ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторОтмены)"; - - ОписаниеРезультатов = Новый Соответствие; - Выборка = Запрос.Выполнить().Выбрать(); - - Пока Выборка.Следующий() Цикл - Если Выборка.ПревышеноВремяВыполнения = Истина Тогда - Если Выборка.ИдентификаторПотока = ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей() Тогда - Контекст.ОбновлениеОтменено = Истина; - Возврат; - КонецЕсли; - Поток = Контекст.ЗанятыеПотоки.Получить(Выборка.ИдентификаторПотока); - Если Поток = Неопределено Тогда - Для Каждого СвободныйПоток Из Контекст.СвободныеПотоки Цикл - Если СвободныйПоток.ИдентификаторПотока = Выборка.ИдентификаторПотока Тогда - Поток = СвободныйПоток; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если Поток = Неопределено Тогда - Продолжить; - КонецЕсли; - Если Поток.Задание.ИдентификаторСписка = Контекст.ИдентификаторСправочникаНаборыГруппДоступа - И Выборка.ДатаИзмененияЗаписиРегистра > (Запрос.Параметры.ГраницаОжиданияВыполнения - - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()) Тогда - Продолжить; - КонецЕсли; - - ПредставлениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Превышено время выполнения задания в потоке (%1 сек). - |Рекомендуется реиндексация и обновление статистик таблиц базы данных. - |В некоторых случаях, достаточно запустить обновление доступа еще раз. - |См. также режим ""Медленный диск"" в панели настройки количества потоков.'"), - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()); - - Поток.Задание.БылаОшибка = Истина; - Поток.Задание.ТекстОшибки = ТекстОшибкиОбновленияСКонтекстом(ПредставлениеОшибки, Поток.Задание); - - ОтменитьФоновоеЗаданиеПотока(Поток, Контекст); - УдалитьПоток(Поток, Контекст); - ОписаниеПотоков.Удалить(Поток.ИдентификаторПотока); - - Если Показатели <> Неопределено Тогда - Показатели.КоличествоПотоковСПревышениемВремениВыполнения = - Показатели.КоличествоПотоковСПревышениемВремениВыполнения + 1; - КонецЕсли; - - ИначеЕсли ТипЗнч(Выборка.Результат) = Тип("ХранилищеЗначения") Тогда - ОписаниеРезультата = Новый Структура; - ОписаниеРезультата.Вставить("ДатаЗавершения", Выборка.ДатаИзмененияЗаписиРегистра); - ОписаниеРезультата.Вставить("Результат", Выборка.Результат.Получить()); - ОписаниеРезультатов.Вставить(Выборка.ИдентификаторПотока, ОписаниеРезультата); - КонецЕсли; - КонецЦикла; - - ЗадержкаЗапроса = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000; - Для Каждого ОписаниеПотока Из ОписаниеПотоков Цикл - Поток = ОписаниеПотока.Значение; - ОписаниеРезультата = ОписаниеРезультатов.Получить(Поток.ИдентификаторПотока); - ОбработатьРезультатВыполненногоЗадания(Поток, ОписаниеРезультата, Контекст, ЗадержкаЗапроса); - КонецЦикла; - - КоличествоПотоков = Контекст.ЗанятыеПотоки.Количество() + Контекст.СвободныеПотоки.Количество(); - Если КоличествоПотоков > Контекст.КоличествоПотоков Тогда - Индекс = Контекст.СвободныеПотоки.Количество() - 1; - Пока Индекс >= 0 Цикл - СвободныйПоток = Контекст.СвободныеПотоки.Получить(Индекс); - УдалитьПоток(СвободныйПоток, Контекст); - Индекс = Индекс - 1; - КоличествоПотоков = КоличествоПотоков - 1; - Если КоличествоПотоков <= Контекст.КоличествоПотоков Тогда - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Ложь; - Если ЗадержкаЗапроса > 0 Тогда - ЭтоОбработкаУстаревшихЭлементов = Контекст.ОбщиеПараметрыОбновления.ЭтоОбработкаУстаревшихЭлементов; - ТекущиеЗанятыеПотоки = Новый Соответствие(Новый ФиксированноеСоответствие(Контекст.ЗанятыеПотоки)); - ТекущийМомент = ТекущаяУниверсальнаяДатаВМиллисекундах(); - ДлительныеПотоки = Новый СписокЗначений; - ЕстьДлительноеЗаданиеПолученияПорций = Ложь; - Для Каждого ОписаниеПотока Из ТекущиеЗанятыеПотоки Цикл - Поток = ОписаниеПотока.Значение; // см. НовыйПоток - Если Поток.ПорцияИзНабора <> Неопределено - Или Поток.Задание.ЭтоОбновлениеПрав - Или Поток.ПолучитьПорции = 0 Тогда - Продолжить; - КонецЕсли; - Если ЭтоДлительноеЗаданиеПолученияПорций(Поток.Задание) Тогда - ЕстьДлительноеЗаданиеПолученияПорций = Истина; - КонецЕсли; - Если ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса / 2 Тогда - Продолжить; - КонецЕсли; - ДлительныеПотоки.Добавить(Поток, Формат(Поток.МоментЗапускаЗадания, "ЧЦ=23; ЧВН=")); - Если ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда - Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Истина; - КонецЕсли; - КонецЦикла; - Если Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных Тогда - ДлительныеПотоки.СортироватьПоПредставлению(); - Поток = ДлительныеПотоки.Получить(0).Значение; // см. НовыйПоток - Граница1 = ТекущаяДатаСеанса() + ЗадержкаЗапроса + 5; - Граница2 = ТекущаяДатаСеанса() + ЗадержкаЗапроса * 10; - Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница1; - ДлительныеПотоки.Удалить(0); - Для Каждого ОписаниеПотока Из ДлительныеПотоки Цикл - Поток = ОписаниеПотока.Значение; // см. НовыйПоток - Если Не ЭтоОбработкаУстаревшихЭлементов И Поток.Задание.ЭтоОбработкаУстаревшихЭлементов Тогда - Граница2 = Граница2 + ЗадержкаЗапроса * 2; - Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница2; - ИначеЕсли ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда - Продолжить; - Иначе - Граница1 = Граница1 + 10; - Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница1; - КонецЕсли; - ОтменитьФоновоеЗаданиеПотока(Поток, Контекст); - УдалитьПоток(Поток, Контекст); - Контекст.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); - КонецЦикла; - КонецЕсли; - Если ЕстьДлительноеЗаданиеПолученияПорций Тогда - Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Истина; - КонецЕсли; - КонецЕсли; - - Если ТекущаяДатаСеанса() > Контекст.ГраницаОбновленияЗаданий Тогда - Контекст.ГраницаОбновленияЗаданий = ТекущаяДатаСеанса() + 2; - УдалитьОстановленныеПотоки(Контекст, Контекст.ЗанятыеПотоки); - УдалитьОстановленныеПотоки(Контекст, Контекст.СвободныеПотоки); - УдалитьНеиспользуемыеСвободныеПотоки(Контекст); - КонецЕсли; - - Если Показатели <> Неопределено Тогда - Показатели.ВремяОбработкиРезультатовЗаданий = Показатели.ВремяОбработкиРезультатовЗаданий - + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОбработки); - КонецЕсли; - -КонецПроцедуры - -// Параметры: -// Задание - СтрокаТаблицыЗначений из см. ТаблицаЗаданийОбновления -// -// Возвращаемое значение: -// Булево -// -Функция ЭтоДлительноеЗаданиеПолученияПорций(Задание) - - Возврат Задание.ДлительноеЗаданиеПолученияПорцийДо > ТекущаяДатаСеанса(); - -КонецФункции - -// Для процедур ОбработатьВыполненныеЗадания, ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора. -Функция ОбновлениеДоступаОтменено() - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИдентификаторПотока", ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей()); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания - |ГДЕ - | ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторПотока"; - - Возврат Не Запрос.Выполнить().Пустой(); - -КонецФункции - -// Для процедуры ОбработатьВыполненныеЗадания. -Процедура ОбработатьРезультатВыполненногоЗадания(Поток, ОписаниеРезультата, Контекст, ЗадержкаЗапроса) - - Если Не Поток.ОтменитьЗадание - И Не Поток.Задание.Удалить Тогда - - Если ОписаниеРезультата = Неопределено Тогда - Возврат; - ИначеЕсли ТипЗнч(ОписаниеРезультата.Результат) <> Тип("Структура") Тогда - Контекст.ОбработкаЗавершена = Ложь; - Иначе - Результат = ОписаниеРезультата.Результат; - Если Результат.Свойство("ПорцияИзНабора") Тогда - Результат.ПорцияИзНабора = Поток.ПорцияИзНабора; - КонецЕсли; - Показатели = Контекст.Показатели; - Если Показатели <> Неопределено Тогда - Показатели.НачалоОбработкиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - Если ЗадержкаЗапроса > 0 - И ЭтоДлительноеЗаданиеПолученияПорций(Поток.Задание) - И Результат.Свойство("НаборПорций") - И ТекущаяУниверсальнаяДатаВМиллисекундах() - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда - Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = '00010101'; - КонецЕсли; - ОбработатьРезультатЗадания(Контекст, Результат, Поток.Задание); - Если Показатели <> Неопределено Тогда - СнятьПоказателиОбработкиРезультатаЗадания(Показатели); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если ОписаниеРезультата = Неопределено Тогда - ДатаЗавершения = Неопределено; - Иначе - ДатаЗавершения = ОписаниеРезультата.ДатаЗавершения; - КонецЕсли; - - ОсвободитьПоток(Поток, Контекст, ДатаЗавершения); - -КонецПроцедуры - -// Для процедур ОбработатьРезультатВыполненногоЗадания, УдалитьПоток. -Процедура ОсвободитьПоток(Поток, Контекст, ДатаЗавершения = Неопределено) - - ПозицияВставки = 0; - Если ДатаЗавершения = Неопределено Тогда - Поток.ДатаОсвобождения = ТекущаяДатаСеанса(); - Иначе - Поток.ДатаОсвобождения = ДатаЗавершения; - Количество = Контекст.СвободныеПотоки.Количество(); - Пока ПозицияВставки < Количество Цикл - ТекущийПоток = Контекст.СвободныеПотоки.Получить(ПозицияВставки); - Если ТекущийПоток.ДатаОсвобождения <= ДатаЗавершения Тогда - Прервать; - КонецЕсли; - ПозицияВставки = ПозицияВставки + 1; - КонецЦикла; - КонецЕсли; - - Контекст.СвободныеПотоки.Вставить(ПозицияВставки, Поток); - Контекст.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); - Поток.Задание.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); - Если Поток.ПорцияИзНабора <> Неопределено Тогда - СнятьПризнакОбрабатываетсяДляПорции(Поток, Поток.Задание); - Поток.ПорцияИзНабора = Неопределено; - КонецЕсли; - Поток.МоментЗапускаЗадания = 0; - Поток.ПолучитьПорции = 0; - Поток.Задание = Неопределено; - Поток.ОтменитьЗадание = Ложь; - -КонецПроцедуры - -// Для процедур ЗапуститьОбновлениеДоступаСписка, ОбработатьРезультатВыполненногоЗадания, ОсвободитьПоток. -Процедура СнятьПризнакОбрабатываетсяДляПорции(ПотокИлиРезультат, Задание) - - ПорцияИзНабора = Неопределено; - - Если Не ПотокИлиРезультат.Свойство("ПорцияИзНабора", ПорцияИзНабора) - Или ПорцияИзНабора = Неопределено - Или Не ПорцияИзНабора.Обрабатывается Тогда - Возврат; - КонецЕсли; - - Если Не ПорцияИзНабора.Обработана Тогда - ИндексПорции = Задание.НаборПорций.Найти(ПорцияИзНабора); - - Если ИндексПорции = Неопределено Тогда - Задание.ИндексСледующейПорцииДляОбработки = 0; - - ИначеЕсли Задание.ИндексСледующейПорцииДляОбработки > ИндексПорции Тогда - Задание.ИндексСледующейПорцииДляОбработки = ИндексПорции; - КонецЕсли; - КонецЕсли; - - ПорцияИзНабора.Обрабатывается = Ложь; - -КонецПроцедуры - -// Для процедуры ОбработатьРезультатВыполненногоЗадания, ЗавершитьОбновлениеДоступа. -Процедура УдалитьПоток(Поток, Контекст) - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); - НаборЗаписей.Отбор.ИдентификаторПотока.Установить(Поток.ИдентификаторПотока); - НаборЗаписей.Записать(); - - Если Контекст.ЗанятыеПотоки.Получить(Поток.ИдентификаторПотока) <> Неопределено Тогда - ОсвободитьПоток(Поток, Контекст); - КонецЕсли; - - Индекс = Контекст.СвободныеПотоки.Найти(Поток); - Если Индекс <> Неопределено Тогда - Контекст.СвободныеПотоки.Удалить(Индекс); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбработатьРезультатВыполненногоЗадания, ЗавершитьОбновлениеДоступа. -Процедура УдалитьОстановленныеПотоки(Контекст, ОписаниеПотоков) - - Если ТипЗнч(ОписаниеПотоков) = Тип("Соответствие") Тогда - ИсходноеОписаниеПотоков = Новый ФиксированноеСоответствие(ОписаниеПотоков); - Иначе - ИсходноеОписаниеПотоков = Новый ФиксированныйМассив(ОписаниеПотоков); - КонецЕсли; - - Для Каждого ОписаниеПотока Из ИсходноеОписаниеПотоков Цикл - Если ТипЗнч(ОписаниеПотока) = Тип("КлючИЗначение") Тогда - Поток = ОписаниеПотока.Значение; - Иначе - Поток = ОписаниеПотока; - КонецЕсли; - ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); - ФоновоеЗадание = Поток.ФоновоеЗадание; - - Если ФоновоеЗадание <> Неопределено - И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда - Продолжить; - КонецЕсли; - Контекст.ОбработкаЗавершена = Ложь; - - УдалитьПоток(Поток, Контекст); - - Если ФоновоеЗадание <> Неопределено - И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда - - ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( - ФоновоеЗадание.ИнформацияОбОшибке, Поток.Задание, Истина), Контекст); - - Если Контекст.Показатели <> Неопределено Тогда - Контекст.Показатели.КоличествоПотоковСНештатнымЗавершением = - Контекст.Показатели.КоличествоПотоковСНештатнымЗавершением + 1; - КонецЕсли; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбработатьВыполненныеЗадания. -Процедура УдалитьНеиспользуемыеСвободныеПотоки(Контекст) - - Количество = Контекст.СвободныеПотоки.Количество(); - Если Количество = 0 Тогда - Возврат; - КонецЕсли; - - СвободныеПотоки = Контекст.СвободныеПотоки; - Индекс = Количество - 1; - ТекущаяДатаСеанса = ТекущаяДатаСеанса(); - - Пока Индекс >= 0 Цикл - Поток = СвободныеПотоки.Получить(Индекс); - Если ТекущаяДатаСеанса > Поток.ДатаОсвобождения + 15 Тогда - УдалитьПоток(Поток, Контекст); - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ДобавитьЗаданияОбновленияДоступа и ОбработатьРезультатЗадания. -Процедура ОтменитьЗадание(Задание) - - Задание.НаборПорций = Новый Массив; - Задание.КоличествоПорцийДляОбработки = 0; - Задание.ИндексСледующейПорцииДляОбработки = 0; - - Для Каждого ОписаниеПотока Из Задание.ЗанятыеПотоки Цикл - ОписаниеПотока.Значение.ОтменитьЗадание = Истина; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ЗапуститьОбновлениеДоступаСписка, ОбработатьРезультатВыполненногоЗадания. -Процедура ОбработатьРезультатЗадания(Контекст, Результат, Задание) - - Если Результат.Свойство("НетЗаданий") Или Результат.Свойство("ПерезапускОбновления") Тогда - Если Результат.Свойство("ПерезапускОбновления") Тогда - Задание.ЕстьПерезапуск = Истина; - Если Результат.Свойство("ПерезапускОбновленияСНачала") Тогда - Задание.ЕстьНачальноеОбновление = Истина; - КонецЕсли; - КонецЕсли; - ОтменитьЗадание(Задание); - Если Результат.Свойство("НетЗаданий") Тогда - СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); - ОбновитьСвойстваЗадания(Задание, Новый Структура("КлючДанных", Null)); - Если Результат.НетЗаданий = "ОбъектМетаданныхОтключен" Тогда - Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Вставить(Задание.ИдентификаторСписка, Истина); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если Результат.Свойство("ТребуетсяПерезапускСеанса") Тогда - Контекст.ТребуетсяПерезапускСеанса = Истина; - Контекст.ОбработкаЗавершена = Ложь; - СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(Результат.ТребуетсяПерезапускСеанса); - СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); - Возврат; - КонецЕсли; - - Если Результат.Свойство("ТекстОшибкиЗавершения") Тогда - Если Не Результат.ОбработкаЗавершена Тогда - Контекст.ОбработкаЗавершена = Ложь; - КонецЕсли; - Если ЗначениеЗаполнено(Результат.ТекстОшибкиЗавершения) Тогда - СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); - ДобавитьТекстОшибкиЗавершения(Контекст.ТекстОшибкиЗавершения, Результат.ТекстОшибкиЗавершения); - Возврат; - КонецЕсли; - КонецЕсли; - - Если Результат.Свойство("НетЗаданий") Тогда - Возврат; - КонецЕсли; - - Если Результат.Свойство("НачальноеОбновлениеЗавершено") Тогда - Задание.ЕстьНачальноеОбновление = Ложь; - Задание.ЕстьПерезапуск = Ложь; - КонецЕсли; - - Если Результат.Свойство("ПорцияИзНабора") Тогда - ИсходнаяПорцияИзНабора = Результат.ПорцияИзНабора; - Если Результат.Свойство("НаборПорций") Тогда - Индекс = Задание.НаборПорций.Найти(ИсходнаяПорцияИзНабора); - Если Задание.ИндексСледующейПорцииДляОбработки > Индекс Тогда - Задание.ИндексСледующейПорцииДляОбработки = Индекс + 1; - КонецЕсли; - Для Каждого НоваяПорцияИзИсходной Из Результат.НаборПорций Цикл - Индекс = Индекс + 1; - Задание.НаборПорций.Вставить(Индекс, НоваяПорцияИзИсходной); - КонецЦикла; - Задание.КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки - + Результат.НаборПорций.Количество(); - ИсходнаяПорцияИзНабора.ПоследнийЭлементПорции = Результат.НовыйПоследнийОбновленныйЭлемент; - ИсходнаяПорцияИзНабора.НовыйПоследнийЭлементПорции = Результат.НовыйПоследнийОбновленныйЭлемент; - КонецЕсли; - ИсходнаяПорцияИзНабора.Обработана = Истина; - СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); - - ИначеЕсли Результат.Свойство("НаборПорций") Тогда - Для Каждого НоваяПорция Из Результат.НаборПорций Цикл - Задание.НаборПорций.Добавить(НоваяПорция); - КонецЦикла; - Задание.КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки - + Результат.НаборПорций.Количество(); - - ИначеЕсли Результат.Свойство("НовыйПоследнийОбновленныйЭлемент") Тогда - ОбновитьСвойстваЗадания(Задание, Результат.НовыйПоследнийОбновленныйЭлемент); - КонецЕсли; - - Если Результат.Свойство("ПорцияИзНабора") И ОбщееЗаданиеВыполняется(Задание) Тогда - Возврат; - КонецЕсли; - - Зафиксировать = Ложь; - Пока Задание.НаборПорций.Количество() > 0 Цикл - ПорцияИзНабора = Задание.НаборПорций[0]; - Если Не ПорцияИзНабора.Обработана Тогда - Прервать; - КонецЕсли; - Зафиксировать = Истина; - НовыйПоследнийОбновленныйЭлемент = ПорцияИзНабора.НовыйПоследнийЭлементПорции; - Задание.НаборПорций.Удалить(0); - Если Задание.ИндексСледующейПорцииДляОбработки > 0 Тогда - Задание.ИндексСледующейПорцииДляОбработки = Задание.ИндексСледующейПорцииДляОбработки - 1; - КонецЕсли; - КонецЦикла; - - Если Зафиксировать Тогда - ЗаписатьПоследнийОбновленныйЭлемент(Результат, НовыйПоследнийОбновленныйЭлемент); - ОбновитьСвойстваЗадания(Задание, НовыйПоследнийОбновленныйЭлемент); - Если Не Результат.ОбработкаЗавершена Тогда - Контекст.ОбработкаЗавершена = Ложь; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбработатьРезультатЗадания. -Процедура ОбновитьСвойстваЗадания(Задание, НовыйПоследнийОбновленныйЭлемент) - - Если НовыйПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда - Задание.Удалить = Истина; - Иначе - Если НовыйПоследнийОбновленныйЭлемент.Свойство("Дата") Тогда - Задание.ДатаПоследнегоОбновленногоЭлемента = НовыйПоследнийОбновленныйЭлемент.Дата; - Иначе - Задание.ДатаПоследнегоОбновленногоЭлемента = '00010101'; - КонецЕсли; - Задание.ЕстьДатаПоследнегоОбновленногоЭлемента - = ЗначениеЗаполнено(Задание.ДатаПоследнегоОбновленногоЭлемента); - - Задание.ПорядокВидаКлючаДанных = НовыйПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных; - ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание); - КонецЕсли; - -КонецПроцедуры - -// Для функции ЗапуститьОбновлениеДоступаСписка. -Процедура ВыполнитьОбновлениеДоступаСпискаВФоне(ОписаниеРодительскогоСеанса) Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - Контекст = Новый Структура; - Контекст.Вставить("Показатели", ПоказателиОбновленияИсполняющегоПотока()); - Контекст.Вставить("ОписаниеРодительскогоСеанса", ОписаниеРодительскогоСеанса); - - Если Не ИсполняющийПотокЗапущен(Контекст) Тогда - Возврат; - КонецЕсли; - Кэш = Новый Структура; - УстановитьЭтоСеансФоновогоОбновленияДоступа(); - - Пока Истина Цикл - Запрос = Контекст.Запрос; // Запрос - Выборка = Запрос.Выполнить().Выбрать(); - Если Не Выборка.Следующий() Тогда - Прервать; - КонецЕсли; - Если ТипЗнч(Выборка.Параметры) <> Тип("ХранилищеЗначения") Тогда - Если ПродолжитьОжиданиеНовогоЗадания(Контекст) Тогда - Продолжить; - Иначе - Прервать; - КонецЕсли; - КонецЕсли; - Результат = ОписаниеОбщихПараметровОбновления(); - Результат.Вставить("ОбработкаЗавершена", Ложь); - Результат.Вставить("ТекстОшибкиЗавершения", ""); - Попытка - ОбщиеПараметрыОбновления = Выборка.Параметры.Получить(); // см. ОписаниеОбщихПараметровОбновления - ЗаполнитьЗначенияСвойств(Результат, ОбщиеПараметрыОбновления); - ОбщиеПараметрыОбновления.Вставить("Кэш", Кэш); - Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания = - Цел(0.025 * Результат.МаксимумМиллисекундОбработки) / 1000; - - ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст); - Результат.ОбработкаЗавершена = ОбщиеПараметрыОбновления.ОбработкаЗавершена; - - ВозвращаемыеСвойства = "НетЗаданий, ПерезапускОбновления, ПерезапускОбновленияСНачала, - |НаборПорций, НовыйПоследнийОбновленныйЭлемент, НачальноеОбновлениеЗавершено, - |ТекстОшибкиЗавершения, ТребуетсяПерезапускСеанса"; - Для Каждого КлючИЗначение Из Новый Структура(ВозвращаемыеСвойства) Цикл - Если ОбщиеПараметрыОбновления.Свойство(КлючИЗначение.Ключ) Тогда - Результат.Вставить(КлючИЗначение.Ключ, ОбщиеПараметрыОбновления[КлючИЗначение.Ключ]); - КонецЕсли; - КонецЦикла; - Если ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") Тогда - Результат.Вставить("ПорцияИзНабора"); - КонецЕсли; - Исключение - ДобавитьТекстОшибкиЗавершения(Результат.ТекстОшибкиЗавершения, ТекстОшибкиОбновленияСКонтекстом( - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()), Результат)); - КонецПопытки; - ЗаписатьРезультатОбновленияДоступаСпискаВФоне(Результат, Выборка.Параметры, Контекст); - КонецЦикла; - - ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока(Контекст); - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Функция ИсполняющийПотокЗапущен(Контекст) - - ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); - Контекст.Вставить("ТекущийСеанс", ТекущийСеанс); - - Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда - ТекстОшибки = НСтр("ru = 'Порция обновления доступа может обрабатываться только в фоновом задании.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Контекст.Вставить("ТекущееФоновоеЗадание", ТекущийСеанс.ПолучитьФоновоеЗадание()); - ИдентификаторПотока = Контекст.ТекущееФоновоеЗадание.УникальныйИдентификатор; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИдентификаторПотока", ИдентификаторПотока); - Запрос.Текст = - "ВЫБРАТЬ - | ВЫБОР - | КОГДА ТекущиеЗадания.ЭтоЗапуск - | ТОГДА ТекущиеЗадания.Параметры - | ИНАЧЕ НЕОПРЕДЕЛЕНО - | КОНЕЦ КАК Параметры - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания - |ГДЕ - | ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторПотока"; - Контекст.Вставить("Запрос", Запрос); - - Блокировка = Новый("БлокировкаДанных"); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания"); - ЭлементБлокировки.УстановитьЗначение("ИдентификаторПотока", ИдентификаторПотока); - Контекст.Вставить("Блокировка", Блокировка); - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); - НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока); - Контекст.Вставить("НаборЗаписей", НаборЗаписей); - - ЗаписьНабора = НаборЗаписей.Добавить(); - ЗаписьНабора.ИдентификаторПотока = ИдентификаторПотока; - ЗаписьНабора.ЭтоЗапуск = Ложь; - Контекст.Вставить("ЗаписьНабора", ЗаписьНабора); - - // Ожидание признака запуска. - ГраницаОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; - Пока Истина Цикл - Если Не Запрос.Выполнить().Пустой() Тогда - Прервать; - КонецЕсли; - Если ТекущаяУниверсальнаяДатаВМиллисекундах() > ГраницаОжидания Тогда - Возврат Ложь; - КонецЕсли; - Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения(0.025); - КонецЦикла; - - Контекст.Вставить("ГраницаПроверкиРодительскогоСеанса", ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000); - Контекст.Вставить("КоличествоСекундОжиданияДоПоискаНовогоЗадания", 0.025); - - Возврат Истина; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Функция ПродолжитьОжиданиеНовогоЗадания(Контекст) - - Если ТекущаяУниверсальнаяДатаВМиллисекундах() > Контекст.ГраницаПроверкиРодительскогоСеанса Тогда - Если ОбновлениеДоступаОтменено() Тогда - Возврат Ложь; - КонецЕсли; - Контекст.ГраницаПроверкиРодительскогоСеанса = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; - Если Не СеансСуществует(Контекст.ОписаниеРодительскогоСеанса) Тогда - Возврат Ложь; - КонецЕсли; - КонецЕсли; - - Показатели = Контекст.Показатели; - Если Показатели <> Неопределено Тогда - Показатели.КоличествоОжиданийНовыхЗаданий = Показатели.КоличествоОжиданийНовыхЗаданий + 1; - КонецЕсли; - - НачалоОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - - Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения( - Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания); - - Если Показатели <> Неопределено Тогда - Показатели.ВремяОжиданияНовыхЗаданий = Показатели.ВремяОжиданияНовыхЗаданий - + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОжидания); - КонецЕсли; - Если Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания < 1 Тогда - Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания = - Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания + 0.010; - КонецЕсли; - - Возврат Истина; - -КонецФункции - -// Для функции ПродолжитьОжиданиеНовогоЗадания. -Функция СеансСуществует(ОписаниеСеанса) - - Если ЗначениеЗаполнено(ОписаниеСеанса.ИдентификаторФоновогоЗадания) Тогда - ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору( - ОписаниеСеанса.ИдентификаторФоновогоЗадания); - - Возврат ФоновоеЗадание <> Неопределено - И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно; - КонецЕсли; - - ОсновнойСеансНайден = Ложь; - Сеансы = ПолучитьСеансыИнформационнойБазы(); - - Для Каждого Сеанс Из Сеансы Цикл - - Если Сеанс.НачалоСеанса = ОписаниеСеанса.НачалоСеанса - И Сеанс.НомерСеанса = ОписаниеСеанса.НомерСеанса Тогда - - ОсновнойСеансНайден = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Возврат ОсновнойСеансНайден; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Процедура ЗаписатьРезультатОбновленияДоступаСпискаВФоне(Результат, ИсходныеПараметры, Контекст) - - НачатьТранзакцию(); - Попытка - Контекст.Блокировка.Заблокировать(); - Запрос = Контекст.Запрос; // Запрос - - Выборка = Запрос.Выполнить().Выбрать(); - - Если Выборка.Следующий() - И XMLСтрока(Выборка.Параметры) = XMLСтрока(ИсходныеПараметры) Тогда - - Контекст.ЗаписьНабора.Параметры = ИсходныеПараметры; - Контекст.ЗаписьНабора.Результат = Новый ХранилищеЗначения(Результат); - Контекст.ЗаписьНабора.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); - НаборЗаписей = Контекст.НаборЗаписей; // РегистрСведенийНаборЗаписей - - НаборЗаписей.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступа. -Функция ПоказателиОбновленияОсновногоСеанса() - - Если Не РегистрироватьПоказателиОбновленияДоступа() - Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда - Возврат Неопределено; - КонецЕсли; - - Показатели = Новый Структура; - Показатели.Вставить("ВремяПроверкиИОбновленияПараметровОграничения", 0); - Показатели.Вставить("ВремяОбновленияПараметровОграничения", 0); - - // Переменные. - Показатели.Вставить("НачалоРаботыВМиллисекундах", ТекущаяУниверсальнаяДатаВМиллисекундах()); - Показатели.Вставить("НачалоВыдачиЗадания"); - - Возврат Показатели; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступа. -Процедура ДобавитьПоказателиОбновленияУправляющегоПотока(Контекст) - - Показатели = Контекст.Показатели; - Если Показатели = Неопределено Тогда - Возврат; - КонецЕсли; - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - ДобавитьПоказателиВыполненияЗаданий(Показатели); - Иначе - Показатели.Вставить("ВремяОжиданийСвободногоПотока", 0); - - Показатели.Вставить("КоличествоВыданныхЗаданий", 0); - Показатели.Вставить("ВремяВыдачиЗаданий", 0); - Показатели.Вставить("МинимальноеВремяВыдачиЗадания", 0); - Показатели.Вставить("МаксимальноеВремяВыдачиЗадания", 0); - - Показатели.Вставить("ВремяОбработкиРезультатовЗаданий", 0); - Показатели.Вставить("МинимальноеВремяОбработкиРезультатаЗадания", 0); - Показатели.Вставить("МаксимальноеВремяОбработкиРезультатаЗадания", 0); - - Показатели.Вставить("КоличествоПотоковСПревышениемВремениВыполнения", 0); - Показатели.Вставить("КоличествоПотоковСНештатнымЗавершением", 0); - - // Переменные. - Показатели.Вставить("НачалоОбработкиЗадания", 0); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Функция ПоказателиОбновленияИсполняющегоПотока() - - Если Не РегистрироватьПоказателиОбновленияДоступа() - Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда - Возврат Неопределено; - КонецЕсли; - - Показатели = Новый Структура; - - Показатели.Вставить("НачалоРаботыВМиллисекундах", ТекущаяУниверсальнаяДатаВМиллисекундах()); - Показатели.Вставить("КоличествоОжиданийНовыхЗаданий", 0); - Показатели.Вставить("ВремяОжиданияНовыхЗаданий", 0); - - ДобавитьПоказателиВыполненияЗаданий(Показатели); - - Возврат Показатели; - -КонецФункции - -// Для функций ПоказателиОбновленияУправляющегоПотока, ПоказателиОбновленияИсполняющегоПотока. -Процедура ДобавитьПоказателиВыполненияЗаданий(Показатели) - - // Переменные. - Показатели.Вставить("ЗаданиеСПолучениемПорций", Истина); - Показатели.Вставить("НачалоПервойПопыткиВыполненияЗадания", 0); - Показатели.Вставить("НачалоВыполненияЗадания", 0); - - // Общие показатели. - Показатели.Вставить("КоличествоЗаданийСПовторамиИзЗаОшибок", 0); - Показатели.Вставить("ВремяВыполненияЗаданийСПовторамиИзЗаОшибок", 0); - Показатели.Вставить("КоличествоПовторовЗаданийИзЗаОшибок", 0); - Показатели.Вставить("МаксимальноеКоличествоПовторовЗаданияПриОшибке", 0); - Показатели.Вставить("ТекстОшибокПриПопыткахПовтора", ""); - - // Получение порций или сразу обработка маленькой порции. - Показатели.Вставить("КоличествоВыполненныхЗаданийСПолучениемПорций", 0); - Показатели.Вставить("ВремяВыполненияЗаданийСПолучениемПорций", 0); - Показатели.Вставить("МинимальноеВремяВыполненияЗаданийСПолучениемПорций", 0); - Показатели.Вставить("МаксимальноеВремяВыполненияЗаданийСПолучениемПорций", 0); - - // Только обработки порции. - Показатели.Вставить("КоличествоВыполненныхЗаданийБезПолученияПорций", 0); - Показатели.Вставить("ВремяВыполненияЗаданийБезПолученияПорций", 0); - Показатели.Вставить("МинимальноеВремяВыполненияЗаданийБезПолученияПорций", 0); - Показатели.Вставить("МаксимальноеВремяВыполненияЗаданийБезПолученияПорций", 0); - -КонецПроцедуры - -// Для функции ЗапуститьОбновлениеДоступаСписка. -Процедура СнятьПоказателиВыдачиЗаданий(Показатели) - - ВремяВыдачиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоВыдачиЗадания; - - Показатели.КоличествоВыданныхЗаданий = Показатели.КоличествоВыданныхЗаданий + 1; - Показатели.ВремяВыдачиЗаданий = Показатели.ВремяВыдачиЗаданий + ВремяВыдачиЗадания; - - Если Показатели.МинимальноеВремяВыдачиЗадания = 0 Тогда - Показатели.МинимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; - КонецЕсли; - Если ВремяВыдачиЗадания < Показатели.МинимальноеВремяВыдачиЗадания Тогда - Показатели.МинимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; - КонецЕсли; - - Если ВремяВыдачиЗадания > Показатели.МаксимальноеВремяВыдачиЗадания Тогда - Показатели.МаксимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; - КонецЕсли; - -КонецПроцедуры - -// Для функции ЗапуститьОбновлениеДоступаСписка. -Процедура СнятьПоказателиОбработкиРезультатаЗадания(Показатели) - - ВремяОбработкиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоОбработкиЗадания; - - Показатели.ВремяОбработкиРезультатовЗаданий = - Показатели.ВремяОбработкиРезультатовЗаданий + ВремяОбработкиЗадания; - - Если Показатели.МинимальноеВремяОбработкиРезультатаЗадания = 0 Тогда - Показатели.МинимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; - КонецЕсли; - Если ВремяОбработкиЗадания < Показатели.МинимальноеВремяОбработкиРезультатаЗадания Тогда - Показатели.МинимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; - КонецЕсли; - - Если ВремяОбработкиЗадания > Показатели.МаксимальноеВремяОбработкиРезультатаЗадания Тогда - Показатели.МаксимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Процедура СнятьПоказателиВыполненияЗадания(Показатели) - - ВремяВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоВыполненияЗадания; - - Если Показатели.ЗаданиеСПолучениемПорций Тогда - Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций = - Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций + 1; - - Показатели.ВремяВыполненияЗаданийСПолучениемПорций = - Показатели.ВремяВыполненияЗаданийСПолучениемПорций + ВремяВыполненияЗадания; - - Если Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = 0 Тогда - Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; - КонецЕсли; - Если ВремяВыполненияЗадания < Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций Тогда - Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; - КонецЕсли; - - Если ВремяВыполненияЗадания > Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций Тогда - Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; - КонецЕсли; - Иначе - Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций = - Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций + 1; - - Показатели.ВремяВыполненияЗаданийБезПолученияПорций = - Показатели.ВремяВыполненияЗаданийБезПолученияПорций + ВремяВыполненияЗадания; - - Если Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = 0 Тогда - Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; - КонецЕсли; - Если ВремяВыполненияЗадания < Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций Тогда - Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; - КонецЕсли; - - Если ВремяВыполненияЗадания > Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций Тогда - Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Процедура СнятьПоказателиОшибокВыполненияЗадания(Показатели, ТекстОшибок, КоличествоОшибок); - - Если КоличествоОшибок = 0 Тогда - Возврат; - КонецЕсли; - - Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок = Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок + 1; - - Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок = Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок - + (ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоПервойПопыткиВыполненияЗадания); - - Показатели.КоличествоПовторовЗаданийИзЗаОшибок = - Показатели.КоличествоПовторовЗаданийИзЗаОшибок + КоличествоОшибок; - - Если КоличествоОшибок > Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке Тогда - Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке = КоличествоОшибок; - КонецЕсли; - - ДобавитьТекстОшибкиЗавершения(Показатели.ТекстОшибокПриПопыткахПовтора, ТекстОшибок); - -КонецПроцедуры - -// Для процедур ЗарегистрироватьПоказателиОбновленияОсновногоПотока, -// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока, -// ДобавитьЗначенияПоказателейРаботыСеанса, -// ДобавитьЗначенияПоказателейВыполненияЗаданий. -// -Функция ФорматСекунд(ЧислоСекунд) - - Если ЧислоСекунд = 0 Тогда - Возврат СтрЗаменить(Формат(1.111), "1", "0"); - КонецЕсли; - - Возврат Формат(ЧислоСекунд, "ЧДЦ=3; ЧГ="); - -КонецФункции - -// Для процедур ЗарегистрироватьПоказателиОбновленияОсновногоПотока, -// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока, -// ДобавитьЗначенияПоказателейВыполненияЗаданий. -// -Функция ФорматКоличества(ЧислоКоличества) - - Возврат Формат(ЧислоКоличества, "ЧН=0; ЧГ="); - -КонецФункции - -// Для процедуры ЗавершитьОбновлениеДоступа. -Процедура ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст) - - Показатели = Контекст.Показатели; - Если Показатели = Неопределено Тогда - Возврат; - КонецЕсли; - - ОписаниеСеанса = Контекст.ОписаниеОсновногоСеанса; // См. ОписаниеОсновногоСеанса - - Если Контекст.ОбновлениеВЭтомСеансе Тогда - Комментарий = НСтр("ru = 'Завершен сеанс обновления доступа.'"); - ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса); - ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели); - Иначе - ВремяОжиданийСвободногоПотока = Показатели.ВремяОжиданийСвободногоПотока / 1000; - - ВремяВыдачиЗаданий = Показатели.ВремяВыдачиЗаданий / 1000; - МинимальноеВремяВыдачиЗадания = Показатели.МинимальноеВремяВыдачиЗадания / 1000; - МаксимальноеВремяВыдачиЗадания = Показатели.МаксимальноеВремяВыдачиЗадания / 1000; - - ВремяОбработкиРезультатовЗаданий = Показатели.ВремяОбработкиРезультатовЗаданий / 1000; - МинимальноеВремяОбработкиРезультатаЗадания = Показатели.МинимальноеВремяОбработкиРезультатаЗадания / 1000; - МаксимальноеВремяОбработкиРезультатаЗадания = Показатели.МаксимальноеВремяОбработкиРезультатаЗадания / 1000; - - Комментарий = НСтр("ru = 'Завершен сеанс управляющего потока обновления доступа.'"); - ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса); - - Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Время ожиданий свободного потока: %1 сек - | - |Количество выданных заданий: %2 - |Время выдачи заданий: %3 сек - |Минимальное время выдачи заданий: %4 сек - |Максимальное время выдачи заданий: %5 сек'"), - ФорматСекунд(ВремяОжиданийСвободногоПотока), - ФорматКоличества(Показатели.КоличествоВыданныхЗаданий), - ФорматСекунд(ВремяВыдачиЗаданий), - ФорматСекунд(МинимальноеВремяВыдачиЗадания), - ФорматСекунд(МаксимальноеВремяВыдачиЗадания)); - - Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Время обработки результатов заданий: %1 сек - |Минимальное время обработки результатов заданий: %2 сек - |Максимальное время обработки результатов заданий: %3 сек - | - |Количество потоков с превышением времени выполнения: %4 - |Количество потоков с нештатным завершением: %5'"), - ФорматСекунд(ВремяОбработкиРезультатовЗаданий), - ФорматСекунд(МинимальноеВремяОбработкиРезультатаЗадания), - ФорматСекунд(МаксимальноеВремяОбработкиРезультатаЗадания), - ФорматКоличества(Показатели.КоличествоПотоковСПревышениемВремениВыполнения), - ФорматКоличества(Показатели.КоличествоПотоковСНештатнымЗавершением)); - КонецЕсли; - Данные = ОписаниеСеанса.Идентификатор; - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Показатели.Обновление доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, , Данные, Комментарий); - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Процедура ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока(Контекст) - - Показатели = Контекст.Показатели; - Если Показатели = Неопределено Тогда - Возврат; - КонецЕсли; - - ВремяОжиданияНовыхЗаданий = Показатели.ВремяОжиданияНовыхЗаданий / 1000; - - Комментарий = НСтр("ru = 'Завершен сеанс исполняющего потока обновления доступа.'"); - ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, Контекст.ТекущийСеанс, Истина); - - ОписаниеСеанса = Контекст.ОписаниеРодительскогоСеанса; // См. ОписаниеОсновногоСеанса - - Комментарий = Комментарий + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Номер сеанса управляющего потока: %1 - |Начало сеанса управляющего потока: %2 - | - |Количество ожиданий новых заданий: %3 - |Время ожидания новых заданий: %4 сек'"), - ОписаниеСеанса.НомерСеанса, - ОписаниеСеанса.НачалоСеанса, - ФорматКоличества(Показатели.КоличествоОжиданийНовыхЗаданий), - ФорматСекунд(ВремяОжиданияНовыхЗаданий)); - - ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели); - Данные = ОписаниеСеанса.Идентификатор; - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Показатели.Обновление доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, , Данные, Комментарий); - -КонецПроцедуры - -// Для процедур ЗарегистрироватьПоказателиОбновленияУправляющегоПотока и -// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока. -// -Процедура ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса, ЭтоИсполняющийПоток = Ложь) - - ВремяРаботы = (ТекущаяУниверсальнаяДатаВМиллисекундах() - - Показатели.НачалоРаботыВМиллисекундах) / 1000; - - Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Номер сеанса: %1 - |Начало сеанса: %2 - |Время работы: %3 сек'"), - ОписаниеСеанса.НомерСеанса, - ОписаниеСеанса.НачалоСеанса, - ФорматСекунд(ВремяРаботы)); - - Если ЭтоИсполняющийПоток Тогда - Возврат; - КонецЕсли; - - Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Время проверки и обновления параметров ограничения: %1 сек - |Время обновления параметров ограничения: %2 сек'"), - ФорматСекунд(Показатели.ВремяПроверкиИОбновленияПараметровОграничения / 1000), - ФорматСекунд(Показатели.ВремяОбновленияПараметровОграничения / 1000)); - -КонецПроцедуры - -// Для процедур ЗарегистрироватьПоказателиОбновленияУправляющегоПотока и -// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока. -// -Процедура ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели) - - ВремяВыполненияЗаданийСПолучениемПорций = Показатели.ВремяВыполненияЗаданийСПолучениемПорций / 1000; - МаксимальноеВремяВыполненияЗаданийСПолучениемПорций = Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций / 1000; - МинимальноеВремяВыполненияЗаданийСПолучениемПорций = Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций / 1000; - - ВремяВыполненияЗаданийБезПолученияПорций = Показатели.ВремяВыполненияЗаданийБезПолученияПорций / 1000; - МаксимальноеВремяВыполненияЗаданийБезПолученияПорций = Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций / 1000; - МинимальноеВремяВыполненияЗаданийБезПолученияПорций = Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций / 1000; - - КоличествоВыполненныхЗаданий = Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций - + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций; - - ВремяВыполненияЗаданий = ВремяВыполненияЗаданийСПолучениемПорций + ВремяВыполненияЗаданийБезПолученияПорций; - ВремяВыполненияЗаданийСПовторамиИзЗаОшибок = Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок / 1000; - - Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Количество выполненных заданий: %1 - |Время выполнения заданий: %2 сек - | - |Количество заданий с повторами из-за ошибок: %3 - |Время выполнения заданий с повторами из-за ошибок: %4 сек - |Количество повторов заданий из-за ошибок: %5 - |Максимум повторов отдельного задания из-за ошибок: %6'"), - ФорматКоличества(КоличествоВыполненныхЗаданий), - ФорматСекунд(ВремяВыполненияЗаданий), - ФорматКоличества(Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок), - ФорматСекунд(ВремяВыполненияЗаданийСПовторамиИзЗаОшибок), - ФорматКоличества(Показатели.КоличествоПовторовЗаданийИзЗаОшибок), - ФорматКоличества(Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке)); - - Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Задания получения порций и/или обработки маленькой порции: - |- количество выполненных заданий: %1 - |- время выполнения заданий: %2 сек - |- минимальное время выполнения задания: %3 сек - |- максимальное время выполнения задания: %4 сек - | - |Задания обработки порций: - |- количество выполненных заданий: %5 - |- время выполнения заданий: %6 сек - |- минимальное время выполнения задания: %7 сек - |- максимальное время выполнения задания: %8 сек'"), - ФорматКоличества(Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций), - ФорматСекунд(ВремяВыполненияЗаданийСПолучениемПорций), - ФорматСекунд(МинимальноеВремяВыполненияЗаданийСПолучениемПорций), - ФорматСекунд(МаксимальноеВремяВыполненияЗаданийСПолучениемПорций), - ФорматКоличества(Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций), - ФорматСекунд(ВремяВыполненияЗаданийБезПолученияПорций), - ФорматСекунд(МинимальноеВремяВыполненияЗаданийБезПолученияПорций), - ФорматСекунд(МаксимальноеВремяВыполненияЗаданийБезПолученияПорций)); - - Если ЗначениеЗаполнено(Показатели.ТекстОшибокПриПопыткахПовтора) Тогда - Комментарий = Комментарий + Символы.ПС + Символы.ПС - + НСтр("ru = 'Тексты ошибок при попытках повторного выполнения:'") - + Символы.ПС + Символы.ПС + Показатели.ТекстОшибокПриПопыткахПовтора; - КонецЕсли; - -КонецПроцедуры - -// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ОбработатьРезультатЗадания, ЗарегистрироватьОшибкуОбновленияДоступа. -Процедура ДобавитьТекстОшибкиЗавершения(ТекстОшибкиЗавершения, ТекстОшибки) - - Если Не ЗначениеЗаполнено(ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - Если ЗначениеЗаполнено(ТекстОшибкиЗавершения) Тогда - Если СтрНайти(ТекстОшибкиЗавершения, ТекстОшибки) > 0 Тогда - Возврат; - КонецЕсли; - ТекстОшибкиЗавершения = ТекстОшибкиЗавершения + Символы.ПС + Символы.ПС; - КонецЕсли; - - ТекстОшибкиЗавершения = ТекстОшибкиЗавершения + ТекстОшибки; - -КонецПроцедуры - -// Для процедур ОбновитьСвойстваФоновогоЗадания, ОтменитьФоновоеЗаданиеПотока, ОбработатьВыполненныеЗадания, -// УдалитьОстановленныеПотоки, ВыполнитьОбновлениеДоступаСпискаВФоне. -// -Функция ТекстОшибкиОбновленияСКонтекстом(ИнформацияОбОшибке, ОбщиеПараметрыОбновления, УстранимаяОшибка = Ложь) - - Если ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда - ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - Иначе - ПредставлениеОшибки = Строка(ИнформацияОбОшибке); - КонецЕсли; - - Если Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда - Возврат ""; - КонецЕсли; - - Если ОбщиеПараметрыОбновления = Неопределено Тогда - ТекстОшибки = ПредставлениеОшибки; - - ИначеЕсли Не ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав Тогда - - Если ОбщиеПараметрыОбновления.ДляВнешнихПользователей Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить ключи доступа к элементам данных списка - |""%1"" (для внешних пользователей) - |по причине: - |%2'"), - Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), - ПредставлениеОшибки); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить ключи доступа к элементам данных списка - |""%1"" (для пользователей) - |по причине: - |%2'"), - Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), - ПредставлениеОшибки); - КонецЕсли; - - Иначе // ОбновлениеКлючейДоступаПользователей. - - Если ОбщиеПараметрыОбновления.ДляВнешнихПользователей Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить ключи доступа внешних пользователей списка - |""%1"" - |по причине: - |%2'"), - Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), - ПредставлениеОшибки); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить ключи доступа пользователей списка - |""%1"" - |по причине: - |%2'"), - Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), - ПредставлениеОшибки); - КонецЕсли; - КонецЕсли; - - Если УстранимаяОшибка Тогда - ТекстОшибки = НСтр("ru = 'Возникла устранимая ошибка (обновление продолжается автоматически).'") - + Символы.ПС + ТекстОшибки; - КонецЕсли; - - Возврат ТекстОшибки; - -КонецФункции - -// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ЗавершитьФоновыеЗадания, -// ОбработатьРезультатВыполненногоЗадания, ОбновитьСвойстваФоновогоЗадания, -// ВыполнитьОбновлениеДоступаСпискаВФоне. -// -Процедура ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибки, Контекст) - - Если Контекст.Свойство("ОписаниеРодительскогоСеанса") Тогда - ОписаниеСеанса = Контекст.ОписаниеРодительскогоСеанса; // См. ОписаниеОсновногоСеанса - Иначе - ОписаниеСеанса = Контекст.ОписаниеОсновногоСеанса; // См. ОписаниеОсновногоСеанса - КонецЕсли; - - Данные = ОписаниеСеанса.Идентификатор; - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Обновление доступа на уровне записей'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Ошибка, , Данные, ТекстОшибки); - -КонецПроцедуры - -// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. -Процедура ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст) - - Показатели = Контекст.Показатели; - - Если Показатели <> Неопределено Тогда - Показатели.НачалоПервойПопыткиВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - - ПопыткаВыполнения = 1; - ОшибкиПопытокВыполнения = Новый Массив; - Пока Истина Цикл - ТекстОшибкиТекущейПопытки = ""; - Если Показатели <> Неопределено Тогда - Показатели.ЗаданиеСПолучениемПорций = Не ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора"); - Показатели.НачалоВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); - КонецЕсли; - Попытка - ВыполнитьОбновлениеДоступаСписка(ОбщиеПараметрыОбновления); - Исключение - Если ТранзакцияАктивна() Тогда - ВызватьИсключение; - КонецЕсли; - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибкиТекущейПопытки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - КонецПопытки; - Если Показатели <> Неопределено И Не ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда - СнятьПоказателиВыполненияЗадания(Показатели); - КонецЕсли; - ТекстОшибкиТребуетсяПерезапуск = ""; - Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(ТекстОшибкиТребуетсяПерезапуск) Тогда - ОбщиеПараметрыОбновления.Вставить("ТребуетсяПерезапускСеанса", ТекстОшибкиТребуетсяПерезапуск); - Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда - ТекстОшибкиТекущейПопытки = ""; - КонецЕсли; - КонецЕсли; - Если ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда - ВремяОшибкиТекущейПопытки = Формат(ТекущаяДатаСеанса(), "ДЛФ=DT"); - ОшибкиПопытокВыполнения.Добавить(ВремяОшибкиТекущейПопытки + " " + ТекстОшибкиТекущейПопытки); - ПопыткаВыполнения = ПопыткаВыполнения + 1; - Если ПопыткаВыполнения < 9 И Не ЗначениеЗаполнено(ТекстОшибкиТребуетсяПерезапуск) Тогда - Для Счетчик = 1 По ПопыткаВыполнения Цикл - // @skip-check query-in-loop - Порционная обработка данных - Если ОбновлениеДоступаОтменено() Тогда - Прервать; - КонецЕсли; - Если Контекст.ТекущееФоновоеЗадание <> Неопределено Тогда - Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения(1); - Иначе - ГраницаОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; - Пока ГраницаОжидания > ТекущаяУниверсальнаяДатаВМиллисекундах() Цикл - Продолжить; - КонецЦикла; - КонецЕсли; - КонецЦикла; - // @skip-check query-in-loop - Порционная обработка данных - Если Не ОбновлениеДоступаОтменено() Тогда - Продолжить; - КонецЕсли; - КонецЕсли; - КонецЕсли; - ТекстОшибки = СтрСоединить(ОшибкиПопытокВыполнения, Символы.ПС + "---" + Символы.ПС); - ТекстОшибки = ТекстОшибкиОбновленияСКонтекстом(ТекстОшибки, ОбщиеПараметрыОбновления); - - Если ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда - ОбщиеПараметрыОбновления.Вставить("ТекстОшибкиЗавершения", ""); - ДобавитьТекстОшибкиЗавершения(ОбщиеПараметрыОбновления.ТекстОшибкиЗавершения, ТекстОшибки); - КонецЕсли; - Если Показатели <> Неопределено Тогда - СнятьПоказателиОшибокВыполненияЗадания(Показатели, ТекстОшибки, ОшибкиПопытокВыполнения.Количество()); - КонецЕсли; - Прервать; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора. -Процедура ВыполнитьОбновлениеДоступаСписка(ОбщиеПараметрыОбновления) - - Если Не ОбщиеПараметрыОбновления.Свойство("Кэш") Тогда - ОбщиеПараметрыОбновления.Вставить("Кэш", Новый Структура); - КонецЕсли; - - Если ОбщиеПараметрыОбновления.ИдентификаторСписка = Неопределено Тогда - ОбъектМетаданных = Null; - ИначеЕсли ОбщиеПараметрыОбновления.Свойство("Кэш") - И ОбщиеПараметрыОбновления.Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда - - ОбъектМетаданных = ОбщиеПараметрыОбновления.Кэш.ОбъектыМетаданныхПоИдентификаторам.Получить( - ОбщиеПараметрыОбновления.ИдентификаторСписка); - Иначе - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору( - ОбщиеПараметрыОбновления.ИдентификаторСписка, Ложь); - КонецЕсли; - - Если ОбъектМетаданных = Неопределено Тогда - // Если расширение конфигурации отключено, тогда обновление невозможно, - // но нельзя очищать регистрацию к обновлению. - ОбщиеПараметрыОбновления.Вставить("НетЗаданий", "ОбъектМетаданныхОтключен"); - Возврат; - КонецЕсли; - - ЭтоОбновлениеПрав = ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав; - - Если Не ОбщиеПараметрыОбновления.ДляВнешнихПользователей - И ОбщиеПараметрыОбновления.ИдентификаторСписка - = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка() Тогда - УдалитьОбъектыНедопустимыхТиповВРегистреКлючиДоступаКОбъектам(); - КонецЕсли; - - ПараметрыОбновления = ПараметрыОбновления(ОбщиеПараметрыОбновления, ОбъектМетаданных); - - // Обработка ранее подготовленной порции для обработки. - Если ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") Тогда - ПорцияИзНабора = ОбщиеПараметрыОбновления.ПорцияИзНабора; // См. ПорцияИзНабора - ЭлементыПорции = ПорцияИзНабора.Элементы.Получить(); - ПараметрыОбновления.Вставить("ПоследнийОбновленныйЭлемент", - ПорцияИзНабора.ПоследнийЭлементПорции); - - ОбновитьПорциюЭлементов(ЭлементыПорции, ПараметрыОбновления); - - ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", - ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); - - Если ЭлементыПорции <> Неопределено Тогда - ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; - ВыбраныВсеЭлементы = ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; - ОбщиеПараметрыОбновления.Вставить("НаборПорций", НаборПорцийЭлементов( - ПараметрыОбновления, ЭлементыПорции, ВыбраныВсеЭлементы)); - КонецЕсли; - Возврат; - КонецЕсли; - - // Подготовка плана обработки элементов данных. - ПодготовкаЗавершена = Ложь; - ПараметрыОбновления.Вставить("ПерезапускОбновления", Ложь); - - Пока Не ПодготовкаЗавершена Цикл - ПодготовкаЗавершена = Истина; - ПараметрыОбновления.Вставить("ЕстьЗадания", Истина); - ПараметрыОбновления.Вставить("ТочечноеЗадание", Неопределено); - ПараметрыОбновления.Вставить("ПоследнийОбновленныйЭлемент", НачальныйЭлемент(ПараметрыОбновления)); - // @skip-check query-in-loop - Порционная обработка данных - ПодготовитьПланОбновления(ПараметрыОбновления, ПодготовкаЗавершена); - КонецЦикла; - - Если Не ПараметрыОбновления.ЕстьЗадания Тогда - ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); - Возврат; - КонецЕсли; - - Если Не ПараметрыОбновления.ЭтоОбновлениеПрав - И ПараметрыОбновления.БезОбновленияКлючейДоступаКОбъектам Тогда - - ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Null; - ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, - ПараметрыОбновления.ПоследнийОбновленныйЭлемент); - ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); - Возврат; - КонецЕсли; - - Если ПараметрыОбновления.ТочечноеЗадание <> Неопределено Тогда - ВыбраныВсеЭлементы = Ложь; - Элементы = ЭлементыТочечногоЗаданияДляОбновления(ПараметрыОбновления, - КоличествоЭлементовВЗапросе(ЭтоОбновлениеПрав), ВыбраныВсеЭлементы); - - Если Элементы <> Неопределено Тогда - МаксимумМиллисекунд = МинимальноеКоличествоСекундВыполненияТочечногоЗадания() * 1000; - Если ПараметрыОбновления.ГраницаВремениОбработки - ТекущаяУниверсальнаяДатаВМиллисекундах() < МаксимумМиллисекунд Тогда - ПараметрыОбновления.ГраницаВремениОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах() + МаксимумМиллисекунд; - КонецЕсли; - ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления, Истина); - КонецЕсли; - Если Элементы <> Неопределено Или Не ВыбраныВсеЭлементы Тогда - ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении(ПараметрыОбновления); - КонецЕсли; - КонецЕсли; - - УточнитьПоследнийОбновленныйЭлемент(ПараметрыОбновления); - - Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда - ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Null; - ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, - ПараметрыОбновления.ПоследнийОбновленныйЭлемент); - ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); - Возврат; - КонецЕсли; - - Если ПараметрыОбновления.ТочечноеЗадание <> Неопределено Тогда - ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Вставить("ОчиститьТочечноеЗадание"); - ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, - ПараметрыОбновления.ПоследнийОбновленныйЭлемент); - ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Удалить("ОчиститьТочечноеЗадание"); - КонецЕсли; - - Если ПараметрыОбновления.ПерезапускОбновления Тогда - ОбщиеПараметрыОбновления.Вставить("ПерезапускОбновления"); - Если ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") Тогда - ОбщиеПараметрыОбновления.Удалить("НовыйПоследнийЭлементПорции"); - КонецЕсли; - КонецЕсли; - - Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) - И Не ОбщиеПараметрыОбновления.РазрешенаОбработкаУстаревшихЭлементов Тогда - - ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, - ПараметрыОбновления.ПоследнийОбновленныйЭлемент); - ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", - ПараметрыОбновления.ПоследнийОбновленныйЭлемент); - ОбщиеПараметрыОбновления.Вставить("НачальноеОбновлениеЗавершено"); - Возврат; - КонецЕсли; - - Если ОбщиеПараметрыОбновления.ПолучитьПорции > 0 - И ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") Тогда - - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); - ЗаполнитьЗначенияСвойств(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, - ОбщиеПараметрыОбновления.НовыйПоследнийЭлементПорции); - КонецЕсли; - - Если Не ЭтоОбновлениеПрав - И ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, - ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата) Тогда - - ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", - ПараметрыОбновления.ПоследнийОбновленныйЭлемент); - - ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; - Возврат; - КонецЕсли; - - // Однопоточное обновление некоторых наборов групп доступа. - Если Не ЭтоОбновлениеПрав - И ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) - И ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Неопределено Тогда - - Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда - УстранитьДублиНаборовИзОдногоПользователяВСправочнике(ПараметрыОбновления); - - ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда - ЗаполнитьПустыеХешиНаборовГрупп(ПараметрыОбновления); - - ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда - Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда - ОбновитьПраваНаРазрешенныйКлючДоступа(); - КонецЕсли; - ОчиститьПраваПустогоНабораГруппДоступа(ПараметрыОбновления); - - ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - ОчиститьПраваНесуществующихНаборовГруппДоступа(ПараметрыОбновления); - КонецЕсли; - КонецЕсли; - - // Запрос элементов для обработки. - ВыбраныВсеЭлементы = Ложь; - - Если ОбщиеПараметрыОбновления.ПолучитьПорции > 0 Тогда - КоличествоВПорции = КоличествоЭлементовВПорции(ПараметрыОбновления); - КоличествоВЗапросе = КоличествоВПорции * ОбщиеПараметрыОбновления.ПолучитьПорции; - Элементы = ЭлементыДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы); - - Если ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") - Или Элементы <> Неопределено - И Элементы.Количество() > КоличествоВПорции * 2 - Или КоличествоВЗапросе = Null Тогда - - ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; - ОбщиеПараметрыОбновления.Вставить("НаборПорций", НаборПорцийЭлементов( - ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы, КоличествоВПорции)); - Если КоличествоВЗапросе = Null Тогда - ОбщиеПараметрыОбновления.НаборПорций[0].Обработана = Истина; - КонецЕсли; - Возврат; - КонецЕсли; - Иначе - Возврат; - КонецЕсли; - - // Обработка элементов данных. - ПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", - НачальныйЭлемент(ПараметрыОбновления, , Истина)); - - ОбщиеПараметрыОбновления.Вставить("НачальноеОбновлениеЗавершено"); - - Если Элементы <> Неопределено Тогда - ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления); - КонецЕсли; - - // Уточнение нового последнего элемента. - Если Элементы = Неопределено И ВыбраныВсеЭлементы Тогда - УстановитьПустойПоследнийЭлемент(ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент, - ПараметрыОбновления); - КонецЕсли; - - // Запись нового последнего элемента. - ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, - ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); - - Если ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда - ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); - Возврат; - КонецЕсли; - - ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", - ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); - - // Подготовка оставшихся элементов к продолжению обновления. - Если Элементы <> Неопределено Тогда - ОбщиеПараметрыОбновления.Вставить("НаборПорций", - НаборПорцийЭлементов(ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы)); - КонецЕсли; - -КонецПроцедуры - -Функция ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) - - Если ПараметрыОбновления.Свойство("Список") Тогда - Возврат ПараметрыОбновления.Список = "Справочник.НаборыГруппДоступа"; - КонецЕсли; - - Возврат ПараметрыОбновления.ИдентификаторСписка - = ПараметрыОбновления.ИдентификаторСправочникаНаборыГруппДоступа; - -КонецФункции - -// Для процедура ВыполнитьОбновлениеДоступаСписка. -// -// Возвращаемое значение: -// Структура: -// * ЭтоОбновлениеПрав - Булево -// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// * ДляВнешнихПользователей - Булево -// * Кэш - см. НовыйКэшКонтекста -// * ДатаНачала - Дата -// * ДатаОкончания - Дата -// * МаксимумПорцийИзИсходной - Число -// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// * ГраницаВремениОбработки - Дата -// -// Свойства, если ЭтоСправочникНаборыГруппДоступа. -// * СписокСДатой - Булево -// * СписокСПериодом - Булево -// * ЭтоСсылочныйТип - Булево -// * ПустойНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа -// -// Свойства, если не ЭтоСправочникНаборыГруппДоступа. -// * ИдентификаторТранзакции - УникальныйИдентификатор -// * ЗависимыеСпискиПоКлючамДоступа - Массив из Строка - полные имена списков -// -// Свойства добавляемые в процессе работы. -// * ЕстьИзмененияПрав - Булево -// * ОбновитьПраваНаКлючи - Булево -// * ПоследнийОбновленныйЭлемент - см. НачальныйЭлемент -// * НовыйПоследнийОбновленныйЭлемент - см. НачальныйЭлемент -// * ПерезапускОбновления - Булево -// * ЕстьЗадания - Булево -// * ТочечноеЗадание - см. ПодготовленноеТочечноеЗадание -// * НаборПорций - Массив из см. ПорцияИзНабора -// * ТипПользователя - Тип -// * ТипГруппыПользователей - Тип -// * ТипГруппыДоступа - Тип -// * ПустаяГруппаДоступа - СправочникСсылка.ГруппыДоступа -// * ПраваГруппДоступаСписка - см. НовыеПраваГруппДоступаСписка -// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей -// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа -// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа -// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа -// * ЗначенияГруппДоступа - см. НовыеЗначенияГруппДоступа -// * РолиПрофилейГруппДоступа - см. НовыеРолиПрофилейГруппДоступа -// * ГруппыДоступаПрофилей - см. НовыеГруппыДоступаПрофилей -// * ПраваНаСпискиВедущихКлючейДоступа - см. НовыеПраваНаСпискиВедущихКлючейДоступа -// * ПраваНаВедущиеКлючиДоступа - см. НовыеПраваНаВедущиеКлючиДоступа -// * ПраваНаВедущиеСписки - см. НовыеПраваНаВедущиеСписки -// * ПраваПоВладельцамНастроекПрав - см. НовыеПраваПоВладельцамНастроекПрав -// * МодельОбъектовВПамяти - см. МодельОбъектовВПамяти -// -// Копия свойств из ПараметрыОграниченияПоСтруктуреОграничения. -// * Список - Строка -// * ДляВнешнихПользователей - Булево -// * Версия - Строка -// * ВедущиеСписки - см. НовыеВедущиеСписки -// * ДоступЗапрещен - Булево -// * ОграничениеОтключено - Булево -// * ОграничениеЧтенияОтключено - Булево -// * ПолеВладельца - см. НовоеПолеВладельца -// * ТребуетсяОграничениеПоВладельцу - Булево -// * ИспользуетсяОграничениеПоВладельцу - Булево -// * РассчитыватьПраваПользователей - Булево -// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа -// * ЧтениеРазрешеноДляВсехПользователей - Булево -// * ИзменениеРазрешеноДляВсехПользователей - Булево -// * ЕстьВедущиеКлючиДоступа - Булево -// * ЕстьВедущиеСпискиПоПравам - Булево -// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево -// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие -// * ИдентификаторТаблицыНастроекПрав - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// * ЕстьВладельцыНастроекПрав - Булево -// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип -// * ВсеВидыОграниченийПрав - Соответствие -// * ПоляТаблицОбъекта - Массив из см. НовыеПоляТаблицыОбъекта -// * ИмяОтдельногоРегистраКлючей - Строка -// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей -// * ВариантДоступа - Число -// * СоставПолей - Число -// * ЕстьОграничениеЧтения - Булево -// * ЕстьОграничениеИзменения - Булево -// * ЕстьОграничениеПоПользователям - Булево -// * СтруктураРасчетаПраваЧтение - см. СтруктураРасчетаПрава -// * СтруктураРасчетаПраваИзменение - см. СтруктураРасчетаПрава -// * Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -// Свойства, добавляемые в процедуре ДобавитьТекстыЗапросовВПараметрыОграничения. -// * ТекстЗапросаПроверкиПравЧтениеИзменение - Строка -// * ТекстЗапросаПроверкиПраваЧтение - Строка -// * ПолеОбъектаВладельцаВЗапросеПроверкиПрав - Строка -// * ТекстЗапросаУстаревшихЭлементовДанных - Строка -// * ТекстЗапросаПроверкиУстаревшихЭлементовДанных - Строка -// * ТекстЗапросаНекорректныхЭлементовДанных - Строка -// * ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра - Строка -// * ТаблицыКлюча - Массив из Строка -// * РеквизитыТаблицКлюча - см. НовыеРеквизитыТаблицКлюча -// * ТекстЗапросаДиапазонаЭлементовДанных - Строка -// * ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами - Строка -// * ТекстЗапросаПроверкиКлючаДоступаОбъекта - Строка -// * ТекстЗапросаЭлементовДанныхБезКлючейДоступа - Строка -// * ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей - Строка -// * ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей - Строка -// * ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам - Соответствие из КлючИЗначение: -// ** Ключ - Строка -// ** Значение - Соответствие из КлючИЗначение: -// *** Ключ - Строка -// *** Значение - Соответствие -// - Структура: -// *** ТипСсылки - ХранилищеЗначения -// *** КлючиЗапросовПоТипам - Соответствие -// *** ТекстыЗапросовПоКлючам - Соответствие -// *** ТекстЗапросаПараметров - Строка -// - Строка -// * ТекстЗапросаТекущихКлючейДоступаРегистра - Строка -// * ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа - Строка -// * ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа - Строка -// * ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения - Строка -// * ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения - Строка -// * ТекстЗапросаСуществованияКлючейДляСравнения - Строка -// * ТекстЗапросаКлючейДоступаДляОбновленияПрав - Строка -// * ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав - Строка -// * ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав - Строка -// * ТекстЗапросаУстаревшихКлючейДоступа - Строка -// -Функция ПараметрыОбновления(ОбщиеПараметрыОбновления, ОбъектМетаданных) - - ПараметрыОбновления = Новый Структура("ЭтоОбновлениеПрав, - |ИдентификаторСписка, ДляВнешнихПользователей, Кэш, - |ДатаНачала, ДатаОкончания, МаксимумПорцийИзИсходной, - |ЭтоФоновоеОбновлениеДоступа, ИдентификаторСправочникаНаборыГруппДоступа"); - - ЗаполнитьЗначенияСвойств(ПараметрыОбновления, ОбщиеПараметрыОбновления); - - Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда - ПараметрыОбновления.Вставить("Список", ОбъектМетаданных.ПолноеИмя()); - КонецЕсли; - - ПараметрыОбновления.Вставить("ГраницаВремениОбработки", - ТекущаяУниверсальнаяДатаВМиллисекундах() - + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки); - - ДобавитьПараметрыОграничения(ПараметрыОбновления); - - Возврат ПараметрыОбновления; - -КонецФункции - -// Для процедура ВыполнитьОбновлениеДоступаСписка. -Процедура ДобавитьПараметрыОграничения(ПараметрыОбновления) - - Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - ПараметрыОбновления.Вставить("СписокСДатой", Ложь); - ПараметрыОбновления.Вставить("СписокСПериодом", Ложь); - ПараметрыОбновления.Вставить("ЭтоСсылочныйТип", Истина); - ПараметрыОбновления.Вставить("ПустойНаборГруппДоступа", Справочники.НаборыГруппДоступа.ПустаяСсылка()); - ПараметрыОбновления.Вставить("БезОбновленияКлючейДоступаКОбъектам", Ложь); - Возврат; - КонецЕсли; - - ИдентификаторТранзакции = Новый УникальныйИдентификатор; - Список = ?(ПараметрыОбновления.Свойство("Список"), ПараметрыОбновления.Список, ""); - СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(Список, ИдентификаторТранзакции); - ПараметрыОграничения = ПараметрыОграничения(Список, - ИдентификаторТранзакции, ПараметрыОбновления.ДляВнешнихПользователей); - - ПараметрыОграничения = Новый Структура(ПараметрыОграничения); - Для Каждого КлючИЗначение Из ПараметрыОбновления Цикл - ПараметрыОграничения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - ПараметрыОбновления = ПараметрыОграничения; - ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); - - ИмяСвойстваВидаПользователей = ?(ПараметрыОбновления.ДляВнешнихПользователей, - "ДляВнешнихПользователей", "ДляПользователей"); - - Если СвойстваСпискаКакВедущего = Неопределено - Или СвойстваСпискаКакВедущего.ПоКлючамДоступа = Неопределено - Или СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей] = Неопределено Тогда - - ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", Новый Массив); - Иначе - ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", - СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей]); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ВыполнитьОбновлениеДоступаСписка, ПодготовитьПланОбновления. -// -// Возвращаемое значение: -// Структура: -// * КлючДанных - ЛюбаяСсылка -// - Null -// - Структура -// * ОбработатьУстаревшиеЭлементы - Булево -// * ОбработатьНаборыГруппСУстаревшимиПравами - Булево -// * Дата - Дата -// -Функция НачальныйЭлемент(ПараметрыОбновления, ВидКлючаДанных = Неопределено, - СохранитьВидКлючаДанных = Ложь, ПерезапускОбновленияСНачала = Ложь) - - НачальныйЭлемент = Новый Структура; - НачальныйЭлемент.Вставить("КлючДанных"); - НачальныйЭлемент.Вставить("ОбработатьУстаревшиеЭлементы", Ложь); - НачальныйЭлемент.Вставить("ОбработатьНаборыГруппСУстаревшимиПравами", Ложь); - СохранитьСвойства = Ложь; - - Если ВидКлючаДанных = Неопределено Тогда - Если СохранитьВидКлючаДанных Тогда - ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; - СохранитьСвойства = Истина; - - ИначеЕсли ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя"; - - ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - ВидКлючаДанных = "ЭлементыСУстаревшимиПравами"; - Иначе - ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами"; - КонецЕсли; - ИначеЕсли ВидКлючаДанных <> "НетДанных" - И ПараметрыОбновления.Свойство("ПоследнийОбновленныйЭлемент") Тогда - СохранитьСвойства = Истина; - КонецЕсли; - Если СохранитьСвойства Тогда - Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы Тогда - НачальныйЭлемент.ОбработатьУстаревшиеЭлементы = Истина; - КонецЕсли; - Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами Тогда - НачальныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; - КонецЕсли; - КонецЕсли; - УстановитьВидКлючаДанных(НачальныйЭлемент, ВидКлючаДанных); - - Если Не ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - НачальныйЭлемент.Вставить("Дата", ?(ПерезапускОбновленияСНачала, - МаксимальнаяДата(), МаксимальнаяДатаПриПродолжении())); - КонецЕсли; - - Возврат НачальныйЭлемент; - -КонецФункции - -// Для процедура ВыполнитьОбновлениеДоступаСписка. -Процедура ПодготовитьПланОбновления(ПараметрыОбновления, ПодготовкаЗавершена) - - ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; - ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; - ЭтоОбновлениеПрав = ПараметрыОбновления.ЭтоОбновлениеПрав; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Список", ИдентификаторСписка); - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); - - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1000 - | КлючиУникальности.КлючУникальности КАК КлючУникальности, - | КлючиУникальности.ПараметрыЗадания КАК ПараметрыЗадания, - | КлючиУникальности.ДатаПоследнегоОбновленногоЭлемента КАК ДатаПоследнегоОбновленногоЭлемента - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК КлючиУникальности - |ГДЕ - | КлючиУникальности.Список = &Список - | И КлючиУникальности.ДляВнешнихПользователей = &ДляВнешнихПользователей - | - |УПОРЯДОЧИТЬ ПО - | КлючиУникальности.Список, - | КлючиУникальности.ДляВнешнихПользователей, - | КлючиУникальности.КлючУникальности"; - - Если ЭтоОбновлениеПрав Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "РегистрСведений.ОбновлениеКлючейДоступаКДанным", - "РегистрСведений.ОбновлениеКлючейДоступаПользователей"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, ", - | КлючиУникальности.ДатаПоследнегоОбновленногоЭлемента КАК ДатаПоследнегоОбновленногоЭлемента", - ""); // @query-part-1 - КонецЕсли; - - РезультатЗапроса = Запрос.Выполнить(); - - Если РезультатЗапроса.Пустой() Тогда - ПараметрыОбновления.ЕстьЗадания = Ложь; - Возврат; - КонецЕсли; - - Выгрузка = РезультатЗапроса.Выгрузить(); - - Если Выгрузка.Количество() = 1000 Тогда - ПодготовкаЗавершена = Ложь; - КонецЕсли; - - Если ЭтоОбновлениеПрав Тогда - ПланОбновления = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаПользователей); - Иначе - ПланОбновления = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); - КонецЕсли; - ПланОбновления.Отбор.Список.Установить(ИдентификаторСписка); - ПланОбновления.Отбор.ДляВнешнихПользователей.Установить(ДляВнешнихПользователей); - - Если ПараметрыОбновления.Список = СписокДляПланированияОбновленияКэшаРасчетаПрав() Тогда - ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка); - ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка); - ПараметрыОбновления.ЕстьЗадания = Ложь; - Возврат; - КонецЕсли; - - ПерезапускОбновления = Ложь; - ПерезапускОбновленияСНачала = Ложь; - СохраняемыеПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ПараметрыОбновления); - - Если Не ЗначениеЗаполнено(Выгрузка[0].КлючУникальности) Тогда - ТекущийИтог = Выгрузка[0]; - ПараметрыЗадания = ТекущийИтог.ПараметрыЗадания.Получить(); - Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") Тогда - СохраняемыеПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, - ПараметрыОбновления, ПараметрыЗадания, ПерезапускОбновления); - Иначе - ПерезапускОбновления = Истина; - КонецЕсли; - Если Не ПерезапускОбновления И Не ЭтоОбновлениеПрав Тогда - СохраненнаяДата = ТекущийИтог.ДатаПоследнегоОбновленногоЭлемента; - Если ТипЗнч(СохраненнаяДата) = Тип("Дата") Тогда - СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент.Дата = СохраненнаяДата; - Иначе - ПерезапускОбновления = Истина; - КонецЕсли; - КонецЕсли; - Выгрузка.Удалить(0); - Если Не ПерезапускОбновления Тогда - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = - СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент; - КонецЕсли; - КонецЕсли; - - Если Не ПерезапускОбновления - И ТекущийИтог <> Неопределено - И Выгрузка.Количество() = 0 Тогда - - ПараметрыОбновления.ТочечноеЗадание = ПодготовленноеТочечноеЗадание( - ЭтоОбновлениеПрав, СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); - Если Не ПерезапускОбновления Тогда - Возврат; - КонецЕсли; - КонецЕсли; - - ПустойИдентификатор = ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор(); - ПолноеИмяРегистра = ?(ЭтоОбновлениеПрав, "РегистрСведений.ОбновлениеКлючейДоступаПользователей", - "РегистрСведений.ОбновлениеКлючейДоступаКДанным"); - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); - ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); - ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); - ЭлементБлокировки.УстановитьЗначение("КлючУникальности", ПустойИдентификатор); - - ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); - ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); - ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); - ЭлементБлокировки.ИсточникДанных = Выгрузка; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючУникальности", "КлючУникальности"); - - МаксимальнаяДата = МаксимальнаяДата(); - СвойстваКлючаДанных = НачальныйЭлемент(ПараметрыОбновления, "НетДанных"); - ВидКлючаДанныхУстановлен = Истина; - Для Каждого Строка Из Выгрузка Цикл - ПараметрыЗадания = Строка.ПараметрыЗадания.Получить(); - Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") И ПараметрыЗадания.Свойство("ТочечноеЗадание") Тогда - ДобавитьВедущийОбъектКТочечномуЗаданию(ПараметрыЗадания.ТочечноеЗадание, - СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); - Иначе - ПерезапускОбновления = Истина; - Если Не ЭтоОбновлениеПрав И Строка.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата Тогда - ПерезапускОбновленияСНачала = Истина; - КонецЕсли; - Если ЕстьСвойстваКлючаДанных(ПараметрыЗадания) Тогда - Если СвойстваКлючаДанных.ПорядокВидаКлючаДанных > ПараметрыЗадания.ПорядокВидаКлючаДанных Тогда - СвойстваКлючаДанных.ПорядокВидаКлючаДанных = ПараметрыЗадания.ПорядокВидаКлючаДанных; - СвойстваКлючаДанных.ВидКлючаДанных = ПараметрыЗадания.ВидКлючаДанных; - КонецЕсли; - Если ЭтоОбработкаУстаревшихЭлементов(Новый Структура("ПоследнийОбновленныйЭлемент", ПараметрыЗадания)) Тогда - СвойстваКлючаДанных.ОбработатьУстаревшиеЭлементы = Истина; - КонецЕсли; - Если ПараметрыЗадания.Свойство("ОбработатьНаборыГруппСУстаревшимиПравами") - И ПараметрыЗадания.ОбработатьНаборыГруппСУстаревшимиПравами = Истина Тогда - СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; - КонецЕсли; - Иначе - ВидКлючаДанныхУстановлен = Ложь; - Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; - КонецЕсли; - Если ЭтоОбновлениеПрав Или ПерезапускОбновленияСНачала Тогда - Прервать; - КонецЕсли; - КонецЕсли; - КонецЕсли; - КонецЦикла; - - ПараметрыОбновления.ТочечноеЗадание = ПодготовленноеТочечноеЗадание( - ЭтоОбновлениеПрав, СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); - - Если ПерезапускОбновления Тогда - ПараметрыОбновления.ПерезапускОбновления = Истина; - Если ПерезапускОбновленияСНачала Тогда - ПараметрыОбновления.Вставить("ПерезапускОбновленияСНачала"); - КонецЕсли; - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = - НачальныйЭлемент(ПараметрыОбновления, , , ПерезапускОбновленияСНачала); - КонецЕсли; - - ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; - Если ВидКлючаДанныхУстановлен Тогда - Если ТекущийИтог = Неопределено Тогда - УстановитьВидКлючаДанных(ПоследнийОбновленныйЭлемент, СвойстваКлючаДанных.ВидКлючаДанных); - - ИначеЕсли ПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных > СвойстваКлючаДанных.ПорядокВидаКлючаДанных Тогда - ПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных = СвойстваКлючаДанных.ПорядокВидаКлючаДанных; - ПоследнийОбновленныйЭлемент.ВидКлючаДанных = СвойстваКлючаДанных.ВидКлючаДанных; - КонецЕсли; - КонецЕсли; - Если СвойстваКлючаДанных.ОбработатьУстаревшиеЭлементы Тогда - ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы = Истина; - КонецЕсли; - Если СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами Тогда - ПоследнийОбновленныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; - КонецЕсли; - СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент = ПоследнийОбновленныйЭлемент; - - Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда - РазмерЗадания = 1; - ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(Новый Структура("ПоследнийОбновленныйЭлемент", - ПоследнийОбновленныйЭлемент)) Тогда - РазмерЗадания = 2; - Иначе - РазмерЗадания = 3; - КонецЕсли; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "ВЫБРАТЬ ПЕРВЫЕ 1000", "ВЫБРАТЬ ПЕРВЫЕ 1"); // @query-part-1, @query-part-2 - ЗаданияУдалены = Ложь; - - ПланОбновления.Отбор.КлючУникальности.Установить(ПустойИдентификатор); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - РезультатЗапроса = Запрос.Выполнить(); - Если РезультатЗапроса.Пустой() Тогда - ЗаданияУдалены = Истина; - Иначе - Запись = ПланОбновления.Добавить(); - Запись.Список = ИдентификаторСписка; - Запись.ДляВнешнихПользователей = ДляВнешнихПользователей; - Запись.ТочечноеЗадание = ПараметрыОбновления.ТочечноеЗадание <> Неопределено; - Запись.ПараметрыЗадания = Новый ХранилищеЗначения(СохраняемыеПараметрыЗадания); - Запись.РазмерЗадания = РазмерЗадания; - Если Не ЭтоОбновлениеПрав Тогда - Запись.ДатаПоследнегоОбновленногоЭлемента = - ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата; - КонецЕсли; - Запись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); - ПланОбновления.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ЗаданияУдалены Тогда - ПараметрыОбновления.ЕстьЗадания = Ложь; - ПараметрыОбновления.ТочечноеЗадание = Неопределено; - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); - Возврат; - КонецЕсли; - - ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка) - -КонецПроцедуры - -// Для процедуры ПодготовитьПланОбновления. -Процедура ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка) - - Если Не ЗначениеЗаполнено(Выгрузка) Тогда - Возврат; - КонецЕсли; - - ПланОбновления.Очистить(); - - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено; - - Если ПакетныйРежим Тогда - Выгрузка.Колонки.Добавить("Список"); - Выгрузка.Колонки.Добавить("ДляВнешнихПользователей"); - Выгрузка.ЗаполнитьЗначения(ПланОбновления.Отбор.Список.Значение, "Список"); - Выгрузка.ЗаполнитьЗначения(ПланОбновления.Отбор.ДляВнешнихПользователей.Значение, "ДляВнешнихПользователей"); - ПланОбновления.Загрузить(Выгрузка); - ПланОбновления.Отбор.Список.Использование = Ложь; - ПланОбновления.Отбор.ДляВнешнихПользователей.Использование = Ложь; - ПланОбновления.Отбор.КлючУникальности.Использование = Ложь; - ПланОбновления.Записать(РежимУдаления); - Иначе - Для Каждого Строка Из Выгрузка Цикл - ПланОбновления.Отбор.КлючУникальности.Установить(Строка.КлючУникальности); - ПланОбновления.Записать(); - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПодготовитьПланОбновления. -Процедура ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка, НоваяВерсияДанныхДляКэша = Неопределено) - - ВерсияДанныхДляКэша = НоваяВерсияДанныхДляКэшаРасчетаПрав(); - - Для Каждого Строка Из Выгрузка Цикл - ПараметрыЗадания = Строка.ПараметрыЗадания.Получить(); - Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") - Или Не ПараметрыЗадания.Свойство("ТочечноеЗадание") - Или ТипЗнч(ПараметрыЗадания.ТочечноеЗадание) <> Тип("Структура") - Или Не ПараметрыЗадания.ТочечноеЗадание.Свойство("ПоДаннымКэшаРасчетаПрав") Тогда - Продолжить; - КонецЕсли; - ИмяИзмененныхДанных = ПараметрыЗадания.ТочечноеЗадание.ПоДаннымКэшаРасчетаПрав; - ОбработатьЗаданиеОбновленияКэшаРасчетаПрав(ВерсияДанныхДляКэша, - ИмяИзмененныхДанных, Строка.КлючУникальности); - КонецЦикла; - - ИмяПараметра = ИмяПараметраВерсииДанныхДляКэшаРасчетаПрав(); - - Если НоваяВерсияДанныхДляКэша = Неопределено Тогда - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); - ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); - ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ТекущееЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - НовоеЗначение = НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша); - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - Иначе - ТекущееЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); - НоваяВерсияДанныхДляКэша = НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша, Ложь); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. -Процедура ОбработатьЗаданиеОбновленияКэшаРасчетаПрав(ВерсияДанныхДляКэша, ИмяИзмененныхДанных, КлючУникальности) - - Если ТипЗнч(ИмяИзмененныхДанных) <> Тип("Строка") - Или Не ВерсияДанныхДляКэша.Свойство(ИмяИзмененныхДанных) Тогда - - Для Каждого КлючИЗначение Из ВерсияДанныхДляКэша Цикл - ВерсияДанныхДляКэша[КлючИЗначение.Ключ] = Строка(Новый УникальныйИдентификатор); - КонецЦикла; - Возврат; - КонецЕсли; - - Если ТипЗнч(ВерсияДанныхДляКэша[ИмяИзмененныхДанных]) = Тип("Строка") Тогда - Возврат; - КонецЕсли; - - Если ВерсияДанныхДляКэша[ИмяИзмененныхДанных] = Неопределено Тогда - ВерсияДанныхДляКэша[ИмяИзмененныхДанных] = Новый ХешированиеДанных(ХешФункция.SHA256); - КонецЕсли; - - ХешированиеДанных = ВерсияДанныхДляКэша[ИмяИзмененныхДанных]; // ХешированиеДанных - ХешированиеДанных.Добавить(Строка(КлючУникальности)); - -КонецПроцедуры - -// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. -Функция НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша, ДляЗаписи = Истина) - - НовоеЗначение = НоваяВерсияДанныхДляКэшаРасчетаПрав(); - - Если ТипЗнч(ТекущееЗначение) = Тип("Структура") Тогда - ЗаполнитьЗначенияСвойств(НовоеЗначение, ТекущееЗначение); - КонецЕсли; - - Для Каждого КлючИЗначение Из ВерсияДанныхДляКэша Цикл - Если КлючИЗначение.Значение = Неопределено Тогда - Продолжить; - КонецЕсли; - Если ТипЗнч(КлючИЗначение.Значение) = Тип("ХешированиеДанных") Тогда - НовоеЗначение[КлючИЗначение.Ключ] = Base64Строка(КлючИЗначение.Значение.ХешСумма); - Иначе - НовоеЗначение[КлючИЗначение.Ключ] = КлючИЗначение.Значение; - КонецЕсли; - КонецЦикла; - - Для Каждого КлючИЗначение Из НовоеЗначение Цикл - Если КлючИЗначение.Значение <> Неопределено Тогда - Продолжить; - КонецЕсли; - НовоеЗначение[КлючИЗначение.Ключ] = ?(ДляЗаписи, - Строка(Новый УникальныйИдентификатор), "00000000-0000-0000-0000-000000000000"); - КонецЦикла; - - Возврат НовоеЗначение; - -КонецФункции - -// Для функции КэшРасчетаПравДляВидаПользователей. -Функция ВерсияДанныхДляКэшаРасчетаПрав() - - ИдентификаторСпискаПланирования = ОбщегоНазначения.ИдентификаторОбъектаМетаданных( - СписокДляПланированияОбновленияКэшаРасчетаПрав()); - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Список", ИдентификаторСпискаПланирования); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1000 - | КлючиУникальности.КлючУникальности КАК КлючУникальности, - | КлючиУникальности.ПараметрыЗадания КАК ПараметрыЗадания - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК КлючиУникальности - |ГДЕ - | КлючиУникальности.Список = &Список - | И КлючиУникальности.ДляВнешнихПользователей = ЛОЖЬ - | - |УПОРЯДОЧИТЬ ПО - | КлючиУникальности.Список, - | КлючиУникальности.ДляВнешнихПользователей, - | КлючиУникальности.КлючУникальности"; - - Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); - КонецЕсли; - - Выгрузка = Запрос.Выполнить().Выгрузить(); - - ВерсияДанныхДляКэша = Новый Структура; - ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка, ВерсияДанныхДляКэша); - - Возврат ВерсияДанныхДляКэша; - -КонецФункции - -// Для процедуры ПодготовитьПланОбновления, ЗаписатьПоследнийОбновленныйЭлемент. -// -// Возвращаемое значение: -// Структура: -// * ПоследнийОбновленныйЭлемент - см. НачальныйЭлемент -// * ТочечноеЗадание - Структура: -// ** ПоКлючамДоступа - Соответствие -// ** ПоЗначениямПолей - Соответствие -// ** ПоЗначениямСГруппами - Соответствие -// -Функция СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ПараметрыОбновления, ПараметрыЗадания = Неопределено, - ПерезапускОбновления = Ложь, ОчиститьТочечноеЗадание = Ложь) - - ТочечноеЗадание = Новый Структура; - ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый Соответствие); - Если Не ЭтоОбновлениеПрав Тогда - ТочечноеЗадание.Вставить("ПоЗначениямПолей", Новый Соответствие); - ТочечноеЗадание.Вставить("ПоЗначениямСГруппами", Новый Соответствие); - КонецЕсли; - - СохраняемыеПараметры = Новый Структура; - СохраняемыеПараметры.Вставить("ТочечноеЗадание", ТочечноеЗадание); - СохраняемыеПараметры.Вставить("ПоследнийОбновленныйЭлемент", НачальныйЭлемент(ПараметрыОбновления)); - - Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") Тогда - Возврат СохраняемыеПараметры; - КонецЕсли; - - Если ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") Тогда - Порядок = ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных); - Если Порядок <> Неопределено Тогда - ЗаполнитьЗначенияСвойств(СохраняемыеПараметры.ПоследнийОбновленныйЭлемент, - ПараметрыЗадания.ПоследнийОбновленныйЭлемент); - КонецЕсли; - КонецЕсли; - - Если ОчиститьТочечноеЗадание Или Не ПараметрыЗадания.Свойство("ТочечноеЗадание") Тогда - Возврат СохраняемыеПараметры; - КонецЕсли; - - ТекущееТочечноеЗадание = ПараметрыЗадания.ТочечноеЗадание; - Если ТипЗнч(ТекущееТочечноеЗадание) <> Тип("Структура") Тогда - ПерезапускОбновления = Истина; - Возврат СохраняемыеПараметры; - КонецЕсли; - - Для Каждого ВариантЗадания Из ТочечноеЗадание Цикл - Если Не ТекущееТочечноеЗадание.Свойство(ВариантЗадания.Ключ) - Или ТипЗнч(ТекущееТочечноеЗадание[ВариантЗадания.Ключ]) <> Тип("Соответствие") Тогда - ПерезапускОбновления = Истина; - Продолжить; - КонецЕсли; - ТочечноеЗадание[ВариантЗадания.Ключ] = ТекущееТочечноеЗадание[ВариантЗадания.Ключ]; - КонецЦикла; - - Возврат СохраняемыеПараметры; - -КонецФункции - -// Для процедуры ПодготовитьПланОбновления. -Процедура ДобавитьВедущийОбъектКТочечномуЗаданию(ТочечноеЗадание, СохраняемоеТочечноеЗадание, - ПерезапускОбновления) - - Если ТипЗнч(ТочечноеЗадание) <> Тип("Структура") Тогда - ПерезапускОбновления = Истина; - Возврат; - КонецЕсли; - МаксимальноеКоличество = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); - - Для Каждого ВариантЗадания Из ТочечноеЗадание Цикл - Если Не СохраняемоеТочечноеЗадание.Свойство(ВариантЗадания.Ключ) Тогда - ПерезапускОбновления = Истина; - Продолжить; - КонецЕсли; - Если ВариантЗадания.Ключ <> "ПоЗначениямПолей" Тогда - Ссылки = ?(ТипЗнч(ВариантЗадания.Значение) = Тип("Массив"), ВариантЗадания.Значение, - ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ВариантЗадания.Значение)); - СохраняемыеСсылки = СохраняемоеТочечноеЗадание[ВариантЗадания.Ключ]; - Для Каждого Ссылка Из Ссылки Цикл - СохраняемыеСсылки.Вставить(Ссылка, Истина); - Если СохраняемыеСсылки.Количество() >= МаксимальноеКоличество Тогда - ПерезапускОбновления = Истина; - Продолжить; - КонецЕсли; - КонецЦикла; - Иначе - Свойства = ВариантЗадания.Значение; - СохраняемыеТаблицы = СохраняемоеТочечноеЗадание[ВариантЗадания.Ключ]; - - Если Не Свойства.Свойство("ИзмененнаяТаблица") - Или Не Свойства.Свойство("СоставИзменений") - Или ТипЗнч(Свойства.СоставИзменений) <> Тип("ТаблицаЗначений") - Или ТипЗнч(СохраняемыеТаблицы) <> Тип("Соответствие") Тогда - - ПерезапускОбновления = Истина; - Продолжить; - КонецЕсли; - СохраняемаяТаблица = СохраняемыеТаблицы.Получить(Свойства.ИзмененнаяТаблица); - СоставИзменений = Свойства.СоставИзменений; - Если СохраняемаяТаблица = Неопределено Тогда - СохраняемыеТаблицы.Вставить(Свойства.ИзмененнаяТаблица, СоставИзменений); - - ИначеЕсли ТипЗнч(СохраняемаяТаблица) <> Тип("ТаблицаЗначений") - Или СоставИзменений.Колонки.Количество() <> СохраняемаяТаблица.Колонки.Количество() Тогда - - ПерезапускОбновления = Истина; - Продолжить; - Иначе - ИменаКолонок = Новый Массив; - Для Каждого Колонка Из СохраняемаяТаблица.Колонки Цикл - Если СоставИзменений.Колонки.Найти(Колонка.Имя) = Неопределено Тогда - ИменаКолонок = Неопределено; - Прервать; - КонецЕсли; - ИменаКолонок.Добавить(Колонка.Имя); - КонецЦикла; - Если ИменаКолонок = Неопределено Тогда - ПерезапускОбновления = Истина; - Продолжить; - КонецЕсли; - СписокИменКолонок = СтрСоединить(ИменаКолонок, ","); - Отбор = Новый Структура(СписокИменКолонок); - Если СохраняемаяТаблица.Индексы.Количество() = 0 Тогда - СохраняемаяТаблица.Индексы.Добавить(СписокИменКолонок); - КонецЕсли; - Для Каждого Строка Из СоставИзменений Цикл - ЗаполнитьЗначенияСвойств(Отбор, Строка); - Если СохраняемаяТаблица.НайтиСтроки(Отбор).Количество() = 0 Тогда - Если СохраняемаяТаблица.Количество() >= МаксимальноеКоличество Тогда - ПерезапускОбновления = Истина; - Прервать; - КонецЕсли; - ЗаполнитьЗначенияСвойств(СохраняемаяТаблица.Добавить(), Строка); - КонецЕсли; - КонецЦикла; - КонецЕсли; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ПодготовитьПланОбновления. -Функция ЕстьСвойстваКлючаДанных(ПараметрыЗадания) - - Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") - Или Не ПараметрыЗадания.Свойство("ВидКлючаДанных") - Или Не ПараметрыЗадания.Свойство("ПорядокВидаКлючаДанных") Тогда - Возврат Ложь; - КонецЕсли; - - Порядок = ПорядокВидаКлючаДанных(ПараметрыЗадания.ВидКлючаДанных); - - Возврат Порядок <> Неопределено И Порядок = ПараметрыЗадания.ПорядокВидаКлючаДанных; - -КонецФункции - -// Для процедур ВыполнитьОбновлениеДоступаСписка, ОбновитьПорциюЭлементов, -// УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных, ОбновитьНаборыГруппДоступа и -// функций ЭлементыДляОбновления, ПоследнийЭлемент, КлючДанных, НаборыГруппДоступаДляОбновления. -// -Функция ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) - - Порядок = ПорядокВидаКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных); - - Возврат Порядок >= ПорядокВидаКлючаДанных("УстаревшиеЭлементы") - И Порядок < ПорядокВидаКлючаДанных("НетДанных"); - -КонецФункции - -// Для функций СохраняемыеПараметрыЗадания, ЕстьСвойстваКлючаДанных и -// процедур ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов, УстановитьВидКлючаДанных. -// -Функция ПорядокВидаКлючаДанных(ВидКлючаДанных) - - ВидыКлючейДанных = Новый Соответствие; - ВидыКлючейДанных.Вставить("ЭлементыСУстаревшимиКлючами", 0); - ВидыКлючейДанных.Вставить("ЭлементыБезКлючейПоЗначениямПолей", 1); - ВидыКлючейДанных.Вставить("ЭлементыБезКлючейПоПериоду", 1); - - ВидыКлючейДанных.Вставить("ЭлементыСУстаревшимиПравами", 0); - - ВидыКлючейДанных.Вставить("НовыеНаборыИзОдногоПользователя", 0); - ВидыКлючейДанных.Вставить("НаборыГруппДоступаНазначенныеПользователям", 1); - ВидыКлючейДанных.Вставить("НаборыГруппПользователейНазначенныеПользователям", 2); - ВидыКлючейДанных.Вставить("НовыеНаборыГруппСУстаревшимиПравами", 3); - ВидыКлючейДанных.Вставить("НаборыГруппРазрешенныеПользователям", 4); - ВидыКлючейДанных.Вставить("НаборыГруппСУстаревшимиПравами", 5); - - ВидыКлючейДанных.Вставить("УстаревшиеЭлементы", 10); - ВидыКлючейДанных.Вставить("НекорректныеЭлементы", 11); - ВидыКлючейДанных.Вставить("НекорректныеЭлементыОбщегоРегистра", 12); - - ВидыКлючейДанных.Вставить("НетДанных", 99); - - Возврат ВидыКлючейДанных.Получить(ВидКлючаДанных); - -КонецФункции - -// Для процедур ЗапланироватьОбновлениеДоступа, ЗапланироватьОбновлениеНаборовГруппДоступа, -// УточнитьПустойПоследнийЭлемент и функции НачальныйЭлемент. -// -Процедура УстановитьВидКлючаДанных(Элемент, ВидКлючаДанных) - - Порядок = ПорядокВидаКлючаДанных(ВидКлючаДанных); - Если Порядок = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректный имя вида порядка ключа данных ""%1""'"), ВидКлючаДанных); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Элемент.Вставить("ВидКлючаДанных", ВидКлючаДанных); - Элемент.Вставить("ПорядокВидаКлючаДанных", Порядок); - -КонецПроцедуры - -// Для процедуры ПодготовитьПланОбновления. -Функция ПодготовленноеТочечноеЗадание(ЭтоОбновлениеПрав, СохраняемоеТочечноеЗадание, ПерезапускОбновления) - - ТочечноеЗадание = Новый Структура; - Если ЭтоОбновлениеПрав Тогда - ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый Массив); - Иначе - ТочечноеЗадание.Вставить("ПоЗначениямПолей", Новый Соответствие); - ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый ТаблицаЗначений); - ТочечноеЗадание.Вставить("ПоЗначениямСГруппами", Новый ТаблицаЗначений); - КонецЕсли; - - ЭтоПустоеЗадание = Истина; - МаксимальноеКоличество = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); - ТипыВедущихОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТиповСсылокВедущихОбъектов(); - - Для Каждого ВариантЗадания Из СохраняемоеТочечноеЗадание Цикл - Если ВариантЗадания.Ключ = "ПоЗначениямПолей" Тогда - Если ЗначениеЗаполнено(ВариантЗадания.Значение) Тогда - ЭтоПустоеЗадание = Ложь; - ТочечноеЗадание.ПоЗначениямПолей = ВариантЗадания.Значение; - КонецЕсли; - Продолжить; - КонецЕсли; - - УдаляемыеСсылки = Новый Массив; - ОписаниеСсылок = ВариантЗадания.Значение; - Если ЭтоОбновлениеПрав Тогда - Ссылки = ТочечноеЗадание[ВариантЗадания.Ключ]; - Иначе - Ссылки = Новый Массив; - Типы = Новый Соответствие; - Таблица = ТочечноеЗадание[ВариантЗадания.Ключ]; // ТаблицаЗначений - КонецЕсли; - Для Каждого ОписаниеСсылки Из ОписаниеСсылок Цикл - Ссылка = ОписаниеСсылки.Ключ; - Тип = ТипЗнч(Ссылка); - Если ТипыВедущихОбъектов.Получить(Тип) = Неопределено Тогда - ПерезапускОбновления = Истина; - УдаляемыеСсылки.Добавить(Ссылка); - Продолжить; - КонецЕсли; - Ссылки.Добавить(Ссылка); - Если Не ЭтоОбновлениеПрав Тогда - Типы.Вставить(Тип, Истина); - Таблица.Добавить(); - КонецЕсли; - Если Ссылки.Количество() >= МаксимальноеКоличество Тогда - ПерезапускОбновления = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - Для Каждого Ссылка Из УдаляемыеСсылки Цикл - ОписаниеСсылок.Удалить(Ссылка); - КонецЦикла; - Если Ссылки.Количество() > 0 Тогда - ЭтоПустоеЗадание = Ложь; - Иначе - Продолжить; - КонецЕсли; - Если Не ЭтоОбновлениеПрав Тогда - ТипыКолонки = Новый Массив; - Для Каждого КлючИЗначение Из Типы Цикл - ТипыКолонки.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - Таблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов(ТипыКолонки)); - Таблица.ЗагрузитьКолонку(Ссылки, "Ссылка"); - КонецЕсли; - КонецЦикла; - - Если ЭтоПустоеЗадание Тогда - Возврат Неопределено; - КонецЕсли; - - Возврат ТочечноеЗадание; - -КонецФункции - -// Для процедура ВыполнитьОбновлениеДоступаСписка. -Функция КоличествоЭлементовВПорции(ПараметрыОбновления) - - Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - Возврат 25; - ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Возврат КоличествоКлючейДоступаВПорции(); - Иначе - Возврат КоличествоЭлементовДанныхВПорции(); - КонецЕсли; - -КонецФункции - -// Для процедура ВыполнитьОбновлениеДоступаСписка. -Функция КоличествоЭлементовВЗапросе(ЭтоОбновлениеПрав) - - Если ЭтоОбновлениеПрав Тогда - Возврат КоличествоКлючейДоступаВЗапросе(); - Иначе - Возврат КоличествоЭлементовДанныхВЗапросе(); - КонецЕсли; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления, ЭтоТочечноеЗадание = Ложь) - - ПараметрыОбновления.Вставить("КоличествоОбработанныхЭлементов", 0); - - Если ЭтоТочечноеЗадание Тогда - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - ОбновитьПраваПорцииКлючейДоступаСписка(Элементы, ПараметрыОбновления); - Иначе - ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(Элементы, ПараметрыОбновления); - КонецЕсли; - - ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - ОбработатьУстаревшиеКлючиДоступаСписка(Элементы, ПараметрыОбновления); - Иначе - ОбновитьПраваПорцииКлючейДоступаСписка(Элементы, ПараметрыОбновления); - КонецЕсли; - - ИначеЕсли ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - ОбновитьНаборыГруппДоступа(Элементы, ПараметрыОбновления); - - ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - УдалитьУстаревшиеЭлементыДанныхСписка(Элементы, ПараметрыОбновления); - Иначе - ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(Элементы, ПараметрыОбновления); - КонецЕсли; - - Если Не ЭтоТочечноеЗадание И Элементы.Количество() > 0 Тогда - ПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", - ПоследнийЭлемент(Элементы, ПараметрыОбновления, Истина)); - КонецЕсли; - - Если Элементы.Количество() = ПараметрыОбновления.КоличествоОбработанныхЭлементов Тогда - Элементы = Неопределено; - Иначе - Для Счетчик = 1 По ПараметрыОбновления.КоличествоОбработанныхЭлементов Цикл - Элементы.Удалить(0); - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для процедур ОбновитьНаборыГруппДоступа, УдалитьУстаревшиеЭлементыДанныхСписка, -// ЗаписатьКлючиДоступаОбъектов, ЗаписатьКлючиДоступаРегистров, -// ОбновитьПраваПорцииКлючейДоступаСписка, УдалитьПорциюКлючейДоступаСписка, -// УдалитьТекущуюПорциюКлючейДоступаСписка. -// -Функция ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанныхНаШаге = 1) - - Если Не ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") - Или Не ПараметрыОбновления.Свойство("ГраницаВремениОбработки") Тогда - Возврат Ложь; - КонецЕсли; - - ПараметрыОбновления.КоличествоОбработанныхЭлементов = - ПараметрыОбновления.КоличествоОбработанныхЭлементов + КоличествоОбработанныхНаШаге; - - Если ТекущаяУниверсальнаяДатаВМиллисекундах() > ПараметрыОбновления.ГраницаВремениОбработки Тогда - Возврат Истина; - КонецЕсли; - - Возврат Ложь; - -КонецФункции - -// Для процедур ВыполнитьОбновлениеДоступаСписка, ПроверитьЗавершитьОбновлениеПоПорциям. -Процедура ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, ПоследнийОбновленныйЭлемент) - - ЭтоОбновлениеПрав = ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав; - ДляВнешнихПользователей = ОбщиеПараметрыОбновления.ДляВнешнихПользователей; - ИдентификаторСписка = ОбщиеПараметрыОбновления.ИдентификаторСписка; - - МенеджерРегистра = ?(ЭтоОбновлениеПрав, РегистрыСведений.ОбновлениеКлючейДоступаПользователей, - РегистрыСведений.ОбновлениеКлючейДоступаКДанным); - - ПланОбновления = СлужебныйНаборЗаписей(МенеджерРегистра); - ПланОбновления.Отбор.Список.Установить(ИдентификаторСписка); - ПланОбновления.Отбор.ДляВнешнихПользователей.Установить(ДляВнешнихПользователей); - ПланОбновления.Отбор.КлючУникальности.Установить( - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - ПолноеИмяРегистра = ?(ЭтоОбновлениеПрав, "РегистрСведений.ОбновлениеКлючейДоступаПользователей", - "РегистрСведений.ОбновлениеКлючейДоступаКДанным"); - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); - ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); - ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); - ЭлементБлокировки.УстановитьЗначение("КлючУникальности", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - ПланОбновления.Прочитать(); - Если ПланОбновления.Количество() > 0 Тогда - Если ПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда - ПланОбновления.Очистить(); - Иначе - Запись = ПланОбновления[0]; - Если ПоследнийОбновленныйЭлемент.Свойство("ОчиститьТочечноеЗадание") Тогда - Запись.ТочечноеЗадание = Ложь; - КонецЕсли; - - ТекущиеПараметрыЗадания = Запись.ПараметрыЗадания.Получить(); - ПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ОбщиеПараметрыОбновления, - ТекущиеПараметрыЗадания, , ПоследнийОбновленныйЭлемент.Свойство("ОчиститьТочечноеЗадание")); - - ЗаполнитьЗначенияСвойств(ПараметрыЗадания.ПоследнийОбновленныйЭлемент, ПоследнийОбновленныйЭлемент); - - Если Не ЭтоОбновлениеПрав И ПоследнийОбновленныйЭлемент.Свойство("Дата") Тогда - Запись.ДатаПоследнегоОбновленногоЭлемента = ПоследнийОбновленныйЭлемент.Дата; - КонецЕсли; - - Запись.ПараметрыЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); - Запись.РазмерЗадания = ?(ЭтоОбработкаУстаревшихЭлементов( - Новый Структура("ПоследнийОбновленныйЭлемент", ПоследнийОбновленныйЭлемент)), 2, 3); - - Запись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); - ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; - КонецЕсли; - ПланОбновления.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Функция ЭлементыДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы) - - Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - ВыбраныВсеЭлементы = Истина; - Возврат Неопределено; - КонецЕсли; - Элементы = НаборыГруппДоступаДляОбновления(ПараметрыОбновления, КоличествоВЗапросе); - Иначе - Запрос = Новый Запрос; - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); - - ПоследнийКлючДоступа = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных; - Если ТипЗнч(ПоследнийКлючДоступа) <> Тип("СправочникСсылка.КлючиДоступа") Тогда - ПоследнийКлючДоступа = Неопределено; - КонецЕсли; - Запрос.УстановитьПараметр("ПоследнийКлючДоступа", ПоследнийКлючДоступа); - - Если ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда - // Для режима ЭтоОчисткаВыбранныхКлючей в процедуре ОбработатьУстаревшиеКлючиДоступаСписка. - // Переключение на шаг УстаревшиеЭлементы выполняется в процедуре УточнитьПоследнийОбновленныйЭлемент. - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Список = &Список - | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступа.Ссылка"; - - ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - Если ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей Тогда - // Для режима ЭтоОчисткаВыбранныхКлючей в процедуре ОбработатьУстаревшиеКлючиДоступаСписка. - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Список = &Список - | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И КлючиДоступа.СоставПолей > 0 - | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступа.Ссылка"; - Иначе - Запрос.УстановитьПараметр("ДатаУстаревания", ДатаУстаревания()); - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаУстаревшихКлючейДоступа; - КонецЕсли; - Иначе - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаКлючейДоступаДляОбновленияПрав; - КонецЕсли; - Иначе - УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных(Запрос, ПараметрыОбновления); - КонецЕсли; - - Если Запрос.Текст = ПризнакПустогоЗапроса() Тогда - ВыбраныВсеЭлементы = Истина; - Возврат Неопределено; - - ИначеЕсли Запрос.Текст = ПризнакИтерационногоЗапроса() Тогда - Возврат ИтерационнаяВыборкаЭлементовДляОбновления(Запрос, - ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы, Неопределено); - Иначе - КоличествоВЗапросе = ?(КоличествоВЗапросе < 1000, 1000, ?(КоличествоВЗапросе > 10000, 10000, КоличествоВЗапросе)); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - - Элементы = Запрос.Выполнить().Выгрузить(); - КонецЕсли; - КонецЕсли; - - Если Элементы.Количество() = 0 Тогда - ВыбраныВсеЭлементы = Истина; - Возврат Неопределено; - КонецЕсли; - - ВыбраныВсеЭлементы = Элементы.Количество() < КоличествоВЗапросе; - - Возврат Элементы; - -КонецФункции - -// Для функции ЭлементыДляОбновления и процедур -// УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных, -// УстановитьОбработкуУстаревшихДанных, -// ДобавитьТекстЗапросаУстаревшихЭлементовДанных. -// -Функция ПризнакПустогоЗапроса() - Возврат "НетЭлементов"; -КонецФункции - -// Для функции ЭлементыДляОбновления и -// процедуры УстановитьПустойПоследнийЭлемент. -// -Функция ПризнакИтерационногоЗапроса() - Возврат "*"; -КонецФункции - -// Для функции ЭлементыДляОбновления. -Функция ИтерационнаяВыборкаЭлементовДляОбновления(Запрос, ПараметрыОбновления, КоличествоВЗапросе, - ВыбраныВсеЭлементы, КоличествоЗапрошенныхЭлементов) - - КоличествоЭлементов = 500; // Начальное количество элементов данных в диапазоне. - ТекстЗапросаДиапазона = ПараметрыОбновления.ТекстЗапросаДиапазонаЭлементовДанных; - ТекстЗапросаЭлементовДанных = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами; - - // Подготовка запроса получения первой границы диапазона. - Если ПараметрыОбновления.СписокСДатой Тогда - Запрос.УстановитьПараметр("ДатаОкончанияДиапазона", Запрос.Параметры.ДатаОкончания); - ТекстЗапросаДиапазона = СтрЗаменить(ТекстЗапросаДиапазона, - "ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона", "ИСТИНА"); // @query-part-1 - ТекстЗапросаЭлементовДанных = СтрЗаменить(ТекстЗапросаЭлементовДанных, - "ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона", "ИСТИНА"); // @query-part-1 - - ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда - Запрос.УстановитьПараметр("СсылкаНачалаДиапазона", Запрос.Параметры.ПоследняяОбработаннаяСсылка); - Иначе - Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл - НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); - ИмяПоля = СтрШаблон("Поле%1НачалаДиапазона", НомерПоля); - Если КлючИЗначение.Значение = Неопределено Тогда - ТекстЗапросаДиапазона = СтрЗаменить(ТекстЗапросаДиапазона, - " > &" + ИмяПоля, " >= &" + ИмяПоля); - ТекстЗапросаЭлементовДанных = СтрЗаменить(ТекстЗапросаЭлементовДанных, - " > &" + ИмяПоля, " >= &" + ИмяПоля); - КонецЕсли; - Запрос.УстановитьПараметр(ИмяПоля, КлючИЗначение.Значение); - КонецЦикла; - КонецЕсли; - - Элементы = Неопределено; - - Пока Истина Цикл - // Получение очередной границы диапазона. - Запрос.Текст = СтрЗаменить(ТекстЗапросаДиапазона, "993", Формат(КоличествоЭлементов, "ЧГ=")); - ТекущийТекстЗапросаДиапазона = Запрос.Текст; - Выгрузка = Запрос.Выполнить().Выгрузить(); - Если Не ЗначениеЗаполнено(Выгрузка) Тогда - ВыбраныВсеЭлементы = Истина; - Прервать; - КонецЕсли; - Если КоличествоЗапрошенныхЭлементов <> Неопределено Тогда - КоличествоЗапрошенныхЭлементов.Добавить(КоличествоЭлементов); - КонецЕсли; - Для Каждого Колонка Из Выгрузка.Колонки Цикл - Запрос.УстановитьПараметр(Колонка.Имя, Выгрузка[0][Колонка.Имя]); - КонецЦикла; - - // Получение элементов с устаревшими ключами из диапазона. - Запрос.Текст = СтрЗаменить(ТекстЗапросаЭлементовДанных, "993", Формат(КоличествоЭлементов, "ЧГ=")); - - МоментНачала = ТекущаяУниверсальнаяДатаВМиллисекундах(); - ТекущиеЭлементы = Запрос.Выполнить().Выгрузить(); - ВремяЗапроса = ТекущаяУниверсальнаяДатаВМиллисекундах() - МоментНачала; - - // Перерасчет количества элементов в диапазоне. - Если ВремяЗапроса < 1000 Тогда - КоличествоЭлементов = КоличествоЭлементов * Цел((1050 - ВремяЗапроса) / 50); - ИначеЕсли ВремяЗапроса > 2000 Тогда - КоличествоЭлементов = КоличествоЭлементов / 2; - КонецЕсли; - КоличествоЭлементов = (1 + Цел((КоличествоЭлементов - 1) / 500)) * 500; - Если КоличествоЭлементов > 10000 Тогда - КоличествоЭлементов = 10000; - КонецЕсли; - Если КоличествоЭлементов < 500 Тогда - КоличествоЭлементов = 500; - КонецЕсли; - - // Проверка неизменности текущего диапазона. - Запрос.Текст = ТекущийТекстЗапросаДиапазона; - Выгрузка = Запрос.Выполнить().Выгрузить(); - ДиапазонИзменился = Ложь; - Для Каждого Колонка Из Выгрузка.Колонки Цикл - Если Запрос.Параметры[Колонка.Имя] <> Выгрузка[0][Колонка.Имя] Тогда - ДиапазонИзменился = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - Если ДиапазонИзменился Тогда - Запрос.Текст = СтрЗаменить(ТекстЗапросаЭлементовДанных, "ПЕРВЫЕ 993", ""); - ТекущиеЭлементы = Запрос.Выполнить().Выгрузить(); - КонецЕсли; - - ПоследнийТекущийЭлемент = Неопределено; - Если ЗначениеЗаполнено(ТекущиеЭлементы) Тогда - Если Элементы = Неопределено Тогда - Элементы = ТекущиеЭлементы; - Иначе - Для Каждого ТекущийЭлемент Из ТекущиеЭлементы Цикл - ЗаполнитьЗначенияСвойств(Элементы.Добавить(), ТекущийЭлемент); - КонецЦикла; - КонецЕсли; - ПоследнийТекущийЭлемент = ТекущиеЭлементы[ТекущиеЭлементы.Количество() - 1]; - КонецЕсли; - - Если Элементы <> Неопределено - И Элементы.Количество() >= КоличествоВЗапросе - Или ТекущаяУниверсальнаяДатаВМиллисекундах() > ПараметрыОбновления.ГраницаВремениОбработки - И (ЗначениеЗаполнено(Элементы) - Или Не ПараметрыОбновления.СписокСДатой - Или Запрос.Параметры.ДатаОкончания > Запрос.Параметры.ДатаНачалаДиапазона) Тогда - - Прервать; - КонецЕсли; - - // Подготовка запроса следующей границы диапазона. - ТекстЗапросаДиапазона = ПараметрыОбновления.ТекстЗапросаДиапазонаЭлементовДанных; - ТекстЗапросаЭлементовДанных = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами; - - Если ПараметрыОбновления.СписокСДатой Тогда - Запрос.УстановитьПараметр("ДатаОкончанияДиапазона", Запрос.Параметры.ДатаНачалаДиапазона); - Запрос.УстановитьПараметр("СсылкаДатыОкончанияДиапазона", Запрос.Параметры.СсылкаДатыНачалаДиапазона); - - ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда - Запрос.УстановитьПараметр("СсылкаНачалаДиапазона", Запрос.Параметры.СсылкаОкончанияДиапазона); - Иначе - Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл - НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); - ИмяПоляНачала = СтрШаблон("Поле%1НачалаДиапазона", НомерПоля); - ИмяПоляОкончания = СтрШаблон("Поле%1ОкончанияДиапазона", НомерПоля); - ЗначениеПоляОкончания = Запрос.Параметры[ИмяПоляОкончания]; - Запрос.УстановитьПараметр(ИмяПоляНачала, ЗначениеПоляОкончания); - КонецЦикла; - КонецЕсли; - КонецЦикла; - - Если ВыбраныВсеЭлементы Или ЗначениеЗаполнено(Элементы) Тогда - Возврат Элементы; - КонецЕсли; - - КоличествоВЗапросе = Null; - - // Подготовка обработанного элемента для продвижения указателя. - Элементы = ТекущиеЭлементы; - Элемент = Элементы.Добавить(); - - Если ПараметрыОбновления.СписокСДатой Тогда - Элемент.Дата = Запрос.Параметры.ДатаНачалаДиапазона; - - ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда - Элемент.ТекущаяСсылка = Запрос.Параметры.СсылкаОкончанияДиапазона; - Иначе - Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл - НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); - ИмяПоляОкончания = СтрШаблон("Поле%1ОкончанияДиапазона", НомерПоля); - Элемент[КлючИЗначение.Ключ] = Запрос.Параметры[ИмяПоляОкончания]; - КонецЦикла; - КонецЕсли; - - Возврат Элементы; - -КонецФункции - -// Для процедур выполнения запросов. -Процедура УстановитьУточнениеПланаЗапроса(ТекстЗапроса, УникальныйПлан = Ложь) - - Если УправлениеДоступомСлужебныйПовтИсп.ТребуетсяУточнениеПланаЗапроса() Тогда - Если УникальныйПлан Тогда - ТекущаяДатаСеанса = ТекущаяДатаСеанса(); - ВсегоМинут = Цел((ТекущаяДатаСеанса - '00010101') / 60); - ОстатокМинут = ВсегоМинут - Цел(ВсегоМинут / 2048) * 2048; - УточнениеПланаЗапроса = УправлениеДоступомСлужебныйПовтИсп.УточнениеПланаЗапроса(ОстатокМинут, 11); - Иначе - ТочноеВремя = ТекущаяУниверсальнаяДатаВМиллисекундах(); - ВсегоДесятыхСекунд = Цел(ТочноеВремя / 100); - ОстатокДесятыхСекунд = ВсегоДесятыхСекунд - Цел(ВсегоДесятыхСекунд / 1048576) * 1048576; - УточнениеПланаЗапроса = УправлениеДоступомСлужебныйПовтИсп.УточнениеПланаЗапроса(ОстатокДесятыхСекунд, 20); - КонецЕсли; - Иначе - УточнениеПланаЗапроса = "ИСТИНА"; - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УточнениеПланаЗапроса", УточнениеПланаЗапроса); - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Функция ЭлементыТочечногоЗаданияДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы) - - Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) - Или ПараметрыОбновления.БезЗаписиКлючейДоступа - Или ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей Тогда - - Возврат Неопределено; - КонецЕсли; - - Запрос = Новый Запрос; - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав; - Если Не ЗначениеЗаполнено(Запрос.Текст) Тогда - Возврат Неопределено; - КонецЕсли; - Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); - Запрос.УстановитьПараметр("ВедущиеКлючиДоступа", ПараметрыОбновления.ТочечноеЗадание.ПоКлючамДоступа); - Иначе - Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда - Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); - КонецЕсли; - ОписаниеЗапросов = ПараметрыОбновления.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам; - ЗапросыПакета = Новый Массив; - ЗапросыДанных = Новый Массив; - Если ЗначениеЗаполнено(ПараметрыОбновления.ТочечноеЗадание.ПоЗначениямПолей) Тогда - ОписаниеЗапросовПоЗначениямПолей = ОписаниеЗапросов.Получить("ПоЗначениямПолей"); - Если ОписаниеЗапросовПоЗначениямПолей = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - Для Каждого ОписаниеИзменений Из ПараметрыОбновления.ТочечноеЗадание.ПоЗначениямПолей Цикл - ОписаниеЗапроса = ОписаниеЗапросовПоЗначениямПолей.Получить(ОписаниеИзменений.Ключ); - Если ОписаниеЗапроса = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - СоставИзменений = ОписаниеИзменений.Значение; // ТаблицаЗначений - Если ОписаниеЗапроса.ТипыПолей.Количество() <> СоставИзменений.Колонки.Количество() Тогда - Возврат Неопределено; - КонецЕсли; - Для Каждого Колонка Из СоставИзменений.Колонки Цикл - ТипыПоля = ОписаниеЗапроса.ТипыПолей.Получить(Колонка.Имя); - Если ТипЗнч(ТипыПоля) <> Тип("ХранилищеЗначения") Тогда - Возврат Неопределено; - КонецЕсли; - ТипКолонки = Новый ОписаниеТипов(Колонка.ТипЗначения,, "Null"); - Если ТипыПоля.Получить() <> ТипКолонки - Или СтрокаДанныхДляХеширования(Колонка.ТипЗначения) - <> СтрокаДанныхДляХеширования(Новый ОписаниеТипов(Колонка.ТипЗначения.Типы())) Тогда - Возврат Неопределено; - КонецЕсли; - КонецЦикла; - ИмяВременнойТаблицыИПараметра = СтрЗаменить(ОписаниеИзменений.Ключ, ".", "_"); - Запрос.УстановитьПараметр(ИмяВременнойТаблицыИПараметра, СоставИзменений); - ЗапросыПакета.Добавить(ОписаниеЗапроса.ТекстЗапросаПараметров); - Для Каждого ТекстЗапросаДанных Из ОписаниеЗапроса.ТекстыЗапросовДанных Цикл - ЗапросыДанных.Добавить(ТекстЗапросаДанных); - КонецЦикла; - КонецЦикла; - КонецЕсли; - Если Не ДобавитьЗапросыТочечногоЗадания("ПоКлючамДоступа", - Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) - Или Не ДобавитьЗапросыТочечногоЗадания("ПоЗначениямСГруппами", - Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) - Или ЗапросыДанных.Количество() = 0 Тогда - Возврат Неопределено; - КонецЕсли; - Если ЗапросыДанных.Количество() = 1 Тогда - ЗапросыПакета.Добавить(СтрЗаменить(ЗапросыДанных[0], - " - |ИЗ - | ", - " - |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам - |ИЗ - | ")); // @query-part-1, @query-part-2 - Иначе - ТекстыЗапросов = СтрСоединить(ЗапросыДанных, - " - | - |ОБЪЕДИНИТЬ ВСЕ - | - |"); // @query-part-1 - ЗапросыПакета.Добавить(СтрЗаменить(ОписаниеЗапросов.Получить("ТекстЗапросаОберткиВыбораДанных"), - "#ЗапросыВыбораДанных", "(" + ТекстСОтступом(ТекстыЗапросов, " ") + ")")); - КонецЕсли; - ЗапросыПакета.Добавить(ОписаниеЗапросов.Получить("ТекстЗапросаТочечнойПроверки")); - Запрос.Текст = СтрСоединить(ЗапросыПакета, ОбщегоНазначения.РазделительПакетаЗапросов()); - КонецЕсли; - - КоличествоВЗапросе = ?(КоличествоВЗапросе < 1000, 1000, ?(КоличествоВЗапросе > 4000, 4000, КоличествоВЗапросе)); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Элементы = Запрос.Выполнить().Выгрузить(); - КоличествоВыбранных = Элементы.Количество(); - Иначе - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - КоличествоВыбранных = РезультатыЗапроса[ЗапросыПакета.Количество() - 2].Выгрузить()[0].Количество; - Элементы = РезультатыЗапроса[ЗапросыПакета.Количество() - 1].Выгрузить(); - КонецЕсли; - - ВыбраныВсеЭлементы = КоличествоВыбранных < КоличествоВЗапросе; - - Если Элементы.Количество() = 0 Тогда - Возврат Неопределено; - КонецЕсли; - - Возврат Элементы; - -КонецФункции - -// Для функции ЭлементыТочечногоЗаданияДляОбновления. -Функция ДобавитьЗапросыТочечногоЗадания(ВидЗадания, Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) - - Данные = ТаблицаТочечногоЗадания(); - Данные = ПараметрыОбновления.ТочечноеЗадание[ВидЗадания]; // см. ТаблицаТочечногоЗадания - Если Не ЗначениеЗаполнено(Данные) Тогда - Возврат Истина; - КонецЕсли; - - ОписаниеЗапросов = - ПараметрыОбновления.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам.Получить(ВидЗадания); - - Если ОписаниеЗапросов = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - ТипКолонки = Данные.Колонки.Ссылка.ТипЗначения; - НедостающиеТипы = Новый ОписаниеТипов(ТипКолонки, , ОписаниеЗапросов.ТипСсылки.Получить().Типы()); - Если НедостающиеТипы.Типы().Количество() > 0 Тогда - Возврат Ложь; - КонецЕсли; - - Запрос.УстановитьПараметр(ВидЗадания, Данные); - ЗапросыПакета.Добавить(ОписаниеЗапросов.ТекстЗапросаПараметров); - - КлючиЗапросов = Новый Соответствие; - Для Каждого Тип Из ТипКолонки.Типы() Цикл - ТекущиеКлючи = ОписаниеЗапросов.КлючиЗапросовПоТипам.Получить(Тип); - Если ТекущиеКлючи = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - Для Каждого Ключ Из ТекущиеКлючи Цикл - КлючиЗапросов.Вставить(Ключ, Истина); - КонецЦикла; - КонецЦикла; - - Для Каждого КлючИЗначение Из КлючиЗапросов Цикл - ТекстЗапроса = ОписаниеЗапросов.ТекстыЗапросовПоКлючам.Получить(КлючИЗначение.Ключ); - Если ТекстЗапроса = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - ЗапросыДанных.Добавить(ТекстЗапроса); - КонецЦикла; - - Возврат Истина; - -КонецФункции - -// Возвращаемое значение: -// ТаблицаЗначений: -// * Ссылка - ЛюбаяСсылка -// -Функция ТаблицаТочечногоЗадания() - - Возврат Неопределено; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении(ПараметрыОбновления) - - ПараметрыОбновления.ПерезапускОбновления = Истина; - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); - - // Регистрация косвенного планирования обновления доступа. - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); - ПараметрыПланирования.РазрешенныеКлючиДоступа = ПараметрыОбновления.ЭтоОбновлениеПрав; - ПараметрыПланирования.ДляПользователей = Не ПараметрыОбновления.ДляВнешнихПользователей; - ПараметрыПланирования.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; - ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; - ПараметрыПланирования.Описание = "ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении"; - - СпискиПоИдентификаторам = Новый Соответствие; - СпискиПоИдентификаторам.Вставить(ПараметрыОбновления.ИдентификаторСписка, ПараметрыОбновления.Список); - - ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования); - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Функция НаборПорцийЭлементов(ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы, РазмерПорции = Неопределено) - - НаборПорций = Новый Массив; - - Если Элементы = Неопределено Тогда - ПорцияИзНабора = ПорцияИзНабора(); - ПорцияИзНабора.Вставить("Обработана", Истина); - ПорцияИзНабора.Вставить("Обрабатывается", Ложь); - ПорцияИзНабора.Вставить("Элементы", Новый ХранилищеЗначения(Новый ТаблицаЗначений)); - ПорцияИзНабора.Вставить("ДатаПоследнегоЭлементаПорции", '00010101'); - ПорцияИзНабора.Вставить("ПоследнийЭлементПорции", НачальныйЭлемент(ПараметрыОбновления,, Истина)); - ПорцияИзНабора.Вставить("НовыйПоследнийЭлементПорции"); - НаборПорций.Добавить(ПорцияИзНабора); - ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; - Если ПорцияИзНабора.ПоследнийЭлементПорции.Свойство("Дата") Тогда - ПорцияИзНабора.ПоследнийЭлементПорции.Дата = '00010101'; - КонецЕсли; - УстановитьПустойПоследнийЭлемент(ПорцияИзНабора.НовыйПоследнийЭлементПорции, - ПараметрыОбновления, '00010101'); - Возврат НаборПорций; - КонецЕсли; - - Если РазмерПорции = Неопределено Тогда - РазмерПорции = ПараметрыОбновления.КоличествоОбработанныхЭлементов; - МаксимумНовыхПорций = ПараметрыОбновления.МаксимумПорцийИзИсходной; - Если Элементы.Количество() / РазмерПорции > МаксимумНовыхПорций Тогда - РазмерПорции = Элементы.Количество() / МаксимумНовыхПорций; - Если РазмерПорции <> Цел(РазмерПорции) Тогда - РазмерПорции = Цел(РазмерПорции) + 1; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - ПараметрыОбновления.Вставить("НаборПорций", НаборПорций); - Индекс = 0; - Для Каждого Элемент Из Элементы Цикл - Если Индекс / РазмерПорции = Цел(Индекс / РазмерПорции) Тогда - ПорцияИзНабора = Новый Массив; - НаборПорций.Добавить(ПорцияИзНабора); - КонецЕсли; - ПорцияИзНабора.Добавить(Элемент); - Индекс = Индекс + 1; - КонецЦикла; - - Для Индекс = 0 По НаборПорций.Количество() - 1 Цикл - ЭлементыПорции = Элементы.Скопировать(НаборПорций[Индекс]); - ПорцияИзНабора = ПорцияИзНабора(); - ПорцияИзНабора.Вставить("Обработана", Ложь); - ПорцияИзНабора.Вставить("Обрабатывается", Ложь); - НаборПорций[Индекс] = ПорцияИзНабора; - ПорцияИзНабора.Вставить("Элементы", Новый ХранилищеЗначения(ЭлементыПорции)); - ПорцияИзНабора.Вставить("ПоследнийЭлементПорции", - ПоследнийЭлемент(ЭлементыПорции, ПараметрыОбновления)); - ПорцияИзНабора.Вставить("ДатаПоследнегоЭлементаПорции", - ?(ПорцияИзНабора.ПоследнийЭлементПорции.Свойство("Дата"), - ПорцияИзНабора.ПоследнийЭлементПорции.Дата, '00010101')); - ПорцияИзНабора.Вставить("НовыйПоследнийЭлементПорции", - ПоследнийЭлемент(ЭлементыПорции, ПараметрыОбновления)); - КонецЦикла; - - Если ВыбраныВсеЭлементы Тогда - ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; - УстановитьПустойПоследнийЭлемент(ПорцияИзНабора.НовыйПоследнийЭлементПорции, - ПараметрыОбновления, '00010101'); - КонецЕсли; - - Возврат НаборПорций; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * Обработана - Булево -// * Обрабатывается - Булево -// * Элементы - ХранилищеЗначения -// * ДатаПоследнегоЭлементаПорции - Дата -// * ПоследнийЭлементПорции - см. НачальныйЭлемент -// * НовыйПоследнийЭлементПорции - см. НачальныйЭлемент -// -Функция ПорцияИзНабора() - - Возврат Новый Структура; - -КонецФункции - -// Для процедур ВыполнитьОбновлениеДоступаСписка, ОбновитьПорциюЭлементов, НаборПорцийЭлементов. -Функция ПоследнийЭлемент(Элементы, ПараметрыОбновления, ПоследнийОбработанный = Ложь) - - НомерПоследнего = ?(ПоследнийОбработанный, - ПараметрыОбновления.КоличествоОбработанныхЭлементов, Элементы.Количество()); - - ПоследнийЭлемент = Элементы[НомерПоследнего - 1]; - - ЭлементДанных = НачальныйЭлемент(ПараметрыОбновления, , Истина); - - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - ЭлементДанных.КлючДанных = ПоследнийЭлемент.Ссылка; - Возврат ЭлементДанных; - КонецЕсли; - - Если ПараметрыОбновления.СписокСДатой - И Не ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - - ЭлементДанных.Дата = ПоследнийЭлемент.Дата; - - ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда - ЭлементДанных.КлючДанных = ПоследнийЭлемент.ТекущаяСсылка; - Иначе - ЭлементДанных.КлючДанных = КлючДанных(ПараметрыОбновления); - ЗаполнитьЗначенияСвойств(ЭлементДанных.КлючДанных, ПоследнийЭлемент); - - Если ПараметрыОбновления.СписокСПериодом - И ЭлементДанных.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда - - ЭлементДанных.Дата = ПоследнийЭлемент.Период; - КонецЕсли; - КонецЕсли; - - Возврат ЭлементДанных; - -КонецФункции - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура УточнитьПоследнийОбновленныйЭлемент(ПараметрыОбновления) - - Если ПараметрыОбновления.Список = "Справочник.НаборыГруппДоступа" - Или ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда - Возврат; - КонецЕсли; - - Если ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда - Если Не ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы Тогда - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = - НачальныйЭлемент(ПараметрыОбновления, "НетДанных"); - - ИначеЕсли Не ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - УстановитьОбработкуУстаревшихДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, - ПараметрыОбновления, "НетДанных"); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедур ВыполнитьОбновлениеДоступаСписка, НаборПорцийЭлементов. -Процедура УстановитьПустойПоследнийЭлемент(Элемент, ПараметрыОбновления, ДатаЭлемента = '00010101') - - ДатаЭлемента = '00010101'; - Элемент = НачальныйЭлемент(ПараметрыОбновления, , Истина); - Элемент.КлючДанных = Null; - - // Уточнение нового последнего элемента. - Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Возврат; - КонецЕсли; - НовыйВидКлючаДанных = ""; - Если Элемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда - НовыйВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям"; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда - НовыйВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям"; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда - НовыйВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами"; - - ИначеЕсли Элемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда - НовыйВидКлючаДанных = "НаборыГруппРазрешенныеПользователям"; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" - И Элемент.ОбработатьНаборыГруппСУстаревшимиПравами Тогда - - НовыйВидКлючаДанных = "НаборыГруппСУстаревшимиПравами"; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" - Или Элемент.ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда - - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - КонецЕсли; - Если ЗначениеЗаполнено(НовыйВидКлючаДанных) Тогда - Элемент = НачальныйЭлемент(ПараметрыОбновления, НовыйВидКлючаДанных); - КонецЕсли; - Возврат; - КонецЕсли; - - Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда - Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиПравами" Тогда - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - КонецЕсли; - Возврат; - КонецЕсли; - - Если Элемент.ВидКлючаДанных = "НекорректныеЭлементыОбщегоРегистра" Тогда - Возврат; - КонецЕсли; - - Если Элемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда - Если ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных <> ПризнакПустогоЗапроса() Тогда - Элемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементы"); - КонецЕсли; - Возврат; - КонецЕсли; - - Если Элемент.ВидКлючаДанных = "НекорректныеЭлементы" Тогда - Если Не ПараметрыОбновления.ЭтоСсылочныйТип - И ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - - Элемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементыОбщегоРегистра"); - КонецЕсли; - Возврат; - КонецЕсли; - - Если ПараметрыОбновления.СписокСДатой Тогда - УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента); - Если Элемент.КлючДанных = Null Тогда - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - КонецЕсли; - Возврат; - КонецЕсли; - - Если ПараметрыОбновления.ЭтоСсылочныйТип - Или ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда - - Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - КонецЕсли; - Возврат; - КонецЕсли; - - Если Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" Тогда - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - Возврат; - КонецЕсли; - - Если Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда - УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента); - Если Элемент.КлючДанных = Null Тогда - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - КонецЕсли; - Возврат; - КонецЕсли; - - Если Не ПараметрыОбновления.СписокСПериодом Тогда - Элемент = НачальныйЭлемент(ПараметрыОбновления, "ЭлементыБезКлючейПоЗначениямПолей"); - Возврат; - КонецЕсли; - - Элемент = НачальныйЭлемент(ПараметрыОбновления, "ЭлементыБезКлючейПоПериоду"); - ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = Элемент; - УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента, МаксимальнаяДата()); - ПараметрыОбновления.ПоследнийОбновленныйЭлемент = ПоследнийОбновленныйЭлемент; - - Если Элемент.КлючДанных = Null Тогда - УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); - КонецЕсли; - -КонецПроцедуры - -// Для процедур УточнитьПоследнийОбновленныйЭлемент, УстановитьПустойПоследнийЭлемент. -Процедура УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления, ВидКлючаДанныхЗавершения = Неопределено) - - НовыйЭлемент = Неопределено; - Если Элемент.ОбработатьУстаревшиеЭлементы Тогда - - Если ПараметрыОбновления.ЭтоОбновлениеПрав - Или ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) - Или ПараметрыОбновления.ТекстЗапросаУстаревшихЭлементовДанных <> ПризнакПустогоЗапроса() Тогда - - НовыйЭлемент = НачальныйЭлемент(ПараметрыОбновления, "УстаревшиеЭлементы"); - - ИначеЕсли ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных <> ПризнакПустогоЗапроса() Тогда - НовыйЭлемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементы"); - КонецЕсли; - КонецЕсли; - - Если НовыйЭлемент <> Неопределено Тогда - Элемент = НовыйЭлемент; - - ИначеЕсли ВидКлючаДанныхЗавершения <> Неопределено Тогда - Элемент = НачальныйЭлемент(ПараметрыОбновления, ВидКлючаДанныхЗавершения); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры УточнитьПустойПоследнийЭлемент. -Процедура УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента, - ДатаНачалаТекущегоПериода = Неопределено) - - Если ДатаНачалаТекущегоПериода = Неопределено Тогда - ДатаНачалаТекущегоПериода = ПараметрыОбновления.ДатаНачала; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДатаНачала", ДатаНачалаТекущегоПериода); - - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаДатыСледующегоЭлементаДанных; - - РезультатЗапроса = Запрос.Выполнить(); - - Если РезультатЗапроса.Пустой() Тогда - Элемент.КлючДанных = Null; - Возврат; - КонецЕсли; - - Элемент = ПоследнийЭлемент(РезультатЗапроса.Выгрузить(), ПараметрыОбновления); - ДатаЭлемента = ?(Элемент.Свойство("Дата"), Элемент.Дата, '00010101'); - -КонецПроцедуры - -// Для функции ЭлементыДляОбновления. -Процедура УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных(Запрос, ПараметрыОбновления) - - Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаУстаревшихЭлементовДанных; - ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НекорректныеЭлементы" Тогда - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных; - Иначе - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра; - КонецЕсли; - Иначе - // ТекстЗапросаДиапазонаЭлементовДанных, ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами. - Запрос.Текст = ПризнакИтерационногоЗапроса(); - Если Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда - Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); - КонецЕсли; - Если ПараметрыОбновления.СписокСДатой Тогда - Запрос.УстановитьПараметр("ДатаНачала", ПараметрыОбновления.ДатаНачала); - Запрос.УстановитьПараметр("ДатаОкончания", ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата); - Возврат; - КонецЕсли; - КонецЕсли; - - КлючДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных; - - Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда - УстановленныйКлючДанных = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(КлючДанных)), КлючДанных, Неопределено); - Запрос.УстановитьПараметр("ПоследняяОбработаннаяСсылка", УстановленныйКлючДанных); - Возврат; - КонецЕсли; - - Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); - УстановленныйКлючДанных = КлючДанных(ПараметрыОбновления, КлючДанных); - ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; - - ЭлементыБезКлючей = ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" - Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей"; - - Если ЭлементыБезКлючей И ПараметрыОбновления.СписокСПериодом Тогда - Если ВидКлючаДанных <> "ЭлементыБезКлючейПоПериоду" Тогда - УстановитьВидКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, - "ЭлементыБезКлючейПоПериоду"); - КонецЕсли; - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхБезКлючейДоступа; - Запрос.УстановитьПараметр("ДатаНачала", ПараметрыОбновления.ДатаНачала); - Запрос.УстановитьПараметр("ДатаОкончания", ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата); - - ИначеЕсли ЭлементыБезКлючей Тогда - Если ВидКлючаДанных <> "ЭлементыБезКлючейПоЗначениямПолей" Тогда - УстановитьВидКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, - "ЭлементыБезКлючейПоЗначениямПолей"); - КонецЕсли; - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхБезКлючейДоступа; - КонецЕсли; - - Если Запрос.Текст = ПризнакИтерационногоЗапроса() Тогда - Запрос.УстановитьПараметр("УстановленныйКлючДанных", УстановленныйКлючДанных); - Возврат; - КонецЕсли; - - Для Каждого КлючИЗначение Из УстановленныйКлючДанных Цикл - Если КлючИЗначение.Значение = Неопределено Тогда - ИмяПоля = КлючИЗначение.Ключ; - Запрос.Текст = СтрЗаменить(Запрос.Текст, " > &" + ИмяПоля, " >= &" + ИмяПоля); - КонецЕсли; - Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - -КонецПроцедуры - -// Для процедур ПоследнийЭлемент, УстановитьПараметрыПоследнегоОбновленногоЭлемента и -// функции ТекстЗапросаКоличестваОставшихсяЭлементовРегистра. -// -// Возвращаемое значение: -// Структура: -// * Поле1 - ЛюбаяСсылка -// * Поле2 - ЛюбаяСсылка -// * Поле3 - ЛюбаяСсылка -// * Поле4 - ЛюбаяСсылка -// * Поле5 - ЛюбаяСсылка -// -Функция КлючДанных(ПараметрыОбновления, ИсходныйКлючДанных = Неопределено) - - КоличествоПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); - - Если КоличествоПолей = 0 - Или ПараметрыОбновления.ИспользуетсяОграничениеПоВладельцу - Или ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - - КоличествоПолей = ПараметрыОбновления.ОпорныеПоля.МаксимальноеКоличество; - КонецЕсли; - ПолеВариантДоступа = ?(ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления), 1, 0); - - Если ТипЗнч(ИсходныйКлючДанных) = Тип("Структура") - И ИсходныйКлючДанных.Количество() = КоличествоПолей + ПолеВариантДоступа Тогда - - ЗначенияПолей = ИсходныйКлючДанных; - Иначе - ЗначенияПолей = Новый Структура; - КонецЕсли; - - НовыеЗначенияПолей = Новый Структура; - Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - ИмяПоля = "ВариантДоступа"; - Если ЗначенияПолей.Свойство(ИмяПоля) Тогда - НовыеЗначенияПолей.Вставить(ИмяПоля, ЗначенияПолей[ИмяПоля]); - Иначе - НовыеЗначенияПолей.Вставить(ИмяПоля, Неопределено); - КонецЕсли; - КонецЕсли; - - Для Номер = 1 По КоличествоПолей Цикл - ИмяПоля = СтрШаблон("Поле%1", Номер); - Если ЗначенияПолей.Свойство(ИмяПоля) Тогда - НовыеЗначенияПолей.Вставить(ИмяПоля, ЗначенияПолей[ИмяПоля]); - Иначе - НовыеЗначенияПолей.Вставить(ИмяПоля, Неопределено); - КонецЕсли; - КонецЦикла; - - Возврат НовыеЗначенияПолей; - -КонецФункции - -// Для процедуры ЭлементыДляОбновления. -Функция НаборыГруппДоступаДляОбновления(ПараметрыОбновления, КоличествоВЗапросе) - - ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; - ВидКлючаДанных = ПоследнийОбновленныйЭлемент.ВидКлючаДанных; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); - Запрос.УстановитьПараметр("ПоследняяОбработаннаяСсылка", ПоследнийОбновленныйЭлемент.КлючДанных); - - Если ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | ТекущийСписок.Ссылка КАК ТекущаяСсылка, - | ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) КАК ЭтоНаборГруппДоступа - |ИЗ - | Справочник.НаборыГруппДоступа КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И ТекущийСписок.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) - | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Ссылка"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - ИначеЕсли ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | СоставыГруппПользователей.Пользователь КАК ТекущаяСсылка, - | СоставыГруппПользователей.Пользователь.Наименование КАК Наименование, - | СоставыГруппПользователей.Используется - | И ЕСТЬNULL(ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ, &ПустойУникальныйИдентификатор) <> &ПустойУникальныйИдентификатор КАК Используется, - | НаборыГруппДоступа.НеИспользуетсяС КАК НеИспользуетсяС - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - | ПО (НаборыГруппДоступа.Пользователь = СоставыГруппПользователей.Пользователь) - | И (НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей) - | И (НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) - | И (НЕ ЛОЖЬ В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ЛОЖЬ - | ИЗ - | Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов - | ГДЕ - | ГруппыНаборов.Ссылка = НаборыГруппДоступа.Ссылка)) - |ГДЕ - | ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.Пользователи) - | И ВЫБОР - | КОГДА СоставыГруппПользователей.Используется - | И ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор - | ТОГДА НаборыГруппДоступа.Пользователь ЕСТЬ NULL - | ИЛИ НаборыГруппДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(1, 1, 1) - | ИНАЧЕ НаборыГруппДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | КОНЕЦ - | И СоставыГруппПользователей.Пользователь > &ПоследняяОбработаннаяСсылка - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | СоставыГруппПользователей.Пользователь"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - ИначеЕсли ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда - Возврат НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа( - ПараметрыОбновления, КоличествоВЗапросе); - - ИначеЕсли ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда - Возврат НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей( - ПараметрыОбновления, КоличествоВЗапросе); - - ИначеЕсли ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | ТекущийСписок.Ссылка КАК ТекущаяСсылка, - | ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) КАК ЭтоНаборГруппДоступа - |ИЗ - | Справочник.НаборыГруппДоступа КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И ТекущийСписок.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - | ГДЕ - | НаборыГруппДоступа.НовыйНаборГруппДоступа = ТекущийСписок.Ссылка) - | ИЛИ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - | ГДЕ - | НаборыГруппДоступа.НовыйНаборГруппПользователей = ТекущийСписок.Ссылка)) - | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Ссылка"; - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - ИначеЕсли ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | ТекущийСписок.Ссылка КАК ТекущаяСсылка - |ИЗ - | Справочник.НаборыГруппДоступа КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | И (ТекущийСписок.НовыйНаборГруппДоступа <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - | И НЕ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - | ГДЕ - | НаборыГруппДоступа.Ссылка = ТекущийСписок.НовыйНаборГруппДоступа - | И НаборыГруппДоступа.НовыйНаборГруппДоступа = ТекущийСписок.НовыйНаборГруппДоступа) - | ИЛИ ТекущийСписок.НовыйНаборГруппПользователей <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - | И НЕ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - | ГДЕ - | НаборыГруппДоступа.Ссылка = ТекущийСписок.НовыйНаборГруппПользователей - | И НаборыГруппДоступа.НовыйНаборГруппПользователей = ТекущийСписок.НовыйНаборГруппПользователей)) - | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Ссылка"; - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - Возврат УстаревшиеНаборыГруппДоступаВСправочнике(ПараметрыОбновления, КоличествоВЗапросе); - КонецЕсли; - - КоличествоВЗапросе = ?(КоличествоВЗапросе < 25, 25, ?(КоличествоВЗапросе > 10000, 10000, КоличествоВЗапросе)); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - - ЭлементыДанных = Запрос.Выполнить().Выгрузить(); - - Возврат ЭлементыДанных; - -КонецФункции - -// Для процедуры ОбновитьПорциюЭлементов. -Процедура ОбновитьНаборыГруппДоступа(ЭлементыДанных, ПараметрыОбновления) - - ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; - - Если ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда - ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления); - - ИначеЕсли ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда - ОбновитьНаборыИзОдногоПользователяВСправочнике(ЭлементыДанных, ПараметрыОбновления); - - ИначеЕсли ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда - ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления, Истина); - - ИначеЕсли ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда - ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления, Ложь); - - ИначеЕсли ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда - ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления, Истина); - - ИначеЕсли ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда - ОбновитьНаборыГруппРазрешенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления); - - ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда - ОбработатьУстаревшиеНаборыВСправочнике(ЭлементыДанных, ПараметрыОбновления); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура ОчиститьПраваПустогоНабораГруппДоступа(ПараметрыОбновления) - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборовГруппДоступа - |ГДЕ - | КлючиДоступаНаборовГруппДоступа.НаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей - |ГДЕ - | КлючиДоступаПользователей.Пользователь = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей - |ГДЕ - | КлючиДоступаВнешнихПользователей.ВнешнийПользователь = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка)"; - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - Если Не РезультатыЗапроса[0].Пустой() Тогда - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); - НаборЗаписей.Отбор.НаборГруппДоступа.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); - НаборЗаписей.Записать(); - КонецЕсли; - - Если Не РезультатыЗапроса[1].Пустой() Тогда - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); - НаборЗаписей.Отбор.Пользователь.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); - НаборЗаписей.Записать(); - КонецЕсли; - - Если Не РезультатыЗапроса[2].Пустой() Тогда - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); - НаборЗаписей.Отбор.ВнешнийПользователь.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); - НаборЗаписей.Записать(); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбновитьНаборыГруппДоступа. -Процедура ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления, ЭтоНовыеНаборы = Ложь) - - Если ЭтоНовыеНаборы Тогда - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - КонецЕсли; - - Для Каждого ЭлементДанных Из ЭлементыДанных Цикл - Если ЭлементДанных.ЭтоНаборГруппДоступа Тогда - // @skip-check query-in-loop - Порционная обработка данных - ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, - "КлючиДоступаНаборовГруппДоступа", "ГруппыДоступа", "НаборГруппДоступа"); - - ИначеЕсли Не ПараметрыОбновления.ДляВнешнихПользователей Тогда - // @skip-check query-in-loop - Порционная обработка данных - ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, - "КлючиДоступаПользователей", "ГруппыПользователей", "Пользователь"); - Иначе - // @skip-check query-in-loop - Порционная обработка данных - ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, - "КлючиДоступаВнешнихПользователей", "ГруппыВнешнихПользователей", "ВнешнийПользователь"); - КонецЕсли; - - Если ЭтоНовыеНаборы Тогда - ЭлементБлокировки.УстановитьЗначение("Ссылка", ЭлементДанных.ТекущаяСсылка); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = СлужебныйЭлемент(Неопределено, ЭлементДанных.ТекущаяСсылка); - Если Объект <> Неопределено Тогда - ИмяРеквизита = ?(ЭлементДанных.ЭтоНаборГруппДоступа, - "НовыйНаборГруппДоступа", "НовыйНаборГруппПользователей"); - Если ЗначениеЗаполнено(Объект[ИмяРеквизита]) Тогда - Объект[ИмяРеквизита] = ПараметрыОбновления.ПустойНаборГруппДоступа; - Объект.Записать(); - КонецЕсли; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбновитьНаборыГруппСУстаревшимиПравами. -Процедура ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, НаборГруппДоступа, ИмяРегистраПрав, - ИмяСправочникаГрупп, ИмяПоляНабораГрупп) - - Если НаборГруппДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа() Тогда - ТекстЗапросаВыбораПорцииДляБлокировки = - "ВЫБРАТЬ ПЕРВЫЕ 1000 - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки, - | ВсеСтроки.КлючДоступа КАК КлючДоступа - |ИЗ - | (ВЫБРАТЬ - | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, - | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, - | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ГДЕ - | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) - | И &УточнениеПланаЗапроса - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.КлючДоступа, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные - | ГДЕ - | &УсловиеОтбораПравГрупп - | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.КлючДоступа, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки, - | КлючДоступа"; - - ТекстЗапросаВыбораПорцииДляОбновления = - "ВЫБРАТЬ ПЕРВЫЕ 100 - | ВсеСтроки.КлючДоступа КАК КлючДоступа, - | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, - | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, - | ИСТИНА КАК ЭтоПраваНабораГрупп, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | (ВЫБРАТЬ - | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, - | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, - | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ГДЕ - | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) - | И КлючиДоступаГруппДоступа.КлючДоступа В(&КлючиДоступа) - | И &УточнениеПланаЗапроса - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.КлючДоступа, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные - | ГДЕ - | &УсловиеОтбораПравГрупп - | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа - | И СтарыеДанные.КлючДоступа В(&КлючиДоступа)) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.КлючДоступа, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки"; - Иначе - ТекстЗапросаВыбораПорцииДляБлокировки = - "ВЫБРАТЬ ПЕРВЫЕ 1000 - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки, - | ВсеСтроки.КлючДоступа КАК КлючДоступа - |ИЗ - | (ВЫБРАТЬ - | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы - | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) - | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) - | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) - | И (ГруппыВходящиеВНаборы.Ссылка = &НаборГруппДоступа) - | И (&УточнениеПланаЗапроса) - | - | СГРУППИРОВАТЬ ПО - | КлючиДоступаГруппДоступа.КлючДоступа - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.КлючДоступа, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные - | ГДЕ - | &УсловиеОтбораПравГрупп - | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.КлючДоступа, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки, - | КлючДоступа"; - - ТекстЗапросаВыбораПорцииДляОбновления = - "ВЫБРАТЬ ПЕРВЫЕ 100 - | ВсеСтроки.КлючДоступа КАК КлючДоступа, - | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, - | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, - | ИСТИНА КАК ЭтоПраваНабораГрупп, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | (ВЫБРАТЬ - | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы - | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) - | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) - | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) - | И (ГруппыВходящиеВНаборы.Ссылка = &НаборГруппДоступа) - | И (КлючиДоступаГруппДоступа.КлючДоступа В (&КлючиДоступа)) - | И (&УточнениеПланаЗапроса) - | - | СГРУППИРОВАТЬ ПО - | КлючиДоступаГруппДоступа.КлючДоступа - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.КлючДоступа, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные - | ГДЕ - | &УсловиеОтбораПравГрупп - | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа - | И СтарыеДанные.КлючДоступа В(&КлючиДоступа)) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.КлючДоступа, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки"; - КонецЕсли; - - ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, - "ТИП(Справочник.ГруппыДоступа)", "ТИП(Справочник." + ИмяСправочникаГрупп + ")"); // @query-part-1, @query-part-2 - - ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, - "ТИП(Справочник.ГруппыДоступа)", "ТИП(Справочник." + ИмяСправочникаГрупп + ")"); // @query-part-1, @query-part-2 - - ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, - "СтарыеДанные.НаборГруппДоступа", "СтарыеДанные." + ИмяПоляНабораГрупп); - - ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, - "СтарыеДанные.НаборГруппДоступа", "СтарыеДанные." + ИмяПоляНабораГрупп); - - ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, - "РегистрСведений.КлючиДоступаНаборовГруппДоступа", "РегистрСведений." + ИмяРегистраПрав); - - ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, - "РегистрСведений.КлючиДоступаНаборовГруппДоступа", "РегистрСведений." + ИмяРегистраПрав); - - ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, - "&УсловиеОтбораПравГрупп", ?(ИмяСправочникаГрупп = "ГруппыДоступа", "ИСТИНА", "СтарыеДанные.ЭтоПраваНабораГрупп")); - - ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, - "&УсловиеОтбораПравГрупп", ?(ИмяСправочникаГрупп = "ГруппыДоступа", "ИСТИНА", "СтарыеДанные.ЭтоПраваНабораГрупп")); - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - Пока Истина Цикл - Запрос = Новый Запрос; - Запрос.Текст = ТекстЗапросаВыбораПорцииДляБлокировки; - УстановитьУточнениеПланаЗапроса(Запрос.Текст, Истина); - Запрос.УстановитьПараметр("НаборГруппДоступа", НаборГруппДоступа); - - Выгрузка = Запрос.Выполнить().Выгрузить(); - Если Выгрузка.Количество() = 0 Тогда - Прервать; - КонецЕсли; - - КлючиДоступа = Выгрузка.Скопировать(Новый Массив, "КлючДоступа"); - ПорцииКлючейДоступа = Новый Массив; - Для Каждого Строка Из Выгрузка Цикл - Если КлючиДоступа.Количество() > 100 Тогда - ПорцииКлючейДоступа.Добавить(КлючиДоступа); - КлючиДоступа = Выгрузка.Скопировать(Новый Массив, "КлючДоступа"); - КонецЕсли; - КлючиДоступа.Добавить().КлючДоступа = Строка.КлючДоступа; - КонецЦикла; - ПорцииКлючейДоступа.Добавить(КлючиДоступа); - - Для Каждого КлючиДоступа Из ПорцииКлючейДоступа Цикл - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраПрав); - ЭлементБлокировки.УстановитьЗначение(ИмяПоляНабораГрупп, НаборГруппДоступа); - ЭлементБлокировки.ИсточникДанных = КлючиДоступа; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючДоступа", "КлючДоступа"); - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = ТекстЗапросаВыбораПорцииДляОбновления; - УстановитьУточнениеПланаЗапроса(Запрос.Текст, Истина); - Запрос.УстановитьПараметр("НаборГруппДоступа", НаборГруппДоступа); - Запрос.УстановитьПараметр("КлючиДоступа", КлючиДоступа.ВыгрузитьКолонку("КлючДоступа")); - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраПрав]); - Если Не ПакетныйРежим Тогда - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляНабораГрупп]; // ЭлементОтбора - ЭлементОтбора.Установить(НаборГруппДоступа); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - // @skip-check query-in-loop - Порционная обработка данных - Выборка = Запрос.Выполнить().Выбрать(); - - УдалениеЗавершено = Ложь; - Пока Выборка.Следующий() Цикл - Если Не ПакетныйРежим Тогда - НаборЗаписей.Отбор.КлючДоступа.Установить(Выборка.КлючДоступа); - КонецЕсли; - Если Не УдалениеЗавершено И Выборка.ВидИзмененияСтроки = 1 Тогда - УдалениеЗавершено = Истина; - Если Не ПакетныйРежим Тогда - ОднаЗапись = НаборЗаписей.Добавить(); - ОднаЗапись[ИмяПоляНабораГрупп] = НаборГруппДоступа; - ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимУдаления); - НаборЗаписей.Очистить(); - КонецЕсли; - КонецЕсли; - Если Не ПакетныйРежим Тогда - Если УдалениеЗавершено Тогда - ЗаполнитьЗначенияСвойств(ОднаЗапись, Выборка); - КонецЕсли; - НаборЗаписей.Записать(); - Иначе - Запись = НаборЗаписей.Добавить(); - Запись[ИмяПоляНабораГрупп] = НаборГруппДоступа; - ЗаполнитьЗначенияСвойств(Запись, Выборка); - КонецЕсли; - КонецЦикла; - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(?(УдалениеЗавершено, РежимСлияния, РежимУдаления)); - КонецЕсли; - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура УстранитьДублиНаборовИзОдногоПользователяВСправочнике(ПараметрыОбновления) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); - Запрос.Текст = - "ВЫБРАТЬ - | НаборыГруппДоступа.Пользователь КАК Пользователь, - | НаборыГруппДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - |ГДЕ - | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | И НаборыГруппДоступа.Пользователь В - | (ВЫБРАТЬ - | ВЫРАЗИТЬ(НаборыГруппДоступа.Пользователь КАК Справочник.Пользователи) КАК Пользователь - | ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - | ГДЕ - | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | СГРУППИРОВАТЬ ПО - | НаборыГруппДоступа.Пользователь - | ИМЕЮЩИЕ - | КОЛИЧЕСТВО(НаборыГруппДоступа.Пользователь) > 1)"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - Выборка = Запрос.Выполнить().Выбрать(); - Пока Выборка.Следующий() Цикл - Если Выборка.Ссылка.УникальныйИдентификатор() = Выборка.Пользователь.УникальныйИдентификатор() Тогда - Продолжить; - КонецЕсли; - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = СлужебныйЭлемент(Неопределено, Выборка.Ссылка); - Если Объект <> Неопределено Тогда - Объект.ТипЭлементовНабора = Неопределено; - Объект.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбновитьНаборыГруппДоступа. -Процедура ОбновитьНаборыИзОдногоПользователяВСправочнике(ЭлементыДанных, ПараметрыОбновления) - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - ТипЭлементовНабора = Справочники.ВнешниеПользователи.ПустаяСсылка(); - ПредставлениеЭлемента = НСтр("ru = 'Внешний пользователь'", ОбщегоНазначения.КодОсновногоЯзыка()); - Иначе - ТипЭлементовНабора = Справочники.Пользователи.ПустаяСсылка(); - ПредставлениеЭлемента = НСтр("ru = 'Пользователь'", ОбщегоНазначения.КодОсновногоЯзыка()); - КонецЕсли; - - Для Каждого Строка Из ЭлементыДанных Цикл - СсылкаНабора = Справочники.НаборыГруппДоступа.ПолучитьСсылку(Строка.ТекущаяСсылка.УникальныйИдентификатор()); - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНабора); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - - Объект = СлужебныйЭлемент(Неопределено, СсылкаНабора); - Если Объект = Неопределено Тогда - Объект = СлужебныйЭлемент(Справочники.НаборыГруппДоступа); - Объект.УстановитьСсылкуНового(СсылкаНабора); - Иначе - Объект.Группы.Очистить(); - КонецЕсли; - Если Строка.Используется Тогда - Объект.НеИспользуетсяС = '00010101'; - ИначеЕсли Не ЗначениеЗаполнено(Строка.НеИспользуетсяС) Тогда - Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); - КонецЕсли; - Объект.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; - Объект.ТипЭлементовНабора = ТипЭлементовНабора; - Объект.Пользователь = Строка.ТекущаяСсылка; - ОписаниеОбъекта = Строка; // СправочникОбъект.Пользователи - Объект.Наименование = Строка(ОписаниеОбъекта.Наименование) + " (" + ПредставлениеЭлемента + ")"; - Объект.Записать(); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура ЗаполнитьПустыеХешиНаборовГрупп(ПараметрыОбновления) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); - Запрос.УстановитьПараметр("РазрешенныйПустойНабор", - УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); - Запрос.Текст = - "ВЫБРАТЬ - | НаборыГруппДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - |ГДЕ - | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГруппДоступа.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) - | И НаборыГруппДоступа.Хеш = 0 - | И НаборыГруппДоступа.Ссылка <> &РазрешенныйПустойНабор"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - Выборка = Запрос.Выполнить().Выбрать(); - Пока Выборка.Следующий() Цикл - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = СлужебныйЭлемент(Неопределено, Выборка.Ссылка); - Если Объект <> Неопределено Тогда - ЗаполнитьХешНабораГрупп(Объект); - Объект.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - -КонецПроцедуры - -// Для функции НаборыГруппДоступаДляОбновления. -Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа(ПараметрыОбновления, - КоличествоВЗапросе) - - Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда - ТекстЗапросаГрупп = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Группа - |ПОМЕСТИТЬ АктивныеГруппы - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль <> &ПрофильАдминистратор - | И НЕ ГруппыДоступа.ПометкаУдаления - | И НЕ ГруппыДоступа.Профиль.ПометкаУдаления - | И ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа - | ГДЕ - | ПользователиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка) - | И ВЫБОР - | КОГДА ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение - | ГДЕ - | Назначение.Ссылка = ГруппыДоступа.Профиль - | И ТИПЗНАЧЕНИЯ(Назначение.ТипПользователей) = ТИП(Справочник.Пользователи)) - | ТОГДА ИСТИНА - | КОГДА НЕ ЛОЖЬ В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ЛОЖЬ - | ИЗ - | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение - | ГДЕ - | Назначение.Ссылка = ГруппыДоступа.Профиль) - | ТОГДА ИСТИНА - | ИНАЧЕ ЛОЖЬ - | КОНЕЦ - | - |ИНДЕКСИРОВАТЬ ПО - | ГруппыДоступа.Ссылка"; - Иначе - ТекстЗапросаГрупп = - "ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК Группа - |ПОМЕСТИТЬ АктивныеГруппы - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - |ГДЕ - | ГруппыДоступа.Профиль <> &ПрофильАдминистратор - | И НЕ ГруппыДоступа.ПометкаУдаления - | И НЕ ГруппыДоступа.Профиль.ПометкаУдаления - | И ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа - | ГДЕ - | ПользователиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка) - | И ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение - | ГДЕ - | Назначение.Ссылка = ГруппыДоступа.Профиль - | И Назначение.ТипПользователей <> НЕОПРЕДЕЛЕНО - | И ТИПЗНАЧЕНИЯ(Назначение.ТипПользователей) <> ТИП(Справочник.Пользователи)) - | - |ИНДЕКСИРОВАТЬ ПО - | ГруппыДоступа.Ссылка"; - КонецЕсли; - - ТекстЗапросаНовыхНаборовГрупп = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | СоставыГруппПользователей.Пользователь КАК Пользователь, - | ПользователиГруппДоступа.Ссылка КАК Группа - |ПОМЕСТИТЬ НовыеНаборыГрупп - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа - | ПО СоставыГруппПользователей.ГруппаПользователей = ПользователиГруппДоступа.Пользователь - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) - | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА) - | И (СоставыГруппПользователей.Используется) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы - | ПО (ПользователиГруппДоступа.Ссылка = АктивныеГруппы.Группа) - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь, - | Группа"; - - ЭлементыДанных = НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, - ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, "НаборГруппДоступа", "ГруппыДоступа"); - - КоличествоВЗапросе = ЭлементыДанных.Количество() + 1; - Возврат ЭлементыДанных; - -КонецФункции - -// Для функции НаборыГруппДоступаДляОбновления. -Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей(ПараметрыОбновления, - КоличествоВЗапросе) - - ТекстЗапросаГрупп = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | СоставыГруппПользователей.ГруппаПользователей КАК Группа - |ПОМЕСТИТЬ АктивныеГруппы - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - |ГДЕ - | СоставыГруппПользователей.Используется - | И ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей) - | - |ИНДЕКСИРОВАТЬ ПО - | СоставыГруппПользователей.ГруппаПользователей"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - ТекстЗапросаГрупп = СтрЗаменить(ТекстЗапросаГрупп, - "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - ТекстЗапросаНовыхНаборовГрупп = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | СоставыГруппПользователей.Пользователь КАК Пользователь, - | СоставыГруппПользователей.ГруппаПользователей КАК Группа - |ПОМЕСТИТЬ НовыеНаборыГрупп - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы - | ПО СоставыГруппПользователей.ГруппаПользователей = АктивныеГруппы.Группа - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) - | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА) - | И (СоставыГруппПользователей.Используется) - | - |ИНДЕКСИРОВАТЬ ПО - | Пользователь, - | Группа"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - ИмяСправочникаГрупп = "ГруппыВнешнихПользователей"; - Иначе - ИмяСправочникаГрупп = "ГруппыПользователей"; - КонецЕсли; - - ЭлементыДанных = НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, - ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, "НаборГруппПользователей", ИмяСправочникаГрупп); - - КоличествоВЗапросе = ЭлементыДанных.Количество() + 1; - Возврат ЭлементыДанных; - -КонецФункции - -// Для функций НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа, -// НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей. -// -Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, - ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, ИмяПоляНабора, ИмяСправочникаГрупп) - - ЧастиЗапроса = Новый Массив; - ЧастиЗапроса.Добавить(ТекстЗапросаГрупп); - ЧастиЗапроса.Добавить(ТекстЗапросаНовыхНаборовГрупп); - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | НовыеНаборыГрупп.Пользователь КАК Пользователь, - | НовыеНаборыГрупп.Группа КАК Группа - |ИЗ - | НовыеНаборыГрупп КАК НовыеНаборыГрупп - | - |УПОРЯДОЧИТЬ ПО - | Пользователь, - | Группа - |ИТОГИ ПО - | Пользователь - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НаборыГрупп.Ссылка КАК ТекущаяСсылка, - | НаборыГрупп.Пользователь КАК Пользователь, - | ВЫБОР - | КОГДА НаборыГрупп.НовыйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - | ТОГДА НаборыГрупп.РазрешенныйНаборГруппДоступа - | ИНАЧЕ НаборыГрупп.НовыйНаборГруппДоступа - | КОНЕЦ КАК ТекущийНаборГрупп - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГрупп - |ГДЕ - | НаборыГрупп.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГрупп.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | И НаборыГрупп.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | И НЕ(НаборыГрупп.РазрешенныйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - | И НаборыГрупп.НовыйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) - | И НЕ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | НовыеНаборыГрупп КАК НовыеНаборыГрупп - | ГДЕ - | НовыеНаборыГрупп.Пользователь = НаборыГрупп.Пользователь)) - | И &УточнениеПланаЗапроса - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НаборыГрупп.Ссылка КАК Ссылка - |ПОМЕСТИТЬ НаборыСАктивнымиГруппами - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГрупп - |ГДЕ - | НаборыГрупп.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГрупп.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) - | И НЕ ЛОЖЬ В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ЛОЖЬ - | ИЗ - | Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов - | ЛЕВОЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы - | ПО - | ГруппыНаборов.Группа = АктивныеГруппы.Группа - | ГДЕ - | ГруппыНаборов.Ссылка = НаборыГрупп.Ссылка - | И АктивныеГруппы.Группа ЕСТЬ NULL) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НаборыГрупп.Ссылка КАК НаборГрупп, - | ГруппыНаборов.Группа КАК Группа - |ИЗ - | НаборыСАктивнымиГруппами КАК НаборыГрупп - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов - | ПО (ГруппыНаборов.Ссылка = НаборыГрупп.Ссылка) - | - |УПОРЯДОЧИТЬ ПО - | НаборГрупп, - | Группа - |ИТОГИ ПО - | НаборГрупп - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаборыГруппДоступа.НовыйНаборГруппДоступа КАК НовыйНабор - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - |ГДЕ - | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГруппДоступа.НовыйНаборГруппДоступа <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка)"; - - ЧастиЗапроса.Добавить(ТекстЗапроса); - Запрос.Текст = СтрСоединить(ЧастиЗапроса, ОбщегоНазначения.РазделительПакетаЗапросов()); - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА", "ИСТИНА"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка)", - "ЗНАЧЕНИЕ(Справочник." + ИмяСправочникаГрупп + ".ПустаяСсылка)"); // @query-part-1, @query-part-2 - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "НовыйНаборГруппДоступа", "Новый" + ИмяПоляНабора); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "РазрешенныйНаборГруппДоступа", "Разрешенный" + ИмяПоляНабора); - - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - НовыеНаборы = РезультатыЗапроса[6].Выгрузить(); - РезультатыЗапроса[6] = Неопределено; - НовыеНаборы.Индексы.Добавить("НовыйНабор"); - - СуществующиеНаборыГрупп = Новый Соответствие; - Выгрузка = РезультатыЗапроса[5].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - РезультатыЗапроса[5] = Неопределено; - Для Каждого СтрокаДЗ Из Выгрузка.Строки Цикл - ГруппыНабора = СтрокаДЗ.Строки.ВыгрузитьКолонку("Группа"); - СуществующиеНаборыГрупп.Вставить(СтрокаДанныхДляХеширования(ГруппыНабора), - Новый Структура("НаборГрупп, НаборГруппНовый", СтрокаДЗ.НаборГрупп, - НовыеНаборы.Найти(СтрокаДЗ.НаборГрупп, "НовыйНабор") <> Неопределено)); - КонецЦикла; - Выгрузка.Строки.Очистить(); - НовыеНаборы.Очистить(); - - НовыеНаборыГрупп = Новый Соответствие; - Выгрузка = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - РезультатыЗапроса[2] = Неопределено; - Для Каждого СтрокаДЗ Из Выгрузка.Строки Цикл - ГруппыНабора = СтрокаДЗ.Строки.ВыгрузитьКолонку("Группа"); - СуществующийНаборГрупп = СуществующиеНаборыГрупп.Получить(СтрокаДанныхДляХеширования(ГруппыНабора)); - Свойства = Новый Структура("НаборГрупп, НаборГруппНовый, ГруппыНабора, ИдентификаторГрупп"); - Если СуществующийНаборГрупп = Неопределено Тогда - Свойства.ГруппыНабора = ГруппыНабора; - Свойства.ИдентификаторГрупп = Новый УникальныйИдентификатор; - Иначе - Свойства.НаборГрупп = СуществующийНаборГрупп.НаборГрупп; - Свойства.НаборГруппНовый = СуществующийНаборГрупп.НаборГруппНовый; - КонецЕсли; - НовыеНаборыГрупп.Вставить(СтрокаДЗ.Пользователь, Свойства); - КонецЦикла; - Выгрузка.Строки.Очистить(); - СуществующиеНаборыГрупп.Очистить(); - - Выборка = РезультатыЗапроса[3].Выбрать(); - РезультатыЗапроса.Очистить(); - - ЭлементыДанных = Новый ТаблицаЗначений; - ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка"); - ЭлементыДанных.Колонки.Добавить("НаборГрупп"); - ЭлементыДанных.Колонки.Добавить("НаборГруппНовый", Новый ОписаниеТипов("Булево")); - ЭлементыДанных.Колонки.Добавить("ГруппыНабора"); - ЭлементыДанных.Колонки.Добавить("ИдентификаторГрупп"); - ПустойНабор = ПредопределенноеЗначение("Справочник.НаборыГруппДоступа.ПустаяСсылка"); - - Пока Выборка.Следующий() Цикл - НовыйНаборГрупп = НовыеНаборыГрупп.Получить(Выборка.Пользователь); - Если НовыйНаборГрупп <> Неопределено - И НовыйНаборГрупп.НаборГрупп = Выборка.ТекущийНаборГрупп Тогда - Продолжить; - КонецЕсли; - СтрокаТЗ = ЭлементыДанных.Добавить(); - СтрокаТЗ.ТекущаяСсылка = Выборка.ТекущаяСсылка; - Если НовыйНаборГрупп = Неопределено Тогда - СтрокаТЗ.НаборГрупп = ПустойНабор; - Продолжить; - ИначеЕсли НовыйНаборГрупп.НаборГрупп <> Неопределено Тогда - СтрокаТЗ.НаборГрупп = НовыйНаборГрупп.НаборГрупп; - СтрокаТЗ.НаборГруппНовый = НовыйНаборГрупп.НаборГруппНовый; - Продолжить; - КонецЕсли; - СтрокаТЗ.ГруппыНабора = НовыйНаборГрупп.ГруппыНабора; - СтрокаТЗ.ИдентификаторГрупп = НовыйНаборГрупп.ИдентификаторГрупп; - КонецЦикла; - - Возврат ЭлементыДанных; - -КонецФункции - -// Для процедуры ОбновитьНаборыГруппДоступа. -Процедура ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, - ПараметрыОбновления, ЭтоОбновлениеНазначенныхНаборовГруппДоступа) - - ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; - - Если ЭтоОбновлениеНазначенныхНаборовГруппДоступа Тогда - ИмяПоляНабора = "НаборГруппДоступа"; - ТипЭлементовНабора = Справочники.ГруппыДоступа.ПустаяСсылка(); - ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()); - - Иначе - ИмяПоляНабора = "НаборГруппПользователей"; - Если Не ДляВнешнихПользователей Тогда - ТипЭлементовНабора = Справочники.ГруппыПользователей.ПустаяСсылка(); - ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы пользователей'", - ОбщегоНазначения.КодОсновногоЯзыка()); - Иначе - ТипЭлементовНабора = Справочники.ГруппыВнешнихПользователей.ПустаяСсылка(); - ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы внешних пользователей'", - ОбщегоНазначения.КодОсновногоЯзыка()); - КонецЕсли; - КонецЕсли; - - НовыеНаборыГрупп = Новый Соответствие; - - Для Каждого Строка Из ЭлементыДанных Цикл - Если Строка.НаборГрупп = Неопределено Тогда - ОписаниеНабораГрупп = НовыеНаборыГрупп.Получить(Строка.ИдентификаторГрупп); - Если ОписаниеНабораГрупп = Неопределено Тогда - ОписаниеНабораГрупп = Новый Структура("НаборГрупп, НаборГруппНовый",, Ложь); - // @skip-check query-in-loop - Порционная обработка данных - ОписаниеНабораГрупп.НаборГрупп = НовыйНаборГрупп(Строка.ГруппыНабора, - ПараметрыОбновления.ДляВнешнихПользователей, - ТипЭлементовНабора, - ИмяПоляНабора, - ПредставлениеЭлементовГрупп, - ОписаниеНабораГрупп.НаборГруппНовый); - НовыеНаборыГрупп.Вставить(Строка.ИдентификаторГрупп, ОписаниеНабораГрупп); - КонецЕсли; - Строка.НаборГрупп = ОписаниеНабораГрупп.НаборГрупп; - Строка.НаборГруппНовый = ОписаниеНабораГрупп.НаборГруппНовый; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - - Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); - Если Строка.НаборГруппНовый Тогда - Объект["Новый" + ИмяПоляНабора] = Строка.НаборГрупп; - Иначе - Объект["Разрешенный" + ИмяПоляНабора] = Строка.НаборГрупп; - Объект["Новый" + ИмяПоляНабора] = ПараметрыОбновления.ПустойНаборГруппДоступа; - КонецЕсли; - Объект.Записать(); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбновитьНаборыГруппНазначенныеПользователямВСправочнике. -Функция НовыйНаборГрупп(ГруппыНабора, ДляВнешнихПользователей, ТипЭлементовНабора, - ИмяПоляНабора, ПредставлениеЭлементовГрупп, НаборГруппНовый) - - НоваяСсылка = Справочники.НаборыГруппДоступа.ПолучитьСсылку(); - Объект = СлужебныйЭлемент(Справочники.НаборыГруппДоступа); - Объект.УстановитьСсылкуНового(НоваяСсылка); - Объект.ДляВнешнихПользователей = ДляВнешнихПользователей; - Объект.ТипЭлементовНабора = ТипЭлементовНабора; - Объект.Наименование = Строка(НоваяСсылка.УникальныйИдентификатор()) + " (" + ПредставлениеЭлементовГрупп + ")"; - - Для Каждого ГруппаНабора Из ГруппыНабора Цикл - Объект.Группы.Добавить().Группа = ГруппаНабора; - КонецЦикла; - - ЗаполнитьХешНабораГрупп(Объект); - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("ТипЭлементовНабора", Объект.ТипЭлементовНабора); - ЭлементБлокировки.УстановитьЗначение("Хеш", Объект.Хеш); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Если НаборГруппСуществует(Объект) Тогда - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); - Запрос.УстановитьПараметр("СуществующийНабор", Объект.Ссылка); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | Справочник.НаборыГруппДоступа КАК ВсеНаборы - |ГДЕ - | ВсеНаборы.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И ВсеНаборы.НовыйНаборГруппДоступа = &СуществующийНабор"; - Запрос.Текст = СтрЗаменить(Запрос.Текст, "НовыйНаборГруппДоступа", "Новый" + ИмяПоляНабора); - - Если Не Запрос.Выполнить().Пустой() Тогда - НаборГруппНовый = Истина; - КонецЕсли; - Иначе - Объект["Новый" + ИмяПоляНабора] = НоваяСсылка; - Объект.Записать(); - НаборГруппНовый = Истина; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Возврат Объект.Ссылка; - -КонецФункции - -// Для функции НовыйНаборГрупп и процедуры ЗаполнитьПустыеХешиНаборовГрупп. -Процедура ЗаполнитьХешНабораГрупп(Объект) - - Объект.Группы.Сортировать("Группа", Новый СравнениеЗначений); - - ДанныеДляХеша = Объект.Группы.ВыгрузитьКолонку("Группа"); - СтрокаДляХеша = СтрокаДанныхДляХеширования(ДанныеДляХеша); - Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); - Хеширование.Добавить(СтрокаДляХеша); - Объект.Хеш = Хеширование.ХешСумма; - -КонецПроцедуры - -// Для функции НовыйНаборГрупп. -Функция НаборГруппСуществует(Объект) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ТипЭлементовНабора", Объект.ТипЭлементовНабора); - Запрос.УстановитьПараметр("Хеш", Объект.Хеш); - Запрос.Текст = - "ВЫБРАТЬ - | СуществующиеНаборы.Ссылка КАК СсылкаНабора, - | СуществующиеНаборы.Группы.( - | Группы.Группа КАК Группа - | ) КАК ГруппыНабора - |ИЗ - | Справочник.НаборыГруппДоступа КАК СуществующиеНаборы - |ГДЕ - | СуществующиеНаборы.ТипЭлементовНабора = &ТипЭлементовНабора - | И СуществующиеНаборы.Хеш = &Хеш - | - |УПОРЯДОЧИТЬ ПО - | Ссылка"; - - ГруппыОбъекта = Объект.Группы.Выгрузить(, "Группа"); - ГруппыОбъекта.Индексы.Добавить("Группа"); - - Выгрузка = Запрос.Выполнить().Выгрузить(); - Для Каждого Строка Из Выгрузка Цикл - Если ГруппыОбъекта.Количество() <> Строка.ГруппыНабора.Количество() Тогда - Продолжить; - КонецЕсли; - ГруппыСовпадают = Истина; - Для Каждого Подстрока Из Строка.ГруппыНабора Цикл - Если ГруппыОбъекта.Найти(Подстрока.Группа, "Группа") = Неопределено Тогда - ГруппыСовпадают = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Если ГруппыСовпадают Тогда - Объект = Новый Структура("Ссылка", Строка.СсылкаНабора); - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для процедуры ОбновитьНаборыГруппДоступа. -Процедура ОбновитьНаборыГруппРазрешенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления) - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - - Для Каждого Строка Из ЭлементыДанных Цикл - ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - - Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); - Если Объект <> Неопределено Тогда - Если ЗначениеЗаполнено(Объект.НовыйНаборГруппДоступа) Тогда - Объект.РазрешенныйНаборГруппДоступа = Объект.НовыйНаборГруппДоступа; - Объект.НовыйНаборГруппДоступа = ПараметрыОбновления.ПустойНаборГруппДоступа; - КонецЕсли; - Если ЗначениеЗаполнено(Объект.НовыйНаборГруппПользователей) Тогда - Объект.РазрешенныйНаборГруппПользователей = Объект.НовыйНаборГруппПользователей; - Объект.НовыйНаборГруппПользователей = ПараметрыОбновления.ПустойНаборГруппДоступа; - КонецЕсли; - Если Объект.Модифицированность() Тогда - Объект.Записать(); - КонецЕсли; - КонецЕсли; - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура ОчиститьПраваНесуществующихНаборовГруппДоступа(ПараметрыОбновления) - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступаНаборов.НаборГруппДоступа КАК Набор - |ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборов - |ГДЕ - | КлючиДоступаНаборов.НаборГруппДоступа.Ссылка ЕСТЬ NULL - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступаНаборов.Пользователь КАК Набор - |ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаНаборов - |ГДЕ - | КлючиДоступаНаборов.Пользователь.Ссылка ЕСТЬ NULL - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступаНаборов.ВнешнийПользователь КАК Набор - |ИЗ - | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаНаборов - |ГДЕ - | КлючиДоступаНаборов.ВнешнийПользователь.Ссылка ЕСТЬ NULL"; - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - Выборка = РезультатыЗапроса[0].Выбрать(); - Пока Выборка.Следующий() Цикл - // @skip-check query-in-loop - Порционная обработка данных - УдалитьЗаписиРегистраДляНабора(Выборка.Набор, - "КлючиДоступаНаборовГруппДоступа", "НаборГруппДоступа"); - КонецЦикла; - - Выборка = РезультатыЗапроса[1].Выбрать(); - Пока Выборка.Следующий() Цикл - // @skip-check query-in-loop - Порционная обработка данных - УдалитьЗаписиРегистраДляНабора(Выборка.Набор, - "КлючиДоступаПользователей", "Пользователь"); - КонецЦикла; - - Выборка = РезультатыЗапроса[2].Выбрать(); - Пока Выборка.Следующий() Цикл - // @skip-check query-in-loop - Порционная обработка данных - УдалитьЗаписиРегистраДляНабора(Выборка.Набор, - "КлючиДоступаВнешнихПользователей", "ВнешнийПользователь"); - КонецЦикла; - -КонецПроцедуры - -// Для функции НаборыГруппДоступаДляОбновления. -Функция УстаревшиеНаборыГруппДоступаВСправочнике(ПараметрыОбновления, КоличествоВЗапросе) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); - Запрос.УстановитьПараметр("ДатаУстаревания", ДатаУстаревания()); - Запрос.УстановитьПараметр("РазрешенныйПустойНабор", - УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); - - Запрос.Текст = - "ВЫБРАТЬ - | НаборыГруппДоступа.Ссылка КАК ТекущаяСсылка, - | НаборыГруппДоступа.ТипЭлементовНабора КАК ТипЭлементовНабора, - | ЛОЖЬ КАК Используется, - | ИСТИНА КАК Удалить - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - |ГДЕ - | НаборыГруппДоступа.ТипЭлементовНабора = НЕОПРЕДЕЛЕНО - | И &УточнениеПланаЗапроса - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | НаборыГруппДоступа.Ссылка, - | НаборыГруппДоступа.ТипЭлементовНабора, - | ЛОЖЬ, - | ИСТИНА - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - |ГДЕ - | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | И (ВЫРАЗИТЬ(НаборыГруппДоступа.Пользователь КАК Справочник.Пользователи).Ссылка ЕСТЬ NULL - | ИЛИ НаборыГруппДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(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) - | ИЛИ НаборыГруппПользователей.НеИспользуетсяС < &ДатаУстаревания - | КОНЕЦ"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - - ЭлементыДанных = Запрос.Выполнить().Выгрузить(); - - КоличествоВЗапросе = ЭлементыДанных.Количество(); - Возврат ЭлементыДанных; - -КонецФункции - -// Для функций УстаревшиеНаборыГруппДоступаВСправочнике, ЭлементыДляОбновления. -Функция ДатаУстаревания() - - Возврат ТекущаяДатаСеанса() - КоличествоЧасовУстареванияНеиспользуемыхЭлементов() * 60 * 60; - -КонецФункции - -// Для процедуры ОбновитьПорциюЭлементов. -Процедура ОбработатьУстаревшиеНаборыВСправочнике(ЭлементыДанных, ПараметрыОбновления) - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - - Для Каждого Строка Из ЭлементыДанных Цикл - ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); - Если Объект <> Неопределено Тогда - Если Строка.Используется Тогда - Объект.НеИспользуетсяС = '00010101'; - ИначеЕсли Не Строка.Удалить Тогда - Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); - Иначе - Объект.ТипЭлементовНабора = Неопределено; - Объект.Хеш = 0; - Объект.Группы.Очистить(); - КонецЕсли; - Объект.Записать(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если Не Строка.Используется И Строка.Удалить Тогда - // @skip-check query-in-loop - Порционная обработка данных - УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаНаборовГруппДоступа", "НаборГруппДоступа"); - // @skip-check query-in-loop - Порционная обработка данных - УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаПользователей", "Пользователь"); - // @skip-check query-in-loop - Порционная обработка данных - УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаВнешнихПользователей", "ВнешнийПользователь"); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); - Если Объект <> Неопределено Тогда - Объект.Удалить(); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры УдалитьУстаревшиеНаборыВСправочнике, ОчиститьПраваНесуществующихНаборовГруппДоступа. -Процедура УдалитьЗаписиРегистраДляНабора(Набор, ИмяРегистраСведений, ИмяПоляНабора) - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Набор", Набор); - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1000 - | КлючиДоступаНаборов.КлючДоступа КАК КлючДоступа - |ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборов - |ГДЕ - | КлючиДоступаНаборов.НаборГруппДоступа = &Набор"; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "КлючиДоступаНаборовГруппДоступа", ИмяРегистраСведений); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "НаборГруппДоступа", ИмяПоляНабора); - - ПолноеИмяРегистраСведений = "РегистрСведений." + ИмяРегистраСведений; - - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено; - - Пока Истина Цикл - Выгрузка = Запрос.Выполнить().Выгрузить(); - Если Выгрузка.Количество() = 0 Тогда - Прервать; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистраСведений); - ЭлементБлокировки.УстановитьЗначение(ИмяПоляНабора, Набор); - ЭлементБлокировки.ИсточникДанных = Выгрузка; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючДоступа", "КлючДоступа"); - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраСведений]); - Если Не ПакетныйРежим Тогда - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляНабора]; // ЭлементОтбора - ЭлементОтбора.Установить(Набор); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Для Каждого Строка Из Выгрузка Цикл - Если ПакетныйРежим Тогда - СтараяЗапись = НаборЗаписей.Добавить(); - СтараяЗапись[ИмяПоляНабора] = Набор; - СтараяЗапись.КлючДоступа = Строка.КлючДоступа; - Иначе - НаборЗаписей.Отбор.КлючДоступа.Установить(Строка.КлючДоступа); - НаборЗаписей.Записать(); - КонецЕсли; - КонецЦикла; - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимУдаления); - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура ОбновитьПраваНаРазрешенныйКлючДоступа(ЕстьИзменения = Ложь) - - ОбновитьГруппыДоступаРазрешенногоКлючаДоступа( , ЕстьИзменения); - -КонецПроцедуры - -// Для процедуры ОбновитьПраваНаРазрешенныйКлючДоступа. -Процедура ОбновитьГруппыДоступаРазрешенногоКлючаДоступа(ГруппыДоступа = Неопределено, ЕстьИзменения = Ложь) Экспорт - - УстановитьПривилегированныйРежим(Истина); - РазрешенныйКлючДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа(); - РазрешенныйПустойНабор = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа(); - - Блокировка = Новый БлокировкаДанных; - - // Обновление групп доступа в регистре КлючиДоступаГруппДоступа. - ЗапросГрупп = Новый Запрос; - ЗапросГрупп.УстановитьПараметр("КлючДоступа", РазрешенныйКлючДоступа); - ЗапросГрупп.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); - ЗапросГрупп.Текст = ТекстЗапросаВыбораРазличийГруппДоступаРазрешенногоКлюча(); - УстановитьУсловиеОтбораВЗапросе(ЗапросГрупп, ГруппыДоступа, "ГруппыДоступа", - "&УсловиеОтбораГруппДоступа1:ГруппыДоступа.Ссылка - |&УсловиеОтбораГруппДоступа2:СтарыеДанные.ГруппаДоступа"); // @query-part-2 - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - ЭлементБлокировкиГрупп = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); - ЭлементБлокировкиГрупп.УстановитьЗначение("КлючДоступа", РазрешенныйКлючДоступа); - НаборЗаписейГрупп = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); - Если Не ПакетныйРежим Тогда - НаборЗаписейГрупп.Отбор.КлючДоступа.Установить(РазрешенныйКлючДоступа); - КонецЕсли; - - // Обновление наборов групп доступа в регистре КлючиДоступаНаборовГруппДоступа. - ЗапросПравДляГруппДоступа = Новый Запрос; - ЗапросПравДляГруппДоступа.УстановитьПараметр("КлючДоступа", РазрешенныйКлючДоступа); - ЗапросПравДляГруппДоступа.УстановитьПараметр("РазрешенныйПустойНабор", РазрешенныйПустойНабор); - ЗапросПравДляГруппДоступа.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа(); - - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", РазрешенныйКлючДоступа); - ПраваДляГруппДоступа = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); - Если Не ПакетныйРежим Тогда - ПраваДляГруппДоступа.Отбор.КлючДоступа.Установить(РазрешенныйКлючДоступа); - КонецЕсли; - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - - РезультатЗапросаГрупп = ЗапросГрупп.Выполнить(); - ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаГрупп, - НаборЗаписейГрупп, "ГруппаДоступа", РазрешенныйКлючДоступа, ЕстьИзменения); - - РезультатЗапросаПравДляГруппДоступа = ЗапросПравДляГруппДоступа.Выполнить(); - ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаПравДляГруппДоступа, - ПраваДляГруппДоступа, "НаборГруппДоступа", РазрешенныйКлючДоступа, ЕстьИзменения); - - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ОбновитьГруппыРазрешенногоКлючаДоступа. -Функция ТекстЗапросаВыбораРазличийГруппДоступаРазрешенногоКлюча() - - ТекстЗапроса = - "ВЫБРАТЬ - | ВсеСтроки.ГруппаДоступа КАК ГруппаДоступа, - | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, - | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | (ВЫБРАТЬ - | ГруппыДоступа.Ссылка КАК ГруппаДоступа, - | ИСТИНА КАК ПравоИзменение, - | ИСТИНА КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа - | ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка - | И (ГруппыДоступа.Профиль <> &ПрофильАдминистратор) - | И (НЕ ГруппыДоступа.ПометкаУдаления) - | И (НЕ ПрофилиГруппДоступа.ПометкаУдаления) - | И (&УсловиеОтбораГруппДоступа1) - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - | ИЗ - | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа - | ГДЕ - | УчастникиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка)) - | И (&УточнениеПланаЗапроса) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.ГруппаДоступа, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК СтарыеДанные - | ГДЕ - | СтарыеДанные.КлючДоступа = &КлючДоступа - | И &УсловиеОтбораГруппДоступа2) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.ГруппаДоступа, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки"; - - УстановитьУточнениеПланаЗапроса(ТекстЗапроса); - - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедуры ОбновитьПорциюЭлементов. -Процедура УдалитьУстаревшиеЭлементыДанныхСписка(ЭлементыДанных, ПараметрыОбновления) - - Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда - УдалитьУстаревшиеЭлементыДанныхСсылочногоТипа(ЭлементыДанных, ПараметрыОбновления) - Иначе - УдалитьУстаревшиеЭлементыДанныхРегистров(ЭлементыДанных, ПараметрыОбновления) - КонецЕсли; - -КонецПроцедуры - -// Для процедуры УдалитьУстаревшиеЭлементыДанныхСписка. -Процедура УдалитьУстаревшиеЭлементыДанныхСсылочногоТипа(ЭлементыДанных, ПараметрыОбновления) - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - Если ПакетныйРежим Тогда - РазмерПорции = 1000; // Удаление N элементов данных по 1000 за раз. - Иначе - РазмерПорции = 100; // Удаление N элементов данных по 100 за раз. - КонецЕсли; - ПорцияЭлементовДанных = Неопределено; - КоличествоЭлементов = ЭлементыДанных.Количество(); - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); - НаборЗаписейДляУдаления = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); - - Индекс = 0; - Пока Индекс < КоличествоЭлементов Цикл - Если ПорцияЭлементовДанных = Неопределено Тогда - ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); - ПорцияДляОбновления = ПорцияЭлементовДанных.Скопировать(); - ПорцияДляПроверки = ПорцияЭлементовДанных.Скопировать(); - КонецЕсли; - ЭлементДанных = ЭлементыДанных[Индекс]; - ЗаполнитьЗначенияСвойств(ПорцияЭлементовДанных.Добавить(), ЭлементДанных); - Если ЭлементДанных.Обновить Тогда - ЗаполнитьЗначенияСвойств(ПорцияДляОбновления.Добавить(), ЭлементДанных); - ИначеЕсли Не ЭлементДанных.Удалить Тогда // Не Обновить И Не Удалить. - ЗаполнитьЗначенияСвойств(ПорцияДляПроверки.Добавить(), ЭлементДанных); - КонецЕсли; - - Индекс = Индекс + 1; - Если ПорцияЭлементовДанных.Количество() < РазмерПорции И Индекс < КоличествоЭлементов Тогда - Продолжить; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); - ЭлементБлокировки.ИсточникДанных = ПорцияЭлементовДанных; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Объект", "ТекущаяСсылка"); - - Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда - ЗапросДляОбновления = Новый Запрос; - ЗапросДляОбновления.Текст = ПараметрыОбновления.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных; - ЗапросДляОбновления.УстановитьПараметр("ЭлементыДанных", ПорцияДляОбновления); - КонецЕсли; - Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда - ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "ТекущаяСсылка"); - ЗапросДляПроверки = Новый Запрос; - ЗапросДляПроверки.Текст = ПараметрыОбновления.ТекстЗапросаПроверкиУстаревшихЭлементовДанных; - ЗапросДляПроверки.УстановитьПараметр("ЭлементыДанных", ПорцияДляПроверки); - УстановитьУточнениеПланаЗапроса(ЗапросДляПроверки.Текст); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда - // @skip-check query-in-loop - Порционная обработка данных - ДанныеДляОбновления = ЗапросДляОбновления.Выполнить().Выгрузить(); - КонецЕсли; - Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда - // @skip-check query-in-loop - Порционная обработка данных - ДанныеДляУдаления = ЗапросДляПроверки.Выполнить().Выгрузить(); - КонецЕсли; - Для Каждого Строка Из ПорцияЭлементовДанных Цикл - Если Не ПакетныйРежим Тогда - НаборЗаписей.Отбор.Объект.Установить(Строка.ТекущаяСсылка); - КонецЕсли; - Если Строка.Обновить Тогда - Если Не ПакетныйРежим Тогда - НаборЗаписей.Очистить(); - КонецЕсли; - НайденнаяСтрока = ДанныеДляОбновления.Найти(Строка.ТекущаяСсылка, "Объект"); - Если НайденнаяСтрока <> Неопределено Тогда - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - НайденнаяСтрока.КлючДоступаПользователей = Неопределено; - Иначе - НайденнаяСтрока.КлючДоступаВнешнихПользователей = Неопределено; - КонецЕсли; - Если ЗначениеЗаполнено(НайденнаяСтрока.КлючДоступаВнешнихПользователей) - Или ЗначениеЗаполнено(НайденнаяСтрока.КлючДоступаПользователей) Тогда - ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НайденнаяСтрока); - ИначеЕсли ПакетныйРежим Тогда - ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), НайденнаяСтрока); - КонецЕсли; - Если Не ПакетныйРежим Тогда - НаборЗаписей.Записать(); - КонецЕсли; - КонецЕсли; - ИначеЕсли Строка.Удалить - Или ЗначениеЗаполнено(ПорцияДляПроверки) - И ДанныеДляУдаления.Найти(Строка.ТекущаяСсылка, "ТекущаяСсылка") <> Неопределено Тогда - - Если ПакетныйРежим Тогда - НаборЗаписейДляУдаления.Добавить().Объект = Строка.ТекущаяСсылка; - Иначе - НаборЗаписей.Очистить(); - НаборЗаписей.Записать(); - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если ПакетныйРежим Тогда - Если ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимСлияния); - КонецЕсли; - Если ЗначениеЗаполнено(НаборЗаписейДляУдаления) Тогда - НаборЗаписейДляУдаления.Записать(РежимУдаления); - КонецЕсли; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - Если ПакетныйРежим Тогда - НаборЗаписей.Очистить(); - НаборЗаписейДляУдаления.Очистить(); - КонецЕсли; - КоличествоОбработанных = ПорцияЭлементовДанных.Количество(); - ПорцияЭлементовДанных = Неопределено; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры УдалитьУстаревшиеЭлементыДанныхСписка. -Процедура УдалитьУстаревшиеЭлементыДанныхРегистров(ЭлементыДанных, ПараметрыОбновления) - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - Если ПакетныйРежим Тогда - РазмерПорции = 1000; // Удаление N элементов данных по 1000 за раз. - Иначе - РазмерПорции = 100; // Удаление N элементов данных по 100 за раз. - КонецЕсли; - - Если ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) - И ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных <> "НекорректныеЭлементыОбщегоРегистра" Тогда - - ИмяРегистра = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; - Иначе - ИмяРегистра = "КлючиДоступаКРегистрам"; - КонецЕсли; - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистра]); - НаборЗаписейДляУдаления = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистра]); - - ИзмеренияСпискаДляБлокировки = Новый Массив; - ОпорныеПоля = ПараметрыОбновления.ОпорныеПоля; - Если ОпорныеПоля = Неопределено Тогда - КоличествоИспользуемыхОпорныхПолей = 0; - МаксимальноеКоличествоОпорныхПолей = - УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистра); - Иначе - КоличествоИспользуемыхОпорныхПолей = ОпорныеПоля.Используемые.Количество(); - МаксимальноеКоличествоОпорныхПолей = ОпорныеПоля.МаксимальноеКоличество; - ОписаниеПолейБлокировки = УправлениеДоступомСлужебныйПовтИсп.ОписаниеПолейБлокировкиРегистра( - ПараметрыОбновления.Список); - ПоляБлокировкиСписка = СтрРазделить(ОписаниеПолейБлокировки.СписокПолей, ","); - БлокироватьСписокПоРегистратору = Ложь; - Номер = 1; - Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл - ИндексПоля = ПоляБлокировкиСписка.Найти(ИмяОпорногоПоля); - Если ИндексПоля <> Неопределено Тогда - ОписаниеПоля = ОписаниеПолейБлокировки.ОписаниеПолей.Получить(ИндексПоля); - ИзмерениеСписка = Новый Структура; - ИзмерениеСписка.Вставить("ИмяОпорногоПоля", ОписаниеПоля.Имя); - ИзмерениеСписка.Вставить("Тип", ОписаниеПоля.Тип); - ИзмерениеСписка.Вставить("ИмяПоля", СтрШаблон("Поле%1", Номер)); - ИзмеренияСпискаДляБлокировки.Добавить(ИзмерениеСписка); - Если ОписаниеПоля.Имя = "Регистратор" - И ОписаниеПолейБлокировки.БлокироватьПоРегистратору Тогда - БлокироватьСписокПоРегистратору = Истина; - КонецЕсли; - КонецЕсли; - Номер = Номер + 1; - КонецЦикла; - КонецЕсли; - ИменаИзмерений = Новый Массив; - Если ИмяРегистра = "КлючиДоступаКРегистрам" Тогда - ИменаИзмерений.Добавить("Регистр"); - КонецЕсли; - ИменаИзмерений.Добавить("ВариантДоступа"); - Для Номер = 1 По КоличествоИспользуемыхОпорныхПолей Цикл - ИменаИзмерений.Добавить(СтрШаблон("Поле%1", Номер)); - КонецЦикла; - - ОтборДанных = Новый Структура; - ТочныйОтборДанных = Новый Структура; - Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл - ОтборДанных.Вставить(ИмяИзмерения); - ТочныйОтборДанных.Вставить(ИмяИзмерения); - КонецЦикла; - Для Счетчик = Номер По МаксимальноеКоличествоОпорныхПолей Цикл - ТочныйОтборДанных.Вставить(СтрШаблон("Поле%1", Счетчик), - Перечисления.ДополнительныеЗначенияДоступа.Null); - КонецЦикла; - - ПорцияЭлементовДанных = Неопределено; - КоличествоЭлементов = ЭлементыДанных.Количество(); - - Индекс = 0; - Пока Индекс < КоличествоЭлементов Цикл - Если ПорцияЭлементовДанных = Неопределено Тогда - ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); - ПорцияДляОбновления = ПорцияЭлементовДанных.Скопировать(); - ПорцияДляПроверки = ПорцияЭлементовДанных.Скопировать(); - КонецЕсли; - ЭлементДанных = ЭлементыДанных[Индекс]; - ЗаполнитьЗначенияСвойств(ПорцияЭлементовДанных.Добавить(), ЭлементДанных); - Если ЭлементДанных.Обновить Тогда - ЗаполнитьЗначенияСвойств(ПорцияДляОбновления.Добавить(), ЭлементДанных); - ИначеЕсли Не ЭлементДанных.Удалить Тогда // Не Обновить И Не Удалить. - Для Каждого ИзмерениеСписка Из ИзмеренияСпискаДляБлокировки Цикл - Если Не ИзмерениеСписка.Тип.СодержитТип(ТипЗнч(ЭлементДанных[ИзмерениеСписка.ИмяПоля])) Тогда - ЭлементДанных.Удалить = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - Если Не ЭлементДанных.Удалить Тогда - ЗаполнитьЗначенияСвойств(ПорцияДляПроверки.Добавить(), ЭлементДанных); - КонецЕсли; - КонецЕсли; - - Индекс = Индекс + 1; - Если ПорцияЭлементовДанных.Количество() < РазмерПорции И Индекс < КоличествоЭлементов Тогда - Продолжить; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистра); - ЭлементБлокировки.ИсточникДанных = ПорцияЭлементовДанных; - Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл - ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ИмяИзмерения, ИмяИзмерения); - КонецЦикла; - - Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда - ЗапросДляОбновления = Новый Запрос; - ЗапросДляОбновления.Текст = ПараметрыОбновления.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных; - ЗапросДляОбновления.УстановитьПараметр("ЭлементыДанных", ПорцияДляОбновления); - КонецЕсли; - Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда - Если БлокироватьСписокПоРегистратору Тогда - ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список + ".НаборЗаписей"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; - ЭлементБлокировки.ИспользоватьИзИсточникаДанных( - ИзмеренияСпискаДляБлокировки[0].ИмяОпорногоПоля, - ИзмеренияСпискаДляБлокировки[0].ИмяПоля); - Иначе - ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - Если ЗначениеЗаполнено(ИзмеренияСпискаДляБлокировки) Тогда - ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; - Для Каждого ИзмерениеСписка Из ИзмеренияСпискаДляБлокировки Цикл - ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ИзмерениеСписка.ИмяОпорногоПоля, - ИзмерениеСписка.ИмяПоля); - КонецЦикла; - КонецЕсли; - КонецЕсли; - ЗапросДляПроверки = Новый Запрос; - ЗапросДляПроверки.Текст = ПараметрыОбновления.ТекстЗапросаПроверкиУстаревшихЭлементовДанных; - ЗапросДляПроверки.УстановитьПараметр("КлючиДоступаКРегистрам", ПорцияДляПроверки); - УстановитьУточнениеПланаЗапроса(ЗапросДляПроверки.Текст); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда - // @skip-check query-in-loop - Порционная обработка данных - ДанныеДляОбновления = ЗапросДляОбновления.Выполнить().Выгрузить(); - КонецЕсли; - Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда - // @skip-check query-in-loop - Порционная обработка данных - ДанныеДляУдаления = ЗапросДляПроверки.Выполнить().Выгрузить(); - КонецЕсли; - Для Каждого Строка Из ПорцияЭлементовДанных Цикл - Если Не ПакетныйРежим Тогда - НаборЗаписей.Очистить(); - Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл - ЭлементОтбора = НаборЗаписей.Отбор[ИмяИзмерения]; // ЭлементОтбора - Если Строка[ИмяИзмерения] = Неопределено Тогда - ЭлементОтбора.Значение = Неопределено; - ЭлементОтбора.Использование = Истина; - Иначе - ЭлементОтбора.Установить(Строка[ИмяИзмерения]); - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если Строка.Обновить Тогда - ЗаполнитьЗначенияСвойств(ОтборДанных, Строка); - НайденныеСтроки = ДанныеДляОбновления.НайтиСтроки(ОтборДанных); - Если Не ЗначениеЗаполнено(НайденныеСтроки) Тогда - Продолжить; - КонецЕсли; - ЗаполнитьЗначенияСвойств(ТочныйОтборДанных, ОтборДанных); - ТочноНайденныеСтроки = ДанныеДляОбновления.НайтиСтроки(ТочныйОтборДанных); - Если ТочноНайденныеСтроки.Количество() > 0 Тогда - НайденнаяСтрока = ТочноНайденныеСтроки.Получить(0); - Если Не ПакетныйРежим Тогда - Если НайденныеСтроки.Количество() = 1 Тогда - Продолжить; - КонецЕсли; - ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НайденнаяСтрока); - КонецЕсли; - Иначе - НайденнаяСтрока = Неопределено; - НоваяЗапись = НаборЗаписей.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяЗапись, НайденныеСтроки[0]); - ЗаполнитьЗначенияСвойств(НоваяЗапись, ТочныйОтборДанных); - КонецЕсли; - Если ПакетныйРежим Тогда - Для Каждого УдаляемаяСтрока Из НайденныеСтроки Цикл - Если УдаляемаяСтрока <> НайденнаяСтрока Тогда - ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), УдаляемаяСтрока); - КонецЕсли; - КонецЦикла; - КонецЕсли; - ИначеЕсли Не Строка.Удалить И ЗначениеЗаполнено(ПорцияДляПроверки) Тогда - ЗаполнитьЗначенияСвойств(ОтборДанных, Строка); - Если ДанныеДляУдаления.НайтиСтроки(ОтборДанных).Количество() = 0 Тогда - Продолжить; - КонецЕсли; - КонецЕсли; - Если Не ПакетныйРежим Тогда - НаборЗаписей.Записать(); - ИначеЕсли Не Строка.Обновить Тогда - ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), Строка); - КонецЕсли; - КонецЦикла; - Если ПакетныйРежим Тогда - Если ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимСлияния); - КонецЕсли; - Если ЗначениеЗаполнено(НаборЗаписейДляУдаления) Тогда - НаборЗаписейДляУдаления.Записать(РежимУдаления); - КонецЕсли; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - Если ПакетныйРежим Тогда - НаборЗаписей.Очистить(); - НаборЗаписейДляУдаления.Очистить(); - КонецЕсли; - КоличествоОбработанных = ПорцияЭлементовДанных.Количество(); - ПорцияЭлементовДанных = Неопределено; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ВыполнитьОбновлениеДоступаСписка. -Процедура УдалитьОбъектыНедопустимыхТиповВРегистреКлючиДоступаКОбъектам() - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) КАК ТипСсылки - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным"; - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); - ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповСсылокДопустимыхОбъектов(); - Выборка = Запрос.Выполнить().Выбрать(); - - Запрос.Текст = - "ВЫБРАТЬ - | КлючиДоступаКДанным.Объект КАК Объект - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным - |ГДЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) = &Тип"; - - Пока Выборка.Следующий() Цикл - Если Выборка.ТипСсылки = Тип("Неопределено") Тогда - НаборЗаписей.Отбор.Объект.Установить(Неопределено); - НаборЗаписей.Записать(); - Продолжить; - ИначеЕсли ДопустимыеТипы.СодержитТип(Выборка.ТипСсылки) Тогда - Продолжить; - КонецЕсли; - Запрос.УстановитьПараметр("Тип", Выборка.ТипСсылки); - // @skip-check query-in-loop - Порционная обработка данных - Объекты = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Объект"); - Для Каждого Объект Из Объекты Цикл - НаборЗаписей.Отбор.Объект.Установить(Объект); - НаборЗаписей.Записать(); - КонецЦикла; - КонецЦикла; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - |ГДЕ - | КлючиДоступаКРегистрам.Регистр = НЕОПРЕДЕЛЕНО"; - - Если Запрос.Выполнить().Пустой() Тогда - Возврат; - КонецЕсли; - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКРегистрам); - НаборЗаписей.Отбор.Регистр.Установить(Неопределено); - НаборЗаписей.Записать(); - -КонецПроцедуры - -// Для процедуры ОбновитьПорциюЭлементов. -Процедура ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(ЭлементыДанных, ПараметрыОбновления) - - РазмерПорции = 100; // Загрузка N элементов данных по 100 за раз. - - Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда - ЭтоОбработкаСуществующихКомбинаций = Ложь; - ЭтоОбработкаНовыхКомбинаций = Ложь; - Иначе - ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; - ЭтоОбработкаСуществующихКомбинаций = ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами"; - ЭтоОбработкаНовыхКомбинаций = ПараметрыОбновления.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей - И ( ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" - Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей"); - КонецЕсли; - - Индекс = 0; - Пока Индекс < ЭлементыДанных.Количество() Цикл - - ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); - Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда - ПорцияЭлементовДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов("Число")); - ПорцияУдаляемыхЭлементовДанных = Новый Массив; - КонецЕсли; - КоличествоПропущенных = 0; - - Пока Индекс < ЭлементыДанных.Количество() - И ПорцияЭлементовДанных.Количество() < РазмерПорции - И (ПараметрыОбновления.ЭтоСсылочныйТип - Или ПорцияУдаляемыхЭлементовДанных.Количество() < РазмерПорции) Цикл - - ЭлементДанных = ЭлементыДанных[Индекс]; - - Если ЭтоОбработкаСуществующихКомбинаций - И НекорректнаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) Тогда - - Если ПорцияЭлементовДанных.Количество() > 0 Тогда - Прервать; - КонецЕсли; - ПорцияУдаляемыхЭлементовДанных.Добавить(ЭлементДанных); - - ИначеЕсли ЭтоОбработкаСуществующихКомбинаций - И ПорцияУдаляемыхЭлементовДанных.Количество() > 0 Тогда - Прервать; - - ИначеЕсли ЭтоОбработкаНовыхКомбинаций - И НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) Тогда - - КоличествоПропущенных = КоличествоПропущенных + 1; - Иначе - НоваяСтрока = ПорцияЭлементовДанных.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭлементДанных); - Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда - НоваяСтрока.ТекущаяСсылка = ПорцияЭлементовДанных.Индекс(НоваяСтрока) + 1; - КонецЕсли; - КонецЕсли; - Индекс = Индекс + 1; - КонецЦикла; - - Если ЭтоОбработкаСуществующихКомбинаций - И ПорцияУдаляемыхЭлементовДанных.Количество() > 0 Тогда - - УдалитьНекорректныеКомбинацииЗначенийОпорныхПолей(ПорцияУдаляемыхЭлементовДанных, ПараметрыОбновления); - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, ПорцияУдаляемыхЭлементовДанных.Количество()) Тогда - Прервать; - КонецЕсли; - КонецЕсли; - - Если ПорцияЭлементовДанных.Количество() > 0 Тогда - // @skip-check query-in-loop - Порционная обработка данных - ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ПорцияЭлементовДанных, ПараметрыОбновления); - КонецЕсли; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоПропущенных) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. -Функция НекорректнаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) - - Номер = 1; - Для Каждого ХранилищеТиповПоля Из ПараметрыОбновления.ОпорныеПоля.ТипыИспользуемых Цикл - ТипыПоля = ХранилищеТиповПоля.Получить(); - ИмяПоля = СтрШаблон("Поле%1", Номер); - - Если Не ТипыПоля.СодержитТип(ТипЗнч(ЭлементДанных[ИмяПоля])) - И ЭлементДанных[ИмяПоля] <> Неопределено Тогда - - Возврат Истина; - КонецЕсли; - - Номер = Номер + 1; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. -Функция НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) - - ТипыПолей = УправлениеДоступомСлужебныйПовтИсп.ТипыОпорныхПолейРегистра( - ПараметрыОбновления.ИмяОтдельногоРегистраКлючей); - - Для Номер = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл - ИмяПоля = СтрШаблон("Поле%1", Номер); - - Если Не ТипыПолей[ИмяПоля].СодержитТип(ТипЗнч(ЭлементДанных[ИмяПоля])) - И ЭлементДанных[ИмяПоля] <> Неопределено Тогда - - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для функции ДоступРазрешен. -Функция МодельОбъектовВПамяти(ОписаниеДанных, ПараметрыОграничения) - - Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда - Объекты = ОписаниеДанных; - Иначе - Объекты = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ОписаниеДанных); - КонецЕсли; - Объект = Объекты[0]; // СправочникОбъект - - ЭлементыДанных = Новый ТаблицаЗначений; - ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов( - ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипЗнч(Объект.Ссылка)))); - - Модель = Новый Структура; - Модель.Вставить("ЭлементыДанных", ЭлементыДанных); - Модель.Вставить("Таблицы", Новый Соответствие); - Модель.Вставить("КлючиДоступаКОбъектам", - РегистрыСведений.КлючиДоступаКОбъектам.СоздатьНаборЗаписей().Выгрузить()); - - ПоляТаблицОбъекта = ПараметрыОграничения.ПоляТаблицОбъекта; - - Для Каждого Объект Из Объекты Цикл - Объект = Объект; // СправочникОбъект - ТекущаяСсылка = ПользователиСлужебный.СсылкаОбъекта(ОписаниеДанных); - ЭлементыДанных.Добавить().ТекущаяСсылка = ТекущаяСсылка; - Для Каждого ОписаниеТаблицы Из ПоляТаблицОбъекта Цикл - ОписаниеТаблицы = ОписаниеТаблицы; // см. НовыеПоляТаблицыОбъекта - Таблица = Модель.Таблицы.Получить(ОписаниеТаблицы.ПолноеИмяТаблицы); // ТаблицаЗначений - СписокПолей = ОписаниеТаблицы.СписокПолей; - Если Таблица = Неопределено Тогда - Таблица = ОписаниеТаблицы.ТаблицаСПолями.Получить(); - Модель.Таблицы.Вставить(ОписаниеТаблицы.ПолноеИмяТаблицы, Таблица); - КонецЕсли; - Если ЗначениеЗаполнено(ОписаниеТаблицы.ТабличнаяЧасть) Тогда - Выгрузка = Объект[ОписаниеТаблицы.ТабличнаяЧасть].Выгрузить(, СписокПолей); // ТаблицаЗначений - Выгрузка.Свернуть(СписокПолей); - Для Каждого Строка Из Выгрузка Цикл - НоваяСтрока = Таблица.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка, СписокПолей); - НоваяСтрока.Ссылка = ТекущаяСсылка; - КонецЦикла; - Иначе - НоваяСтрока = Таблица.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, Объект, СписокПолей); - НоваяСтрока.Ссылка = ТекущаяСсылка; - КонецЕсли; - КонецЦикла; - КонецЦикла; - - Возврат Модель; - -КонецФункции - -// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами, ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи. -Процедура ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ПорцияЭлементовДанных, ПараметрыОбновления) - - ЭтоСсылочныйТип = ПараметрыОбновления.ЭтоСсылочныйТип; - ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; - - Контекст = Новый Структура; - Контекст.Вставить("ПорцияЭлементовДанных", ПорцияЭлементовДанных); - - ЗапросЗначенийЭлементовДанных = Новый Запрос; - Если ЭтоСсылочныйТип Тогда - Контекст.Вставить("СсылкиНаОбъекты", ПорцияЭлементовДанных.ВыгрузитьКолонку("ТекущаяСсылка")); - КонецЕсли; - Если ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда - Если ЭтоСсылочныйТип Тогда - ЗапросЗначенийЭлементовДанных.УстановитьПараметр("СсылкиНаОбъекты", Контекст.СсылкиНаОбъекты); - ИндексТаблицы = 0; - КонецЕсли; - Если ПараметрыОбновления.Свойство("МодельОбъектовВПамяти") Тогда - ЗапросЗначенийЭлементовДанных.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа; - Для Каждого Таблица Из ПараметрыОбновления.МодельОбъектовВПамяти.Таблицы Цикл - ЗапросЗначенийЭлементовДанных.УстановитьПараметр(Таблица.Ключ, Таблица.Значение); - КонецЦикла; - ИндексТаблицы = ПараметрыОбновления.МодельОбъектовВПамяти.Таблицы.Количество(); - Иначе - ЗапросЗначенийЭлементовДанных.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа; - Если Не ЭтоСсылочныйТип Тогда - ЗапросЗначенийЭлементовДанных.УстановитьПараметр("ИдентификаторРегистра", ИдентификаторСписка); - ЗапросЗначенийЭлементовДанных.УстановитьПараметр("ЗначенияОпорныхПолей", ПорцияЭлементовДанных); - ИндексТаблицы = 1; - КонецЕсли; - КонецЕсли; - УстановитьУточнениеПланаЗапроса(ЗапросЗначенийЭлементовДанных.Текст); - РезультатыЗапросаЗначенийЭлементов = ЗапросЗначенийЭлементовДанных.ВыполнитьПакет(); - Иначе - РезультатыЗапросаЗначенийЭлементов = Новый Массив; - КонецЕсли; - - ДанныеСтроковыхКлючейДоступа = Новый Соответствие; - ТаблицыКлюча = ПараметрыОбновления.ТаблицыКлюча; - - ЗначенияСтрокТаблиц = Новый Соответствие; - КлючиЗначенийСтрокОбъектов = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийЭлементов, - ИндексТаблицы, ТаблицыКлюча, ЗначенияСтрокТаблиц); - - ТребуемыеКлючиДоступа = Новый Массив; - ХешиТребуемыхКлючейДоступа = Новый Массив; - ОписаниеКлючейДоступаОбъектов = Новый Массив; - Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл - ОписаниеКлючейЗначений = КлючиЗначенийСтрокОбъектов.Получить(ЭлементДанных.ТекущаяСсылка); - СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); - Свойства = ДанныеСтроковыхКлючейДоступа.Получить(СтрокаДляХеша); - Если Свойства = Неопределено Тогда - Свойства = Новый Структура("ЗначенияТаблиц, СтрокаДляХеша, Хеш, КлючДоступа, ЗначенияКолонокТаблиц"); - ДанныеСтроковыхКлючейДоступа.Вставить(СтрокаДляХеша, Свойства); - ЗначенияТаблиц = Новый Массив; - Для Каждого ИмяТаблицы Из ТаблицыКлюча Цикл - КлючЗначений = ОписаниеКлючейЗначений.КлючиЗначений[ТаблицыКлюча.Найти(ИмяТаблицы)]; - ЗначенияСтрок = ЗначенияСтрокТаблиц.Получить(ИмяТаблицы).Получить(КлючЗначений); - Если ЗначенияСтрок = Неопределено Тогда - ЗначенияСтрок = Новый Массив; - КонецЕсли; - ЗначенияТаблиц.Добавить(Новый Структура("ИмяТаблицы, Таблица", ИмяТаблицы, ЗначенияСтрок)); - КонецЦикла; - Свойства.ЗначенияТаблиц = ЗначенияТаблиц; - Свойства.СтрокаДляХеша = СтрокаДляХеша; - Свойства.ЗначенияКолонокТаблиц = ОписаниеКлючейЗначений.ЗначенияКолонокТаблиц; - Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); - Хеширование.Добавить(СтрокаДляХеша); - Свойства.Хеш = Хеширование.ХешСумма; - ТребуемыеКлючиДоступа.Добавить(Свойства); - ХешиТребуемыхКлючейДоступа.Добавить(Свойства.Хеш); - КонецЕсли; - ОписаниеКлючейДоступаОбъектов.Добавить( - Новый Структура("ТекущаяСсылка, СвойстваКлюча", ЭлементДанных.ТекущаяСсылка, Свойства)); - КонецЦикла; - Контекст.Вставить("ОписаниеКлючейДоступаОбъектов", ОписаниеКлючейДоступаОбъектов); - - // Получение данных существующих ключей доступа по хешам требуемых ключей доступа. - ЗапросЗначенийКлючей = Новый Запрос; - ЗапросЗначенийКлючей.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения; - ЗапросЗначенийКлючей.УстановитьПараметр("Хеши", ХешиТребуемыхКлючейДоступа); - ЗапросЗначенийКлючей.УстановитьПараметр("Список", ИдентификаторСписка); - УстановитьУточнениеПланаЗапроса(ЗапросЗначенийКлючей.Текст); - РезультатыЗапросаЗначенийКлючей = ЗапросЗначенийКлючей.ВыполнитьПакет(); - - КлючиЗначенийСтрокКлючей = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийКлючей, - ?(Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) - Или СтрНачинаетсяС(ТаблицыКлюча[0], "Шапка"), 0, 1), - ТаблицыКлюча); - Выборка = РезультатыЗапросаЗначенийКлючей[0].Выбрать(); - - Пока Выборка.Следующий() Цикл - ОписаниеКлючейЗначений = КлючиЗначенийСтрокКлючей.Получить(Выборка.ТекущаяСсылка); - СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); - Свойства = ДанныеСтроковыхКлючейДоступа.Получить(СтрокаДляХеша); - Если Свойства <> Неопределено И Свойства.КлючДоступа = Неопределено Тогда - Свойства.КлючДоступа = Выборка.ТекущаяСсылка; - КонецЕсли; - КонецЦикла; - - // Создание недостающих ключей доступа. - ОписаниеНовыхКлючей = Новый Массив; - Для Каждого ОписаниеКлюча Из ТребуемыеКлючиДоступа Цикл - Если ОписаниеКлюча.КлючДоступа <> Неопределено Тогда - Продолжить; - КонецЕсли; - ОписаниеНовыхКлючей.Добавить(ОписаниеКлюча); - КонецЦикла; - Если ОписаниеНовыхКлючей.Количество() > 0 Тогда - ОбновитьПраваНаКлючиДоступа(ОписаниеНовыхКлючей, ПараметрыОбновления, Истина, Контекст); - Для Каждого ОписаниеКлюча Из ОписаниеНовыхКлючей Цикл - КлючДоступаОбъект = ОписаниеКлюча.КлючДоступаОбъект; // СправочникОбъект.КлючиДоступа - Если ЗначениеЗаполнено(КлючДоступаОбъект.Ссылка) Тогда - ОписаниеКлюча.КлючДоступа = КлючДоступаОбъект.Ссылка; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - // Обновление ключей доступа элементов данных. - Если ЭтоСсылочныйТип Тогда - Если ПараметрыОбновления.Свойство("МодельОбъектовВПамяти") Тогда - ИмяПоляКлюча = ?(ПараметрыОбновления.ДляВнешнихПользователей, - "КлючДоступаВнешнихПользователей", "КлючДоступаПользователей"); - КлючиДоступаКОбъектам = ПараметрыОбновления.МодельОбъектовВПамяти.КлючиДоступаКОбъектам; // РегистрСведенийНаборЗаписей - Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл - НоваяСтрока = КлючиДоступаКОбъектам.Добавить(); - НоваяСтрока.Объект = ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка; - НоваяСтрока[ИмяПоляКлюча] = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; - КонецЦикла; - Иначе - ЗаписатьКлючиДоступаОбъектов(ПараметрыОбновления, Контекст); - КонецЕсли; - Иначе - ЗаписатьКлючиДоступаРегистров(ПараметрыОбновления, Контекст); - КонецЕсли; - - // Принудительное обновление прав вручную. - Если ПараметрыОбновления.Свойство("ОбновитьПраваНаКлючи") - И ПараметрыОбновления.ОбновитьПраваНаКлючи Тогда - - СуществующиеКлючиДоступа = Новый Массив; - Для Каждого ОписаниеКлюча Из ТребуемыеКлючиДоступа Цикл - Если ОписаниеНовыхКлючей.Найти(ОписаниеКлюча) <> Неопределено Тогда - Продолжить; - КонецЕсли; - СуществующиеКлючиДоступа.Добавить(ОписаниеКлюча.КлючДоступа); - КонецЦикла; - Если СуществующиеКлючиДоступа.Количество() > 0 Тогда - ОбновитьПраваНаКлючиДоступа(СуществующиеКлючиДоступа, ПараметрыОбновления); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка. -Процедура ОбновитьПраваНаКлючиДоступа(ОписаниеКлючей, ПараметрыОбновления, ЭтоНовыеКлючи = Ложь, Контекст = Неопределено) - - Если ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") Тогда - КоличествоОбработанных = ПараметрыОбновления.КоличествоОбработанныхЭлементов; - ПараметрыОбновления.КоличествоОбработанныхЭлементов = 0; - КонецЕсли; - - Если ЭтоНовыеКлючи Тогда - КлючиДоступа = Новый ТаблицаЗначений; - КлючиДоступа.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); - - ЗапросЗначенийКлючей = Новый Запрос; - ЗапросЗначенийКлючей.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения; - ЗапросЗначенийКлючей.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); - УстановитьУточнениеПланаЗапроса(ЗапросЗначенийКлючей.Текст); - - ЗапросСуществованияКлючей = Новый Запрос; - ЗапросСуществованияКлючей.Текст = ПараметрыОбновления.ТекстЗапросаСуществованияКлючейДляСравнения; - ЗапросСуществованияКлючей.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); - УстановитьУточнениеПланаЗапроса(ЗапросСуществованияКлючей.Текст); - - ОписаниеНовыхКлючей = Новый Структура; - ОписаниеНовыхКлючей.Вставить("ОписаниеКлючей", ОписаниеКлючей); - ОписаниеНовыхКлючей.Вставить("КлючиДоступа", КлючиДоступа); - ОписаниеНовыхКлючей.Вставить("ЗначенияТаблиц", Новый Структура); - ОписаниеНовыхКлючей.Вставить("ОписанияКлючейПоСсылке", Новый Соответствие); - ОписаниеНовыхКлючей.Вставить("ЗапросЗначенийКлючей", ЗапросЗначенийКлючей); - ОписаниеНовыхКлючей.Вставить("ЗапросСуществованияКлючей", ЗапросСуществованияКлючей); - - ДопустимыеТипыЗначений = УправлениеДоступомСлужебныйПовтИсп.ДопустимыеТипыЗначенийКлючейДоступа(); - ЗначенияТаблиц = ОписаниеНовыхКлючей.ЗначенияТаблиц; - - Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл - ТаблицаЗначений = ЗначенияТаблицыКлюча(); - ТаблицаЗначений.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); - ПоляТаблицы = ПараметрыОбновления.РеквизитыТаблицКлюча.Получить(ТаблицаКлюча); - Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") И ТаблицаКлюча <> "Шапка0" Тогда - ТаблицаЗначений.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число")); - КонецЕсли; - Для Каждого Поле Из ПоляТаблицы Цикл - ТаблицаЗначений.Колонки.Добавить(Поле, ДопустимыеТипыЗначений); - КонецЦикла; - ЗначенияТаблиц.Вставить(ТаблицаКлюча, ТаблицаЗначений); - КонецЦикла; - - Для Каждого ОписаниеКлюча Из ОписаниеКлючей Цикл - ПроверитьТипЗначенийКлючаДоступа(ОписаниеКлюча, ДопустимыеТипыЗначений, ПараметрыОбновления); - ПодготовитьНовыйКлючДоступа(ОписаниеКлюча, ОписаниеНовыхКлючей, ПараметрыОбновления); - КонецЦикла; - ОписаниеКлючейДоступа = ОписаниеНовыхКлючей; - Иначе - ОписаниеКлючейДоступа = Новый ТаблицаЗначений; - ОписаниеКлючейДоступа.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); - Для Каждого КлючДоступаСсылка Из ОписаниеКлючей Цикл - ОписаниеКлючейДоступа.Добавить().Ссылка = КлючДоступаСсылка; - КонецЦикла; - КонецЕсли; - - ОбновитьПраваПорцииКлючейДоступаСписка(ОписаниеКлючейДоступа, ПараметрыОбновления, ЭтоНовыеКлючи); - - Если ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") Тогда - ПараметрыОбновления.КоличествоОбработанныхЭлементов = КоличествоОбработанных; - КонецЕсли; - -КонецПроцедуры - -// Возвращаемое значение: -// ТаблицаЗначений: -// * Ссылка - СправочникСсылка.КлючиДоступа -// * НомерСтроки - Число - номер строки табличной части -// -Функция ЗначенияТаблицыКлюча() - - Возврат Новый ТаблицаЗначений; - -КонецФункции - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка. -Функция СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча) - - Если ОписаниеКлючейЗначений = Неопределено Тогда - ОписаниеКлючейЗначений = Новый Структура( - "КлючиЗначений, ИменаТаблиц, ЗначенияКолонокТаблиц", - Новый Массив, Новый Массив, Новый Массив); - КонецЕсли; - - КлючиЗначений = ОписаниеКлючейЗначений.КлючиЗначений; - ИменаТаблиц = ОписаниеКлючейЗначений.ИменаТаблиц; - - Если ИменаТаблиц.Количество() <> ТаблицыКлюча.Количество() Тогда - // В ключе доступа используются табличные части и некоторые пустые. - Для Индекс = 0 По ТаблицыКлюча.Количество() - 1 Цикл - - Если Индекс >= ИменаТаблиц.Количество() - Или ИменаТаблиц[Индекс] <> ТаблицыКлюча[Индекс] Тогда - - ИменаТаблиц.Вставить(Индекс, ТаблицыКлюча[Индекс]); - КлючиЗначений.Вставить(Индекс, "6ab8db6a-4878-483a-b9d5-ef905ff1537e"); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Возврат СтрСоединить(КлючиЗначений); - -КонецФункции - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. -Процедура ЗаписатьКлючиДоступаОбъектов(ПараметрыОбновления, Контекст) - - ЗаписыватьТолькоИзмененные = ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных(); - - Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей - Или ЗаписыватьТолькоИзмененные Тогда - - ЗапросТекущихКлючей = Новый Запрос; - ЗапросТекущихКлючей.Текст = - "ВЫБРАТЬ - | КлючиДоступаКОбъектам.Объект КАК Объект, - | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, - | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - |ГДЕ - | КлючиДоступаКОбъектам.Объект В (&СсылкиНаОбъекты)"; - ЗапросТекущихКлючей.УстановитьПараметр("СсылкиНаОбъекты", Контекст.СсылкиНаОбъекты); - КонецЕсли; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - ИмяРеквизитаСохраняемогоКлюча = "КлючДоступаПользователей"; - ИмяРеквизитаОбновляемогоКлюча = "КлючДоступаВнешнихПользователей"; - Иначе - ИмяРеквизитаСохраняемогоКлюча = "КлючДоступаВнешнихПользователей"; - ИмяРеквизитаОбновляемогоКлюча = "КлючДоступаПользователей"; - КонецЕсли; - - ОбъектТип = Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект.Тип; - Если Не ОбъектТип.СодержитТип(ТипЗнч(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка)) Тогда - ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Невозможно обновить ключ доступа объекта ""%1"" типа ""%2"", - |так как тип ""%3"" не указан в определяемом типе ""%4"".'"), - Строка(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка), - Строка(ТипЗнч(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка)), - ИмяТипаСсылки(ПараметрыОбновления.Список, ТипыТаблицПоИменам), - "ВладелецЗначенийКлючейДоступа"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если ЗаписыватьТолькоИзмененные Тогда - ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); - ТекущиеКлючиДоБлокировки = ЗапросТекущихКлючей.Выполнить().Выгрузить(); - ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); - КонецЕсли; - - КоличествоОбработанных = 0; - ОписаниеКлючейДоступаОбъектов = Новый Массив; - - Блокировка = Новый БлокировкаДанных; - Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл - КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; - Если КлючДоступа = Неопределено Тогда - Прервать; - КонецЕсли; - Если ЗаписыватьТолькоИзмененные Тогда - Строка = ТекущиеКлючиДоБлокировки.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "Объект"); - Если Строка <> Неопределено И Строка[ИмяРеквизитаОбновляемогоКлюча] = КлючДоступа Тогда - КоличествоОбработанных = КоличествоОбработанных + 1; - Продолжить; - КонецЕсли; - КонецЕсли; - ОписаниеКлючейДоступаОбъектов.Добавить(ОписаниеКлючаДоступаОбъекта); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); - ЭлементБлокировки.УстановитьЗначение("Объект", ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); - КонецЦикла; - - Если ОписаниеКлючейДоступаОбъектов.Количество() = 0 Тогда - ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных); - Возврат; - КонецЕсли; - - СпискиДляОбновления = Новый Структура("ИменаСписков, ДляВнешнихПользователей", - ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа, - ПараметрыОбновления.ДляВнешнихПользователей); - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, - ПараметрыОбновления.ИдентификаторТранзакции, "ЗаполнитьКэшПараметровОграниченияДоступа"); - КонецЕсли; - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - ПакетныйРежим = РежимСлияния <> Неопределено; - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); - Если Не ПакетныйРежим Тогда - Запись = НаборЗаписей.Добавить(); - КонецЕсли; - - НачатьТранзакцию(); - Попытка - ПередБлокировкойДанных(ПараметрыОбновления); - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); - КонецЕсли; - Блокировка.Заблокировать(); - ПослеБлокировкиДанных(ПараметрыОбновления); - - Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей Тогда - ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); - ТекущиеКлючи = ЗапросТекущихКлючей.Выполнить().Выгрузить(); - ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); - КонецЕсли; - - ПередЗаписьюСтрок(ПараметрыОбновления); - СсылкиНаОбъекты = Новый Массив; - Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл - СсылкиНаОбъекты.Добавить(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); - Если Не ПакетныйРежим Тогда - НаборЗаписей.Отбор.Объект.Установить(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); - Иначе - Запись = НаборЗаписей.Добавить(); - КонецЕсли; - Запись.Объект = ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка; - Запись[ИмяРеквизитаОбновляемогоКлюча] = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; - - Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей Тогда - Строка = ТекущиеКлючи.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "Объект"); - Если Строка <> Неопределено Тогда - Запись[ИмяРеквизитаСохраняемогоКлюча] = Строка[ИмяРеквизитаСохраняемогоКлюча]; - КонецЕсли; - КонецЕсли; - Если Не ПакетныйРежим Тогда - НаборЗаписей.Записать(); - КонецЕсли; - КонецЦикла; - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимСлияния); - КонецЕсли; - ПослеЗаписиСтрок(ПараметрыОбновления, ОписаниеКлючейДоступаОбъектов.Количество()); - - ПередПланированиемОбновления(ПараметрыОбновления); - ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, - ПараметрыОбновления.ИдентификаторТранзакции, - "ЗаписатьКлючиДоступаОбъектов", - ?(СсылкиНаОбъекты.Количество() > 25, Неопределено, - Новый Структура("ПоКлючамДоступа", СсылкиНаОбъекты)), - ПараметрыОбновления.Свойство("ЭтоФоновоеОбновлениеДоступа")); - ПослеПланированияОбновления(ПараметрыОбновления); - - // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, - // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), - // а в режиме анализа производительности последствия учитываются и не являются критичными. - ПередФиксациейТранзакции(ПараметрыОбновления); - ЗафиксироватьТранзакцию(); - ПослеФиксацииТранзакции(ПараметрыОбновления); - // АПК:330-вкл. - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - КоличествоОбработанных = КоличествоОбработанных + ОписаниеКлючейДоступаОбъектов.Количество(); - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда - Возврат; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. -Процедура ЗаписатьКлючиДоступаРегистров(ПараметрыОбновления, Контекст) - - ПорцияЭлементовДанных = Контекст.ПорцияЭлементовДанных; - - ЗаписыватьТолькоИзмененные = ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных(); - Если ЗаписыватьТолькоИзмененные Тогда - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); - ТекстЗапроса = ПараметрыОбновления.ТекстЗапросаТекущихКлючейДоступаРегистра; - ТекстыПакета = Новый Массив; - НомерСтроки = 1; - Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл - ТекущийНомер = "_" + Формат(НомерСтроки, "ЧГ="); - ТекстыПакета.Добавить(СтрЗаменить(ТекстЗапроса, "_%1", ТекущийНомер)); - Для НомерПоля = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); - Запрос.УстановитьПараметр(ИмяПоля + ТекущийНомер, ЭлементДанных[ИмяПоля]); - КонецЦикла; - НомерСтроки = НомерСтроки + 1; - КонецЦикла; - Запрос.Текст = СтрСоединить(ТекстыПакета, ОбщегоНазначения.РазделительПакетаЗапросов()); - ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); - Если ТекстыПакета.Количество() > 1 Тогда - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - Иначе - РезультатыЗапроса = Новый Массив; - РезультатыЗапроса.Добавить(Запрос.Выполнить()); - КонецЕсли; - ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); - КонецЕсли; - - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; - Иначе - ИмяРегистраКлючей = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; - КонецЕсли; - - КоличествоОбработанных = 0; - ОписаниеКлючейДоступаОбъектов = Новый Массив; - - ИндексРезультата = -1; - Блокировка = Новый БлокировкаДанных; - Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл - ИндексРезультата = ИндексРезультата + 1; - КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; - Если КлючДоступа = Неопределено Тогда - Прервать; - КонецЕсли; - Если ЗаписыватьТолькоИзмененные Тогда - РезультатЗапроса = РезультатыЗапроса[ИндексРезультата]; - Если Не РезультатЗапроса.Пустой() Тогда - Выгрузка = РезультатЗапроса.Выгрузить(); - Если Выгрузка.Количество() = 1 И Выгрузка[0].КлючДоступа = КлючДоступа Тогда - КоличествоОбработанных = КоличествоОбработанных + 1; - Продолжить; - КонецЕсли; - КонецЕсли; - КонецЕсли; - ОписаниеКлючейДоступаОбъектов.Добавить(ОписаниеКлючаДоступаОбъекта); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраКлючей); - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - ЭлементБлокировки.УстановитьЗначение("Регистр", ПараметрыОбновления.ИдентификаторСписка); - КонецЕсли; - ЭлементБлокировки.УстановитьЗначение("ВариантДоступа", ПараметрыОбновления.ВариантДоступа); - ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); - Для НомерПоля = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - ЭлементБлокировки.УстановитьЗначение(ИмяПоля, ЭлементДанных[ИмяПоля]); - КонецЦикла; - КонецЦикла; - - Если ОписаниеКлючейДоступаОбъектов.Количество() = 0 Тогда - ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных); - Возврат; - КонецЕсли; - - ПустыеЗначенияОпорныхПолей = УправлениеДоступомСлужебныйПовтИсп.ПустыеЗначенияОпорныхПолей( - ПараметрыОбновления.ОпорныеПоля.МаксимальноеКоличество); - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - ПакетныйРежим = РежимСлияния <> Неопределено; - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраКлючей]); - Если Не ПакетныйРежим Тогда - Запись = НаборЗаписей.Добавить(); - КонецЕсли; - - Если Не ПакетныйРежим Тогда - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - НаборЗаписей.Отбор.Регистр.Установить(ПараметрыОбновления.ИдентификаторСписка); - КонецЕсли; - НаборЗаписей.Отбор.ВариантДоступа.Установить(ПараметрыОбновления.ВариантДоступа); - КонецЕсли; - КоличествоИспользуемыхПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); - - НачатьТранзакцию(); - Попытка - ПередБлокировкойДанных(ПараметрыОбновления); - Блокировка.Заблокировать(); - ПослеБлокировкиДанных(ПараметрыОбновления); - - ПередЗаписьюСтрок(ПараметрыОбновления); - Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл - Если ПакетныйРежим Тогда - Запись = НаборЗаписей.Добавить(); - КонецЕсли; - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - Запись.Регистр = ПараметрыОбновления.ИдентификаторСписка; - КонецЕсли; - Запись.ВариантДоступа = ПараметрыОбновления.ВариантДоступа; - - ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); - ЗаполнитьЗначенияСвойств(Запись, ПустыеЗначенияОпорныхПолей); - Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - Если Не ПакетныйРежим Тогда - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоля]; // ЭлементОтбора - Если ЭлементДанных[ИмяПоля] = Неопределено Тогда - ЭлементОтбора.Значение = Неопределено; - ЭлементОтбора.Использование = Истина; - Иначе - ЭлементОтбора.Установить(ЭлементДанных[ИмяПоля]); - КонецЕсли; - КонецЕсли; - Запись[ИмяПоля] = ЭлементДанных[ИмяПоля]; - КонецЦикла; - - Запись.КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; - Если Не ПакетныйРежим Тогда - НаборЗаписей.Записать(); - КонецЕсли; - КонецЦикла; - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимСлияния); - КонецЕсли; - ПослеЗаписиСтрок(ПараметрыОбновления, ОписаниеКлючейДоступаОбъектов.Количество()); - - // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, - // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), - // а в режиме анализа производительности последствия учитываются и не являются критичными. - ПередФиксациейТранзакции(ПараметрыОбновления); - ЗафиксироватьТранзакцию(); - ПослеФиксацииТранзакции(ПараметрыОбновления); - // АПК:330-вкл. - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - КоличествоОбработанных = КоличествоОбработанных + ОписаниеКлючейДоступаОбъектов.Количество(); - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда - Возврат; - КонецЕсли; - -КонецПроцедуры - -// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. -Процедура УдалитьНекорректныеКомбинацииЗначенийОпорныхПолей(ПорцияЭлементовДанных, ПараметрыОбновления) - - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; - Иначе - ИмяРегистраКлючей = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; - КонецЕсли; - НаборИзОднойЗаписи = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраКлючей]); - КоличествоИспользуемыхПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); - - Блокировка = Новый БлокировкаДанных; - Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраКлючей); - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - ЭлементБлокировки.УстановитьЗначение("Регистр", ПараметрыОбновления.ИдентификаторСписка); - КонецЕсли; - ЭлементБлокировки.УстановитьЗначение("ВариантДоступа", ПараметрыОбновления.ВариантДоступа); - Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - ЭлементБлокировки.УстановитьЗначение(ИмяПоля, ЭлементДанных[ИмяПоля]); - КонецЦикла; - КонецЦикла; - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл - Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда - НаборИзОднойЗаписи.Отбор.Регистр.Установить(ПараметрыОбновления.ИдентификаторСписка); - КонецЕсли; - НаборИзОднойЗаписи.Отбор.ВариантДоступа.Установить(ПараметрыОбновления.ВариантДоступа); - Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - ЭлементОтбора = НаборИзОднойЗаписи.Отбор[ИмяПоля]; // ЭлементОтбора - Если ЭлементДанных[ИмяПоля] = Неопределено Тогда - ЭлементОтбора.Значение = Неопределено; - ЭлементОтбора.Использование = Истина; - Иначе - ЭлементОтбора.Установить(ЭлементДанных[ИмяПоля]); - КонецЕсли; - КонецЦикла; - НаборИзОднойЗаписи.Записать(); - КонецЦикла; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. -Функция КлючиЗначенийСтрокОбъектов(РезультатыЗапроса, Индекс, ТаблицыКлюча, ЗначенияСтрокТаблиц = Неопределено) - - КлючиЗначенийСтрокОбъектов = Новый Соответствие; - - Если ЗначенияСтрокТаблиц = Неопределено Тогда - ЗначенияСтрокТаблиц = Новый Соответствие; - КонецЕсли; - - Для Каждого ИмяТаблицыКлючаДоступа Из ТаблицыКлюча Цикл - ЗначенияСтрокТаблицы = ЗначенияСтрокТаблиц.Получить(ИмяТаблицыКлючаДоступа); - Если ЗначенияСтрокТаблицы = Неопределено Тогда - ЗначенияСтрокТаблицы = Новый Соответствие; - ЗначенияСтрокТаблиц.Вставить(ИмяТаблицыКлючаДоступа, ЗначенияСтрокТаблицы); - КонецЕсли; - Дерево = РезультатыЗапроса[Индекс].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Индекс = Индекс + 1; - Для Каждого Строка Из Дерево.Строки Цикл - ЗначенияКолонокТаблицы = Новый Массив; - Для Каждого Колонка Из Дерево.Колонки Цикл - Если СтрНачинаетсяС(Колонка.Имя, "Значение") Тогда - ЗначенияКолонокТаблицы.Добавить(Строка.Строки.ВыгрузитьКолонку(Колонка.Имя)); - КонецЕсли; - КонецЦикла; - КлючЗначенийСтрок = СтрокаДанныхДляХеширования(ЗначенияКолонокТаблицы); - Если ЗначенияСтрокТаблицы.Получить(КлючЗначенийСтрок) = Неопределено Тогда - ЗначенияСтрокТаблицы.Вставить(КлючЗначенийСтрок, Строка.Строки); - КонецЕсли; - ОписаниеКлючейЗначений = КлючиЗначенийСтрокОбъектов.Получить(Строка.ТекущаяСсылка); - Если ОписаниеКлючейЗначений = Неопределено Тогда - ОписаниеКлючейЗначений = Новый Структура( - "КлючиЗначений, ИменаТаблиц, ЗначенияКолонокТаблиц", - Новый Массив, Новый Массив, Новый Массив); - КлючиЗначенийСтрокОбъектов.Вставить(Строка.ТекущаяСсылка, ОписаниеКлючейЗначений); - КонецЕсли; - ОписаниеКлючейЗначений.ИменаТаблиц.Добавить(ИмяТаблицыКлючаДоступа); - ОписаниеКлючейЗначений.КлючиЗначений.Добавить(КлючЗначенийСтрок); - ОписаниеКлючейЗначений.ЗначенияКолонокТаблиц.Добавить(ЗначенияКолонокТаблицы); - КонецЦикла; - КонецЦикла; - - Возврат КлючиЗначенийСтрокОбъектов; - -КонецФункции - -// Для функции КлючиЗначенийСтрокОбъектов и др. -Функция СтрокаДанныхДляХеширования(Данные) - - // Возвращает строку данных для последующего хеширования, например, - // строковое описание ссылок, сохраняемых в базе данных, с учетом типов - // по внутренним идентификаторам, что обеспечивает неизменность хеш-суммы - // при изменении имен таблиц и имен реквизитов, то есть обеспечивает - // соответствие хеш-суммы данных самим данным, сохраняемым в базе данных. - // - // Это позволяет избежать избыточного массового пересоздания ключей доступа с последующим - // перерасчетом пользователей и групп доступа для пересозданных ключей доступа. - - Возврат ЗначениеВСтрокуВнутр(Данные); - -КонецФункции - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. -Процедура ПроверитьТипЗначенийКлючаДоступа(ОписаниеКлюча, ДопустимыеТипыЗначений, ПараметрыОбновления) - - ЗначенияКолонокТаблиц = ОписаниеКлюча.ЗначенияКолонокТаблиц; - - Для Каждого ЗначенияКолонокТаблицы Из ЗначенияКолонокТаблиц Цикл - Для Каждого ЗначенияКолонкиТаблицы Из ЗначенияКолонокТаблицы Цикл - Для Каждого Значение Из ЗначенияКолонкиТаблицы Цикл - Если Не ДопустимыеТипыЗначений.СодержитТип(ТипЗнч(Значение)) Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Невозможно сохранить значение ""%1"" типа ""%2"" - |при обновлении ключей доступа списка ""%3"", - |так как этот тип не указан в определяемом типе %4.'"), - Строка(Значение), - Строка(ТипЗнч(Значение)), - ПараметрыОбновления.Список, - "ЗначениеДоступа"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - КонецЦикла; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. -Процедура ПодготовитьНовыйКлючДоступа(ОписаниеКлюча, ОписаниеНовыхКлючей, ПараметрыОбновления) - - НоваяСсылка = Справочники.КлючиДоступа.ПолучитьСсылку(); - НовыйКлюч = СлужебныйЭлемент(Справочники.КлючиДоступа); // СправочникОбъект.КлючиДоступа - - НовыйКлюч.УстановитьСсылкуНового(НоваяСсылка); - НовыйКлюч.Наименование = Строка(НоваяСсылка.УникальныйИдентификатор()); - НовыйКлюч.Список = ПараметрыОбновления.ИдентификаторСписка; - НовыйКлюч.СоставПолей = ПараметрыОбновления.СоставПолей; - НовыйКлюч.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; - НовыйКлюч.Хеш = ОписаниеКлюча.Хеш; - - ВсеЗначенияТаблиц = ОписаниеНовыхКлючей.ЗначенияТаблиц; - - Для Каждого ЗначенияТаблицы Из ОписаниеКлюча.ЗначенияТаблиц Цикл - ВсеЗначенияТаблицы = ВсеЗначенияТаблиц[ЗначенияТаблицы.ИмяТаблицы]; // См. ЗначенияТаблицыКлюча - - Если СтрНачинаетсяС(ЗначенияТаблицы.ИмяТаблицы, "Шапка") Тогда - НоваяСтрока = ВсеЗначенияТаблицы.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, ЗначенияТаблицы.Таблица[0]); - НоваяСтрока.Ссылка = НоваяСсылка; - - Если СтрЗаканчиваетсяНа(ЗначенияТаблицы.ИмяТаблицы, "0") Тогда - ЗаполнитьЗначенияСвойств(НовыйКлюч, ЗначенияТаблицы.Таблица[0],, "Родитель"); - Иначе - НомерСтроки = Число(Прав(ЗначенияТаблицы.ИмяТаблицы, 1)); - НовыйКлюч.Шапка.Добавить(); - ЗаполнитьЗначенияСвойств(НовыйКлюч.Шапка[НомерСтроки - 1], ЗначенияТаблицы.Таблица[0]); - НоваяСтрока.НомерСтроки = НомерСтроки; - КонецЕсли; - Иначе - Для Каждого Строка Из ЗначенияТаблицы.Таблица Цикл - ТабличнаяЧастьКлюча = НовыйКлюч[ЗначенияТаблицы.ИмяТаблицы]; // ТабличнаяЧасть - ЗаполнитьЗначенияСвойств(ТабличнаяЧастьКлюча.Добавить(), Строка); - НоваяСтрока = ВсеЗначенияТаблицы.Добавить(); - ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); - НоваяСтрока.Ссылка = НоваяСсылка; - КонецЦикла; - КонецЕсли; - КонецЦикла; - - ОписаниеКлюча.Вставить("КлючДоступаОбъект", НовыйКлюч); - ОписаниеНовыхКлючей.КлючиДоступа.Добавить().Ссылка = НоваяСсылка; - ОписаниеНовыхКлючей.ОписанияКлючейПоСсылке.Вставить(НоваяСсылка, ОписаниеКлюча); - -КонецПроцедуры - -// Для процедур ОбновитьПорциюЭлементов, ОбновитьПраваНаКлючиДоступа. -Процедура ОбновитьПраваПорцииКлючейДоступаСписка(ОписаниеКлючейДоступа, ПараметрыОбновления, ЭтоНовыеКлючи = Ложь) - - Если Не ПараметрыОбновления.Свойство("Кэш") Тогда - ПараметрыОбновления.Вставить("Кэш", Новый Структура); - КонецЕсли; - КлючиДоступа = ?(ЭтоНовыеКлючи, ОписаниеКлючейДоступа.КлючиДоступа, ОписаниеКлючейДоступа); - - Если ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда - Запрос = Новый Запрос; - Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав; - НомерТаблицы = 0; - - Если ЭтоНовыеКлючи Тогда - ТекстыЗапроса = Новый Массив; - РеквизитыТаблицКлюча = ПараметрыОбновления.РеквизитыТаблицКлюча; - Шаблон = - "ВЫБРАТЬ - | &Поля - |ПОМЕСТИТЬ Таблица - |ИЗ - | &Таблица КАК Таблица"; - Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл - ПолеНомерСтроки = ""; - Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") Тогда - Если СтрЗаканчиваетсяНа(ТаблицаКлюча, "0") Тогда - ИмяВременнойТаблицы = "СправочникКлючиДоступа"; - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "@Справочник.КлючиДоступа ", ИмяВременнойТаблицы + " "); - Иначе - ИмяВременнойТаблицы = "СправочникКлючиДоступа" + ТаблицаКлюча; - ПолеНомерСтроки = "НомерСтроки, "; // @query-part-1 - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "@Справочник.КлючиДоступа.Шапка КАК " + ТаблицаКлюча, - ИмяВременнойТаблицы + " КАК " + ТаблицаКлюча); // @query-part-1, @query-part-2 - КонецЕсли; - Иначе - ИмяВременнойТаблицы = "СправочникКлючиДоступа" + ТаблицаКлюча; - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "@Справочник.КлючиДоступа." + ТаблицаКлюча, ИмяВременнойТаблицы); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(Шаблон, "Таблица", ИмяВременнойТаблицы); - РеквизитыТаблицы = РеквизитыТаблицКлюча.Получить(ТаблицаКлюча); - Поля = "Ссылка, " + ПолеНомерСтроки + СтрСоединить(РеквизитыТаблицы, ", "); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Поля", Поля); - ТекстыЗапроса.Добавить(ТекстЗапроса); - Запрос.УстановитьПараметр(ИмяВременнойТаблицы, ОписаниеКлючейДоступа.ЗначенияТаблиц[ТаблицаКлюча]); - НомерТаблицы = НомерТаблицы + 1; - КонецЦикла; - ТекстыЗапроса.Добавить(Запрос.Текст); - Запрос.Текст = СтрСоединить(ТекстыЗапроса, ОбщегоНазначения.РазделительПакетаЗапросов()); - Иначе - Запрос.Текст = СтрЗаменить(Запрос.Текст, "@Справочник.КлючиДоступа", "Справочник.КлючиДоступа"); - КонецЕсли; - Запрос.УстановитьПараметр("КлючиДоступа", КлючиДоступа); - - Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", - ПараметрыОбновления.ИдентификаторТаблицыНастроекПрав); - - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - УстановитьУточнениеПланаЗапроса(Запрос.Текст); - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - Иначе - РезультатыЗапроса = Новый Массив; - КонецЕсли; - - ПараметрыОбновления.Вставить("ТипПользователя", ?(ПараметрыОбновления.ДляВнешнихПользователей, - Тип("СправочникСсылка.ВнешниеПользователи"), Тип("СправочникСсылка.Пользователи"))); - - ПараметрыОбновления.Вставить("ТипГруппыПользователей", ?(ПараметрыОбновления.ДляВнешнихПользователей, - Тип("СправочникСсылка.ГруппыВнешнихПользователей"), Тип("СправочникСсылка.ГруппыПользователей"))); - - ПараметрыОбновления.Вставить("ТипГруппыДоступа", Тип("СправочникСсылка.ГруппыДоступа")); - ПараметрыОбновления.Вставить("ПустаяГруппаДоступа", Справочники.ГруппыДоступа.ПустаяСсылка()); - - ЗначенияТаблицКлючей = НовыеЗначенияТаблицКлючей(); - Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл - НомерТаблицы = НомерТаблицы + 1; - ЗначенияТаблицКлючей.Вставить(ТаблицаКлюча, - РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам)); - КонецЦикла; - ЗаполнитьПраваНаВедущиеКлючиДоступаИВедущиеСписки(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления); - ЗаполнитьПраваПоВладельцамНастроекПрав(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления); - - КэшРасчетаПрав = КэшРасчетаПравДляВидаПользователей(ПараметрыОбновления.ДляВнешнихПользователей); - Если Не ПараметрыОбновления.Кэш.Свойство("ПраваРолейФункцииПравоДоступа") - Или КэшРасчетаПрав.РолиПрофилейГруппДоступа = Неопределено Тогда - ПараметрыОбновления.Кэш.Вставить("ПраваРолейФункцииПравоДоступа", Новый Соответствие); - ПараметрыОбновления.Кэш.Вставить("ОбъектыМетаданныхФункцииПравоДоступа", Новый Соответствие); - ПараметрыОбновления.Кэш.Вставить("ПраваПрофилейФункцииПравоДоступа", Новый Соответствие); - КонецЕсли; - - ЗаполнитьПраваГруппДоступаСписка(ПараметрыОбновления, КэшРасчетаПрав); - ЗаполнитьЗначенияГруппДоступаДляРасчетаПрав(ПараметрыОбновления, КэшРасчетаПрав); - ЗаполнитьПользователейГруппПользователей(ПараметрыОбновления, КэшРасчетаПрав); - ЗаполнитьУчастниковГруппДоступаСписка(ПараметрыОбновления, КэшРасчетаПрав); - ЗаполнитьГруппыПользователейКакЗначенияДоступа(ПараметрыОбновления, КэшРасчетаПрав); - ЗаполнитьРолиИГруппыДоступаПрофилей(ПараметрыОбновления, КэшРасчетаПрав); - - ЗначенияПервойТаблицы = ?(ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей), - ЗначенияТаблицКлючей.Получить(ПараметрыОбновления.ТаблицыКлюча[0]), - Новый Структура("Строки", КлючиДоступа)); - ИндексПоследнегоКлюча = ЗначенияПервойТаблицы.Строки.Количество() - 1; - - Для ИндексКлюча = 0 По ИндексПоследнегоКлюча Цикл - ЗначенияТаблицКлюча = НовыеЗначенияТаблицКлюча(); - Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл - ЗначенияТаблицы = ЗначенияТаблицКлючей.Получить(ТаблицаКлюча).Строки[ИндексКлюча].Строки; - Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") Тогда - ЗначенияТаблицы = ЗначенияТаблицы[0]; - КонецЕсли; - ЗначенияТаблицКлюча.Вставить(ТаблицаКлюча, ЗначенияТаблицы); - КонецЦикла; - СтрокаЗначений = ЗначенияПервойТаблицы.Строки[ИндексКлюча]; // СправочникОбъект.КлючиДоступа - КлючДоступа = СтрокаЗначений.Ссылка; - - ПраваНаКлюч = ПраваНаКлючДоступаСписка(ЗначенияТаблицКлюча, ПараметрыОбновления); - // @skip-check query-in-loop - Порционная обработка данных - ОбновитьПраваНаКлючДоступаСписка(КлючДоступа, ПраваНаКлюч, - ?(ЭтоНовыеКлючи, ОписаниеКлючейДоступа, Неопределено), ПараметрыОбновления); - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Возвращаемое значение: -// Структура из КлючИЗначение: -// * Ключ - Строка - имя таблицы ключа -// * Значение - ДеревоЗначений -// -Функция НовыеЗначенияТаблицКлючей() - Возврат Новый Соответствие; -КонецФункции - -// Возвращаемое значение: -// Структура из КлючИЗначение: -// * Ключ - Строка - имя таблицы ключа -// * Значение - см. НовыеЗначенияТаблицыКлюча -// -Функция НовыеЗначенияТаблицКлюча() - Возврат Новый Структура; -КонецФункции - -// Возвращаемое значение: -// - КоллекцияСтрокДереваЗначений -// - ТаблицаЗначений -// - СтрокаДереваЗначений -// -Функция НовыеЗначенияТаблицыКлюча() - Возврат Новый ТаблицаЗначений; -КонецФункции - -// Для процедуры ОбновитьПорциюЭлементов. -Процедура ОбработатьУстаревшиеКлючиДоступаСписка(ЭлементыДанных, ПараметрыОбновления) - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК Поле1 - |ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - |ГДЕ - | КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК Поле1 - |ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборовГруппДоступа - |ГДЕ - | КлючиДоступаНаборовГруппДоступа.КлючДоступа = &КлючДоступа - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК Поле1 - |ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей - |ГДЕ - | КлючиДоступаПользователей.КлючДоступа = &КлючДоступа - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК Поле1 - |ИЗ - | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей - |ГДЕ - | КлючиДоступаВнешнихПользователей.КлючДоступа = &КлючДоступа"; - - ЭтоОчисткаВыбранныхКлючей = ПараметрыОбновления.БезЗаписиКлючейДоступа - Или ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей; - - Если Не ЭтоОчисткаВыбранныхКлючей Тогда - ЗапросИспользованияКлюча = Новый Запрос; - ЗапросИспользованияКлюча.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Ссылка = &Ссылка - | И КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1)"; - КонецЕсли; - - НаборЗаписейГруппДоступаКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); - НаборЗаписейНаборовГруппДоступаКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); - НаборЗаписейПользователейКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); - НаборЗаписейВнешнихПользователейКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); - - Для Каждого Строка Из ЭлементыДанных Цикл - СтрокаЗначений = Строка; // СправочникОбъект.КлючиДоступа - Ссылка = СтрокаЗначений.Ссылка; - Если Не ЭтоОчисткаВыбранныхКлючей И Строка.Используется Тогда - ЗапросИспользованияКлюча.УстановитьПараметр("Ссылка", Ссылка); - // @skip-check query-in-loop - Порционная обработка данных - Если Не ЗапросИспользованияКлюча.Выполнить().Пустой() Тогда - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - Продолжить; - КонецЕсли; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - Если Не ЭтоОчисткаВыбранныхКлючей Тогда - ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); - ЭлементБлокировки.УстановитьЗначение("Список", Строка.Список); - ЭлементБлокировки.УстановитьЗначение("Хеш", Строка.Хеш); - ЭлементБлокировки.УстановитьЗначение("СоставПолей", Строка.СоставПолей); - ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", - ПараметрыОбновления.ДляВнешнихПользователей); - КонецЕсли; - ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); - ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); - - НачатьТранзакцию(); - Попытка - Блокировка.Заблокировать(); - Объект = СлужебныйЭлемент(Неопределено, Ссылка); - УдалитьКлюч = Ложь; - Если ЭтоОчисткаВыбранныхКлючей Или Объект = Неопределено Тогда - УдалитьКлюч = Истина; - ИначеЕсли Строка.Используется Тогда - Объект.НеИспользуетсяС = '00010101'; - ИначеЕсли Не Строка.Удалить Тогда - Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); - ИначеЕсли ЗначениеЗаполнено(Объект.НеИспользуетсяС) Тогда - УдалитьКлюч = Истина; - КонецЕсли; - Если УдалитьКлюч Тогда - Запрос.УстановитьПараметр("КлючДоступа", Ссылка); - // @skip-check query-in-loop - Порционная обработка данных - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - Если Не РезультатыЗапроса[0].Пустой() Тогда - НаборЗаписейГруппДоступаКлюча.Отбор.КлючДоступа.Установить(Ссылка); - НаборЗаписейГруппДоступаКлюча.Записать(); - КонецЕсли; - Если Не РезультатыЗапроса[1].Пустой() Тогда - НаборЗаписейНаборовГруппДоступаКлюча.Отбор.КлючДоступа.Установить(Ссылка); - НаборЗаписейНаборовГруппДоступаКлюча.Записать(); - КонецЕсли; - Если Не РезультатыЗапроса[2].Пустой() Тогда - НаборЗаписейПользователейКлюча.Отбор.КлючДоступа.Установить(Ссылка); - НаборЗаписейПользователейКлюча.Записать(); - КонецЕсли; - Если Не РезультатыЗапроса[3].Пустой() Тогда - НаборЗаписейВнешнихПользователейКлюча.Отбор.КлючДоступа.Установить(Ссылка); - НаборЗаписейВнешнихПользователейКлюча.Записать(); - КонецЕсли; - КонецЕсли; - Если Объект <> Неопределено Тогда - Если УдалитьКлюч Тогда - Объект.Удалить(); - ИначеЕсли Объект.Модифицированность() Тогда - Объект.Записать(); - КонецЕсли; - КонецЕсли; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда - Прервать; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -// -// Возвращаемое значение: -// Структура: -// * ПраваГруппДоступаСписков - Соответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор списка -// ** Значение - см. ПраваГруппДоступаСписка -// -// * ЗначенияГруппДоступа - см. НовыеЗначенияГруппДоступа -// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа -// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей -// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа -// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа -// * РолиПрофилейГруппДоступа - см. НовыеРолиПрофилейГруппДоступа -// * ГруппыДоступаПрофилей - см. НовыеГруппыДоступаПрофилей -// -Функция КэшРасчетаПравДляВидаПользователей(ДляВнешнихПользователей) Экспорт - - КлючДанныхПовторногоИспользования = Строка(ПараметрыСеанса.КлючДанныхПовторногоИспользования); - Кэш = УправлениеДоступомСлужебныйПовтИсп.КэшРасчетаПрав(КлючДанныхПовторногоИспользования); - - ВерсияДанных = ВерсияДанныхДляКэшаРасчетаПрав(); - - Если Кэш.ВерсияДанных.ТаблицыГруппДоступа <> ВерсияДанных.ТаблицыГруппДоступа Тогда - СброситьКэшРасчетаПрав(Кэш, "ПраваГруппДоступаСписков", Истина); - Кэш.ВерсияДанных.ТаблицыГруппДоступа = ВерсияДанных.ТаблицыГруппДоступа; - КонецЕсли; - - Если Кэш.ВерсияДанных.ЗначенияГруппДоступа <> ВерсияДанных.ЗначенияГруппДоступа Тогда - СброситьКэшРасчетаПрав(Кэш, "ЗначенияГруппДоступа"); - СброситьКэшРасчетаПрав(Кэш, "ГруппыПользователейКакЗначенияДоступа"); - Кэш.ВерсияДанных.ЗначенияГруппДоступа = ВерсияДанных.ЗначенияГруппДоступа; - КонецЕсли; - - Если Кэш.ВерсияДанных.УчастникиГруппДоступа <> ВерсияДанных.УчастникиГруппДоступа Тогда - СброситьКэшРасчетаПрав(Кэш, "УчастникиГруппДоступа"); - СброситьКэшРасчетаПрав(Кэш, "ГрупповыеПользователиГруппДоступа"); - Кэш.ВерсияДанных.УчастникиГруппДоступа = ВерсияДанных.УчастникиГруппДоступа; - КонецЕсли; - - Если Кэш.ВерсияДанных.СоставыГруппПользователей <> ВерсияДанных.СоставыГруппПользователей Тогда - СброситьКэшРасчетаПрав(Кэш, "ПользователиГруппПользователей"); - СброситьКэшРасчетаПрав(Кэш, "УчастникиГруппДоступа"); - СброситьКэшРасчетаПрав(Кэш, "ГрупповыеПользователиГруппДоступа"); - СброситьКэшРасчетаПрав(Кэш, "ГруппыПользователейКакЗначенияДоступа"); - Кэш.ВерсияДанных.СоставыГруппПользователей = ВерсияДанных.СоставыГруппПользователей; - КонецЕсли; - - Если Кэш.ВерсияДанных.РолиПрофилейГруппДоступа <> ВерсияДанных.РолиПрофилейГруппДоступа Тогда - СброситьКэшРасчетаПрав(Кэш, "РолиПрофилейГруппДоступа"); - СброситьКэшРасчетаПрав(Кэш, "ГруппыДоступаПрофилей"); - Кэш.ВерсияДанных.РолиПрофилейГруппДоступа = ВерсияДанных.РолиПрофилейГруппДоступа; - КонецЕсли; - - Если Кэш.ВерсияДанных.ГруппыДоступаПрофилей <> ВерсияДанных.ГруппыДоступаПрофилей Тогда - СброситьКэшРасчетаПрав(Кэш, "РолиПрофилейГруппДоступа"); - СброситьКэшРасчетаПрав(Кэш, "ГруппыДоступаПрофилей"); - Кэш.ВерсияДанных.ГруппыДоступаПрофилей = ВерсияДанных.ГруппыДоступаПрофилей; - КонецЕсли; - - Если ДляВнешнихПользователей Тогда - Возврат Кэш.ДляВнешнихПользователей; - Иначе - Возврат Кэш.ДляПользователей; - КонецЕсли; - -КонецФункции - -// Для функции КэшРасчетаПравДляВидаПользователей. -Процедура СброситьКэшРасчетаПрав(Кэш, Свойство, НовоеСоответствие = Ложь) - - Кэш.ДляПользователей[Свойство] = ?(НовоеСоответствие, Новый Соответствие, Неопределено); - Кэш.ДляВнешнихПользователей[Свойство] = ?(НовоеСоответствие, Новый Соответствие, Неопределено); - -КонецПроцедуры - -// Для процедур ЗаполнитьПраваГруппДоступаСписка и -// ЗаполнитьУчастниковГруппДоступаСписка. -// -Функция ТекстЗапросаНазначенияПрофилей() - - Возврат - "ВЫБРАТЬ - | Профили.Ссылка КАК Профиль, - | МАКСИМУМ(ВЫБОР - | КОГДА НазначениеПрофилей.ТипПользователей ЕСТЬ NULL - | ТОГДА ИСТИНА - | ИНАЧЕ ТИПЗНАЧЕНИЯ(НазначениеПрофилей.ТипПользователей) = ТИП(Справочник.Пользователи) - | КОНЕЦ) КАК ДляПользователей, - | МАКСИМУМ(ВЫБОР - | КОГДА НазначениеПрофилей.ТипПользователей ЕСТЬ NULL - | ТОГДА ЛОЖЬ - | ИНАЧЕ НазначениеПрофилей.ТипПользователей <> НЕОПРЕДЕЛЕНО - | И ТИПЗНАЧЕНИЯ(НазначениеПрофилей.ТипПользователей) <> ТИП(Справочник.Пользователи) - | КОНЕЦ) КАК ДляВнешнихПользователей - |ПОМЕСТИТЬ НазначениеПрофилей - |ИЗ - | Справочник.ПрофилиГруппДоступа КАК Профили - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Назначение КАК НазначениеПрофилей - | ПО (НазначениеПрофилей.Ссылка = Профили.Ссылка) - | - |СГРУППИРОВАТЬ ПО - | Профили.Ссылка"; - -КонецФункции - -// Параметры: -// Права - ТаблицаЗначений -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа -// * ПравоИзменение - Булево -// * ПравоДобавление - Булево -// * ПравоЧтениеБезОграничения - Булево -// * ПравоИзменениеБезОграничения - Булево -// * ПравоДобавлениеБезОграничения - Булево -// -Функция НовыеПраваГруппДоступаСписка(Права) - Возврат Права; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьПраваГруппДоступаСписка(ПараметрыОбновления, Кэш) - - ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; - ПраваГруппДоступаСписка = Кэш.ПраваГруппДоступаСписков.Получить(ИдентификаторСписка); - Если ПраваГруппДоступаСписка <> Неопределено Тогда - ПараметрыОбновления.Вставить("ПраваГруппДоступаСписка", ПраваГруппДоступаСписка); - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("Таблица", ИдентификаторСписка); - Запрос.Текст = - "ВЫБРАТЬ - | ТаблицыГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, - | ТаблицыГруппДоступа.ПравоИзменение КАК ПравоИзменение, - | ТаблицыГруппДоступа.ПравоДобавление КАК ПравоДобавление, - | ТаблицыГруппДоступа.ПравоЧтениеБезОграничения КАК ПравоЧтениеБезОграничения, - | ТаблицыГруппДоступа.ПравоИзменениеБезОграничения КАК ПравоИзменениеБезОграничения, - | ТаблицыГруппДоступа.ПравоДобавлениеБезОграничения КАК ПравоДобавлениеБезОграничения - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа - | ПО (ТаблицыГруппДоступа.Таблица = &Таблица) - | И (ГруппыДоступа.Ссылка = ТаблицыГруппДоступа.ГруппаДоступа) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НазначениеПрофилей КАК НазначениеПрофилей - | ПО (НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль) - | И (НазначениеПрофилей.ДляПользователей)"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); - КонецЕсли; - - Запрос.Текст = ТекстЗапросаНазначенияПрофилей() - + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; - - ПраваГруппДоступаСписка = НовыеПраваГруппДоступаСписка(Запрос.Выполнить().Выгрузить()); - Кэш.ПраваГруппДоступаСписков.Вставить(ИдентификаторСписка, ПраваГруппДоступаСписка); - ПараметрыОбновления.Вставить("ПраваГруппДоступаСписка", ПраваГруппДоступаСписка); - -КонецПроцедуры - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ГруппыВнешнихПользователей -// - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// * Значение - Соответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// ** Значение - Булево - Истина -// -Функция НовыеПользователиГруппПользователей() - Возврат Новый Соответствие; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьПользователейГруппПользователей(ПараметрыОбновления, Кэш) - - ПараметрыОбновления.Вставить("ПользователиГруппПользователей", НовыеПользователиГруппПользователей()); - - Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда - Возврат; - КонецЕсли; - - Если Кэш.ПользователиГруппПользователей <> Неопределено Тогда - ПараметрыОбновления.ПользователиГруппПользователей = Кэш.ПользователиГруппПользователей; - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, - | СоставыГруппПользователей.Пользователь КАК Пользователь - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи - | ПО (Пользователи.Ссылка = СоставыГруппПользователей.Пользователь) - | И (Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)) - | И (СоставыГруппПользователей.Используется) - |ИТОГИ ПО - | ГруппаПользователей"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - ПользователиГруппПользователей = ПараметрыОбновления.ПользователиГруппПользователей; - - РезультатЗапроса = Запрос.Выполнить(); - ЗаполнитьПользователейГрупп(ПользователиГруппПользователей, РезультатЗапроса); - - Кэш.ПользователиГруппПользователей = ПользователиГруппПользователей; - -КонецПроцедуры - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ГруппыВнешнихПользователей -// * Значение - Соответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// ** Значение - Булево - Истина -// -Функция НовыеГруппыПользователейКакЗначенияДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьГруппыПользователейКакЗначенияДоступа(ПараметрыОбновления, Кэш) - - ПараметрыОбновления.Вставить("ГруппыПользователейКакЗначенияДоступа", - НовыеГруппыПользователейКакЗначенияДоступа()); - - Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда - Возврат; - КонецЕсли; - - Если Кэш.ГруппыПользователейКакЗначенияДоступа <> Неопределено Тогда - ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа = Кэш.ГруппыПользователейКакЗначенияДоступа; - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, - | СоставыГруппПользователей.Пользователь КАК Пользователь - |ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияГруппДоступа КАК ЗначенияГруппДоступа - | ПО СоставыГруппПользователей.ГруппаПользователей = ЗначенияГруппДоступа.ЗначениеДоступа - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)) - | И (ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыПользователей)) - |ИТОГИ ПО - | ГруппаПользователей"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - ГруппыПользователейКакЗначенияДоступа = ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа; - - РезультатЗапроса = Запрос.Выполнить(); - ЗаполнитьПользователейГрупп(ГруппыПользователейКакЗначенияДоступа, РезультатЗапроса); - - Кэш.ГруппыПользователейКакЗначенияДоступа = ГруппыПользователейКакЗначенияДоступа; - -КонецПроцедуры - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.ГруппыДоступа -// * Значение - Соответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.Пользователи -// - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ВнешниеПользователи -// - СправочникСсылка.ГруппыВнешнихПользователей -// ** Значение - Булево - Истина -// -Функция НовыеУчастникиГруппДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.ГруппыДоступа -// * Значение - Соответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// ** Значение - Булево - Истина -// -Функция НовыеГрупповыеПользователиГруппДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьУчастниковГруппДоступаСписка(ПараметрыОбновления, Кэш) - - ПараметрыОбновления.Вставить("УчастникиГруппДоступа", НовыеУчастникиГруппДоступа()); - ПараметрыОбновления.Вставить("ГрупповыеПользователиГруппДоступа", НовыеГрупповыеПользователиГруппДоступа()); - - Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда - Возврат; - КонецЕсли; - - Если Кэш.УчастникиГруппДоступа <> Неопределено Тогда - ПараметрыОбновления.УчастникиГруппДоступа = Кэш.УчастникиГруппДоступа; - ПараметрыОбновления.ГрупповыеПользователиГруппДоступа = Кэш.ГрупповыеПользователиГруппДоступа; - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ПользователиГруппыДоступа.Ссылка КАК ГруппаДоступа, - | ПользователиГруппыДоступа.Пользователь КАК Участник - |ИЗ - | Справочник.ГруппыДоступа КАК ГруппыДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НазначениеПрофилей КАК НазначениеПрофилей - | ПО (НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль) - | И (НазначениеПрофилей.ДляПользователей) - | И (НЕ ГруппыДоступа.ПометкаУдаления) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппыДоступа - | ПО (ПользователиГруппыДоступа.Ссылка = ГруппыДоступа.Ссылка) - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи - | ПО - | СоставыГруппПользователей.ГруппаПользователей = ПользователиГруппыДоступа.Пользователь - | И СоставыГруппПользователей.Используется - | И Пользователи.Ссылка = СоставыГруппПользователей.Пользователь - | И Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор)) - |ИТОГИ ПО - | ГруппаДоступа"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); - КонецЕсли; - - Запрос.Текст = ТекстЗапросаНазначенияПрофилей() - + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; - - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - УчастникиГруппДоступа = ПараметрыОбновления.УчастникиГруппДоступа; - ГрупповыеПользователиГруппДоступа = ПараметрыОбновления.ГрупповыеПользователиГруппДоступа; - ТипГруппыПользователей = ПараметрыОбновления.ТипГруппыПользователей; - ПользователиГруппПользователей = ПараметрыОбновления.ПользователиГруппПользователей; - - Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - - Для Каждого Строка Из Дерево.Строки Цикл - УчастникиГруппыДоступа = Новый Соответствие; - ГрупповыеПользователиГруппыДоступа = Новый Соответствие; - Для Каждого Подстрока Из Строка.Строки Цикл - УчастникиГруппыДоступа.Вставить(Подстрока.Участник, Истина); - Если ТипЗнч(Подстрока.Участник) = ТипГруппыПользователей Тогда - ПользователиГруппы = ПользователиГруппПользователей.Получить(Подстрока.Участник); - Если ПользователиГруппы <> Неопределено Тогда - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - ГрупповыеПользователиГруппыДоступа.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЦикла; - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если УчастникиГруппыДоступа.Количество() > 0 Тогда - УчастникиГруппДоступа.Вставить(Строка.ГруппаДоступа, УчастникиГруппыДоступа); - КонецЕсли; - Если ГрупповыеПользователиГруппыДоступа.Количество() > 0 Тогда - ГрупповыеПользователиГруппДоступа.Вставить(Строка.ГруппаДоступа, ГрупповыеПользователиГруппыДоступа); - КонецЕсли; - КонецЦикла; - - Кэш.УчастникиГруппДоступа = УчастникиГруппДоступа; - Кэш.ГрупповыеПользователиГруппДоступа = ГрупповыеПользователиГруппДоступа; - -КонецПроцедуры - -// Для процедур ЗаполнитьПользователейГруппПользователей и -// ЗаполнитьГруппыПользователейКакЗначенияДоступа. -// -Процедура ЗаполнитьПользователейГрупп(ПользователиГруппПользователей, РезультатЗапроса) - - Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого Строка Из Дерево.Строки Цикл - ПользователиГруппыПользователей = Новый Соответствие; - Для Каждого Подстрока Из Строка.Строки Цикл - ПользователиГруппыПользователей.Вставить(Подстрока.Пользователь, Истина); - КонецЦикла; - ПользователиГруппПользователей.Вставить(Строка.ГруппаПользователей, ПользователиГруппыПользователей); - КонецЦикла; - -КонецПроцедуры - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - Тип - тип значений доступа -// * Значение - Структура: -// ** ВсеРазрешены - Булево -// ** Значения - Соответствие из КлючИЗначение: -// *** Ключ - ОпределяемыйТип.ЗначениеДоступа -// *** Значение - Булево - Истина -// -Функция НовыеЗначенияГруппыДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.ГруппыДоступа -// * Значение - см. НовыеЗначенияГруппыДоступа -// -Функция НовыеЗначенияГруппДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьЗначенияГруппДоступаДляРасчетаПрав(ПараметрыОбновления, Кэш) - - Если Кэш.ЗначенияГруппДоступа <> Неопределено Тогда - ПараметрыОбновления.Вставить("ЗначенияГруппДоступа", Кэш.ЗначенияГруппДоступа); - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | ЗначенияГруппДоступаПоУмолчанию.ГруппаДоступа КАК ГруппаДоступа, - | ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступаПоУмолчанию.ТипЗначенийДоступа) КАК ТипЗначенийДоступа, - | ЗначенияГруппДоступаПоУмолчанию.ВсеРазрешены КАК ВсеРазрешены - |ИЗ - | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияГруппДоступаПоУмолчанию - |ГДЕ - | НЕ ЗначенияГруппДоступаПоУмолчанию.БезНастройки - |ИТОГИ ПО - | ГруппаДоступа - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ЗначенияГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, - | ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступа.ЗначениеДоступа) КАК ТипЗначенийДоступа, - | ЗначенияГруппДоступа.ЗначениеДоступа КАК ЗначениеДоступа - |ИЗ - | РегистрСведений.ЗначенияГруппДоступа КАК ЗначенияГруппДоступа - |ИТОГИ ПО - | ГруппаДоступа, - | ТипЗначенийДоступа"; - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - ЗначенияГруппДоступа = НовыеЗначенияГруппДоступа(); - - Дерево = РезультатыЗапроса[0].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого Строка Из Дерево.Строки Цикл - ЗначенияГруппыДоступа = НовыеЗначенияГруппыДоступа(); - Для Каждого Подстрока Из Строка.Строки Цикл - ЗначенияОдногоТипа = Новый Структура; - ЗначенияОдногоТипа.Вставить("ВсеРазрешены", Подстрока.ВсеРазрешены); - ЗначенияОдногоТипа.Вставить("Значения", Новый Соответствие); - ЗначенияГруппыДоступа.Вставить(Подстрока.ТипЗначенийДоступа, ЗначенияОдногоТипа); - КонецЦикла; - ЗначенияГруппДоступа.Вставить(Строка.ГруппаДоступа, ЗначенияГруппыДоступа); - КонецЦикла; - - Дерево = РезультатыЗапроса[1].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого Строка Из Дерево.Строки Цикл - ЗначенияГруппыДоступа = ЗначенияГруппДоступа.Получить(Строка.ГруппаДоступа); - Если ЗначенияГруппыДоступа = Неопределено Тогда - Продолжить; - КонецЕсли; - Для Каждого Подстрока Из Строка.Строки Цикл - ЗначенияОдногоТипа = ЗначенияГруппыДоступа.Получить(Подстрока.ТипЗначенийДоступа); - Если ЗначенияОдногоТипа = Неопределено Тогда - Продолжить; - КонецЕсли; - Значения = ЗначенияОдногоТипа.Значения; - Для Каждого ОписаниеЗначения Из Подстрока.Строки Цикл - Значения.Вставить(ОписаниеЗначения.ЗначениеДоступа, Истина); - КонецЦикла; - КонецЦикла; - КонецЦикла; - - ПараметрыОбновления.Вставить("ЗначенияГруппДоступа", ЗначенияГруппДоступа); - Кэш.ЗначенияГруппДоступа = ЗначенияГруппДоступа; - -КонецПроцедуры - -// Возвращаемое значение: -// ТаблицаЗначений: -// * Профиль - СправочникСсылка.ПрофилиГруппДоступа -// * Роль - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// * ИмяРоли - Строка -// * ИмяРолиВерхнийРегистр - Строка -// -Функция НовыеРолиПрофилейГруппДоступа() - Возврат Новый ТаблицаЗначений; -КонецФункции - -// Возвращаемое значение: -// ТаблицаЗначений: -// * Профиль - СправочникСсылка.ПрофилиГруппДоступа -// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа -// -Функция НовыеГруппыДоступаПрофилей() - Возврат Новый ТаблицаЗначений; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьРолиИГруппыДоступаПрофилей(ПараметрыОбновления, Кэш) - - ПараметрыОбновления.Вставить("РолиПрофилейГруппДоступа", НовыеРолиПрофилейГруппДоступа()); - ПараметрыОбновления.Вставить("ГруппыДоступаПрофилей", НовыеГруппыДоступаПрофилей()); - - Если Не ПараметрыОбновления.ЕстьФункцияПравоДоступаИлиРольДоступна Тогда - Возврат; - КонецЕсли; - - Если Кэш.РолиПрофилейГруппДоступа <> Неопределено Тогда - ПараметрыОбновления.РолиПрофилейГруппДоступа = Кэш.РолиПрофилейГруппДоступа; - ПараметрыОбновления.ГруппыДоступаПрофилей = Кэш.ГруппыДоступаПрофилей; - Возврат; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | РолиПрофилей.Роль КАК Роль - |ИЗ - | НазначениеПрофилей КАК НазначениеПрофилей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей - | ПО (РолиПрофилей.Ссылка = НазначениеПрофилей.Профиль) - | И (НазначениеПрофилей.ДляПользователей) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | РолиПрофилей.Ссылка КАК Профиль, - | РолиПрофилей.Роль КАК Роль - |ИЗ - | НазначениеПрофилей КАК НазначениеПрофилей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей - | ПО (РолиПрофилей.Ссылка = НазначениеПрофилей.Профиль) - | И (НазначениеПрофилей.ДляПользователей) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НазначениеПрофилей.Профиль КАК Профиль, - | ГруппыДоступа.Ссылка КАК ГруппаДоступа - |ИЗ - | НазначениеПрофилей КАК НазначениеПрофилей - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа - | ПО НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль - | И (НазначениеПрофилей.ДляПользователей)"; - - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); - КонецЕсли; - - Запрос.Текст = ТекстЗапросаНазначенияПрофилей() - + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - Роли = РезультатыЗапроса[1].Выгрузить().ВыгрузитьКолонку("Роль"); - ОбъектыМетаданныхРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(Роли, Ложь); - - РолиПрофилейГруппДоступа = РезультатыЗапроса[2].Выгрузить(); - ТипИмениРоли = Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.Имя.Тип; - РолиПрофилейГруппДоступа.Колонки.Добавить("ИмяРоли", ТипИмениРоли); - РолиПрофилейГруппДоступа.Колонки.Добавить("ИмяРолиВерхнийРегистр", ТипИмениРоли); - РолиПрофилейГруппДоступа.Индексы.Добавить("Роль"); - Отбор = Новый Структура("Роль"); - ТребуетсяПроверитьАктуальностьМетаданных = Ложь; - - Для Каждого ОписаниеРоли Из ОбъектыМетаданныхРолей Цикл - Если ТипЗнч(ОписаниеРоли.Значение) <> Тип("ОбъектМетаданных") Тогда - ТребуетсяПроверитьАктуальностьМетаданных = Истина; - Продолжить; - КонецЕсли; - ИмяРоли = ОписаниеРоли.Значение.Имя; - ИмяРолиВерхнийРегистр = ВРег(ИмяРоли); - Отбор.Роль = ОписаниеРоли.Ключ; - Строки = РолиПрофилейГруппДоступа.НайтиСтроки(Отбор); - Для Каждого Строка Из Строки Цикл - Строка.ИмяРоли = ИмяРоли; - Строка.ИмяРолиВерхнийРегистр = ИмяРолиВерхнийРегистр; - КонецЦикла; - КонецЦикла; - Если ТребуетсяПроверитьАктуальностьМетаданных Тогда - ПроверитьАктуальностьМетаданных(); - КонецЕсли; - РолиПрофилейГруппДоступа.Индексы.Добавить("Профиль,ИмяРолиВерхнийРегистр"); - - ГруппыДоступаПрофилей = РезультатыЗапроса[3].Выгрузить(); - ГруппыДоступаПрофилей.Индексы.Добавить("ГруппаДоступа"); - - ПараметрыОбновления.РолиПрофилейГруппДоступа = РолиПрофилейГруппДоступа; - ПараметрыОбновления.ГруппыДоступаПрофилей = ГруппыДоступаПрофилей; - Кэш.РолиПрофилейГруппДоступа = РолиПрофилейГруппДоступа; - Кэш.ГруппыДоступаПрофилей = ГруппыДоступаПрофилей; - -КонецПроцедуры - -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.КлючиДоступа -// * Значение - ФиксированнаяСтруктура: -// ** ОграничениеЧтенияОтключено - Булево -// ** ОграничениеОтключено - Булево -// ** ПоГруппамДоступа - ФиксированноеСоответствие из КлючИЗначение: -// *** Ключ - СправочникСсылка.ГруппыДоступа -// *** Значение - Булево - право изменение -// -Функция НовыеПраваНаСпискиВедущихКлючейДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.КлючиДоступа -// * Значение - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.ГруппыДоступа -// - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ГруппыВнешнихПользователей -// ** Значение - Булево - право изменение -// -Функция НовыеПраваНаВедущиеКлючиДоступа() - Возврат Новый Соответствие; -КонецФункции - -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор списка -// - Тип - тип значений списка -// * Значение - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.ГруппыДоступа -// - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ГруппыВнешнихПользователей -// ** Значение - Булево - право изменение -// -Функция НовыеПраваНаВедущиеСписки() - Возврат Новый Соответствие; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьПраваНаВедущиеКлючиДоступаИВедущиеСписки(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления) - - ПраваНаСпискиВедущихКлючейДоступа = НовыеПраваНаСпискиВедущихКлючейДоступа(); - ПраваНаВедущиеКлючиДоступа = НовыеПраваНаВедущиеКлючиДоступа(); - Если ПараметрыОбновления.ЕстьВедущиеКлючиДоступа Тогда - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ПараметрыОбновления.ИдентификаторТранзакции, Неопределено, Ложь); - Если ПараметрыОбновления.ДляВнешнихПользователей Тогда - ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; - Иначе - ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; - КонецЕсли; - НомерТаблицы = НомерТаблицы + 1; - ПраваНаСписки = Новый Соответствие; - Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - ИдентификаторыСписков = Дерево.Строки.ВыгрузитьКолонку("Список"); - Если ПараметрыОбновления.Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда - ОбъектыМетаданныхПоИдентификаторам = ПараметрыОбновления.Кэш.ОбъектыМетаданныхПоИдентификаторам; - НенайденныеИдентификаторыСписков = Новый Массив; - Для Каждого ИдентификаторСписка Из ИдентификаторыСписков Цикл - Если ОбъектыМетаданныхПоИдентификаторам.Получить(ИдентификаторСписка) = Неопределено Тогда - НенайденныеИдентификаторыСписков.Добавить(ИдентификаторСписка); - КонецЕсли; - КонецЦикла; - Результат = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( - НенайденныеИдентификаторыСписков, Ложь); - Для Каждого КлючИЗначение Из Результат Цикл - ОбъектыМетаданныхПоИдентификаторам.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - Иначе - ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( - ИдентификаторыСписков, Ложь); - КонецЕсли; - Для Каждого Строка Из Дерево.Строки Цикл - ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(Строка.Список); - Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда - Продолжить; - КонецЕсли; - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - ПоГруппамДоступа = Новый Соответствие; - Для Каждого Подстрока Из Строка.Строки Цикл - ПоГруппамДоступа.Вставить(Подстрока.ГруппаДоступа, Подстрока.ПравоИзменение); - КонецЦикла; - ПраваНаСписок = Новый Структура; - ПраваНаСписок.Вставить("ОграничениеЧтенияОтключено", - ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения.Получить(ПолноеИмя) <> Неопределено); - ПраваНаСписок.Вставить("ОграничениеОтключено", - ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(ПолноеИмя) <> Неопределено); - ПраваНаСписок.Вставить("ПоГруппамДоступа", Новый ФиксированноеСоответствие(ПоГруппамДоступа)); - ПраваНаСписки.Вставить(Строка.Список, Новый ФиксированнаяСтруктура(ПраваНаСписок)); - КонецЦикла; - НомерТаблицы = НомерТаблицы + 1; - Таблица = РезультатыЗапроса[НомерТаблицы].Выгрузить(); - Для Каждого Строка Из Таблица Цикл - ПраваНаСпискиВедущихКлючейДоступа.Вставить(Строка.КлючДоступа, - ПраваНаСписки.Получить(Строка.Список)); - КонецЦикла; - НомерТаблицы = НомерТаблицы + 1; - Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого Строка Из Дерево.Строки Цикл - ПраваНаВедущийКлюч = Новый Соответствие; - Для Каждого Подстрока Из Строка.Строки Цикл - ПраваНаВедущийКлюч.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); - КонецЦикла; - ПраваНаВедущиеКлючиДоступа.Вставить(Строка.КлючДоступа, - Новый ФиксированноеСоответствие(ПраваНаВедущийКлюч)); - КонецЦикла; - КонецЕсли; - ПараметрыОбновления.Вставить("ПраваНаСпискиВедущихКлючейДоступа", - Новый ФиксированноеСоответствие(ПраваНаСпискиВедущихКлючейДоступа)); - ПараметрыОбновления.Вставить("ПраваНаВедущиеКлючиДоступа", - Новый ФиксированноеСоответствие(ПраваНаВедущиеКлючиДоступа)); - - ПраваНаВедущиеСписки = НовыеПраваНаВедущиеСписки(); - Если ПараметрыОбновления.ЕстьВедущиеСпискиПоПравам Тогда - НомерТаблицы = НомерТаблицы + 1; - Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - ДобавитьПраваПоТипам = Дерево.Колонки.Найти("ТипЗначения") <> Неопределено; - Для Каждого Строка Из Дерево.Строки Цикл - ПраваНаВедущийСписок = Новый Соответствие; - Для Каждого Подстрока Из Строка.Строки Цикл - ПраваНаВедущийСписок.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); - Если ДобавитьПраваПоТипам Тогда - ТипЗначенияСписка = Подстрока.ТипЗначения; - КонецЕсли; - КонецЦикла; - ПраваНаВедущиеСписки.Вставить(Строка.Список, - Новый ФиксированноеСоответствие(ПраваНаВедущийСписок)); - Если ДобавитьПраваПоТипам Тогда - ПраваНаВедущиеСписки.Вставить(ТипЗначенияСписка, - Новый ФиксированноеСоответствие(ПраваНаВедущийСписок)); - КонецЕсли; - КонецЦикла; - КонецЕсли; - ПараметрыОбновления.Вставить("ПраваНаВедущиеСписки", - Новый ФиксированноеСоответствие(ПраваНаВедущиеСписки)); - -КонецПроцедуры - -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - ОпределяемыйТип.ВладелецНастроекПрав -// * Значение - ФиксированноеСоответствие из КлючИЗначение: -// ** Ключ - СправочникСсылка.Пользователи -// - СправочникСсылка.ГруппыПользователей -// - СправочникСсылка.ВнешниеПользователи -// - СправочникСсылка.ГруппыВнешнихПользователей -// ** Значение - Булево - право изменение -// -Функция НовыеПраваПоВладельцамНастроекПрав() - Возврат Новый Соответствие; -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ЗаполнитьПраваПоВладельцамНастроекПрав(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления) - - ПраваПоВладельцамНастроекПрав = НовыеПраваПоВладельцамНастроекПрав(); - Если ПараметрыОбновления.ЕстьВладельцыНастроекПрав Тогда - НомерТаблицы = НомерТаблицы + 5; - Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого Строка Из Дерево.Строки Цикл - ПраваПоВладельцуНастроекПрав = Новый Соответствие; - Для Каждого Подстрока Из Строка.Строки Цикл - ПраваПоВладельцуНастроекПрав.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); - КонецЦикла; - ПраваПоВладельцамНастроекПрав.Вставить(Строка.ВладелецНастроекПрав, - Новый ФиксированноеСоответствие(ПраваПоВладельцуНастроекПрав)); - КонецЦикла; - КонецЕсли; - ПараметрыОбновления.Вставить("ПраваПоВладельцамНастроекПрав", - Новый ФиксированноеСоответствие(ПраваПоВладельцамНастроекПрав)); - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ЗначенияТаблицКлюча - см. НовыеЗначенияТаблицКлюча -// * БезЗаписиПраваЧтение - Булево -// * РеквизитыТаблицКлюча - см. НовыеРеквизитыТаблицКлюча -// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа -// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа -// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа -// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей -// * ПраваНаСпискиВедущихКлючейДоступа - см. НовыеПраваНаСпискиВедущихКлючейДоступа -// * ПраваНаВедущиеКлючиДоступа - см. НовыеПраваНаВедущиеКлючиДоступа -// * ПраваНаВедущиеСписки - см. НовыеПраваНаВедущиеСписки -// * ПраваПоВладельцамНастроекПрав - см. НовыеПраваПоВладельцамНастроекПрав -// * ТипГруппыДоступа - Тип -// * ПустаяГруппаДоступа - СправочникСсылка.ГруппыДоступа -// * ТипПользователя - Тип -// * ТипГруппыПользователей - Тип -// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие -// * ПраваРолейФункцииПравоДоступа - Соответствие -// * ОбъектыМетаданныхФункцииПравоДоступа - Соответствие -// * ПраваПрофилейФункцииПравоДоступа - Соответствие -// * РолиПрофилейГруппДоступа - см. РолиПрофилейГруппДоступа -// * ГруппыДоступаПрофилей - см. ГруппыДоступаПрофилей -// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа - текущее значение -// * ЗначенияГруппыДоступа - см. НовыеЗначенияГруппыДоступа -// * ОписанияТребуемыхТаблицКлюча - Массив из Структура: -// ** РеквизитыТаблиц - Соответствие из КлючИЗначение: -// *** Ключ - Строка - имя таблицы ключа -// *** Значение - Массив из Строка - имя реквизита таблицы ключа -// ** ЗначенияТаблиц - см. ТекущиеЗначенияТаблицКлюча -// ** ИндексыСтрокТаблиц - Соответствие -// * ТекущиеСтрокиТаблицКлюча - см. НовыеЗначенияТаблицКлюча -// -Функция НовыйКонтекстРасчетаПрав() - Возврат Новый Структура; -КонецФункции - -// Для процедуры ОбновитьПраваНаКлючиДоступаСписка. -Функция ПраваНаКлючДоступаСписка(ЗначенияТаблицКлюча, ПараметрыОбновления) - - ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); - - Если ПараметрыОбновления.ОграничениеОтключено Тогда - Если Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа Тогда - Возврат ПраваНаКлюч; - ИначеЕсли ПараметрыОбновления.ИзменениеРазрешеноДляВсехПользователей Тогда - ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, - Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); - Возврат ПраваНаКлюч; - КонецЕсли; - КонецЕсли; - - БезЗаписиПраваЧтение = ПараметрыОбновления.ОграничениеЧтенияОтключено - И Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа; - - Контекст = НовыйКонтекстРасчетаПрав(); - Контекст.Вставить("ЗначенияТаблицКлюча", ЗначенияТаблицКлюча); - Контекст.Вставить("БезЗаписиПраваЧтение", БезЗаписиПраваЧтение); - Контекст.Вставить("РеквизитыТаблицКлюча", ПараметрыОбновления.РеквизитыТаблицКлюча); - Контекст.Вставить("УчастникиГруппДоступа", ПараметрыОбновления.УчастникиГруппДоступа); - Контекст.Вставить("ГрупповыеПользователиГруппДоступа", ПараметрыОбновления.ГрупповыеПользователиГруппДоступа); - Контекст.Вставить("ГруппыПользователейКакЗначенияДоступа", ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа); - Контекст.Вставить("ПользователиГруппПользователей", ПараметрыОбновления.ПользователиГруппПользователей); - Контекст.Вставить("ПраваНаСпискиВедущихКлючейДоступа", ПараметрыОбновления.ПраваНаСпискиВедущихКлючейДоступа); - Контекст.Вставить("ПраваНаВедущиеКлючиДоступа", ПараметрыОбновления.ПраваНаВедущиеКлючиДоступа); - Контекст.Вставить("ПраваНаВедущиеСписки", ПараметрыОбновления.ПраваНаВедущиеСписки); - Контекст.Вставить("ПраваПоВладельцамНастроекПрав", ПараметрыОбновления.ПраваПоВладельцамНастроекПрав); - Контекст.Вставить("РассчитыватьПраваПользователей", ПараметрыОбновления.РассчитыватьПраваПользователей); - Контекст.Вставить("ТипГруппыДоступа", ПараметрыОбновления.ТипГруппыДоступа); - Контекст.Вставить("ПустаяГруппаДоступа", ПараметрыОбновления.ПустаяГруппаДоступа); - Контекст.Вставить("ТипПользователя", ПараметрыОбновления.ТипПользователя); - Контекст.Вставить("ТипГруппыПользователей", ПараметрыОбновления.ТипГруппыПользователей); - Контекст.Вставить("ТипыВладельцевНастроекПрав", ПараметрыОбновления.ТипыВладельцевНастроекПрав); - Контекст.Вставить("ПраваРолейФункцииПравоДоступа", ПараметрыОбновления.Кэш.ПраваРолейФункцииПравоДоступа); - Контекст.Вставить("ОбъектыМетаданныхФункцииПравоДоступа", ПараметрыОбновления.Кэш.ОбъектыМетаданныхФункцииПравоДоступа); - Контекст.Вставить("ПраваПрофилейФункцииПравоДоступа", ПараметрыОбновления.Кэш.ПраваПрофилейФункцииПравоДоступа); - Контекст.Вставить("РолиПрофилейГруппДоступа", ПараметрыОбновления.РолиПрофилейГруппДоступа); - Контекст.Вставить("ГруппыДоступаПрофилей", ПараметрыОбновления.ГруппыДоступаПрофилей); - - ЧтениеРазрешеноДляВсехГруппДоступа = Истина; - ИзменениеРазрешеноДляВсехГруппДоступа = Истина; - ДобавлениеРазрешеноДляВсехГруппДоступа = Истина; - - Для Каждого ОписаниеПрав Из ПараметрыОбновления.ПраваГруппДоступаСписка Цикл - ГруппаДоступа = ОписаниеПрав.ГруппаДоступа; - ПраваГруппыДоступа = ОписаниеПрав; // СтрокаТаблицыЗначений - - Контекст.Вставить("ГруппаДоступа", ГруппаДоступа); - Контекст.Вставить("ЗначенияГруппыДоступа", - ПараметрыОбновления.ЗначенияГруппДоступа.Получить(ГруппаДоступа)); - - Если БезЗаписиПраваЧтение - Или ПраваГруппыДоступа.ПравоЧтениеБезОграничения Тогда - - ПравоЧтение = "Истина"; - Иначе - ПравоЧтение = РассчитанноеУсловиеДляСтрок(Контекст, - ПараметрыОбновления.СтруктураРасчетаПраваЧтение); - КонецЕсли; - - Если ПравоЧтение <> "Истина" Тогда - ЧтениеРазрешеноДляВсехГруппДоступа = Ложь; - ИзменениеРазрешеноДляВсехГруппДоступа = Ложь; - ДобавлениеРазрешеноДляВсехГруппДоступа = Ложь; - КонецЕсли; - - Если ПравоЧтение = "Ложь" - Или ТипЗнч(ПравоЧтение) = Тип("Соответствие") - И ПравоЧтение.Количество() = 0 Тогда - - Продолжить; - КонецЕсли; - - Если ПраваГруппыДоступа.ПравоИзменениеБезОграничения - И ПраваГруппыДоступа.ПравоДобавлениеБезОграничения Тогда - - ПравоИзменение = "Истина"; - - ИначеЕсли Не ПраваГруппыДоступа.ПравоИзменение Тогда - ПравоИзменение = "Ложь"; - - ИначеЕсли ПараметрыОбновления.ЕстьОграничениеИзменения Тогда - ПравоИзменение = РассчитанноеУсловиеДляСтрок(Контекст, - ПараметрыОбновления.СтруктураРасчетаПраваИзменение); - - ИначеЕсли БезЗаписиПраваЧтение - Или ПраваГруппыДоступа.ПравоЧтениеБезОграничения Тогда - - ПравоИзменение = РассчитанноеУсловиеДляСтрок(Контекст, - ПараметрыОбновления.СтруктураРасчетаПраваЧтение); - Иначе - ПравоИзменение = "Истина"; - КонецЕсли; - - ПравоДобавление = ?(ПраваГруппыДоступа.ПравоДобавление, ПравоИзменение, "Ложь"); - - Если ПраваГруппыДоступа.ПравоИзменениеБезОграничения Тогда - ПравоИзменение = "Истина"; - КонецЕсли; - - Если ПравоИзменение <> "Истина" Тогда - ИзменениеРазрешеноДляВсехГруппДоступа = Ложь; - КонецЕсли; - Если ПравоДобавление <> "Истина" Тогда - ДобавлениеРазрешеноДляВсехГруппДоступа = Ложь; - КонецЕсли; - - Если Контекст.РассчитыватьПраваПользователей Тогда - ДобавитьПраваПользователейНаКлючДоступа(ПраваНаКлюч, - ПравоЧтение, ПравоИзменение, ПравоДобавление, Контекст); - - ИначеЕсли Не БезЗаписиПраваЧтение Или ПравоИзменение = "Истина" Или ПравоДобавление = "Истина" Тогда - ПраваНаКлюч.ДляГрупп.Вставить(ГруппаДоступа, Новый Структура("ПравоИзменение, ПравоДобавление", - ПравоИзменение = "Истина", ПравоДобавление = "Истина")); - КонецЕсли; - КонецЦикла; - - Если Не ЧтениеРазрешеноДляВсехГруппДоступа - Или ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - И Не ПараметрыОбновления.ЧтениеРазрешеноДляВсехПользователей Тогда - - Возврат ПраваНаКлюч; - КонецЕсли; - - Если ДобавлениеРазрешеноДляВсехГруппДоступа - И ( Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Или ПараметрыОбновления.ИзменениеРазрешеноДляВсехПользователей) Тогда - - ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); - ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, - Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); - - Иначе // ЧтениеРазрешеноДляВсехГруппДоступа. - ТекущиеПраваНаКлюч = ПраваНаКлюч; - ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); - Если Не БезЗаписиПраваЧтение Или ИзменениеРазрешеноДляВсехГруппДоступа Тогда - ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, - Новый Структура("ПравоИзменение, ПравоДобавление", ИзменениеРазрешеноДляВсехГруппДоступа, Ложь)); - КонецЕсли; - ИмяПрава = ?(ИзменениеРазрешеноДляВсехГруппДоступа, "ПравоДобавление", "ПравоИзменение"); - Для Каждого КлючИЗначение Из ТекущиеПраваНаКлюч.ДляГрупп Цикл - Если КлючИЗначение.Значение[ИмяПрава] Тогда - ПраваНаКлюч.ДляГрупп.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЕсли; - КонецЦикла; - Для Каждого КлючИЗначение Из ТекущиеПраваНаКлюч.ДляПользователей Цикл - Если КлючИЗначение.Значение[ИмяПрава] Тогда - ПраваНаКлюч.ДляПользователей.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Возврат ПраваНаКлюч; - -КонецФункции - -// Для процедуры ПраваНаКлючДоступаСписка. -Процедура ДобавитьПраваПользователейНаКлючДоступа(ПраваНаКлюч, ПравоЧтение, ПравоИзменение, ПравоДобавление, Контекст) - - Если ТипЗнч(ПравоИзменение) = Тип("Соответствие") И ПравоИзменение.Количество() = 0 Тогда - ПравоИзменение = "Ложь"; - ПравоДобавление = "Ложь"; - - ИначеЕсли ТипЗнч(ПравоДобавление) = Тип("Соответствие") И ПравоДобавление.Количество() = 0 Тогда - ПравоДобавление = "Ложь"; - КонецЕсли; - - Права = НовыеПрава(ПравоИзменение = "Истина", ПравоДобавление = "Истина"); - - Если ТипЗнч(ПравоЧтение) <> Тип("Соответствие") Тогда - Если Не Контекст.БезЗаписиПраваЧтение Или Права.ПравоИзменение Или Права.ПравоДобавление Тогда - ПраваНаКлюч.ДляГрупп.Вставить(Контекст.ГруппаДоступа, - Новый Структура("ПравоИзменение, ПравоДобавление", - Права.ПравоИзменение, Права.ПравоДобавление)); - КонецЕсли; - Иначе - ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлюч.ДляПользователей, - ПравоЧтение, Права.ПравоИзменение, Права.ПравоДобавление, Контекст.БезЗаписиПраваЧтение); - КонецЕсли; - - Если ТипЗнч(ПравоИзменение) <> Тип("Соответствие") - И ТипЗнч(ПравоДобавление) <> Тип("Соответствие") Тогда - Возврат; - КонецЕсли; - - Право = ?(ТипЗнч(ПравоИзменение) = Тип("Соответствие"), ПравоИзменение, ПравоДобавление); - ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлюч.ДляПользователей, - Право, Истина, ПравоДобавление <> "Ложь", Контекст.БезЗаписиПраваЧтение); - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ПравоИзменение - Булево -// * ПравоДобавление - Булево -// -Функция НовыеПрава(ПравоИзменение, ПравоДобавление) - - Возврат Новый Структура("ПравоИзменение, ПравоДобавление", ПравоИзменение, ПравоДобавление); - -КонецФункции - -// Для процедуры ДобавитьПраваПользователейНаКлючДоступа. -Процедура ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлючДляПользователей, - СоставПользователей, ПравоИзменение, ПравоДобавление, БезЗаписиПраваЧтение) - - Если ПравоИзменение И ПравоДобавление Тогда - Для Каждого КлючИЗначение Из СоставПользователей Цикл - ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, - Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); - КонецЦикла; - - ИначеЕсли Не ПравоИзменение И Не ПравоДобавление Тогда - Если Не БезЗаписиПраваЧтение Тогда - Для Каждого КлючИЗначение Из СоставПользователей Цикл - Права = ПраваНаКлючДляПользователей.Получить(КлючИЗначение.Ключ); - Если Права = Неопределено Тогда - Права = Новый Структура("ПравоИзменение, ПравоДобавление", Ложь, Ложь); - ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, Права); - КонецЕсли; - КонецЦикла; - КонецЕсли; - Иначе - Для Каждого КлючИЗначение Из СоставПользователей Цикл - Права = ПраваНаКлючДляПользователей.Получить(КлючИЗначение.Ключ); // См. НовыеПрава - Если Права = Неопределено Тогда - Права = Новый Структура("ПравоИзменение, ПравоДобавление", - ПравоИзменение, ПравоДобавление); - Иначе - Права.ПравоИзменение = Права.ПравоИзменение Или ПравоИзменение; - Права.ПравоДобавление = Права.ПравоДобавление Или ПравоДобавление; - КонецЕсли; - ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, Права); - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для функций ПраваНаКлючДоступаСписка и РассчитанноеУсловие. -Функция РассчитанноеУсловиеДляСтрок(Контекст, Условие, УзелРеквизитов = Неопределено, ДляЛюбойИзСтрок = Истина, КорневойУзел = Истина) - - Если УзелРеквизитов = Неопределено Тогда - Контекст.Вставить("ОписанияТребуемыхТаблицКлюча", Новый Массив); - Если Условие.Узел = "ДляВсехСтрок" Или Условие.Узел = "ДляОднойИзСтрок" Тогда - Возврат РассчитанноеУсловие(Контекст, Условие, КорневойУзел); - КонецЕсли; - УзелРеквизитов = Условие; - КонецЕсли; - - Если Не ЗначениеЗаполнено(УзелРеквизитов.ТребуемыеРеквизитыТабличныхЧастейКлюча) Тогда - Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", Контекст.ЗначенияТаблицКлюча); - Возврат РассчитанноеУсловие(Контекст, Условие, КорневойУзел); - КонецЕсли; - РеквизитыТаблиц = УзелРеквизитов.ТребуемыеРеквизитыТабличныхЧастейКлюча; - ЗначенияТаблиц = ТекущиеЗначенияТаблицКлюча(Контекст, РеквизитыТаблиц); - ИндексыСтрокТаблиц = Новый Соответствие; - - Контекст.ОписанияТребуемыхТаблицКлюча.Добавить( - Новый Структура("РеквизитыТаблиц, ЗначенияТаблиц, ИндексыСтрокТаблиц", - РеквизитыТаблиц, ЗначенияТаблиц, ИндексыСтрокТаблиц)); - - ТекущиеСтрокиТаблицКлюча = ?(Контекст.Свойство("ТекущиеСтрокиТаблицКлюча"), - Контекст.ТекущиеСтрокиТаблицКлюча, Неопределено); - - Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", Новый Структура); - Для Каждого ОписаниеЗначений Из Контекст.ЗначенияТаблицКлюча Цикл - Если СтрНачинаетсяС(ОписаниеЗначений.Ключ, "Шапка") Тогда - Контекст.ТекущиеСтрокиТаблицКлюча.Вставить(ОписаниеЗначений.Ключ, ОписаниеЗначений.Значение); - КонецЕсли; - КонецЦикла; - - Результат = "Неопределено"; - - Пока Истина Цикл - ИндексИзменен = Ложь; - Для Каждого ОписаниеТаблицы Из РеквизитыТаблиц Цикл - ИмяТаблицыКлюча = ОписаниеТаблицы.Ключ; - ИндексСтроки = ИндексыСтрокТаблиц.Получить(ИмяТаблицыКлюча); - ЗначенияТаблицы = ЗначенияТаблиц[ИмяТаблицыКлюча]; - Если ИндексСтроки = Неопределено Тогда - ИндексСтроки = 0; - Иначе - Если ИндексСтроки >= ЗначенияТаблицы.Количество() - 1 Тогда - Продолжить; - КонецЕсли; - ИндексСтроки = ИндексСтроки + 1; - КонецЕсли; - ИндексИзменен = Истина; - ИндексыСтрокТаблиц.Вставить(ИмяТаблицыКлюча, ИндексСтроки); - Контекст.ТекущиеСтрокиТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицы[ИндексСтроки]); - КонецЦикла; - Если Не ИндексИзменен Тогда - Прервать; - КонецЕсли; - ТекущийРезультат = РассчитанноеУсловие(Контекст, Условие); - Если ТипЗнч(ТекущийРезультат) <> Тип("Соответствие") Тогда - Если ДляЛюбойИзСтрок Тогда - Если ТекущийРезультат = "Истина" Тогда - Результат = "Истина"; - Прервать; - ИначеЕсли ТекущийРезультат = "Ложь" Тогда - Если Результат = "Неопределено" Или Результат = "Пусто" Тогда - Результат = "Ложь"; - КонецЕсли; - ИначеЕсли ТекущийРезультат = "Пусто" Тогда - Если Результат = "Неопределено" Тогда - Результат = "Пусто"; - КонецЕсли; - КонецЕсли; - Иначе - Если ТекущийРезультат = "Ложь" Тогда - Результат = "Ложь"; - Прервать; - ИначеЕсли ТекущийРезультат = "Истина" Тогда - Если Результат = "Неопределено" Или Результат = "Пусто" Тогда - Результат = "Истина"; - КонецЕсли; - ИначеЕсли ТекущийРезультат = "Пусто" Тогда - Если Результат = "Неопределено" Тогда - Результат = "Пусто"; - КонецЕсли; - КонецЕсли; - КонецЕсли; - Иначе - Если Не ДляЛюбойИзСтрок И ТекущийРезультат.Количество() = 0 Тогда - Результат = "Ложь"; - Прервать; - КонецЕсли; - Если ТипЗнч(Результат) = Тип("Строка") Тогда - Результат = ТекущийРезультат; - Иначе - ДобавитьТекущийРезультат(Результат, ТекущийРезультат, ДляЛюбойИзСтрок, Контекст); - КонецЕсли; - КонецЕсли; - КонецЦикла; - - Если Результат = "Неопределено" Тогда - Результат = "Ложь"; - ИначеЕсли КорневойУзел И Результат = "Пусто" Тогда - Результат = "Истина"; - КонецЕсли; - - Контекст.ОписанияТребуемыхТаблицКлюча.Удалить( - Контекст.ОписанияТребуемыхТаблицКлюча.Количество() - 1); - - Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", ТекущиеСтрокиТаблицКлюча); - - Возврат Результат; - -КонецФункции - -// Для функции РассчитанноеУсловиеДляСтрок. -Процедура ДобавитьТекущийРезультат(Результат, ТекущийРезультат, ДляЛюбойИзСтрок, Контекст) - - Если ДляЛюбойИзСтрок Тогда - Для Каждого КлючИЗначение Из ТекущийРезультат Цикл - Результат.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - Иначе - Если Результат.Количество() > ТекущийРезультат.Количество() Тогда - МеньшийРезультат = ТекущийРезультат; - БольшийРезультат = Результат; - Иначе - МеньшийРезультат = Результат; - БольшийРезультат = ТекущийРезультат; - КонецЕсли; - Результат = Новый Соответствие; - ТипГруппыПользователей = Неопределено; - - Для Каждого КлючИЗначение Из МеньшийРезультат Цикл - Участник = КлючИЗначение.Ключ; - Если БольшийРезультат.Получить(Участник) <> Неопределено Тогда - Результат.Вставить(Участник, Истина); - Иначе - Если ТипГруппыПользователей = Неопределено Тогда - ТипГруппыПользователей = Контекст.ТипГруппыПользователей; - ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; - БольшийРезультатПользователиГрупп = ПользователиГрупп(БольшийРезультат, Контекст); - КонецЕсли; - Если ТипЗнч(Участник) = ТипГруппыПользователей Тогда - ПользователиГруппы = ПользователиГруппПользователей.Получить(Участник); - Если ПользователиГруппы = Неопределено Тогда - Продолжить; - КонецЕсли; - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - Если БольшийРезультатПользователиГрупп.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда - Результат.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЕсли; - КонецЦикла; - ИначеЕсли БольшийРезультатПользователиГрупп.Получить(Участник) <> Неопределено Тогда - Результат.Вставить(Участник, Истина); - КонецЕсли; - КонецЕсли; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ДобавитьТекущийРезультат и УстановитьОбратныйРезультат. -Функция ПользователиГрупп(ПользователиИГруппы, Контекст) - - ПользователиГрупп = Новый Соответствие; - - ТипГруппыПользователей = Контекст.ТипГруппыПользователей; - ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; - - Для Каждого КлючИЗначение Из ПользователиИГруппы Цикл - Если ТипЗнч(КлючИЗначение.Ключ) = ТипГруппыПользователей Тогда - ПользователиГруппы = ПользователиГруппПользователей.Получить(КлючИЗначение.Ключ); - Если ПользователиГруппы <> Неопределено Тогда - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - ПользователиГрупп.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЦикла; - КонецЕсли; - КонецЕсли; - КонецЦикла; - - Возврат ПользователиГрупп; - -КонецФункции - -// Для функции РассчитанноеУсловие. -Процедура УстановитьОбратныйРезультат(Результат, Контекст) - - СписокИсключений = Результат; - Результат = Новый Соответствие; - - УчастникиТекущейГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); - Если УчастникиТекущейГруппыДоступа = Неопределено Тогда - Возврат; - КонецЕсли; - - ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; - ТипГруппыПользователей = Контекст.ТипГруппыПользователей; - ТипПользователя = Контекст.ТипПользователя; - - ПользователиИсключаемыхГрупп = ПользователиГрупп(СписокИсключений, Контекст); - - Для Каждого КлючИЗначение Из УчастникиТекущейГруппыДоступа Цикл - Участник = КлючИЗначение.Ключ; - Если СписокИсключений.Получить(Участник) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Если ТипЗнч(Участник) = ТипПользователя Тогда - Если СписокИсключений.Получить(Участник) = Неопределено - И ПользователиИсключаемыхГрупп.Получить(Участник) = Неопределено Тогда - - Результат.Вставить(Участник, Истина); - КонецЕсли; - ИначеЕсли ТипЗнч(Участник) = ТипГруппыПользователей Тогда - ПользователиГруппы = ПользователиГруппПользователей.Получить(Участник); - Если ПользователиГруппы = Неопределено Тогда - Продолжить; - КонецЕсли; - ВсяГруппаБезИсключений = Истина; - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - Если СписокИсключений.Получить(ОписаниеПользователя.Ключ) <> Неопределено - Или ПользователиИсключаемыхГрупп.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда - - ВсяГруппаБезИсключений = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Если ВсяГруппаБезИсключений Тогда - Результат.Вставить(Участник, Истина); - Иначе - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - Если СписокИсключений.Получить(ОписаниеПользователя.Ключ) = Неопределено - И ПользователиИсключаемыхГрупп.Получить(ОписаниеПользователя.Ключ) = Неопределено Тогда - - Результат.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЕсли; - КонецЦикла; - КонецЕсли; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для функции РассчитанноеУсловиеДляСтрок. -// -// Возвращаемое значение: -// Структура из КлючИЗначение: -// * Ключ - Строка - имя таблицы ключа -// * Значение - см. ЗначенияТаблицыКлюча -// -Функция ТекущиеЗначенияТаблицКлюча(Контекст, ТребуемыеРеквизитыТабличныхЧастейКлюча) - - ТекущиеЗначенияТаблицКлюча = Новый Структура; - Для Каждого ОписаниеТаблицы Из ТребуемыеРеквизитыТабличныхЧастейКлюча Цикл - ИмяТаблицыКлюча = ОписаниеТаблицы.Ключ; - Реквизиты = ОписаниеТаблицы.Значение; - ЗначенияТаблицыКлюча = Контекст.ЗначенияТаблицКлюча[ИмяТаблицыКлюча]; - Отбор = Новый Структура; - Для Каждого ТекущееОписание Из Контекст.ОписанияТребуемыхТаблицКлюча Цикл - РеквизитыТаблицы = ТекущееОписание.РеквизитыТаблиц.Получить(ИмяТаблицыКлюча); - ЗначенияТаблицы = ТекущееОписание.ЗначенияТаблиц[ИмяТаблицыКлюча]; - ИндексСтрокиТаблицы = ТекущееОписание.ИндексыСтрокТаблиц.Получить(ИмяТаблицыКлюча); - СтрокаТаблицы = ЗначенияТаблицы[ИндексСтрокиТаблицы]; - Для Каждого ИмяРеквизита Из РеквизитыТаблицы Цикл - Отбор.Вставить(ИмяРеквизита, СтрокаТаблицы[ИмяРеквизита]); - КонецЦикла; - КонецЦикла; - ВсегоРеквизитовТаблицы = Контекст.РеквизитыТаблицКлюча.Получить(ИмяТаблицыКлюча).Количество(); - Если ВсегоРеквизитовТаблицы = Реквизиты.Количество() И Не ЗначениеЗаполнено(Отбор) Тогда - ТекущиеЗначенияТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицыКлюча); - Продолжить; - КонецЕсли; - Строки = ЗначенияТаблицыКлюча; - Если ЗначениеЗаполнено(Отбор) Тогда - Строки = Строки.НайтиСтроки(Отбор); - КонецЕсли; - ЗначенияТаблицы = НовыеЗначенияТаблицыКлюча(); - Для Каждого ИмяРеквизита Из Реквизиты Цикл - ЗначенияТаблицы.Колонки.Добавить(ИмяРеквизита); - КонецЦикла; - Для Каждого Строка Из Строки Цикл - ЗаполнитьЗначенияСвойств(ЗначенияТаблицы.Добавить(), Строка); - КонецЦикла; - Если Реквизиты.Количество() < ВсегоРеквизитовТаблицы Тогда - РеквизитыСтрокой = СтрСоединить(Реквизиты, ", "); - ЗначенияТаблицы.Свернуть(РеквизитыСтрокой); - КонецЕсли; - ТекущиеЗначенияТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицы); - КонецЦикла; - - Возврат ТекущиеЗначенияТаблицКлюча; - -КонецФункции - -// Для функции РассчитанноеУсловиеДляСтрок. -Функция РассчитанноеУсловие(Контекст, Условие, КорневойУзел = Ложь) - - // Проверяемые типы уже учтены. - - Если Условие.Узел = "Поле" Тогда - Значение = Контекст.ТекущиеСтрокиТаблицКлюча[Условие.Таблица][Условие.Реквизит]; - Результат = ?(Значение = Перечисления.ДополнительныеЗначенияДоступа.Истина - Или Значение = Null И Условие.Свойство("ПроверкаЕстьNull"), "Истина", "Ложь"); - - ИначеЕсли Условие.Узел = "Константа" Тогда - Результат = ?(Условие.Значение = Истина, "Истина", - ?(Условие.Значение = "Пусто", "Пусто", "Ложь")); - - ИначеЕсли Условие.Узел = "И" Тогда - - Результат = "Неопределено"; - Для Каждого Аргумент Из Условие.Аргументы Цикл - ТекущийРезультат = РассчитанноеУсловие(Контекст, Аргумент); - Если ТекущийРезультат = "Ложь" Тогда - Результат = "Ложь"; - Прервать; - КонецЕсли; - Если ТекущийРезультат = "Истина" Тогда - Если Результат = "Неопределено" Или Результат = "Пусто" Тогда - Результат = "Истина"; - КонецЕсли; - ИначеЕсли ТекущийРезультат = "Пусто" Тогда - Если Результат = "Неопределено" Тогда - Результат = "Пусто"; - КонецЕсли; - ИначеЕсли ТипЗнч(ТекущийРезультат) = Тип("Соответствие") Тогда - Если ТекущийРезультат.Количество() = 0 Тогда - Результат = "Ложь"; - Прервать; - КонецЕсли; - Если ТипЗнч(Результат) = Тип("Строка") Тогда - Результат = ТекущийРезультат; - Иначе - ДобавитьТекущийРезультат(Результат, ТекущийРезультат, Ложь, Контекст); - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если Результат = "Неопределено" Тогда - Результат = "Ложь"; - КонецЕсли; - - ИначеЕсли Условие.Узел = "Или" Тогда - - Результат = "Неопределено"; - Для Каждого Аргумент Из Условие.Аргументы Цикл - ТекущийРезультат = РассчитанноеУсловие(Контекст, Аргумент); - Если ТекущийРезультат = "Истина" Тогда - Результат = "Истина"; - Прервать; - КонецЕсли; - Если ТекущийРезультат = "Ложь" Тогда - Если Результат = "Неопределено" Или Результат = "Пусто" Тогда - Результат = "Ложь"; - КонецЕсли; - ИначеЕсли ТекущийРезультат = "Пусто" Тогда - Если Результат = "Неопределено" Тогда - Результат = "Пусто"; - КонецЕсли; - ИначеЕсли ТипЗнч(ТекущийРезультат) = Тип("Соответствие") Тогда - Если ТекущийРезультат.Количество() = 0 Тогда - Если Результат = "Неопределено" Тогда - Результат = "Ложь"; - КонецЕсли; - ИначеЕсли ТипЗнч(Результат) = Тип("Строка") Тогда - Результат = ТекущийРезультат; - Иначе - ДобавитьТекущийРезультат(Результат, ТекущийРезультат, Истина, Контекст); - КонецЕсли; - КонецЕсли; - КонецЦикла; - Если Результат = "Неопределено" Тогда - Результат = "Ложь"; - КонецЕсли; - - ИначеЕсли Условие.Узел = "Не" Тогда - Результат = РассчитанноеУсловие(Контекст, Условие.Аргумент); - Если Результат = "Истина" Тогда - Результат = "Ложь"; - ИначеЕсли Результат = "Ложь" Тогда - Результат = "Истина"; - ИначеЕсли ТипЗнч(Результат) = Тип("Соответствие") Тогда - Если Результат.Количество() = 0 Тогда - Результат = "Истина"; - Иначе - УстановитьОбратныйРезультат(Результат, Контекст); - КонецЕсли; - КонецЕсли; - - ИначеЕсли Условие.Узел = "ДляВсехСтрок" - Или Условие.Узел = "ДляОднойИзСтрок" Тогда - - Результат = РассчитанноеУсловиеДляСтрок(Контекст, - Условие.Аргумент, Условие, Условие.Узел = "ДляОднойИзСтрок", Ложь); - - ИначеЕсли Условие.Узел = "Выбор" Тогда - Результат = Неопределено; - Для Каждого Когда Из Условие.Когда Цикл - Если РассчитанноеУсловие(Контекст, Когда.Условие) = "Истина" Тогда - Результат = РассчитанноеУсловие(Контекст, Когда.Значение); - Прервать; - КонецЕсли; - КонецЦикла; - Если Результат = Неопределено Тогда - Результат = РассчитанноеУсловие(Контекст, Условие.Иначе); - КонецЕсли; - - ИначеЕсли Условие.Узел = "ЗначениеРазрешено" - Или Условие.Узел = "ЭтоАвторизованныйПользователь" - Или Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" - Или Условие.Узел = "ЧтениеСпискаРазрешено" - Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда - - Значение = Контекст.ТекущиеСтрокиТаблицКлюча[Условие.Поле.Таблица][Условие.Поле.Реквизит]; - Если Значение = Null Тогда - Значение = Перечисления.ДополнительныеЗначенияДоступа.Null; - ИначеЕсли Значение = Неопределено Тогда - Значение = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; - КонецЕсли; - ОтключеноКакЛожь = Условие.УточненияСравнения.Получить("Отключено") = "Ложь"; - - Если Значение = Перечисления.ДополнительныеЗначенияДоступа.ТипРазрешенный Тогда - Если ОтключеноКакЛожь Тогда - ТекущийРезультат = "Пусто"; - Иначе - ТекущийРезультат = "Истина"; - КонецЕсли; - - ИначеЕсли Значение = Перечисления.ДополнительныеЗначенияДоступа.ТипЗапрещенный Тогда - Если ОтключеноКакЛожь Тогда - ТекущийРезультат = "Пусто"; - Иначе - ТекущийРезультат = "Ложь"; - КонецЕсли; - Иначе - ТекущийРезультат = Неопределено; - Для Каждого УточнениеСравнения Из Условие.УточненияСравнения Цикл - Если УточнениеСравнения.Ключ = "Null" - Или УточнениеСравнения.Ключ = "Неопределено" Тогда - Если Значение = Перечисления.ДополнительныеЗначенияДоступа[УточнениеСравнения.Ключ] Тогда - ТекущийРезультат = УточнениеСравнения.Значение; - Прервать; - КонецЕсли; - ИначеЕсли УточнениеСравнения.Ключ = "ПустаяСсылка" Тогда - Если Значение = Перечисления.ДополнительныеЗначенияДоступа.ПустаяСсылкаЛюбогоТипа - Или Значение.Пустая() Тогда - ТекущийРезультат = УточнениеСравнения.Значение; - Прервать; - КонецЕсли; - ИначеЕсли УточнениеСравнения.Ключ = ТипЗнч(Значение) Тогда - ТекущийРезультат = УточнениеСравнения.Значение; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Если ТекущийРезультат <> Неопределено Тогда - Результат = ТекущийРезультат; - - ИначеЕсли Условие.Узел = "ЗначениеРазрешено" Тогда - Если Значение = Перечисления.ДополнительныеЗначенияДоступа.Null - Или Значение = Перечисления.ДополнительныеЗначенияДоступа.Неопределено Тогда - Если ОтключеноКакЛожь Тогда - Результат = "Пусто"; - Иначе - Результат = "Ложь"; - КонецЕсли; - Иначе - Если Контекст.ЗначенияГруппыДоступа = Неопределено Тогда - ЗначенияОдногоТипа = Неопределено; - Иначе - ТипЗначения = ТипЗнч(Значение); - ЗначенияОдногоТипа = Контекст.ЗначенияГруппыДоступа.Получить(ТипЗначения); - КонецЕсли; - Если ЗначенияОдногоТипа = Неопределено Тогда - Если ОтключеноКакЛожь Тогда - Результат = "Пусто"; - Иначе - Результат = "Истина"; - КонецЕсли; - Иначе - ЗначениеУказано = ЗначенияОдногоТипа.Значения.Получить(Значение) <> Неопределено; - Если Не ЗначениеУказано И ТипЗначения = Контекст.ТипПользователя Тогда - ЗначениеУказано = ЗначениеУказаноВГруппеПользователей(Значение, Контекст); - КонецЕсли; - Результат = "Ложь"; - Если ЗначениеУказано И Не ЗначенияОдногоТипа.ВсеРазрешены - Или Не ЗначениеУказано И ЗначенияОдногоТипа.ВсеРазрешены Тогда - Результат = "Истина"; - - ИначеЕсли ТипЗначения = Контекст.ТипПользователя Тогда - ЗаполнитьРезультатДляПользователя(Результат, Значение, Контекст); - - ИначеЕсли ТипЗначения = Контекст.ТипГруппыПользователей Тогда - ЗаполнитьРезультатДляГруппыПользователей(Результат, Значение, Контекст); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" Тогда - Если ТипЗнч(Значение) = Контекст.ТипПользователя Тогда - ЗаполнитьРезультатДляПользователя(Результат, Значение, Контекст); - Иначе - Результат = "Ложь"; - КонецЕсли; - - ИначеЕсли ТипЗнч(Значение) = Тип("СправочникСсылка.КлючиДоступа") Тогда - ПраваНаСписок = Контекст.ПраваНаСпискиВедущихКлючейДоступа.Получить(Значение); - Если ПраваНаСписок = Неопределено Тогда - Результат = "Ложь"; - Иначе - ПравоИзменение = ПраваНаСписок.ПоГруппамДоступа.Получить(Контекст.ГруппаДоступа); - Если Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение = Неопределено - Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение <> Истина Тогда - Результат = "Ложь"; - - ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" И ПраваНаСписок.ОграничениеЧтенияОтключено - Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПраваНаСписок.ОграничениеОтключено Тогда - - Результат = "Истина"; - Иначе - ПраваНаВедущийКлючДоступа = Контекст.ПраваНаВедущиеКлючиДоступа.Получить(Значение); - Если ПраваНаВедущийКлючДоступа = Неопределено Тогда - Результат = "Ложь"; - - ИначеЕсли Контекст.РассчитыватьПраваПользователей Тогда - Если Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда - - Результат = "Ложь"; - ПроверятьПравоИзменение = Условие.Узел <> "ЧтениеОбъектаРазрешено"; - ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ПустаяГруппаДоступа); - Если ПравоИзменение <> Неопределено - И (Не ПроверятьПравоИзменение Или ПравоИзменение) Тогда - Результат = "Истина"; - Иначе - ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ГруппаДоступа); - Если ПравоИзменение <> Неопределено - И (Не ПроверятьПравоИзменение Или ПравоИзменение) Тогда - Результат = "Истина"; - КонецЕсли; - КонецЕсли; - Если Результат <> "Истина" Тогда - Результат = Новый Соответствие; - Для Каждого КлючИЗначение Из ПраваНаВедущийКлючДоступа Цикл - Если ПроверятьПравоИзменение И Не КлючИЗначение.Значение Тогда - Продолжить; - КонецЕсли; - ЗначениеКлюча = КлючИЗначение.Ключ; - ТипКлюча = ТипЗнч(ЗначениеКлюча); - Если ТипКлюча = Контекст.ТипГруппыДоступа Тогда - Продолжить; - КонецЕсли; - ТекущийРезультат = "Ложь"; - Если ТипКлюча = Контекст.ТипПользователя Тогда - ЗаполнитьРезультатДляПользователя(ТекущийРезультат, ЗначениеКлюча, Контекст); - ИначеЕсли ТипКлюча = Контекст.ТипГруппыПользователей Тогда - ЗаполнитьРезультатДляГруппыПользователей(ТекущийРезультат, ЗначениеКлюча, Контекст); - КонецЕсли; - Если ТекущийРезультат = "Ложь" Тогда - Продолжить; - КонецЕсли; - Для Каждого ОписаниеУчастника Из ТекущийРезультат Цикл - Результат.Вставить(ОписаниеУчастника.Ключ, Истина); - КонецЦикла; - КонецЦикла; - Если Результат.Количество() = 0 Тогда - Результат = "Ложь"; - КонецЕсли; - КонецЕсли; - Иначе - Результат = "Ложь"; - КонецЕсли; - Иначе - ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ГруппаДоступа); - Если Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение <> Неопределено - Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение = Истина Тогда - Результат = "Истина"; - Иначе - Результат = "Ложь"; - КонецЕсли; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - ИначеЕсли Контекст.ТипыВладельцевНастроекПрав.Получить(ТипЗнч(Значение)) <> Неопределено Тогда - ПраваПоВладельцуНастроекПрав = Контекст.ПраваПоВладельцамНастроекПрав.Получить(Значение); - Если ПраваПоВладельцуНастроекПрав = Неопределено Тогда - Результат = "Ложь"; - - ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда - - ПроверятьПравоИзменение = Условие.Узел <> "ЧтениеОбъектаРазрешено"; - Результат = Новый Соответствие; - Для Каждого КлючИЗначение Из ПраваПоВладельцуНастроекПрав Цикл - Если ПроверятьПравоИзменение И Не КлючИЗначение.Значение Тогда - Продолжить; - КонецЕсли; - ЗначениеКлюча = КлючИЗначение.Ключ; - ТипКлюча = ТипЗнч(ЗначениеКлюча); - ТекущийРезультат = "Ложь"; - Если ТипКлюча = Контекст.ТипПользователя Тогда - ЗаполнитьРезультатДляПользователя(ТекущийРезультат, ЗначениеКлюча, Контекст); - ИначеЕсли ТипКлюча = Контекст.ТипГруппыПользователей Тогда - ЗаполнитьРезультатДляГруппыПользователей(ТекущийРезультат, ЗначениеКлюча, Контекст); - КонецЕсли; - Если ТекущийРезультат = "Ложь" Тогда - Продолжить; - КонецЕсли; - Для Каждого ОписаниеУчастника Из ТекущийРезультат Цикл - Результат.Вставить(ОписаниеУчастника.Ключ, Истина); - КонецЦикла; - КонецЦикла; - Если Результат.Количество() = 0 Тогда - Результат = "Ложь"; - КонецЕсли; - Иначе - Результат = "Ложь"; - КонецЕсли; - - Иначе // Проверка прав на список. - ПраваНаВедущийСписок = Контекст.ПраваНаВедущиеСписки.Получить(Значение); - Если ПраваНаВедущийСписок = Неопределено Тогда - ПраваНаВедущийСписок = Контекст.ПраваНаВедущиеСписки.Получить(ТипЗнч(Значение)); - КонецЕсли; - Если ПраваНаВедущийСписок = Неопределено Тогда - Результат = "Ложь"; - Иначе - ПравоИзменение = ПраваНаВедущийСписок.Получить(Контекст.ГруппаДоступа); - Если Условие.Узел = "ЧтениеСпискаРазрешено" И ПравоИзменение <> Неопределено - Или Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение <> Неопределено - Или Условие.Узел = "ИзменениеСпискаРазрешено" И ПравоИзменение = Истина - Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение = Истина Тогда - - Результат = "Истина"; - Иначе - Результат = "Ложь"; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - ИначеЕсли Условие.Узел = "ПравоДоступа" Тогда - Результат = ?(ЕстьПравоДоступаВРоляхПрофиляГруппыДоступа(Условие, Контекст), "Истина", "Ложь"); - - ИначеЕсли Условие.Узел = "РольДоступна" Тогда - Результат = ?(ЕстьРольВПрофилеГруппыДоступа(Условие, Контекст), "Истина", "Ложь"); - - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При вычислении прав на ключ доступа узел не поддерживается ""%1"".'"), - Условие.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если КорневойУзел И Результат = "Пусто" Тогда - Результат = "Истина"; - КонецЕсли; - - Возврат Результат; - -КонецФункции - -// Для функции РассчитанноеУсловие. -Функция ЗначениеУказаноВГруппеПользователей(Пользователь, Контекст) - - УказанныеГруппыПользователей = Контекст.ЗначенияГруппыДоступа.Получить(Контекст.ТипГруппыПользователей); - Если УказанныеГруппыПользователей = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - Для Каждого УказаннаяГруппаПользователей Из УказанныеГруппыПользователей.Значения Цикл - ПользователиГруппы = Контекст.ГруппыПользователейКакЗначенияДоступа.Получить(УказаннаяГруппаПользователей.Ключ); - Если ПользователиГруппы = Неопределено Тогда - Продолжить; - КонецЕсли; - Если ПользователиГруппы.Получить(Пользователь) <> Неопределено Тогда - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для функции РассчитанноеУсловие. -Процедура ЗаполнитьРезультатДляПользователя(Результат, Пользователь, Контекст) - - Результат = "Ложь"; - - УчастникиГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); - Если УчастникиГруппыДоступа = Неопределено Тогда - Возврат; - КонецЕсли; - Если УчастникиГруппыДоступа.Получить(Пользователь) <> Неопределено Тогда - Результат = Новый Соответствие; - Результат.Вставить(Пользователь, Истина); - Возврат; - КонецЕсли; - - ГрупповыеПользователиГруппыДоступа = Контекст.ГрупповыеПользователиГруппДоступа.Получить(Контекст.ГруппаДоступа); - Если ГрупповыеПользователиГруппыДоступа = Неопределено Тогда - Возврат; - КонецЕсли; - - Если ГрупповыеПользователиГруппыДоступа.Получить(Пользователь) <> Неопределено Тогда - Результат = Новый Соответствие; - Результат.Вставить(Пользователь, Истина); - КонецЕсли; - -КонецПроцедуры - -// Для функции РассчитанноеУсловие. -Процедура ЗаполнитьРезультатДляГруппыПользователей(Результат, ГруппаПользователей, Контекст) - - Результат = "Ложь"; - - УчастникиГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); - Если УчастникиГруппыДоступа = Неопределено Тогда - Возврат; - КонецЕсли; - - Если УчастникиГруппыДоступа.Получить(ГруппаПользователей) <> Неопределено Тогда - Результат = Новый Соответствие; - Результат.Вставить(ГруппаПользователей, Истина); - Возврат; - КонецЕсли; - - ПользователиГруппы = Контекст.ПользователиГруппПользователей.Получить(ГруппаПользователей); - Если ПользователиГруппы = Неопределено Тогда - Возврат; - КонецЕсли; - - ГрупповыеПользователиГруппыДоступа = Контекст.ГрупповыеПользователиГруппДоступа.Получить(Контекст.ГруппаДоступа); - Если ГрупповыеПользователиГруппыДоступа = Неопределено Тогда - ГрупповыеПользователиГруппыДоступа = Новый Соответствие; - КонецЕсли; - - Результат = Новый Соответствие; - - Если УчастникиГруппыДоступа.Количество() > ПользователиГруппы.Количество() Тогда - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - Если УчастникиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда - Результат.Вставить(ОписаниеПользователя.Ключ, Истина); - Продолжить; - КонецЕсли; - Если ГрупповыеПользователиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда - Результат.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЕсли; - КонецЦикла; - Иначе - Для Каждого ОписаниеУчастника Из УчастникиГруппыДоступа Цикл - Если ПользователиГруппы.Получить(ОписаниеУчастника.Ключ) <> Неопределено Тогда - Результат.Вставить(ОписаниеУчастника.Ключ, Истина); - КонецЕсли; - КонецЦикла; - Если ГрупповыеПользователиГруппыДоступа.Количество() > ПользователиГруппы.Количество() Тогда - Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл - Если ГрупповыеПользователиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда - Результат.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЕсли; - КонецЦикла; - Иначе - Для Каждого ОписаниеПользователя Из ГрупповыеПользователиГруппыДоступа Цикл - Если ПользователиГруппы.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда - Результат.Вставить(ОписаниеПользователя.Ключ, Истина); - КонецЕсли; - КонецЦикла; - КонецЕсли; - КонецЕсли; - - Если Результат.Количество() = 0 Тогда - Результат = "Ложь"; - КонецЕсли; - -КонецПроцедуры - -// Для функции РассчитанноеУсловие. -Функция ЕстьПравоДоступаВРоляхПрофиляГруппыДоступа(Условие, Контекст) - - ПолноеИмя = Условие.ПолноеИмяОбъектаМетаданных; - Описание = Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Получить(ПолноеИмя); - Если Описание = Неопределено Тогда - Описание = Новый Структура("ОбъектМетаданных, ИмяСтандартногоРеквизита"); - Описание.ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава( - ПолноеИмя, Описание.ИмяСтандартногоРеквизита); - Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Вставить(ПолноеИмя, Описание); - КонецЕсли; - - СтрокаТаблицы = Контекст.ГруппыДоступаПрофилей.Найти(Контекст.ГруппаДоступа, "ГруппаДоступа"); - Если СтрокаТаблицы = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - ПраваПрофиля = Контекст.ПраваПрофилейФункцииПравоДоступа.Получить(СтрокаТаблицы.Профиль); - Если ПраваПрофиля = Неопределено Тогда - ПраваПрофиля = Новый Соответствие; - Контекст.ПраваПрофилейФункцииПравоДоступа.Вставить(СтрокаТаблицы.Профиль, ПраваПрофиля); - КонецЕсли; - - КлючПраваВРоляхПрофиля = ПолноеИмя + "/" + Условие.ИмяПрава; - ЕстьПравоВРоляхПрофиля = ПраваПрофиля.Получить(КлючПраваВРоляхПрофиля); - Если ТипЗнч(ЕстьПравоВРоляхПрофиля) = Тип("Булево") Тогда - Возврат ЕстьПравоВРоляхПрофиля; - КонецЕсли; - - Отбор = Новый Структура("Профиль", СтрокаТаблицы.Профиль); - РолиПрофиля = Контекст.РолиПрофилейГруппДоступа.НайтиСтроки(Отбор); - - ЕстьПравоВРоли = Ложь; - Для Каждого ОписаниеРоли Из РолиПрофиля Цикл - КлючПраваРоли = ОписаниеРоли.ИмяРоли + "/" + ПолноеИмя + "/" + Условие.ИмяПрава; - ЕстьПравоВРоли = Контекст.ПраваРолейФункцииПравоДоступа.Получить(КлючПраваРоли); - Если ЕстьПравоВРоли = Неопределено Тогда - Если ЗначениеЗаполнено(ОписаниеРоли.ИмяРоли) Тогда - ПолноеИмяРоли = "Роль." + ОписаниеРоли.ИмяРоли; - Роль = Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Получить(ПолноеИмяРоли); - Если Роль = Неопределено Тогда - Роль = Метаданные.Роли[ОписаниеРоли.ИмяРоли]; - Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Вставить(ПолноеИмяРоли, Роль); - КонецЕсли; - ЕстьПравоВРоли = ПравоДоступа(Условие.ИмяПрава, Описание.ОбъектМетаданных, Роль, - Описание.ИмяСтандартногоРеквизита); - Иначе - ЕстьПравоВРоли = Ложь; - КонецЕсли; - Контекст.ПраваРолейФункцииПравоДоступа.Вставить(КлючПраваРоли, ЕстьПравоВРоли); - КонецЕсли; - Если ЕстьПравоВРоли Тогда - Прервать; - КонецЕсли; - КонецЦикла; - - ПраваПрофиля.Вставить(КлючПраваВРоляхПрофиля, ЕстьПравоВРоли); - - Возврат ЕстьПравоВРоли; - -КонецФункции - -// Для функции РассчитанноеУсловие. -Функция ЕстьРольВПрофилеГруппыДоступа(Условие, Контекст) - - СтрокаТаблицы = Контекст.ГруппыДоступаПрофилей.Найти(Контекст.ГруппаДоступа, "ГруппаДоступа"); - Если СтрокаТаблицы = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - Отбор = Новый Структура("Профиль,ИмяРолиВерхнийРегистр", СтрокаТаблицы.Профиль, ВРег(Условие.ИмяРоли)); - - Возврат Контекст.РолиПрофилейГруппДоступа.НайтиСтроки(Отбор).Количество() > 0; - -КонецФункции - -// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. -Процедура ОбновитьПраваНаКлючДоступаСписка(КлючДоступа, ПраваНаКлюч, ОписаниеНовыхКлючей, ПараметрыОбновления) - - Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда - ПраваНаКлючДляПользователей = Новый Соответствие; - ТипПользователя = ПараметрыОбновления.ТипПользователя; - Для Каждого КлючИЗначение Из ПраваНаКлюч.ДляПользователей Цикл - Если ТипЗнч(КлючИЗначение.Ключ) = ТипПользователя Тогда - Набор = Справочники.НаборыГруппДоступа.ПолучитьСсылку(КлючИЗначение.Ключ.УникальныйИдентификатор()); - ПраваНаКлючДляПользователей.Вставить(Набор, КлючИЗначение.Значение); - Иначе - ПраваНаКлюч.ДляГрупп.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Блокировка = Новый БлокировкаДанных; - - ЗапросГрупп = Новый Запрос; - ЗапросГрупп.УстановитьПараметр("КлючДоступа", КлючДоступа); - ЗапросГрупп.Текст = - "ВЫБРАТЬ - | КлючиДоступаГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, - | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, - | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление - |ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - |ГДЕ - | КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа - | И &УточнениеПланаЗапроса"; - УстановитьУточнениеПланаЗапроса(ЗапросГрупп.Текст); - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - ЭлементБлокировкиГрупп = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); - ЭлементБлокировкиГрупп.УстановитьЗначение("КлючДоступа", КлючДоступа); - НаборЗаписейГрупп = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); - Если Не ПакетныйРежим Тогда - НаборЗаписейГрупп.Отбор.КлючДоступа.Установить(КлючДоступа); - КонецЕсли; - - ЗапросНаборовГруппДоступа = Новый Запрос; - ЗапросНаборовГруппДоступа.УстановитьПараметр("КлючДоступа", КлючДоступа); - ЗапросНаборовГруппДоступа.УстановитьПараметр("РазрешенныйПустойНабор", - УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); - - ЗапросНаборовГруппДоступа.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа(); - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", КлючДоступа); - НаборЗаписейНаборовГруппДоступа = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); - Если Не ПакетныйРежим Тогда - НаборЗаписейНаборовГруппДоступа.Отбор.КлючДоступа.Установить(КлючДоступа); - КонецЕсли; - - Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("КлючДоступа", КлючДоступа); - - Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда - Запрос.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляПользователей(); - ИмяПоляВладельцаПрав = "Пользователь"; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); - Иначе - Запрос.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляВнешнихПользователей(); - ИмяПоляВладельцаПрав = "ВнешнийПользователь"; - ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); - КонецЕсли; - ЭлементБлокировки.УстановитьЗначение("КлючДоступа", КлючДоступа); - Если Не ПакетныйРежим Тогда - НаборЗаписей.Отбор.КлючДоступа.Установить(КлючДоступа); - КонецЕсли; - КонецЕсли; - - Если ОписаниеНовыхКлючей <> Неопределено Тогда - ОписаниеНовогоКлюча = ОписаниеНовыхКлючей.ОписанияКлючейПоСсылке.Получить(КлючДоступа); - КлючДоступаОбъект = ОписаниеНовогоКлюча.КлючДоступаОбъект; // СправочникОбъект.КлючиДоступа - ЭлементБлокировкиКлюча = Блокировка.Добавить("Справочник.КлючиДоступа"); - ЭлементБлокировкиКлюча.УстановитьЗначение("Хеш", КлючДоступаОбъект.Хеш); - ЭлементБлокировкиКлюча.УстановитьЗначение("Список", КлючДоступаОбъект.Список); - ЭлементБлокировкиКлюча.УстановитьЗначение("ДляВнешнихПользователей", КлючДоступаОбъект.ДляВнешнихПользователей); - ЭлементБлокировкиКлюча.УстановитьЗначение("СоставПолей", КлючДоступаОбъект.СоставПолей); - КонецЕсли; - - ОбновлениеВручную = ПараметрыОбновления.Свойство("ОбновитьПраваНаКлючи") - И ПараметрыОбновления.ОбновитьПраваНаКлючи; - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - Если ОписаниеНовыхКлючей <> Неопределено Тогда - ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); - КонецЕсли; - ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); - ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; - КонецЕсли; - - НачатьТранзакцию(); - Попытка - ПередБлокировкойДанных(ПараметрыОбновления); - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); - КонецЕсли; - Блокировка.Заблокировать(); - ПослеБлокировкиДанных(ПараметрыОбновления); - - ЕстьИзмененияПрав = Ложь; - - Если ОписаниеНовыхКлючей = Неопределено - Или Не НовыйКлючДоступаУжеСуществует(ОписаниеНовыхКлючей, ОписаниеНовогоКлюча, ПараметрыОбновления) Тогда - - Если ОписаниеНовыхКлючей <> Неопределено Тогда - ПередЗаписьюНовогоКлюча(ПараметрыОбновления); - КлючДоступаОбъект.Записать(); - ПослеЗаписиНовогоКлюча(ПараметрыОбновления); - КонецЕсли; - - ПередЗапросомПравГруппДоступа(ПараметрыОбновления); - РезультатЗапросаГрупп = ЗапросГрупп.Выполнить(); - ПослеЗапросаПравГруппДоступа(ПараметрыОбновления); - - ЕстьИзменения = Новый Структура("ПраваГруппДоступа, ПраваГруппПользователей", Ложь, Ложь); - ОбновитьИсходныеПраваГруппНаКлючДоступа(РезультатЗапросаГрупп, НаборЗаписейГрупп, "ГруппаДоступа", - КлючДоступа, ПраваНаКлюч.ДляГрупп, ПараметрыОбновления, ЕстьИзменения); - - ЕстьИзмененияПрав = ЕстьИзменения.ПраваГруппДоступа Или ЕстьИзменения.ПраваГруппПользователей; - - Если ЕстьИзменения.ПраваГруппДоступа Или ОбновлениеВручную Тогда - ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления); - РезультатЗапросаНаборовГруппДоступа = ЗапросНаборовГруппДоступа.Выполнить(); - ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления); - ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаНаборовГруппДоступа, - НаборЗаписейНаборовГруппДоступа, "НаборГруппДоступа", КлючДоступа, , ПараметрыОбновления); - КонецЕсли; - - Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда - ЗапросыПакета = СтрРазделить(Запрос.Текст, ";", Ложь); - Если ЕстьИзменения.ПраваГруппПользователей Или ОбновлениеВручную Тогда - Запрос.Текст = ЗапросыПакета[1]; - ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления); - РезультатЗапроса = Запрос.Выполнить(); - ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления); - ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапроса, - НаборЗаписей, ИмяПоляВладельцаПрав, КлючДоступа, , ПараметрыОбновления); - НаборЗаписей.Очистить(); - КонецЕсли; - Запрос.Текст = ЗапросыПакета[0]; - ПередЗапросомПравПользователей(ПараметрыОбновления); - РезультатЗапросаПользователей = Запрос.Выполнить(); - ПослеЗапросаПравПользователей(ПараметрыОбновления); - ОбновитьИсходныеПраваПользователейНаКлючДоступа(РезультатЗапросаПользователей, НаборЗаписей, - ИмяПоляВладельцаПрав, КлючДоступа, ПраваНаКлючДляПользователей, ЕстьИзмененияПрав, ПараметрыОбновления); - КонецЕсли; - - Если ОписаниеНовыхКлючей = Неопределено - И ЕстьИзмененияПрав - И ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа.Количество() > 0 Тогда - - ПередПланированиемОбновления(ПараметрыОбновления); - ЗапланироватьОбновлениеПользователейКлючейДоступа(ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа, - "ОбновитьПраваНаКлючДоступаСписка", - Не ПараметрыОбновления.ДляВнешнихПользователей, - ПараметрыОбновления.ДляВнешнихПользователей, , - Новый Структура("ПоКлючамДоступа", КлючДоступа)); - ПослеПланированияОбновления(ПараметрыОбновления); - КонецЕсли; - КонецЕсли; - - // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, - // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), - // а в режиме анализа производительности последствия учитываются и не являются критичными. - ПередФиксациейТранзакции(ПараметрыОбновления); - ЗафиксироватьТранзакцию(); - ПослеФиксацииТранзакции(ПараметрыОбновления); - // АПК:330-вкл. - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - - Если ЕстьИзмененияПрав И ПараметрыОбновления.Свойство("ЕстьИзмененияПрав") Тогда - ПараметрыОбновления.ЕстьИзмененияПрав = Истина; - КонецЕсли; - -КонецПроцедуры - -// Для процедур ОбновитьПраваНаКлючДоступаСписка, ОбновитьГруппыДоступаРазрешенногоКлючаДоступа. -Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа() - - ТекстЗапроса = - "ВЫБРАТЬ - | ВсеСтроки.НаборГруппДоступа КАК НаборГруппДоступа, - | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, - | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | (ВЫБРАТЬ - | ГруппыВходящиеВНаборы.Ссылка КАК НаборГруппДоступа, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы - | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) - | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) - | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) - | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) - | И (&УточнениеПланаЗапроса) - | - | СГРУППИРОВАТЬ ПО - | ГруппыВходящиеВНаборы.Ссылка - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | &РазрешенныйПустойНабор, - | КлючиДоступаГруппДоступа.ПравоИзменение, - | КлючиДоступаГруппДоступа.ПравоДобавление, - | 1 - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ГДЕ - | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) - | И КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.НаборГруппДоступа, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные - | ГДЕ - | СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.НаборГруппДоступа, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки"; - - УстановитьУточнениеПланаЗапроса(ТекстЗапроса); - - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедур ОбновитьПраваНаКлючДоступаСписка. -Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляПользователей() - - ТекстЗапроса = - "ВЫБРАТЬ - | КлючиДоступаПользователей.Пользователь КАК Пользователь, - | КлючиДоступаПользователей.ПравоИзменение КАК ПравоИзменение, - | КлючиДоступаПользователей.ПравоДобавление КАК ПравоДобавление, - | КлючиДоступаПользователей.ЭтоПраваНабораГрупп КАК ЭтоПраваНабораГрупп - |ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей - |ГДЕ - | КлючиДоступаПользователей.КлючДоступа = &КлючДоступа - | И НЕ КлючиДоступаПользователей.ЭтоПраваНабораГрупп - | И &УточнениеПланаЗапроса - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ВсеСтроки.Пользователь КАК Пользователь, - | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, - | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, - | ИСТИНА КАК ЭтоПраваНабораГрупп, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | (ВЫБРАТЬ - | ГруппыВходящиеВНаборы.Ссылка КАК Пользователь, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы - | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) - | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыПользователей)) - | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыПользователей)) - | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) - | И (&УточнениеПланаЗапроса) - | - | СГРУППИРОВАТЬ ПО - | ГруппыВходящиеВНаборы.Ссылка - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.Пользователь, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК СтарыеДанные - | ГДЕ - | СтарыеДанные.ЭтоПраваНабораГрупп - | И СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.Пользователь, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки"; - - УстановитьУточнениеПланаЗапроса(ТекстЗапроса); - - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедур ОбновитьПраваНаКлючДоступаСписка. -Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляВнешнихПользователей() - - ТекстЗапроса = - "ВЫБРАТЬ - | КлючиДоступаВнешнихПользователей.ВнешнийПользователь КАК ВнешнийПользователь, - | КлючиДоступаВнешнихПользователей.ПравоИзменение КАК ПравоИзменение, - | КлючиДоступаВнешнихПользователей.ПравоДобавление КАК ПравоДобавление, - | КлючиДоступаВнешнихПользователей.ЭтоПраваНабораГрупп КАК ЭтоПраваНабораГрупп - |ИЗ - | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей - |ГДЕ - | КлючиДоступаВнешнихПользователей.КлючДоступа = &КлючДоступа - | И НЕ КлючиДоступаВнешнихПользователей.ЭтоПраваНабораГрупп - | И &УточнениеПланаЗапроса - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ВсеСтроки.ВнешнийПользователь КАК ВнешнийПользователь, - | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, - | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, - | ИСТИНА КАК ЭтоПраваНабораГрупп, - | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки - |ИЗ - | (ВЫБРАТЬ - | ГруппыВходящиеВНаборы.Ссылка КАК ВнешнийПользователь, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, - | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, - | 1 КАК ВидИзмененияСтроки - | ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы - | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) - | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыВнешнихПользователей)) - | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыВнешнихПользователей)) - | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) - | И (&УточнениеПланаЗапроса) - | - | СГРУППИРОВАТЬ ПО - | ГруппыВходящиеВНаборы.Ссылка - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | СтарыеДанные.ВнешнийПользователь, - | СтарыеДанные.ПравоИзменение, - | СтарыеДанные.ПравоДобавление, - | -1 - | ИЗ - | РегистрСведений.КлючиДоступаВнешнихПользователей КАК СтарыеДанные - | ГДЕ - | СтарыеДанные.ЭтоПраваНабораГрупп - | И СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки - | - |СГРУППИРОВАТЬ ПО - | ВсеСтроки.ВнешнийПользователь, - | ВсеСтроки.ПравоИзменение, - | ВсеСтроки.ПравоДобавление - | - |ИМЕЮЩИЕ - | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 - | - |УПОРЯДОЧИТЬ ПО - | ВидИзмененияСтроки"; - - УстановитьУточнениеПланаЗапроса(ТекстЗапроса); - - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедуры ОбновитьПраваНаКлючДоступаСписка. -Функция НовыйКлючДоступаУжеСуществует(ОписаниеНовыхКлючей, ОписаниеНовогоКлюча, ПараметрыОбновления) - - ЗапросСуществованияКлючей = ОписаниеНовыхКлючей.ЗапросСуществованияКлючей; - ЗапросСуществованияКлючей.УстановитьПараметр("Хеш", ОписаниеНовогоКлюча.КлючДоступаОбъект.Хеш); - - Если ЗапросСуществованияКлючей.Выполнить().Пустой() Тогда - Возврат Ложь; - КонецЕсли; - - ЗапросЗначенийКлючей = ОписаниеНовыхКлючей.ЗапросЗначенийКлючей; - ЗапросЗначенийКлючей.УстановитьПараметр("Хеши", ОписаниеНовогоКлюча.КлючДоступаОбъект.Хеш); - - РезультатыЗапросаЗначенийКлючей = ЗапросЗначенийКлючей.ВыполнитьПакет(); - - ТаблицыКлюча = ПараметрыОбновления.ТаблицыКлюча; - КлючиЗначенийСтрокКлючей = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийКлючей, - ?(Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) - Или СтрНачинаетсяС(ТаблицыКлюча[0], "Шапка"), 0, 1), - ТаблицыКлюча); - - Выборка = РезультатыЗапросаЗначенийКлючей[0].Выбрать(); - - Пока Выборка.Следующий() Цикл - Ссылка = Выборка.ТекущаяСсылка; // СправочникСсылка.КлючиДоступа - ОписаниеКлючейЗначений = КлючиЗначенийСтрокКлючей.Получить(Ссылка); - СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); - Если ОписаниеНовогоКлюча.СтрокаДляХеша = СтрокаДляХеша Тогда - ОписаниеНовогоКлюча.КлючДоступаОбъект = Новый Структура("Ссылка", Ссылка); - НеИспользуетсяС = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "НеИспользуетсяС"); - Если ЗначениеЗаполнено(НеИспользуетсяС) Тогда - Объект = СлужебныйЭлемент(Неопределено, Ссылка); - Объект.НеИспользуетсяС = '00010101'; - Объект.Записать(); - КонецЕсли; - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для процедуры ОбновитьПраваНаКлючДоступаСписка. -Процедура ОбновитьИсходныеПраваГруппНаКлючДоступа(РезультатЗапроса, НаборЗаписей, ИмяПоляВладельцаПрав, - КлючДоступа, ПраваНаКлюч, ПараметрыОбновления, ЕстьИзменения) - - Выборка = РезультатЗапроса.Выбрать(); - ТипГруппыДоступа = ПараметрыОбновления.ТипГруппыДоступа; - ЕстьИзмененияПравГруппДоступа = Ложь; - ЕстьИзмененияПравГруппПользователей = Ложь; - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - КоличествоЗаписанных = 0; - ПередЗаписьюСтрок(ПараметрыОбновления); - - Пока Выборка.Следующий() Цикл - ВладелецПрав = Выборка[ИмяПоляВладельцаПрав]; - Права = ПраваНаКлюч.Получить(ВладелецПрав); // См. НовыеПрава - Если Права = Неопределено Тогда - Если ПакетныйРежим Тогда - СтараяЗапись = НаборЗаписей.Добавить(); - СтараяЗапись.КлючДоступа = КлючДоступа; - СтараяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; - Иначе - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора - ЭлементОтбора.Установить(ВладелецПрав); - НаборЗаписей.Записать(); - КонецЕсли; - Если ТипЗнч(ВладелецПрав) = ТипГруппыДоступа Тогда - ЕстьИзмененияПравГруппДоступа = Истина; - Иначе - ЕстьИзмененияПравГруппПользователей = Истина; - КонецЕсли; - ИначеЕсли Выборка.ПравоИзменение = Права.ПравоИзменение - И Выборка.ПравоДобавление = Права.ПравоДобавление Тогда - ПраваНаКлюч.Вставить(ВладелецПрав, Null); - КонецЕсли; - КонецЦикла; - - Если Не ПакетныйРежим Тогда - ОднаЗапись = НаборЗаписей.Добавить(); - ОднаЗапись.КлючДоступа = КлючДоступа; - - ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимУдаления); - НаборЗаписей.Очистить(); - КонецЕсли; - - Для Каждого ОписаниеПрав Из ПраваНаКлюч Цикл - Права = ОписаниеПрав.Значение; // См. НовыеПрава - Если Права = Null Тогда - Продолжить; - КонецЕсли; - ВладелецПрав = ОписаниеПрав.Ключ; - Если ПакетныйРежим Тогда - НоваяЗапись = НаборЗаписей.Добавить(); - НоваяЗапись.КлючДоступа = КлючДоступа; - НоваяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; - НоваяЗапись.ПравоИзменение = Права.ПравоИзменение; - НоваяЗапись.ПравоДобавление = Права.ПравоДобавление; - Иначе - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора - ЭлементОтбора.Установить(ВладелецПрав); - ОднаЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; - ОднаЗапись.ПравоИзменение = Права.ПравоИзменение; - ОднаЗапись.ПравоДобавление = Права.ПравоДобавление; - НаборЗаписей.Записать(); - КонецЕсли; - Если ТипЗнч(ВладелецПрав) = ТипГруппыДоступа Тогда - ЕстьИзмененияПравГруппДоступа = Истина; - Иначе - ЕстьИзмененияПравГруппПользователей = Истина; - КонецЕсли; - КоличествоЗаписанных = КоличествоЗаписанных + 1; - КонецЦикла; - - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимСлияния); - КонецЕсли; - - ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); - - ЕстьИзменения.ПраваГруппДоступа = ЕстьИзмененияПравГруппДоступа; - ЕстьИзменения.ПраваГруппПользователей = ЕстьИзмененияПравГруппПользователей; - -КонецПроцедуры - -// Для процедуры ОбновитьПраваНаКлючДоступаСписка. -Процедура ОбновитьИсходныеПраваПользователейНаКлючДоступа(РезультатЗапроса, НаборЗаписей, - ИмяПоляВладельцаПрав, КлючДоступа, ПраваНаКлюч, ЕстьИзмененияПрав, ПараметрыОбновления) - - Выборка = РезультатЗапроса.Выбрать(); - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - КоличествоЗаписанных = 0; - ПередЗаписьюСтрок(ПараметрыОбновления); - - Пока Выборка.Следующий() Цикл - ВладелецПрав = Выборка[ИмяПоляВладельцаПрав]; - Права = ПраваНаКлюч.Получить(ВладелецПрав); // См. НовыеПрава - Если Права = Неопределено Тогда - Если ПакетныйРежим Тогда - СтараяЗапись = НаборЗаписей.Добавить(); - СтараяЗапись.КлючДоступа = КлючДоступа; - СтараяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; - Иначе - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора - ЭлементОтбора.Установить(ВладелецПрав); - НаборЗаписей.Записать(); - КонецЕсли; - ЕстьИзмененияПрав = Истина; - ИначеЕсли Выборка.ПравоИзменение = Права.ПравоИзменение - И Выборка.ПравоДобавление = Права.ПравоДобавление - И Выборка.ЭтоПраваНабораГрупп = Ложь Тогда - ПраваНаКлюч.Вставить(ВладелецПрав, Null); - КонецЕсли; - КонецЦикла; - - Если Не ПакетныйРежим Тогда - ОднаЗапись = НаборЗаписей.Добавить(); - ОднаЗапись.КлючДоступа = КлючДоступа; - - ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимУдаления); - НаборЗаписей.Очистить(); - КонецЕсли; - - Для Каждого ОписаниеПрав Из ПраваНаКлюч Цикл - Права = ОписаниеПрав.Значение; // См. НовыеПрава - Если Права = Null Тогда - Продолжить; - КонецЕсли; - ВладелецПрав = ОписаниеПрав.Ключ; - Если ПакетныйРежим Тогда - НоваяЗапись = НаборЗаписей.Добавить(); - НоваяЗапись.КлючДоступа = КлючДоступа; - НоваяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; - НоваяЗапись.ПравоИзменение = Права.ПравоИзменение; - НоваяЗапись.ПравоДобавление = Права.ПравоДобавление; - НоваяЗапись.ЭтоПраваНабораГрупп = Ложь; - Иначе - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора - ЭлементОтбора.Установить(ВладелецПрав); - ОднаЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; - ОднаЗапись.ПравоИзменение = Права.ПравоИзменение; - ОднаЗапись.ПравоДобавление = Права.ПравоДобавление; - ОднаЗапись.ЭтоПраваНабораГрупп = Ложь; - НаборЗаписей.Записать(); - КонецЕсли; - ЕстьИзмененияПрав = Истина; - КоличествоЗаписанных = КоличествоЗаписанных + 1; - КонецЦикла; - - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимСлияния); - КонецЕсли; - - ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); - -КонецПроцедуры - -// Для процедуры ОбновитьПраваНаКлючДоступаСписка. -Процедура ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапроса, НаборЗаписей, ИмяПоляВладельцаПрав, - КлючДоступа, ЕстьИзменения = Ложь, ПараметрыОбновления = Неопределено) - - Выборка = РезультатЗапроса.Выбрать(); - УдалениеЗавершено = Ложь; - - РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); - РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); - ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; - - КоличествоЗаписанных = 0; - ПередЗаписьюСтрок(ПараметрыОбновления); - - Пока Выборка.Следующий() Цикл - Если Не ПакетныйРежим Тогда - ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора - ЭлементОтбора.Установить(Выборка[ИмяПоляВладельцаПрав]); - КонецЕсли; - Если Не УдалениеЗавершено И Выборка.ВидИзмененияСтроки = 1 Тогда - УдалениеЗавершено = Истина; - Если Не ПакетныйРежим Тогда - ОднаЗапись = НаборЗаписей.Добавить(); - ОднаЗапись.КлючДоступа = КлючДоступа; - ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(РежимУдаления); - НаборЗаписей.Очистить(); - КонецЕсли; - КонецЕсли; - Если Не ПакетныйРежим Тогда - Если УдалениеЗавершено Тогда - ЗаполнитьЗначенияСвойств(ОднаЗапись, Выборка); - КонецЕсли; - НаборЗаписей.Записать(); - Иначе - Запись = НаборЗаписей.Добавить(); - Запись.КлючДоступа = КлючДоступа; - ЗаполнитьЗначенияСвойств(Запись, Выборка); - КонецЕсли; - ЕстьИзменения = Истина; - КоличествоЗаписанных = КоличествоЗаписанных + 1; - КонецЦикла; - - Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда - НаборЗаписей.Записать(?(УдалениеЗавершено, РежимСлияния, РежимУдаления)); - КонецЕсли; - - ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); - -КонецПроцедуры - -// Создает служебный элемент справочника, который не участвует в подписках на события. -Функция СлужебныйЭлемент(МенеджерСправочника, Ссылка = Неопределено) - - Если Ссылка = Неопределено Тогда - ЭлементСправочника = МенеджерСправочника.СоздатьЭлемент(); - Иначе - ЭлементСправочника = Ссылка.ПолучитьОбъект(); - Если ЭлементСправочника = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - КонецЕсли; - - ЭлементСправочника.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); - ЭлементСправочника.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); - ЭлементСправочника.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; - ЭлементСправочника.ОбменДанными.Загрузка = Истина; - - Возврат ЭлементСправочника; - -КонецФункции - -// Создает набор записей служебного регистра, который не участвует в подписках на события. -Функция СлужебныйНаборЗаписей(МенеджерРегистра) - - НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей(); - НаборЗаписей.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); - НаборЗаписей.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); - НаборЗаписей.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; - НаборЗаписей.ОбменДанными.Загрузка = Истина; - - Возврат НаборЗаписей; - -КонецФункции - -// Создает менеджер значения служебной константы, которая не участвует в подписках на события. -Функция СлужебныйМенеджерЗначения(МенеджерКонстанты) - - МенеджерЗначения = МенеджерКонстанты.СоздатьМенеджерЗначения(); - МенеджерЗначения.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); - МенеджерЗначения.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); - МенеджерЗначения.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; - МенеджерЗначения.ОбменДанными.Загрузка = Истина; - - Возврат МенеджерЗначения; - -КонецФункции - -// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступа. -Процедура ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале(Списки, ПараметрыПланирования) - - КомментарийДляЖурнала = НСтр("ru = 'Источник'", ОбщегоНазначения.КодОсновногоЯзыка()) - + ": " + ПараметрыПланирования.Описание + Символы.ПС; - - Если Списки.Количество() > 1 Тогда - КомментарийДляЖурнала = КомментарийДляЖурнала - + НСтр("ru = 'Списки'", ОбщегоНазначения.КодОсновногоЯзыка()) + ":" - + Символы.ПС + Символы.Таб + СтрСоединить(Списки, Символы.ПС + Символы.Таб); - Иначе - КомментарийДляЖурнала = КомментарийДляЖурнала - + НСтр("ru = 'Список'", ОбщегоНазначения.КодОсновногоЯзыка()); - - КомментарийДляЖурнала = КомментарийДляЖурнала + " = " + Списки[0]; - КонецЕсли; - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоТочечноеЗадание" - + " = " + ?(ПараметрыПланирования.Свойство("ЭтоТочечноеЗадание"), "Да", "Нет"); - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "КлючиДоступаКДанным" - + " = " + ?(ПараметрыПланирования.КлючиДоступаКДанным, "Да", "Нет"); - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "РазрешенныеКлючиДоступа" - + " = " + ?(ПараметрыПланирования.РазрешенныеКлючиДоступа, "Да", "Нет"); - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ДляПользователей" - + " = " + ?(ПараметрыПланирования.ДляПользователей, "Да", "Нет"); - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ДляВнешнихПользователей" - + " = " + ?(ПараметрыПланирования.ДляВнешнихПользователей, "Да", "Нет"); - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоПродолжениеОбновления" - + " = " + ?(ПараметрыПланирования.ЭтоПродолжениеОбновления, "Да", "Нет"); - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоОбработкаУстаревшихЭлементов" - + " = " + ?(ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов, "Да", "Нет"); - - ВедущийОбъект = Неопределено; - ОписаниеВедущегоОбъекта = ПараметрыПланирования.ВедущийОбъект; // См. ОписаниеВедущегоОбъекта - - Если ТипЗнч(ОписаниеВедущегоОбъекта) = Тип("Структура") Тогда - Если ОписаниеВедущегоОбъекта.Свойство("ПоЗначениямПолей") Тогда - Указатели = ОписаниеВедущегоОбъекта.ПоЗначениямПолей.Описание; - ВедущийОбъект = "ПоЗначениямПолей"; - ИначеЕсли ОписаниеВедущегоОбъекта.Свойство("ПоКлючамДоступа") Тогда - Указатели = ОписаниеВедущегоОбъекта.ПоКлючамДоступа; - ВедущийОбъект = "ПоКлючамДоступа"; - ИначеЕсли ОписаниеВедущегоОбъекта.Свойство("ПоЗначениямСГруппами") Тогда - Указатели = ОписаниеВедущегоОбъекта.ПоЗначениямСГруппами; - ВедущийОбъект = "ПоЗначениямСГруппами"; - КонецЕсли; - Если ВедущийОбъект <> Неопределено Тогда - Если ТипЗнч(Указатели) = Тип("Массив") И Указатели.Количество() > 1 Тогда - ВедущийОбъект = ВедущийОбъект + ":"; - Для Каждого Указатель Из Указатели Цикл - ВедущийОбъект = ВедущийОбъект + Символы.ПС + """" + Строка(Указатель) + """ " - + ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования); - КонецЦикла; - Иначе - Указатель = ?(ТипЗнч(Указатели) = Тип("Массив"), Указатели[0], Указатели); - ВедущийОбъект = ВедущийОбъект + ": """ + Строка(Указатель) + """ " - + ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования); - КонецЕсли; - КонецЕсли; - Если ОписаниеВедущегоОбъекта.Свойство("ПоДаннымКэшаРасчетаПрав") Тогда - ВедущийОбъект = "ПоДаннымКэшаРасчетаПрав" + ": """ - + ОписаниеВедущегоОбъекта.ПоДаннымКэшаРасчетаПрав; - КонецЕсли; - КонецЕсли; - - Попытка - ВызватьИсключение НСтр("ru = 'Стек вызовов'"); - Исключение - СтекВызовов = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()); - КонецПопытки; - - КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + Символы.ПС + СтекВызовов; - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Показатели.Планирование обновления доступа'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, , - ВедущийОбъект, - КомментарийДляЖурнала, - ?(ТранзакцияАктивна(), РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная, Неопределено)); - -КонецПроцедуры - -// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале. -Функция ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования) - - Если ПараметрыПланирования.Свойство("ТиповСсылокВедущихОбъектов") Тогда - ТипыСсылок = ПараметрыПланирования.ТиповСсылокВедущихОбъектов; - Иначе - ТипыСсылок = УправлениеДоступомСлужебныйПовтИсп.ТиповСсылокВедущихОбъектов(); - ПараметрыПланирования.Вставить("ТиповСсылокВедущихОбъектов", ТипыСсылок); - КонецЕсли; - - Если ТипыСсылок.Получить(ТипЗнч(Указатель)) <> Неопределено Тогда - Возврат ПолучитьНавигационнуюСсылку(Указатель); - КонецЕсли; - - Описание = ""; - Для Каждого ЭлементОтбора Из Указатель Цикл - Если Не ЭлементОтбора.Использование Тогда - Продолжить; - КонецЕсли; - Если ТипыСсылок.Получить(ТипЗнч(ЭлементОтбора.Значение)) <> Неопределено Тогда - ОписаниеЗначения = ПолучитьНавигационнуюСсылку(ЭлементОтбора.Значение); - ИначеЕсли ТипЗнч(ЭлементОтбора.Значение) = Тип("Неопределено") Тогда - ОписаниеЗначения = НСтр("ru = 'Неопределено'"); - Иначе - ОписаниеЗначения = Формат(ЭлементОтбора.Значение, "ЧН=0; ДП='01.01.0001 00:00:00'"); - КонецЕсли; - Описание = Описание + ?(Описание = "", "", ", ") - + ЭлементОтбора.Имя + " = " + ОписаниеЗначения; - КонецЦикла; - - Возврат Описание; - -КонецФункции - -// Для вызова из мест планирования обновления доступа. -Процедура ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования, ВсеСписки = Ложь) - - Если Не РегистрироватьПоказателиПланированияОбновленияДоступа() - Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда - Возврат; - КонецЕсли; - - Если ПараметрыПланирования = Неопределено Тогда - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); - КонецЕсли; - - Списки = Новый Массив; - - Если Не ВсеСписки Тогда - Если ПараметрыПланирования.ИдентификаторыВсехСписков <> Неопределено Тогда - ВсеПолныеИменаПоИдентификаторам = Новый Соответствие; - Для Каждого КлючИЗначение Из ПараметрыПланирования.ИдентификаторыВсехСписков Цикл - ВсеПолныеИменаПоИдентификаторам.Вставить(КлючИЗначение.Значение, КлючИЗначение.Ключ); - КонецЦикла; - КонецЕсли; - Для Каждого ОписаниеСписка Из СпискиПоИдентификаторам Цикл - Если ЗначениеЗаполнено(ОписаниеСписка.Значение) Тогда - Списки.Добавить(ОписаниеСписка.Значение); - Иначе - Списки.Добавить(ПолноеИмяСписка(ОписаниеСписка.Ключ, ВсеПолныеИменаПоИдентификаторам)); - КонецЕсли; - КонецЦикла; - Иначе - Списки.Добавить("Все"); - КонецЕсли; - - ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале(Списки, ПараметрыПланирования); - -КонецПроцедуры - -// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступа. -Функция ПолноеИмяСписка(ОписаниеСписка, ВсеПолныеИменаПоИдентификаторам) - - Если ТипЗнч(ОписаниеСписка) = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") - Или ТипЗнч(ОписаниеСписка) = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда - - Если ВсеПолныеИменаПоИдентификаторам = Неопределено Тогда - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(ОписаниеСписка, Ложь); - Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда - Возврат ОбъектМетаданных.ПолноеИмя(); - КонецЕсли; - Иначе - ПолноеИмя = ВсеПолныеИменаПоИдентификаторам.Получить(ОписаниеСписка); - КонецЕсли; - - Если ПолноеИмя <> Неопределено Тогда - Возврат ПолноеИмя; - Иначе - Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ОписаниеСписка, "ПолноеИмя"); - КонецЕсли; - Иначе - Возврат Строка(ОписаниеСписка); - КонецЕсли; - -КонецФункции - -// Для процедуры УправлениеДоступом.ОтключитьОбновлениеКлючейДоступа. -// -// Параметры: -// Списки - Массив -// ДобавленныеСписки - Соответствие -// НедоступныеСписки - Массив - возвращаемое значение. -// -Процедура ДобавитьЗависимыеСписки(Списки, ДобавленныеСписки, НедоступныеСписки) Экспорт - - ИсходныеСписки = Новый ФиксированныйМассив(Списки); - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - - НенайденныеСписки = Новый Массив; - - Для Каждого ИсходныйСписок Из ИсходныеСписки Цикл - Свойства = ДействующиеПараметры.ВедущиеСписки.Получить(ИсходныйСписок); - Если Свойства = Неопределено Тогда - Продолжить; - КонецЕсли; - Для Каждого КлючИЗначение Из Свойства.ЗависимыеСписки Цикл - Если ДобавленныеСписки.Получить(КлючИЗначение.Ключ) = Неопределено Тогда - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(КлючИЗначение.Ключ); - Если ОбъектМетаданных = Неопределено Тогда - НенайденныеСписки.Добавить(КлючИЗначение.Ключ); - Иначе - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - Списки.Добавить(ПолноеИмя); - ДобавленныеСписки.Вставить(ПолноеИмя, Истина); - КонецЕсли; - ДобавленныеСписки.Вставить(КлючИЗначение.Ключ, Истина); - КонецЕсли; - КонецЦикла; - КонецЦикла; - - Если НенайденныеСписки.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - НедоступныеСписки = ВсеИдентификаторыСПодобнымиПолнымиИменами(НенайденныеСписки); - -КонецПроцедуры - -Функция ОписаниеОграниченийДанных() Экспорт - - ОбщийКонтекст = Новый Структура; - ОбщийКонтекст.Вставить("СпискиСОграничением", УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением()); - - Результат = Новый Соответствие; - - Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл - ПолноеИмя = ОписаниеСписка.Ключ; - ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); - Результат.Вставить(ПолноеИмя, ОписаниеОграничения); - КонецЦикла; - - Возврат Результат; - -КонецФункции - -#Область ПараметрыДляПереопределенияЧерезРасширениеКонфигурации - -Функция КоличествоЧасовУстареванияНеиспользуемыхЭлементов() - - Возврат 47; - -КонецФункции - -Функция КоличествоЧасовМеждуПланированиемОбработкиУстаревшихЭлементов() - - Возврат 48; - -КонецФункции - -Функция МаксимальноеКоличествоМинутВыполненияФоновогоЗаданияОбновленияДоступа() - - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - Возврат 2; - Иначе - Возврат 15; - КонецЕсли; - -КонецФункции - -Функция МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке() Экспорт - - Возврат 900; // 15 минут (например, избыточно длительный запрос SQL). - -КонецФункции - -Функция МинимальноеКоличествоСекундОбработкиПорцииВОтдельномПотоке() - - Возврат 1; - -КонецФункции - -Функция МинимальноеКоличествоСекундВыполненияТочечногоЗадания() - - Возврат 15; - -КонецФункции - -Функция ЗагружатьСвободныеПотокиСледующимиЗаданиямиПриДлительныхЗапросах() - - Возврат Истина; - -КонецФункции - -Функция МаксимальныйПериодПолученияПорцийЗапросом() - - Возврат "Год"; // Год, Квартал, Месяц, Неделя. - -КонецФункции - -Функция ЗапускатьОбновлениеПолученныхПорцийПриПолученииНовыхПорций() - - Возврат Ложь; - -КонецФункции - -Функция МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных() - - Возврат 15; // 0 - отключить балансировку нагрузки на диск. - -КонецФункции - -Функция КоличествоЭлементовДанныхВЗапросе() - - Возврат 1000; - -КонецФункции - -Функция КоличествоЭлементовДанныхВПорции() - - Возврат 1000; - -КонецФункции - -Функция КоличествоКлючейДоступаВЗапросе() - - Возврат 1000; - -КонецФункции - -Функция КоличествоКлючейДоступаВПорции() - - Возврат 200; - -КонецФункции - -Функция ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных() - - Возврат Ложь; - -КонецФункции - -Функция МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных() - - Возврат 100; - -КонецФункции - -Функция КоличествоСекундПередОтключениемРегламентногоЗаданияПослеПолногоЗавершенияОбновления() - - Возврат 15; - -КонецФункции - -Функция ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(ПроверкаПриЗапуске) - - Результат = Ложь; - - Если ОбщегоНазначения.РазделениеВключено() Тогда - Результат = Истина; - КонецЕсли; - - Возврат Результат; - -КонецФункции - -Функция РегистрироватьПоказателиОбновленияДоступа() - - Возврат Истина; - -КонецФункции - -Функция РегистрироватьПоказателиПланированияОбновленияДоступа() - - Возврат Ложь; - -КонецФункции - -Функция РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() - - Возврат Ложь; - -КонецФункции - -#КонецОбласти - -#Область ТочкиПодключенияДляАнализаПроизводительностиЧерезРасширениеКонфигурации - -Процедура ПередБлокировкойДанных(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеБлокировкиДанных(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередЗаписьюСтрок(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных) - Возврат; -КонецПроцедуры - -Процедура ПередФиксациейТранзакции(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеФиксацииТранзакции(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередПланированиемОбновления(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеПланированияОбновления(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередЗаписьюНовогоКлюча(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеЗаписиНовогоКлюча(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередЗапросомПравГруппДоступа(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеЗапросаПравГруппДоступа(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередЗапросомПравПользователей(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПослеЗапросаПравПользователей(ПараметрыОбновления) - Возврат; -КонецПроцедуры - -Процедура ПередИзменениемПараметровСеансаДляШаблонов(НовыеЗначения, ЭтоУстановка) - Возврат; -КонецПроцедуры - -Процедура ПриОшибкеПроверкиАктуальностиМетаданных(ТекстОшибки) - Возврат; -КонецПроцедуры - -#КонецОбласти - -#КонецОбласти - -#Область ПараметрыОграниченияДоступа - -#Область ПараметрыОграниченияДоступаОбщаяЧасть - -// Основная функция, возвращающая параметры, необходимые для регистрации -// необходимости обновления ключей доступа к элементам данных. -// -// Параметры: -// ПолноеИмя - Строка - полное имя списка -// ИдентификаторТранзакции - УникальныйИдентификатор -// ПовторныйВызов - Булево - только при вызове из самой же функции -// -// Возвращаемое значение: -// Структура: -// * ЗависимыеСписки - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка. -// ** Значение - Булево - Истина. -// * ПоЗначениямПолей - см. ВедущийСписокПоЗначениямПолей -// * ПоКлючамДоступа - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами -// * ПоЗначениямСГруппами - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами -// -Функция СвойстваСпискаКакВедущего(ПолноеИмя, ИдентификаторТранзакции = Неопределено, ПовторныйВызов = Ложь) Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, Неопределено, ПовторныйВызов); - ХранимыеСвойстваСпискаКакВедущего = ДействующиеПараметры.ВедущиеСписки.Получить(ПолноеИмя); - - Если ХранимыеСвойстваСпискаКакВедущего = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - - Кэш = КэшПараметровОграничения(); - - СвойстваСпискаКакВедущего = Кэш.ВедущиеСпискиПроверенные.Получить(ПолноеИмя); - Если СвойстваСпискаКакВедущего <> Неопределено Тогда - Возврат СвойстваСпискаКакВедущего; - КонецЕсли; - - СвойстваСпискаКакВедущего = Новый Структура(ХранимыеСвойстваСпискаКакВедущего); - Отказ = Ложь; - ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка(ПолноеИмя, - СвойстваСпискаКакВедущего, Отказ); - - Если Не Отказ Тогда - Кэш.ВедущиеСпискиПроверенные.Вставить(ПолноеИмя, - Новый ФиксированнаяСтруктура(СвойстваСпискаКакВедущего)); - - Возврат СвойстваСпискаКакВедущего; - КонецЕсли; - - Если ПовторныйВызов Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось подготовить свойства списка ""%1"" как ведущего, - |из-за некорректного состояния параметров ограничения доступа.'"), - ПолноеИмя); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Возврат СвойстваСпискаКакВедущего(ПолноеИмя, ИдентификаторТранзакции, Истина); - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ВедущиеСпискиПроверенные - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. УправлениеДоступомСлужебный.СвойстваСпискаКакВедущего -// * ОграниченияСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. УправлениеДоступомСлужебный.РассчитанныеПараметрыОграничения -// * ИдентификаторыТранзакции - Соответствие из КлючИЗначение: -// ** Ключ - УникальныйИдентификатор - произвольный УИД. -// ** Значение - Булево - значение Истина. -// * ВидыОграниченийПравДляПользователей - Неопределено -// - Строка -// * ВидыОграниченийПравДляВнешнихПользователей - Неопределено -// - Строка -// -Функция НовыйКэшПараметровОграничения() Экспорт - - Хранилище = Новый Структура; - Хранилище.Вставить("ВедущиеСпискиПроверенные", Новый Соответствие); - Хранилище.Вставить("ОграниченияСписков", Новый Соответствие); - Хранилище.Вставить("ИдентификаторыТранзакции", Новый Соответствие); - Хранилище.Вставить("ВидыОграниченийПравДляПользователей", Неопределено); - Хранилище.Вставить("ВидыОграниченийПравДляВнешнихПользователей", Неопределено); - - Возврат Хранилище; - -КонецФункции - -// Для функции СвойстваСпискаКакВедущего и процедур ЗаполнитьПараметрыОграничения, -// ОбновитьИдентификаторыТранзакции, УстановитьВерсиюПараметров. -// -Функция КэшПараметровОграничения() - - КлючДанныхПовторногоИспользования = Строка(ПараметрыСеанса.КлючДанныхПовторногоИспользования); - - Возврат УправлениеДоступомСлужебныйПовтИсп.КэшПараметровОграничения(КлючДанныхПовторногоИспользования); - -КонецФункции - -Процедура СброситьКэшПараметровОграничения() - - Кэш = КэшПараметровОграничения(); - НовыйКэш = НовыйКэшПараметровОграничения(); - - Для Каждого КлючИЗначение Из НовыйКэш Цикл - Кэш.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - -КонецПроцедуры - -// Для функции СвойстваСпискаКакВедущего. -Процедура ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка(ПолноеИмя, Свойства, Отказ) - - Свойства.Удалить("ЗависимыеСписки"); - Если Свойства.ПоЗначениямПолей = Неопределено Тогда - Возврат; - КонецЕсли; - - ПоЗначениямПолей = Новый Структура(Свойства.ПоЗначениямПолей); // См. ВедущийСписокПоЗначениямПолей - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); - - Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда - Если ЗначениеЗаполнено(ПоЗначениямПолей.ПоляШапки.ВсеПоля) Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ТекущаяТаблица.Поле1 КАК Поле1 - |ИЗ - | (ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина) КАК ЗначениеИстина - | ЛЕВОЕ СОЕДИНЕНИЕ ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица - | ПО (ТекущаяТаблица.Ссылка = &СсылкаНаОбъект)"; - ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, - ПолноеИмя, ПоЗначениямПолей.ПоляШапки.ВсеПоля, ОбъектМетаданных, Отказ); - Иначе - ТекстЗапроса = ""; - КонецЕсли; - - Для Каждого ТабличнаяЧасть Из ПоЗначениямПолей.ТабличныеЧасти Цикл - Коллекции = Новый Структура("СтандартныеТабличныеЧасти, ТабличныеЧасти"); - ТабличнаяЧастьИмя = ТабличнаяЧасть.Имя; - ЗаполнитьЗначенияСвойств(Коллекции, ОбъектМетаданных); - МетаданныеТаблицы = Неопределено; - Если ТипЗнч(Коллекции.ТабличныеЧасти) = Тип("КоллекцияОбъектовМетаданных") Тогда - МетаданныеТаблицы = ОбъектМетаданных.ТабличныеЧасти.Найти(ТабличнаяЧастьИмя); - КонецЕсли; - Если МетаданныеТаблицы = Неопределено - И ТипЗнч(Коллекции.СтандартныеТабличныеЧасти) = Тип("ОписанияСтандартныхТабличныхЧастей") Тогда - Для Каждого СтандартнаяТабличнаяЧасть Из Коллекции.СтандартныеТабличныеЧасти Цикл - СтандартнаяТабличнаяЧасть = СтандартнаяТабличнаяЧасть; // ОписаниеСтандартнойТабличнойЧасти - Если СтандартнаяТабличнаяЧасть.Имя = ТабличнаяЧастьИмя Тогда - МетаданныеТаблицы = СтандартнаяТабличнаяЧасть; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если МетаданныеТаблицы = Неопределено Тогда - Отказ = Истина; - Прервать; - КонецЕсли; - - ТекстЗапросаТабличнойЧасти = - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100 - | ТекущаяТаблица.Поле1 КАК Поле1 - |ИЗ - | ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица - |ГДЕ - | ТекущаяТаблица.Ссылка = &СсылкаНаОбъект"; - ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапросаТабличнойЧасти, - ПолноеИмя + "." + ТабличнаяЧастьИмя, ТабличнаяЧасть.ВсеПоля, МетаданныеТаблицы, Отказ, Истина); - - ТекстЗапроса = ТекстЗапроса + ?(ТекстЗапроса = "", "", - ОбщегоНазначения.РазделительПакетаЗапросов()) + ТекстЗапросаТабличнойЧасти; - КонецЦикла; - - ИначеЕсли ЗначениеЗаполнено(ПоЗначениямПолей.ПоляШапки.ВсеПоля) Тогда - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100 - | ТекущаяТаблица.Поле1 КАК Поле1 - |ИЗ - | ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица - |ГДЕ - | &ОтборПоИзмерениям"; - ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, - ПолноеИмя, ПоЗначениямПолей.ПоляШапки.ВсеПоля, ОбъектМетаданных, Отказ); - Иначе - ТекстЗапроса = ""; - КонецЕсли; - - ПоЗначениямПолей.Вставить("ТекстЗапроса", ТекстЗапроса); - Свойства.ПоЗначениямПолей = Новый ФиксированнаяСтруктура(ПоЗначениямПолей); - -КонецПроцедуры - -// Для процедуры ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка. -Процедура ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, ПолноеИмя, ОписаниеПолей, - МетаданныеТаблицы, Отказ, ЭтоТабличнаяЧасть = Ложь) - - КоллекцииПолей = Новый Структура("Реквизиты, Измерения, Ресурсы, СтандартныеРеквизиты"); - ЗаполнитьЗначенияСвойств(КоллекцииПолей, МетаданныеТаблицы); - - ПоляВыбора = ""; - Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл - ИмяПоля = ?(ТипЗнч(ОписаниеПолей) = Тип("ФиксированныйМассив"), ОписаниеПоля, ОписаниеПоля.Ключ); - - Если Не ПолеСуществует(КоллекцииПолей.Реквизиты, ИмяПоля) - И Не ПолеСуществует(КоллекцииПолей.Измерения, ИмяПоля) - И Не ПолеСуществует(КоллекцииПолей.Ресурсы, ИмяПоля) - И Не ПолеСуществует(КоллекцииПолей.СтандартныеРеквизиты, ИмяПоля) - И Не (ЭтоТабличнаяЧасть - И (ВРег(ИмяПоля) = ВРег("Ссылка") - Или ВРег(ИмяПоля) = ВРег("Ref"))) Тогда // @Non-NLS - - Отказ = Истина; - Прервать; - КонецЕсли; - - ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", "," + Символы.ПС) - + "ТекущаяТаблица." + ИмяПоля + " КАК " + ИмяПоля; // @query-part-5 - КонецЦикла; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "ТекущаяТаблица.Поле1 КАК Поле1", ТекстСОтступом(СокрЛ(ПоляВыбора), " ")); // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущаяТаблицаЭлементовДанных", ПолноеИмя); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПЕРВЫЕ 100", "ПЕРВЫЕ " + Формат( - МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных() * 10, "ЧГ=")); // @query-part-1, @query-part-2 - -КонецПроцедуры - -// Для процедуры ЗаполнитьПоляВыбораТекущейТаблицы. -Функция ПолеСуществует(Коллекция, ИмяПоля) - - Если ТипЗнч(Коллекция) = Тип("КоллекцияОбъектовМетаданных") Тогда - Возврат Коллекция.Найти(ИмяПоля) <> Неопределено; - - ИначеЕсли ТипЗнч(Коллекция) = Тип("ОписанияСтандартныхРеквизитов") Тогда - Для Каждого СтандартныйРеквизит Из Коллекция Цикл - Если СтандартныйРеквизит.Имя = ИмяПоля Тогда - Возврат Истина; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Возврат Ложь; - -КонецФункции - -// Основная функция, возвращающая параметры, необходимые для проверки прав в момент записи элементов данных. -// -// Возвращаемое значение: -// см. ПараметрыОграниченияПоСтруктуреОграничения -// -Функция ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции = Неопределено, ДляВнешнихПользователей = Неопределено) Экспорт - - УстановитьОтключениеБезопасногоРежима(Истина); - УстановитьПривилегированныйРежим(Истина); - - ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, Неопределено, Ложь); - Параметры = КэшПараметровОграничения().ОграниченияСписков.Получить(ПолноеИмя); - - Если Параметры = Неопределено Тогда - ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры); - КонецЕсли; - - Если ДляВнешнихПользователей = Null Тогда - Возврат Параметры; - КонецЕсли; - - Если ДляВнешнихПользователей = Неопределено Тогда - ДляВнешнихПользователей = Пользователи.ЭтоСеансВнешнегоПользователя(); - КонецЕсли; - - Если ДляВнешнихПользователей Тогда - Возврат Параметры.ДляВнешнихПользователей; - КонецЕсли; - - Возврат Параметры.ДляПользователей; - -КонецФункции - -// Для функций СвойстваСпискаКакВедущего, ПараметрыОграничения. -Процедура ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры, - ОбщийКонтекст = Неопределено, ПовторныйВызов = Ложь) - - Если ОбщийКонтекст = Неопределено Тогда - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(ПолноеИмя); - ОбщийКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); - КонецЕсли; - - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, Ложь); - - ВерсияОграничений = ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя); - ЕстьОшибка = Ложь; - Попытка - РассчитанныеПараметры = РассчитанныеПараметрыОграничения(ПолноеИмя, ОбщийКонтекст, ДействующиеПараметры); - Исключение - Если ПовторныйВызов Тогда - ВызватьИсключение; - КонецЕсли; - Попытка - Значение = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); - Исключение - Значение = Неопределено; - КонецПопытки; - Если Значение = Неопределено Тогда - ВызватьИсключение; - КонецЕсли; - ЕстьОшибка = Истина; - КонецПопытки; - - Если ЕстьОшибка Или ВерсияОграничений <> РассчитанныеПараметры.Версия Тогда - Если ПовторныйВызов Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить параметры ограничения доступа списка ""%1"" - |из-за нестабильной строки свойств версии параметров для вычисления хеш-суммы.'"), - ПолноеИмя); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, Истина); - ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры, ОбщийКонтекст, Истина); - Возврат; - КонецЕсли; - - Параметры = ОбщегоНазначения.ФиксированныеДанные(РассчитанныеПараметры); - - КэшПараметровОграничения().ОграниченияСписков.Вставить(ПолноеИмя, Параметры); - -КонецПроцедуры - -// Для процедуры ЗаполнитьПараметрыОграничения и функций -// ХранимыеПараметрыОграниченияДоступа, ОшибкиОграниченийДоступа. -// -// Возвращаемое значение: -// Структура: -// * СвойстваВидовДоступа - см. СвойстваВидовДоступа -// * ТипыПользователя - Массив из Тип -// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие -// * ОтдельныеТаблицыНастроекПрав - ФиксированноеСоответствие -// * ВнешниеПользователиВключены - Булево -// * ИспользуемыеТипыЗначений - см. ИспользуемыеТипыЗначений -// * СпискиСОграничением - см. УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением -// -Функция ОбщийКонтекстРасчетаПараметровОграничения(ПолноеИмя = Неопределено, - ВсеВидыДоступаИспользуются = Неопределено, ЗаполнитьСпискиСОграничением = Истина) - - ТипыПользователя = Новый Массив; - ТипыПользователя.Добавить(Тип("СправочникСсылка.Пользователи")); - ТипыПользователя.Добавить(Тип("СправочникСсылка.ГруппыПользователей")); - ТипыПользователя.Добавить(Тип("СправочникСсылка.ВнешниеПользователи")); - ТипыПользователя.Добавить(Тип("СправочникСсылка.ГруппыВнешнихПользователей")); - - ОграничениеДоступаВключено = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); - Если УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() <> ОграничениеДоступаВключено Тогда - ОбновитьПовторноИспользуемыеЗначения(); - КонецЕсли; - СвойстваВидовДоступа = СвойстваВидовДоступа(); - - ИспользуемыеТипыЗначений = ИспользуемыеТипыЗначений(СвойстваВидовДоступа, ПолноеИмя, ВсеВидыДоступаИспользуются); - Если ТипЗнч(ВсеВидыДоступаИспользуются) = Тип("Булево") Тогда - ОграничениеДоступаВключено = ВсеВидыДоступаИспользуются; - ВнешниеПользователиВключены = ВсеВидыДоступаИспользуются; - Иначе - ВнешниеПользователиВключены = Константы.ИспользоватьВнешнихПользователей.Получить(); - КонецЕсли; - - ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); - - ОбщийКонтекст = Новый Структура; - ОбщийКонтекст.Вставить("СвойстваВидовДоступа", СвойстваВидовДоступа); - ОбщийКонтекст.Вставить("ТипыПользователя", ТипыПользователя); - ОбщийКонтекст.Вставить("ТипыВладельцевНастроекПрав", ВозможныеПрава.ПоТипамСсылок); - ОбщийКонтекст.Вставить("ОтдельныеТаблицыНастроекПрав", ВозможныеПрава.ОтдельныеТаблицы); - ОбщийКонтекст.Вставить("ВнешниеПользователиВключены", ВнешниеПользователиВключены); - ОбщийКонтекст.Вставить("ОграничениеДоступаВключено", ОграничениеДоступаВключено); - ОбщийКонтекст.Вставить("ИспользуемыеТипыЗначений", ИспользуемыеТипыЗначений); - - Если ЗаполнитьСпискиСОграничением Тогда - ОбщийКонтекст.Вставить("СпискиСОграничением", УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением()); - КонецЕсли; - - Возврат ОбщийКонтекст; - -КонецФункции - -// Для функций ОбщийКонтекстРасчетаПараметровОграничения и ИспользованиеВидовДоступаИзменено. -// -// Параметры: -// СвойстваВидовДоступа - см. СвойстваВидовДоступа -// ПолноеИмя - Строка -// ВсеВидыДоступаИспользуются - Неопределено -// - Булево -// ТолькоХешСумма - Булево -// -// Возвращаемое значение: -// Структура: -// * ДляИБ - Соответствие из КлючИЗначение: -// ** Ключ - Тип -// ** Значение - Булево - Истина -// * ПоТаблицам - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя объекта метаданных -// ** Значение - Соответствие из КлючИЗначение: -// *** Ключ - Тип -// *** Значение - Булево - Истина -// * ХешСумма - Строка - контрольная сумма настроек использования ДляИБ и ПоТаблицам. -// * ПолноеИмяТаблицы - Строка - полное имя таблицы, когда свойство ПоТаблицам -// заполнено только для одной таблицы. -// - Неопределено - когда свойство ПоТаблицам не заполнялось (ВсеВидыДоступаИспользуются = Истина). -// -Функция ИспользуемыеТипыЗначений(СвойстваВидовДоступа, ПолноеИмя = Неопределено, ВсеВидыДоступаИспользуются = Неопределено, ТолькоХешСумма = Ложь) - - ИспользуемыеТипыЗначений = Новый Структура; - ИспользуемыеТипыЗначений.Вставить("ДляИБ", Новый Соответствие); - ИспользуемыеТипыЗначений.Вставить("ПоТаблицам", Новый Соответствие); - ИспользуемыеТипыЗначений.Вставить("ХешСумма", ""); - ИспользуемыеТипыЗначений.Вставить("ПолноеИмяТаблицы", ""); - - Если ВсеВидыДоступаИспользуются = Ложь Тогда - Возврат ИспользуемыеТипыЗначений; - КонецЕсли; - - Если ВсеВидыДоступаИспользуются = Истина Тогда - ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Неопределено; - Иначе - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | ИспользуемыеВидыДоступа.ТипЗначенийДоступа КАК ТипЗначенийДоступа - |ИЗ - | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа - |ГДЕ - | ИспользуемыеВидыДоступа.Используется = ИСТИНА - | И &ОграничиватьДоступНаУровнеЗаписей - | - |УПОРЯДОЧИТЬ ПО - | ТипЗначенийДоступа - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ИспользуемыеВидыДоступаПоТаблицам.Таблица КАК Таблица, - | ИспользуемыеВидыДоступаПоТаблицам.ТипЗначенийДоступа КАК ТипЗначенийДоступа - |ИЗ - | РегистрСведений.ИспользуемыеВидыДоступаПоТаблицам КАК ИспользуемыеВидыДоступаПоТаблицам - |ГДЕ - | ИспользуемыеВидыДоступаПоТаблицам.Таблица = &Таблица - | - |УПОРЯДОЧИТЬ ПО - | Таблица, - | ТипЗначенийДоступа"; - - Если ПолноеИмя <> Неопределено Тогда - Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПолноеИмя, Ложь); - Если Идентификатор <> Null Тогда - Запрос.УстановитьПараметр("Таблица", Идентификатор); - КонецЕсли; - КонецЕсли; - Если ПолноеИмя = Неопределено Или Идентификатор = Null Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ИспользуемыеВидыДоступаПоТаблицам.Таблица = &Таблица", "ИСТИНА"); - Иначе - ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = ПолноеИмя; - КонецЕсли; - СтрокаОграничениеДоступаВключено = - ?(Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(), "ИСТИНА", "ЛОЖЬ"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОграничиватьДоступНаУровнеЗаписей", - СтрокаОграничениеДоступаВключено); - - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - Используемые = РезультатыЗапроса[0].Выгрузить(); - ИспользуемыеПоТаблицам = РезультатыЗапроса[1].Выгрузить(); - Если ПолноеИмя = Неопределено Тогда - Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); - Хеширование.Добавить(СтрокаОграничениеДоступаВключено); - Хеширование.Добавить(СтрокаДанныхДляХеширования(Используемые)); - Хеширование.Добавить(СтрокаДанныхДляХеширования(ИспользуемыеПоТаблицам)); - ИспользуемыеТипыЗначений.ХешСумма = Base64Строка(Хеширование.ХешСумма); - Если ТолькоХешСумма Тогда - Возврат ИспользуемыеТипыЗначений; - КонецЕсли; - КонецЕсли; - Таблицы = ИспользуемыеПоТаблицам.Скопировать(, "Таблица"); - Таблицы.Свернуть("Таблица"); - Идентификаторы = Таблицы.ВыгрузитьКолонку("Таблица"); - ОбъектыМетаданных = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, Ложь); - ТекущаяТаблица = Неопределено; - Для Каждого Строка Из ИспользуемыеПоТаблицам Цикл - Если ТекущаяТаблица <> Строка.Таблица Тогда - ОбъектМетаданных = ОбъектыМетаданных.Получить(Строка.Таблица); - Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда - Продолжить; - КонецЕсли; - ТекущееПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - ТекущаяТаблица = Строка.Таблица; - ТекущиеИспользуемыеТипы = Новый Соответствие; - ИспользуемыеТипыЗначений.ПоТаблицам.Вставить(ТекущееПолноеИмя, ТекущиеИспользуемыеТипы); - КонецЕсли; - ТекущиеИспользуемыеТипы.Вставить(ТипЗнч(Строка.ТипЗначенийДоступа), Истина); - КонецЦикла; - КонецЕсли; - - СвойстваВидовДоступаМассив = СвойстваВидовДоступа.Массив; // Массив Из см. СвойстваВидаДоступа - Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступаМассив Цикл - Если ВсеВидыДоступаИспользуются <> Истина - И Используемые.Найти(СвойстваВидаДоступа.Ссылка) = Неопределено Тогда - Продолжить; - КонецЕсли; - ИспользуемыеТипыЗначений.ДляИБ.Вставить(СвойстваВидаДоступа.ТипЗначений, Истина); - Для Каждого ОписаниеДополнительногоТипа Из СвойстваВидаДоступа.ДополнительныеТипы Цикл - ИспользуемыеТипыЗначений.ДляИБ.Вставить(ОписаниеДополнительногоТипа.ТипЗначений, Истина); - КонецЦикла; - КонецЦикла; - - Возврат ИспользуемыеТипыЗначений; - -КонецФункции - -// Для процедуры ДобавитьПараметрыОграниченияСписка. -// -// Возвращаемое значение: -// Структура: -// * Версия - Строка -// * ВедущиеСписки - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. СвойстваСпискаКакВедущего -// * ДляПользователей - см. ПараметрыОграниченияПоСтруктуреОграничения -// * ДляВнешнихПользователей - см. ПараметрыОграниченияПоСтруктуреОграничения -// -Функция РассчитанныеПараметрыОграничения(ПолноеИмя, ОбщийКонтекст, ДействующиеПараметры) Экспорт - - ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); - - // Для пользователей. - СтруктураОграниченияДляПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, - ОписаниеОграничения.Текст, ОписаниеОграничения.ТекстВМодулеМенеджера, Ложь); - - ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); - ЗаполнитьЗначенияСвойств(ДополнительныйКонтекст, ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей); - ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Ложь); - - РезультатДляПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, - СтруктураОграниченияДляПользователей, Ложь, ОбщийКонтекст, ДополнительныйКонтекст); - - // Для внешних пользователей. - СтруктураОграниченияДляВнешнихПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, - ОписаниеОграничения.ТекстДляВнешнихПользователей, ОписаниеОграничения.ТекстВМодулеМенеджера, Истина); - - ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); - ЗаполнитьЗначенияСвойств(ДополнительныйКонтекст, ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей); - ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Истина); - - РезультатДляВнешнихПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, - СтруктураОграниченияДляВнешнихПользователей, Истина, ОбщийКонтекст, ДополнительныйКонтекст); - - // Заполнение параметров на основе параметров обоих видов пользователей. - Версия = ОбщаяВерсия(ОбщийКонтекст, ПолноеИмя, РезультатДляПользователей.Версия, РезультатДляВнешнихПользователей.Версия); - УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляПользователей); - УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляВнешнихПользователей); - СЗаписьюДвухКлючей = Не РезультатДляПользователей.БезЗаписиКлючейДоступа И Не РезультатДляВнешнихПользователей.БезЗаписиКлючейДоступа; - БезЗаписиКлючей = РезультатДляПользователей.БезЗаписиКлючейДоступа И РезультатДляВнешнихПользователей.БезЗаписиКлючейДоступа; - РезультатДляПользователей.Вставить( "СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", СЗаписьюДвухКлючей); - РезультатДляВнешнихПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", СЗаписьюДвухКлючей); - РезультатДляПользователей.Вставить( "БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", БезЗаписиКлючей); - РезультатДляВнешнихПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", БезЗаписиКлючей); - - // Формирование текстов запросов. - ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляПользователей); - ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляВнешнихПользователей); - - ВедущиеСписки = Новый Структура; - ВедущиеСписки.Вставить("ДляПользователей", РезультатДляПользователей.ВедущиеСписки); - ВедущиеСписки.Вставить("ДляВнешнихПользователей", РезультатДляВнешнихПользователей.ВедущиеСписки); - - Параметры = Новый Структура; - Параметры.Вставить("Версия", Версия); - Параметры.Вставить("ВедущиеСписки", ВедущиеСписки); - Параметры.Вставить("ДляПользователей", РезультатДляПользователей); - Параметры.Вставить("ДляВнешнихПользователей", РезультатДляВнешнихПользователей); - - Возврат Параметры; - -КонецФункции - -// Для функции ОшибкиОграниченийДоступа. -Функция ОшибкаОграниченияДоступа(ОбщийКонтекст, ПолноеИмя) - - ТекстОшибкиДляПользователей = ""; - ТекстОшибкиДляВнешнихПользователей = ""; - - Попытка - ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, Истина); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Возврат ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - КонецПопытки; - Если ТипЗнч(ОписаниеОграничения) = Тип("Строка") Тогда - Возврат ОписаниеОграничения; - КонецЕсли; - - // Для пользователей. - СтруктураОграниченияДляПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, - ОписаниеОграничения.Текст, ОписаниеОграничения.ТекстВМодулеМенеджера, Ложь, Истина); - - Если СтруктураОграниченияДляПользователей <> Неопределено - И СтруктураОграниченияДляПользователей.ОписаниеОшибок.ЕстьОшибки Тогда - - ТекстОшибкиДляПользователей = ТекстОшибокДляВызоваИсключения(ПолноеИмя, - СтруктураОграниченияДляПользователей.ОписаниеОшибок, Ложь, ОписаниеОграничения.ТекстВМодулеМенеджера); - Иначе - ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); - ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Ложь); - - ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); - ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); - Попытка - РезультатДляПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, - СтруктураОграниченияДляПользователей, Ложь, ОбщийКонтекст, ДополнительныйКонтекст); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда - ТекстОшибкиДляПользователей = ОшибкаПриВызовеИсключения.Текст; - Иначе - ТекстОшибкиДляПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось сформировать параметры ограничения доступа для пользователей по причине: - |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецЕсли; - КонецПопытки; - - Если Не ЗначениеЗаполнено(ТекстОшибкиДляПользователей) Тогда - РезультатДляПользователей.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; - УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляПользователей); - РезультатДляПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); - РезультатДляПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); - Попытка - ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляПользователей); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда - ТекстОшибкиДляПользователей = ОшибкаПриВызовеИсключения.Текст; - Иначе - ТекстОшибкиДляПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа - |для пользователей по причине: - |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецЕсли; - КонецПопытки; - КонецЕсли; - КонецЕсли; - - // Для внешних пользователей. - СтруктураОграниченияДляВнешнихПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, - ОписаниеОграничения.ТекстДляВнешнихПользователей, ОписаниеОграничения.ТекстВМодулеМенеджера, Истина, Истина); - - Если СтруктураОграниченияДляВнешнихПользователей <> Неопределено - И СтруктураОграниченияДляВнешнихПользователей.ОписаниеОшибок.ЕстьОшибки Тогда - - ТекстОшибкиДляВнешнихПользователей = ТекстОшибокДляВызоваИсключения(ПолноеИмя, - СтруктураОграниченияДляВнешнихПользователей.ОписаниеОшибок, Истина, ОписаниеОграничения.ТекстВМодулеМенеджера); - Иначе - ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); - ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Истина); - - ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); - ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); - Попытка - РезультатДляВнешнихПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, - СтруктураОграниченияДляВнешнихПользователей, Истина, ОбщийКонтекст, ДополнительныйКонтекст); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда - ТекстОшибкиДляВнешнихПользователей = ОшибкаПриВызовеИсключения.Текст; - Иначе - ТекстОшибкиДляВнешнихПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось сформировать параметры ограничения доступа для внешних пользователей по причине: - |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецЕсли; - КонецПопытки; - - Если Не ЗначениеЗаполнено(ТекстОшибкиДляВнешнихПользователей) Тогда - РезультатДляВнешнихПользователей.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; - УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляВнешнихПользователей); - РезультатДляВнешнихПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); - РезультатДляВнешнихПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); - Попытка - ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляВнешнихПользователей); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда - ТекстОшибкиДляВнешнихПользователей = ОшибкаПриВызовеИсключения.Текст; - Иначе - ТекстОшибкиДляВнешнихПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа - |для внешних пользователей по причине: - |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецЕсли; - КонецПопытки; - КонецЕсли; - КонецЕсли; - - Возврат СокрЛП(ТекстОшибкиДляПользователей - + Символы.ПС + Символы.ПС + ТекстОшибкиДляВнешнихПользователей); - -КонецФункции - -// Для функции РезультатПроверкиОграниченияДоступа. -Функция РезультатПроверкиОграниченияДоступаОбъекта(ПолноеИмя, ДополнительныеПараметры) - - Параметры = Новый Структура; - Параметры.Вставить("Текст", Неопределено); - Параметры.Вставить("ТекстДляВнешнихПользователей", Неопределено); - Параметры.Вставить("УчитыватьЗависимости", Ложь); - Параметры.Вставить("ВсеВидыДоступаИспользуются", Истина); - - Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда - ЗаполнитьЗначенияСвойств(Параметры, ДополнительныеПараметры); - КонецЕсли; - - ДляПользователей = СтруктураРезультатаПроверкиОграниченияДляВидаПользователей(); - ДляВнешнихПользователей = СтруктураРезультатаПроверкиОграниченияДляВидаПользователей(); - - Результат = Новый Структура; - Результат.Вставить("ОшибкаОписанияОграничения", ""); - Результат.Вставить("ТекстВМодулеМенеджера", Неопределено); - Результат.Вставить("ДляПользователей", ДляПользователей); - Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); - Результат.Вставить("НастройкиВнедрения", Новый Структура); - - ОбщийКонтекст = Неопределено; - Попытка - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Параметры.ВсеВидыДоступаИспользуются, Ложь); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - КонецПопытки; - - Если ОбщийКонтекст = Неопределено Тогда - Возврат Результат; - КонецЕсли; - - УчетЗависимостейДоступен = Истина; - СпискиСОграничением = Неопределено; - Попытка - СпискиСОграничением = УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением(); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - УчетЗависимостейДоступен = Ложь; - КонецПопытки; - - Если СпискиСОграничением <> Неопределено Тогда - СпискиСОграничением = Новый Соответствие(СпискиСОграничением); - Иначе - СпискиСОграничением = Новый Соответствие; - УчетЗависимостейДоступен = Ложь; - КонецЕсли; - ОбщийКонтекст.Вставить("СпискиСОграничением", СпискиСОграничением); - - ОписаниеОграничения = Неопределено; - Попытка - ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, Истина); - Исключение - Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - УчетЗависимостейДоступен = Ложь; - КонецПопытки; - Если ТипЗнч(ОписаниеОграничения) = Тип("Строка") Тогда - Результат.ОшибкаОписанияОграничения = ОписаниеОграничения; - ОписаниеОграничения = Неопределено; - КонецЕсли; - - Если ОписаниеОграничения <> Неопределено Тогда - Результат.ТекстВМодулеМенеджера = ОписаниеОграничения.ТекстВМодулеМенеджера; - ДляПользователей.ОграничениеВМодуле = ОписаниеОграничения.Текст; - ДляПользователей.ПоВладельцуБезЗаписиКлючейДоступа = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступа; - ДляВнешнихПользователей.ОграничениеВМодуле = ОписаниеОграничения.ТекстДляВнешнихПользователей; - ДляВнешнихПользователей.ПоВладельцуБезЗаписиКлючейДоступа = - ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей; - - Если Параметры.Текст = Неопределено Тогда - ДляПользователей.ПроверяемоеОграничение = ДляПользователей.ОграничениеВМодуле; - Иначе - ДляПользователей.ПроверяемоеОграничение = Параметры.Текст; - ОписаниеОграничения.Текст = Параметры.Текст; - КонецЕсли; - - Если Параметры.ТекстДляВнешнихПользователей = Неопределено Тогда - ДляВнешнихПользователей.ПроверяемоеОграничение = ДляВнешнихПользователей.ОграничениеВМодуле; - Иначе - ДляВнешнихПользователей.ПроверяемоеОграничение = Параметры.ТекстДляВнешнихПользователей; - ОписаниеОграничения.ТекстДляВнешнихПользователей = Параметры.ТекстДляВнешнихПользователей; - КонецЕсли; - КонецЕсли; - - Если СпискиСОграничением.Получить(ПолноеИмя) = Неопределено Тогда - СпискиСОграничением.Вставить(ПолноеИмя, Истина); - Результат.ТекстВМодулеМенеджера = Неопределено; - КонецЕсли; - - Контекст = Новый Структура; - Контекст.Вставить("ПолноеИмя", ПолноеИмя); - Контекст.Вставить("ОбщийРезультат", Результат); - Контекст.Вставить("ОбщийКонтекст", ОбщийКонтекст); - Контекст.Вставить("ОписаниеОграничения", ОписаниеОграничения); - Контекст.Вставить("УчитыватьЗависимости", Параметры.УчитыватьЗависимости); - Контекст.Вставить("УчетЗависимостейДоступен", УчетЗависимостейДоступен); - Контекст.Вставить("ВерсииОграниченийСписков", Новый Соответствие); - Контекст.Вставить("ВедущиеСписки", Новый Соответствие); - Контекст.Вставить("ДополнительныйКонтекст", Новый Структура("ДляПользователей, ДляВнешнихПользователей")); - - ПроверитьОграничениеДляВидаПользователей(Контекст, ДляПользователей, Ложь, - Контекст.ДополнительныйКонтекст.ДляПользователей); - - ПроверитьОграничениеДляВидаПользователей(Контекст, ДляВнешнихПользователей, Истина, - Контекст.ДополнительныйКонтекст.ДляВнешнихПользователей); - - Если Не Контекст.УчетЗависимостейДоступен Тогда - Возврат Результат; - КонецЕсли; - - Если Параметры.УчитыватьЗависимости Тогда - ОбщийКонтекст.Вставить("СпециальноеПолноеИмя", ПолноеИмя); - ОбщийКонтекст.Вставить("СпециальноеОписаниеОграничения", ОписаниеОграничения); - ОбщийКонтекст.Вставить("СпискиСОграничением", Новый ФиксированноеСоответствие(СпискиСОграничением)); - НовыеХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст); - ДействующиеПараметры = Новый Структура(НовыеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); // см. НоваяСтруктураХранимыхПараметровЗаписи - Если ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя) = Неопределено Тогда - Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, Истина); - Иначе - Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, - ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя)); - КонецЕсли; - УстановитьОграничениеПоВладельцуИспользуется(ДляПользователей, - ПолноеИмя, ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей); - УстановитьОграничениеПоВладельцуИспользуется(ДляВнешнихПользователей, - ПолноеИмя, ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей); - Иначе - Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, Истина); - ДействующиеПараметры = Новый Структура; - ДействующиеПараметры.Вставить("ДополнительныйКонтекст", Контекст.ДополнительныйКонтекст); - КонецЕсли; - ДействующиеПараметры.Вставить("ВерсииОграниченийСписков", Контекст.ВерсииОграниченийСписков); - ДействующиеПараметры.Вставить("ВедущиеСписки", Контекст.ВедущиеСписки); - - Настройки = НастройкиВнедрения(ДействующиеПараметры); - - ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; - УстановитьНастройкиВнедрения(Результат.НастройкиВнедрения, Настройки, ТипыТаблицПоИменам); - - Результат.ДляПользователей.ОграничениеВРолях = Настройки.ОграниченияВРолях.ДляПользователей.Получить( - ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам)); - - Результат.ДляВнешнихПользователей.ОграничениеВРолях = Настройки.ОграниченияВРолях.ДляВнешнихПользователей.Получить( - ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам)); - - Возврат Результат; - -КонецФункции - -// Для функции РезультатПроверкиОграниченияДоступаОбъекта -Процедура УстановитьОграничениеПоВладельцуИспользуется(Результат, ПолноеИмя, ДополнительныйКонтекст) - - Свойства = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(ПолноеИмя); - Если Свойства = Неопределено Тогда - Возврат; - КонецЕсли; - - Результат.ОграничениеПоВладельцуИспользуется = - Свойства.ПолеВладельца <> Неопределено И Не Свойства.ПолеВладельца.Отключено; - -КонецПроцедуры - -// Для функции РезультатПроверкиОграниченияДоступаОбъекта. -Процедура УстановитьНастройкиВнедрения(НастройкиВнедрения, Данные, ТипыТаблицПоИменам) - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, - Данные.ЗначенияДоступа, "ЗначениеДоступа"); - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, - Данные.ВладельцыЗначенийКлючейДоступа.Ссылки, "ВладелецЗначенийКлючейДоступа"); - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, - Данные.ВладельцыЗначенийКлючейДоступа.Объекты, "ВладелецЗначенийКлючейДоступаОбъект"); - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, - Данные.ВладельцыЗначенийКлючейДоступа.Документы, "ВладелецЗначенийКлючейДоступаДокумент"); - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, - Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписей, "ВладелецЗначенийКлючейДоступаНаборЗаписей"); - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, - Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета, - "ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета"); - - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, - Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета, - "ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета"); - - НастройкиВнедрения.Вставить("ПолеРегистраКлючейДоступаКРегистрам", ""); - НастройкиВнедрения.Вставить("ТипыИзмеренийОтдельногоРегистраКлючей", Неопределено); - Для Каждого КлючИЗначение Из Данные.ТипыИзмеренийРегистровКлючей Цикл - Если СтрНайти(КлючИЗначение.Ключ, ".") > 0 Тогда - Продолжить; - КонецЕсли; - ИмяРегистраКлючей = КлючИЗначение.Ключ; - - Если ИмяРегистраКлючей = "КлючиДоступаКРегистрам" Тогда - ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, - КлючИЗначение.Значение.ИменаТипов, "ПолеРегистраКлючейДоступаКРегистрам"); - Иначе - ИзмеренияРегистра = Метаданные.РегистрыСведений[ИмяРегистраКлючей].Измерения; - СписокТипов = ""; - НомерПоля = 1; - Для Каждого ОписаниеПолейРегистра Из КлючИЗначение.Значение.ПоляРегистров Цикл - Прервать; - КонецЦикла; - Для Каждого ОписаниеПоля Из ОписаниеПолейРегистра.Значение Цикл - ИмяПоля = СтрШаблон("Поле%1", НомерПоля); - ПолеРегистра = ИзмеренияРегистра.Найти(ИмяПоля); - ОписаниеТипов = ?(ПолеРегистра = Неопределено, Новый ОписаниеТипов, ПолеРегистра.Тип); - СписокТипов = СписокТипов + ?(СписокТипов = "", "", Символы.ПС) - + НСтр("ru = '- для измерения'") + " " + ИмяПоля + ":" + Символы.ПС - + " " + ТекстСОтступом(СписокТиповИзМассива(ОписаниеПоля.Тип.Типы(), - Истина, ТипыТаблицПоИменам, ОписаниеТипов), " "); - НомерПоля = НомерПоля + 1; - КонецЦикла; - НастройкиВнедрения.Вставить("ТипыИзмеренийОтдельногоРегистраКлючей", - Новый Структура("ИмяРегистраСведений, ТипыИзмерений", ИмяРегистраКлючей, СписокТипов)); - КонецЕсли; - КонецЦикла; - - НастройкиВнедрения.Вставить("ПредопределенныйИдентификатор", Неопределено); - Для Каждого КлючИЗначение Из Данные.ПредопределенныеИдентификаторы Цикл - ЧастиИмени = СтрРазделить(КлючИЗначение.Ключ, ".", Ложь); - УжеДобавлен = Метаданные.Справочники[ЧастиИмени[0]].ПолучитьИменаПредопределенных().Найти(ЧастиИмени[1]) <> Неопределено; - НастройкиВнедрения.Вставить("ПредопределенныйИдентификатор", - Новый Структура("ИмяСправочника, ИмяПредопределенного", ЧастиИмени[0], - "- " + ЧастиИмени[1] + ?(УжеДобавлен, " (" + НСтр("ru = 'уже добавлен'") + ")", ""))); - Прервать; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры УстановитьНастройкиВнедрения. -Процедура ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, ТипыСсылок, ИменаТипов, ИмяОпределяемогоТипа) - - НастройкиВнедрения.Вставить(ИмяОпределяемогоТипа, ""); - Если ИменаТипов.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - НастройкиВнедрения[ИмяОпределяемогоТипа] = СписокТиповИзМассива(ИменаТипов, - ТипыСсылок, ТипыТаблицПоИменам, Метаданные.ОпределяемыеТипы[ИмяОпределяемогоТипа].Тип); - -КонецПроцедуры - -// Для процедур УстановитьНастройкиВнедрения, ДобавитьТипыТребуемыеВОпределяемомТипе. -Функция СписокТиповИзМассива(ИменаТипов, ТипыСсылок, ТипыТаблицПоИменам, ОписаниеТипов) - - СписокТипов = ""; - Для Каждого ИмяТипа Из ИменаТипов Цикл - Если ТипЗнч(ИмяТипа) = Тип("Тип") Тогда - Тип = ИмяТипа; - Иначе - Тип = Тип(ИмяТипа); - КонецЕсли; - ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); - Если ОбъектМетаданных = Неопределено Тогда - ИмяТипа = Строка(Тип); - Иначе - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - ИмяТипа = ?(ТипыСсылок, ИмяТипаСсылки(ПолноеИмя, ТипыТаблицПоИменам), - ИмяТипаОбъектаИлиНабораЗаписей(ПолноеИмя, ТипыТаблицПоИменам)); - КонецЕсли; - - СписокТипов = СписокТипов + ?(СписокТипов = "", "", Символы.ПС) + "- " + ИмяТипа; - - Если ОписаниеТипов.СодержитТип(Тип) Тогда - СписокТипов = СписокТипов + " (" + НСтр("ru = 'уже добавлен'") + ")"; - КонецЕсли; - КонецЦикла; - - Возврат СписокТипов; - -КонецФункции - -// Для функции РезультатПроверкиОграниченияДоступаОбъекта. -Функция СтруктураРезультатаПроверкиОграниченияДляВидаПользователей() - - Свойства = Новый Структура; - Свойства.Вставить("ПроверяемоеОграничение"); - Свойства.Вставить("ОписаниеОшибок"); - Свойства.Вставить("ОшибкаФормированияПараметровОграничения"); - Свойства.Вставить("ОшибкаФормированияТекстовЗапросов"); - Свойства.Вставить("ОграничениеПоВладельцуВозможно"); - Свойства.Вставить("ОграничениеПоВладельцуИспользуется"); - Свойства.Вставить("ОграничениеВРолях"); - Свойства.Вставить("ОграничениеВМодуле"); - Свойства.Вставить("ПоВладельцуБезЗаписиКлючейДоступа"); - - Возврат Свойства; - -КонецФункции - -// Для функции РезультатПроверкиОграниченияДоступаОбъекта. -Процедура ПроверитьОграничениеДляВидаПользователей(Контекст, Результат, ДляВнешнихПользователей, ДополнительныйКонтекст) - - ТекстОграничения = ?(ДляВнешнихПользователей, Контекст.ОбщийРезультат.ДляВнешнихПользователей, - Контекст.ОбщийРезультат.ДляПользователей).ПроверяемоеОграничение; - - СтруктураОграничения = РассчитаннаяСтруктураОграничения(Контекст.ПолноеИмя, - ТекстОграничения, Контекст.ОбщийРезультат.ТекстВМодулеМенеджера, ДляВнешнихПользователей, Истина); - - Если СтруктураОграничения <> Неопределено - И СтруктураОграничения.ОписаниеОшибок.ЕстьОшибки Тогда - - Результат.ОписаниеОшибок = СтруктураОграничения.ОписаниеОшибок; - Контекст.УчетЗависимостейДоступен = Ложь; - Возврат; - КонецЕсли; - - ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); - ДобавитьДополнительныйКонтекст(Контекст.ПолноеИмя, - ДополнительныйКонтекст, Контекст.ОписаниеОграничения, ДляВнешнихПользователей); - - ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); - ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); - - Попытка - ПараметрыОграничения = ПараметрыОграниченияПоСтруктуреОграничения(Контекст.ПолноеИмя, - СтруктураОграничения, ДляВнешнихПользователей, Контекст.ОбщийКонтекст, ДополнительныйКонтекст); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ПараметрыОграничения = Неопределено; - Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда - Результат.ОшибкаФормированияПараметровОграничения = ОшибкаПриВызовеИсключения.Текст; - Иначе - Результат.ОшибкаФормированияПараметровОграничения = - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось сформировать параметры ограничения доступа по причине: - |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецЕсли; - Контекст.УчетЗависимостейДоступен = Ложь; - КонецПопытки; - - Если ПараметрыОграничения <> Неопределено Тогда - Результат.ОграничениеПоВладельцуВозможно = ПараметрыОграничения.ПолеВладельца <> Неопределено; - ПараметрыОграничения.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; - УстановитьСвойстваЗаписиКлючейДоступа(ПараметрыОграничения); - ПараметрыОграничения.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); - ПараметрыОграничения.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); - Для Каждого КлючИЗначение Из ПараметрыОграничения.ВедущиеСписки.ПоЗначениямПолей Цикл - Контекст.ВедущиеСписки.Вставить(КлючИЗначение.Ключ, Неопределено); - КонецЦикла; - Для Каждого КлючИЗначение Из ПараметрыОграничения.ВедущиеСписки.ПоКлючамДоступа Цикл - Контекст.ВерсииОграниченийСписков.Вставить(КлючИЗначение.Ключ, Неопределено); - КонецЦикла; - Попытка - ДобавитьТекстыЗапросовВПараметрыОграничения(ПараметрыОграничения); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда - Результат.ОшибкаФормированияТекстовЗапросов = ОшибкаПриВызовеИсключения.Текст; - Иначе - Результат.ОшибкаФормированияТекстовЗапросов = - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа по причине: - |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - КонецЕсли; - Контекст.УчетЗависимостейДоступен = Ложь; - КонецПопытки; - КонецЕсли; - - Если Контекст.УчитыватьЗависимости Тогда - Возврат; - КонецЕсли; - - СокращенныеСвойства = Новый Структура; - СокращенныеСвойства.Вставить("ДоступЗапрещен", Ложь); - СокращенныеСвойства.Вставить("ПолеВладельца", Неопределено); - СокращенныеСвойства.Вставить("ОпорныеПоля", Неопределено); - СокращенныеСвойства.Вставить("ИмяОтдельногоРегистраКлючей", Неопределено); - ДополнительныйКонтекст.СвойстваОграниченияСписков.Вставить(Контекст.ПолноеИмя, СокращенныеСвойства); - - Если Не Контекст.УчетЗависимостейДоступен Тогда - Возврат; - КонецЕсли; - - ЗаполнитьЗначенияСвойств(СокращенныеСвойства, ПараметрыОграничения); - -КонецПроцедуры - -// Для функций ХранимыеПараметрыОграниченияДоступа, РассчитанныеПараметрыОграничения. -Функция ОбщаяВерсия(ОбщийКонтекст, ПолноеИмя, ВерсияДляПользователей, ВерсияДляВнешнихПользователей) - - Если ОбщийКонтекст.СпискиСОграничением.Получить(ПолноеИмя) = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - - Возврат СтрПолучитьСтроку(ВерсияДляПользователей, 1) - + Символы.ПС + СтрПолучитьСтроку(ВерсияДляВнешнихПользователей, 1) - + Символы.ПС + СтрПолучитьСтроку(ВерсияДляПользователей, 2) - + Символы.ПС + СтрПолучитьСтроку(ВерсияДляВнешнихПользователей, 2) - -КонецФункции - -// Для функции РассчитанныеПараметрыОграничения. -Процедура УстановитьСвойстваЗаписиКлючейДоступа(Результат) - - БезЗаписиКлючей = Ложь; - СЗаписьюКлючаДляЗависимыхСписковБезКлючей = Ложь; - - Если Результат.ОграничениеОтключено - Или Результат.ДоступЗапрещен - Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда - - Если Результат.ИспользуетсяОграничениеПоВладельцу - Или Результат.Контекст.БезОбъектаМетаданных - Или Результат.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить( - Результат.Список) = Неопределено Тогда - - БезЗаписиКлючей = Истина; - Иначе - СЗаписьюКлючаДляЗависимыхСписковБезКлючей = Истина; - КонецЕсли; - КонецЕсли; - - Результат.Вставить("БезЗаписиКлючейДоступа", БезЗаписиКлючей); - Результат.Вставить("СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей", - СЗаписьюКлючаДляЗависимыхСписковБезКлючей); - -КонецПроцедуры - -// Для функций РассчитанныеПараметрыОграничения, ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * Текст - Строка -// * ТекстДляВнешнихПользователей - Строка -// * ПоВладельцуБезЗаписиКлючейДоступа - Булево -// - Неопределено -// * ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей - Булево -// - Неопределено -// * ТекстВМодулеМенеджера - Булево -// -Функция ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, БезВызоваИсключения = Ложь) - - Ограничение = Новый Структура; - Ограничение.Вставить("Текст", ""); - Ограничение.Вставить("ТекстДляВнешнихПользователей", ""); - Ограничение.Вставить("ПоВладельцуБезЗаписиКлючейДоступа", Неопределено); - Ограничение.Вставить("ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", Неопределено); - Ограничение.Вставить("ТекстВМодулеМенеджера", Ложь); - - ТекстВМодулеМенеджера = ОбщийКонтекст.СпискиСОграничением.Получить(ПолноеИмя); - Если ТекстВМодулеМенеджера = Неопределено Тогда - Возврат Ограничение; - КонецЕсли; - - Ограничение.ТекстВМодулеМенеджера = ТекстВМодулеМенеджера; - - Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда - МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный"); - ЭтоСправочникФайлов = МодульРаботаСФайламиСлужебный.ЭтоСправочникФайловИлиВерсийФайлов(ПолноеИмя); - Иначе - ЭтоСправочникФайлов = Ложь; - КонецЕсли; - - Если ЭтоЖурналДокументов(ПолноеИмя) Или ЭтоСправочникФайлов Тогда - // Для журналов документов ограничение должно быть - // по документу-владельцу без записи ключей доступа, если не требуется другое. - // Аналогично (по умолчанию) для справочников файлов и версий файлов. - Ограничение.ПоВладельцуБезЗаписиКлючейДоступа = Истина; - Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей = Истина; - КонецЕсли; - - Если ТекстВМодулеМенеджера Тогда - Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя); - - Попытка - Менеджер.ПриЗаполненииОграниченияДоступа(Ограничение); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре - |%2 общего модуля %3. - | - |Некорректно указано ограничение доступа этого списка в модуле менеджера - |в процедуре %4 по причине: - | - |%5'"), - ПолноеИмя, - "ПриЗаполненииСписковСОграничениемДоступа", - "УправлениеДоступомПереопределяемый", - "ПриЗаполненииОграниченияДоступа", - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - - Если БезВызоваИсключения Тогда - Возврат ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецПопытки; - Иначе - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); - Попытка - УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа(ОбъектМетаданных, Ограничение); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре - |%2 общего модуля %3. - | - |Некорректно указано ограничение доступа этого списка в общем модуле %4 - |в процедуре %5 по причине: - | - |%6'"), - ПолноеИмя, - "ПриЗаполненииСписковСОграничениемДоступа", - "УправлениеДоступомПереопределяемый", - "УправлениеДоступомПереопределяемый", - "ПриЗаполненииОграниченияДоступа", - ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); - - Если БезВызоваИсключения Тогда - Возврат ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецПопытки; - КонецЕсли; - - Если ЭтоЖурналДокументов(ПолноеИмя) - И ( Ограничение.ПоВладельцуБезЗаписиКлючейДоступа <> Истина - Или Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей <> Истина) Тогда - - Если ВариантВстроенногоЯзыкаРусский() Тогда - ШаблонОграничения = - "РазрешитьЧтениеИзменение - |ГДЕ - | ЧтениеОбъектаРазрешено(Ссылка)"; // @Non-NLS - Иначе - ШаблонОграничения = - "AllowReadWrite - |WHERE - | ObjectReadingAllowed(Ref)"; - КонецЕсли; - - Если ТекстВМодулеМенеджера Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре - |%2 общего модуля %3. - | - |Некорректно указано ограничение доступа этого списка в модуле менеджера - |в процедуре %4 по причине: - | - |Для журналов документов не поддерживается ограничение, как для регистров, - |то есть, кроме варианта ограничения по владельцу без записи ключей доступа: - | - |%5'"), - ПолноеИмя, - "ПриЗаполненииСписковСОграничениемДоступа", - "УправлениеДоступомПереопределяемый", - "ПриЗаполненииОграниченияДоступа", - ШаблонОграничения); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре - |%2 общего модуля %3. - | - |Некорректно указано ограничение доступа этого списка в общем модуле %4 - |в процедуре %5 по причине: - | - |Для журналов документов не поддерживается ограничение, как для регистров, - |то есть, кроме варианта ограничения по владельцу без записи ключей доступа: - | - |%6'"), - ПолноеИмя, - "ПриЗаполненииСписковСОграничениемДоступа", - "УправлениеДоступомПереопределяемый", - "УправлениеДоступомПереопределяемый", - "ПриЗаполненииОграниченияДоступа", - ШаблонОграничения); - КонецЕсли; - Если БезВызоваИсключения Тогда - Возврат ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Возврат Ограничение; - -КонецФункции - -// Для функции ОписаниеОграниченияДанных. -Функция ЭтоЖурналДокументов(ПолноеИмя) - - Возврат СтрНачинаетсяС(ВРег(ПолноеИмя), ВРег("ЖурналДокументов.")) - Или СтрНачинаетсяС(ВРег(ПолноеИмя), ВРег("DocumentJournal.")); // @Non-NLS - -КонецФункции - -// Для функций РассчитанныеПараметрыОграничения и ПараметрыОграниченияДляВидаПользователей. -// -// Возвращаемое значение: -// см. СтруктураОграничения -// -Функция РассчитаннаяСтруктураОграничения(ПолноеИмя, ТекстОграничения, ТекстВМодулеМенеджера, ДляВнешнихПользователей, БезИсключения = Ложь) - - Если Не ЗначениеЗаполнено(ТекстОграничения) Тогда - Возврат Неопределено; - КонецЕсли; - - РазобранноеОграничение = РазобранноеОграничение(ПолноеИмя, ТекстОграничения); - - ПроверитьТаблицыПоляИТипыПолей(РазобранноеОграничение); - - СтруктураОграничения = СтруктураОграничения(РазобранноеОграничение); - - Если БезИсключения Или Не СтруктураОграничения.ОписаниеОшибок.ЕстьОшибки Тогда - Возврат СтруктураОграничения; - КонецЕсли; - - ТекстОшибок = ТекстОшибокДляВызоваИсключения(ПолноеИмя, - СтруктураОграничения.ОписаниеОшибок, ДляВнешнихПользователей, ТекстВМодулеМенеджера); - - ВызватьИсключение ТекстОшибок; - -КонецФункции - -// Для функций СвойстваСпискаКакВедущего, ПараметрыОграничения и процедур УстановкаПараметровСеанса, -// ЗаполнитьПараметрыОграничения, ДобавитьПараметрыОграниченияСписка. -// -// Возвращаемое значение: -// см. НоваяСтруктураХранимыхПараметровЗаписи -// -Функция ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, - Обновить, УстановкаПараметровСеансаДляШаблонов = Ложь, - УстановкаПараметровДляОтчетаПраваДоступа = Ложь, ЕстьИзменения = Ложь) Экспорт - - Если Обновить Тогда - ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст, ЕстьИзменения); - УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст); - ПараметрыОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа - Возврат ПараметрыОграниченияДоступа.Параметры; - КонецЕсли; - - ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа - - Если Не ТекущиеПараметры.Свойство("Параметры") Или ТекущиеПараметры.Параметры = Неопределено Тогда - ТекущиеПараметры = Новый Структура("Версия, ХешСумма", "", ""); // См. СеансовыеПараметрыОграниченияДоступа - ИдентификаторыТранзакции = Новый Соответствие; - Иначе - ИдентификаторыТранзакции = КэшПараметровОграничения().ИдентификаторыТранзакции; - КонецЕсли; - - Если ТранзакцияАктивна() - И ИдентификаторыТранзакции.Получить(ИдентификаторТранзакции) <> Неопределено Тогда - - Возврат ТекущиеПараметры.Параметры; - КонецЕсли; - - Пока Истина Цикл - ОписаниеВерсии = ОписаниеПоследнейВерсии(); - Если ТекущиеПараметры.Версия = ОписаниеВерсии.Версия - И ТекущиеПараметры.ХешСумма = ОписаниеВерсии.ХешСумма Тогда - Прервать; - КонецЕсли; - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - Прервать; - КонецЕсли; - Если ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() Тогда - Прервать; - КонецЕсли; - КонецЦикла; - - Если Не УстановкаПараметровСеансаДляШаблонов - И Не УстановкаПараметровДляОтчетаПраваДоступа - И ТекущиеПараметры.Версия = ОписаниеВерсии.Версия - И ТекущиеПараметры.ХешСумма = ОписаниеВерсии.ХешСумма Тогда - - ОбновитьИдентификаторыТранзакции(ИдентификаторТранзакции); - Возврат ТекущиеПараметры.Параметры; - КонецЕсли; - - // Параметры в базе данных отличаются от параметров в памяти. - Если ЗначениеЗаполнено(ОписаниеВерсии.Версия) Тогда - ВерсияПараметров = ВерсияПараметров(ОписаниеВерсии.Версия, - УстановкаПараметровСеансаДляШаблонов, УстановкаПараметровДляОтчетаПраваДоступа); - Иначе - ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); - КонецЕсли; - - УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, - УстановкаПараметровСеансаДляШаблонов); - - ПараметрыОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа - Возврат ПараметрыОграниченияДоступа.Параметры; - -КонецФункции - -// Для отчета ПраваДоступа. -// -// Возвращаемое значение: -// Структура: -// * ДляПользователей - Строка -// * ДляВнешнихПользователей - Строка -// -Функция ВсеВидыОграниченийПравДляОтчетаПраваДоступа() - - Кэш = КэшПараметровОграничения(); - - Если Кэш.ВидыОграниченийПравДляПользователей <> Неопределено - И Кэш.ВидыОграниченийПравДляВнешнихПользователей <> Неопределено Тогда - Возврат Новый Структура("ДляПользователей, ДляВнешнихПользователей", - Кэш.ВидыОграниченийПравДляПользователей, - Кэш.ВидыОграниченийПравДляВнешнихПользователей); - КонецЕсли; - - ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь, Ложь, Истина); - - Возврат ВсеВидыОграниченийПравДляОтчетаПраваДоступа(); - -КонецФункции - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -Функция ЗаписьПараметровОграниченияДоступаВТекущемСеансе() - - УстановитьПривилегированныйРежим(Истина); - ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; - УстановитьПривилегированныйРежим(Ложь); - - Возврат ТекущиеПараметры.Свойство("ЗаписьПараметровОграниченияДоступаВТекущемСеансе"); - -КонецФункции - -// Для функций ДействующиеПараметрыОграниченияДоступа, НоваяВерсияПараметровОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * Версия - Число -// - Неопределено -// * ХешСумма - Строка -// - Неопределено -// * ДатаСоздания - Дата -// - Неопределено -// * ВерсииПараметровШаблонов - ХранилищеЗначения -// - Неопределено -// -Функция ОписаниеПоследнейВерсии(ПрочитатьВерсииПараметровШаблонов = Ложь) - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ПараметрыОграниченияДоступа.Версия КАК Версия, - | ПараметрыОграниченияДоступа.ХешСумма КАК ХешСумма, - | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания, - | ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов КАК ВерсииПараметровШаблонов - |ИЗ - | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа - | - |УПОРЯДОЧИТЬ ПО - | ПараметрыОграниченияДоступа.Версия УБЫВ"; - - Если Не ПрочитатьВерсииПараметровШаблонов Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов", "Неопределено"); - КонецЕсли; - - Выборка = Запрос.Выполнить().Выбрать(); - Выборка.Следующий(); - - Результат = Новый Структура("Версия, ХешСумма, ДатаСоздания, ВерсииПараметровШаблонов"); - ЗаполнитьЗначенияСвойств(Результат, Выборка); - - Возврат Результат; - -КонецФункции - -// Для функции ДействующиеПараметрыОграниченияДоступа. -Функция ВерсияПараметров(Версия, УстановкаПараметровСеансаДляШаблонов, УстановкаПараметровДляОтчетаПраваДоступа) - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ПараметрыОграниченияДоступа.Версия КАК Версия, - | ПараметрыОграниченияДоступа.ХешСумма КАК ХешСумма, - | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания, - | ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей КАК ДляШаблоновВСеансахПользователей, - | ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей КАК ДляШаблоновВСеансахВнешнихПользователей, - | ПараметрыОграниченияДоступа.ДляЗаписиОбъектовИПроверкиПрав КАК ДляЗаписиОбъектовИПроверкиПрав, - | ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов КАК ВерсииПараметровШаблонов, - | ПараметрыОграниченияДоступа.ДляОтчетаПоПравамДоступа КАК ДляОтчетаПоПравамДоступа - |ИЗ - | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа - |ГДЕ - | ПараметрыОграниченияДоступа.Версия = &Версия"; - - Если УстановкаПараметровСеансаДляШаблонов Или УстановкаПараметровДляОтчетаПраваДоступа Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ПараметрыОграниченияДоступа.ДляЗаписиОбъектовИПроверкиПрав", "Неопределено"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов", "Неопределено"); - КонецЕсли; - Если Не УстановкаПараметровДляОтчетаПраваДоступа Тогда - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ПараметрыОграниченияДоступа.ДляОтчетаПоПравамДоступа", "Неопределено"); - КонецЕсли; - - Если УстановкаПараметровСеансаДляШаблонов - Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда - - Запрос.Текст = СтрЗаменить(Запрос.Текст, ?(Пользователи.ЭтоСеансВнешнегоПользователя(), - "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей", - "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей"), "Неопределено"); - Иначе - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей", "Неопределено"); - Запрос.Текст = СтрЗаменить(Запрос.Текст, - "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей", "Неопределено"); - КонецЕсли; - - Запрос.УстановитьПараметр("Версия", Версия); - - Выборка = Запрос.Выполнить().Выбрать(); - Выборка.Следующий(); - - Возврат Выборка; - -КонецФункции - -// Для функции ДействующиеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// см. ХранимыеПараметрыОграниченияДоступа -// -Функция НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст, ЕстьИзменения = Ложь) - - Попытка - ПроверитьАктуальностьМетаданных(); - Исключение - Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда - ЗапланироватьОбновлениеПараметровОграниченияДоступа( - "НоваяВерсияПараметровОграниченияДоступа", Истина); - КонецЕсли; - ВызватьИсключение; - КонецПопытки; - - УдалитьСтрокиВерсииХранимыхПараметров = Ложь; - - Если ТипЗнч(ОбщийКонтекст) <> Тип("Структура") - Или ЗначениеЗаполнено(ОбщийКонтекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы) Тогда - ОбновитьПовторноИспользуемыеЗначения(); - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); - КонецЕсли; - - Если РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() Тогда - Если Не ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - ОбщийКонтекст.Вставить("СтрокиВерсииХранимыхПараметров"); - УдалитьСтрокиВерсииХранимыхПараметров = Истина; - КонецЕсли; - КонецЕсли; - - ВерсииОграниченийСписков = Новый Соответствие; - ОбщийКонтекст.Вставить("ИнформацияДляЖурнала", НоваяИнформацияНесоответствияПараметровДляЖурнала()); - ХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст, ВерсииОграниченийСписков); - ВерсииОграниченийСписков.Вставить("Справочник.НаборыГруппДоступа", "1"); - - ПараметрыЗаписи = Новый Структура; - ПараметрыЗаписи.Вставить("ВерсииОграниченийСписков", ВерсииОграниченийСписков); - ПараметрыЗаписи.Вставить("ИдентификаторыВсехСписков"); - ПараметрыЗаписи.Вставить("ХранимыеПараметры", ХранимыеПараметры); - ПараметрыЗаписи.Вставить("ИдентификаторДоступа", ИдентификаторДоступа()); - ПараметрыЗаписи.Вставить("ИнформацияДляЖурнала", ОбщийКонтекст.ИнформацияДляЖурнала); - ОбщийКонтекст.Удалить("ИнформацияДляЖурнала"); - - Если ОбщийКонтекст.Свойство("СпискиСУстаревшимиВариантамиДоступа") Тогда - ПараметрыЗаписи.Вставить("СпискиСУстаревшимиВариантамиДоступа", - ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа); - Иначе - ПараметрыЗаписи.Вставить("СпискиСУстаревшимиВариантамиДоступа"); - КонецЕсли; - - Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - ПараметрыЗаписи.Вставить("СтрокиВерсии", ОбщийКонтекст.СтрокиВерсииХранимыхПараметров); - КонецЕсли; - - Если Не ТранзакцияАктивна() - Или МонопольныйРежим() - Или ОбщийКонтекст.Свойство("ЗаписатьВТекущейТранзакции") - Или ОбщегоНазначения.ИнформационнаяБазаФайловая() - Или СтандартныеПодсистемыСервер.ЭтоРазделенныйРежимСеансаБезРазделителей() - Или ЗаписьПараметровОграниченияДоступаВТекущемСеансе() Тогда - - НомерПопыткиБлокировки = 0; - Пока Истина Цикл - НомерПопыткиБлокировки = НомерПопыткиБлокировки + 1; - ЭтоОшибкаБлокировки = Ложь; - Попытка - ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа(ПараметрыЗаписи,, ЭтоОшибкаБлокировки); - Исключение - Если ЭтоОшибкаБлокировки - И НомерПопыткиБлокировки < 3 - И Не ТранзакцияАктивна() Тогда - Продолжить; - КонецЕсли; - Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда - ЗапланироватьОбновлениеПараметровОграниченияДоступа( - "НоваяВерсияПараметровОграниченияДоступа", Истина); - КонецЕсли; - ВызватьИсключение; - КонецПопытки; - Прервать; - КонецЦикла; - Иначе - ПараметрыЗаписиВХранилище = Новый ХранилищеЗначения(ПараметрыЗаписи); - ОписаниеВерсии = Неопределено; - Пока Истина Цикл - ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа( - ПараметрыЗаписиВХранилище.Получить(), Истина); - Если ОписаниеВерсии <> Неопределено Тогда - Прервать; - КонецЕсли; - Если ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() Тогда - Прервать; - КонецЕсли; - КонецЦикла; - Если ОписаниеВерсии = Неопределено Тогда - ПараметрыЗаписи.ИдентификаторыВсехСписков = ИдентификаторыВсехСписков(); - ПараметрыЗаписиВХранилище = Новый ХранилищеЗначения(ПараметрыЗаписи); - ИмяПроцедуры = ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа(); - АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено); - ПараметрыПроцедуры = Новый Массив; - ПараметрыПроцедуры.Добавить(АдресРезультата); - ПараметрыПроцедуры.Добавить(ПараметрыЗаписиВХранилище); - ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); - НаименованиеЗадания = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Управление доступом: Запись новой версии параметров ограничения доступа (из сеанса %1 от %2)'", - ОбщегоНазначения.КодОсновногоЯзыка()), - Формат(ТекущийСеанс.НомерСеанса, "ЧГ="), - Формат(ТекущийСеанс.НачалоСеанса, "ДЛФ=DT")); - ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяПроцедуры, ПараметрыПроцедуры,, НаименованиеЗадания); - ФоновоеЗадание = ФоновоеЗадание.ОжидатьЗавершенияВыполнения(60); - Результат = ПолучитьИзВременногоХранилища(АдресРезультата); - ЗаголовокОшибки = НСтр("ru = 'Не удалось записать новую версию параметров ограничения доступа по причине:'"); - Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда - ФоновоеЗадание.Отменить(); - ТекстОшибки = ЗаголовокОшибки + Символы.ПС - + НСтр("ru = 'Фоновое задание выполняется более 60 секунд, поэтому отменено.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Отменено Тогда - ТекстОшибки = ЗаголовокОшибки + Символы.ПС - + НСтр("ru = 'Фоновое задание отменено администратором.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Если ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Завершено Тогда - Если ТипЗнч(ФоновоеЗадание.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда - ТекстОшибки = ЗаголовокОшибки + Символы.ПС - + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ФоновоеЗадание.ИнформацияОбОшибке); - Иначе - ТекстОшибки = ЗаголовокОшибки + Символы.ПС - + НСтр("ru = 'Фоновое задание завершилось аварийно.'"); - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Если ТипЗнч(Результат) <> Тип("Структура") Тогда - ТекстОшибки = ЗаголовокОшибки + Символы.ПС - + НСтр("ru = 'Фоновое задание не вернуло результат.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Если Результат.ТребуетсяПерезапускСеанса Тогда - ЗапланироватьОбновлениеПараметровОграниченияДоступа( - "НоваяВерсияПараметровОграниченияДоступа", Истина); - ПроверитьАктуальностьМетаданных(); - СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(Результат.ТекстОшибки); - ВызватьИсключение Результат.ТекстОшибки; - КонецЕсли; - Если ЗначениеЗаполнено(Результат.ТекстОшибки) Тогда - ТекстОшибки = ЗаголовокОшибки + Символы.ПС + Результат.ТекстОшибки; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ОписаниеВерсии = Результат.ОписаниеВерсии; - КонецЕсли; - КонецЕсли; - - Если ОбщийКонтекст.Свойство("СпискиСУстаревшимиВариантамиДоступа") Тогда - ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа = - ОписаниеВерсии.СпискиСУстаревшимиВариантамиДоступа; - КонецЕсли; - - Если УдалитьСтрокиВерсииХранимыхПараметров Тогда - ОбщийКонтекст.Удалить("СтрокиВерсииХранимыхПараметров"); - - ИначеЕсли ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - ОбщийКонтекст.СтрокиВерсииХранимыхПараметров = ОписаниеВерсии.СтрокиВерсии; - КонецЕсли; - - Если ОписаниеВерсии.ЕстьИзменения Тогда - ЕстьИзменения = Истина; - КонецЕсли; - - Для Каждого КлючИЗначение Из ОписаниеВерсии.ЗаполняемыеСвойстваВерсии Цикл - ХранимыеПараметры.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - - Возврат ХранимыеПараметры; - -КонецФункции - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -Функция ИдентификаторыВсехСписков() - - Списки = Новый Массив; - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыОбмена); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Справочники); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Документы); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ЖурналыДокументов); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыВидовХарактеристик); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыСчетов); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыВидовРасчета); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыСведений); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыНакопления); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыБухгалтерии); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыРасчета); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.БизнесПроцессы); - ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Задачи); - - Возврат ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки); - -КонецФункции - -// Для функции ИдентификаторыВсехСписков. -Процедура ДобавитьПолныеИменаКоллекции(Списки, КоллекцияОбъектовМетаданных) - - Для Каждого ОбъектМетаданных Из КоллекцияОбъектовМетаданных Цикл - Списки.Добавить(ОбъектМетаданных.ПолноеИмя()); - КонецЦикла; - -КонецПроцедуры - -// Для функций НоваяВерсияПараметровОграниченияДоступа и -// ДействующиеПараметрыОграниченияДоступа. -// -Функция ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() - - ОтборЗаданий = Новый Структура("ИмяМетода, Состояние", - ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа(), - СостояниеФоновогоЗадания.Активно); - - НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(ОтборЗаданий); - - Если НайденныеЗадания.Количество() = 0 Тогда - Возврат Истина; - КонецЕсли; - - ФоновыеЗадания.ОжидатьЗавершенияВыполнения(НайденныеЗадания, 1); - - Возврат Ложь; - -КонецФункции - -// Для функций НоваяВерсияПараметровОграниченияДоступа и -// ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа. -// -Функция ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() - - Возврат "УправлениеДоступомСлужебный.ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне"; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// Предупреждение - Строка -// Ошибка - Строка -// ВерсияТекстовОграниченияДоступа - Строка -// -Функция НоваяИнформацияНесоответствияПараметровДляЖурнала() - - Результат = Новый Структура; - Результат.Вставить("Предупреждение", ""); - Результат.Вставить("Ошибка", ""); - Результат.Вставить("ВерсияТекстовОграниченияДоступа", ""); - - Возврат Результат; - -КонецФункции - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -Процедура ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне(АдресРезультата, ХранилищеПараметров) Экспорт - - ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( - "УправлениеДоступомСлужебный.ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне"); - - Результат = Новый Структура; - Результат.Вставить("ОписаниеВерсии", Новый Структура); - Результат.Вставить("ТекстОшибки", ""); - Результат.Вставить("ТребуетсяПерезапускСеанса", Ложь); - - УстановитьПривилегированныйРежим(Истина); - Попытка - Параметры = ХранилищеПараметров.Получить(); - Если Параметры.ИдентификаторДоступа = ИдентификаторДоступа() Тогда - Результат.ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа(Параметры); - Иначе - Результат.ТекстОшибки = НСтр("ru = 'Ошибка проверки доступа.'"); - КонецЕсли; - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(Результат.ТекстОшибки) Тогда - Результат.ТребуетсяПерезапускСеанса = Истина; - КонецЕсли; - Если Не Результат.ТребуетсяПерезапускСеанса - Или Не СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда - Результат.ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); - КонецЕсли; - КонецПопытки; - УстановитьПривилегированныйРежим(Ложь); - - ПоместитьВоВременноеХранилище(Результат, АдресРезультата); - -КонецПроцедуры - -// Для функции НоваяВерсияПараметровОграниченияДоступа и -// процедуры ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне. -// -Функция ИдентификаторДоступа() - - Возврат ПоследнееОбновлениеДоступа().ИдентификаторДоступа; - -КонецФункции - -// Для функции НоваяВерсияПараметровОграниченияДоступа и -// процедуры ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне. -// -Функция ОписаниеНовойВерсииПараметровОграниченияДоступа(Параметры, БезЗаписи = Ложь, ЭтоОшибкаБлокировки = Ложь) - - Запись = НоваяТаблицаРегистраСведенийПараметрыОграниченияДоступа().Добавить(); - ЗаполнитьЗначенияСвойств(Запись, Параметры.ХранимыеПараметры); - - ЗаполняемыеСвойстваВерсии = Новый Структура("Версия, ДатаСоздания, ХешСумма, - |ВерсииПараметровШаблонов, ХешСуммаПостоянныхПараметров, ХешСуммаПараметровШаблонов, - |ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей"); - - Результат = Новый Структура; - Результат.Вставить("ЕстьИзменения", Ложь); - Результат.Вставить("ЗаполняемыеСвойстваВерсии", ЗаполняемыеСвойстваВерсии); - Результат.Вставить("СпискиСУстаревшимиВариантамиДоступа", - Параметры.СпискиСУстаревшимиВариантамиДоступа); - Параметры.Вставить("СпискиСНовымОсновнымВариантомДоступа", Новый Массив); - Если Параметры.Свойство("СтрокиВерсии") Тогда - Результат.Вставить("СтрокиВерсии", Параметры.СтрокиВерсии); - КонецЕсли; - - Если БезЗаписи Тогда - ОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); - ЗаполнитьПараметрыДляШаблонов(Запись, Параметры, ОписаниеВерсии); - Если ОписаниеВерсии.ХешСумма <> Запись.ХешСумма Тогда - Возврат Неопределено; - КонецЕсли; - Иначе - НачатьТранзакцию(); - Попытка - Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда - ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(ЭтоОшибкаБлокировки, Истина); - КонецЕсли; - ОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); - Пока Истина Цикл - ЗаполнитьПараметрыДляШаблонов(Запись, Параметры, ОписаниеВерсии); - Если ОписаниеВерсии.ХешСумма = Запись.ХешСумма Тогда - Прервать; - КонецЕсли; - - ПроверитьАктуальностьМетаданных(); - - Если ЗначениеЗаполнено(ОписаниеВерсии.Версия) Тогда - НоваяВерсия = ОписаниеВерсии.Версия + 1; - Иначе - НоваяВерсия = 1; - КонецЕсли; - - БлокировкаДанных = Новый БлокировкаДанных; - ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); - ЭлементБлокировки.УстановитьЗначение("Версия", НоваяВерсия); - БлокировкаДанных.Заблокировать(); - НовоеОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); - - Если ОписаниеВерсии.Версия <> НовоеОписаниеВерсии.Версия - Или НовоеОписаниеВерсии.Версия = НоваяВерсия Тогда - - ОписаниеВерсии = НовоеОписаниеВерсии; - Продолжить; - КонецЕсли; - - ПроверитьАктуальностьМетаданных(); - - Запись.Версия = НоваяВерсия; - - НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ПараметрыОграниченияДоступа); - ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), Запись); - Запись = НаборЗаписей[0]; - НаборЗаписей.Отбор.Версия.Установить(НоваяВерсия); - ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, Запись); - - ЗапланироватьОбновлениеДоступаПриИзмененииПараметров(ОписаниеВерсии.Версия, Параметры); - НаборЗаписей.Записать(); - Результат.ЕстьИзменения = Истина; - - ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Параметры.ИнформацияДляЖурнала.Предупреждение); - ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Параметры.ИнформацияДляЖурнала.Ошибка, Истина); - - Если РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() Тогда - ЗарегистрироватьСтрокуВерсииПараметровОграниченияДоступа(НаборЗаписей[0], - Параметры.СтрокиВерсии); - КонецЕсли; - - Прервать; - КонецЦикла; - ЗафиксироватьТранзакцию(); - Исключение - ОтменитьТранзакцию(); - ВызватьИсключение; - КонецПопытки; - КонецЕсли; - - Если Не Результат.ЕстьИзменения Тогда - ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, ОписаниеВерсии, - "Версия, ДатаСоздания, ХешСумма, ВерсииПараметровШаблонов"); - ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, Запись, - "ХешСуммаПостоянныхПараметров, ХешСуммаПараметровШаблонов, - |ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей"); - ИначеЕсли Не ТранзакцияАктивна() Тогда - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ТекущаяДатаСеанса(), Истина); - ВерсияТекстов = Параметры.ИнформацияДляЖурнала.ВерсияТекстовОграниченияДоступа; - ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; - СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ВерсияТекстов, Истина); - УстановитьОбновлениеДоступа(Истина); - КонецЕсли; - - Возврат Результат; - -КонецФункции - -// Возвращаемое значение: -// ТаблицаЗначений: -// * Версия - Число -// * ХешСумма - Строка -// * ХешСуммаПостоянныхПараметров - Строка -// * ДляЗаписиОбъектовИПроверкиПрав - ХранилищеЗначения -// * ДляОтчетаПоПравамДоступа - ХранилищеЗначения -// * ХешСуммаПараметровШаблонов - Строка -// * ДляШаблоновВСеансахПользователей - ХранилищеЗначения -// * ДляШаблоновВСеансахВнешнихПользователей - ХранилищеЗначения -// * ВерсииПараметровШаблонов - ХранилищеЗначения -// * ДатаСоздания - Дата -// -Функция НоваяТаблицаРегистраСведенийПараметрыОграниченияДоступа() - - ТипВерсии = Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(15, 0, ДопустимыйЗнак.Неотрицательный)); - ТипХешСуммы = Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(48, ДопустимаяДлина.Переменная)); - - Таблица = Новый ТаблицаЗначений; - Таблица.Колонки.Добавить("Версия", ТипВерсии); - Таблица.Колонки.Добавить("ХешСумма", ТипХешСуммы); - Таблица.Колонки.Добавить("ХешСуммаПостоянныхПараметров", ТипХешСуммы); - Таблица.Колонки.Добавить("ДляЗаписиОбъектовИПроверкиПрав", Новый ОписаниеТипов("ХранилищеЗначения")); - Таблица.Колонки.Добавить("ДляОтчетаПоПравамДоступа", Новый ОписаниеТипов("ХранилищеЗначения")); - Таблица.Колонки.Добавить("ХешСуммаПараметровШаблонов", ТипХешСуммы); - Таблица.Колонки.Добавить("ДляШаблоновВСеансахПользователей", Новый ОписаниеТипов("ХранилищеЗначения")); - Таблица.Колонки.Добавить("ДляШаблоновВСеансахВнешнихПользователей", Новый ОписаниеТипов("ХранилищеЗначения")); - Таблица.Колонки.Добавить("ВерсииПараметровШаблонов", Новый ОписаниеТипов("ХранилищеЗначения")); - Таблица.Колонки.Добавить("ДатаСоздания", Новый ОписаниеТипов("Дата")); - - Возврат Таблица; - -КонецФункции - -// Для функции ОписаниеНовойВерсииПараметровОграниченияДоступа. -Процедура ЗапланироватьОбновлениеДоступаПриИзмененииПараметров(СтараяВерсия, Параметры) - - НедоступныеСписки = Новый Массив; - СтараяВерсияСтруктурыКэша = "0"; - Списки = СпискиСИзменениемВерсий(СтараяВерсия, - Параметры.ВерсииОграниченийСписков, НедоступныеСписки, СтараяВерсияСтруктурыКэша); - - ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); - ПараметрыПланирования.ВерсииОграниченийСписков = Параметры.ВерсииОграниченийСписков; - ПараметрыПланирования.ИдентификаторыВсехСписков = Параметры.ИдентификаторыВсехСписков; - ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; - ПараметрыПланирования.Описание = "НоваяВерсияПараметровОграниченияДоступа"; - - ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; - ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); - - Если ЗначениеЗаполнено(НедоступныеСписки) Тогда - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Ложь; - ЗапланироватьОбновлениеДоступа(НедоступныеСписки, ПараметрыПланирования); - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; - ЗапланироватьОбновлениеДоступа(НедоступныеСписки, ПараметрыПланирования); - КонецЕсли; - - Если ЗначениеЗаполнено(Параметры.СпискиСНовымОсновнымВариантомДоступа) Тогда - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Ложь; - ЗапланироватьОбновлениеДоступа(Параметры.СпискиСНовымОсновнымВариантомДоступа, - ПараметрыПланирования); - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; - ЗапланироватьОбновлениеДоступа(Параметры.СпискиСНовымОсновнымВариантомДоступа, - ПараметрыПланирования); - КонецЕсли; - Если ЗначениеЗаполнено(Параметры.СпискиСУстаревшимиВариантамиДоступа) Тогда - ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; - ЗапланироватьОбновлениеДоступа(Параметры.СпискиСУстаревшимиВариантамиДоступа, - ПараметрыПланирования); - КонецЕсли; - - Если Списки = Неопределено - Или СтараяВерсияСтруктурыКэша = ВерсияСтруктурыКэша() Тогда - Возврат; - КонецЕсли; - - НовыеПараметры = Новый Структура(Параметры.ХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); - НовыеПараметры.Вставить("ИдентификаторыВсехСписков", Параметры.ИдентификаторыВсехСписков); - РегистрыСведений.ПараметрыОграниченияДоступа.ПриИзмененииВерсииСтруктурыКэша( - СтараяВерсияСтруктурыКэша, НовыеПараметры); - -КонецПроцедуры - -// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений и -// функции НоваяВерсияПараметровОграниченияДоступа. -// -Процедура ПроверитьАктуальностьМетаданных() Экспорт - - КонфигурацияИзменена = КонфигурацияБазыДанныхИзмененаДинамически(); - РасширенияИзменены = Справочники.ВерсииРасширений.РасширенияИзмененыДинамически(); - - Если Не КонфигурацияИзменена И Не РасширенияИзменены Тогда - Возврат; - КонецЕсли; - - Попытка - Попытка - Если КонфигурацияИзменена Тогда - СтандартныеПодсистемыСервер.ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияВерсииПрограммы(); - ИначеЕсли РасширенияИзменены Тогда - СтандартныеПодсистемыСервер.ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияРасширенийПрограммы(); - КонецЕсли; - Исключение - Если ЭтоСеансФоновогоЗадания() - Или СтандартныеПодсистемыСервер.ЭтоРазделенныйРежимСеансаБезРазделителей() Тогда - ВызватьИсключение; - КонецЕсли; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось проверить или обновить права доступа по причине: - |%1 - | - |Повторите операцию через минуту, и если проблема останется, перезапустите сеанс.'"), - ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); - ВызватьИсключение ТекстОшибки; - КонецПопытки; - Исключение - ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); - СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(ТекстОшибки); - ПриОшибкеПроверкиАктуальностиМетаданных(ТекстОшибки); - ВызватьИсключение; - КонецПопытки; - -КонецПроцедуры - -// Для процедуры ПроверитьАктуальностьМетаданных -Функция ЭтоСеансФоновогоЗадания() - - Если ТекущийРежимЗапуска() <> Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); - Возврат ТекущийСеанс.ИмяПриложения = "BackgroundJob"; - -КонецФункции - -// Для процедуры УстановитьОбновлениеДоступа -Функция ЭтоСеансФоновогоОбновленияДоступа() - - УстановитьПривилегированныйРежим(Истина); - Возврат ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЭтоСеансФоновогоОбновленияДоступа"); - -КонецФункции - -// Для процедур ВыполнитьОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступаСпискаВФоне. -Процедура УстановитьЭтоСеансФоновогоОбновленияДоступа() - - Если ТекущийРежимЗапуска() <> Неопределено Тогда - Возврат; - КонецЕсли; - - ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); - Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда - Возврат; - КонецЕсли; - - УстановитьПривилегированныйРежим(Истина); - - Параметры = Новый Структура(ПараметрыСеанса.ПараметрыОграниченияДоступа); - Параметры.Вставить("ЭтоСеансФоновогоОбновленияДоступа"); - ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(Параметры); - -КонецПроцедуры - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -Процедура ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Комментарий, ЭтоОшибка = Ложь) - - Если Не ЗначениеЗаполнено(Комментарий) Тогда - Возврат; - КонецЕсли; - - ИмяСобытия = НСтр("ru = 'Управление доступом.Параметры ограничения доступа.Несоответствие'", - ОбщегоНазначения.КодОсновногоЯзыка()); - ШаблонЗаголовка = - НСтр("ru = 'Есть несоответствие в записанных параметрах ограничения доступа - |Версия %1, Дата создания %2, Хеш-Сумма: %3, - |Хеш-сумма постоянных параметров: %4'"); - - Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗаголовка, - Запись.Версия, - Запись.ДатаСоздания, - Запись.ХешСумма, - Запись.ХешСуммаПостоянныхПараметров); - - УровеньЖурнала = ?(ЭтоОшибка, УровеньЖурналаРегистрации.Ошибка, - УровеньЖурналаРегистрации.Предупреждение); - - ЗаписьЖурналаРегистрации(ИмяСобытия, - УровеньЖурнала, - Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа,, - Заголовок + Символы.ПС + Символы.ПС + Комментарий, - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - -КонецПроцедуры - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -Процедура ЗарегистрироватьСтрокуВерсииПараметровОграниченияДоступа(Запись, СтрокиВерсии) - - Состав = Новый Массив; - Состав.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - "Версия = %1 - |ДатаСоздания = %2 - |ХешСумма = %3 - |ХешСуммаПостоянныхПараметров = %4 - |ХешСуммаПараметровШаблонов = %5", - Запись.Версия, - Формат(Запись.ДатаСоздания, "ДЛФ=DT"), - Запись.ХешСумма, - Запись.ХешСуммаПостоянныхПараметров, - Запись.ХешСуммаПараметровШаблонов)); - - Для Каждого Строка Из СтрокиВерсии.СтрокиВерсийСписков Цикл - Состав.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - "[Список = %1, ДляВнешнихПользователей = %2, Версия = %3] - |%4", - Строка.Список, - ?(Строка.ДляВнешнихПользователей, "Да", "Нет"), - Строка.Версия, - Строка.СтрокаВерсии)); - КонецЦикла; - - Состав.Добавить("[ВсеВерсииСтрокой] - |" + СтрокиВерсии.ВсеВерсииСтрокой); - - Состав.Добавить("[ВидыОграниченийПравДляПользователейСтрокой] - |" + СтрокиВерсии.ВидыОграниченийПравДляПользователейСтрокой); - - Состав.Добавить("[ВидыОграниченийПравДляВнешнихПользователейСтрокой] - |" + СтрокиВерсии.ВидыОграниченийПравДляВнешнихПользователейСтрокой); - - Состав.Добавить("[СпискиСОграничениемПоПолямВСеансахПользователей] - |" + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахПользователей); - - Состав.Добавить("[СпискиСОграничениемПоПолямВСеансахВнешнихПользователей] - |" + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахВнешнихПользователей); - - Комментарий = СтрСоединить(Состав, Символы.ПС); - - ЗаписьЖурналаРегистрации( - НСтр("ru = 'Управление доступом.Параметры ограничения доступа.Строка версии'", - ОбщегоНазначения.КодОсновногоЯзыка()), - УровеньЖурналаРегистрации.Информация, - Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа,, - Комментарий, - РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); - -КонецПроцедуры - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -Функция СпискиСИзменениемВерсий(Версия, НовыеВерсииОграниченийСписков, НедоступныеСписки, - СтараяВерсияСтруктурыКэша) - - Если Не ЗначениеЗаполнено(Версия) Тогда - Возврат Неопределено; - КонецЕсли; - - ВерсияПараметров = ВерсияПараметров(Версия, Ложь, Ложь); - ПараметрыЗаписиХранилище = ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав; - - Если ТипЗнч(ПараметрыЗаписиХранилище) <> Тип("ХранилищеЗначения") Тогда - Возврат Неопределено; - КонецЕсли; - ПараметрыЗаписи = ЗначениеИзХранилища(ПараметрыЗаписиХранилище); - - Если ТипЗнч(ПараметрыЗаписи) <> Тип("ФиксированнаяСтруктура") - Или Не ПараметрыЗаписи.Свойство("ВерсииОграниченийСписков") - Или ТипЗнч(ПараметрыЗаписи.ВерсииОграниченийСписков) <> Тип("ФиксированноеСоответствие") Тогда - Возврат Неопределено; - КонецЕсли; - - Свойства = Новый Структура("ВерсияСтруктурыКэша", СтараяВерсияСтруктурыКэша); - ЗаполнитьЗначенияСвойств(Свойства, ПараметрыЗаписи); - СтараяВерсияСтруктурыКэша = Свойства.ВерсияСтруктурыКэша; - - Таблица = Новый ТаблицаЗначений; - Таблица.Колонки.Добавить("Список", Новый ОписаниеТипов("Строка")); - Таблица.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка")); - Таблица.Колонки.Добавить("ВидИзменения", Новый ОписаниеТипов("Число")); - - Для Каждого КлючИЗначение Из ПараметрыЗаписи.ВерсииОграниченийСписков Цикл - Строка = Таблица.Добавить(); - Строка.Список = КлючИЗначение.Ключ; - Строка.Версия = СтрПолучитьСтроку(КлючИЗначение.Значение, 1) - + Символы.ПС + СтрПолучитьСтроку(КлючИЗначение.Значение, 2); - Строка.ВидИзменения = -1; - КонецЦикла; - - Для Каждого КлючИЗначение Из НовыеВерсииОграниченийСписков Цикл - Строка = Таблица.Добавить(); - Строка.Список = КлючИЗначение.Ключ; - Строка.Версия = СтрПолучитьСтроку(КлючИЗначение.Значение, 1) - + Символы.ПС + СтрПолучитьСтроку(КлючИЗначение.Значение, 2); - Строка.ВидИзменения = 1; - КонецЦикла; - - Таблица.Свернуть("Список, Версия", "ВидИзменения"); - Списки = Новый Массив; - НенайденныеСписки = Новый Массив; - - Для Каждого Строка Из Таблица Цикл - Если Строка.ВидИзменения = 0 Тогда - Продолжить; - КонецЕсли; - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Строка.Список); - Если ОбъектМетаданных = Неопределено Тогда - НенайденныеСписки.Добавить(Строка.Список); - Продолжить; - КонецЕсли; - ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); - Если Списки.Найти(ПолноеИмя) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Списки.Добавить(ПолноеИмя); - КонецЦикла; - - Если НенайденныеСписки.Количество() > 0 Тогда - НедоступныеСписки = ВсеИдентификаторыСПодобнымиПолнымиИменами(НенайденныеСписки); - - ИначеЕсли Списки.Количество() = 1 И Списки[0] = "Справочник.НаборыГруппДоступа" Тогда - Списки = Новый Массив; - КонецЕсли; - - Возврат Списки; - -КонецФункции - -// Для функции СпискиСИзменениемВерсий и для процедуры ДобавитьЗависимыеСписки. -Функция ВсеИдентификаторыСПодобнымиПолнымиИменами(ПолныеИмена) - - Запрос = Новый Запрос; - Запрос.Текст = - "ВЫБРАТЬ - | Идентификаторы.Ссылка КАК Ссылка - |ИЗ - | Справочник.ИдентификаторыОбъектовМетаданных КАК Идентификаторы - |ГДЕ - | &УсловияОтбораИОМ - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | Идентификаторы.Идентификатор - |ИЗ - | РегистрСведений.ИдентификаторыОбъектовВерсийРасширений КАК Идентификаторы - |ГДЕ - | &УсловияОтбораИОР"; - - УсловияОтбораИОМ = Новый Массив; - УсловияОтбораИОР = Новый Массив; - - НомерПараметра = 1; - Для Каждого ПолноеИмя Из ПолныеИмена Цикл - ИмяПараметра = "ПолноеИмя" + Формат(НомерПараметра, "ЧГ="); - Запрос.УстановитьПараметр(ИмяПараметра, ПолноеИмя); - УсловияОтбораИОМ.Добавить(СтрЗаменить("Идентификаторы.ПолноеИмя ПОДОБНО &ИмяПараметра СПЕЦСИМВОЛ ""~""", - "ИмяПараметра", ИмяПараметра)); // @query-part-1, @query-part-2 - УсловияОтбораИОР.Добавить(СтрЗаменить("Идентификаторы.ПолноеИмяОбъекта ПОДОБНО &ИмяПараметра СПЕЦСИМВОЛ ""~""", - "ИмяПараметра", ИмяПараметра)); // @query-part-1, @query-part-2 - НомерПараметра = НомерПараметра + 1; - КонецЦикла; - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловияОтбораИОМ", - СтрСоединить(УсловияОтбораИОМ, Символы.ПС + " ИЛИ ")); // @query-part-2 - - Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловияОтбораИОР", - СтрСоединить(УсловияОтбораИОР, Символы.ПС + " ИЛИ ")); // @query-part-2 - - Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); - -КонецФункции - -// Для процедуры ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Строка -// -Функция ВерсияСтруктурыКэша() Экспорт - - // Число нужно увеличивать при внесении изменений в состав параметров кэша - // (в том числе при изменении версии шаблонов). - Возврат "28.2" + ВерсияПеревода(); - -КонецФункции - -Функция ВерсияПеревода() - - Если ВариантВстроенногоЯзыкаРусский() Тогда - Возврат ""; - Иначе - Возврат "/" + Метаданные.Версия; - КонецЕсли; - -КонецФункции - -// Для процедур УстановкаПараметровСеанса, УточнитьВерсииШаблоновОграниченияДоступа и -// для функции СтруктураХранимыхПараметровШаблонов. -// -// Возвращаемое значение: -// Строка -// -Функция ВерсииШаблоновОграниченияДоступа() - - Возврат - ",ДляОбъекта9, - |,ДляРегистра9, - |,ПоЗначениям18, - |,ПоЗначениямРасширенный18, - |,ПоЗначениямИНаборамРасширенный18, - |,ПоНаборамЗначений18,"; - -КонецФункции - -// Для процедур УстановитьВерсиюПараметров, ЗаполнитьПараметрыДляШаблонов и -// функции НоваяСтруктураХранимыхВерсийПараметровШаблонов. -// -// -// Возвращаемое значение: -// Строка -// -Функция ВерсияСтруктурыВерсийПараметровШаблонов() - - // Число нужно увеличивать только при внесении изменений - // в состав параметра ВерсииПараметровШаблонов. - Возврат "1"; - -КонецФункции - -// Для функции ДействующиеПараметрыОграниченияДоступа. -Процедура ОбновитьИдентификаторыТранзакции(ИдентификаторТранзакции) - - Кэш = КэшПараметровОграничения(); - - Если Не ТранзакцияАктивна() И Кэш.ИдентификаторыТранзакции.Количество() = 0 - Или ТранзакцияАктивна() И ИдентификаторТранзакции = Неопределено Тогда - Возврат; - КонецЕсли; - - Если ИдентификаторТранзакции <> Неопределено И ТранзакцияАктивна() Тогда - Кэш.ИдентификаторыТранзакции.Вставить(ИдентификаторТранзакции, Истина); - Иначе - Кэш.ИдентификаторыТранзакции.Очистить(); - КонецЕсли; - -КонецПроцедуры - -// Для функции ДействующиеПараметрыОграниченияДоступа. -Процедура УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, - УстановкаПараметровСеансаДляШаблонов = Ложь, ПовторныйВызов = Ложь) - - Если Не ПовторныйВызов Тогда - Если УстановкаПараметровСеансаДляШаблонов Тогда - СброситьКэшПараметровОграничения(); - Иначе - ОбновитьПовторноИспользуемыеЗначения(); - КонецЕсли; - КонецЕсли; - - Если ИдентификаторТранзакции <> Неопределено И ТранзакцияАктивна() Тогда - Кэш = КэшПараметровОграничения(); - Кэш.ИдентификаторыТранзакции.Вставить(ИдентификаторТранзакции, Истина); - КонецЕсли; - - Если ТипЗнч(ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав) = Тип("ХранилищеЗначения") Тогда - ДляЗаписиОбъектовИПроверкиПрав = СтруктураХранимыхПараметровЗаписи( - ЗначениеИзХранилища(ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав)); - - Если ДляЗаписиОбъектовИПроверкиПрав.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда - ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); - УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, - УстановкаПараметровСеансаДляШаблонов, Истина); - Возврат; - КонецЕсли; - Иначе - ДляЗаписиОбъектовИПроверкиПрав = Неопределено; - КонецЕсли; - - Если ТипЗнч(ВерсияПараметров.ВерсииПараметровШаблонов) = Тип("ХранилищеЗначения") Тогда - ВерсииПараметровШаблонов = СтруктураХранимыхВерсийПараметровШаблонов( - ЗначениеИзХранилища(ВерсияПараметров.ВерсииПараметровШаблонов)); - - Если ВерсииПараметровШаблонов.ВерсияСтруктурыВерсий <> ВерсияСтруктурыВерсийПараметровШаблонов() Тогда - ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); - УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, - УстановкаПараметровСеансаДляШаблонов, Истина); - Возврат; - КонецЕсли; - Иначе - ВерсииПараметровШаблонов = Неопределено; - КонецЕсли; - - Если ТипЗнч(ВерсияПараметров.ДляОтчетаПоПравамДоступа) = Тип("ХранилищеЗначения") Тогда - ДляОтчетаПоПравамДоступа = СтруктураХранимыхПараметровОтчета( - ЗначениеИзХранилища(ВерсияПараметров.ДляОтчетаПоПравамДоступа)); - - Если ДляОтчетаПоПравамДоступа.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда - ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); - УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, - УстановкаПараметровСеансаДляШаблонов, Истина); - Возврат; - КонецЕсли; - Кэш = КэшПараметровОграничения(); - Кэш.ВидыОграниченийПравДляПользователей - = ДляОтчетаПоПравамДоступа.ВидыОграниченийПравДляПользователей; - Кэш.ВидыОграниченийПравДляВнешнихПользователей - = ДляОтчетаПоПравамДоступа.ВидыОграниченийПравДляВнешнихПользователей; - КонецЕсли; - - Если УстановкаПараметровСеансаДляШаблонов - Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда - - ХранилищеДляШаблоновВСеансах = ?(Пользователи.ЭтоСеансВнешнегоПользователя(), - ВерсияПараметров.ДляШаблоновВСеансахВнешнихПользователей, - ВерсияПараметров.ДляШаблоновВСеансахПользователей); - - Если ТипЗнч(ХранилищеДляШаблоновВСеансах) = Тип("ХранилищеЗначения") Тогда - ДляШаблоновОграниченияДоступа = СтруктураХранимыхПараметровШаблонов( - ЗначениеИзХранилища(ХранилищеДляШаблоновВСеансах)); - - Если ДляШаблоновОграниченияДоступа.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда - ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); - УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, - УстановкаПараметровСеансаДляШаблонов, Истина); - Возврат; - КонецЕсли; - Иначе - ДляШаблоновОграниченияДоступа = НоваяСтруктураХранимыхПараметровШаблонов(); - КонецЕсли; - - ВерсииШаблонов = СтрСоединить(СтрРазделить( - ДляШаблоновОграниченияДоступа.ВерсииШаблонов, Символы.ПС + Символы.ВК, Ложь), Символы.ПС); - УточнитьВерсииШаблоновОграниченияДоступа(ВерсииШаблонов); - - ПараметрыШаблонов = Новый Структура(СтруктураПараметровШаблонов( - ДляШаблоновОграниченияДоступа.ПараметрыШаблонов)); - ПараметрыШаблонов.Вставить("ВерсииШаблоновОграниченияДоступа", ВерсииШаблонов); - - ОбновитьПараметрыСеансаДляШаблонов = УстановкаПараметровСеансаДляШаблонов; - Если Не УстановкаПараметровСеансаДляШаблонов - И ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда - - Для Каждого КлючИЗначение Из ПараметрыШаблонов Цикл - Если ПараметрыСеанса[КлючИЗначение.Ключ] <> КлючИЗначение.Значение Тогда - ОбновитьПараметрыСеансаДляШаблонов = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если ОбновитьПараметрыСеансаДляШаблонов Тогда - ПередИзменениемПараметровСеансаДляШаблонов(ПараметрыШаблонов, УстановкаПараметровСеансаДляШаблонов); - ЗаполнитьЗначенияСвойств(ПараметрыСеанса, ПараметрыШаблонов); - КонецЕсли; - КонецЕсли; - - ОбновитьРазрешенныеНаборыВПараметрахСеанса(УстановкаПараметровСеансаДляШаблонов, Истина); - - Параметры = СеансовыеПараметрыОграниченияДоступа(ВерсияПараметров, - ДляЗаписиОбъектовИПроверкиПрав, ВерсииПараметровШаблонов, УстановкаПараметровСеансаДляШаблонов); - ПараметрыСеанса.ПараметрыОграниченияДоступа = Параметры; - -КонецПроцедуры - -// Для процедуры УстановитьВерсиюПараметров. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * Версия - Строка -// * ХешСумма - Строка -// * ДатаСоздания - Дата -// * Параметры - см. СтруктураХранимыхПараметровЗаписи -// -Функция СеансовыеПараметрыОграниченияДоступа(ВерсияПараметров, ДляЗаписиОбъектовИПроверкиПрав, - ВерсииПараметровШаблонов, УстановкаПараметровСеансаДляШаблонов) - - ПараметрыОграничения = Новый Структура; - ПараметрыОграничения.Вставить("Версия", ВерсияПараметров.Версия); - ПараметрыОграничения.Вставить("ХешСумма", ВерсияПараметров.ХешСумма); - ПараметрыОграничения.Вставить("ДатаСоздания", ВерсияПараметров.ДатаСоздания); - - Если ДляЗаписиОбъектовИПроверкиПрав = Неопределено Тогда - Параметры = Неопределено; - Иначе - ПрочитанныеПараметры = Новый Структура(ДляЗаписиОбъектовИПроверкиПрав); - ДополнительныйКонтекст = Новый Структура(ПрочитанныеПараметры.ДополнительныйКонтекст); - ДляПользователей = Новый Структура(ДополнительныйКонтекст.ДляПользователей); - ДляПользователей.ОсновныеВариантыДоступа = Новый ФиксированноеСоответствие( - ВерсииПараметровШаблонов.ДляПользователей.ОсновныеВариантыДоступа); - ДополнительныйКонтекст.ДляПользователей = Новый ФиксированнаяСтруктура(ДляПользователей); - ДляВнешнихПользователей = Новый Структура(ДополнительныйКонтекст.ДляВнешнихПользователей); - ДляВнешнихПользователей.ОсновныеВариантыДоступа = Новый ФиксированноеСоответствие( - ВерсииПараметровШаблонов.ДляВнешнихПользователей.ОсновныеВариантыДоступа); - ДополнительныйКонтекст.ДляВнешнихПользователей = Новый ФиксированнаяСтруктура(ДляВнешнихПользователей); - ПрочитанныеПараметры.ДополнительныйКонтекст = Новый ФиксированнаяСтруктура(ДополнительныйКонтекст); - Параметры = Новый ФиксированнаяСтруктура(ПрочитанныеПараметры); - КонецЕсли; - - ПараметрыОграничения.Вставить("Параметры", Параметры); - - Если УстановкаПараметровСеансаДляШаблонов - Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда - ПараметрыОграничения.Вставить("ПараметрыСеансаДляШаблоновУстановлены"); - КонецЕсли; - - Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЗаписьПараметровОграниченияДоступаВТекущемСеансе") Тогда - ПараметрыОграничения.Вставить("ЗаписьПараметровОграниченияДоступаВТекущемСеансе", - ПараметрыСеанса.ПараметрыОграниченияДоступа.ЗаписьПараметровОграниченияДоступаВТекущемСеансе); - КонецЕсли; - - Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЭтоСеансФоновогоОбновленияДоступа") Тогда - ПараметрыОграничения.Вставить("ЭтоСеансФоновогоОбновленияДоступа"); - КонецЕсли; - - Возврат Новый ФиксированнаяСтруктура(ПараметрыОграничения); - -КонецФункции - -// Для процедуры УстановитьВерсиюПараметров. -Процедура УточнитьВерсииШаблоновОграниченияДоступа(ВерсииШаблонов) - - Если ВерсииШаблонов = ВерсииШаблоновОграниченияДоступа() Тогда - Возврат; - КонецЕсли; - - ВерсииШаблонов = ВерсииШаблоновОграниченияДоступа() + " - |,ТребуетсяПерезапуститьСеанс,"; - -КонецПроцедуры - -// Для процедуры УстановитьВерсиюПараметров, ПроверитьДоступКОбъекту, -// ПроверитьДоступКНаборуЗаписей и функции ДоступРазрешен. -// -Процедура ОбновитьРазрешенныеНаборыВПараметрахСеанса(УстановкаПараметровСеансаДляШаблонов = Ложь, - УстановкаПараметровОграниченияДоступа = Ложь) - - Если Не УстановкаПараметровСеансаДляШаблонов - И Не ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда - Возврат; - КонецЕсли; - - ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); - - Если Не УстановкаПараметровСеансаДляШаблонов - И Не УстановкаПараметровОграниченияДоступа - И ПоследняяПроверка.Дата + 5 >= ТекущаяДатаСеанса() Тогда - Возврат; - КонецЕсли; - - ПоследняяПроверка.Дата = ТекущаяДатаСеанса(); - - Состав = РазрешенныеНаборыПараметровЗапроса(); - - Если Не УстановкаПараметровСеансаДляШаблонов - И ПараметрыСеанса.РазрешенныйПользователь = Состав.РазрешенныйПользователь - И ПараметрыСеанса.РазрешенныйНаборГруппДоступа = Состав.РазрешенныйНаборГруппДоступа - И ПараметрыСеанса.РазрешенныйНаборГруппПользователей = Состав.РазрешенныйНаборГруппПользователей - И ПараметрыСеанса.РазрешенныйПустойНаборГруппДоступа = Состав.РазрешенныйПустойНаборГруппДоступа Тогда - - Возврат; - КонецЕсли; - - Состав.Вставить("ОбщиеПараметрыШаблоновОграниченияДоступа", ""); - УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса(Состав); - - ПередИзменениемПараметровСеансаДляШаблонов(Состав, УстановкаПараметровСеансаДляШаблонов); - ЗаполнитьЗначенияСвойств(ПараметрыСеанса, Состав); - -КонецПроцедуры - -// Для процедуры ОбновитьРазрешенныеНаборыВПараметрахСеанса и -// УстановитьРазрешенныеНаборыВПараметрыЗапроса. -// -// Параметры: -// Пользователь - СправочникСсылка.Пользователи -// - СправочникСсылка.ВнешниеПользователи -// - Неопределено - текущий пользователь. -// -// Возвращаемое значение: -// Структура: -// * РазрешенныйПользователь - СправочникСсылка.НаборыГруппДоступа -// * РазрешенныйНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа -// * РазрешенныйНаборГруппПользователей - СправочникСсылка.НаборыГруппДоступа -// * РазрешенныйПустойНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа -// -Функция РазрешенныеНаборыПараметровЗапроса(Знач Пользователь = Неопределено) - - ПустойНаборГруппДоступа = Справочники.НаборыГруппДоступа.ПустаяСсылка(); - - Состав = Новый Структура; - Состав.Вставить("РазрешенныйПользователь", ПустойНаборГруппДоступа); - Состав.Вставить("РазрешенныйНаборГруппДоступа", ПустойНаборГруппДоступа); - Состав.Вставить("РазрешенныйНаборГруппПользователей", ПустойНаборГруппДоступа); - Состав.Вставить("РазрешенныйПустойНаборГруппДоступа", - УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); - - Если Пользователи.ЭтоПолноправныйПользователь(Пользователь,, Ложь) Тогда - Возврат Состав; - КонецЕсли; - - Если Пользователь = Неопределено Тогда - Пользователь = Пользователи.АвторизованныйПользователь(); - КонецЕсли; - - Состав.РазрешенныйПользователь = Справочники.НаборыГруппДоступа.ПолучитьСсылку( - Пользователь.УникальныйИдентификатор()); - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("РазрешенныйПользователь", Состав.РазрешенныйПользователь); - Запрос.Текст = - "ВЫБРАТЬ - | НаборыГруппДоступа.РазрешенныйНаборГруппДоступа КАК РазрешенныйНаборГруппДоступа, - | НаборыГруппДоступа.РазрешенныйНаборГруппПользователей КАК РазрешенныйНаборГруппПользователей - |ИЗ - | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа - |ГДЕ - | НаборыГруппДоступа.Ссылка = &РазрешенныйПользователь"; - - Выборка = Запрос.Выполнить().Выбрать(); - Если Выборка.Следующий() Тогда - Состав.РазрешенныйНаборГруппДоступа = Выборка.РазрешенныйНаборГруппДоступа; - Состав.РазрешенныйНаборГруппПользователей = Выборка.РазрешенныйНаборГруппПользователей; - КонецЕсли; - - Возврат Состав; - -КонецФункции - -// Для процедуры ОбновитьРазрешенныеНаборыВПараметрахСеанса. -Процедура УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса(Состав) - - Если Не УправлениеДоступомСлужебныйПовтИсп.ТребуетсяУточнениеПланаЗапроса() Тогда - Возврат; - КонецЕсли; - - Состав.ОбщиеПараметрыШаблоновОграниченияДоступа = ";УточнитьДляВсех;" - + ОписаниеХешСуммыНастроекПрав(Состав.РазрешенныйНаборГруппДоступа) - + ОписаниеХешСуммыНастроекПрав(Состав.РазрешенныйПользователь, "^"); - -КонецПроцедуры - -// Для процедуры УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса. -Функция ОписаниеХешСуммыНастроекПрав(НаборГруппДоступа, Символ = "") - - ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.CRC32); - ХешированиеДанных.Добавить(ПолучитьДвоичныеДанныеИзHexСтроки(СтрЗаменить( - НаборГруппДоступа.УникальныйИдентификатор(), "-", ""))); - Остаток = ХешированиеДанных.ХешСумма; - - Результат = ""; - Для Счетчик = 1 По 32 Цикл - Целое = Цел(Остаток / 2); - Результат = ?(Остаток - Целое * 2 = 0, "", XMLСтрока(Счетчик) + Символ + ";") + Результат; - Остаток = Целое; - КонецЦикла; - - Возврат Символы.ПС + ";" + Результат; - -КонецФункции - -// Для функции ДоступРазрешен и процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. -Процедура УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос, Знач Пользователь = Неопределено) - - Если Пользователь = Неопределено Тогда - Параметры = ПараметрыСеанса; - Пользователь = Пользователи.АвторизованныйПользователь(); - Иначе - Параметры = РазрешенныеНаборыПараметровЗапроса(Пользователь); - КонецЕсли; - - Запрос.УстановитьПараметр("РазрешенныйНаборГруппДоступа", Параметры.РазрешенныйНаборГруппДоступа); - Запрос.УстановитьПараметр("РазрешенныйПустойНаборГруппДоступа", Параметры.РазрешенныйПустойНаборГруппДоступа); - Запрос.УстановитьПараметр("РазрешенныйНаборГруппПользователей", Параметры.РазрешенныйНаборГруппПользователей); - Запрос.УстановитьПараметр("РазрешенныйПользователь", Параметры.РазрешенныйПользователь); - Запрос.УстановитьПараметр("АвторизованныйПользователь", Пользователь); - -КонецПроцедуры - -// Для функции НоваяВерсияПараметровОграниченияДоступа. -// -// Параметры: -// ОбщийКонтекст - см. ОбщийКонтекстРасчетаПараметровОграничения -// ВерсииОграниченийСписков - Соответствие -// -// Возвращаемое значение: -// Структура: -// * ДатаСоздания - Дата -// * ДляЗаписиОбъектовИПроверкиПрав - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровЗаписи -// * ДляОтчетаПоПравамДоступа - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровОтчета -// * ХешСуммаПостоянныхПараметров - Строка -// * ДляШаблоновВСеансахПользователей - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровШаблонов -// * ДляШаблоновВСеансахВнешнихПользователей - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровШаблонов -// * ВерсииПараметровШаблонов - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхВерсийПараметровШаблонов -// * ХешСуммаПараметровШаблонов - Строка - заполняется при записи после обновления -// параметра ВерсииПараметровШаблонов и заполнения свойства СпискиСОграничениемПоПолям -// параметров ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей. -// * ХешСумма - Строка - заполняется при записи, -// вычисляется из хеш-сумм ХешСуммаПостоянныхПараметров и ХешСуммаПараметровШаблонов. -// -Функция ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст, ВерсииОграниченийСписков = Неопределено) - - ДатаСоздания = ТекущаяДатаСеанса(); - - Если ОбщийКонтекст = Неопределено Тогда - ОбновитьПовторноИспользуемыеЗначения(); - ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); - - ИначеЕсли ОбщийКонтекст.Свойство("СпециальноеПолноеИмя") Тогда - СпециальноеПолноеИмя = ОбщийКонтекст.СпециальноеПолноеИмя; - СпециальноеОписаниеОграничения = ОбщийКонтекст.СпециальноеОписаниеОграничения; - КонецЕсли; - - ДополнительныйКонтекстДляПользователей = НовыйДополнительныйКонтекст(); - ДополнительныйКонтекстДляВнешнихПользователей = НовыйДополнительныйКонтекст(); - - ОписаниеОграничений = Новый Соответствие; - ПолныеИменаСписков = Новый Массив; - Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл - ПолноеИмя = ОписаниеСписка.Ключ; - ПолныеИменаСписков.Добавить(ПолноеИмя); - Если ПолноеИмя = СпециальноеПолноеИмя Тогда - ОписаниеОграничения = СпециальноеОписаниеОграничения; - Иначе - ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); - КонецЕсли; - ОписаниеОграничений.Вставить(ПолноеИмя, ОписаниеОграничения); - - ДобавитьДополнительныйКонтекст(ПолноеИмя, - ДополнительныйКонтекстДляПользователей, ОписаниеОграничения, Ложь); - - ДобавитьДополнительныйКонтекст(ПолноеИмя, - ДополнительныйКонтекстДляВнешнихПользователей, ОписаниеОграничения, Истина); - КонецЦикла; - - СпискиСДатой = Новый Соответствие; - ИдентификаторыСписков = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИменаСписков); - ВерсияТекстовОграниченияДоступа = - РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(ОписаниеОграничений); - - ВидыОграниченийПравДляПользователей = Новый Соответствие; - ВидыОграниченийПравДляВнешнихПользователей = Новый Соответствие; - - Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - СтрокиВерсийСписков = НовыеСтрокиВерсийСписков(); - СтрокиВерсииХранимыхПараметров = Новый Структура; - СтрокиВерсииХранимыхПараметров.Вставить("ВсеВерсииСтрокой", ""); - СтрокиВерсииХранимыхПараметров.Вставить("ВидыОграниченийПравДляПользователейСтрокой", ""); - СтрокиВерсииХранимыхПараметров.Вставить("ВидыОграниченийПравДляВнешнихПользователейСтрокой", ""); - СтрокиВерсииХранимыхПараметров.Вставить("СтрокиВерсийСписков", СтрокиВерсийСписков); - ОбщийКонтекст.СтрокиВерсииХранимыхПараметров = СтрокиВерсииХранимыхПараметров; - КонецЕсли; - - Если ОбщийКонтекст.Свойство("ИнформацияДляЖурнала") Тогда - СпискиБезВнедрения = Новый Структура; - СпискиБезВнедрения.Вставить("ОбъектыПредупреждения", Новый Соответствие); - СпискиБезВнедрения.Вставить("ОбъектыОшибки", Новый Соответствие); - СпискиБезВнедрения.Вставить("РегистрыПредупреждения", Новый Массив); - Иначе - СпискиБезВнедрения = Неопределено; - КонецЕсли; - - // Заполнение для пользователей. - КонтекстДляПользователей = Новый Структура; - КонтекстДляПользователей.Вставить("ДляВнешнихПользователей", Ложь); - КонтекстДляПользователей.Вставить("ДатаСоздания", ДатаСоздания); - КонтекстДляПользователей.Вставить("ОбщийКонтекст", ОбщийКонтекст); - КонтекстДляПользователей.Вставить("ДополнительныйКонтекст", ДополнительныйКонтекстДляПользователей); - КонтекстДляПользователей.Вставить("ВедущиеСписки", Новый Соответствие); - КонтекстДляПользователей.Вставить("ВерсииОграниченийСписков", Новый Соответствие); - КонтекстДляПользователей.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); - КонтекстДляПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); - КонтекстДляПользователей.Вставить("СпискиСДатой", СпискиСДатой); - КонтекстДляПользователей.Вставить("ИдентификаторыСписков", ИдентификаторыСписков); - КонтекстДляПользователей.Вставить("ВсеВидыОграниченийПрав", ВидыОграниченийПравДляПользователей); - КонтекстДляПользователей.Вставить("ВедущиеРоли", Новый Соответствие); - КонтекстДляПользователей.Вставить("СпискиБезВнедрения", СпискиБезВнедрения); - - ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(КонтекстДляПользователей); - - // Заполнение для внешних пользователей. - КонтекстДляВнешнихПользователей = Новый Структура; - КонтекстДляВнешнихПользователей.Вставить("ДляВнешнихПользователей", Истина); - КонтекстДляВнешнихПользователей.Вставить("ДатаСоздания", ДатаСоздания); - КонтекстДляВнешнихПользователей.Вставить("ОбщийКонтекст", ОбщийКонтекст); - КонтекстДляВнешнихПользователей.Вставить("ДополнительныйКонтекст", ДополнительныйКонтекстДляВнешнихПользователей); - КонтекстДляВнешнихПользователей.Вставить("ВедущиеСписки", Новый Соответствие); - КонтекстДляВнешнихПользователей.Вставить("ВерсииОграниченийСписков", Новый Соответствие); - КонтекстДляВнешнихПользователей.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); - КонтекстДляВнешнихПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); - КонтекстДляВнешнихПользователей.Вставить("СпискиСДатой", СпискиСДатой); - КонтекстДляВнешнихПользователей.Вставить("ИдентификаторыСписков", ИдентификаторыСписков); - КонтекстДляВнешнихПользователей.Вставить("ВсеВидыОграниченийПрав", ВидыОграниченийПравДляВнешнихПользователей); - КонтекстДляВнешнихПользователей.Вставить("ВедущиеРоли", Новый Соответствие); - КонтекстДляВнешнихПользователей.Вставить("СпискиБезВнедрения", СпискиБезВнедрения); - - ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(КонтекстДляВнешнихПользователей); - - Если ОбщийКонтекст.Свойство("ИнформацияДляЖурнала") Тогда - ЗаполнитьНесоответствиеПараметровДляЖурнала(СпискиБезВнедрения, ОбщийКонтекст.ИнформацияДляЖурнала); - ОбщийКонтекст.ИнформацияДляЖурнала.ВерсияТекстовОграниченияДоступа = ВерсияТекстовОграниченияДоступа; - КонецЕсли; - - // Заполнение общей и отдельной частей ведущих списков для пользователей и внешних пользователей. - ВедущиеСписки = Новый Соответствие; - Для Каждого ОписаниеВедущихСписков Из КонтекстДляПользователей.ВедущиеСписки Цикл - ДобавитьВедущиеСписки(ВедущиеСписки, - "ДляПользователей", ОписаниеВедущихСписков.Ключ, ОписаниеВедущихСписков.Значение); - КонецЦикла; - Для Каждого ОписаниеВедущихСписков Из КонтекстДляВнешнихПользователей.ВедущиеСписки Цикл - ДобавитьВедущиеСписки(ВедущиеСписки, - "ДляВнешнихПользователей", ОписаниеВедущихСписков.Ключ, ОписаниеВедущихСписков.Значение); - КонецЦикла; - Свойства = ВедущийСписокПоЗначениямПолей(); - Для Каждого ВедущийСписок Из ВедущиеСписки Цикл - Свойства = ВедущийСписок.Значение; - Если Свойства.ПоЗначениямПолей <> Неопределено Тогда - ПоЗначениямПолей = Свойства.ПоЗначениямПолей; - Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда - ТабличныеЧасти = Новый Массив; - Для Каждого ОписаниеТабличнойЧасти Из ПоЗначениямПолей.ТабличныеЧасти Цикл - ТабличныеЧасти.Добавить(ОписаниеТабличнойЧасти.Значение); - КонецЦикла; - ПоЗначениямПолей.ТабличныеЧасти = ТабличныеЧасти; - КонецЕсли; - КонецЕсли; - КонецЦикла; - - // Заполнение ведущих ролей для пользователей и внешних пользователей. - ВедущиеРоли = Новый Соответствие; - ДобавитьВедущиеРоли(ВедущиеРоли, "ДляПользователей", КонтекстДляПользователей); - ДобавитьВедущиеРоли(ВедущиеРоли, "ДляВнешнихПользователей", КонтекстДляВнешнихПользователей); - - // Расчет версий ограничения доступа. - ВерсииОграниченийСписков = Новый Соответствие; - Версии = Новый СписокЗначений; - Версии.Добавить(ВерсияСтруктурыКэша()); - Для Каждого ОписаниеВерсии Из КонтекстДляПользователей.ВерсииОграниченийСписков Цикл - ОбщаяВерсия = ОбщаяВерсия(ОбщийКонтекст, ОписаниеВерсии.Ключ, ОписаниеВерсии.Значение, - КонтекстДляВнешнихПользователей.ВерсииОграниченийСписков.Получить(ОписаниеВерсии.Ключ)); - ВерсииОграниченийСписков.Вставить(ОписаниеВерсии.Ключ, ОбщаяВерсия); - Версии.Добавить(ОбщаяВерсия, ПолучитьHexСтрокуИзДвоичныхДанных( - ПолучитьДвоичныеДанныеИзСтроки(Строка(ОбщаяВерсия)))); - КонецЦикла; - Версии.СортироватьПоПредставлению(); - ВерсииСтрокой = СтрСоединить(Версии.ВыгрузитьЗначения(), Символы.ПС); - ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); - ХешированиеДанных.Добавить(ВерсииСтрокой); - Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВсеВерсииСтрокой = ВерсииСтрокой; - КонецЕсли; - - // Подготовка дополнительного контекста для расчета параметров ограничения отдельного списка. - ДляПользователей = НовыйХранимыйДополнительныйКонтекст(); - ЗаполнитьЗначенияСвойств(ДляПользователей, КонтекстДляПользователей.ДополнительныйКонтекст); - ДляВнешнихПользователей = НовыйХранимыйДополнительныйКонтекст(); - ЗаполнитьЗначенияСвойств(ДляВнешнихПользователей, КонтекстДляВнешнихПользователей.ДополнительныйКонтекст); - ДополнительныйКонтекст = Новый Структура; - ДополнительныйКонтекст.Вставить("ДляПользователей", ДляПользователей); - ДополнительныйКонтекст.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); - - ПараметрыЗаписи = НоваяСтруктураХранимыхПараметровЗаписи(); - ПараметрыЗаписи.ВерсииОграниченийСписков = ВерсииОграниченийСписков; - ПараметрыЗаписи.ВедущиеСписки = ВедущиеСписки; - ПараметрыЗаписи.ДополнительныйКонтекст = ДополнительныйКонтекст; - ПараметрыЗаписи.СпискиСДатой = СпискиСДатой; - ПараметрыЗаписи.ВедущиеРоли = ВедущиеРоли; - ПараметрыЗаписи.ИспользуемыеТипыЗначений = Новый ХранилищеЗначения( - Новый Структура("ХешСумма", ОбщийКонтекст.ИспользуемыеТипыЗначений.ХешСумма)); - ПараметрыЗаписи.ВнешниеПользователиВключены = ОбщийКонтекст.ВнешниеПользователиВключены; - ПараметрыЗаписи.ОграничениеДоступаВключено = ОбщийКонтекст.ОграничениеДоступаВключено; - ПараметрыЗаписи.ВерсияТекстовОграниченияДоступа = ВерсияТекстовОграниченияДоступа; - ХешированиеДанных.Добавить(ОбщийКонтекст.ИспользуемыеТипыЗначений.ХешСумма); - - ХранимыеПараметры = Новый Структура; - - ХранимыеПараметрыШаблоновДляПользователей = НоваяСтруктураХранимыхПараметровШаблонов(); - ХранимыеПараметрыШаблоновДляПользователей.ПараметрыШаблонов = КонтекстДляПользователей.ПараметрыШаблонов; - ХранимыеПараметры.Вставить("ДляШаблоновВСеансахПользователей", - Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыШаблоновДляПользователей))); - - ХранимыеПараметрыШаблоновДляВнешнихПользователей = НоваяСтруктураХранимыхПараметровШаблонов(); - ХранимыеПараметрыШаблоновДляВнешнихПользователей.ПараметрыШаблонов = КонтекстДляВнешнихПользователей.ПараметрыШаблонов; - ХранимыеПараметры.Вставить("ДляШаблоновВСеансахВнешнихПользователей", - Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыШаблоновДляВнешнихПользователей))); - - ХранимыеВерсииПараметровШаблонов = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); - ХранимыеВерсииПараметровШаблонов.ДляПользователей.ВерсииПараметровШаблонов = - КонтекстДляПользователей.ВерсииПараметровШаблонов; - ХранимыеВерсииПараметровШаблонов.ДляВнешнихПользователей.ВерсииПараметровШаблонов = - КонтекстДляВнешнихПользователей.ВерсииПараметровШаблонов; - ХранимыеПараметры.Вставить("ВерсииПараметровШаблонов", - Новый ХранилищеЗначения(ХранимыеВерсииПараметровШаблонов)); - - ХранимыеПараметры.Вставить("ДляЗаписиОбъектовИПроверкиПрав", - Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ПараметрыЗаписи))); - - ХранимыеПараметрыОтчета = НоваяСтруктураХранимыхПараметровОтчета(); - ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей = - ВидыОграниченийПравСтрокой(ВидыОграниченийПравДляПользователей); - ХешированиеДанных.Добавить(ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей); - ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей = - ВидыОграниченийПравСтрокой(ВидыОграниченийПравДляВнешнихПользователей); - ХешированиеДанных.Добавить(ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей); - Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВидыОграниченийПравДляПользователейСтрокой - = ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей; - ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВидыОграниченийПравДляВнешнихПользователейСтрокой - = ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей; - КонецЕсли; - - ХранимыеПараметры.Вставить("ДляОтчетаПоПравамДоступа", - Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыОтчета))); - - ХранимыеПараметры.Вставить("ХешСуммаПостоянныхПараметров", Base64Строка(ХешированиеДанных.ХешСумма)); - ХранимыеПараметры.Вставить("ДатаСоздания", ДатаСоздания); - - Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - СтрокиВерсийСписков.Сортировать("Список, ДляВнешнихПользователей"); - КонецЕсли; - - Возврат ХранимыеПараметры; - -КонецФункции - -// Возвращаемое значение: -// ТаблицаЗначений: -// * Список - Строка -// * ДляВнешнихПользователей - Булево -// * Версия - Строка -// * СтрокаВерсии - Строка -// -Функция НовыеСтрокиВерсийСписков() - - СтрокиВерсийСписков = Новый ТаблицаЗначений; - СтрокиВерсийСписков.Колонки.Добавить("Список", Новый ОписаниеТипов("Строка")); - СтрокиВерсийСписков.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); - СтрокиВерсийСписков.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка")); - СтрокиВерсийСписков.Колонки.Добавить("СтрокаВерсии", Новый ОписаниеТипов("Строка")); - - Возврат СтрокиВерсийСписков; - -КонецФункции - -// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * ОписанияОграничений - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. СокращенноеОписаниеОграничения -// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. НовыеСвойстваОграниченияСписка -// * СпискиСОграничениемПоВладельцу - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - значение ПоВладельцу, кроме Неопределено. -// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа -// -Функция НовыйДополнительныйКонтекст() - - ДополнительныйКонтекст = Новый Структура; - ДополнительныйКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СвойстваОграниченияСписков", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСОграничениемПоВладельцу", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничением", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничениемЧтения", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей", Неопределено); - ДополнительныйКонтекст.Вставить("ОсновныеВариантыДоступа", Новый Соответствие); - - Возврат ДополнительныйКонтекст; - -КонецФункции - -// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. НовыеСвойстваОграниченияСписка -// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа -// -Функция НовыйХранимыйДополнительныйКонтекст() - - ДополнительныйКонтекст = Новый Структура; - ДополнительныйКонтекст.Вставить("СвойстваОграниченияСписков", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничением", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничениемЧтения", Новый Соответствие); - ДополнительныйКонтекст.Вставить("СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей", Неопределено); - ДополнительныйКонтекст.Вставить("ОсновныеВариантыДоступа", Новый Соответствие); - - Возврат ДополнительныйКонтекст; - -КонецФункции - -// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. -Процедура ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, - ОписаниеОграничения, ДляВнешнихПользователей) - - Если ДляВнешнихПользователей Тогда - Текст = ОписаниеОграничения.ТекстДляВнешнихПользователей; - ПоВладельцу = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей; - Иначе - Текст = ОписаниеОграничения.Текст; - ПоВладельцу = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступа; - КонецЕсли; - ВМодулеМенеджера = ОписаниеОграничения.ТекстВМодулеМенеджера; - - СокращенноеОписаниеОграничения = СокращенноеОписаниеОграничения(); - СокращенноеОписаниеОграничения.Вставить("Текст", Текст); - СокращенноеОписаниеОграничения.Вставить("ВМодулеМенеджера", ВМодулеМенеджера); - - ДополнительныйКонтекст.ОписанияОграничений.Вставить(ПолноеИмя, СокращенноеОписаниеОграничения); - - Если ПоВладельцу <> Неопределено Тогда - ДополнительныйКонтекст.СпискиСОграничениемПоВладельцу.Вставить(ПолноеИмя, ПоВладельцу); - КонецЕсли; - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * Текст - Строка -// * ВМодулеМенеджера - Булево -// -Функция СокращенноеОписаниеОграничения() - - Возврат Новый Структура; - -КонецФункции - -// Для функции ХранимыеПараметрыОграниченияДоступа. -Процедура ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(Контекст) - - // Подготовка параметров с учетом зависимостей только по ключам доступа. - ТаблицаСвойств = СвойстваСписковДляРасчетаХранимыхПараметров(); - ТаблицаСвойств = Новый ТаблицаЗначений; - ТаблицаСвойств.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка")); - ТаблицаСвойств.Колонки.Добавить("Зависимый", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("Ведущие", Новый ОписаниеТипов("Массив")); - ТаблицаСвойств.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число")); - ТаблицаСвойств.Колонки.Добавить("Ведущий", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("Зависимые", Новый ОписаниеТипов("Массив")); - ТаблицаСвойств.Колонки.Добавить("Параметры", Новый ОписаниеТипов("Структура")); - ТаблицаСвойств.Колонки.Добавить("Обработан", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("ОграничениеПоВладельцуВозможно", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("ОграничениеПоВладельцуВключено", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("КлючиДоступаПользователей", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Новый ОписаниеТипов("Булево")); - ТаблицаСвойств.Колонки.Добавить("ЗависимыеСпискиБезЗаписиКлючейДоступа", Новый ОписаниеТипов("Соответствие")); - ТаблицаСвойств.Колонки.Добавить("КлючиДоступаПользователейИГруппДоступа", Новый ОписаниеТипов("Булево")); - - СпискиСОграничением = Новый Соответствие(Контекст.ОбщийКонтекст.СпискиСОграничением); - СпискиСОтключеннымОграничением = Новый Соответствие; - СпискиСОтключеннымОграничениемЧтения = Новый Соответствие; - - Для Каждого ОписаниеСписка Из СпискиСОграничением Цикл - ПолноеИмя = ОписаниеСписка.Ключ; - - Если ТипЗнч(ОписаниеСписка.Значение) = Тип("Булево") Тогда - Свойства = ТаблицаСвойств.Добавить(); - Свойства.ПолноеИмя = ПолноеИмя; - СпискиСОграничением.Вставить(ПолноеИмя, Свойства); - Параметры = ПараметрыОграниченияДляВидаПользователей(ПолноеИмя, Контекст); - Свойства.Параметры = Параметры; - Иначе - Свойства = ОписаниеСписка.Значение; // См. СвойстваСписковДляРасчетаХранимыхПараметров - Параметры = Свойства.Параметры; - КонецЕсли; - - Если Параметры.ОграничениеЧтенияОтключено Тогда - СпискиСОтключеннымОграничениемЧтения.Вставить(ПолноеИмя, Истина); - КонецЕсли; - Если Параметры.ОграничениеОтключено Тогда - СпискиСОтключеннымОграничением.Вставить(ПолноеИмя, Истина); - КонецЕсли; - Если Параметры.ЕстьОграничениеПоПользователям Тогда - Свойства.КлючиДоступаПользователей = Истина; - УстановитьСвойствоОграничения(ПолноеИмя, "РассчитыватьПраваПользователей", Истина, Контекст); - КонецЕсли; - Если Параметры.ПолеВладельца <> Неопределено Тогда - УстановитьСвойствоОграничения(ПолноеИмя, "ПолеВладельца", Параметры.ПолеВладельца, Контекст); - КонецЕсли; - - ВедущиеСписки = Параметры.ВедущиеСписки; - Если ВедущиеСписки.ПоКлючамДоступа.Количество() > 0 Тогда - Свойства.Зависимый = Истина; - Для Каждого КлючИЗначение Из ВедущиеСписки.ПоКлючамДоступа Цикл - ВедущийСписок = КлючИЗначение.Ключ; - Свойства.Ведущие.Добавить(ВедущийСписок); - СвойстваВедущего = СпискиСОграничением.Получить(ВедущийСписок); - Если СвойстваВедущего = Неопределено Или ТипЗнч(СвойстваВедущего) = Тип("Булево") Тогда - СвойстваВедущего = ТаблицаСвойств.Добавить(); - СвойстваВедущего.ПолноеИмя = ВедущийСписок; - СпискиСОграничением.Вставить(ВедущийСписок, СвойстваВедущего); - ПараметрыВедущего = ПараметрыОграниченияДляВидаПользователей(ВедущийСписок, Контекст); - СвойстваВедущего.Параметры = ПараметрыВедущего; - Если ПараметрыВедущего.ОграничениеЧтенияОтключено Тогда - СпискиСОтключеннымОграничениемЧтения.Вставить(ВедущийСписок, Истина); - КонецЕсли; - Если ПараметрыВедущего.ОграничениеОтключено Тогда - СпискиСОтключеннымОграничением.Вставить(ВедущийСписок, Истина); - КонецЕсли; - Если ПараметрыВедущего.ЕстьОграничениеПоПользователям Тогда - СвойстваВедущего.КлючиДоступаПользователей = Истина; - УстановитьСвойствоОграничения(ВедущийСписок, - "РассчитыватьПраваПользователей", Истина, Контекст); - КонецЕсли; - Если ПараметрыВедущего.ПолеВладельца <> Неопределено Тогда - УстановитьСвойствоОграничения(ВедущийСписок, - "ПолеВладельца", ПараметрыВедущего.ПолеВладельца, Контекст); - КонецЕсли; - КонецЕсли; - СвойстваВедущего.Ведущий = Истина; - СвойстваВедущего.Зависимые.Добавить(ПолноеИмя); - КонецЦикла; - КонецЕсли; - КонецЦикла; - - МаксимальныйУровень = 0; - Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Зависимый, Ведущий", Ложь, Истина)); - Для Каждого Строка Из Строки Цикл - УстановитьУровеньЗависимыхСписков(Строка, СпискиСОграничением, Новый Массив, МаксимальныйУровень); - КонецЦикла; - // Обработка зависимых списков, ведущих для самих себя (зацикленных на себя). - Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Обработан", Ложь)); - Для Каждого Строка Из Строки Цикл - УстановитьУровеньЗависимыхСписков(Строка, СпискиСОграничением, Новый Массив, МаксимальныйУровень); - КонецЦикла; - - Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Зависимый, Ведущий", Истина, Ложь)); - Для Каждого Строка Из Строки Цикл - НастроитьОптимизациюПоПолюВладельцу(Строка, СпискиСОграничением, Контекст); - КонецЦикла; - - // Сокращение зависимостей по ключам доступа зависимых объектов. - СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; - Отбор = Новый Структура("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Истина); - Строки = ТаблицаСвойств.НайтиСтроки(Отбор); - Для Каждого Строка Из Строки Цикл - СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Вставить(Строка.ПолноеИмя, Истина); - КонецЦикла; - ДополнительныйКонтекст = Контекст.ДополнительныйКонтекст; - ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения = СпискиСОтключеннымОграничениемЧтения; - ДополнительныйКонтекст.СпискиСОтключеннымОграничением = СпискиСОтключеннымОграничением; - ДополнительныйКонтекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - = СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей; - - Отбор = Новый Структура("Уровень, ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", 0, Истина); - Строки = ТаблицаСвойств.НайтиСтроки(Отбор); - Для Каждого Строка Из Строки Цикл - Строка.Параметры = ПараметрыОграниченияДляВидаПользователей(Строка.ПолноеИмя, Контекст); - КонецЦикла; - - СвойстваСписковПоУровням = Новый Массив; - Для Уровень = 1 По МаксимальныйУровень Цикл - СвойстваСписков = ТаблицаСвойств.НайтиСтроки(Новый Структура("Уровень", Уровень)); - СвойстваСписковПоУровням.Добавить(СвойстваСписков); - КонецЦикла; - - ОбщийКонтекстСпискиСОграничением = Контекст.ОбщийКонтекст.СпискиСОграничением; - - Для Каждого СвойстваСписков Из СвойстваСписковПоУровням Цикл - Для Каждого СвойстваСписка Из СвойстваСписков Цикл - СвойстваСписка = СвойстваСписка; // См. СвойстваСписковДляРасчетаХранимыхПараметров - - ВсеВедущиеСпискиСОграничением = Истина; - ИзмененоСвойствоРассчитыватьПраваПользователей = Ложь; - КлючиДоступаПользователей = Ложь; - КлючиДоступаГруппДоступа = Ложь; - - Для Каждого Ведущий Из СвойстваСписка.Ведущие Цикл - СвойстваВедущего = СпискиСОграничением.Получить(Ведущий); - Если СвойстваВедущего.КлючиДоступаПользователей Тогда - КлючиДоступаПользователей = Истина; - Иначе - КлючиДоступаГруппДоступа = Истина; - КонецЕсли; - Если ОбщийКонтекстСпискиСОграничением.Получить(Ведущий) = Неопределено - Или СпискиСОтключеннымОграничением.Получить(Ведущий) <> Неопределено Тогда - ВсеВедущиеСпискиСОграничением = Ложь; - КонецЕсли; - КонецЦикла; - - Если КлючиДоступаПользователей Тогда - Если Не СвойстваСписка.ОграничениеПоВладельцуВключено - И Не СвойстваСписка.КлючиДоступаПользователей Тогда - - ИзмененоСвойствоРассчитыватьПраваПользователей = Истина; - УстановитьСвойствоОграничения(СвойстваСписка.ПолноеИмя, - "РассчитыватьПраваПользователей", Истина, Контекст); - КонецЕсли; - СвойстваСписка.КлючиДоступаПользователей = Истина; - Если СвойстваСписка.ОграничениеПоВладельцуВключено - И КлючиДоступаГруппДоступа Тогда - СвойстваСписка.КлючиДоступаПользователейИГруппДоступа = Истина; - КонецЕсли; - КонецЕсли; - - Если СвойстваСписка.ОграничениеПоВладельцуВключено - И ВсеВедущиеСпискиСОграничением - И Не ИзмененоСвойствоРассчитыватьПраваПользователей - И СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(СвойстваСписка.ПолноеИмя) = Неопределено - Тогда - Продолжить; - КонецЕсли; - - СвойстваСписка.Параметры = - ПараметрыОграниченияДляВидаПользователей(СвойстваСписка.ПолноеИмя, Контекст); - КонецЦикла; - КонецЦикла; - - // Заполнение хранимых свойств списков. - Для Каждого СвойстваСписка Из ТаблицаСвойств Цикл - ПолноеИмя = СвойстваСписка.ПолноеИмя; - - Если СвойстваСписка.Параметры.ДоступЗапрещен Тогда - УстановитьСвойствоОграничения(ПолноеИмя, "ДоступЗапрещен", Истина, Контекст); - КонецЕсли; - Если ЗначениеЗаполнено(СвойстваСписка.Параметры.ИмяОтдельногоРегистраКлючей) Тогда - УстановитьСвойствоОграничения(ПолноеИмя, - "ИмяОтдельногоРегистраКлючей", СвойстваСписка.Параметры.ИмяОтдельногоРегистраКлючей, Контекст); - КонецЕсли; - Если ЗначениеЗаполнено(СвойстваСписка.Параметры.ОпорныеПоля) Тогда - ОпорныеПоля = Новый Структура("Все, ТипыВсех, Используемые"); - ЗаполнитьЗначенияСвойств(ОпорныеПоля, СвойстваСписка.Параметры.ОпорныеПоля); - УстановитьСвойствоОграничения(ПолноеИмя, "ОпорныеПоля", ОпорныеПоля, Контекст); - КонецЕсли; - Если СвойстваСписка.КлючиДоступаПользователейИГруппДоступа Тогда - УстановитьСвойствоОграничения(ПолноеИмя, - "ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа", Истина, Контекст); - ИначеЕсли СвойстваСписка.КлючиДоступаПользователей Тогда - УстановитьСвойствоОграничения(ПолноеИмя, - "ОграничениеВШаблонахЧерезКлючиДоступаПользователей", Истина, Контекст); - КонецЕсли; - Если СвойстваСписка.Параметры.ОграничениеЧтенияОтключено Тогда - СпискиСОтключеннымОграничениемЧтения.Вставить(ПолноеИмя, Истина); - КонецЕсли; - Если СвойстваСписка.Параметры.ОграничениеОтключено Тогда - СпискиСОтключеннымОграничением.Вставить(ПолноеИмя, Истина); - КонецЕсли; - УстановитьСвойствоОграничения(ПолноеИмя, "ИспользуемыеТипыЗначенийДоступа", - Новый ХранилищеЗначения(СвойстваСписка.Параметры.ИспользуемыеТипыЗначенийДоступа), Контекст); - - Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, СвойстваСписка.Параметры.Версия); - Если Контекст.ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда - СтрокиВерсийСписков = Контекст.ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.СтрокиВерсийСписков; // См. НовыеСтрокиВерсийСписков - НоваяСтрока = СтрокиВерсийСписков.Добавить(); - НоваяСтрока.Список = СвойстваСписка.ПолноеИмя; - НоваяСтрока.ДляВнешнихПользователей = Контекст.ДляВнешнихПользователей; - НоваяСтрока.Версия = СвойстваСписка.Параметры.Версия; - НоваяСтрока.СтрокаВерсии = СвойстваСписка.Параметры.Контекст.СтрокаСвойствВерсии; - КонецЕсли; - - ВедущиеСписки = СвойстваСписка.Параметры.ВедущиеСписки; - - Если ВедущиеСписки.ПоЗначениямПолей.Количество() > 0 - Или ВедущиеСписки.ПоКлючамДоступа.Количество() > 0 - Или ВедущиеСписки.ПоЗначениямСГруппами.Количество() > 0 Тогда - - Контекст.ВедущиеСписки.Вставить(ПолноеИмя, ВедущиеСписки); - КонецЕсли; - - НастроитьПараметрыШаблонов(СвойстваСписка, Контекст); - - Если СвойстваСписка.Параметры.СписокСДатой Тогда - Контекст.СпискиСДатой.Вставить(СвойстваСписка.ПолноеИмя, Истина); - КонецЕсли; - - Для Каждого КлючИЗначение Из СвойстваСписка.Параметры.ВсеВидыОграниченийПрав Цикл - Контекст.ВсеВидыОграниченийПрав.Вставить(СвойстваСписка.ПолноеИмя + "." + КлючИЗначение.Ключ, Истина); - КонецЦикла; - - Если ЗначениеЗаполнено(СвойстваСписка.Параметры.Контекст.ВедущиеРоли) Тогда - Для Каждого КлючИЗначение Из СвойстваСписка.Параметры.Контекст.ВедущиеРоли Цикл - ЗависимыеСписки = Контекст.ВедущиеРоли.Получить(КлючИЗначение.Ключ); - Если ЗависимыеСписки = Неопределено Тогда - ЗависимыеСписки = Новый Соответствие; - Контекст.ВедущиеРоли.Вставить(КлючИЗначение.Ключ, ЗависимыеСписки); - КонецЕсли; - ЗависимыеСписки.Вставить(СвойстваСписка.ПолноеИмя, Истина); - КонецЦикла; - КонецЕсли; - - ЗаполнитьСпискиБезВнедрения(Контекст.СпискиБезВнедрения, СвойстваСписка); - КонецЦикла; - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ПолноеИмя - Строка -// * Зависимый - Булево -// * Ведущие - Массив -// * Уровень - Число -// * Ведущий - Булево -// * Параметры - Структура -// * Обработан - Булево -// * ОграничениеПоВладельцуВозможно - Булево -// * ОграничениеПоВладельцуВключено - Булево -// * КлючиДоступаПользователей - Булево -// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево -// * КлючиДоступаПользователейИГруппДоступа - Булево -// -Функция СвойстваСписковДляРасчетаХранимыхПараметров() - - Возврат Неопределено; - -КонецФункции - -// Для процедуры ХранимыеПараметрыОграниченияДляВидаПользователей. -// -// Возвращаемое значение: -// см. ПараметрыОграниченияПоСтруктуреОграничения -// -Функция ПараметрыОграниченияДляВидаПользователей(ПолноеИмя, Контекст) - - ОписаниеОграничения = Контекст.ДополнительныйКонтекст.ОписанияОграничений.Получить(ПолноеИмя); - - Если ОписаниеОграничения = Неопределено Тогда - СтруктураОграничения = Неопределено; - Иначе - СтруктураОграничения = РассчитаннаяСтруктураОграничения(ПолноеИмя, - ОписаниеОграничения.Текст, ОписаниеОграничения.ВМодулеМенеджера, Контекст.ДляВнешнихПользователей); - КонецЕсли; - - Возврат ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, - СтруктураОграничения, - Контекст.ДляВнешнихПользователей, - Контекст.ОбщийКонтекст, - Контекст.ДополнительныйКонтекст); - -КонецФункции - -// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. -Процедура УстановитьУровеньЗависимыхСписков(СвойстваВедущегоСписка, СвойстваСписков, ПредыдущиеВедущие, - МаксимальныйУровень) - - ПредыдущиеВедущие.Добавить(СвойстваВедущегоСписка.ПолноеИмя); - - Для Каждого ЗависимыйСписок Из СвойстваВедущегоСписка.Зависимые Цикл - Если ПредыдущиеВедущие.Найти(ЗависимыйСписок) <> Неопределено Тогда - УчастникиЦикла = ""; - Индекс = ПредыдущиеВедущие.Количество() - 1; - Пока Истина Цикл - УчастникиЦикла = "- " + ПредыдущиеВедущие[Индекс] + Символы.ПС + УчастникиЦикла; - Если ПредыдущиеВедущие[Индекс] = ЗависимыйСписок Тогда - Прервать; - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - УчастникиЦикла = УчастникиЦикла + "(!) " + ЗависимыйСписок; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ограничения доступа, заполненные в процедурах %1 - |модулей менеджеров или общем модуле %2, - |содержат недопустимую циклическую зависимость при использовании функции - |%3 или %4 в одном или нескольких - |списках-участниках цикла: - |%5'"), - "ПриЗаполненииОграниченияДоступа", - "УправлениеДоступомПереопределяемый", - "ЧтениеОбъектаРазрешено", - "ИзменениеОбъектаРазрешено", - УчастникиЦикла); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - СвойстваЗависимогоСписка = СвойстваСписков.Получить(ЗависимыйСписок); - Если СвойстваЗависимогоСписка.Уровень < СвойстваВедущегоСписка.Уровень + 1 Тогда - СвойстваЗависимогоСписка.Уровень = СвойстваВедущегоСписка.Уровень + 1; - Если МаксимальныйУровень < СвойстваЗависимогоСписка.Уровень Тогда - МаксимальныйУровень = СвойстваЗависимогоСписка.Уровень; - КонецЕсли; - КонецЕсли; - Если Не СвойстваЗависимогоСписка.Ведущий Тогда - СвойстваЗависимогоСписка.Обработан = Истина; - Продолжить; - КонецЕсли; - УстановитьУровеньЗависимыхСписков(СвойстваЗависимогоСписка, СвойстваСписков, ПредыдущиеВедущие, МаксимальныйУровень); - КонецЦикла; - - ПредыдущиеВедущие.Удалить(ПредыдущиеВедущие.Количество() - 1); - СвойстваВедущегоСписка.Обработан = Истина; - -КонецПроцедуры - -// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. -Процедура НастроитьОптимизациюПоПолюВладельцу(СвойстваЗависимогоСписка, СвойстваСписков, Контекст) - - СвойстваЗависимогоСписка.ОграничениеПоВладельцуВозможно = - СвойстваЗависимогоСписка.Параметры.ПолеВладельца <> Неопределено; - - СвойстваЗависимогоСписка.ОграничениеПоВладельцуВключено = - СвойстваЗависимогоСписка.ОграничениеПоВладельцуВозможно - И Не СвойстваЗависимогоСписка.Параметры.ПолеВладельца.Отключено; - - ЗависимыйСписокСОптимизацией = СвойстваЗависимогоСписка.ОграничениеПоВладельцуВключено; - - Для Каждого ВедущийСписок Из СвойстваЗависимогоСписка.Ведущие Цикл - СвойстваВедущегоСписка = СвойстваСписков.Получить(ВедущийСписок); // См. СвойстваСписковДляРасчетаХранимыхПараметров - Если СвойстваВедущегоСписка.Параметры.ДоступЗапрещен Тогда - Продолжить; - КонецЕсли; - Если Не СвойстваВедущегоСписка.Зависимый Тогда - Если ЗависимыйСписокСОптимизацией Тогда - УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка); - КонецЕсли; - Продолжить; - КонецЕсли; - Если ЗависимыйСписокСОптимизацией Тогда - Если СвойстваВедущегоСписка.Параметры.ПолеВладельца <> Неопределено - И Не СвойстваВедущегоСписка.Параметры.ПолеВладельца.Отключено Тогда - Если СвойстваВедущегоСписка.Параметры.ТребуетсяОграничениеПоВладельцу Тогда - ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, - "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", но такая - |оптимизация невозможна, так как она требуется для зависимого списка ""%2"".'"), - ИмяПризнакаОптимизации, - СвойстваЗависимогоСписка.ПолноеИмя); - КонтекстОшибки = Новый Структура("СпискиСОграничением, ОписанияОграничений"); - КонтекстОшибки.Вставить("Список", СвойстваВедущегоСписка.ПолноеИмя); - КонтекстОшибки.Вставить("ОписанияОграничений", Контекст.ДополнительныйКонтекст.ОписанияОграничений); - КонтекстОшибки.Вставить("ДляВнешнихПользователей", Контекст.ДляВнешнихПользователей); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, КонтекстОшибки); - ВызватьИсключение ТекстОшибки; - Иначе - СвойстваВедущегоСписка.ОграничениеПоВладельцуВключено = Ложь; - СвойстваВедущегоСписка.Параметры.ПолеВладельца.Отключено = Истина; - УстановитьСвойствоОграничения(СвойстваВедущегоСписка.ПолноеИмя, - "ПолеВладельца", СвойстваВедущегоСписка.Параметры.ПолеВладельца, Контекст); - КонецЕсли; - КонецЕсли; - УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка); - КонецЕсли; - НастроитьОптимизациюПоПолюВладельцу(СвойстваВедущегоСписка, СвойстваСписков, Контекст); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры НастроитьОптимизациюПоПолюВладельцу. -Процедура УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка) - - СвойстваВедущегоСписка.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина; - СвойстваВедущегоСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа.Вставить(СвойстваЗависимогоСписка.ПолноеИмя, Истина); - -КонецПроцедуры - -// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. -Процедура ЗаполнитьСпискиБезВнедрения(СпискиБезВнедрения, СвойстваСписка) - - Если СпискиБезВнедрения = Неопределено Тогда - Возврат; - КонецЕсли; - - Параметры = СвойстваСписка.Параметры; - - Если Параметры.БезОбновленияКлючейДоступаКОбъектам - И СтрПолучитьСтроку(Параметры.Версия, 1) <> " " - И Не ЭтоУстаревшийОбъектМетаданных(СвойстваСписка.ПолноеИмя) Тогда - - Если СтрПолучитьСтроку(Параметры.Версия, 1) = " " Тогда - Списки = СпискиБезВнедрения.ОбъектыПредупреждения; - Иначе - Списки = СпискиБезВнедрения.ОбъектыОшибки; - КонецЕсли; - ЗависимыеСписки = Списки.Получить(СвойстваСписка.ПолноеИмя); - Если ЗначениеЗаполнено(ЗависимыеСписки) Тогда - Для Каждого КлючИЗначение Из СвойстваСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа Цикл - ЗависимыеСписки.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - Иначе - ЗависимыеСписки = СвойстваСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа; - Списки.Вставить(СвойстваСписка.ПолноеИмя, ЗависимыеСписки); - КонецЕсли; - Если ЗначениеЗаполнено(СтрПолучитьСтроку(Параметры.Версия, 1)) Тогда - ЗависимыеСписки.Вставить("ЕстьОграничениеСписка", Истина); - КонецЕсли; - КонецЕсли; - - Если Параметры.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей Тогда - Контекст = Параметры.Контекст; - ТекстОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список).Текст; - ОписаниеРегистра = Новый Структура; - ОписаниеРегистра.Вставить("ПолноеИмя", СвойстваСписка.ПолноеИмя); - ОписаниеРегистра.Вставить("ИмяОтдельногоРегистраКлючей", Параметры.ИмяОтдельногоРегистраКлючей); - ОписаниеРегистра.Вставить("НедостающиеТипы", Контекст.ОпорныеПоля.НедостающиеТипы); - ОписаниеРегистра.Вставить("ПоляНедостающихТипов", Контекст.ОпорныеПоля.ПоляНедостающихТипов); - ОписаниеРегистра.Вставить("ТекстОграничения", ТекстОграничения); - СпискиБезВнедрения.РегистрыПредупреждения.Добавить(ОписаниеРегистра); - КонецЕсли; - -КонецПроцедуры - -// Для функции ЗаполнитьСпискиБезВнедрения. -Функция ЭтоУстаревшийОбъектМетаданных(ПолноеИмя) - - ЧастиИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Если ЧастиИмени.Количество() <> 2 Тогда - Возврат Ложь; - КонецЕсли; - - Возврат СтрНачинаетсяС(ВРег(ЧастиИмени[1]), ВРег("Удалить")); - -КонецФункции - -// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. -Процедура УстановитьСвойствоОграничения(ПолноеИмя, ИмяСвойства, ЗначениеСвойства, Контекст) - - Свойства = СвойстваОграниченияСписка(ПолноеИмя, Контекст.ДополнительныйКонтекст, Истина); - - Свойства[ИмяСвойства] = ЗначениеСвойства; - -КонецПроцедуры - -// Для процедур УстановитьСвойствоОграничения, ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. -Функция СвойстваОграниченияСписка(ПолноеИмя, Контекст, ДобавлятьВКоллекцию = Ложь) - - Свойства = Контекст.СвойстваОграниченияСписков.Получить(ПолноеИмя); - - Если Свойства = Неопределено Тогда - Свойства = НовыеСвойстваОграниченияСписка(); - Если ДобавлятьВКоллекцию Тогда - Контекст.СвойстваОграниченияСписков.Вставить(ПолноеИмя, Свойства); - КонецЕсли; - КонецЕсли; - - Возврат Свойства; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ДоступЗапрещен - Булево -// * ПолеВладельца - см. НовоеПолеВладельца -// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей -// * ИмяОтдельногоРегистраКлючей - Строка -// * РассчитыватьПраваПользователей - Булево -// * ИспользуемыеТипыЗначенийДоступа - ХранилищеЗначения - содержит тип Массив из Тип -// * ОграничениеВШаблонахЧерезКлючиДоступаПользователей - Булево -// * ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа - Булево -// -Функция НовыеСвойстваОграниченияСписка() - - Свойства = Новый Структура; - Свойства.Вставить("ДоступЗапрещен", Ложь); - Свойства.Вставить("ПолеВладельца", Неопределено); - Свойства.Вставить("ОпорныеПоля", Неопределено); - Свойства.Вставить("ИмяОтдельногоРегистраКлючей", ""); - Свойства.Вставить("РассчитыватьПраваПользователей", Ложь); - Свойства.Вставить("ОграничениеВШаблонахЧерезКлючиДоступаПользователей", Ложь); - Свойства.Вставить("ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа", Ложь); - Свойства.Вставить("ИспользуемыеТипыЗначенийДоступа", Неопределено); - - Возврат Свойства; - -КонецФункции - -// Для функции ХранимыеПараметрыОграниченияДоступа. -// -// Параметры: -// СпискиБезВнедрения - Соответствие -// ИнформацияДляЖурнала - см. НоваяИнформацияНесоответствияПараметровДляЖурнала -// -Процедура ЗаполнитьНесоответствиеПараметровДляЖурнала(СпискиБезВнедрения, ИнформацияДляЖурнала); - - Если ЗначениеЗаполнено(СпискиБезВнедрения.ОбъектыПредупреждения) Тогда - ИнформацияДляЖурнала.Предупреждение = ОписаниеНесоответствияПараметров( - СпискиБезВнедрения.ОбъектыПредупреждения); - КонецЕсли; - - Если ЗначениеЗаполнено(СпискиБезВнедрения.ОбъектыОшибки) Тогда - ИнформацияДляЖурнала.Ошибка = ОписаниеНесоответствияПараметров( - СпискиБезВнедрения.ОбъектыОшибки); - КонецЕсли; - - Если Не ЗначениеЗаполнено(СпискиБезВнедрения.РегистрыПредупреждения) Тогда - Возврат; - КонецЕсли; - - Предупреждения = Новый СписокЗначений; - - Для Каждого ОписаниеРегистра Из СпискиБезВнедрения.РегистрыПредупреждения Цикл - Если ЗначениеЗаполнено(ОписаниеРегистра.ИмяОтдельногоРегистраКлючей) Тогда - Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В таблице %1 будут недоступны строки - |для значений которых в измерениях регистра сведений - | %2 - |не хватает типов: - | - %3, - |имеющихся у полей (%4) в ограничении доступа: - | %5'"), - ОписаниеРегистра.ПолноеИмя, - ОписаниеРегистра.ИмяОтдельногоРегистраКлючей, - СтрСоединить(ОписаниеРегистра.НедостающиеТипы, "," + Символы.ПС + " - "), - СтрСоединить(ОписаниеРегистра.ПоляНедостающихТипов, ", "), - ТекстСОтступом(ОписаниеРегистра.ТекстОграничения, " ")); - Иначе - Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В таблице %1 будут недоступны строки для значений которых - |в определяемом типе %2 не хватает типов: - | - %3, - |имеющихся у полей (%4) в ограничении доступа: - | %5'"), - ОписаниеРегистра.ПолноеИмя, - "ПолеРегистраКлючейДоступаКРегистрам", - СтрСоединить(ОписаниеРегистра.НедостающиеТипы, "," + Символы.ПС + " - "), - СтрСоединить(ОписаниеРегистра.ПоляНедостающихТипов, ", "), - ТекстСОтступом(ОписаниеРегистра.ТекстОграничения, " ")); - КонецЕсли; - Предупреждения.Добавить(Текст, ОписаниеРегистра.ПолноеИмя); - КонецЦикла; - - Предупреждения.СортироватьПоПредставлению(); - Если ЗначениеЗаполнено(ИнформацияДляЖурнала.Предупреждение) Тогда - Предупреждения.Вставить(0, ИнформацияДляЖурнала.Предупреждение); - КонецЕсли; - ИнформацияДляЖурнала.Предупреждение = - СтрСоединить(Предупреждения.ВыгрузитьЗначения(), Символы.ПС + Символы.ПС + Символы.ПС); - -КонецПроцедуры - -// Для процедуры ЗаполнитьНесоответствиеПараметровДляЖурнала. -Функция ОписаниеНесоответствияПараметров(СпискиБезВнедрения) - - Списки = Новый СписокЗначений; - ВедущиеСписки = Новый СписокЗначений; - - Для Каждого ВедущийСписок Из СпискиБезВнедрения Цикл - ЗависимыеСписки = Новый СписокЗначений; - Для Каждого ЗависимыйСписок Из ВедущийСписок.Значение Цикл - Если ЗависимыйСписок.Ключ = "ЕстьОграничениеСписка" Тогда - Списки.Добавить(ВедущийСписок.Ключ); - Иначе - ЗависимыеСписки.Добавить(ЗависимыйСписок.Ключ); - КонецЕсли; - КонецЦикла; - Если Не ЗначениеЗаполнено(ЗависимыеСписки) Тогда - Продолжить; - КонецЕсли; - ЗависимыеСписки.СортироватьПоЗначению(); - - ВедущиеСписки.Добавить(ВедущийСписок.Ключ + " {" + Символы.ПС + " " - + СтрСоединить(ЗависимыеСписки.ВыгрузитьЗначения(), Символы.ПС + " ") - + Символы.ПС + "}", ВедущийСписок.Ключ); - КонецЦикла; - - Результат = Новый Массив; - - Если ЗначениеЗаполнено(Списки) Тогда - Списки.СортироватьПоПредставлению(); - Результат.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Типы следующих таблиц не указаны в определяемом типе %1, - |поэтому их строки будут недоступны: - | - |%2'"), - "ВладелецЗначенийКлючейДоступа", - СтрСоединить(Списки.ВыгрузитьЗначения(), Символы.ПС))); - КонецЕсли; - - Если ЗначениеЗаполнено(ВедущиеСписки) Тогда - ВедущиеСписки.СортироватьПоПредставлению(); - Результат.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Типы следующих ведущих таблиц не указаны в определяемом типе %1, - |поэтому в зависимых от них таблицах (в фигурных скобках) - |будут недоступны строки, содержащие ссылки на объекты этих типов - |в тех полях, которые используются в ограничении доступа к ним: - | - |%2'"), - "ВладелецЗначенийКлючейДоступа", - СтрСоединить(ВедущиеСписки.ВыгрузитьЗначения(), Символы.ПС))); - КонецЕсли; - - Возврат СтрСоединить(Результат, Символы.ПС + Символы.ПС + Символы.ПС); - -КонецФункции - -// Для функции ХранимыеПараметрыОграниченияДоступа. -Процедура ДобавитьВедущиеРоли(ВедущиеРоли, ИмяСвойстваВидаПользователей, КонтекстВидаПользователей) - - Для Каждого ОписаниеВедущейРоли Из КонтекстВидаПользователей.ВедущиеРоли Цикл - ИмяРоли = ОписаниеВедущейРоли.Ключ; - ЗависимыеСписки = ВедущиеРоли.Получить(ИмяРоли); - Если ЗависимыеСписки = Неопределено Тогда - ЗависимыеСписки = Новый Структура("ДляПользователей, ДляВнешнихПользователей"); - ВедущиеРоли.Вставить(ИмяРоли, ЗависимыеСписки); - КонецЕсли; - ЗависимыеСписки[ИмяСвойстваВидаПользователей] = - Новый ФиксированноеСоответствие(ОписаниеВедущейРоли.Значение); - КонецЦикла; - -КонецПроцедуры - -// Для функции ХранимыеПараметрыОграниченияДоступа. -Процедура ДобавитьВедущиеСписки(ВедущиеСписки, ИмяСвойстваВидаПользователей, ЗависимыйСписок, - ВедущиеСпискиЗависимогоСписка) - - Для Каждого ОписаниеВедущегоСписка Из ВедущиеСпискиЗависимогоСписка.ПоЗначениямПолей Цикл - ВедущийСписок = ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ОписаниеВедущегоСписка.Ключ); - ВедущийСписок.ЗависимыеСписки.Вставить(ЗависимыйСписок, Истина); - ДобавляемыеПоля = ОписаниеВедущегоСписка.Значение; - - Если ВедущийСписок.ПоЗначениямПолей = Неопределено Тогда - ПоЗначениямПолей = Новый Структура; - ПоЗначениямПолей.Вставить("ЭтоСсылочныйТип", ДобавляемыеПоля.ЭтоСсылочныйТип); - ПоЗначениямПолей.Вставить("ПоляШапки", ОписаниеПолейВедущегоСписка()); - Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда - ПоЗначениямПолей.Вставить("ТабличныеЧасти", Новый Соответствие); - КонецЕсли; - ВедущийСписок.ПоЗначениямПолей = ПоЗначениямПолей; - Иначе - ПоЗначениямПолей = ВедущийСписок.ПоЗначениямПолей; - КонецЕсли; - - ДобавитьПоляВедущегоСписка(ПоЗначениямПолей.ПоляШапки, ДобавляемыеПоля.ДляОтслеживания.ПоляШапки, - ДобавляемыеПоля.ДляОтбора.ПоляШапки, ЗависимыйСписок, ИмяСвойстваВидаПользователей); - - Для Каждого ТабличнаяЧасть Из ДобавляемыеПоля.ДляОтслеживания.ТабличныеЧасти Цикл - ОписаниеТабличнойЧасти = ПоЗначениямПолей.ТабличныеЧасти.Получить(ТабличнаяЧасть.Ключ); - Если ОписаниеТабличнойЧасти = Неопределено Тогда - ОписаниеТабличнойЧасти = ОписаниеПолейВедущегоСписка(); - ОписаниеТабличнойЧасти.Вставить("Имя", ТабличнаяЧасть.Ключ); - ПоЗначениямПолей.ТабличныеЧасти.Вставить(ТабличнаяЧасть.Ключ, ОписаниеТабличнойЧасти); - КонецЕсли; - ТабличнаяЧастьПоляОтбора = ДобавляемыеПоля.ДляОтбора.ТабличныеЧасти.Получить(ТабличнаяЧасть.Ключ); - ДобавитьПоляВедущегоСписка(ОписаниеТабличнойЧасти, ТабличнаяЧасть.Значение, - ТабличнаяЧастьПоляОтбора, ЗависимыйСписок, ИмяСвойстваВидаПользователей); - КонецЦикла; - КонецЦикла; - - ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, - ИмяСвойстваВидаПользователей, ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, "ПоКлючамДоступа"); - - ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, - ИмяСвойстваВидаПользователей, ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, "ПоЗначениямСГруппами"); - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * ЭтоСсылочныйТип - Булево -// * ПоляШапки - см. ОписаниеПолейВедущегоСписка -// * ТабличныеЧасти - Массив из см. ОписаниеПолейВедущегоСписка -// -Функция ВедущийСписокПоЗначениямПолей() - - Возврат Новый Структура; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ДляПользователей - Массив из Строка - полные имена списков -// * ДляВнешнихПользователей - Массив из Строка - полные имена списков -// -Функция ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами() - - Возврат Новый Структура; - -КонецФункции - -// Для процедуры ДобавитьВедущиеСписки. -// -// Возвращаемое значение: -// Структура: -// * ВсеПоля - Массив -// * ТипыВсехПолей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя поля. -// ** Значение - ХранилищеЗначения - содержит тип ОписаниеТипов - тип поля. -// * НаборыПолей - Структура: -// ** ДляПользователей - Булево -// ** ДляВнешнихПользователей - Булево -// * Имя - Строка - имя табличной части (есть только у полей табличной части) -// -Функция ОписаниеПолейВедущегоСписка() - - Описание = Новый Структура; - Описание.Вставить("ВсеПоля", Новый Массив); - Описание.Вставить("ТипыВсехПолей", Новый Соответствие); - Описание.Вставить("НаборыПолей", Новый Структура("ДляПользователей, ДляВнешнихПользователей")); - - Возврат Описание; - -КонецФункции - -// Для процедуры ДобавитьВедущиеСписки. -Процедура ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, ИмяСвойстваВидаПользователей, - ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, ВидЗависимости) - - Для Каждого ОписаниеВедущегоСписка Из ВедущиеСпискиЗависимогоСписка[ВидЗависимости] Цикл - ВедущийСписок = ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ОписаниеВедущегоСписка.Ключ); - ВедущийСписок.ЗависимыеСписки.Вставить(ЗависимыйСписок, Истина); - - Если ВедущийСписок[ВидЗависимости] = Неопределено Тогда - Свойства = ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами(); - Свойства.Вставить("ДляПользователей", Неопределено); - Свойства.Вставить("ДляВнешнихПользователей", Неопределено); - ВедущийСписок[ВидЗависимости] = Свойства; - Иначе - Свойства = ВедущийСписок[ВидЗависимости]; - КонецЕсли; - - Если Свойства[ИмяСвойстваВидаПользователей] = Неопределено Тогда - Свойства[ИмяСвойстваВидаПользователей] = Новый Массив; - КонецЕсли; - ЗависимыеСписки = Свойства[ИмяСвойстваВидаПользователей]; // Массив - ЗависимыеСписки.Добавить(ЗависимыйСписок); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ДобавитьВедущиеСписки. -// -// Возвращаемое значение: -// Структура: -// * ЗависимыеСписки - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * ПоЗначениямПолей - Структура - похожая на см. ВедущийСписокПоПоЗначениямПолей -// * ПоКлючамДоступа - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами -// * ПоЗначениямСГруппами - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами -// -Функция ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ПолноеИмя) - - ВедущийСписок = ВедущиеСписки.Получить(ПолноеИмя); - Если ВедущийСписок = Неопределено Тогда - ВедущийСписок = Новый Структура; - ВедущийСписок.Вставить("ЗависимыеСписки", Новый Соответствие); - ВедущийСписок.Вставить("ПоЗначениямПолей", Неопределено); - ВедущийСписок.Вставить("ПоКлючамДоступа", Неопределено); - ВедущийСписок.Вставить("ПоЗначениямСГруппами", Неопределено); - ВедущиеСписки.Вставить(ПолноеИмя, ВедущийСписок) - КонецЕсли; - - Возврат ВедущийСписок; - -КонецФункции - -// Для процедуры ДобавитьВедущиеСписки. -Процедура ДобавитьПоляВедущегоСписка(ТекущиеПоля, ОписаниеПолей, ОписаниеПолейОтбора, ЗависимыйСписок, - ИмяСвойстваВидаПользователей) - - СписокПолей = Новый СписокЗначений; - Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл - Если ТекущиеПоля.ВсеПоля.Найти(ОписаниеПоля.Ключ) = Неопределено Тогда - ТекущиеПоля.ВсеПоля.Добавить(ОписаниеПоля.Ключ); - ТекущиеПоля.ТипыВсехПолей.Вставить(ОписаниеПоля.Ключ, ОписаниеПоля.Значение); - КонецЕсли; - СписокПолей.Добавить(ОписаниеПоля.Ключ); - КонецЦикла; - СписокПолей.СортироватьПоЗначению(); - НаборПолей = СтрСоединить(СписокПолей.ВыгрузитьЗначения(), ", "); - - НаборыПолей = ТекущиеПоля.НаборыПолей[ИмяСвойстваВидаПользователей]; - Если НаборыПолей = Неопределено Тогда - НаборыПолей = Новый Соответствие; - ТекущиеПоля.НаборыПолей[ИмяСвойстваВидаПользователей] = НаборыПолей; - КонецЕсли; - ЗависимыеСпискиПоПолямОтбора = НаборыПолей.Получить(НаборПолей); - Если ЗависимыеСпискиПоПолямОтбора = Неопределено Тогда - ЗависимыеСпискиПоПолямОтбора = Новый Соответствие; - НаборыПолей.Вставить(НаборПолей, ЗависимыеСпискиПоПолямОтбора); - КонецЕсли; - - СписокПолей = Новый СписокЗначений; - Для Каждого ОписаниеПоля Из ОписаниеПолейОтбора Цикл - СписокПолей.Добавить(ОписаниеПоля.Ключ); - КонецЦикла; - СписокПолей.СортироватьПоЗначению(); - НаборПолейОтбора = СтрСоединить(СписокПолей.ВыгрузитьЗначения(), ", "); - - ЗависимыеСписки = ЗависимыеСпискиПоПолямОтбора.Получить(НаборПолейОтбора); - Если ЗависимыеСписки = Неопределено Тогда - ЗависимыеСписки = Новый Массив; - ЗависимыеСпискиПоПолямОтбора.Вставить(НаборПолейОтбора, ЗависимыеСписки); - КонецЕсли; - ЗависимыеСписки.Добавить(ЗависимыйСписок); - -КонецПроцедуры - -// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. -Процедура НастроитьПараметрыШаблонов(СвойстваСписка, Контекст) - - Параметры = СвойстваСписка.Параметры; - ПараметрыШаблонов = Контекст.ПараметрыШаблонов; - - Если Параметры.ДоступЗапрещен Тогда - Уточнение = ?(Контекст.ДляВнешнихПользователей - И Не Контекст.ОбщийКонтекст.ВнешниеПользователиВключены, "1", "0"); - ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = - ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - + СвойстваСписка.ПолноеИмя + ";" + Уточнение + Символы.ПС; - Возврат; - КонецЕсли; - - Если Не Параметры.ИспользуетсяОграничениеПоВладельцу - И Не Параметры.ЭтоСсылочныйТип - И Не Параметры.ОграничениеОтключено Тогда - - ОпорныеПоля = Параметры.ОпорныеПоля; - Версия = НоваяВерсияПараметровШаблонов(); - Версия.ДатаСоздания = Контекст.ДатаСоздания; - Версия.Список = СвойстваСписка.ПолноеИмя; - Версия.ПоляСоединения = СтрСоединить(ОпорныеПоля.Используемые, ","); - Версия.ПоляШаблона = СтрСоединить(ОпорныеПоля.Все, ","); - Версия.ВариантДоступа = ОпорныеПоля.Используемые.Количество() * 2 - + ?(Контекст.ДляВнешнихПользователей, 1, 0); - Версии = Новый Массив; - Версии.Добавить(Версия); - КлючТаблицы = КлючТаблицы(СвойстваСписка.ПолноеИмя, Параметры.Контекст.ИмяКоллекцииТипа); - Контекст.ВерсииПараметровШаблонов.Вставить(КлючТаблицы, Версии); - КонецЕсли; - - Если Параметры.ОграничениеЧтенияОтключено Тогда - ПараметрыШаблонов.СпискиСОтключеннымОграничениемЧтения = - ПараметрыШаблонов.СпискиСОтключеннымОграничениемЧтения - + СвойстваСписка.ПолноеИмя + ";" + Символы.ПС; - Возврат; - КонецЕсли; - - ПолеВладельцаОтключено = ""; - - Если Параметры.ИспользуетсяОграничениеПоВладельцу - Или Параметры.ЭтоСсылочныйТип Тогда - - ПолеВладельца = Параметры.ПолеВладельца; // См. НовоеПолеВладельца - Если ПолеВладельца <> Неопределено Тогда - Поля = ":" + ПолеВладельца.Имя; - Если Не Параметры.ИспользуетсяОграничениеПоВладельцу Тогда - ПолеВладельцаОтключено = ";-"; - КонецЕсли; - Иначе - Поля = ":"; - КонецЕсли; - Иначе - ОпорныеПоля = Параметры.ОпорныеПоля; - Если ЗначениеЗаполнено(Параметры.ИмяОтдельногоРегистраКлючей) Тогда - Поля = "КлючиДоступаКРегистру" + СтрРазделить(СвойстваСписка.ПолноеИмя, ".")[1]; - Иначе - Поля = УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных( - СвойстваСписка.ПолноеИмя); - КонецЕсли; - Поля = ":[" + Поля + "]"; - Номер = 1; - Для Каждого ИмяПоля Из ОпорныеПоля.Все Цикл - Поля = Поля + ":" + ИмяПоля; - Номер = Номер + 1; - КонецЦикла; - НомерПустогоПоля = ОпорныеПоля.Все.Количество() + 1; - Для Номер = НомерПустогоПоля По ОпорныеПоля.МаксимальноДопустимоеКоличество Цикл - Поля = Поля + ":"; - КонецЦикла; - КонецЕсли; - - ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = - ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - + СвойстваСписка.ПолноеИмя + Поля + ";*" + ПолеВладельцаОтключено + Символы.ПС; - - Если СвойстваСписка.КлючиДоступаПользователейИГруппДоступа - Или СвойстваСписка.КлючиДоступаПользователей Тогда - - ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаПользователей = - ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаПользователей - + СвойстваСписка.ПолноеИмя + Поля + ";+" + ПолеВладельцаОтключено + Символы.ПС; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры НастроитьПараметрыШаблонов. -// -// Параметры: -// ПолноеИмя - Строка -// ИмяКоллекцииТипа - Строка -// ТипыТаблицПоИменам - Соответствие -// -// Возвращаемое значение: -// Строка -// -Функция КлючТаблицы(ПолноеИмя, ИмяКоллекцииТипа = Неопределено, ТипыТаблицПоИменам = Неопределено) - - Если ИмяКоллекцииТипа = Неопределено Тогда - СвойстваТипа = ТипыТаблицПоИменам.Получить(ВРег(СтрРазделить(ПолноеИмя, ".", Ложь)[0])); - ИмяКоллекцииТипа = СвойстваТипа.ИмяКоллекции; - КонецЕсли; - - Если ИмяКоллекцииТипа = "РегистрыСведений" - Или ИмяКоллекцииТипа = "РегистрыНакопления" - Или ИмяКоллекцииТипа = "РегистрыБухгалтерии" - Или ИмяКоллекцииТипа = "РегистрыРасчета" Тогда - - ТипКлючаТаблицы = ТипКлючаЗаписиПоПолномуИмениМетаданных(ПолноеИмя); - - ИначеЕсли ИмяКоллекцииТипа = "Последовательности" Тогда - ТипКлючаТаблицы = ТипНабораЗаписейПоПолномуИмениМетаданных(ПолноеИмя); - - ИначеЕсли ИмяКоллекцииТипа = "ЖурналыДокументов" Тогда - ТипКлючаТаблицы = ТипМенеджераОбъектаПоПолномуИмениМетаданных(ПолноеИмя); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Неизвестный нессылочный объект метаданных - |""%1"" - |с поддержкой ограничений на уровне записей.'"), ПолноеИмя); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); - СтрокаДляХеширования = СтрокаДанныхДляХеширования(ТипКлючаТаблицы); - ХешированиеДанных.Добавить(СтрокаДляХеширования); - - Возврат Base64Строка(ХешированиеДанных.ХешСумма); - -КонецФункции - -// Для процедуры ОписаниеНовойВерсииПараметровОграниченияДоступа. -Процедура ЗаполнитьПараметрыДляШаблонов(Запись, ПараметрыЗаписи, ОписаниеВерсии) - - Если ТипЗнч(ОписаниеВерсии.ДатаСоздания) = Тип("Дата") Тогда - СтараяДатаСоздания = ОписаниеВерсии.ДатаСоздания; - Иначе - СтараяДатаСоздания = '00010101'; - КонецЕсли; - - ХранимыеТекущиеВерсии = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); - ТекущиеСвойстваОграниченияСписковДляПользователей = Новый Соответствие; - ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = Новый Соответствие; - ВерсииПараметровШаблоновПолучены = Ложь; - - Если ТипЗнч(ОписаниеВерсии.ВерсииПараметровШаблонов) = Тип("ХранилищеЗначения") Тогда - СодержимоеХранилища = ЗначениеИзХранилища(ОписаниеВерсии.ВерсииПараметровШаблонов); - Если ЗначениеЗаполнено(СодержимоеХранилища) Тогда - ХранимыеТекущиеВерсии = СтруктураХранимыхВерсийПараметровШаблонов(СодержимоеХранилища); - Если ХранимыеТекущиеВерсии.ВерсияСтруктурыВерсий = ВерсияСтруктурыВерсийПараметровШаблонов() Тогда - ВерсииПараметровШаблоновПолучены = Истина; - ТекущиеСвойстваОграниченияСписковДляПользователей = Неопределено; - ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = Неопределено; - Иначе - ХранимыеТекущиеВерсии = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); - КонецЕсли; - ИначеЕсли ТипЗнч(ОписаниеВерсии.Версия) = Тип("Число") Тогда - ТекущиеХранимыеПараметры = ВерсияПараметров(ОписаниеВерсии.Версия, Ложь, Ложь); - Если ТипЗнч(ТекущиеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав) = Тип("ХранилищеЗначения") Тогда - ТекущиеПараметрыЗаписи = СтруктураХранимыхПараметровЗаписи( - ЗначениеИзХранилища(ТекущиеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав)); - Если ТекущиеПараметрыЗаписи.ВерсияСтруктурыКэша = ВерсияСтруктурыКэша() - Или ТекущиеПараметрыЗаписи.ВерсияСтруктурыКэша = "20" Тогда - ТекущиеСвойстваОграниченияСписковДляПользователей = - ТекущиеПараметрыЗаписи.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков; - ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = - ТекущиеПараметрыЗаписи.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков; - КонецЕсли; - КонецЕсли; - КонецЕсли; - КонецЕсли; - Если Не ВерсииПараметровШаблоновПолучены Тогда - ОписаниеВерсии.ХешСумма = "#" + ОписаниеВерсии.ХешСумма; - КонецЕсли; - - Если ПараметрыЗаписи.Свойство("СтрокиВерсии") Тогда - СтрокиВерсии = ПараметрыЗаписи.СтрокиВерсии; - Иначе - СтрокиВерсии = Новый Структура; - КонецЕсли; - СтрокиВерсии.Вставить("СпискиСОграничениемПоПолямВСеансахПользователей"); - СтрокиВерсии.Вставить("СпискиСОграничениемПоПолямВСеансахВнешнихПользователей"); - - Если ТекущиеСвойстваОграниченияСписковДляПользователей <> Неопределено Тогда - НовыеПараметрыЗаписи = ПараметрыЗаписи.ХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить(); - НовыеСвойстваОграниченияСписковДляПользователей = - НовыеПараметрыЗаписи.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков; - НовыеСвойстваОграниченияСписковДляВнешнихПользователей = - НовыеПараметрыЗаписи.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков; - КонецЕсли; - - ХранимыеНовыеВерсии = ПараметрыЗаписи.ХранимыеПараметры.ВерсииПараметровШаблонов.Получить(); - ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); - - Параметры = НоваяСтруктураДляЗаполненияПараметровШаблонов(); - Параметры.Вставить("ИдентификаторыВсехСписков", ПараметрыЗаписи.ИдентификаторыВсехСписков); - Если ТипЗнч(ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа) = Тип("Массив") Тогда - Параметры.Вставить("ОтключитьДополнительныеВариантыДоступа"); - Иначе - ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа = Новый Массив; - КонецЕсли; - Параметры.Вставить("СтараяДатаСоздания", СтараяДатаСоздания); - Параметры.Вставить("ХешированиеДанных", ХешированиеДанных); - Параметры.Вставить("СпискиСНовымОсновнымВариантомДоступа", ПараметрыЗаписи.СпискиСНовымОсновнымВариантомДоступа); - Параметры.Вставить("СпискиСУстаревшимиВариантамиДоступа", ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа); - - Параметры.Вставить("ХранимыеТекущиеВерсии", ХранимыеТекущиеВерсии.ДляПользователей); - Параметры.Вставить("НовыеВерсииПолейСписков", ХранимыеНовыеВерсии.ДляПользователей.ВерсииПараметровШаблонов); - Параметры.Вставить("ТекущиеСвойстваОграниченияСписков", ТекущиеСвойстваОграниченияСписковДляПользователей); - Параметры.Вставить("НовыеСвойстваОграниченияСписков", НовыеСвойстваОграниченияСписковДляПользователей); - - ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, - Запись.ДляШаблоновВСеансахПользователей, - СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахПользователей); - - Параметры.ХранимыеТекущиеВерсии = ХранимыеТекущиеВерсии.ДляВнешнихПользователей; - Параметры.НовыеВерсииПолейСписков = ХранимыеНовыеВерсии.ДляВнешнихПользователей.ВерсииПараметровШаблонов; - Параметры.ТекущиеСвойстваОграниченияСписков = ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей; - Параметры.НовыеСвойстваОграниченияСписков = НовыеСвойстваОграниченияСписковДляВнешнихПользователей; - - ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, - Запись.ДляШаблоновВСеансахВнешнихПользователей, - СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахВнешнихПользователей); - - Запись.ХешСуммаПараметровШаблонов = Base64Строка(ХешированиеДанных.ХешСумма); - Запись.ВерсииПараметровШаблонов = Новый ХранилищеЗначения(ХранимыеТекущиеВерсии); - - ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); - ХешированиеДанных.Добавить(Запись.ХешСуммаПостоянныхПараметров); - ХешированиеДанных.Добавить(Запись.ХешСуммаПараметровШаблонов); - Запись.ХешСумма = Base64Строка(ХешированиеДанных.ХешСумма); - -КонецПроцедуры - -// Для процедуры ЗаполнитьПараметрыДляШаблонов. -// -// Возвращаемое значение: -// Структура: -// * СтараяДатаСоздания - Дата -// * ХешированиеДанных - ХешированиеДанных -// * СпискиСНовымОсновнымВариантомДоступа - Массив из Строка -// * СпискиСУстаревшимиВариантамиДоступа - Массив из Строка -// * ХранимыеТекущиеВерсии - Структура: -// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов -// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа -// * НовыеВерсииПолейСписков - см. НовыеВерсииПараметровШаблонов -// * ТекущиеСвойстваОграниченияСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. НовыеСвойстваОграниченияСписка -// * НовыеСвойстваОграниченияСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. НовыеСвойстваОграниченияСписка -// * ИдентификаторыВсехСписков - Неопределено -// - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных -// - СправочникСсылка.ИдентификаторыОбъектовРасширений -// -Функция НоваяСтруктураДляЗаполненияПараметровШаблонов() - - Возврат Новый Структура; - -КонецФункции - -// Для процедуры ЗаполнитьПараметрыДляШаблонов. -// -// Параметры: -// Параметры - см. НоваяСтруктураДляЗаполненияПараметровШаблонов -// ХранилищеДляШаблоновВСеансах - ХранилищеЗначения - обновляемое значение -// СпискиСОграничениемПоПолям - Строка - возвращаемое значение -// -Процедура ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, - ХранилищеДляШаблоновВСеансах, СпискиСОграничениемПоПолям) - - МаксимальноеКоличествоВерсий = МаксимальноеКоличествоВерсийВВариантеДоступа(); - НастройкиОграниченийСписков = Новый СписокЗначений; - ТекущиеВерсииПолейСписков = Параметры.ХранимыеТекущиеВерсии.ВерсииПараметровШаблонов; - - Если Параметры.ТекущиеСвойстваОграниченияСписков <> Неопределено Тогда - ВариантыДоступаВБазеДанных = ВариантыДоступаВБазеДанных(Параметры); - Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл - ТекущиеВерсииПолейСписка = Новый Массив; - ДобавитьСуществующиеВерсииПолейСписка(ТекущиеВерсииПолейСписка, - КлючИЗначение.Значение[0], ВариантыДоступаВБазеДанных, Параметры); - Если ЗначениеЗаполнено(ТекущиеВерсииПолейСписка) Тогда - ТекущиеВерсииПолейСписков.Вставить(КлючИЗначение.Ключ, ТекущиеВерсииПолейСписка); - КонецЕсли; - КонецЦикла; - КонецЕсли; - - ВозможноНеиспользуемыеВерсииПолейСписков = Новый Массив; - - Для Каждого КлючИЗначение Из ТекущиеВерсииПолейСписков Цикл - ТекущиеВерсииПолейСписка = КлючИЗначение.Значение; - НовыеВерсииПолейСписка = Параметры.НовыеВерсииПолейСписков.Получить(КлючИЗначение.Ключ); - - Если НовыеВерсииПолейСписка = Неопределено Тогда - ИспользованиеОтключалось = Ложь; - Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл - Если Версия.Используется Тогда - Версия.Используется = Ложь; - ИспользованиеОтключалось = Истина; - КонецЕсли; - КонецЦикла; - Если ИспользованиеОтключалось И ТекущиеВерсииПолейСписка.Количество() > 0 Тогда - ПолноеИмя = ТекущиеВерсииПолейСписка[0].Список; - Если ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) <> Неопределено Тогда - Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить( - ТекущиеВерсииПолейСписка[0].Список); - КонецЕсли; - КонецЕсли; - Продолжить; - КонецЕсли; - - НоваяВерсия = НовыеВерсииПолейСписка[0]; - НоваяВерсияСуществует = Ложь; - Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл - Если ВРег(Версия.ПоляСоединения) = ВРег(НоваяВерсия.ПоляСоединения) - И Версия.ВариантДоступа > 1 Тогда - НоваяВерсияСуществует = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - ОсновнаяВерсияИзменена = Истина; - Если НоваяВерсияСуществует Тогда - Индекс = ТекущиеВерсииПолейСписка.Найти(Версия); - Если Индекс > 0 Тогда - ТекущиеВерсииПолейСписка.Удалить(Индекс); - ТекущиеВерсииПолейСписка.Вставить(0, Версия); - Иначе - ОсновнаяВерсияИзменена = Ложь; - КонецЕсли; - ЗаполнитьЗначенияСвойств(Версия, НоваяВерсия,, "ВариантДоступа"); - Иначе - ИспользуемыеНомераВерсий = Новый Массив(МаксимальноеКоличествоВерсий); - СамаяСтараяВерсия = Неопределено; - УдаляемыеВерсии = Новый Массив; - Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл - НомерВерсии = Цел(Версия.ВариантДоступа / 64); - Если НоваяВерсия.ВариантДоступа <> (Версия.ВариантДоступа - НомерВерсии * 64) Тогда - Продолжить; - КонецЕсли; - Если НомерВерсии < МаксимальноеКоличествоВерсий Тогда - ИспользуемыеНомераВерсий[НомерВерсии] = Версия; - СамаяСтараяВерсия = Версия; - Иначе - УдаляемыеВерсии.Добавить(Версия); - КонецЕсли; - КонецЦикла; - Для Индекс = 0 По МаксимальноеКоличествоВерсий - 1 Цикл - Если ИспользуемыеНомераВерсий[Индекс] = Неопределено Тогда - Прервать; - КонецЕсли; - КонецЦикла; - Если Индекс >= МаксимальноеКоличествоВерсий Тогда - УдаляемыеВерсии.Добавить(СамаяСтараяВерсия); - НоваяВерсия.ВариантДоступа = НоваяВерсия.ВариантДоступа - + ИспользуемыеНомераВерсий.Найти(СамаяСтараяВерсия) * 64; - Иначе - НоваяВерсия.ВариантДоступа = НоваяВерсия.ВариантДоступа + Индекс * 64; - КонецЕсли; - Для Каждого УдаляемаяВерсия Из УдаляемыеВерсии Цикл - ТекущиеВерсииПолейСписка.Удалить(ТекущиеВерсииПолейСписка.Найти(УдаляемаяВерсия)); - КонецЦикла; - ТекущиеВерсииПолейСписка.Вставить(0, НоваяВерсия); - КонецЕсли; - - Если ОсновнаяВерсияИзменена Тогда - Параметры.СпискиСНовымОсновнымВариантомДоступа.Добавить( - ТекущиеВерсииПолейСписка[0].Список); - КонецЕсли; - - ОбновитьИспользованиеВерсийПолейСписка(ТекущиеВерсииПолейСписка, ОсновнаяВерсияИзменена, - ВозможноНеиспользуемыеВерсииПолейСписков, Параметры); - КонецЦикла; - - ОтключитьИспользованиеВерсийКромеОсновнойДляОбновленныхСписков( - ВозможноНеиспользуемыеВерсииПолейСписков, Параметры); - - ОсновныеВариантыДоступа = Параметры.ХранимыеТекущиеВерсии.ОсновныеВариантыДоступа; - - Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл - ТекущиеВерсииПолейСписка = ТекущиеВерсииПолейСписков.Получить(КлючИЗначение.Ключ); - Если ТекущиеВерсииПолейСписка = Неопределено Тогда - ТекущиеВерсииПолейСписка = КлючИЗначение.Значение; - ТекущиеВерсииПолейСписков.Вставить(КлючИЗначение.Ключ, ТекущиеВерсииПолейСписка); - Параметры.СпискиСНовымОсновнымВариантомДоступа.Добавить( - ТекущиеВерсииПолейСписка[0].Список); - КонецЕсли; - ИспользуемыеВариантыДоступа = Новый Массив; - Для Каждого ВерсияПолейСписка Из ТекущиеВерсииПолейСписка Цикл - Если ВерсияПолейСписка.Используется Тогда - ИспользуемыйВариантДоступа = НовыйИспользуемыйВариантДоступа(); - ИспользуемыйВариантДоступа.ВариантДоступа = ВерсияПолейСписка.ВариантДоступа; - ИспользуемыйВариантДоступа.ПоляСоединения = ВерсияПолейСписка.ПоляСоединения; - ИспользуемыеВариантыДоступа.Добавить(Новый ФиксированнаяСтруктура(ИспользуемыйВариантДоступа)); - КонецЕсли; - КонецЦикла; - ОсновныеВариантыДоступа.Вставить(ТекущиеВерсииПолейСписка[0].Список, - Новый ФиксированныйМассив(ИспользуемыеВариантыДоступа)); - КонецЦикла; - - Для Каждого КлючИЗначение Из ТекущиеВерсииПолейСписков Цикл - ДобавитьПоляОграниченияСписка(НастройкиОграниченийСписков, КлючИЗначение.Значение); - КонецЦикла; - - НастройкиОграниченийСписков.СортироватьПоПредставлению(); - СпискиСОграничениемПоПолям = СтрСоединить(НастройкиОграниченийСписков.ВыгрузитьЗначения(), Символы.ПС); - Параметры.ХешированиеДанных.Добавить(СпискиСОграничениемПоПолям); - - ХранимыеПараметрыШаблонов = Новый Структура(ХранилищеДляШаблоновВСеансах.Получить()); - ПараметрыШаблонов = Новый Структура(ХранимыеПараметрыШаблонов.ПараметрыШаблонов); - ПараметрыШаблонов.СпискиСОграничениемПоПолям = СпискиСОграничениемПоПолям; - ХранимыеПараметрыШаблонов.ПараметрыШаблонов = Новый ФиксированнаяСтруктура(ПараметрыШаблонов); - ХранилищеДляШаблоновВСеансах = Новый ХранилищеЗначения( - Новый ФиксированнаяСтруктура(ХранимыеПараметрыШаблонов)); - -КонецПроцедуры - -// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -Процедура ОбновитьИспользованиеВерсийПолейСписка(ТекущиеВерсииПолейСписка, ОсновнаяВерсияИзменена, - ВозможноНеиспользуемыеВерсииПолейСписков, Параметры) - - МаксимальноеКоличествоВариантовСоединений = МаксимальноеКоличествоВариантовСоединений(); - НоваяВерсия = ТекущиеВерсииПолейСписка[0]; - ПоляШаблона = СтрРазделить(ВРег(НоваяВерсия.ПоляШаблона), ",", Ложь); - - КоличествоИспользуемыхВерсий = 0; - ИспользованиеОтключалось = Ложь; - - Для Каждого ТекущаяВерсия Из ТекущиеВерсииПолейСписка Цикл - Если Не ТекущаяВерсия.Используется Тогда - Продолжить; - КонецЕсли; - Если ВРег(ТекущаяВерсия.ПоляШаблона) <> ВРег(НоваяВерсия.ПоляШаблона) Тогда - ИменаПолей = СтрРазделить(ТекущаяВерсия.ПоляСоединения, ",", Ложь); - Для Каждого ИмяПоля Из ИменаПолей Цикл - Если ПоляШаблона.Найти(ВРег(ИмяПоля)) = Неопределено Тогда - ТекущаяВерсия.Используется = Ложь; - ИспользованиеОтключалось = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если Не ТекущаяВерсия.Используется Тогда - Продолжить; - КонецЕсли; - Если КоличествоИспользуемыхВерсий >= МаксимальноеКоличествоВариантовСоединений Тогда - ТекущаяВерсия.Используется = Ложь; - ИспользованиеОтключалось = Истина; - Иначе - КоличествоИспользуемыхВерсий = КоличествоИспользуемыхВерсий + 1; - КонецЕсли; - КонецЦикла; - - Если ИспользованиеОтключалось Тогда - Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить( - ТекущиеВерсииПолейСписка[0].Список); - КонецЕсли; - - Если Не ОсновнаяВерсияИзменена И КоличествоИспользуемыхВерсий > 1 Тогда - ВозможноНеиспользуемыеВерсииПолейСписков.Добавить(ТекущиеВерсииПолейСписка); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -Процедура ДобавитьПоляОграниченияСписка(СпискиСОграничениемПоПолям, ТекущиеВерсииПолейСписка) - - НоваяВерсия = ТекущиеВерсииПолейСписка[0]; - ПолноеИмя = НоваяВерсия.Список; - ПоляШаблона = СтрРазделить(ВРег(НоваяВерсия.ПоляШаблона), ",", Ложь); - НастройкиОграниченийСписка = Новый Массив; - МаксимальноеКоличествоВариантов = МаксимальноеКоличествоВариантовСоединений(); - - НомерВарианта = 1; - Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл - Если Не Версия.Используется Тогда - Прервать; - КонецЕсли; - - НомерПоляСоединения = 1; - ИменаПолей = СтрРазделить(Версия.ПоляСоединения, ",", Ложь); - Для Каждого ИмяПоля Из ИменаПолей Цикл - НомерПоляШаблона = ПоляШаблона.Найти(ВРег(ИмяПоля)) + 1; - НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=%4;", - ПолноеИмя, - "Вариант" + XMLСтрока(НомерВарианта), - "Поле" + XMLСтрока(НомерПоляСоединения), - "Поле" + XMLСтрока(НомерПоляШаблона))); - НомерПоляСоединения = НомерПоляСоединения + 1; - КонецЦикла; - - Если Цел(Версия.ВариантДоступа / 2) = 0 Тогда - НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=0;", - ПолноеИмя, - "Вариант" + XMLСтрока(НомерВарианта), - "Версия" + XMLСтрока(НомерВарианта))); - Иначе - Остаток = Цел(Версия.ВариантДоступа / 64); - НомерБита = 0; - Пока Остаток > 0 Цикл - НовыйОстаток = Цел(Остаток / 2); - Если Остаток - НовыйОстаток * 2 > 0 Тогда - НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=1;", - ПолноеИмя, - "Версия" + XMLСтрока(НомерВарианта), - "Бит" + XMLСтрока(НомерБита))); - КонецЕсли; - Остаток = НовыйОстаток; - НомерБита = НомерБита + 1; - КонецЦикла; - КонецЕсли; - - НомерВарианта = НомерВарианта + 1; - Если НомерВарианта > МаксимальноеКоличествоВариантов Тогда - Прервать; - КонецЕсли; - КонецЦикла; - - СпискиСОграничениемПоПолям.Добавить( - СтрСоединить(НастройкиОграниченийСписка, Символы.ПС), ПолноеИмя); - -КонецПроцедуры - -// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -Функция ВариантыДоступаВБазеДанных(Параметры) - - Если Не ЗначениеЗаполнено(Параметры.НовыеВерсииПолейСписков) Тогда - Возврат Новый Соответствие; - КонецЕсли; - - ТекстОбщегоЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущаяТаблица.Регистр КАК Регистр, - | ТекущаяТаблица.ВариантДоступа КАК ВариантДоступа - |ИЗ - | РегистрСведений.КлючиДоступаКРегистрам КАК ТекущаяТаблица - |ГДЕ - | ВЫБОР - | КОГДА ТекущаяТаблица.ВариантДоступа = 0 - | ТОГДА ЛОЖЬ - | ИНАЧЕ ТекущаяТаблица.ВариантДоступа - (ВЫРАЗИТЬ(ТекущаяТаблица.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 - | КОНЕЦ = &ДляВнешнихПользователей - | - |УПОРЯДОЧИТЬ ПО - | Регистр, - | ВариантДоступа"; - - ТекстыЗапросов = Новый Массив; - ТекстыЗапросов.Добавить(ТекстОбщегоЗапроса); - - ПолныеИмена = Новый Массив; - ИндексыРезультатовЗапроса = Новый Соответствие; - - Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл - Список = КлючИЗначение.Значение[0].Список; - СвойстваСписка = Параметры.НовыеСвойстваОграниченияСписков.Получить(Список); - Если СвойстваСписка = Неопределено - Или Не ЗначениеЗаполнено(СвойстваСписка.ОпорныеПоля) Тогда - Продолжить; - КонецЕсли; - ПолныеИмена.Добавить(Список); - Если ЗначениеЗаполнено(СвойстваСписка.ИмяОтдельногоРегистраКлючей) Тогда - ИндексыРезультатовЗапроса.Вставить(Список, ТекстыЗапросов.Количество()); - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущаяТаблица.ВариантДоступа КАК ВариантДоступа - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | ВЫБОР - | КОГДА ТекущаяТаблица.ВариантДоступа = 0 - | ТОГДА ЛОЖЬ - | ИНАЧЕ ТекущаяТаблица.ВариантДоступа - (ВЫРАЗИТЬ(ТекущаяТаблица.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 - | КОНЕЦ = &ДляВнешнихПользователей - | - |УПОРЯДОЧИТЬ ПО - | ВариантДоступа"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", - "РегистрСведений." + СвойстваСписка.ИмяОтдельногоРегистраКлючей); - ТекстыЗапросов.Добавить(ТекстЗапроса); - Иначе - ИндексыРезультатовЗапроса.Вставить(Список, 0); - КонецЕсли; - КонецЦикла; - - ИдентификаторыСписков = ?(Параметры.ИдентификаторыВсехСписков = Неопределено, - ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена, Ложь), - Параметры.ИдентификаторыВсехСписков); - - Запрос = Новый Запрос; - ВариантДоступа = КлючИЗначение.Значение[0].ВариантДоступа; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ВариантДоступа - Цел(ВариантДоступа / 2) * 2 > 0); - Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - Выгрузка = РезультатыЗапроса[0].Выгрузить(); - Выгрузка.Индексы.Добавить("Регистр"); - - Результат = Новый Соответствие; - - Для Каждого КлючИЗначение Из ИндексыРезультатовЗапроса Цикл - Если КлючИЗначение.Значение = 0 Тогда - ИдентификаторСписка = ИдентификаторыСписков.Получить(КлючИЗначение.Ключ); - ВариантыДоступа = Новый Массив; - Если ИдентификаторСписка <> Неопределено И ИдентификаторСписка <> Null Тогда - НайденныеСтроки = Выгрузка.НайтиСтроки(Новый Структура("Регистр", ИдентификаторСписка)); - Для Каждого НайденнаяСтрока Из НайденныеСтроки Цикл - ВариантыДоступа.Добавить(НайденнаяСтрока.ВариантДоступа); - КонецЦикла; - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не найден идентификатор объекта метаданных ""%1"".'"), КлючИЗначение.Ключ); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - Результат.Вставить(КлючИЗначение.Ключ, ВариантыДоступа); - Иначе - Результат.Вставить(КлючИЗначение.Ключ, - РезультатыЗапроса[КлючИЗначение.Значение].Выгрузить().ВыгрузитьКолонку("ВариантДоступа")); - КонецЕсли; - КонецЦикла; - - Возврат Результат; - -КонецФункции - -// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -Процедура ОтключитьИспользованиеВерсийКромеОсновнойДляОбновленныхСписков( - ВозможноНеиспользуемыеВерсииПолейСписков, Параметры) - - Если Не ЗначениеЗаполнено(ВозможноНеиспользуемыеВерсииПолейСписков) - Или Не Параметры.Свойство("ОтключитьДополнительныеВариантыДоступа") Тогда - Возврат; - КонецЕсли; - - Списки = Новый Массив; - ВерсииПолейСписков = Новый Соответствие; - Для Каждого ВерсииПолейСписка Из ВозможноНеиспользуемыеВерсииПолейСписков Цикл - Список = ВерсииПолейСписка[0].Список; - Списки.Добавить(Список); - ВерсииПолейСписков.Вставить(Список, ВерсииПолейСписка); - КонецЦикла; - - ДляВнешнихПользователей = ВерсииПолейСписка[0].ВариантДоступа - - Цел(ВерсииПолейСписка[0].ВариантДоступа / 2) * 2 = 1; - - ТипыИдентификаторов = Новый Массив; - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); - ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); - - ИдентификаторыСписков = Новый ТаблицаЗначений; - ИдентификаторыСписков.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); - - СпискиПоИдентификаторам = Новый Соответствие; - ИдентификаторыОбъектов = ?(Параметры.ИдентификаторыВсехСписков = Неопределено, - ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки, Ложь), - Параметры.ИдентификаторыВсехСписков); - - Для Каждого Список Из Списки Цикл - ИдентификаторСписка = ИдентификаторыОбъектов.Получить(Список); - Если ИдентификаторСписка <> Неопределено И ИдентификаторСписка <> Null Тогда - ИдентификаторыСписков.Добавить().ИдентификаторСписка = ИдентификаторСписка; - СпискиПоИдентификаторам.Вставить(ИдентификаторСписка, Список); - КонецЕсли; - КонецЦикла; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); - Запрос.УстановитьПараметр("ИдентификаторыСписков", ИдентификаторыСписков); - Запрос.Текст = - "ВЫБРАТЬ - | ИдентификаторыСписков.ИдентификаторСписка КАК ИдентификаторСписка - |ПОМЕСТИТЬ ИдентификаторыСписков - |ИЗ - | &ИдентификаторыСписков КАК ИдентификаторыСписков - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ИдентификаторыСписков.ИдентификаторСписка КАК ИдентификаторСписка - |ИЗ - | ИдентификаторыСписков КАК ИдентификаторыСписков - |ГДЕ - | НЕ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным - | ГДЕ - | ОбновлениеКлючейДоступаКДанным.Список = ИдентификаторыСписков.ИдентификаторСписка - | И ОбновлениеКлючейДоступаКДанным.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И ОбновлениеКлючейДоступаКДанным.РазмерЗадания = 3)"; - - Выборка = Запрос.Выполнить().Выбрать(); - Пока Выборка.Следующий() Цикл - Список = СпискиПоИдентификаторам.Получить(Выборка.ИдентификаторСписка); - ВерсииПолейСписка = ВерсииПолейСписков.Получить(Список); - ОсновнаяВерсия = ВерсииПолейСписка[0]; - Для Каждого ВерсияПолейСписка Из ВерсииПолейСписка Цикл - Если ВерсияПолейСписка = ОсновнаяВерсия Тогда - Продолжить; - КонецЕсли; - Если ВерсияПолейСписка.Используется Тогда - ВерсияПолейСписка.Используется = Ложь; - Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить(Список); - КонецЕсли; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -Процедура ДобавитьСуществующиеВерсииПолейСписка(ТекущиеВерсииПолейСписка, НоваяВерсия, - ВариантыДоступаВБазеДанных, Параметры) - - ВариантыДоступа = ВариантыДоступаВБазеДанных.Получить(НоваяВерсия.Список); - Если Не ЗначениеЗаполнено(ВариантыДоступа) Тогда - Возврат; - КонецЕсли; - - ТекущиеСвойстваСписка = Параметры.ТекущиеСвойстваОграниченияСписков.Получить(НоваяВерсия.Список); - ОпорныеПоля = ?(ТекущиеСвойстваСписка = Неопределено, Неопределено, ТекущиеСвойстваСписка.ОпорныеПоля); - Если ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) И ЗначениеЗаполнено(ОпорныеПоля) Тогда - ТребуемыйВариантДоступа = ОпорныеПоля.Используемые.Количество() * 2 - + НоваяВерсия.ВариантДоступа - Цел(НоваяВерсия.ВариантДоступа / 2) * 2; - Иначе - ТребуемыйВариантДоступа = НоваяВерсия.ВариантДоступа; - КонецЕсли; - - Если ВариантыДоступа.Количество() = 1 - И (Не ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) - Или ЗначениеЗаполнено(ОпорныеПоля)) - И ( ВариантыДоступа[0] < 2 - Или ВариантыДоступа[0] - Цел(ВариантыДоступа[0] / 64) * 64 = ТребуемыйВариантДоступа) Тогда - - // Переход с версий конфигурации без поля ВариантДоступа или восстановление - // либо после очистки регистра ПараметрыОграниченияДоступа, - // либо после изменения номера в функции ВерсияСтруктурыВерсийПараметровШаблонов. - Если Не ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) Тогда - ПоляСоединения = НоваяВерсия.ПоляСоединения; - ПоляШаблона = НоваяВерсия.ПоляСоединения; - Иначе - ПоляСоединения = СтрСоединить(ОпорныеПоля.Используемые, ","); - ПоляШаблона = СтрСоединить(ОпорныеПоля.Все, ","); - КонецЕсли; - - ПредыдущаяВерсия = НоваяВерсияПараметровШаблонов(); - ПредыдущаяВерсия.ДатаСоздания = Параметры.СтараяДатаСоздания; - ПредыдущаяВерсия.Список = НоваяВерсия.Список; - ПредыдущаяВерсия.ПоляСоединения = ПоляСоединения; - ПредыдущаяВерсия.ПоляШаблона = ПоляШаблона; - ПредыдущаяВерсия.ВариантДоступа = ВариантыДоступа[0]; - - ТекущиеВерсииПолейСписка.Добавить(ПредыдущаяВерсия); - Иначе - // Несколько версий существующих одновременно не могут быть сопоставлены - // одному набору полей и не могут использоваться для новых наборов полей. - Для Каждого ВариантДоступа Из ВариантыДоступа Цикл - НеизвестнаяВерсия = НоваяВерсияПараметровШаблонов(); - НеизвестнаяВерсия.ДатаСоздания = Параметры.СтараяДатаСоздания; - НеизвестнаяВерсия.Список = НоваяВерсия.Список; - НеизвестнаяВерсия.ВариантДоступа = ВариантДоступа; - НеизвестнаяВерсия.Используется = Ложь; - - ТекущиеВерсииПолейСписка.Добавить(НеизвестнаяВерсия); - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для процедур ОбновитьИспользованиеВерсийПолейСписка и ДобавитьПоляОграниченияСписка. -Функция МаксимальноеКоличествоВариантовСоединений() - - // При изменении нужно синхронно изменить шаблон ограничения доступа ДляРегистра. - Возврат 3; - -КонецФункции - -// Для процедур ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -Функция МаксимальноеКоличествоВерсийВВариантеДоступа() - - Возврат 16; - -КонецФункции - -// Для процедур УстановитьВерсиюПараметров, ЗаполнитьПараметрыДляШаблонов, -// ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений и -// функции СпискиСИзменениемВерсий. -// -Функция ЗначениеИзХранилища(ХранилищеЗначения) - - Попытка - Значение = ХранилищеЗначения.Получить(); - Исключение - Значение = Неопределено; - КонецПопытки; - - Возврат Значение; - -КонецФункции - -// Для процедуры УстановитьВерсиюПараметров, и для функции ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша -// * ВерсииОграниченийСписков - ФиксированноеСоответствие -// * ВедущиеСписки - ФиксированноеСоответствие -// * ДополнительныйКонтекст - ФиксированнаяСтруктура -// * СпискиСДатой - ФиксированноеСоответствие -// * ВнешниеПользователиВключены - Булево -// * ОграничениеДоступаВключено - Булево -// * ИспользуемыеТипыЗначений - ХранилищеЗначения -// -Функция СтруктураХранимыхПараметровЗаписи(Значения) - - ХранимыеПараметрыЗаписи = НоваяСтруктураХранимыхПараметровЗаписи(); - ХранимыеПараметрыЗаписи.ВерсияСтруктурыКэша = ""; - - Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") - И Значения.Свойство("ВерсияСтруктурыКэша") - И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") - И Значения.Свойство("ВерсииОграниченийСписков") - И ТипЗнч(Значения.ВерсииОграниченийСписков) = Тип("ФиксированноеСоответствие") - И Значения.Свойство("ВедущиеСписки") - И ТипЗнч(Значения.ВедущиеСписки) = Тип("ФиксированноеСоответствие") - И Значения.Свойство("ДополнительныйКонтекст") - И ТипЗнч(Значения.ДополнительныйКонтекст) = Тип("ФиксированнаяСтруктура") - И Значения.Свойство("СпискиСДатой") - И ТипЗнч(Значения.СпискиСДатой) = Тип("ФиксированноеСоответствие") - И Значения.Свойство("ВнешниеПользователиВключены") - И ТипЗнч(Значения.ВнешниеПользователиВключены) = Тип("Булево") - И Значения.Свойство("ОграничениеДоступаВключено") - И ТипЗнч(Значения.ОграничениеДоступаВключено) = Тип("Булево") - И Значения.Свойство("ИспользуемыеТипыЗначений") - И ТипЗнч(Значения.ИспользуемыеТипыЗначений) = Тип("ХранилищеЗначения") - И Значения.Свойство("ВерсияТекстовОграниченияДоступа") - И ТипЗнч(Значения.ВерсияТекстовОграниченияДоступа) = Тип("Строка") Тогда - - ЗаполнитьЗначенияСвойств(ХранимыеПараметрыЗаписи, Значения); - КонецЕсли; - - Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыЗаписи); - -КонецФункции - -// Для функций СтруктураХранимыхПараметровЗаписи и ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша -// * ВерсииОграниченийСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Строка - общая версия ограничения списка -// первая строка - хеш-сумма свойств версии для пользователей и через Символы.ПС -// вторая строка - хеш-сумма свойств версии для внешних пользователей. -// -// * ВедущиеСписки - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. СвойстваСпискаКакВедущего -// -// * ДополнительныйКонтекст - Структура: -// ** ДляПользователей - см. НовыйХранимыйДополнительныйКонтекст -// ** ДляВнешнихПользователей - см. НовыйХранимыйДополнительныйКонтекст -// -// * СпискиСДатой - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * ВнешниеПользователиВключены - Булево -// * ОграничениеДоступаВключено - Булево -// * ИспользуемыеТипыЗначений - ХранилищеЗначения - смотри функцию ИспользуемыеТипыЗначений. -// * ВерсияТекстовОграниченияДоступа - Строка -// -Функция НоваяСтруктураХранимыхПараметровЗаписи() Экспорт - - ХранимыеПараметрыЗаписи = Новый Структура; - ХранимыеПараметрыЗаписи.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); - ХранимыеПараметрыЗаписи.Вставить("ВерсииОграниченийСписков", Новый Соответствие); - ХранимыеПараметрыЗаписи.Вставить("ВедущиеСписки", Новый Соответствие); - ХранимыеПараметрыЗаписи.Вставить("ДополнительныйКонтекст", Новый Структура); - ХранимыеПараметрыЗаписи.Вставить("СпискиСДатой", Новый Соответствие); - ХранимыеПараметрыЗаписи.Вставить("ВедущиеРоли", Новый Соответствие); - ХранимыеПараметрыЗаписи.Вставить("ВнешниеПользователиВключены", Ложь); - ХранимыеПараметрыЗаписи.Вставить("ОграничениеДоступаВключено", Ложь); - ХранимыеПараметрыЗаписи.Вставить("ИспользуемыеТипыЗначений", Новый ХранилищеЗначения(Новый Соответствие)); - ХранимыеПараметрыЗаписи.Вставить("ВерсияТекстовОграниченияДоступа", ""); - - Возврат ХранимыеПараметрыЗаписи; - -КонецФункции - -// Для процедуры УстановитьВерсиюПараметров. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша -// * ВерсииШаблонов - см. ВерсииШаблоновОграниченияДоступа -// * ПараметрыШаблонов - см. СтруктураПараметровШаблонов -// -Функция СтруктураХранимыхПараметровШаблонов(Значения) - - ХранимыеПараметрыШаблонов = НоваяСтруктураХранимыхПараметровШаблонов(); - ХранимыеПараметрыШаблонов.ВерсияСтруктурыКэша = ""; - - Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") - И Значения.Свойство("ВерсияСтруктурыКэша") - И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") - И Значения.Свойство("ВерсииШаблонов") - И ТипЗнч(Значения.ВерсииШаблонов) = Тип("Строка") - И Значения.Свойство("ПараметрыШаблонов") - И ТипЗнч(Значения.ПараметрыШаблонов) = Тип("ФиксированнаяСтруктура") Тогда - - ЗаполнитьЗначенияСвойств(ХранимыеПараметрыШаблонов, Значения); - КонецЕсли; - - Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыШаблонов); - -КонецФункции - -// Для функций СтруктураХранимыхПараметровШаблонов, СтруктураХранимыхПараметровЗаписи и -// ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша -// * ВерсииШаблонов - см. ВерсииШаблоновОграниченияДоступа -// * ПараметрыШаблонов - см. СтруктураПараметровШаблонов -// -Функция НоваяСтруктураХранимыхПараметровШаблонов() - - ХранимыеПараметрыШаблонов = Новый Структура; - ХранимыеПараметрыШаблонов.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); - ХранимыеПараметрыШаблонов.Вставить("ВерсииШаблонов", ВерсииШаблоновОграниченияДоступа()); - ХранимыеПараметрыШаблонов.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); - - Возврат ХранимыеПараметрыШаблонов; - -КонецФункции - -// Для процедуры УстановитьВерсиюПараметров. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - Строка -// * СпискиСОграничениемЧерезКлючиДоступаПользователей - Строка -// * СпискиСОграничениемПоПолям - Строка -// * СпискиСОтключеннымОграничениемЧтения - Строка -// -Функция СтруктураПараметровШаблонов(Значения) - - ПараметрыШаблонов = НоваяСтруктураПараметровШаблонов(); - - Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") - И Значения.Количество() = ПараметрыШаблонов.Количество() Тогда - - Совпадает = Истина; - Для Каждого КлючИЗначение Из ПараметрыШаблонов Цикл - Если Не Значения.Свойство(КлючИЗначение.Ключ) - Или Не ТипЗнч(Значения[КлючИЗначение.Ключ]) = ТипЗнч(КлючИЗначение.Значение) Тогда - Совпадает = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Если Совпадает Тогда - ЗаполнитьЗначенияСвойств(ПараметрыШаблонов, Значения); - КонецЕсли; - КонецЕсли; - - Возврат Новый ФиксированнаяСтруктура(ПараметрыШаблонов); - -КонецФункции - -// Для функций СтруктураПараметровШаблонов, ХранимыеПараметрыОграниченияДоступа и -// НоваяСтруктураХранимыхПараметровШаблонов. -// -// Возвращаемое значение: -// Структура: -// * СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - Строка -// * СпискиСОграничениемЧерезКлючиДоступаПользователей - Строка -// * СпискиСОграничениемПоПолям - Строка -// * СпискиСОтключеннымОграничениемЧтения - Строка -// -Функция НоваяСтруктураПараметровШаблонов() - - ПараметрыШаблонов = Новый Структура; - ПараметрыШаблонов.Вставить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа", ""); - ПараметрыШаблонов.Вставить("СпискиСОграничениемЧерезКлючиДоступаПользователей", ""); - ПараметрыШаблонов.Вставить("СпискиСОграничениемПоПолям", ""); - ПараметрыШаблонов.Вставить("СпискиСОтключеннымОграничениемЧтения", ""); - - Возврат ПараметрыШаблонов; - -КонецФункции - -// Для процедур УстановитьВерсиюПараметров и ЗаполнитьПараметрыДляШаблонов. -// -// Возвращаемое значение: -// см. НоваяСтруктураХранимыхВерсийПараметровШаблонов -// -Функция СтруктураХранимыхВерсийПараметровШаблонов(Значения) - - ХранимыеВерсийПараметровШаблонов = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); - ХранимыеВерсийПараметровШаблонов.ВерсияСтруктурыВерсий = ""; - - Если ТипЗнч(Значения) = Тип("Структура") - И Значения.Свойство("ВерсияСтруктурыВерсий") - И ТипЗнч(Значения.ВерсияСтруктурыВерсий) = Тип("Строка") - И Значения.Свойство("ДляПользователей") - - И ТипЗнч(Значения.ДляПользователей) = Тип("Структура") - И Значения.ДляПользователей.Свойство("ВерсииПараметровШаблонов") - И ТипЗнч(Значения.ДляПользователей.ВерсииПараметровШаблонов) = Тип("Соответствие") - И Значения.ДляПользователей.Свойство("ОсновныеВариантыДоступа") - И ТипЗнч(Значения.ДляПользователей.ОсновныеВариантыДоступа) = Тип("Соответствие") - - И Значения.Свойство("ДляВнешнихПользователей") - И ТипЗнч(Значения.ДляВнешнихПользователей) = Тип("Структура") - И Значения.ДляВнешнихПользователей.Свойство("ВерсииПараметровШаблонов") - И ТипЗнч(Значения.ДляВнешнихПользователей.ВерсииПараметровШаблонов) = Тип("Соответствие") - И Значения.ДляВнешнихПользователей.Свойство("ОсновныеВариантыДоступа") - И ТипЗнч(Значения.ДляВнешнихПользователей.ОсновныеВариантыДоступа) = Тип("Соответствие") Тогда - - ЗаполнитьЗначенияСвойств(ХранимыеВерсийПараметровШаблонов, Значения); - КонецЕсли; - - Возврат ХранимыеВерсийПараметровШаблонов; - -КонецФункции - -// Для функций ХранимыеПараметрыОграниченияДоступа, СтруктураХранимыхВерсийПараметровШаблонов и -// процедуры ЗаполнитьПараметрыДляШаблонов. -// -// Возвращаемое значение: -// Структура: -// * ВерсияСтруктурыВерсий - см. ВерсияСтруктурыВерсийПараметровШаблонов -// * ДляПользователей - Структура: -// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов -// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа -// * ДляВнешнихПользователей - Структура: -// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов -// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа -// -Функция НоваяСтруктураХранимыхВерсийПараметровШаблонов() - - ДляПользователей = Новый Структура; - ДляПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); - ДляПользователей.Вставить("ОсновныеВариантыДоступа", НовыеОсновныеВариантыДоступа()); - - ДляВнешнихПользователей = Новый Структура; - ДляВнешнихПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); - ДляВнешнихПользователей.Вставить("ОсновныеВариантыДоступа", НовыеОсновныеВариантыДоступа()); - - ХранимыеПараметрыШаблонов = Новый Структура; - ХранимыеПараметрыШаблонов.Вставить("ВерсияСтруктурыВерсий", ВерсияСтруктурыВерсийПараметровШаблонов()); - ХранимыеПараметрыШаблонов.Вставить("ДляПользователей", ДляПользователей); - ХранимыеПараметрыШаблонов.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); - - Возврат ХранимыеПараметрыШаблонов; - -КонецФункции - -// Для функций ХранимыеПараметрыОграниченияДоступа и -// НоваяСтруктураХранимыхВерсийПараметровШаблонов. -// -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - Строка - полное имя регистра. -// * Значение - Массив из см. НоваяВерсияПараметровШаблонов -// -Функция НовыеВерсииПараметровШаблонов() - - Возврат Новый Соответствие; - -КонецФункции - -// Для функции НовыеВерсииПараметровШаблонов и процедуры НастроитьПараметрыШаблонов. -// -// Возвращаемое значение: -// Структура: -// * ДатаСоздания - Дата - момент добавления новой версии. -// * Список - Строка - полное имя объекта метаданных. -// * ПоляСоединения - Строка - список полей, используемых в соединении. -// * ПоляШаблона - Строка - список полей, указанных в шаблоне #ДляРегистра. -// * Используется - Булево - признак того, что версия используется в шаблонах. -// * ВариантДоступа - Число - значение поля ВариантДоступа в регистрах КлючиДоступаКРегистрам, -// КлючиДоступаКРегистру*. -// -Функция НоваяВерсияПараметровШаблонов() - - ВерсияПараметров = Новый Структура; - ВерсияПараметров.Вставить("ДатаСоздания", '00010101'); - ВерсияПараметров.Вставить("Список", ""); - ВерсияПараметров.Вставить("ПоляСоединения", ""); - ВерсияПараметров.Вставить("ПоляШаблона", ""); - ВерсияПараметров.Вставить("Используется", Истина); - ВерсияПараметров.Вставить("ВариантДоступа", 0); - - Возврат ВерсияПараметров; - -КонецФункции - -// Для функции НоваяСтруктураХранимыхВерсийПараметровШаблонов. -// -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - Строка - полное имя регистра. -// * Значение - Массив из см. НовыйИспользуемыйВариантДоступа -// -Функция НовыеОсновныеВариантыДоступа() - - Возврат Новый Соответствие; - -КонецФункции - -// Для функции ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. -// -// Возвращаемое значение: -// Структура: -// * ВариантДоступа - Число - значение поля ВариантДоступа -// в регистрах КлючиДоступаКРегистрам, КлючиДоступаКРегистру*, -// начиная с основного варианта доступа. -// * ПоляСоединения - Строка - имена полей соединения для варианта доступа через запятую. -// -Функция НовыйИспользуемыйВариантДоступа() - - Возврат Новый Структура("ВариантДоступа, ПоляСоединения"); - -КонецФункции - -// Для процедуры УстановитьВерсиюПараметров. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша -// * ВидыОграниченийПравДляПользователей - Строка -// * ВидыОграниченийПравДляВнешнихПользователей - Строка -// -Функция СтруктураХранимыхПараметровОтчета(Значения) - - ХранимыеПараметрыОтчета = НоваяСтруктураХранимыхПараметровОтчета(); - ХранимыеПараметрыОтчета.ВерсияСтруктурыКэша = ""; - - Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") - И Значения.Свойство("ВерсияСтруктурыКэша") - И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") - И Значения.Свойство("ВидыОграниченийПравДляПользователей") - И ТипЗнч(Значения.ВидыОграниченийПравДляПользователей) = Тип("Строка") - И Значения.Свойство("ВидыОграниченийПравДляВнешнихПользователей") - И ТипЗнч(Значения.ВидыОграниченийПравДляВнешнихПользователей) = Тип("Строка") Тогда - - ЗаполнитьЗначенияСвойств(ХранимыеПараметрыОтчета, Значения); - КонецЕсли; - - Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыОтчета); - -КонецФункции - -// Для функций СтруктураХранимыхПараметровОтчета и ХранимыеПараметрыОграниченияДоступа. -// -// Возвращаемое значение: -// Структура: -// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша -// * ВидыОграниченийПравДляПользователей - Строка -// * ВидыОграниченийПравДляВнешнихПользователей - Строка -// -Функция НоваяСтруктураХранимыхПараметровОтчета() - - ХранимыеПараметрыОтчета = Новый Структура; - ХранимыеПараметрыОтчета.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); - ХранимыеПараметрыОтчета.Вставить("ВидыОграниченийПравДляПользователей", ""); - ХранимыеПараметрыОтчета.Вставить("ВидыОграниченийПравДляВнешнихПользователей", ""); - - Возврат ХранимыеПараметрыОтчета; - -КонецФункции - -// Для функции ХранимыеПараметрыОграниченияДоступа. -Функция ВидыОграниченийПравСтрокой(ВидыОграниченийПрав) - - Список = Новый СписокЗначений; - Для Каждого КлючИЗначение Из ВидыОграниченийПрав Цикл - Список.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - Список.СортироватьПоЗначению(); - ВидыОграниченийСтрокой = СтрСоединить(Список.ВыгрузитьЗначения(), Символы.ПС); - - Возврат ВидыОграниченийСтрокой; - -КонецФункции - -#КонецОбласти - -#Область ПараметрыОграниченияДоступаДляСпискаОтдельно - -// Основная функция области, возвращающая параметры ограничения доступа -// для вида пользователей списка без учета зависимости от других списков, -// как по ключам доступа, так и по наличию видов доступа Пользователи и ВнешниеПользователи. -// -// Возвращаемое значение: -// Структура: -// * Список - Строка - полное имя таблицы объекта метаданных. -// * ДляВнешнихПользователей - Булево - вид пользователей, для которых предназначены параметры. -// * Версия - Строка - хеш-сумма параметров ограничения доступа для отслеживания их изменения. -// * ВедущиеСписки - см. НовыеВедущиеСписки -// * ДоступЗапрещен - Булево - Истина, если текст ограничения "ГДЕ ЛОЖЬ", -// а также не указан для внешних пользователей. -// * ОграничениеОтключено - Булево - Истина, если текст ограничения не указан или указан, -// но ограничение отключено из-за отключения использования -// видов доступа, задействованных в нем. -// * ОграничениеЧтенияОтключено - Булево - Истина, если текст ограничения чтения не указан или указан, -// но ограничение отключено из-за отключения использования -// видов доступа, задействованных в нем. -// -// Поле владельца, когда возможно ограничение только по объекту-владельцу. -// * ПолеВладельца - см. НовоеПолеВладельца -// -// * ТребуетсяОграничениеПоВладельцу - Булево - признак оптимизации, указанный разработчиком -// рядом с текстом ограничения. -// * ИспользуетсяОграничениеПоВладельцу - Булево - признак использования оптимизации, -// вычисленный на втором проходе графа. -// * РассчитыватьПраваПользователей - Булево - признак расчета прав на ключи доступа для пользователей, -// а не для групп доступа, вычисленный на втором проходе графа. -// Имеет смысл только, когда признак -// ИспользуетсяОграничениеПоВладельцу = Ложь. -// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево - признак того, что ведущий список должен записывать -// ключи для зависимых списков, которые не записывают -// своих ключей. Признак вычисляется на втором проходе графа. -// * БезОбновленияКлючейДоступаКОбъектам - Булево - когда Истина, запись связи объекта с ключом доступа -// пропускается так как тип списка не указан -// в определяемом типе ВладелецЗначенийКлючейДоступа. -// * БезОбновленияВсехКомбинацийЗначенийОпорныхПолей - Булево - когда Истина, запись связи строки регистра с ключом -// доступа пропускается, если тип значения опорного поля регистра не -// указан в определяемом типе ПолеРегистраКлючейДоступаКРегистрам -// или типе соответствующего поля отдельного регистра ключей. -// * ЧтениеРазрешеноДляВсехПользователей - Булево - признак, вычисленный на втором проходе графа. -// Когда ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина, -// тогда показывает наличие права Чтение в одной из ролей -// БазовыеПрава* или БазовыеПраваВнешнихПользователей*. -// * ИзменениеРазрешеноДляВсехПользователей - Булево - признак, вычисленный на втором проходе графа. -// Когда ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина, -// тогда показывает наличие права Изменение в одной из ролей -// БазовыеПрава* или БазовыеПраваВнешнихПользователей*. -// * ЕстьВедущиеКлючиДоступа - Булево - признак наличия ведущих ключей доступа в ограничении. -// * ЕстьВедущиеСпискиПоПравам - Булево - признак наличия ведущих списков по правам в ограничении. -// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево - признак наличия перечисленных функций в ограничении. -// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие - типы владельцев настроек прав, используемые -// при расчете прав на ключи доступа (см. ПоТипамСсылок). -// * ИдентификаторТаблицыНастроекПрав - СправочникСсылка.ИдентификаторыОбъектовМетаданных - идентификатор -// списка, если для него используются отдельные настройки прав -// или пустой идентификатор. -// * ЕстьВладельцыНастроекПрав - Булево - признак наличия ограничения по владельцу настроек прав. -// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип - описание типов значений доступа, -// которые используются в ограничении доступа. -// * ВсеВидыОграниченийПрав - Соответствие - все виды ограничений прав без учета использования. -// * ПоляТаблицОбъекта - Массив из см. НовыеПоляТаблицыОбъекта -// * ИмяОтдельногоРегистраКлючей - Строка - для регистров. -// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей -// * ВариантДоступа - Число - основной вариант доступа смотри также НовыеОсновныеВариантыДоступа. -// * СоставПолей - Число - число, описывающее реквизиты, используемые в ключе. -// * ЕстьОграничениеЧтения - Булево - установлено, если ограничение чтения отличается от "ГДЕ ИСТИНА". -// * ЕстьОграничениеИзменения - Булево - установлено, если ограничение изменения отличается от "ГДЕ ИСТИНА". -// * ЕстьОграничениеПоПользователям - Булево - установлено, если проверяются значения Пользователь -// или ГруппаПользователей или ВнешнийПользователь -// или ГруппаВнешнихПользователей для функций -// ЗначениеРазрешено или ЭтоАвторизованныйПользователь. -// * СтруктураРасчетаПраваЧтение - см. СтруктураРасчетаПрава -// * СтруктураРасчетаПраваИзменение - см. СтруктураРасчетаПрава -// * Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Функция ПараметрыОграниченияПоСтруктуреОграничения(Список, СтруктураОграничения, - ДляВнешнихПользователей, ОбщийКонтекст, ДополнительныйКонтекст) - - ВедущиеСписки = НовыеВедущиеСписки(); - - Результат = Новый Структура; - Результат.Вставить("Список", Список); - Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); - Результат.Вставить("Версия", ""); - Результат.Вставить("ВедущиеСписки", ВедущиеСписки); - Результат.Вставить("ДоступЗапрещен", ДляВнешнихПользователей); - Результат.Вставить("ОграничениеОтключено", Не ДляВнешнихПользователей); - Результат.Вставить("ОграничениеЧтенияОтключено", Не ДляВнешнихПользователей); - Результат.Вставить("ПолеВладельца"); - Результат.Вставить("ТребуетсяОграничениеПоВладельцу", Ложь); - Результат.Вставить("ИспользуетсяОграничениеПоВладельцу", Ложь); - Результат.Вставить("РассчитыватьПраваПользователей", Ложь); - Результат.Вставить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Ложь); - Результат.Вставить("БезОбновленияКлючейДоступаКОбъектам", Ложь); - Результат.Вставить("БезОбновленияВсехКомбинацийЗначенийОпорныхПолей", Ложь); - Результат.Вставить("ЧтениеРазрешеноДляВсехПользователей", Ложь); - Результат.Вставить("ИзменениеРазрешеноДляВсехПользователей", Ложь); - Результат.Вставить("ЕстьВедущиеКлючиДоступа", Ложь); - Результат.Вставить("ЕстьВедущиеСпискиПоПравам", Ложь); - Результат.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступна", Ложь); - Результат.Вставить("ТипыВладельцевНастроекПрав", ОбщийКонтекст.ТипыВладельцевНастроекПрав); - Результат.Вставить("ИдентификаторТаблицыНастроекПрав", Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка()); - Результат.Вставить("ЕстьВладельцыНастроекПрав", Ложь); - Результат.Вставить("ИспользуемыеТипыЗначенийДоступа", Новый Массив); - Результат.Вставить("ВсеВидыОграниченийПрав", Новый Соответствие); - Результат.Вставить("ПоляТаблицОбъекта", Новый Массив); - Результат.Вставить("ИмяОтдельногоРегистраКлючей", ""); - Результат.Вставить("ОпорныеПоля"); - Результат.Вставить("ВариантДоступа"); - Результат.Вставить("СоставПолей"); - Результат.Вставить("ЕстьОграничениеЧтения", Ложь); - Результат.Вставить("ЕстьОграничениеИзменения", Ложь); - Результат.Вставить("ЕстьОграничениеПоПользователям", Ложь); - Результат.Вставить("СтруктураРасчетаПраваЧтение", СтруктураРасчетаПрава()); - Результат.Вставить("СтруктураРасчетаПраваИзменение", СтруктураРасчетаПрава()); - - ИмяКоллекцииТипа = ""; - Результат.Вставить("ЭтоСсылочныйТип", ?(ЗначениеЗаполнено(Список), - ЭтоСсылочныйТипТаблицы(Список, ИмяКоллекцииТипа), Ложь)); - - Результат.Вставить("СписокСДатой", - ИмяКоллекцииТипа = "Документы" - Или ИмяКоллекцииТипа = "БизнесПроцессы" - Или ИмяКоллекцииТипа = "Задачи"); - - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Список); - - Если Результат.ЭтоСсылочныйТип И ОбъектМетаданных <> Неопределено Тогда - ТипПоля = Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект.Тип; - ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; - ТипСсылки = Тип(ИмяТипаСсылки(Список, ТипыТаблицПоИменам)); - Если Не ТипПоля.СодержитТип(ТипСсылки) Тогда - Результат.БезОбновленияКлючейДоступаКОбъектам = Истина; - КонецЕсли; - КонецЕсли; - - Если ИмяКоллекцииТипа = "РегистрыСведений" Тогда - Результат.Вставить("СписокСПериодом", ?(ОбъектМетаданных = Неопределено, Ложь, - ОбъектМетаданных.ПериодичностьРегистраСведений - <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический)); - Иначе - Результат.Вставить("СписокСПериодом", - ИмяКоллекцииТипа = "РегистрыНакопления" - Или ИмяКоллекцииТипа = "РегистрыБухгалтерии" - Или ИмяКоллекцииТипа = "РегистрыРасчета"); - КонецЕсли; - - Контекст = КонтекстПараметровПоСтруктуреОграничения(); - Контекст.Вставить("СтрокаСвойствВерсии", ""); - Результат.Вставить("Контекст", Контекст); - - Для Каждого КлючИЗначение Из ОбщийКонтекст Цикл - Контекст.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - Для Каждого КлючИЗначение Из ДополнительныйКонтекст Цикл - Контекст.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - - Контекст.Вставить("Список", Список); - Контекст.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); - Контекст.Вставить("ЭтоСсылочныйТип", Результат.ЭтоСсылочныйТип); - Контекст.Вставить("СписокСДатой", Результат.СписокСДатой); - Контекст.Вставить("СписокСПериодом", Результат.СписокСПериодом); - Контекст.Вставить("ИмяКоллекцииТипа", ИмяКоллекцииТипа); - Контекст.Вставить("СвойстваВерсии", Новый Массив); - Контекст.Вставить("ВедущиеРоли", Новый Соответствие); - - ДобавитьСвойствоВерсии(Контекст, Контекст, "Список"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "ДляВнешнихПользователей"); - - ОписаниеОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список); - Если ОписаниеОграничения = Неопределено Тогда - ОписаниеОграничения = Новый Структура("Текст", ""); - КонецЕсли; - ДобавитьСвойствоВерсии(Контекст, ОписаниеОграничения, "Текст"); - - ДобавитьСвойствоВерсии(Контекст, Контекст, "ЭтоСсылочныйТип"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "СписокСДатой"); - - // Поля таблиц требуются только для ссылочных объектов. - Контекст.Вставить("ПоляТаблицОбъекта", НовоеОписаниеПолейТаблицОбъекта(Результат)); - - // Опорные поля не требуются для ссылочных типов данных (всегда Ссылка). - ЗаполнитьНовоеОписаниеОпорныхПолей(Результат, Контекст); - - Контекст.Вставить("БезОбъектаМетаданных", ОбъектМетаданных = Неопределено); - - Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено Тогда - Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); - Результат.РассчитыватьПраваПользователей = Свойства.РассчитыватьПраваПользователей; - Результат.ИспользуетсяОграничениеПоВладельцу = Свойства.ПолеВладельца <> Неопределено - И Не Свойства.ПолеВладельца.Отключено; - Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(Список) <> Неопределено Тогда - Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина; - Результат.ЧтениеРазрешеноДляВсехПользователей = - ПравоРазрешеноДляВсехПользователей("Чтение", ОбъектМетаданных, ДляВнешнихПользователей); - Результат.ИзменениеРазрешеноДляВсехПользователей = - ПравоРазрешеноДляВсехПользователей("Изменение", ОбъектМетаданных, ДляВнешнихПользователей); - КонецЕсли; - КонецЕсли; - Контекст.Вставить("ИспользуетсяОграничениеПоВладельцу", Результат.ИспользуетсяОграничениеПоВладельцу); - Контекст.Вставить("РассчитыватьПраваПользователей", Результат.РассчитыватьПраваПользователей); - Контекст.Вставить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа); - Контекст.Вставить("ЧтениеРазрешеноДляВсехПользователей", Результат.ЧтениеРазрешеноДляВсехПользователей); - Контекст.Вставить("ИзменениеРазрешеноДляВсехПользователей", Результат.ИзменениеРазрешеноДляВсехПользователей); - - Если СтруктураОграничения = Неопределено Тогда - Если Не Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Или Результат.ДоступЗапрещен - Или Контекст.БезОбъектаМетаданных Тогда - Возврат Результат; - КонецЕсли; - СтруктураОграничения = РассчитаннаяСтруктураОграничения(Список, - "РазрешитьЧтениеИзменение ГДЕ ИСТИНА", Истина, ДляВнешнихПользователей); - КонецЕсли; - - Контекст.Вставить("СтруктураОграничения", СтруктураОграничения); - Контекст.Вставить("ВедущиеСпискиПоЗначениямПолей", ОписаниеВедущихСписковПоЗначениямПолей()); - Контекст.Вставить("ВедущиеСпискиПоКлючамДоступа", ОписаниеВедущихСписковПоПолюСсылка()); - Контекст.Вставить("ВедущиеСпискиПоЗначениямСГруппами", ОписаниеВедущихСписковПоПолюСсылка()); - Контекст.Вставить("ЕстьПроверкаАвторизованногоПользователя", Ложь); - Контекст.Вставить("НеиспользуемыеТипыЗначенийДоступа", Новый Массив); - Контекст.Вставить("ВсеВидыОграниченийПрав", Результат.ВсеВидыОграниченийПрав); - - Если Не Контекст.ЭтоСсылочныйТип Тогда - Результат.ИмяОтдельногоРегистраКлючей = Контекст.ИмяОтдельногоРегистраКлючей; - КонецЕсли; - - ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, Ложь); - ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения(Результат, Контекст); - - ЗаполнитьСвойстваПолей(Контекст); - - Результат.ЕстьФункцияПравоДоступаИлиРольДоступна = Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна; - - Если ДляВнешнихПользователей И Не ОбщийКонтекст.ВнешниеПользователиВключены - Или ЭтоБезусловноеОграничение(Контекст, Результат) Тогда - - Результат.ДоступЗапрещен = Истина; - Результат.Версия = " "; - Возврат Результат; - КонецЕсли; - - Результат.ДоступЗапрещен = Ложь; - Результат.ОграничениеОтключено = Истина; - Результат.ОграничениеЧтенияОтключено = Истина; - - ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, Истина); - ЗаполнитьОграничениеПоОбъектуВладельцуПослеУпрощения(Результат, Контекст); - ЗаполнитьНаличиеВедущихКлючейИСписковИВладельцевНастроекПрав(Результат, Контекст); - УдалитьПоляНеиспользуемыхВидовДоступа(Результат, Контекст); - ЗаполнитьНаличиеОграниченияПоВидуДоступаПользователи(Результат, Контекст); - ЗаполнитьНаличиеОграниченияЧтения(Результат, Контекст); - - Контекст.Вставить("ЕстьОграничениеПоПользователям", Результат.ЕстьОграничениеПоПользователям); - - Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Неопределено Тогда - Результат.РассчитыватьПраваПользователей = Результат.ЕстьОграничениеПоПользователям; - Результат.ИспользуетсяОграничениеПоВладельцу = Результат.ПолеВладельца <> Неопределено - И Не Результат.ПолеВладельца.Отключено; - - Контекст.Вставить("ИспользуетсяОграничениеПоВладельцу", Результат.ИспользуетсяОграничениеПоВладельцу); - Контекст.Вставить("РассчитыватьПраваПользователей", Результат.РассчитыватьПраваПользователей); - КонецЕсли; - ДобавитьСвойствоВерсии(Контекст, Контекст, "ИспользуетсяОграничениеПоВладельцу"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "РассчитыватьПраваПользователей"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "ЧтениеРазрешеноДляВсехПользователей"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "ИзменениеРазрешеноДляВсехПользователей"); - - Контекст.Вставить("ГруппыПолей"); - Контекст.Вставить("ПсевдонимыТабличныхЧастейОбъекта"); - Контекст.Вставить("ГруппыДополнительныхТаблиц"); - Контекст.Вставить("КоличествоТабличныхЧастейКлюча"); - - ЗаполнитьГруппыПолейИДополнительныхТаблиц(Контекст); - - Результат.СоставПолей = Контекст.СоставПолей; - - Если Результат.Контекст.СвойстваПолей.Количество() = 0 - И (Не Результат.ЭтоСсылочныйТип - Или Не Результат.ЕстьФункцияПравоДоступаИлиРольДоступна) Тогда // Ограничение отключено. - - Если Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа Тогда - НастроитьСозданиеКлючаДоступаДляЗависимыхСписковБезКлючей(Результат); - Если Контекст.СпискиСОграничением.Получить(Результат.Список) = Неопределено Тогда - Результат.Версия = " "; - Иначе - Результат.Версия = " "; - КонецЕсли; - Иначе - Результат.Версия = " "; - КонецЕсли; - КонецЕсли; - - Если Результат.Версия <> " " И Результат.БезОбновленияКлючейДоступаКОбъектам Тогда - ДобавитьСвойствоВерсии(Контекст, Результат, "БезОбновленияКлючейДоступаКОбъектам"); - КонецЕсли; - Если Результат.Версия <> " " - И Контекст.ИмяКоллекцииТипа <> "ЖурналыДокументов" - И УправлениеДоступомСлужебныйПовтИсп.ТаблицыВПодпискахПроверитьДоступ().Получить(Список) = Неопределено Тогда - ДобавитьЭлементВерсии(Контекст, "ОбъектВПодпискахПроверитьДоступ", Ложь) - КонецЕсли; - - Если Результат.Версия <> "" Тогда - Возврат Результат; - КонецЕсли; - - ЗаполнитьНедостающиеТипыОпорныхПолей(Результат, Контекст); - - Результат.ОграничениеОтключено = Ложь; - - Контекст.Вставить("ИмяПрава", "Чтение"); - ЗаполнитьСтруктуруРасчетаПрава(Результат.СтруктураРасчетаПраваЧтение, - Контекст.СтруктураОграничения.ОграничениеЧтения, Контекст); - - Контекст.Вставить("ИмяПрава", "Изменение"); - ЗаполнитьСтруктуруРасчетаПрава(Результат.СтруктураРасчетаПраваИзменение, - Контекст.СтруктураОграничения.ОграничениеИзменения, Контекст); - - Контекст.Удалить("ИмяПрава"); - ДобавитьСвойствоВерсииВедущиеРоли(Контекст); - - Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда - Контекст.ВедущиеСпискиПоЗначениямПолей = ОписаниеВедущихСписковПоЗначениямПолей(); - КонецЕсли; - ВедущиеСписки.ПоЗначениямПолей = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля; - ВедущиеСписки.ПоКлючамДоступа = Контекст.ВедущиеСпискиПоКлючамДоступа.Списки; - ВедущиеСписки.ПоЗначениямСГруппами = Контекст.ВедущиеСпискиПоЗначениямСГруппами.Списки; - - ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); - СтрокаСвойствВерсии = СтрСоединить(Контекст.СвойстваВерсии, Символы.ПС); - Контекст.СтрокаСвойствВерсии = СтрокаСвойствВерсии; - ХешированиеДанных.Добавить(СтрокаСвойствВерсии); - Результат.Версия = Base64Строка(ХешированиеДанных.ХешСумма); - - Возврат Результат; - -КонецФункции - -// Списки с полями от которых зависит ограничение доступа. -// -// Возвращаемое значение: -// Структура: -// * ПоЗначениямПолей - Соответствие - списки с полями, от которых зависит ограничение доступа -// (для регистрации заданий обновления). -// * ПоКлючамДоступа - Соответствие - списки от ключей доступа которых зависит ограничение доступа -// (для установки параметров сеанса и регистрации заданий обновления). -// * ПоЗначениямСГруппами - Соответствие - списки значений доступа с группами, от которых зависит -// ограничение доступа (для регистрации заданий обновления). -// -Функция НовыеВедущиеСписки() - - ВедущиеСписки = Новый Структура; - ВедущиеСписки.Вставить("ПоЗначениямПолей", Новый Соответствие); - ВедущиеСписки.Вставить("ПоКлючамДоступа", Новый Соответствие); - ВедущиеСписки.Вставить("ПоЗначениямСГруппами", Новый Соответствие); - - Возврат ВедущиеСписки; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * СтрокаСвойствВерсии - Строка -// * Список - Строка -// * ДляВнешнихПользователей - Булево -// * ЭтоСсылочныйТип - Булево -// * СписокСДатой - Булево -// * СписокСПериодом - Булево -// * ИмяКоллекцииТипа - Строка -// * СвойстваВерсии - Массив из Строка -// * ПоляТаблицОбъекта - см. НовоеОписаниеПолейТаблицОбъекта -// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей -// * ВариантДоступа - Число - основной вариант доступа смотри также НовыеОсновныеВариантыДоступа. -// * ИспользуетсяОграничениеПоВладельцу - Булево -// * РассчитыватьПраваПользователей - Булево -// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево -// * ЧтениеРазрешеноДляВсехПользователей - Булево -// * ИзменениеРазрешеноДляВсехПользователей - Булево -// * БезОбъектаМетаданных - Булево -// * СтруктураОграничения - см. СтруктураОграничения -// * ИсходнаяСтруктураОграничения - см. СтруктураОграничения -// * ВедущиеСпискиПоЗначениямПолей - см. ОписаниеВедущихСписковПоЗначениямПолей -// * ВедущиеСпискиПоКлючамДоступа - см. ОписаниеВедущихСписковПоПолюСсылка -// * ВедущиеСпискиПоЗначениямСГруппами - см. ОписаниеВедущихСписковПоПолюСсылка -// * ЕстьПроверкаАвторизованногоПользователя - Булево -// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево -// * ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения - Булево -// * НеиспользуемыеТипыЗначенийДоступа - Массив из Тип -// * ВсеВидыОграниченийПрав - Соответствие -// * ЕстьОграничениеПоПользователям - Булево -// * ИспользуетсяОграничениеПоВладельцу - Булево -// * РассчитыватьПраваПользователей - Булево -// * СвойстваВсехПолей - Соответствие из КлючИЗначение: -// ** Ключ - см. ОписаниеУзла -// ** Значение - см. СвойстваПоля -// * ОставшиесяПоляПослеУпрощения - Соответствие из КлючИЗначение: -// ** Ключ - см. ОписаниеУзла -// ** Значение - Массив из см. ОписаниеУзла -// * ПоляКлючаДоступаПослеУпрощения - Массив из см. НовоеПолеКлючаДоступа -// * СвойстваПолейКлючаДоступа - Соответствие из КлючИЗначение: -// ** Ключ - см. ОписаниеУзла -// ** Значение - см. СвойстваПоля -// * ГруппыПолей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя группы полей (Шапка?, ТабличнаяЧасть?) -// ** Значение - Массив из см. СвойстваПоля -// * ПсевдонимыТабличныхЧастейОбъекта - Соответствие из КлючИЗначение: -// ** Ключ - Число - номер табличной части ключа -// ** Значение - Строка - псевдоним таблицы -// * ГруппыДополнительныхТаблиц - см. ГруппыДополнительныхТаблиц -// * КоличествоТабличныхЧастейКлюча - Число -// * ПоляУсловияСоединенияДополнительныхТаблиц - Массив из Структура: -// ** УзелПоле - см. ОписаниеУзла -// ** ПсевдонимТаблицыУсловия - Строка -// * ИмяПрава - Строка -// * ТребуемыеРеквизитыТабличныхЧастейКлюча - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя таблицы ключа (ИмяГруппыПолейКлючаДоступа) -// ** Значение - Массив из Строка - имя реквизита таблицы ключа (ИмяРеквизитаГруппыПолейКлючаДоступа) -// * СтруктураРасчетаПраваСвойстваВерсии - Массив из Строка -// * ВедущиеРоли - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя роли -// ** Значение - Булево - значение Истина. -// -// Свойства, скопированные от ОбщийКонтекст: -// * СвойстваВидовДоступа - см. СвойстваВидовДоступа -// * ТипыПользователя - Массив из Тип -// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие -// * ОтдельныеТаблицыНастроекПрав - ФиксированноеСоответствие -// * ИспользуемыеТипыЗначений - см. ИспользуемыеТипыЗначений -// * СпискиСОграничением - см. УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением -// * ВнешниеПользователиВключены - Булево -// -// Свойства, скопированные от ДополнительныйКонтекст: -// * ОписанияОграничений - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. СокращенноеОписаниеОграничения -// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - см. НовыеСвойстваОграниченияСписка -// * СпискиСОграничениемПоВладельцу - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - значение ПоВладельцу, кроме Неопределено. -// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя списка -// ** Значение - Булево - Истина -// -Функция КонтекстПараметровПоСтруктуреОграничения() - - Возврат Новый Структура; - -КонецФункции - -// Структура ограничения, приведенную к формату размещения значений в ключах доступа. -// -// Возвращаемое значение: -// Структура: -// * Узел - Строка - одна из строк "Поле", "Константа", "И", "Или", "Не", "Выбор", -// "ЗначениеРазрешено", "ЭтоАвторизованныйПользователь", -// "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено", -// "ЧтениеСпискаРазрешено", "ИзменениеСпискаРазрешено", -// "ДляВсехСтрок", "ДляОднойИзСтрок". -// -// Свойства узла Поле. -// * Таблица - Строка - таблица ключа доступа (Шапка?, ТабличнаяЧасть?). -// * Реквизит - Строка - имя реквизита таблицы ключа доступа (Реквизит?). -// * ПроверкаЕстьNull - Булево - Истина (необязательное свойство). -// -// Свойства узла Константа. -// * Значение - Булево -// - Число -// - Строка -// - Неопределено - Ложь, Истина, произвольное -// целое число до 16 разрядов или произвольная строка до 150 символов. -// -// Свойства узлов И, Или. -// * Аргументы - Массив из см. СтруктураРасчетаПрава -// -// Свойства узла Не. -// * Аргумент - см. СтруктураРасчетаПрава -// -// * Узел - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узла Выбор (Иначе может быть Неопределено). -// * Иначе - см. СтруктураРасчетаПрава -// * Когда - Массив из Структура: -// ** Условие - см. СтруктураРасчетаПрава -// ** Значение - см. СтруктураРасчетаПрава -// -// * Узел - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узлов ЗначениеРазрешено, ЭтоАвторизованныйПользователь, -// ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, -// ЧтениеСпискаРазрешено, ИзменениеСпискаРазрешено. -// * Поле - см. СтруктураРасчетаПрава -// * УточненияСравнения - Соответствие из КлючИЗначение: -// ** Ключ - Строка -// - Тип - уточняемое значение "Неопределено", "Null", "ПустаяСсылка", -// "Отключено", Тип (Ссылка, Число, Даты, Булево). -// ** Значение - Строка - результат "Ложь", "Истина". -// -// Свойства узлов ДляВсехСтрок, ДляОднойИзСтрок. -// * Аргумент - см. СтруктураРасчетаПрава -// -Функция СтруктураРасчетаПрава() - - Возврат Новый Структура; - -КонецФункции - -// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. -Процедура НастроитьСозданиеКлючаДоступаДляЗависимыхСписковБезКлючей(Результат) - - Если Не Результат.ЭтоСсылочныйТип Тогда - Возврат; - КонецЕсли; - - Если Результат.СоставПолей <> 0 Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Для списка %1 некорректно рассчиталось поле %2. - |Указано значение %3, ожидалось значение 0.'"), - Результат.Список, "СоставПолей", Формат(Результат.СоставПолей, "ЧН=0; ЧГ=")); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Результат.ЕстьОграничениеЧтения = Истина; - Результат.ЕстьОграничениеИзменения = Истина; - - Результат.ЕстьФункцияПравоДоступаИлиРольДоступна = Истина; - - СтруктураРасчетаПраваЧтение = Новый Структура; - СтруктураРасчетаПраваЧтение.Вставить("Узел", "ПравоДоступа"); - СтруктураРасчетаПраваЧтение.Вставить("ИмяПрава", "Чтение"); - СтруктураРасчетаПраваЧтение.Вставить("ПолноеИмяОбъектаМетаданных", Результат.Список); - СтруктураРасчетаПраваЧтение.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); - Результат.СтруктураРасчетаПраваЧтение = СтруктураРасчетаПраваЧтение; - - СтруктураРасчетаПраваИзменение = Новый Структура; - СтруктураРасчетаПраваИзменение.Вставить("Узел", "ПравоДоступа"); - СтруктураРасчетаПраваИзменение.Вставить("ИмяПрава", "Изменение"); - СтруктураРасчетаПраваИзменение.Вставить("ПолноеИмяОбъектаМетаданных", Результат.Список); - СтруктураРасчетаПраваИзменение.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); - Результат.СтруктураРасчетаПраваИзменение = СтруктураРасчетаПраваИзменение; - -КонецПроцедуры - -// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. -Функция ПравоРазрешеноДляВсехПользователей(ИмяПрава, ОбъектМетаданных, ДляВнешнихПользователей) - - Если ОбъектМетаданных = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - ИменаРолейБазовыеПрава = УправлениеДоступомСлужебныйПовтИсп.ИменаРолейБазовыеПрава(ДляВнешнихПользователей); - МетаданныеРоли = Метаданные.Роли; - - Для Каждого ИмяРоли Из ИменаРолейБазовыеПрава Цикл - Если ПравоДоступа(ИмяПрава, ОбъектМетаданных, МетаданныеРоли[ИмяРоли]) Тогда - Возврат Истина; - КонецЕсли; - КонецЦикла; - - Возврат Ложь; - -КонецФункции - -// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. -Процедура ДобавитьСвойствоВерсииВедущиеРоли(Контекст) - - Если Не ЗначениеЗаполнено(Контекст.ВедущиеРоли) Тогда - Возврат; - КонецЕсли; - - СписокЗначений = Новый СписокЗначений; - Для Каждого КлючИЗначение Из Контекст.ВедущиеРоли Цикл - СписокЗначений.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - СписокЗначений.СортироватьПоПредставлению(); - - ДобавитьЭлементВерсии(Контекст, "ВедущиеРоли", СписокЗначений.ВыгрузитьЗначения()); - -КонецПроцедуры - -// Для процедуры УдалитьПоляНеиспользуемыхВидовДоступа и функции ГруппыДополнительныхТаблиц. -Процедура ДобавитьСвойстваВерсии(Контекст, Структура, ИменаПолей = "") Экспорт - - Если ЗначениеЗаполнено(ИменаПолей) Тогда - СохраняемаяСтруктура = Новый Структура(ИменаПолей); - ЗаполнитьЗначенияСвойств(СохраняемаяСтруктура, Структура); - Иначе - СохраняемаяСтруктура = Структура; - КонецЕсли; - - СписокЗначений = Новый СписокЗначений; - Для Каждого КлючИЗначение Из СохраняемаяСтруктура Цикл - СписокЗначений.Добавить(КлючИЗначение.Значение, КлючИЗначение.Ключ) - КонецЦикла; - СписокЗначений.СортироватьПоПредставлению(); - - Для Каждого ЭлементСписка Из СписокЗначений Цикл - ДобавитьЭлементВерсии(Контекст, ЭлементСписка.Представление, ЭлементСписка.Значение); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. -Процедура ДобавитьСвойствоВерсии(Контекст, Структура, ИмяПоля) - - ДобавитьЭлементВерсии(Контекст, ИмяПоля, Структура[ИмяПоля]); - -КонецПроцедуры - -// Для процедур ДобавитьСвойстваВерсии, ДобавитьСвойствоВерсии. -Процедура ДобавитьЭлементВерсии(Контекст, ИмяПоля, Значение) Экспорт - - Если ТипЗнч(Значение) = Тип("Строка") Тогда - Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + Значение); - - ИначеЕсли ТипЗнч(Значение) = Тип("Число") Тогда - - Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + Формат(Значение, "ЧГ=")); - - ИначеЕсли ТипЗнч(Значение) = Тип("Булево") Тогда - - Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + ?(Значение, "Да", "Нет")); - - ИначеЕсли ТипЗнч(Значение) = Тип("Неопределено") Тогда - - Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + "Неопределено"); - - ИначеЕсли ТипЗнч(Значение) = Тип("ФиксированныйМассив") Тогда - Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + СтрокаДанныхДляХеширования(Новый Массив(Значение))); - - ИначеЕсли ТипЗнч(Значение) = Тип("ОписаниеТипов") - Или ТипЗнч(Значение) = Тип("Тип") - Или ТипЗнч(Значение) = Тип("Массив") Тогда - - Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + СтрокаДанныхДляХеширования(Значение)); - Иначе - ТекстОшибки = НСтр("ru = 'Некорректный тип данных для версии ограничения доступа.'"); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - -КонецПроцедуры - -// Для функции ПараметрыОграниченияПоСтруктуреОграничения и формы ОбновлениеДоступаРучноеУправление. -// -// Возвращаемое значение: -// Булево -// -Функция ЭтоСсылочныйТипТаблицы(ПолноеИмя, ИмяКоллекцииТипа = "") Экспорт - - СинтаксисЯзыка = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка(); - СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - - ТипТаблицы = СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0])); - Если ТипТаблицы = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - ИмяКоллекцииТипа = ТипТаблицы.ИмяКоллекции; - - Возврат ТипТаблицы.ЭтоСсылочныйТип; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ПолноеИмяТаблицы - Строка -// * ТабличнаяЧасть - Строка -// * Поля - Массив из Строка - с полем Ссылка -// * СписокПолей - Строка - без поля Ссылка -// * ТаблицаСПолями - ХранилищеЗначения - с объектом ТаблицаЗначений -// с типизированными полями (включая поле Ссылка). -// -Функция НовыеПоляТаблицыОбъекта() - - ПоляТаблицы = Новый Структура; - ПоляТаблицы.Вставить("ПолноеИмяТаблицы", ""); - ПоляТаблицы.Вставить("ТабличнаяЧасть", ""); - ПоляТаблицы.Вставить("Поля", Новый Массив); - ПоляТаблицы.Вставить("СписокПолей", ""); - ПоляТаблицы.Вставить("ТаблицаСПолями", Новый ХранилищеЗначения(Новый ТаблицаЗначений)); - - Возврат ПоляТаблицы; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * Результат - Массив из см. НовыеПоляТаблицыОбъекта -// * Состав - Структура: -// ** Ключ - Строка - полное имя таблицы объекта. -// ** Значение - Структура: -// *** Ключ - Строка - имя поля. -// *** Значение - Структура: -// **** Тип - ОписаниеТипов - типы поля. -// **** Использование - Булево - использование поля. -// * ПоСвойствамПолей - Соответствие из КлючИЗначение: -// ** Ключ - см. НовыеСвойстваПоля -// ** Значение - Структура: -// *** Таблица - Строка - полное имя таблицы объекта. -// *** Поле - Строка - имя поля. -// * ПоДополнительнымТаблицам - Соответствие из КлючИЗначение: -// ** Ключ - Строка - дополнительная таблица -// ** Значение - Структура: -// *** Ключ - Строка - полное имя таблицы объекта. -// *** Значение - Массив из Строка - имя поля. -// -Функция НовоеОписаниеПолейТаблицОбъекта(Результат) - - Возврат Новый Структура("Результат, Состав", Результат.ПоляТаблицОбъекта, Новый Структура); - -КонецФункции - -// Для функции ПараметрыОграниченияПоСтруктуреОграничения. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьНовоеОписаниеОпорныхПолей(Результат, Контекст) - - ОпорныеПоля = НовоеОписаниеОпорныхПолей(); - Контекст.Вставить("ОпорныеПоля", ОпорныеПоля); - Контекст.Вставить("ВариантДоступа", Неопределено); - - Если Контекст.ЭтоСсылочныйТип Тогда - Возврат; - КонецЕсли; - - Если Контекст.Свойство("ОсновныеВариантыДоступа") Тогда - ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); - Если ИспользуемыеВариантыДоступа <> Неопределено Тогда - Результат.ВариантДоступа = ИспользуемыеВариантыДоступа[0].ВариантДоступа; - КонецЕсли; - Контекст.Вставить("ВариантДоступа", Результат.ВариантДоступа); - КонецЕсли; - - Если СтрРазделить(Контекст.Список, ".").Количество() > 1 Тогда - ИмяОтдельногоРегистраКлючей = "КлючиДоступаКРегистру" + СтрРазделить(Контекст.Список, ".")[1]; - Если Метаданные.РегистрыСведений.Найти(ИмяОтдельногоРегистраКлючей) = Неопределено Тогда - ИмяОтдельногоРегистраКлючей = ""; - КонецЕсли; - Иначе - ИмяОтдельногоРегистраКлючей = ""; - КонецЕсли; - Контекст.Вставить("ИмяОтдельногоРегистраКлючей", ИмяОтдельногоРегистраКлючей); - - ОпорныеПоля.МаксимальноеКоличество = - УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяОтдельногоРегистраКлючей); - - ОпорныеПоля.МаксимальноДопустимоеКоличество = - УправлениеДоступомСлужебныйПовтИсп.МаксимальноеКоличествоОпорныхПолейРегистра(); - - Если ОпорныеПоля.МаксимальноеКоличество > ОпорныеПоля.МаксимальноДопустимоеКоличество Тогда - // Превышение количества опорных полей в отдельном регистре. - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Количество опорных полей в регистре сведений %1 - |превышает максимально допустимое количество: %2'"), - ?(ИмяОтдельногоРегистраКлючей = "", "КлючиДоступаКРегистрам", ИмяОтдельногоРегистраКлючей), - ОпорныеПоля.МаксимальноДопустимоеКоличество); - - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ДобавитьСвойствоВерсии(Контекст, ОпорныеПоля, "МаксимальноеКоличество"); - - Результат.ОпорныеПоля = НовоеОписаниеОпорныхПолей(); - ЗаполнитьЗначенияСвойств(Результат.ОпорныеПоля, Контекст.ОпорныеПоля); - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * Все - Массив -// * ТипыВсех - Массив из ХранилищеЗначения - содержит тип ОписаниеТипов -// * Используемые - Массив -// * ТипыИспользуемых - Массив из ХранилищеЗначения - содержит тип ОписаниеТипов -// * МаксимальноеКоличество - Число -// * МаксимальноДопустимоеКоличество - Число -// -// * Список - СписокЗначений -// * ТипыПоИменамПолей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя опорного поля -// ** Значение - ОписаниеТипов - типы опорного поля -// * ПоСвойствамПолей - Соответствие из КлючИЗначение: -// ** Ключ - см. НовыеСвойстваПоля -// ** Значение - Строка - имя опорного поля -// * ПоДополнительнымТаблицам - Соответствие из КлючИЗначение: -// ** Ключ - Строка - дополнительная таблица -// ** Значение - Массив из Строка - имена опорных полей -// * НедостающиеТипы - Массив из Строка - полные имена типов -// * ПоляНедостающихТипов - Массив из Строка - имена полей регистра ключей -// -Функция НовоеОписаниеОпорныхПолей() - - ОпорныеПоля = Новый Структура; - ОпорныеПоля.Вставить("Все", Новый Массив); - ОпорныеПоля.Вставить("ТипыВсех", Новый Массив); - ОпорныеПоля.Вставить("Используемые", Новый Массив); - ОпорныеПоля.Вставить("ТипыИспользуемых", Новый Массив); - ОпорныеПоля.Вставить("МаксимальноеКоличество", 0); - ОпорныеПоля.Вставить("МаксимальноДопустимоеКоличество", 0); - - Возврат ОпорныеПоля; - -КонецФункции - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// -Функция ЭтоБезусловноеОграничение(Контекст, Результат) - - СтруктураОграничения = Контекст.СтруктураОграничения; - - Возврат ЗначениеЗаполнено(СтруктураОграничения.ОграничениеЧтения) - И СтруктураОграничения.ОграничениеЧтения.Узел = "Константа" - И СтруктураОграничения.ОграничениеЧтения.Значение = Ложь; - -КонецФункции - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// -Процедура ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, ПослеУпрощения) - - СтруктураОграничения = Контекст.СтруктураОграничения; - - Результат.ЕстьОграничениеЧтения = - ЗначениеЗаполнено(СтруктураОграничения.ОграничениеЧтения) - И ( СтруктураОграничения.ОграничениеЧтения.Узел <> "Константа" - Или СтруктураОграничения.ОграничениеЧтения.Значение <> Истина); - - Результат.ЕстьОграничениеИзменения = - ЗначениеЗаполнено(СтруктураОграничения.ОграничениеИзменения) - И ( СтруктураОграничения.ОграничениеИзменения.Узел <> "Константа" - Или СтруктураОграничения.ОграничениеИзменения.Значение <> Истина); - - Если ПослеУпрощения Тогда - ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеЧтения"); - ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеИзменения"); - КонецЕсли; - -КонецПроцедуры - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения(Результат, Контекст) - - НастройкаПоВладельцу = Контекст.СпискиСОграничениемПоВладельцу.Получить(Контекст.Список); - ПолеВладельца = НовоеПолеВладельца(); - - ТребуетсяОграничениеПоВладельцу = Ложь; - Если ТипЗнч(НастройкаПоВладельцу) = Тип("Булево") Тогда - ТребуетсяОграничениеПоВладельцу = НастройкаПоВладельцу; - КонецЕсли; - Результат.ТребуетсяОграничениеПоВладельцу = ТребуетсяОграничениеПоВладельцу; - - ОграничениеЧтения = Контекст.СтруктураОграничения.ОграничениеЧтения; - ОграничениеИзменения = Контекст.СтруктураОграничения.ОграничениеИзменения; - - ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, - "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); - - Если Результат.ЕстьОграничениеЧтения Тогда - - Если ТребуетсяОграничениеПоВладельцу Или Не Контекст.ЭтоСсылочныйТип Тогда - Если ОграничениеЧтения.Узел <> "ЧтениеОбъектаРазрешено" Тогда - Если Не ТребуетсяОграничениеПоВладельцу Тогда - Возврат; - КонецЕсли; - Если ЗначениеЗаполнено(ОграничениеИзменения) Тогда - ШаблонОшибки = - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но указанное ограничение чтения изменения не представлено одной функцией ""%2"".'"); - Иначе - ШаблонОшибки = - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но указанное ограничение чтения не представлено одной функцией ""%2"".'"); - КонецЕсли; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, - ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено"); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Иначе - ОграничениеЧтения = ВозможноеОграничениеПоОбъектуВладельцу(ОграничениеЧтения, Ложь, Контекст); - Если ОграничениеЧтения = Неопределено Тогда - Возврат; - КонецЕсли; - КонецЕсли; - Если ЗначениеЗаполнено(ОграничениеЧтения) Тогда - Если Не ФункцияБезУточненийТиповСПолемБезВложений(ОграничениеЧтения) Тогда - Если ТребуетсяОграничениеПоВладельцу Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но параметры функции ""%2"" не представлены - |только одним параметром - полем владельцем без других параметров.'"), - ИмяПризнакаОптимизации, - "ЧтениеОбъектаРазрешено"); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - Иначе - Возврат; - КонецЕсли; - КонецЕсли; - ОграничениеЧтенияПоле = ОграничениеЧтения.Поле; // См. ОписаниеУзла - ПолеВладельца.Имя = ОграничениеЧтенияПоле.Имя; - КонецЕсли; - КонецЕсли; - - Если Результат.ЕстьОграничениеИзменения Тогда - - Если ТребуетсяОграничениеПоВладельцу Или Не Контекст.ЭтоСсылочныйТип Тогда - - Если ОграничениеИзменения.Узел <> "ЧтениеОбъектаРазрешено" - И ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено" Тогда - - Если Не ТребуетсяОграничениеПоВладельцу Тогда - Возврат; - КонецЕсли; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но указанное ограничение изменения не представлено одной функцией - |""%2"" или ""%3"".'"), - ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено"); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - Иначе - ОграничениеИзменения = ВозможноеОграничениеПоОбъектуВладельцу(ОграничениеИзменения, Истина, Контекст); - Если ОграничениеИзменения = Неопределено Тогда - Возврат; - КонецЕсли; - КонецЕсли; - Если ЗначениеЗаполнено(ОграничениеИзменения) Тогда - Если Не ФункцияБезУточненийТиповСПолемБезВложений(ОграничениеИзменения) Тогда - Если ТребуетсяОграничениеПоВладельцу Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но параметры функции ""%2"" не представлены - |только одним параметром - полем владельцем без других параметров.'"), - ИмяПризнакаОптимизации, - ОграничениеИзменения.Узел); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - Иначе - Возврат; - КонецЕсли; - КонецЕсли; - ОграничениеИзмененияПоле = ОграничениеИзменения.Поле; // См. ОписаниеУзла - - Если ПолеВладельца.Имя = "" Тогда - ПолеВладельца.Имя = ОграничениеИзмененияПоле.Имя; - - ИначеЕсли ПолеВладельца.Имя <> ОграничениеИзмененияПоле.Имя Тогда - Если ТребуетсяОграничениеПоВладельцу Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но поле владельца не совпадает в ограничениях чтения и изменения.'"), - ИмяПризнакаОптимизации, - ОграничениеИзменения.Узел); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - Иначе - Возврат; - КонецЕсли; - КонецЕсли; - ПолеВладельца.ИзменениеКакЧтение = - ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено"; - Иначе - ПолеВладельца.ИзменениеКакЧтение = Истина; - КонецЕсли; - Иначе - ПолеВладельца.ИзменениеКакЧтение = Истина; - КонецЕсли; - - Если Не ЗначениеЗаполнено(ПолеВладельца.Имя) Тогда - Если ТребуетсяОграничениеПоВладельцу Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но указанное ограничение не содержит ни одной из функций - |""%2"", ""%3"".'"), - ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено"); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - Иначе - Возврат; - КонецЕсли; - КонецЕсли; - - Результат.ПолеВладельца = ПолеВладельца; - - Если Не Контекст.ЭтоСсылочныйТип Тогда - Результат.ТребуетсяОграничениеПоВладельцу = Истина; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения. -Функция ВозможноеОграничениеПоОбъектуВладельцу(Условие, ЭтоОграничениеИзменения, Контекст) - - Если Не ЗначениеЗаполнено(Условие) Тогда - Возврат Новый Структура; - КонецЕсли; - - Если Условие.Узел = "Поле" - Или Условие.Узел = "ЕстьNull" - Или Условие.Узел = "=" - Или Условие.Узел = "<>" - Или Условие.Узел = "В" - Или Условие.Узел = "Константа" - Или Условие.Узел = "ЗначениеРазрешено" Тогда - - Возврат Новый Структура; - - ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" - Или Условие.Узел = "ЧтениеСпискаРазрешено" - Или Условие.Узел = "ИзменениеСпискаРазрешено" - Или Условие.Узел = "ПравоДоступа" - Или Условие.Узел = "РольДоступна" Тогда - - Возврат Неопределено; - - ИначеЕсли Условие.Узел = "И" - Или Условие.Узел = "Или" Тогда - - НайденноеОграничение = Новый Структура; - Для Каждого Аргумент Из Условие.Аргументы Цикл - Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Аргумент, - ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда - Возврат Неопределено; - КонецЕсли; - КонецЦикла; - Возврат НайденноеОграничение; - - ИначеЕсли Условие.Узел = "Не" - Или Условие.Узел = "ДляВсехСтрок" - Или Условие.Узел = "ДляОднойИзСтрок" Тогда - - Возврат ВозможноеОграничениеПоОбъектуВладельцу(Условие.Аргумент, - ЭтоОграничениеИзменения, Контекст); - - ИначеЕсли Условие.Узел = "Выбор" Тогда - НайденноеОграничение = Новый Структура; - Для Каждого Когда Из Условие.Когда Цикл - Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Когда.Значение, - ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда - Возврат Неопределено; - КонецЕсли; - КонецЦикла; - Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Условие.Иначе, - ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда - Возврат Неопределено; - КонецЕсли; - Возврат НайденноеОграничение; - - ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ЭтоОграничениеИзменения Тогда - - Возврат Условие; - КонецЕсли; - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При заполнении возможного ограничения по объекту владельцу - |для списка ""%1"" - |узел не поддерживается ""%2"".'"), - Контекст.Список, - Условие.Узел); - - ВызватьИсключение ТекстОшибки; - -КонецФункции - -// Для функции ВозможноеОграничениеПоОбъектуВладельцу. -Функция ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Условие, - ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) - - ВложенноеОграничение = ВозможноеОграничениеПоОбъектуВладельцу(Условие, - ЭтоОграничениеИзменения, Контекст); - - Если ВложенноеОграничение = Неопределено Тогда - Возврат Ложь; - КонецЕсли; - - Если ЗначениеЗаполнено(ВложенноеОграничение) Тогда - Если ЗначениеЗаполнено(НайденноеОграничение) Тогда - Возврат Ложь; - КонецЕсли; - НайденноеОграничение = ВложенноеОграничение; - КонецЕсли; - - Возврат Истина; - -КонецФункции - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьОграничениеПоОбъектуВладельцуПослеУпрощения(Результат, Контекст) - - ПолеВладельца = Результат.ПолеВладельца; - Если ПолеВладельца = Неопределено Тогда - Возврат; - КонецЕсли; - ТребуетсяОграничениеПоВладельцу = Результат.ТребуетсяОграничениеПоВладельцу; - - НастройкаПоВладельцу = Контекст.СпискиСОграничениемПоВладельцу.Получить(Контекст.Список); - Если ТипЗнч(НастройкаПоВладельцу) = Тип("Булево") Тогда - ПолеВладельца.Отключено = Не НастройкаПоВладельцу; - Иначе - ПолеВладельца.Отключено = Ложь; - КонецЕсли; - - ОграничениеЧтения = Контекст.СтруктураОграничения.ОграничениеЧтения; - ОграничениеИзменения = Контекст.СтруктураОграничения.ОграничениеИзменения; - - ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, - "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); - - Если Не Результат.ЕстьОграничениеЧтения - И Не Результат.ЕстьОграничениеИзменения - Или Результат.ЕстьОграничениеЧтения - И ОграничениеЧтения.Узел <> "ЧтениеОбъектаРазрешено" - Или Результат.ЕстьОграничениеИзменения - И ОграничениеИзменения.Узел <> "ЧтениеОбъектаРазрешено" - И ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено" Тогда - - ПолеВладельца.Отключено = Истина; - Иначе - СвойстваПолей = Контекст.СвойстваПолей; - - Если СвойстваПолей.Количество() <> 1 Тогда - Если ТребуетсяОграничениеПоВладельцу И СвойстваПолей.Количество() <> 0 Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но количество полей, используемых в ограничении, не равно одному.'"), - ИмяПризнакаОптимизации); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - Иначе - ПолеВладельца.Отключено = Истина; - КонецЕсли; - Иначе - СвойстваПоля = СвойстваПолей[0]; - - ТипИОМ = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных"); - ТипИОР = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений"); - - КоличествоТиповИдентификаторовВКонечномПоле = 0; - Если СвойстваПоля.ТипКонечногоПоля.СодержитТип(ТипИОМ) Тогда - КоличествоТиповИдентификаторовВКонечномПоле = 1; - КонецЕсли; - Если СвойстваПоля.ТипКонечногоПоля.СодержитТип(ТипИОР) Тогда - КоличествоТиповИдентификаторовВКонечномПоле = КоличествоТиповИдентификаторовВКонечномПоле + 1; - КонецЕсли; - - Если СвойстваПоля.ТипКонечногоПоля.Типы().Количество() - КоличествоТиповИдентификаторовВКонечномПоле - <> СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() Тогда - - НекорректныеТипы = Новый Массив; - Для Каждого Тип Из СвойстваПоля.ТипКонечногоПоля.Типы() Цикл - Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Найти(Тип) <> Неопределено - Или Тип = ТипИОМ - Или Тип = ТипИОР Тогда - Продолжить; - КонецЕсли; - НекорректныеТипы.Добавить(ИмяТипаНаЯзыкеЗапросов(Тип)); - КонецЦикла; - Если ТребуетсяОграничениеПоВладельцу Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", - |но для следующих таблиц невозможно записать ключи доступа: - |%2'"), - ИмяПризнакаОптимизации, - СтрСоединить(НекорректныеТипы, Символы.ПС)); - ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - Иначе - ПолеВладельца.Отключено = Истина; - КонецЕсли; - КонецЕсли; - КонецЕсли; - КонецЕсли; - - ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "ИзменениеКакЧтение"); - ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "Имя"); - ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "Отключено"); - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * Имя - Строка -// * ИзменениеКакЧтение - Булево -// * Отключено - Булево -// -Функция НовоеПолеВладельца() - - Возврат Новый Структура("Имя, ИзменениеКакЧтение, Отключено", "", Ложь, Истина); - -КонецФункции - -// Для функции ЗаполнитьОграничениеПоОбъектуВладельцу и процедуры НастроитьОптимизациюПоПолюВладельцу. -Функция ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст) - - ОписаниеОшибок = ОписаниеОшибок(); - ОписаниеОшибок.ЕстьОшибки = Истина; - ОписаниеОшибок.ТекстОшибок = ТекстОшибки; - ОписаниеОшибок.Ошибки = Новый Массив(1); - - ОписаниеОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список); - - ОписаниеОшибок.Ограничение = - ПронумерованныйТекстОграниченияСОтметкамиОшибок(ОписаниеОграничения.Текст, - Новый Массив, СтрДлина(Формат(СтрЧислоСтрок(ОписаниеОграничения.Текст), "ЧГ="))); - - Возврат СокрЛП(ТекстОшибокДляВызоваИсключения(Контекст.Список, - ОписаниеОшибок, Контекст.ДляВнешнихПользователей, ОписаниеОграничения.ВМодулеМенеджера)); - -КонецФункции - -// Для процедуры ЗаполнитьОграничениеПоОбъектуВладельцу. -Функция ФункцияБезУточненийТиповСПолемБезВложений(Ограничение) - - Если Ограничение.Типы.Количество() <> 0 - Или Ограничение.УточненияСравнения.Количество() <> 0 Тогда - Возврат Ложь; - КонецЕсли; - - Поле = Ограничение.Поле; - - Возврат Не ЗначениеЗаполнено(Поле.Выразить) - И Не ЗначениеЗаполнено(Поле.Вложение) - И Не ЗначениеЗаполнено(Поле.ЕстьNull); - -КонецФункции - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьНаличиеВедущихКлючейИСписковИВладельцевНастроекПрав(Результат, Контекст) - - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() > 0 Тогда - Результат.ЕстьВедущиеКлючиДоступа = Истина; - КонецЕсли; - Если СвойстваПоля.ЕстьТипВедущегоСписка Тогда - Результат.ЕстьВедущиеСпискиПоПравам = Истина; - КонецЕсли; - Если СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда - Результат.ЕстьВладельцыНастроекПрав = Истина; - КонецЕсли; - Если СвойстваПоля.ЕстьПроверкаАвторизованногоПользователя Тогда - Контекст.ЕстьПроверкаАвторизованногоПользователя = Истина; - КонецЕсли; - Для Каждого Тип Из СвойстваПоля.ИспользуемыеТипыЗначенийДоступа Цикл - Если Результат.ИспользуемыеТипыЗначенийДоступа.Найти(Тип) = Неопределено Тогда - Результат.ИспользуемыеТипыЗначенийДоступа.Добавить(Тип); - КонецЕсли; - КонецЦикла; - КонецЦикла; - - Для Каждого КлючИЗначение Из Контекст.ОтдельныеТаблицыНастроекПрав Цикл - Если КлючИЗначение.Значение = Контекст.Список Тогда - Результат.ИдентификаторТаблицыНастроекПрав = КлючИЗначение.Ключ; - Прервать; - КонецЕсли; - КонецЦикла; - - ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВедущиеКлючиДоступа"); - ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВедущиеСпискиПоПравам"); - ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВладельцыНастроекПрав"); - ДобавитьСвойствоВерсии(Контекст, Результат, "ИспользуемыеТипыЗначенийДоступа"); - ДобавитьСвойствоВерсии(Контекст, Контекст, "НеиспользуемыеТипыЗначенийДоступа"); - - СохраняемыеСвойства = Новый Структура("ОтдельнаяТаблицаНастроекПрав", - ЗначениеЗаполнено(Результат.ИдентификаторТаблицыНастроекПрав)); - - ДобавитьСвойствоВерсии(Контекст, СохраняемыеСвойства, "ОтдельнаяТаблицаНастроекПрав"); - -КонецПроцедуры - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура УдалитьПоляНеиспользуемыхВидовДоступа(Результат, Контекст) - - СвойстваПолей = Контекст.СвойстваПолей; - - Если Не Результат.ЕстьВедущиеКлючиДоступа - И Не Результат.ЕстьВедущиеСпискиПоПравам - И Не Результат.ЕстьВладельцыНастроекПрав - И Не Результат.ЕстьФункцияПравоДоступаИлиРольДоступна - И Не Контекст.ЕстьПроверкаАвторизованногоПользователя - И Результат.ИспользуемыеТипыЗначенийДоступа.Количество() = 0 - И Контекст.НеиспользуемыеТипыЗначенийДоступа.Количество() > 0 Тогда - - СвойстваПолей.Очистить(); - Возврат; - КонецЕсли; - - Индекс = СвойстваПолей.Количество(); - Пока Индекс > 0 Цикл - Индекс = Индекс - 1; - СвойстваПоля = СвойстваПолей.Получить(Индекс); - УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, СвойстваПоля); - УстановитьИспользованиеОпорногоПоля(Контекст, СвойстваПоля); - ДобавитьСвойстваВерсии(Контекст, СвойстваПоля, - "ЕстьУточнениеNull, - |ЕстьУточнениеНеопределено, - |ИмяПоляДляЗапроса, - |НесколькоГруппЗначений, - |ТипКонечногоПоля, - |ТипыСохраненияГруппЗначений, - |ТипыСохраненияЗначений, - |ТипыСохраненияКлючейДоступа, - |ТипыСохраненияПустойСсылки, - |ТипыСохраненияТипаРазрешенный, - |ТипыСохраненияТипаЗапрещенный, - |ТипыСохраненияТипов, - |ТипыСохраненияТиповКонфигурации, - |ТипыСохраненияТиповПростых, - |ТипыСохраненияТиповРасширений, - |ТипыСтрокой"); - КонецЦикла; - -КонецПроцедуры - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьНаличиеОграниченияПоВидуДоступаПользователи(Результат, Контекст) - - Если Результат.ЕстьВладельцыНастроекПрав Тогда - Результат.ЕстьОграничениеПоПользователям = Истина; - Иначе - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - Если СвойстваПоля.ТипыСохраненияЗначений.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - ОписаниеТипов = Новый ОписаниеТипов(СвойстваПоля.ТипыСохраненияЗначений); - Если Не Результат.ДляВнешнихПользователей - И ( ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.Пользователи")) - Или ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ГруппыПользователей")) ) Тогда - - Результат.ЕстьОграничениеПоПользователям = Истина; - Прервать; - КонецЕсли; - Если Результат.ДляВнешнихПользователей - И ( ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ВнешниеПользователи")) - Или ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ГруппыВнешнихПользователей")) ) Тогда - - Результат.ЕстьОграничениеПоПользователям = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеПоПользователям"); - -КонецПроцедуры - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьНаличиеОграниченияЧтения(Результат, Контекст) - - Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения Тогда - Результат.ОграничениеЧтенияОтключено = Ложь; - Иначе - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - Если СвойстваПоля.Чтение Тогда - Результат.ОграничениеЧтенияОтключено = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - ДобавитьСвойствоВерсии(Контекст, Результат, "ОграничениеЧтенияОтключено"); - -КонецПроцедуры - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьГруппыПолейИДополнительныхТаблиц(Контекст) - - // Поля шапки (начинаются от шапки - группировка по пустому псевдониму, если нет имени табличной части). - // Поля каждой ТЧ (начинаются от табличной части - группировка по имени табличной части). - // Поля группы связанных дополнительных таблиц (начинаются от экземпляра доп. таблицы - группировка - // по псевдониму, но если одна таблица ссылается на другую в соединении, тогда образуется группа таблиц). - - НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = 0; - НомерПоследнейТабличнойЧастиОбъекта = 0; - НомераТабличныхЧастейОбъекта = Новый Соответствие; - - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" - И СвойстваПоля.НесколькоГруппЗначений Тогда - - НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = - НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + 1; - - ИначеЕсли СвойстваПоля.ПсевдонимТаблицы <> "ТекущийСписок" - И СтрНачинаетсяС(СвойстваПоля.ПсевдонимТаблицы, "ТекущийСписок") - И НомераТабличныхЧастейОбъекта.Получить(СвойстваПоля.ПсевдонимТаблицы) = Неопределено Тогда - - НомерПоследнейТабличнойЧастиОбъекта = НомерПоследнейТабличнойЧастиОбъекта + 1; - НомераТабличныхЧастейОбъекта.Вставить(СвойстваПоля.ПсевдонимТаблицы, НомерПоследнейТабличнойЧастиОбъекта); - КонецЕсли; - КонецЦикла; - - РазмерностьКлючаДоступа = УправлениеДоступомСлужебныйПовтИсп.РазмерностьКлючаДоступа(); - - КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта = Цел( - (НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа - + РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти - 1) - / РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти); - - ГруппыДополнительныхТаблиц = ГруппыДополнительныхТаблиц(Контекст); - КоличествоТабличныхЧастейКлюча = НомерПоследнейТабличнойЧастиОбъекта - + ГруппыДополнительныхТаблиц.ТаблицыПоГруппам.Количество() - + КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта; - - ЗавершитьПодготовкуПолейТаблицОбъекта(Контекст); - ЗавершитьПодготовкуОпорныхПолей(Контекст); - - Если КоличествоТабличныхЧастейКлюча > РазмерностьКлючаДоступа.КоличествоТабличныхЧастей Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В ограничении доступа списка %1 - |количество полей, требующих отдельных табличных частей в ключе доступа, - |более, чем количество доступных табличных частей в ключе доступа. - | - |К таким полям относятся: - |- поля табличных частей, - |- поля дополнительных таблиц, присоединенных к списку, - |- поля шапки, у которых значение доступа может иметь более одной группы значений доступа.'"), - Контекст.Список); - - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если Не Контекст.ЭтоСсылочныйТип - И Контекст.ОпорныеПоля.Все.Количество() > Контекст.ОпорныеПоля.МаксимальноеКоличество Тогда - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В ограничении доступа списка %1 - |количество полей списка, используемых в ограничении доступа, - |превышает максимально допустимое количество опорных полей: %2.'"), - Контекст.Список, - Контекст.ОпорныеПоля.МаксимальноеКоличество); - - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ГруппыПолей = Новый Соответствие; - ПсевдонимыТабличныхЧастейОбъекта = Новый Соответствие; - НомерПоследнегоРеквизитаШапки = 0; - НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = 0; - - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" Тогда - - Если СвойстваПоля.НесколькоГруппЗначений Тогда - НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = - НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + 1; - - НомерТабличнойЧастиКлюча = Цел(НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа - / РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти) + 1; - - ИмяГруппыПолей = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); - Иначе - НомерПоследнегоРеквизитаШапки = НомерПоследнегоРеквизитаШапки + 1; - Если НомерПоследнегоРеквизитаШапки < 6 Тогда - ИмяГруппыПолей = "Шапка0"; - ИначеЕсли НомерПоследнегоРеквизитаШапки < 11 Тогда - ИмяГруппыПолей = "Шапка1"; - ИначеЕсли НомерПоследнегоРеквизитаШапки < 16 Тогда - ИмяГруппыПолей = "Шапка2"; - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В ограничении доступа списка %1 - |количество полей списка, используемых в ограничении доступа, - |превышает максимально допустимое количество: 15.'"), - Контекст.Список); - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - КонецЕсли; - Иначе - Если СвойстваПоля.ПсевдонимТаблицы <> "ТекущийСписок" - И СтрНачинаетсяС(СвойстваПоля.ПсевдонимТаблицы, "ТекущийСписок") Тогда - - НомерТабличнойЧастиКлюча = КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта - + НомераТабличныхЧастейОбъекта.Получить(СвойстваПоля.ПсевдонимТаблицы); - - Если ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча) = Неопределено Тогда - ПсевдонимыТабличныхЧастейОбъекта.Вставить(НомерТабличнойЧастиКлюча, СвойстваПоля.ПсевдонимТаблицы) - КонецЕсли; - Иначе - НомерТабличнойЧастиКлюча = КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта - + НомераТабличныхЧастейОбъекта.Количество() - + ГруппыДополнительныхТаблиц.НомераПоПсевдонимам.Получить(СвойстваПоля.ПсевдонимТаблицы); - КонецЕсли; - ИмяГруппыПолей = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); - КонецЕсли; - ГруппаПолей = ГруппыПолей.Получить(ИмяГруппыПолей); - Если ГруппаПолей = Неопределено Тогда - ГруппаПолей = Новый Массив; - ГруппыПолей.Вставить(ИмяГруппыПолей, ГруппаПолей); - КонецЕсли; - ГруппаПолей.Добавить(СвойстваПоля); - СвойстваПоля.Вставить("ИмяГруппыПолейКлючаДоступа", ИмяГруппыПолей); - СвойстваПоля.Вставить("ИмяРеквизитаГруппыПолейКлючаДоступа", - "Значение" + XMLСтрока(ГруппаПолей.Количество() + ?(ИмяГруппыПолей = "Шапка1" Или ИмяГруппыПолей = "Шапка2", 5, 0))); - - Если Не СтрНачинаетсяС(ИмяГруппыПолей, "Шапка") - И ГруппаПолей.Количество() > РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти Тогда - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В ограничении доступа списка %1 - |количество полей одной табличной части, используемых в ограничении доступа, - |превышает максимально допустимое количество: %2.'"), - Контекст.Список, - РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти); - - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - КонецЦикла; - - Контекст.Вставить("ГруппыПолей", ГруппыПолей); - Контекст.Вставить("ПсевдонимыТабличныхЧастейОбъекта", ПсевдонимыТабличныхЧастейОбъекта); - Контекст.Вставить("ГруппыДополнительныхТаблиц", ГруппыДополнительныхТаблиц); - Контекст.Вставить("КоличествоТабличныхЧастейКлюча", КоличествоТабличныхЧастейКлюча); - - // Расчет числа СоставПолей. - - // Шапка и табличные части: ТЧ4 ТЧ3 ТЧ2 ТЧ1 Ш. - // Двоичный формат: 0000 0000 0000 0000 0000. - // Шестнадцатеричный формат: x0 x0 x0 x0 x0. - // - // Например: Ш0=1, ТЧ1=1. - // Двоичный формат: 0000 0000 0000 0001 0001. - // Шестнадцатеричный формат: x0 x0 x0 x1 x1. - // Число = 1*16^0 + 1*16^1 = 1 + 16 = 17. - - СоставПолей = НомерПоследнегоРеквизитаШапки; - - Для НомерТабличнойЧастиКлюча = 1 По КоличествоТабличныхЧастейКлюча Цикл - ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); - ГруппаПолей = ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); - СоставПолей = СоставПолей + ГруппаПолей.Количество() * Степень16(НомерТабличнойЧастиКлюча); - КонецЦикла; - - Контекст.Вставить("СоставПолей", СоставПолей); - -КонецПроцедуры - -// Для функции ПараметрыОграниченияДоступа. -// -// Параметры: -// УсловиеРасчета - см. СтруктураРасчетаПрава -// Условие - см. ОписаниеУзла -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета, Условие, Контекст, КореньУсловия = Истина) - - Если Не ЗначениеЗаполнено(Условие) Тогда - Возврат; - КонецЕсли; - - Если КореньУсловия Тогда - Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); - Контекст.Вставить("СтруктураРасчетаПраваСвойстваВерсии", Новый Массив); - КонецЕсли; - - СвойстваПоля = Неопределено; - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Узел", Условие.Узел); - - Если Условие.Узел = "Поле" Тогда - СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие); - - ИначеЕсли Условие.Узел = "И" - Или Условие.Узел = "Или" Тогда - - УсловиеРасчета = Новый Структура("Узел, Аргументы", Условие.Узел, Новый Массив); - Индекс = 0; - Для Каждого Аргумент Из Условие.Аргументы Цикл - УсловиеРасчета.Аргументы.Добавить(Неопределено); - ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргументы[Индекс], Аргумент, Контекст, Ложь); - Индекс = Индекс + 1; - КонецЦикла; - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "Не" Тогда - УсловиеРасчета = Новый Структура("Узел, Аргумент", Условие.Узел, Неопределено); - ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргумент, Условие.Аргумент, Контекст, Ложь); - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "ДляВсехСтрок" - Или Условие.Узел = "ДляОднойИзСтрок" Тогда - - Если Не КореньУсловия Тогда - ТребуемыеРеквизитыТабличныхЧастейКлюча = Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча; - Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); - КонецЕсли; - - УсловиеРасчета = Новый Структура("Узел, Аргумент", Условие.Узел, Неопределено); - ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргумент, Условие.Аргумент, Контекст, Ложь); - - Если Не КореньУсловия Тогда - УсловиеРасчета.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча); - Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", ТребуемыеРеквизитыТабличныхЧастейКлюча); - КонецЕсли; - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "ЕстьNull" Тогда - СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.Аргумент); - - ИначеЕсли Условие.Узел = "=" - Или Условие.Узел = "<>" Тогда - - СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.ПервыйАргумент); - Если СвойстваПоля = Неопределено Тогда - СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.ВторойАргумент); - КонецЕсли; - - ИначеЕсли Условие.Узел = "В" Тогда - СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.Искомое); - - ИначеЕсли Условие.Узел = "Выбор" Тогда - УсловиеРасчета = Новый Структура("Узел, Когда, Иначе", Условие.Узел, Новый Массив, Неопределено); - Для Каждого Когда Из Условие.Когда Цикл - СтруктураКогда = Новый Структура("Условие, Значение"); - УсловиеРасчета.Когда.Добавить(СтруктураКогда); - Если Условие.Выбор = Неопределено Тогда - ЗаполнитьСтруктуруРасчетаПрава(СтруктураКогда.Условие, Когда.Условие, Контекст, Ложь); - Иначе - Свойства = Контекст.СвойстваПолейКлючаДоступа.Получить(Когда.Условие); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Узел", "Поле"); - УсловиеРасчетаПоле(СтруктураКогда.Условие, Свойства, Контекст); - КонецЕсли; - ЗаполнитьСтруктуруРасчетаПрава(СтруктураКогда.Значение, Когда.Значение, Контекст, Ложь); - КонецЦикла; - ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Иначе, Условие.Иначе, Контекст, Ложь); - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "ЗначениеРазрешено" - Или Условие.Узел = "ЭтоАвторизованныйПользователь" - Или Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" - Или Условие.Узел = "ЧтениеСпискаРазрешено" - Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда - - УсловиеРасчета = Новый Структура("Узел, Поле", Условие.Узел, Неопределено); - УсловиеРасчета.Вставить("УточненияСравнения", Новый Соответствие); - Для Каждого КлючИЗначение Из Условие.УточненияСравнения Цикл - Если КлючИЗначение.Ключ = "Null" - Или КлючИЗначение.Ключ = "Неопределено" - Или КлючИЗначение.Ключ = "ПустаяСсылка" - Или КлючИЗначение.Ключ = "Отключено" Тогда - УсловиеРасчета.УточненияСравнения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - Иначе - ИмяТипа = СтрЗаменить(КлючИЗначение.Ключ, ".", "Ссылка."); - УсловиеРасчета.УточненияСравнения.Вставить(Тип(ИмяТипа), КлючИЗначение.Значение); - КонецЕсли; - КонецЦикла; - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "УточненияСравнения", Условие.УточненияСравнения); - ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Поле, Условие.Поле, Контекст, Ложь); - - Если УсловиеРасчета.Поле = Null Тогда - УсловиеРасчета = Новый Структура("Узел, Значение", "Константа", Истина); - КонецЕсли; - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "Константа" Тогда - УсловиеРасчета = Новый Структура("Узел, Значение", Условие.Узел, Условие.Значение); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Значение", Условие.Значение); - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "ПравоДоступа" Тогда - УсловиеРасчета = Новый Структура("Узел, ИмяПрава, ПолноеИмяОбъектаМетаданных", - Условие.Узел, Условие.ИмяПрава, Условие.ПолноеИмяОбъектаМетаданных); - ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ИмяПрава", Условие.ИмяПрава); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ПолноеИмяОбъектаМетаданных", - Условие.ПолноеИмяОбъектаМетаданных); - СвойстваПоля = Null; - - ИначеЕсли Условие.Узел = "РольДоступна" Тогда - УсловиеРасчета = Новый Структура("Узел, ИмяРоли", Условие.Узел, Условие.ИмяРоли); - ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ИмяРоли", Условие.ИмяРоли); - СвойстваПоля = Null; - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При заполнении структуры расчета права %1 на ключи доступа - |списка ""%2"" - |узел не поддерживается ""%3"".'"), - Контекст.ИмяПрава, - Контекст.Список, - Условие.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если СвойстваПоля = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При заполнении структуры расчета права %1 на ключи доступа - |списка ""%2"" - |свойства поля не определены для узла ""%3"".'"), - Контекст.ИмяПрава, - Контекст.Список, - Условие.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если СвойстваПоля <> Null Тогда - УсловиеРасчетаПоле(УсловиеРасчета, СвойстваПоля, Контекст); - КонецЕсли; - - Если КореньУсловия Тогда - УсловиеРасчета.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", - Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча); - - ДобавитьЭлементВерсии(Контекст, ?(Контекст.ИмяПрава = "Чтение", - "СтруктураРасчетаПраваЧтение", "СтруктураРасчетаПраваИзменение"), - Контекст.СтруктураРасчетаПраваСвойстваВерсии); - - Контекст.Удалить("СтруктураРасчетаПраваСвойстваВерсии"); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьСтруктуруРасчетаПрава. -Процедура УсловиеРасчетаПоле(УсловиеРасчета, СвойстваПоля, Контекст) - - Если Контекст.СвойстваПолей.Найти(СвойстваПоля) = Неопределено Тогда - УсловиеРасчета = Null; // Поле удалено из-за неиспользуемых типов значений доступа. - Иначе - УсловиеРасчета = Новый Структура("Узел", "Поле"); - УсловиеРасчета.Вставить("Таблица", СвойстваПоля.ИмяГруппыПолейКлючаДоступа); - УсловиеРасчета.Вставить("Реквизит", СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); - Если СтрНачинаетсяС(УсловиеРасчета.Таблица, "ТабличнаяЧасть") Тогда - Реквизиты = Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча.Получить(УсловиеРасчета.Таблица); - Если Реквизиты = Неопределено Тогда - Реквизиты = Новый Массив; - Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча.Вставить(УсловиеРасчета.Таблица, Реквизиты); - КонецЕсли; - Если Реквизиты.Найти(УсловиеРасчета.Реквизит) = Неопределено Тогда - Реквизиты.Добавить(УсловиеРасчета.Реквизит); - КонецЕсли; - КонецЕсли; - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Таблица", УсловиеРасчета.Таблица); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Реквизит", УсловиеРасчета.Реквизит); - Если СвойстваПоля.Свойство("ПроверкаЕстьNull") Тогда - УсловиеРасчета.Вставить("ПроверкаЕстьNull"); - ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ПроверкаЕстьNull", Истина); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьСтруктуруРасчетаПрава. -Процедура ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета) - - Если УсловиеРасчета.Свойство("ИмяРоли") Тогда - Роль = Метаданные.Роли.Найти(УсловиеРасчета.ИмяРоли); - Контекст.ВедущиеРоли.Вставить(Роль.Имя, Истина); - Возврат; - КонецЕсли; - - ИмяСтандартногоРеквизита = Неопределено; - ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава( - УсловиеРасчета.ПолноеИмяОбъектаМетаданных, ИмяСтандартногоРеквизита); - - Для Каждого Роль Из Метаданные.Роли Цикл - Если ПравоДоступа(УсловиеРасчета.ИмяПрава, ОбъектМетаданных, Роль, ИмяСтандартногоРеквизита) Тогда - Контекст.ВедущиеРоли.Вставить(Роль.Имя, Истина); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ЗаполнитьСтруктуруРасчетаПрава, УсловиеРасчетаПоле. -Процедура ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, Имя, Значение); - - Если ТипЗнч(Значение) = Тип("Соответствие") Тогда - СписокЗначений = Новый СписокЗначений; - Для Каждого КлючИЗначение Из Значение Цикл - СписокЗначений.Добавить(КлючИЗначение.Значение, КлючИЗначение.Ключ); - КонецЦикла; - СписокЗначений.СортироватьПоПредставлению(); - Для Каждого ЭлементСписка Из СписокЗначений Цикл - Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(ЭлементСписка.Представление); - Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(ЭлементСписка.Значение); - КонецЦикла; - Иначе - Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(Имя); - Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(Значение); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. -Функция Степень16(Степень) - - Степень16 = 1; - - Для Счетчик = 1 По Степень Цикл - Степень16 = Степень16 * 16; - КонецЦикла; - - Возврат Степень16; - -КонецФункции - -// Для функции ЗаполнитьГруппыПолейИДополнительныхТаблиц. -// -// Параметры: -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -// Возвращаемое значение: -// Структура: -// * НомераПоПсевдонимам - Соответствие из КлючИЗначение: -// ** Ключ - Строка - псевдоним дополнительной таблицы -// ** Значение - Число - номер группы дополнительных таблиц -// -// * ТаблицыПоГруппам - Соответствие из КлючИЗначение: -// ** Ключ - Число - номер группы дополнительных таблиц -// ** Значение - Массив из см. НовоеОписаниеСоединения -// -// * ПсевдонимыТаблицСПолями - Соответствие из КлючИЗначение: -// ** Ключ - Строка - псевдоним дополнительной таблицы -// с полями ключа доступа (кроме полей соединений). -// ** Значение - Булево - Истина. -// -Функция ГруппыДополнительныхТаблиц(Контекст) - - ДополнительныеТаблицы = Контекст.СтруктураОграничения.ДополнительныеТаблицы; - НомераГруппПоПсевдонимам = Новый Соответствие; - - Контекст.ОпорныеПоля.Вставить("ПоДополнительнымТаблицам", Новый Соответствие); - Контекст.ПоляТаблицОбъекта.Вставить("ПоДополнительнымТаблицам", Новый Соответствие); - Контекст.Вставить("ПоляУсловияСоединенияДополнительныхТаблиц", Новый Массив); - - ПоследняяГруппа = 0; - Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл - ДополнительнаяТаблица.Вставить("ПсевдонимыТребуемыхТаблиц", Новый Массив); - ДополнительнаяТаблица.Вставить("ПоляУсловияСоединения", Новый Массив); - - ТекстУсловияСоединения = ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст); - ДополнительнаяТаблица.Вставить("ТекстУсловияСоединения", ?(Лев(ТекстУсловияСоединения, 1) = "(", - ТекстУсловияСоединения, "(" + ТекстУсловияСоединения + ")")); - - ТекущаяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); - Если ТекущаяГруппа = Неопределено Тогда - ПоследняяГруппа = ПоследняяГруппа + 1; - ТекущаяГруппа = ПоследняяГруппа; - НомераГруппПоПсевдонимам.Вставить(ДополнительнаяТаблица.Псевдоним, ТекущаяГруппа); - КонецЕсли; - - Для Каждого Псевдоним Из ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц Цикл - ГруппаТребуемойТаблицы = НомераГруппПоПсевдонимам.Получить(Псевдоним); - Если ГруппаТребуемойТаблицы = Неопределено Тогда - НомераГруппПоПсевдонимам.Вставить(Псевдоним, ТекущаяГруппа); - Продолжить; - КонецЕсли; - Если ГруппаТребуемойТаблицы = ТекущаяГруппа Тогда - Продолжить; - КонецЕсли; - ПсевдонимыЗаменяемойГруппы = Новый Массив; - Для Каждого КлючИЗначение Из НомераГруппПоПсевдонимам Цикл - Если КлючИЗначение.Значение <> ГруппаТребуемойТаблицы Тогда - Продолжить; - КонецЕсли; - ПсевдонимыЗаменяемойГруппы.Добавить(КлючИЗначение.Ключ); - КонецЦикла; - Для Каждого Псевдоним Из ПсевдонимыЗаменяемойГруппы Цикл - НомераГруппПоПсевдонимам.Вставить(Псевдоним, ТекущаяГруппа); - КонецЦикла; - КонецЦикла; - КонецЦикла; - - ПсевдонимыТаблицСПолями = Новый Соответствие; - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" Тогда - Продолжить; - КонецЕсли; - ПсевдонимыТаблицСПолями.Вставить(СвойстваПоля.ПсевдонимТаблицы, Истина); - КонецЦикла; - - ИспользованиеГрупп = Новый Соответствие; - Для Группа = 1 По ПоследняяГруппа Цикл - Для Каждого КлючИЗначение Из НомераГруппПоПсевдонимам Цикл - Если КлючИЗначение.Значение <> Группа Тогда - Продолжить; - КонецЕсли; - Если ИспользованиеГрупп.Получить(Группа) = Неопределено Тогда - ИспользованиеГрупп.Вставить(Группа, Ложь); - КонецЕсли; - Если ПсевдонимыТаблицСПолями.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда - ИспользованиеГрупп.Вставить(Группа, Истина); - КонецЕсли; - КонецЦикла; - КонецЦикла; - - НоваяГруппа = 1; - НовыеГруппы = Новый Соответствие; - Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл - СтараяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); - Если Не ИспользованиеГрупп.Получить(СтараяГруппа) Тогда - Продолжить; - КонецЕсли; - Если НовыеГруппы.Получить(СтараяГруппа) <> Неопределено Тогда - Продолжить; - КонецЕсли; - НовыеГруппы.Вставить(СтараяГруппа, НоваяГруппа); - НоваяГруппа = НоваяГруппа + 1; - КонецЦикла; - - Группы = Новый Структура; - Группы.Вставить("НомераПоПсевдонимам", Новый Соответствие); - Группы.Вставить("ТаблицыПоГруппам", Новый Соответствие); - Группы.Вставить("ПсевдонимыТаблицСПолями", ПсевдонимыТаблицСПолями); - - Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл - СтараяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); - Если Не ИспользованиеГрупп.Получить(СтараяГруппа) Тогда - Продолжить; - КонецЕсли; - УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, , ДополнительнаяТаблица); - УстановитьИспользованиеОпорногоПоля(Контекст, , ДополнительнаяТаблица); - Группа = НовыеГруппы.Получить(СтараяГруппа); - Группы.НомераПоПсевдонимам.Вставить(ДополнительнаяТаблица.Псевдоним, Группа); - ГруппаТаблиц = Группы.ТаблицыПоГруппам.Получить(Группа); - Если ГруппаТаблиц = Неопределено Тогда - ГруппаТаблиц = Новый Массив; - Группы.ТаблицыПоГруппам.Вставить(Группа, ГруппаТаблиц); - КонецЕсли; - ГруппаТаблиц.Добавить(ДополнительнаяТаблица); - КонецЦикла; - - Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл - ТекущиеСвойства = СвойстваПоля; - Пока ТекущиеСвойства <> Неопределено Цикл - ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, - ТекущиеСвойства.УзелПоле, - ТекущиеСвойства.СвойстваВложения, - ?(ТекущиеСвойства.ЭтоПолеСписка, Неопределено, ТекущиеСвойства.ПсевдонимТаблицы)); - ТекущиеСвойства = ТекущиеСвойства.СвойстваВложения; - КонецЦикла; - КонецЦикла; - - Для Каждого ОписаниеПоляУсловия Из Контекст.ПоляУсловияСоединенияДополнительныхТаблиц Цикл - Группа = Группы.НомераПоПсевдонимам.Получить(ОписаниеПоляУсловия.ПсевдонимТаблицыУсловия); - Если Группа <> Неопределено Тогда - УзелПоле = ОписаниеПоляУсловия.УзелПоле; - ДобавитьСвойстваВерсии(Контекст, УзелПоле, "Псевдоним, Имя, ТипыСтрокой"); - ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, УзелПоле,, - Группы.ТаблицыПоГруппам.Получить(Группа), ОписаниеПоляУсловия.ПсевдонимТаблицыУсловия); - КонецЕсли; - КонецЦикла; - - Для Каждого Описание Из Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов Цикл - ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка(Описание.Ключ, - Описание.Значение, Группы, Контекст); - КонецЦикла; - ЗаполнитьОтборыВедущихСписковПоПолюСсылка(Контекст.ВедущиеСпискиПоКлючамДоступа, Группы, Контекст); - ЗаполнитьОтборыВедущихСписковПоПолюСсылка(Контекст.ВедущиеСпискиПоЗначениямСГруппами, Группы, Контекст); - - Возврат Группы; - -КонецФункции - -// Для функции ГруппыДополнительныхТаблиц. -Функция ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст, - Условие = Null, Поле = Неопределено, Псевдоним = Неопределено) - - Если Условие = Null Тогда - Условие = ДополнительнаяТаблица.УсловиеСоединения; - КонецЕсли; - - // Возможные узлы: "Поле", "Значение", "Константа", "И", "=". - - Если Условие.Узел = "Поле" Тогда - Контекст.ПоляУсловияСоединенияДополнительныхТаблиц.Добавить(Новый Структура( - "УзелПоле, ПсевдонимТаблицыУсловия", Условие, ДополнительнаяТаблица.Псевдоним)); - ДобавитьПолеТаблицыОбъекта(Контекст, Условие, , ДополнительнаяТаблица); - Если Условие.Псевдоним = Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда - ДобавитьОпорноеПоле(Контекст, Условие, , ДополнительнаяТаблица); - Псевдоним = "ТекущийСписок"; - Поле = Псевдоним + "." + Условие.Имя; - Возврат ИмяПоляСРазверткойОпорногоПоляПоТипам(Псевдоним, Условие); - КонецЕсли; - Псевдоним = Условие.Псевдоним; - Если Псевдоним <> ДополнительнаяТаблица.Псевдоним - И ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц.Найти(Псевдоним) = Неопределено Тогда - ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц.Добавить(Псевдоним); - КонецЕсли; - Поле = Псевдоним + "." + Условие.Имя; - Возврат Поле; - КонецЕсли; - - Если Условие.Узел = "Значение" - Или Условие.Узел = "Константа" Тогда - - Поле = ВыражениеУзлаЗначениеИлиКонстанта(Условие); - Возврат Поле; - КонецЕсли; - - Если Условие.Узел = "И" Тогда - Текст = ""; - Для Каждого Аргумент Из Условие.Аргументы Цикл - Текст = Текст + ?(Текст = "", "", Символы.ПС + "И "); - Текст = Текст + ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст, Аргумент); - КонецЦикла; - Возврат Текст; - КонецЕсли; - - Если Условие.Узел = "=" Тогда - ПервоеПоле = НовоеПолеУсловияСоединения(); - ВтороеПоле = НовоеПолеУсловияСоединения(); - - ПервыйАргумент = ТекстУсловияСоединения(ДополнительнаяТаблица, - Контекст, Условие.ПервыйАргумент, ПервоеПоле.Поле, ПервоеПоле.Псевдоним); - - ВторойАргумент = ТекстУсловияСоединения(ДополнительнаяТаблица, - Контекст, Условие.ВторойАргумент, ВтороеПоле.Поле, ВтороеПоле.Псевдоним); - - Если ПервоеПоле.Псевдоним = ДополнительнаяТаблица.Псевдоним - Или Не ЗначениеЗаполнено(ВтороеПоле.Псевдоним) Тогда - ТекстУсловия = "(" + ПервыйАргумент + " = " + ВторойАргумент + ")"; - ПоляУсловия = ПараПолейУсловияСоединения(ПервоеПоле, ВтороеПоле); - Иначе - ТекстУсловия = "(" + ВторойАргумент + " = " + ПервыйАргумент + ")"; - ПоляУсловия = ПараПолейУсловияСоединения(ВтороеПоле, ПервоеПоле); - КонецЕсли; - ДополнительнаяТаблица.ПоляУсловияСоединения.Добавить(ПоляУсловия); - Возврат ТекстУсловия; - КонецЕсли; - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не определена обработка узла ""%1""'"), Условие.Узел); - - ВызватьИсключение ТекстОшибки; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ПервоеПоле - см. НовоеПолеУсловияСоединения -// * ВтороеПоле - см. НовоеПолеУсловияСоединения -// -Функция ПараПолейУсловияСоединения(ПервоеПоле, ВтороеПоле) - - Возврат Новый Структура("ПервоеПоле, ВтороеПоле", ПервоеПоле, ВтороеПоле); - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * Поле - Строка -// * Псевдоним - Строка -// -Функция НовоеПолеУсловияСоединения() - - Возврат Новый Структура("Поле, Псевдоним"); - -КонецФункции - -// Для функций СвойстваПоля, ТекстУсловияСоединения. -Процедура ДобавитьПолеТаблицыОбъекта(Контекст, УзелПоле, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено, ТабличнаяЧасть = "") - - Если Не Контекст.ЭтоСсылочныйТип Тогда - Возврат; - КонецЕсли; - - ИмяТаблицыОбъекта = Контекст.Список; - - Если ЗначениеЗаполнено(УзелПоле.Псевдоним) - И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы - И ВРег(Контекст.Список) <> ВРег(УзелПоле.Таблица) Тогда - - ЧастиИмениТаблицы = СтрРазделить(УзелПоле.Таблица, ".", Ложь); - Если ЧастиИмениТаблицы.Количество() <> 3 Тогда - Возврат; - КонецЕсли; - ИмяТаблицыОбъекта = Контекст.Список + "." + ЧастиИмениТаблицы[2]; - КонецЕсли; - - ЧастиИмениПоля = СтрРазделить(УзелПоле.Имя, ".", Ложь); - Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда - ИмяПоляТаблицы = ЧастиИмениПоля[1]; - ТипыПоляТаблицы = УзелПоле.ТипыПоля[1]; - ИмяТаблицыОбъекта = Контекст.Список + "." + ТабличнаяЧасть; - Иначе - ИмяПоляТаблицы = ЧастиИмениПоля[0]; - ТипыПоляТаблицы = УзелПоле.ТипыПоля[0]; - КонецЕсли; - - ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; - ИмяТаблицыОбъекта = СтрЗаменить(ИмяТаблицыОбъекта, ".", "_"); - - Если СвойстваПоля <> Неопределено Тогда - ОписаниеПоляТаблицы = Новый Структура("Таблица, Поле", ИмяТаблицыОбъекта, ИмяПоляТаблицы); - ПоляТаблицОбъекта.ПоСвойствамПолей.Вставить(СвойстваПоля, ОписаниеПоляТаблицы); - КонецЕсли; - - Если ДополнительнаяТаблица <> Неопределено Тогда - ПоляТаблиц = ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); - Если ПоляТаблиц = Неопределено Тогда - ПоляТаблиц = Новый Структура; - ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Вставить(ДополнительнаяТаблица, ПоляТаблиц); - КонецЕсли; - Если Не ПоляТаблиц.Свойство(ИмяТаблицыОбъекта) Тогда - ПоляТаблиц.Вставить(ИмяТаблицыОбъекта, Новый Массив); - КонецЕсли; - ПоляТаблицы = ПоляТаблиц[ИмяТаблицыОбъекта]; // Массив - ПоляТаблицы.Добавить(ИмяПоляТаблицы); - КонецЕсли; - - Если Не ПоляТаблицОбъекта.Состав.Свойство(ИмяТаблицыОбъекта) Тогда - ПоляТаблицОбъекта.Состав.Вставить(ИмяТаблицыОбъекта, Новый Структура); - КонецЕсли; - ПоляТаблицы = ПоляТаблицОбъекта.Состав[ИмяТаблицыОбъекта]; - Если Не ПоляТаблицы.Свойство(ИмяПоляТаблицы) Тогда - ПоляТаблицы.Вставить(ИмяПоляТаблицы, Новый Структура("Тип, Использование", ТипыПоляТаблицы, Ложь)); - КонецЕсли; - -КонецПроцедуры - -// Для функций СвойстваПоля, ТекстУсловияСоединения. -Процедура ДобавитьОпорноеПоле(Контекст, УзелПоле, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) - - Если Не УзелПоле.Свойство("ОсновнойПорядок") Тогда - Возврат; - КонецЕсли; - - Позиция = СтрНайти(УзелПоле.Имя, "."); - Если Позиция = 0 Тогда - ИмяОпорногоПоля = УзелПоле.Имя; - Иначе - ИмяОпорногоПоля = Лев(УзелПоле.Имя, Позиция - 1); - КонецЕсли; - - ОпорныеПоля = Контекст.ОпорныеПоля; - - Если СвойстваПоля <> Неопределено Тогда - ОпорныеПоля.ПоСвойствамПолей.Вставить(СвойстваПоля, ИмяОпорногоПоля); - КонецЕсли; - - Если ДополнительнаяТаблица <> Неопределено Тогда - ИменаОпорныхПолей = ОпорныеПоля.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); - Если ИменаОпорныхПолей = Неопределено Тогда - ИменаОпорныхПолей = Новый Массив; - ОпорныеПоля.ПоДополнительнымТаблицам.Вставить(ДополнительнаяТаблица, ИменаОпорныхПолей); - КонецЕсли; - ИменаОпорныхПолей.Добавить(ИмяОпорногоПоля); - КонецЕсли; - - Если ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля) = Неопределено Тогда - ОпорныеПоля.Список.Добавить(ИмяОпорногоПоля, УзелПоле.ОсновнойПорядок); - ТипыОпорногоПоля = УзелПоле.ТипыПоля[0]; - ОпорныеПоля.ТипыПоИменамПолей.Вставить(ИмяОпорногоПоля, ТипыОпорногоПоля); - Если Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда - ЗапрещенныеТипы = Новый Массив; - Если ЕстьПростойТип(ТипыОпорногоПоля) Тогда - Для Каждого Тип Из ТипыОпорногоПоля.Типы() Цикл - Если ЭтоПростойТип(Тип) Тогда - ЗапрещенныеТипы.Добавить(Строка(Тип)); - КонецЕсли; - КонецЦикла; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В ограничении доступа списка %1 - |опорное поле %2 содержит простые типы: %3. - | - |Это недопустимо при использовании общего регистра сведений %4. - |Либо исключите простые типы из состава типов опорного поля, - |либо создайте отдельный регистр ключей доступа для этого списка.'"), - Контекст.Список, - ИмяОпорногоПоля, - СтрСоединить(ЗапрещенныеТипы, ", "), - "КлючиДоступаКРегистрам"); - - Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда - Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; - КонецЕсли; - ВызватьИсключение ТекстОшибки; - КонецЕсли; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедур УдалитьПоляНеиспользуемыхВидовДоступа, ГруппыДополнительныхТаблиц. -Процедура УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) - - Если Не Контекст.ЭтоСсылочныйТип Тогда - Возврат; - КонецЕсли; - - ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; - - Если СвойстваПоля <> Неопределено Тогда - ОписаниеПоля = ПоляТаблицОбъекта.ПоСвойствамПолей.Получить(СвойстваПоля); - Если ОписаниеПоля <> Неопределено Тогда - ПоляТаблицОбъекта.Состав[ОписаниеПоля.Таблица][ОписаниеПоля.Поле].Использование = Истина; - КонецЕсли; - Иначе - ПоляТаблиц = ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); - Если ПоляТаблиц <> Неопределено Тогда - Для Каждого ОписаниеПолей Из ПоляТаблиц Цикл - ПоляТаблицы = ПоляТаблицОбъекта.Состав[ОписаниеПолей.Ключ]; - Для Каждого ИмяПоля Из ОписаниеПолей.Значение Цикл - ПоляТаблицы[ИмяПоля].Использование = Истина; - КонецЦикла; - КонецЦикла; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедур УдалитьПоляНеиспользуемыхВидовДоступа, ГруппыДополнительныхТаблиц. -Процедура УстановитьИспользованиеОпорногоПоля(Контекст, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) - - ОпорныеПоля = Контекст.ОпорныеПоля; - - Если СвойстваПоля <> Неопределено Тогда - ИмяОпорногоПоля = ОпорныеПоля.ПоСвойствамПолей.Получить(СвойстваПоля); - Если ИмяОпорногоПоля <> Неопределено Тогда - ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля).Пометка = Истина; - КонецЕсли; - Иначе - ИменаОпорныхПолей = ОпорныеПоля.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); - Если ИменаОпорныхПолей <> Неопределено Тогда - Для Каждого ИмяОпорногоПоля Из ИменаОпорныхПолей Цикл - ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля).Пометка = Истина; - КонецЦикла; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. -// -// Параметры: -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗавершитьПодготовкуПолейТаблицОбъекта(Контекст) - - ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; - - Если Не Контекст.ЭтоСсылочныйТип Тогда - ПоляТаблицОбъекта.Удалить("ПоСвойствамПолей"); - ПоляТаблицОбъекта.Удалить("ПоДополнительнымТаблицам"); - Возврат; - КонецЕсли; - - ПолноеИмяОсновнойТаблицы = СтрЗаменить(Контекст.Список, ".", "_"); - ТипСсылки = Тип(ИмяТипаСсылки(Контекст.Список, Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам)); - ОписаниеТипаСсылки = Новый ОписаниеТипов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки)); - СвойстваВидаДоступа = Контекст.СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамСсылок.Получить(ТипСсылки); - Если СвойстваВидаДоступа <> Неопределено И Не СвойстваВидаДоступа.НесколькоГруппЗначений Тогда - МетаданныеТаблицы = Метаданные.НайтиПоТипу(ТипСсылки); - РеквизитГруппаДоступа = МетаданныеТаблицы.Реквизиты.Найти("ГруппаДоступа"); - КонецЕсли; - - ЕстьОсновнаяТаблица = Ложь; - ЕстьТабличнаяЧасть = Ложь; - - Для Каждого ОписаниеТаблицы Из ПоляТаблицОбъекта.Состав Цикл - ПоляТаблицы = НовыеПоляТаблицыОбъекта(); - ПоляТаблицы.ПолноеИмяТаблицы = ОписаниеТаблицы.Ключ; - ТаблицаЗначений = Новый ТаблицаЗначений; - ЕстьИспользуемыеПоля = Ложь; - Для Каждого ОписаниеПоля Из ОписаниеТаблицы.Значение Цикл - Если Не ОписаниеПоля.Значение.Использование Тогда - Продолжить; - КонецЕсли; - ЕстьИспользуемыеПоля = Истина; - Если ВРег("Ссылка") = ВРег(ОписаниеПоля.Ключ) Тогда - Продолжить; - КонецЕсли; - ПоляТаблицы.Поля.Добавить(ОписаниеПоля.Ключ); - ТаблицаЗначений.Колонки.Добавить(ОписаниеПоля.Ключ, ОписаниеПоля.Значение.Тип); - КонецЦикла; - Если Не ЕстьИспользуемыеПоля Тогда - Продолжить; - КонецЕсли; - Если ТипЗнч(РеквизитГруппаДоступа) = Тип("ОбъектМетаданных") - И ПоляТаблицы.Поля.Найти("ГруппаДоступа") = Неопределено Тогда - ПоляТаблицы.Поля.Добавить("ГруппаДоступа"); - ТаблицаЗначений.Колонки.Добавить("ГруппаДоступа", РеквизитГруппаДоступа.Тип); - КонецЕсли; - ПоляТаблицы.СписокПолей = СтрСоединить(ПоляТаблицы.Поля, ", "); - ПоляТаблицы.Поля.Вставить(0, "Ссылка"); - ТаблицаЗначений.Колонки.Добавить("Ссылка", ОписаниеТипаСсылки); - ПоляТаблицы.ТаблицаСПолями = Новый ХранилищеЗначения(ТаблицаЗначений); - Если ПоляТаблицы.ПолноеИмяТаблицы = ПолноеИмяОсновнойТаблицы Тогда - ЕстьОсновнаяТаблица = Истина; - Иначе - ЕстьТабличнаяЧасть = Истина; - ПоляТаблицы.ТабличнаяЧасть = Сред(ПоляТаблицы.ПолноеИмяТаблицы, - СтрДлина(ПолноеИмяОсновнойТаблицы) + 2); - КонецЕсли; - ПоляТаблицОбъекта.Результат.Добавить(ПоляТаблицы); - КонецЦикла; - - Если ЕстьТабличнаяЧасть И Не ЕстьОсновнаяТаблица Тогда - ПоляТаблицы = НовыеПоляТаблицыОбъекта(); - ПоляТаблицы.ПолноеИмяТаблицы = ПолноеИмяОсновнойТаблицы; - ПоляТаблицы.Поля.Вставить(0, "Ссылка"); - ТаблицаЗначений = Новый ТаблицаЗначений; - ТаблицаЗначений.Колонки.Добавить("Ссылка", ОписаниеТипаСсылки); - ПоляТаблицы.ТаблицаСПолями = Новый ХранилищеЗначения(ТаблицаЗначений); - ПоляТаблицОбъекта.Результат.Вставить(0, ПоляТаблицы); - КонецЕсли; - - ПоляТаблицОбъекта.Удалить("ПоСвойствамПолей"); - ПоляТаблицОбъекта.Удалить("ПоДополнительнымТаблицам"); - -КонецПроцедуры - -// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. -// -// Параметры: -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ЗавершитьПодготовкуОпорныхПолей(Контекст) - - ОпорныеПоля = Контекст.ОпорныеПоля; - ОпорныеПоля.Список.СортироватьПоПредставлению(); - - Для Каждого ЭлементСписка Из ОпорныеПоля.Список Цикл - ОпорныеПоля.Все.Добавить(ЭлементСписка.Значение); - ОпорныеПоля.ТипыВсех.Добавить(Новый ХранилищеЗначения( - ОпорныеПоля.ТипыПоИменамПолей.Получить(ЭлементСписка.Значение))); - - Если ЭлементСписка.Пометка Тогда - ОпорныеПоля.Используемые.Добавить(ЭлементСписка.Значение); - ОпорныеПоля.ТипыИспользуемых.Добавить(Новый ХранилищеЗначения( - ОпорныеПоля.ТипыПоИменамПолей.Получить(ЭлементСписка.Значение))); - КонецЕсли; - КонецЦикла; - - ОпорныеПоля.Удалить("Список"); - ОпорныеПоля.Удалить("ТипыПоИменамПолей"); - ОпорныеПоля.Удалить("ПоСвойствамПолей"); - ОпорныеПоля.Удалить("ПоДополнительнымТаблицам"); - -КонецПроцедуры - -// Для функций ТекстУсловияСоединения, СвойстваПоля. -Функция ИмяПоляСРазверткойОпорногоПоляПоТипам(Псевдоним, УзелПоле) - - Если Не УзелПоле.Свойство("ОсновнойПорядок") - Или Не УзелПоле.Свойство("ТаблицыСледующегоПоля") Тогда - - Возврат Псевдоним + "." + УзелПоле.Имя; - КонецЕсли; - - КоличествоТаблиц = УзелПоле.ТаблицыСледующегоПоля[0].Количество(); - - Если КоличествоТаблиц >= 70 Тогда // Ограничение платформы. - Возврат Псевдоним + "." + УзелПоле.Имя; - КонецЕсли; - - Позиция = СтрНайти(УзелПоле.Имя, "."); - ОпорноеПоле = Псевдоним + "." + Лев(УзелПоле.Имя, Позиция - 1); - ОстальныеПоля = Сред(УзелПоле.Имя, Позиция + 1); - - ИмяПоля = ""; - Для Каждого ИмяТипа Из УзелПоле.ТаблицыСледующегоПоля[0] Цикл - ТекущееИмяПоля = СтрШаблон("ВЫРАЗИТЬ(%1 КАК %2).%3", ОпорноеПоле, ИмяТипа, ОстальныеПоля); // @query-part-1 - Если ЗначениеЗаполнено(ИмяПоля) Тогда - ИмяПоля = - "ЕСТЬNULL(" + ТекущееИмяПоля + ", - | " + ТекстСОтступом(ИмяПоля, " ") + ")"; // @query-part-1 - Иначе - ИмяПоля = ТекущееИмяПоля; - КонецЕсли; - КонецЦикла; - - Возврат ИмяПоля; - -КонецФункции - -// Для функции ПараметрыОграниченияДоступа. -Процедура ЗаполнитьСвойстваПолей(Контекст) - - // 1. Для полей-аргументов узлов сравнения =, <>, В, ЕстьNull - // вычисляется результат сравнения и сохраняется в ключе. - - // 2. Для значений типа Булево сохраняются значения: - // - Перечисления.ДополнительныеЗначенияДоступа.ЗначениеИстина, - // - Перечисления.ДополнительныеЗначенияДоступа.ЗначениеЛожь. - - // 3. Для значений типов Число, Дата, Строка сохраняется результат - // сравнения со значением Истина, как указано в пункте 2. - - Контекст.ОпорныеПоля.Вставить("Список", Новый СписокЗначений); - Контекст.ОпорныеПоля.Вставить("ТипыПоИменамПолей", Новый Соответствие); - Контекст.ОпорныеПоля.Вставить("ПоСвойствамПолей", Новый Соответствие); - Контекст.ПоляТаблицОбъекта.Вставить("ПоСвойствамПолей", Новый Соответствие); - - СвойстваВсехПолей = Новый Соответствие; - ПоляКлючаДоступаДоУпрощения = Контекст.СтруктураОграничения.ВнутренниеДанные.ПоляКлючаДоступа; - Для Каждого ОписаниеПоля Из ПоляКлючаДоступаДоУпрощения Цикл - СвойстваПоля = СвойстваПоля(ОписаниеПоля.Поле, Контекст); - СвойстваВсехПолей.Вставить(ОписаниеПоля.Поле, СвойстваПоля); - КонецЦикла; - Контекст.Вставить("СвойстваВсехПолей", СвойстваВсехПолей); - - Контекст.Вставить("ОставшиесяПоляПослеУпрощения", Новый Соответствие); - Контекст.Вставить("ИсходнаяСтруктураОграничения", Контекст.СтруктураОграничения); - Контекст.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступна", Ложь); - - СтруктураОграничения = Новый Структура(Новый ФиксированнаяСтруктура(Контекст.СтруктураОграничения)); // см. СтруктураОграничения - Контекст.Вставить("ИмяПрава", "Чтение"); - СтруктураОграничения.ОграничениеЧтения = УпрощенноеУсловиеОграничения( - СтруктураОграничения.ОграничениеЧтения, Контекст, Истина); - Контекст.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения", - Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна); - Контекст.Вставить("ИмяПрава", "Изменение"); - СтруктураОграничения.ОграничениеИзменения = УпрощенноеУсловиеОграничения( - СтруктураОграничения.ОграничениеИзменения, Контекст, Истина); - Контекст.Вставить("СтруктураОграничения", СтруктураОграничения); - - Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения Тогда - ДобавитьВидОграниченияПрав("ФункцияПравоДоступаИлиРольДоступна", - Новый Структура("Чтение, Изменение", Истина, Ложь), Контекст); - КонецЕсли; - Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна Тогда - ДобавитьВидОграниченияПрав("ФункцияПравоДоступаИлиРольДоступна", - Новый Структура("Чтение, Изменение", Ложь, Истина), Контекст); - КонецЕсли; - - ПоляКлючаДоступаПослеУпрощения = Новый Массив; // Массив Из см. НовоеПолеКлючаДоступа - Для Каждого ОписаниеПоля Из ПоляКлючаДоступаДоУпрощения Цикл - РодителиПоля = Контекст.ОставшиесяПоляПослеУпрощения.Получить(ОписаниеПоля.Поле); // Массив из см. ОписаниеУзла - Если РодителиПоля = Неопределено Тогда - Продолжить; - КонецЕсли; - РодителиПоля.Добавить(Новый Структура("Узел", "")); - ОписаниеПоля.Вставить("Родители", РодителиПоля); - ПоляКлючаДоступаПослеУпрощения.Добавить(ОписаниеПоля); - КонецЦикла; - Контекст.Вставить("ПоляКлючаДоступаПослеУпрощения", ПоляКлючаДоступаПослеУпрощения); - - Контекст.Вставить("СвойстваПолейКлючаДоступа", Новый Соответствие); - Контекст.Вставить("ОбратныйТипПользователя", ?(Контекст.ДляВнешнихПользователей, - Тип("СправочникСсылка.Пользователи"), Тип("СправочникСсылка.ВнешниеПользователи"))); - Контекст.Вставить("ОбратныйТипГруппыПользователей", ?(Контекст.ДляВнешнихПользователей, - Тип("СправочникСсылка.ГруппыПользователей"), Тип("СправочникСсылка.ГруппыВнешнихПользователей"))); - ДобавленныеПоля = Новый Соответствие; - ИменаПолейДляЗапроса = Новый Массив; - Для Каждого ОписаниеПоля Из ПоляКлючаДоступаПослеУпрощения Цикл - СвойстваПоля = СвойстваВсехПолей.Получить(ОписаниеПоля.Поле); // см. СвойстваПоля - СвойстваПоля.Вставить("Чтение", ОписаниеПоля.Чтение); - СвойстваПоля.Вставить("Изменение", ОписаниеПоля.Изменение); - УточнитьСвойстваПоляСравнения(СвойстваПоля, ОписаниеПоля, Контекст); - НаборПолей = НаборПолейУсловияКогда(СвойстваПоля, ОписаниеПоля, Контекст); - Для Каждого СвойстваПоля Из НаборПолей Цикл - ДобавитьСвойстваТиповПоля(СвойстваПоля, ОписаниеПоля, Контекст); - ОдинаковыеПоля = ДобавленныеПоля.Получить(ВРег(СвойстваПоля.ИмяПоляДляЗапроса)); - Если ОдинаковыеПоля = Неопределено Тогда - ОдинаковыеПоля = Новый Массив; - ДобавленныеПоля.Вставить(ВРег(СвойстваПоля.ИмяПоляДляЗапроса), ОдинаковыеПоля); - ИменаПолейДляЗапроса.Добавить(СвойстваПоля.ИмяПоляДляЗапроса); - КонецЕсли; - ОдинаковыеПоля.Добавить(СвойстваПоля); - КонецЦикла; - КонецЦикла; - - СвойстваПолей = Новый Массив; // Массив из см. СвойстваПоля - СовмещенныеПоля = Новый Соответствие; - Для Каждого ИмяПоляДляЗапроса Из ИменаПолейДляЗапроса Цикл - ОдинаковыеПоля = ДобавленныеПоля.Получить(ВРег(ИмяПоляДляЗапроса)); - ОбработанныеОдинаковыеПоля = Новый Массив; - Для Каждого СвойстваПоля Из ОдинаковыеПоля Цикл - СовмещенноеПоле = ОбработанноеСовмещенноеПоле(ОбработанныеОдинаковыеПоля, СвойстваПоля); - Если СовмещенноеПоле <> Неопределено Тогда - СовмещенныеПоля.Вставить(СвойстваПоля, СовмещенноеПоле); - Продолжить; - КонецЕсли; - ОбработанныеОдинаковыеПоля.Добавить(СвойстваПоля); - КонецЦикла; - Для Каждого СвойстваПоля Из ОбработанныеОдинаковыеПоля Цикл - СвойстваПолей.Добавить(СвойстваПоля); - КонецЦикла; - КонецЦикла; - - Для Каждого Описание Из Контекст.СвойстваПолейКлючаДоступа Цикл - СовмещенноеПоле = СовмещенныеПоля.Получить(Описание.Значение); - Если СовмещенноеПоле <> Неопределено Тогда - Контекст.СвойстваПолейКлючаДоступа[Описание.Ключ] = СовмещенноеПоле; - КонецЕсли; - КонецЦикла; - - Для Каждого СвойстваПоля Из СвойстваПолей Цикл - СвойстваПоля.Вставить("ТипыСохраненияТиповКонфигурации", Новый Массив); - СвойстваПоля.Вставить("ТипыСохраненияТиповРасширений", Новый Массив); - СвойстваПоля.Вставить("ТипыСохраненияТиповПростых", Новый Массив); - - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипов Цикл - ОбъектМетаданных = Неопределено; - ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип, ОбъектМетаданных); - - Если СтрНайти(ИмяТипа, ".") = 0 Тогда - СвойстваПоля.ТипыСохраненияТиповПростых.Добавить(Тип); - - ИначеЕсли ОбъектМетаданных.РасширениеКонфигурации() = Неопределено Тогда - СвойстваПоля.ТипыСохраненияТиповКонфигурации.Добавить(Тип); - Иначе - СвойстваПоля.ТипыСохраненияТиповРасширений.Добавить(Тип); - КонецЕсли; - КонецЦикла; - КонецЦикла; - - Контекст.Вставить("СвойстваПолей", СвойстваПолей); - -КонецПроцедуры - -// Для процедуры ЗаполнитьСвойстваПолей. -Функция УпрощенноеУсловиеОграничения(Знач Условие, Контекст, КореньУсловия = Ложь, ДобавитьОставшиесяПоля = Истина) - - Если Не ЗначениеЗаполнено(Условие) Тогда - Возврат Условие; - КонецЕсли; - - ОставшиесяПоляПослеУпрощения = Контекст.ОставшиесяПоляПослеУпрощения; - Контекст.ОставшиесяПоляПослеУпрощения = Новый Соответствие; - - Если Условие.Узел = "Поле" Тогда - Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие, Новый Массив); - - ИначеЕсли Условие.Узел = "И" - Или Условие.Узел = "Или" Тогда - - БезусловныйРезультат = ?(Условие.Узел = "И", Ложь, Истина); - ЕстьБезусловныйРезультат = Ложь; - Аргументы = Новый Массив; - ЕстьФункцияПравоДоступаИлиРольДоступна = Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна; - Для Каждого ТекущийАргумент Из Условие.Аргументы Цикл - Аргумент = УпрощенноеУсловиеОграничения(ТекущийАргумент, Контекст); - Если Аргумент.Узел <> "Константа" Тогда - Аргументы.Добавить(Аргумент); - ИначеЕсли Аргумент.Значение = БезусловныйРезультат Тогда - ЕстьБезусловныйРезультат = Истина; - КонецЕсли; - КонецЦикла; - Если ЕстьБезусловныйРезультат Или Аргументы.Количество() = 0 Тогда - Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна = ЕстьФункцияПравоДоступаИлиРольДоступна; - Условие = Новый Структура("Узел, Значение", "Константа", - ?(ЕстьБезусловныйРезультат, БезусловныйРезультат, Истина)); - ИначеЕсли Аргументы.Количество() = 1 Тогда - Условие = Аргументы[0]; - Иначе - Условие = Новый Структура("Узел, Аргументы", Условие.Узел, Аргументы); - КонецЕсли; - - ИначеЕсли Условие.Узел = "Не" Тогда - Аргумент = УпрощенноеУсловиеОграничения(Условие.Аргумент, Контекст); - Если Аргумент.Узел = "Константа" Тогда - Условие = Новый Структура("Узел, Значение", "Константа", - ?(Аргумент.Значение = "Пусто", "Пусто", Не Аргумент.Значение)); - Иначе - Условие = Новый Структура("Узел, Аргумент", Условие.Узел, Аргумент); - КонецЕсли; - - ИначеЕсли Условие.Узел = "ДляВсехСтрок" - Или Условие.Узел = "ДляОднойИзСтрок" - Или Условие.Узел = "ЕстьNull" - Или Условие.Узел = "ТипЗначения" Тогда - - Аргумент = УпрощенноеУсловиеОграничения(Условие.Аргумент, Контекст); - Если Аргумент.Узел = "Константа" Тогда - Условие = Аргумент; - Иначе - Условие = Новый Структура("Узел, Аргумент", Условие.Узел, Аргумент); - КонецЕсли; - - ИначеЕсли Условие.Узел = "=" - Или Условие.Узел = "<>" Тогда - - ПервыйАргумент = УпрощенноеУсловиеОграничения(Условие.ПервыйАргумент, Контекст); - ВторойАргумент = УпрощенноеУсловиеОграничения(Условие.ВторойАргумент, Контекст); - - Если ПервыйАргумент.Узел = "Константа" - И ВторойАргумент.Узел = "Константа" Тогда - - Условие = Новый Структура("Узел, Значение", "Константа", ?(Условие.Узел = "=", - ПервыйАргумент.Значение = ВторойАргумент.Значение, - ПервыйАргумент.Значение <> ВторойАргумент.Значение)); - Иначе - Условие = Новый Структура("Узел, ПервыйАргумент, ВторойАргумент", - Условие.Узел, ПервыйАргумент, ВторойАргумент); - КонецЕсли; - - ИначеЕсли Условие.Узел = "В" Тогда - Условие = Новый Структура("Узел, Искомое, Значения", - Условие.Узел, - УпрощенноеУсловиеОграничения(Условие.Искомое, Контекст), - Условие.Значения); - - ИначеЕсли Условие.Узел = "Выбор" Тогда - ВсеЗначенияВыбораИстина = Истина; - ВсеЗначенияВыбораЛожь = Истина; - ВсеЗначенияВыбораПусто = Истина; - Выбор = Новый Структура("Узел, Выбор, Когда, Иначе", Условие.Узел, Условие.Выбор, Новый Массив); - НовоеУсловиеИначе = Неопределено; - Для Каждого Когда Из Условие.Когда Цикл - Если Условие.Выбор = Неопределено Тогда - УсловиеКогда = УпрощенноеУсловиеОграничения(Когда.Условие, Контекст); - Если УсловиеКогда.Узел = "Константа" Тогда - Если УсловиеКогда.Значение Тогда - НовоеУсловиеИначе = ?(НовоеУсловиеИначе = Неопределено, Когда.Значение, НовоеУсловиеИначе); - КонецЕсли; - ЗначениеКогда = УпрощенноеУсловиеОграничения(Когда.Значение, Контекст, , Ложь); - Продолжить; - КонецЕсли; - Иначе - УсловиеКогда = Когда.Условие; - КонецЕсли; - ЗначениеКогда = УпрощенноеУсловиеОграничения(Когда.Значение, Контекст); - ОбработатьУпрощенноеЗначениеВыбора(ЗначениеКогда, - ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто); - СтруктураКогда = Новый Структура("Условие, Значение", УсловиеКогда, ЗначениеКогда); - Выбор.Когда.Добавить(СтруктураКогда); - КонецЦикла; - УсловиеИначе = ?(НовоеУсловиеИначе = Неопределено, Условие.Иначе, НовоеУсловиеИначе); - Выбор.Иначе = УпрощенноеУсловиеОграничения(УсловиеИначе, Контекст); - ОбработатьУпрощенноеЗначениеВыбора(Выбор.Иначе, - ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто); - Если ВсеЗначенияВыбораИстина Или ВсеЗначенияВыбораЛожь Или ВсеЗначенияВыбораПусто Тогда - Условие = Новый Структура("Узел, Значение", "Константа", - ?(ВсеЗначенияВыбораПусто, "Пусто", ВсеЗначенияВыбораИстина)); - ИначеЕсли Выбор.Когда.Количество() = 0 Тогда - Условие = Выбор.Иначе; - Иначе - Условие = Выбор; - КонецЕсли; - - ИначеЕсли Условие.Узел = "ЗначениеРазрешено" - Или Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда - - СвойстваПоля = Контекст.СвойстваВсехПолей.Получить(Условие.Поле); - Если СвойстваПоля = Неопределено Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При упрощении условия ограничения права %1 - |списка ""%2"" - |свойства поля не определены для узла ""%3"".'"), - Контекст.ИмяПрава, - Контекст.Список, - Условие.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - ТипыКонечногоПоля = СвойстваПоля.ТипКонечногоПоля.Типы(); - - Если Условие.Узел = "ЗначениеРазрешено" Тогда - Результат = РезультатФункцииЗначениеРазрешено(Условие, ТипыКонечногоПоля, Контекст); - Иначе - Результат = РезультатФункцииПравоОбъектаРазрешено(Условие, ТипыКонечногоПоля, Контекст); - КонецЕсли; - - Если Результат <> Неопределено Тогда - Условие = Новый Структура("Узел, Значение", "Константа", Результат); - Иначе - Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие.Поле, Новый Массив); - КонецЕсли; - - ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" - Или Условие.Узел = "ЧтениеСпискаРазрешено" - Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда - - Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие.Поле, Новый Массив); - - ИначеЕсли Условие.Узел = "ПравоДоступа" - Или Условие.Узел = "РольДоступна" Тогда - - Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна = Истина; - - ИначеЕсли Условие.Узел <> "Константа" - И Условие.Узел <> "Значение" - И Условие.Узел <> "Тип" Тогда - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'При упрощении условия ограничения права %1 - |списка ""%2"" - |узел не поддерживается ""%3"".'"), - Контекст.ИмяПрава, - Контекст.Список, - Условие.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - Если Условие.Узел = "Константа" Тогда - Если КореньУсловия И Условие.Значение = "Пусто" Тогда - Условие.Значение = Истина; - КонецЕсли; - ИначеЕсли ДобавитьОставшиесяПоля Тогда - Для Каждого КлючИЗначение Из Контекст.ОставшиесяПоляПослеУпрощения Цикл - Если Условие.Узел <> "Поле" Тогда - РодителиПоля = КлючИЗначение.Значение; // Массив Из см. ОписаниеУзла - РодителиПоля.Добавить(Условие); - КонецЕсли; - ОставшиесяПоляПослеУпрощения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); - КонецЦикла; - КонецЕсли; - Контекст.ОставшиесяПоляПослеУпрощения = ОставшиесяПоляПослеУпрощения; - - Возврат Условие; - -КонецФункции - -// Для функции УпрощенноеУсловиеОграничения. -Процедура ОбработатьУпрощенноеЗначениеВыбора(Условие, - ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто) - - Если Условие.Узел <> "Константа" Тогда - ВсеЗначенияВыбораИстина = Ложь; - ВсеЗначенияВыбораЛожь = Ложь; - ВсеЗначенияВыбораПусто = Ложь; - - ИначеЕсли Условие.Значение = "Пусто" Тогда - ВсеЗначенияВыбораИстина = Ложь; - ВсеЗначенияВыбораЛожь = Ложь; - - ИначеЕсли Условие.Значение Тогда - ВсеЗначенияВыбораЛожь = Ложь; - ВсеЗначенияВыбораПусто = Ложь; - Иначе - ВсеЗначенияВыбораИстина = Ложь; - ВсеЗначенияВыбораПусто = Ложь; - КонецЕсли; - -КонецПроцедуры - -// Для функции УпрощенноеУсловиеОграничения. -Функция РезультатФункцииЗначениеРазрешено(Условие, ТипыКонечногоПоля, Контекст) - - СвойстваВидовДоступаПоТипам = Контекст.СвойстваВидовДоступа.ПоТипамГруппИЗначений; - ОтключеноКакЛожь = УточнениеТипа(Условие, "Отключено") = "Ложь"; - - РезультатВсегдаЛожь = Истина; - РезультатВсегдаИстина = Истина; - ЕстьРезультатПусто = Ложь; - - Для Каждого Тип Из ТипыКонечногоПоля Цикл - ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); - - Уточнение = УточнениеТипа(Условие, ИмяТипа); - Если Уточнение = "Истина" Тогда - РезультатВсегдаЛожь = Ложь; - Продолжить; - ИначеЕсли Уточнение = "Ложь" Тогда - РезультатВсегдаИстина = Ложь; - Продолжить; - КонецЕсли; - - Если Не ТипПроверяется(Условие, ИмяТипа) Тогда - РезультатВсегдаИстина = Ложь; - Продолжить; - КонецЕсли; - - СвойстваВидаДоступа = СвойстваВидовДоступаПоТипам.Получить(Тип); - Если СвойстваВидаДоступа = Неопределено Тогда - РезультатВсегдаЛожь = Ложь; - Продолжить; - КонецЕсли; - - Если Не ТипЗначенийДоступаИспользуется(Контекст, СвойстваВидаДоступа.ТипЗначений) Тогда - Если Контекст.НеиспользуемыеТипыЗначенийДоступа.Найти(СвойстваВидаДоступа.ТипЗначений) = Неопределено Тогда - Контекст.НеиспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); - КонецЕсли; - Если ОтключеноКакЛожь Тогда - РезультатВсегдаИстина = Ложь; - ЕстьРезультатПусто = Истина; - Иначе - РезультатВсегдаЛожь = Ложь; - КонецЕсли; - Иначе - РезультатВсегдаИстина = Ложь; - РезультатВсегдаЛожь = Ложь; - КонецЕсли; - КонецЦикла; - - Если РезультатВсегдаИстина Тогда - Возврат Истина; - ИначеЕсли РезультатВсегдаЛожь Тогда - Если ЕстьРезультатПусто Тогда - Возврат "Пусто"; - Иначе - Возврат Ложь; - КонецЕсли; - КонецЕсли; - - Возврат Неопределено; - -КонецФункции - -// Для функции РезультатФункцииЗначениеРазрешено и процедуры ДобавитьСвойстваТиповПоля. -Функция ТипЗначенийДоступаИспользуется(Контекст, ТипЗначений) - - Если Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Неопределено Тогда - ИспользуемыеТипыЗначений = Контекст.ИспользуемыеТипыЗначений.ДляИБ; - Иначе - ИспользуемыеТипыЗначений = Контекст.ИспользуемыеТипыЗначений.ПоТаблицам.Получить(Контекст.Список); - КонецЕсли; - - Если ИспользуемыеТипыЗначений = Неопределено Тогда - Если Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Контекст.Список - Или Не ЗначениеЗаполнено(Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы) Тогда - Возврат Ложь; - КонецЕсли; - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ошибка вызова функции %1 общего модуля %2: - |Для таблицы %3 - |не заполнены используемые типы значений доступа.'"), - "ТипЗначенийДоступаИспользуется", - "УправлениеДоступомСлужебный", - Контекст.Список); - ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); - КонецЕсли; - - Возврат ИспользуемыеТипыЗначений.Получить(ТипЗначений) <> Неопределено; - -КонецФункции - -// Для функции УпрощенноеУсловиеОграничения. -Функция РезультатФункцииПравоОбъектаРазрешено(Условие, ТипыКонечногоПоля, Контекст) - - Если Контекст.ОграничениеДоступаВключено Тогда - Возврат Неопределено; - КонецЕсли; - - РезультатВсегдаИстина = Истина; - - Для Каждого Тип Из ТипыКонечногоПоля Цикл - ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); - - Уточнение = УточнениеТипа(Условие, ИмяТипа); - Если Уточнение = "Истина" Тогда - Продолжить; - ИначеЕсли Уточнение = "Ложь" Тогда - РезультатВсегдаИстина = Ложь; - Прервать; - КонецЕсли; - - Если Не ТипПроверяется(Условие, ИмяТипа) Тогда - РезультатВсегдаИстина = Ложь; - Прервать; - КонецЕсли; - - Значение = Контекст.ТипыВладельцевНастроекПрав.Получить(Тип); - Если Значение = Неопределено - Или ВРег(Контекст.Список) <> ВРег(Значение[0].ВладелецПрав) Тогда - - РезультатВсегдаИстина = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - - Если РезультатВсегдаИстина Тогда - Возврат Истина; - КонецЕсли; - - Возврат Неопределено; - -КонецФункции - -// Для процедуры ЗаполнитьСвойстваПолей. -Функция ОбработанноеСовмещенноеПоле(ОбработанныеОдинаковыеПоля, СвойстваПоля) - - Для Каждого Поле Из ОбработанныеОдинаковыеПоля Цикл - Совместимо = Истина; - Если Поле.ПсевдонимТаблицы = "ТекущийСписок" - И Поле.НесколькоГруппЗначений <> СвойстваПоля.НесколькоГруппЗначений Тогда - Продолжить; - КонецЕсли; - // По пустой ссылке на ключ доступа или значению Null невозможно определить тип значения, - // поэтому сохранение ключа доступа несовместимо с остальными вариантами. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияКлючейДоступа Цикл - Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияГруппЗначений.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Совместимо = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Для Каждого Тип Из Поле.ТипыСохраненияКлючейДоступа Цикл - Если СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияГруппЗначений.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Совместимо = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Если Не Совместимо Тогда - Продолжить; - КонецЕсли; - // По значению Null вместо группы значений невозможно определить тип значения, - // поэтому сохранение группы значений несовместимо с остальными вариантами. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияГруппЗначений Цикл - Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Совместимо = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Для Каждого Тип Из Поле.ТипыСохраненияГруппЗначений Цикл - Если СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Совместимо = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - // Вместо простых типов сохраняется значения ТипРазрешенный или ТипЗапрещенный, - // поэтому сохранение запрещенного простого типа несовместимо с остальными вариантами. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаЗапрещенный Цикл - Если Не ЭтоПростойТип(Тип) Тогда - Продолжить; - КонецЕсли; - Если Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Совместимо = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Для Каждого Тип Из Поле.ТипыСохраненияТипаЗапрещенный Цикл - Если Не ЭтоПростойТип(Тип) Тогда - Продолжить; - КонецЕсли; - Если СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Совместимо = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - Если Не Совместимо Тогда - Продолжить; - КонецЕсли; - // Объединение уточнений специальных значений. - Поле.ЕстьУточнениеNull = - Поле.ЕстьУточнениеNull Или СвойстваПоля.ЕстьУточнениеNull; - Поле.ЕстьУточнениеНеопределено = - Поле.ЕстьУточнениеНеопределено Или СвойстваПоля.ЕстьУточнениеНеопределено; - Поле.ЕстьТипВедущегоСписка = - Поле.ЕстьТипВедущегоСписка Или СвойстваПоля.ЕстьТипВедущегоСписка; - Поле.ЕстьТипВладельцаНастроекПрав = - Поле.ЕстьТипВладельцаНастроекПрав Или СвойстваПоля.ЕстьТипВладельцаНастроекПрав; - Поле.ЕстьПроверкаАвторизованногоПользователя = - Поле.ЕстьПроверкаАвторизованногоПользователя Или СвойстваПоля.ЕстьПроверкаАвторизованногоПользователя; - // Объединение типов сохранения пустой ссылки. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияПустойСсылки Цикл - Если Поле.ТипыСохраненияПустойСсылки.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Поле.ТипыСохраненияПустойСсылки.Добавить(Тип); - КонецЦикла; - // Объединение типов сохранения значения ТипРазрешенный. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаРазрешенный Цикл - Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); - Поле.ТипыСохраненияТипов.Добавить(Тип); - Продолжить; - КонецЕсли; - Поле.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - КонецЦикла; - // Объединение типов сохранения значения ТипЗапрещенный. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаЗапрещенный Цикл - Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); - Поле.ТипыСохраненияТипов.Добавить(Тип); - Продолжить; - КонецЕсли; - Поле.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - КонецЦикла; - // Объединение типов сохранения типа значения. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипов Цикл - Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено - Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); - КонецЕсли; - Поле.ТипыСохраненияТипов.Добавить(Тип); - КонецЦикла; - // Объединение типов сохранения значения. - Для Каждого Тип Из СвойстваПоля.ТипыСохраненияЗначений Цикл - Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипов.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипов.Удалить(Индекс); - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); - КонецЕсли; - Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); - Если Индекс <> Неопределено Тогда - Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); - КонецЕсли; - Поле.ТипыСохраненияЗначений.Добавить(Тип); - КонецЦикла; - // Объединение неиспользуемых типов значений доступа. - Для Каждого Тип Из СвойстваПоля.НеиспользуемыеТипыЗначенийДоступа Цикл - Если Поле.НеиспользуемыеТипыЗначенийДоступа.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Поле.НеиспользуемыеТипыЗначенийДоступа.Добавить(Тип); - КонецЦикла; - // Объединение используемых типов значений доступа. - Для Каждого Тип Из СвойстваПоля.ИспользуемыеТипыЗначенийДоступа Цикл - Если Поле.ИспользуемыеТипыЗначенийДоступа.Найти(Тип) <> Неопределено Тогда - Продолжить; - КонецЕсли; - Поле.ИспользуемыеТипыЗначенийДоступа.Добавить(Тип); - КонецЦикла; - Поле.Чтение = Поле.Чтение Или СвойстваПоля.Чтение; - Если Поле.ТипыСтрокой <> СвойстваПоля.ТипыСтрокой Тогда - Поле.ТипыСтрокой = Поле.ТипыСтрокой + Символы.ПС + СвойстваПоля.ТипыСтрокой; - КонецЕсли; - Возврат Поле; - КонецЦикла; - - Возврат Неопределено; - -КонецФункции - -// Для процедуры ЗаполнитьСвойстваПолей. -Процедура УточнитьСвойстваПоляСравнения(Свойства, ОписаниеПоля, Контекст) - - Контекст.СвойстваПолейКлючаДоступа.Вставить(ОписаниеПоля.Поле, Свойства); - - Родитель = ОписаниеПоля.Родители[0]; - - Узлы = ",ТипЗначения,=,<>,В,ЕстьNull,"; // В ключ сохраняется результат сравнения. - Если СтрНайти(Узлы, "," + Родитель.Узел + ",") = 0 Тогда - Возврат; - КонецЕсли; - - Если Родитель.Узел = "ТипЗначения" Тогда - РодительУзлаСравнения = ОписаниеПоля.Родители[1]; - - Если РодительУзлаСравнения.ВторойАргумент = Родитель Тогда - УзелТип = РодительУзлаСравнения.ПервыйАргумент; // См. ОписаниеУзла - УзелТипЗначения = РодительУзлаСравнения.ВторойАргумент; - Иначе - УзелТип = РодительУзлаСравнения.ВторойАргумент; // См. ОписаниеУзла - УзелТипЗначения = РодительУзлаСравнения.ПервыйАргумент; - КонецЕсли; - Контекст.СвойстваПолейКлючаДоступа.Вставить(УзелТипЗначения, Свойства); - - ВыражениеТипаЗначения = "ТИПЗНАЧЕНИЯ(" + Свойства.ИмяПоляДляЗапроса + ")"; // @query-part-1 - ВыражениеТипа = "ТИП(" + УзелТип.Имя + ")"; // @query-part-1 - ОднойСтрокой = СтрДлина(ВыражениеТипаЗначения) + СтрДлина(ВыражениеТипа) < 60; - - Свойства.ИмяПоляДляЗапроса = ВыражениеТипаЗначения + ?(ОднойСтрокой, " ", " - | ") + РодительУзлаСравнения.Узел + " " + ВыражениеТипа; - - ИначеЕсли Родитель.Узел = "=" - Или Родитель.Узел = "<>" Тогда - - УзелЗначениеИлиКонстанта = ?(Родитель.ВторойАргумент = ОписаниеПоля.Поле, - Родитель.ПервыйАргумент, Родитель.ВторойАргумент); - - ВыражениеУзла = ВыражениеУзлаЗначениеИлиКонстанта(УзелЗначениеИлиКонстанта); - ОднойСтрокой = СтрДлина(Свойства.ИмяПоляДляЗапроса) + СтрДлина(ВыражениеУзла) < 60; - - Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + ?(ОднойСтрокой, " ", " - | ") + Родитель.Узел + " " + ВыражениеУзла; - - ИначеЕсли Родитель.Узел = "В" Тогда - - СписокЗначений = ""; - Для Каждого УзелЗначениеИлиКонстанта Из Родитель.Значения Цикл - СписокЗначений = СписокЗначений + ?(СписокЗначений = "", "", ","); - ПоследняяСтрока = СтрПолучитьСтроку(СписокЗначений, СтрЧислоСтрок(СписокЗначений)); - Если СтрДлина(ПоследняяСтрока) > 40 Тогда - СписокЗначений = СписокЗначений + " - | "; - Иначе - СписокЗначений = СписокЗначений + " "; - КонецЕсли; - СписокЗначений = СписокЗначений - + ВыражениеУзлаЗначениеИлиКонстанта(УзелЗначениеИлиКонстанта); - КонецЦикла; - Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " - | В (" + СписокЗначений + ")"; - - Иначе // Родитель.Узел = "ЕстьNull". - Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " ЕСТЬ NULL"; - Свойства.Вставить("ПроверкаЕстьNull"); - КонецЕсли; - - Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); - -КонецПроцедуры - -// Для процедуры ЗаполнитьСвойстваПолей. -Функция НаборПолейУсловияКогда(ИсходныеСвойстваПоля, ОписаниеПоля, Контекст) - - Родитель = ОписаниеПоля.Родители[0]; - НаборПолей = Новый Массив; - - Если Родитель.Узел <> "Выбор" - Или Родитель.Выбор = Неопределено Тогда - - НаборПолей.Добавить(ИсходныеСвойстваПоля); - Возврат НаборПолей; - КонецЕсли; - - // Для "ВЫБОР <Поле> КОГДА <Значение>" в ключ сохраняется - // результат сравнения "<Поле> = <Значение>". - - Для Каждого ОписаниеКогда Из Родитель.Когда Цикл - ФиксированныеСвойства = Новый ФиксированнаяСтруктура(ИсходныеСвойстваПоля); - Свойства = Новый Структура(ФиксированныеСвойства); - - ВыражениеУзла = ВыражениеУзлаЗначениеИлиКонстанта(ОписаниеКогда.Условие); - ОднойСтрокой = СтрДлина(Свойства.ИмяПоляДляЗапроса) + СтрДлина(ВыражениеУзла) < 60; - - Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + ?(ОднойСтрокой, " = ", " - | = ") + ВыражениеУзла; - - Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); - НаборПолей.Добавить(Свойства); - - Контекст.СвойстваПолейКлючаДоступа.Вставить(ОписаниеКогда.Условие, Свойства); - КонецЦикла; - - Возврат НаборПолей; - -КонецФункции - -// Для функций СвойстваПоля, УточнитьСвойстваПоляСравнения, НаборПолейУсловияКогда. -Функция БезЗначенияNull(СвойстваПоля) - - Возврат СтрЧислоВхождений(СвойстваПоля.ИмяПоляДляЗапроса, ".") = 1 - И Не СвойстваПоля.Свойство("ПолеСодержитNull") - И СтрНачинаетсяС(СвойстваПоля.ИмяПоляДляЗапроса, "ТекущийСписок."); - -КонецФункции - -// Для процедуры ЗаполнитьСвойстваПолей. -// -// Параметры: -// Свойства - см. СвойстваПоля -// ОписаниеПоля - см. НовоеПолеКлючаДоступа -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// -Процедура ДобавитьСвойстваТиповПоля(Свойства, ОписаниеПоля, Контекст) - - Свойства.Вставить("ТипыСохраненияКлючейДоступа", Новый Массив); - Свойства.Вставить("ТипыСохраненияГруппЗначений", Новый Массив); - Свойства.Вставить("ТипыСохраненияЗначений", Новый Массив); - Свойства.Вставить("ТипыСохраненияПустойСсылки", Новый Массив); - Свойства.Вставить("ТипыСохраненияТипов", Новый Массив); - Свойства.Вставить("ТипыСохраненияТипаЗапрещенный", Новый Массив); - Свойства.Вставить("ТипыСохраненияТипаРазрешенный", Новый Массив); - Свойства.Вставить("НеиспользуемыеТипыЗначенийДоступа", Новый Массив); - Свойства.Вставить("ИспользуемыеТипыЗначенийДоступа", Новый Массив); - Свойства.Вставить("НесколькоГруппЗначений", Ложь); - Свойства.Вставить("ЭтоСписокЗначенийДоступаСГруппамиЗначений", Ложь); - Свойства.Вставить("ЕстьУточнениеNull", Ложь); - Свойства.Вставить("ЕстьУточнениеНеопределено", Ложь); - Свойства.Вставить("ЕстьТипВедущегоСписка", Ложь); - Свойства.Вставить("ЕстьТипВладельцаНастроекПрав", Ложь); - Свойства.Вставить("ЕстьПроверкаАвторизованногоПользователя", Ложь); - - Родитель = ОписаниеПоля.Родители[0]; - - Если Родитель.Узел = "ЧтениеОбъектаРазрешено" - Или Родитель.Узел = "ИзменениеОбъектаРазрешено" - Или Родитель.Узел = "ЧтениеСпискаРазрешено" - Или Родитель.Узел = "ИзменениеСпискаРазрешено" - Или Родитель.Узел = "ЗначениеРазрешено" - Или Родитель.Узел = "ЭтоАвторизованныйПользователь" Тогда - - ЕстьУточнениеПустойСсылки = ТипУточнен(Родитель, "ПустаяСсылка"); - Свойства.ЕстьУточнениеNull = ТипУточнен(Родитель, "Null") Или Свойства.Свойство("ЕстьВыразить"); - Свойства.ЕстьУточнениеНеопределено = ТипУточнен(Родитель, "Неопределено"); - КонецЕсли; - - Если Родитель.Узел = "ЧтениеОбъектаРазрешено" - Или Родитель.Узел = "ИзменениеОбъектаРазрешено" - Или Родитель.Узел = "ЧтениеСпискаРазрешено" - Или Родитель.Узел = "ИзменениеСпискаРазрешено" Тогда - - Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл - ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); - - Уточнение = УточнениеТипа(Родитель, ИмяТипа); - Если Уточнение = "Истина" Тогда - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - Продолжить; - ИначеЕсли Уточнение = "Ложь" Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если ЭтоПростойТип(Тип) Тогда - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") - Или Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда - - Свойства.ТипыСохраненияЗначений.Добавить(Тип); - Свойства.ЕстьТипВедущегоСписка = Истина; - - ВидОграничения = ?(Родитель.Узел = "ЧтениеСпискаРазрешено" - Или Родитель.Узел = "ЧтениеОбъектаРазрешено", "ПравоЧтения", "ПравоИзменения"); - ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); - Продолжить; - КонецЕсли; - - Если Родитель.Узел = "ЧтениеСпискаРазрешено" - Или Родитель.Узел = "ИзменениеСпискаРазрешено" Тогда - - Свойства.ТипыСохраненияТипов.Добавить(Тип); - Свойства.ЕстьТипВедущегоСписка = Истина; - - ВидОграничения = ?(Родитель.Узел = "ЧтениеСпискаРазрешено", "ПравоЧтения", "ПравоИзменения"); - ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); - Продолжить; - КонецЕсли; - - Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено - И Не Контекст.ИспользуетсяОграничениеПоВладельцу - И ( Контекст.СпискиСОграничением.Получить(ИмяТипа) = Неопределено - Или Контекст.СпискиСОтключеннымОграничением.Получить(ИмяТипа) <> Неопределено) Тогда - - Свойства.ТипыСохраненияТипов.Добавить(Тип); - Свойства.ЕстьТипВедущегоСписка = Истина; - - ВидОграничения = ?(Родитель.Узел = "ЧтениеОбъектаРазрешено", "ПравоЧтения", "ПравоИзменения"); - ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); - Продолжить; - КонецЕсли; - - Если ЕстьУточнениеПустойСсылки Тогда - Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); - КонецЕсли; - - ИмяВедущегоПрава = ?(Родитель.Узел = "ЧтениеОбъектаРазрешено", "Чтение", "Изменение"); - - Значение = Контекст.ТипыВладельцевНастроекПрав.Получить(Тип); - Если Значение <> Неопределено - И (ВРег(Контекст.Список) = ВРег(Значение[0].ВладелецПрав) - Или Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено - И Не Контекст.ИспользуетсяОграничениеПоВладельцу) Тогда - - Свойства.ТипыСохраненияЗначений.Добавить(Тип); - Свойства.ЕстьТипВладельцаНастроекПрав = Истина; - ВидОграничения = "НастройкиПрав." + ИмяТипа + "." + ИмяВедущегоПрава; - ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); - Продолжить; - КонецЕсли; - - Свойства.ТипыСохраненияКлючейДоступа.Добавить(Тип); - Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Неопределено - Или ( Контекст.СпискиСОграничением.Получить(ИмяТипа) <> Неопределено - И Контекст.СпискиСОтключеннымОграничением.Получить(ИмяТипа) = Неопределено) Тогда - - ДобавитьВедущийСписокПоПолюСсылка(Контекст.ВедущиеСпискиПоКлючамДоступа, - ИмяТипа, ОписаниеПоля, Свойства, Контекст); - - ВидОграничения = "Объект." + ИмяТипа + "." + ИмяВедущегоПрава; - ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); - КонецЕсли; - КонецЦикла; - - Возврат; - КонецЕсли; - - Если Родитель.Узел = "ЗначениеРазрешено" Тогда - СвойстваВидовДоступа = Контекст.СвойстваВидовДоступа; - ОтключеноКакЛожь = УточнениеТипа(Родитель, "Отключено") = "Ложь"; - - Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл - ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); - - Уточнение = УточнениеТипа(Родитель, ИмяТипа); - Если Уточнение = "Истина" Тогда - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - Продолжить; - ИначеЕсли Уточнение = "Ложь" Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - СвойстваВидаДоступа = СвойстваВидовДоступа.ПоТипамГруппИЗначений.Получить(Тип); // См. СвойстваВидаДоступа - Если СвойстваВидаДоступа = Неопределено Тогда - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если Тип = Контекст.ОбратныйТипПользователя - Или Тип = Контекст.ОбратныйТипГруппыПользователей Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - ДобавитьВидОграниченияПрав(СвойстваВидаДоступа.Имя, Свойства, Контекст); - - Если Не ТипЗначенийДоступаИспользуется(Контекст, СвойстваВидаДоступа.ТипЗначений) Тогда - Свойства.НеиспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); - - Если ОтключеноКакЛожь Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Иначе - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - КонецЕсли; - Продолжить; - КонецЕсли; - - Свойства.ИспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); - - Если СвойстваВидовДоступа.ПоТипамЗначений.Получить(Тип) = Неопределено Тогда - // Тип группы значений доступа. - Если Контекст.Список = Метаданные.НайтиПоТипу(Тип).ПолноеИмя() - Или Контекст.ТипыПользователя.Найти(Тип) <> Неопределено Тогда - - Свойства.ТипыСохраненияЗначений.Добавить(Тип); - Иначе - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - КонецЕсли; - Продолжить; - КонецЕсли; - - Если ЕстьУточнениеПустойСсылки Тогда - Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); - КонецЕсли; - - Если СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами.Получить(Тип) = Неопределено - Или Контекст.ТипыПользователя.Найти(Тип) <> Неопределено Тогда - - Свойства.ТипыСохраненияЗначений.Добавить(Тип); - Продолжить; - КонецЕсли; - Свойства.ТипыСохраненияГруппЗначений.Добавить(Тип); - - Если Контекст.Список = ИмяТипа - И ВРег(Свойства.ИмяПоляДляЗапроса) = ВРег("ТекущийСписок.Ссылка") Тогда // @query-part-1 - - Свойства.ЭтоСписокЗначенийДоступаСГруппамиЗначений = Истина; - Иначе - ДобавитьВедущийСписокПоПолюСсылка(Контекст.ВедущиеСпискиПоЗначениямСГруппами, - ИмяТипа, ОписаниеПоля, Свойства, Контекст); - КонецЕсли; - - Если Не СвойстваВидаДоступа.НесколькоГруппЗначений Тогда - Продолжить; - КонецЕсли; - Свойства.НесколькоГруппЗначений = Истина; - КонецЦикла; - - Возврат; - КонецЕсли; - - Если Родитель.Узел = "ЭтоАвторизованныйПользователь" Тогда - Свойства.ЕстьПроверкаАвторизованногоПользователя = Истина; - ДобавитьВидОграниченияПрав("ФункцияЭтоАвторизованныйПользователь", Свойства, Контекст); - - Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл - ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); - - Уточнение = УточнениеТипа(Родитель, ИмяТипа); - Если Уточнение = "Истина" Тогда - Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); - Продолжить; - ИначеЕсли Уточнение = "Ложь" Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если Тип <> Тип("СправочникСсылка.Пользователи") - И Тип <> Тип("СправочникСсылка.ВнешниеПользователи") Тогда - - Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); - Продолжить; - КонецЕсли; - - Если ЕстьУточнениеПустойСсылки Тогда - Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); - КонецЕсли; - - Свойства.ТипыСохраненияЗначений.Добавить(Тип); - КонецЦикла; - - Возврат; - КонецЕсли; - - // Остались только узлы Поле для получения значения Булево. - Свойства.ТипыСохраненияЗначений.Добавить(Тип("Булево")); - - Если Свойства.ТипКонечногоПоля.Типы().Количество() = 1 - И Свойства.ТипКонечногоПоля.СодержитТип(Тип("Булево")) Тогда - Возврат; - КонецЕсли; - Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); - Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " = ИСТИНА"; // @query-part-1 - -КонецПроцедуры - -// Для функций СвойстваПоля, ДобавитьСвойстваТиповПоля. -Функция ИмяТипаНаЯзыкеЗапросов(Тип, ОбъектМетаданных = Неопределено) - - ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); - Если ОбъектМетаданных <> Неопределено Тогда - Возврат ОбъектМетаданных.ПолноеИмя(); - КонецЕсли; - - Возврат Строка(Тип); - -КонецФункции - -// Для процедуры ДобавитьСвойстваТиповПоля. -Процедура ДобавитьВидОграниченияПрав(ВидОграничения, СвойстваПоля, Контекст, ПоОбъекту = Ложь) - - Если СвойстваПоля.Чтение Тогда - Контекст.ВсеВидыОграниченийПрав.Вставить("Чтение." + ВидОграничения, Истина); - КонецЕсли; - Если Не ПоОбъекту Или СвойстваПоля.Изменение Тогда - Контекст.ВсеВидыОграниченийПрав.Вставить("Изменение." + ВидОграничения, Истина); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьСвойстваПолей. -// -// Параметры: -// УзелПоле - см. ОписаниеУзла -// Контекст - см. КонтекстПараметровПоСтруктуреОграничения -// СвойстваПоля - см. СвойстваПоля -// -// Возвращаемое значение: -// Структура: -// * ПсевдонимТаблицы - Строка -// * ИмяПоляДляЗапроса - Строка -// * ТабличнаяЧасть - Строка -// * ЭтоПолеСписка - Булево -// * БезЗначенияNull - Булево -// * ПолеСодержитNull - Неопределено -// * ЕстьВыразить - Неопределено -// * УзелПоле - см. ОписаниеУзла -// * СвойстваВложения - см. СвойстваПоля -// * Чтение - Булево -// * ПроверкаЕстьNull - Неопределено -// * ТипыСохраненияКлючейДоступа - Массив из Тип -// * ТипыСохраненияГруппЗначений - Массив из Тип -// * ТипыСохраненияЗначений - Массив из Тип -// * ТипыСохраненияПустойСсылки - Массив из Тип -// * ТипыСохраненияТипов - Массив из Тип -// * ТипыСохраненияТипаЗапрещенный - Массив из Тип -// * ТипыСохраненияТипаРазрешенный - Массив из Тип -// * НеиспользуемыеТипыЗначенийДоступа - Массив из Тип -// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип -// * НесколькоГруппЗначений - Булево -// * ЭтоСписокЗначенийДоступаСГруппамиЗначений - Булево -// * ЕстьУточнениеNull - Булево -// * ЕстьУточнениеНеопределено - Булево -// * ЕстьТипВедущегоСписка - Булево -// * ЕстьТипВладельцаНастроекПрав - Булево -// * ЕстьПроверкаАвторизованногоПользователя - Булево -// * ТипыСохраненияТиповКонфигурации - Массив из Тип -// * ТипыСохраненияТиповРасширений - Массив из Тип -// * ТипыСохраненияТиповПростых - Массив из Тип -// * ИмяГруппыПолейКлючаДоступа - Строка -// * ИмяРеквизитаГруппыПолейКлючаДоступа - Строка -// -Функция СвойстваПоля(УзелПоле, Контекст, СвойстваПоля = Неопределено) - - Свойства = Новый Структура; - ЭтоКорневойУзел = СвойстваПоля = Неопределено; - - Если ЭтоКорневойУзел Тогда - СвойстваПоля = Свойства; - // Внутри функции ЕстьNull() может быть только поле, т.е. функции Выразить() не может быть. - Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда - Типы = Новый Массив; - Типы.Добавить(ТипСсылкиПоПолномуИмениМетаданных(УзелПоле.Выразить)); - ТипКонечногоПоля = Новый ОписаниеТипов(Типы); - Иначе - ТипКонечногоПоля = УзелПоле.ТипыПоля[УзелПоле.ТипыПоля.Количество() - 1]; - Если ЗначениеЗаполнено(УзелПоле.ЕстьNull) Тогда - Типы = Новый Массив; - Типы.Добавить(ТипЗначенияУзлаЗначениеИлиКонстанта(УзелПоле.ЕстьNull)); - ТипКонечногоПоля = Новый ОписаниеТипов(ТипКонечногоПоля, Типы); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если УзелПоле.Вложение <> Неопределено Тогда - СвойстваВложения = СвойстваПоля(УзелПоле.Вложение, Контекст, СвойстваПоля); - ТабличнаяЧасть = СвойстваВложения.ТабличнаяЧасть; - ПсевдонимТаблицы = СвойстваВложения.ПсевдонимТаблицы; - ИмяПоляДляЗапроса = СвойстваВложения.ИмяПоляДляЗапроса + "." + УзелПоле.Имя; - ТипыСтрокой = СвойстваВложения.ТипыСтрокой + Символы.ПС + УзелПоле.ТипыСтрокой; - Иначе - Если ТипЗнч(УзелПоле.ТипыПоля[0]) = Тип("ОписаниеТипов") Тогда - ТабличнаяЧасть = ""; - Если ЗначениеЗаполнено(УзелПоле.Псевдоним) - И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда - - ПсевдонимТаблицы = УзелПоле.Псевдоним; - ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + УзелПоле.Имя; - Иначе - ПсевдонимТаблицы = "ТекущийСписок"; - ДобавитьОпорноеПоле(Контекст, УзелПоле, СвойстваПоля); - Если Не ЗначениеЗаполнено(УзелПоле.Выразить) Тогда - ИмяПоляДляЗапроса = ТекстСОтступом( - ИмяПоляСРазверткойОпорногоПоляПоТипам(ПсевдонимТаблицы, УзелПоле), " "); - Иначе - ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + УзелПоле.Имя; - КонецЕсли; - КонецЕсли; - Иначе // Первая часть имени поля - это имя табличной части. - ТабличнаяЧасть = УзелПоле.ТипыПоля[0]; - ПсевдонимТаблицы = "ТекущийСписок" + ТабличнаяЧасть; - ЧастиИмени = СтрРазделить(УзелПоле.Имя, "."); - ЧастиИмени.Удалить(0); - ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + СтрСоединить(ЧастиИмени, "."); - КонецЕсли; - ДобавитьПолеТаблицыОбъекта(Контекст, УзелПоле, СвойстваПоля,, ТабличнаяЧасть); - ТипыСтрокой = УзелПоле.ТипыСтрокой; - КонецЕсли; - - // Внутри функции ЕстьNull() может быть только поле, т.е. функции Выразить() не может быть. - Если ЗначениеЗаполнено(УзелПоле.ЕстьNull) Тогда - ИмяПоляДляЗапроса = "ЕСТЬNULL(" + ИмяПоляДляЗапроса + ", " - + ВыражениеУзлаЗначениеИлиКонстанта(УзелПоле.ЕстьNull) + ")"; // @query-part-1 - - Если ЭтоКорневойУзел Тогда - Свойства.Вставить("БезЗначенияNull", Истина); - КонецЕсли; - КонецЕсли; - - Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда - ИмяПоляДляЗапроса = "ВЫРАЗИТЬ(" + ИмяПоляДляЗапроса + " КАК " + УзелПоле.Выразить + ")"; // @query-part-1, @query-part-2 - СвойстваПоля.Вставить("ЕстьВыразить"); - КонецЕсли; - - Свойства.Вставить("ПсевдонимТаблицы", ПсевдонимТаблицы); - Свойства.Вставить("ИмяПоляДляЗапроса", ИмяПоляДляЗапроса); - Свойства.Вставить("ТипКонечногоПоля", ТипКонечногоПоля); - Свойства.Вставить("ТипыСтрокой", ТипыСтрокой); - - Если УзелПоле.Свойство("ПолеСодержитNull") Тогда - Свойства.Вставить("ПолеСодержитNull"); - КонецЕсли; - - // Для расчета ведущих списков. - Свойства.Вставить("ТабличнаяЧасть", ТабличнаяЧасть); - Свойства.Вставить("СвойстваВложения", СвойстваВложения); - Свойства.Вставить("УзелПоле", УзелПоле); - Свойства.Вставить("ЭтоПолеСписка", - ПсевдонимТаблицы = "ТекущийСписок" - Или СвойстваВложения <> Неопределено - И ЗначениеЗаполнено(СвойстваВложения.ТабличнаяЧасть)); - - Возврат Свойства; - -КонецФункции - - -// Для функции ПараметрыОграниченияПоСтруктуреОграничения. -// -// Возвращаемое значение: -// Структура: -// * Поля - Соответствие -// * СоединенияОтборов - Соответствие -// -Функция ОписаниеВедущихСписковПоЗначениямПолей() - - Возврат Новый Структура("Поля, СоединенияОтборов", Новый Соответствие, Новый Соответствие); - -КонецФункции - -// Для функций ГруппыДополнительныхТаблиц. -Процедура ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, УзелПоле, СвойстваВложения = Неопределено, - ГруппаТаблиц = Неопределено, ПсевдонимТаблицыУсловия = Неопределено) - - ДополнительныйКонтекст = Новый Структура; - ДополнительныйКонтекст.Вставить("СвойстваПоляРодителя", СвойстваВложения); - ДополнительныйКонтекст.Вставить("ГруппаТаблиц", ГруппаТаблиц); - ДополнительныйКонтекст.Вставить("ПсевдонимТаблицыУсловия", ПсевдонимТаблицыУсловия); - ДополнительныйКонтекст.Вставить("ПсевдонимТаблицыПоля", УзелПоле.Псевдоним); - - ИменаПолей = СтрРазделить(УзелПоле.Имя, "."); - - Если УзелПоле.Вложение <> Неопределено Тогда - ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, УзелПоле.Таблица, ИменаПолей[0], - УзелПоле.ТипыПоля[0], ДополнительныйКонтекст, Истина, Истина); - - ИначеЕсли ЗначениеЗаполнено(УзелПоле.Псевдоним) - И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда - - ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, УзелПоле.Таблица, ИменаПолей[0], - УзелПоле.ТипыПоля[0], ДополнительныйКонтекст); - КонецЕсли; - - ИндексПервогоПоля = ?(ТипЗнч(УзелПоле.ТипыПоля[0]) = Тип("ОписаниеТипов"), 0, 1); - - Если ИндексПервогоПоля + 2 > ИменаПолей.Количество() Тогда - Возврат; - КонецЕсли; - - СвойстваПоляРодителя = Новый Структура("ИмяПоляДляЗапроса, ТабличнаяЧасть"); - Если СвойстваВложения <> Неопределено Тогда - ЗаполнитьЗначенияСвойств(СвойстваПоляРодителя, СвойстваВложения); - СвойстваПоляРодителя.ИмяПоляДляЗапроса = СвойстваПоляРодителя.ИмяПоляДляЗапроса + "." + ИменаПолей[ИндексПервогоПоля]; - Иначе - Если ИндексПервогоПоля > 0 Тогда - СвойстваПоляРодителя.ТабличнаяЧасть = ИменаПолей[0]; - КонецЕсли; - Если Не ЗначениеЗаполнено(УзелПоле.Псевдоним) - Или УзелПоле.Псевдоним = Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда - - ПсевдонимПоляРодителя = "ТекущийСписок"; - ДополнительныйКонтекст.ГруппаТаблиц = Неопределено; - Иначе - ПсевдонимПоляРодителя = УзелПоле.Псевдоним; - КонецЕсли; - СвойстваПоляРодителя.ИмяПоляДляЗапроса = ПсевдонимПоляРодителя + "." + ИменаПолей[ИндексПервогоПоля]; - КонецЕсли; - ДополнительныйКонтекст.СвойстваПоляРодителя = СвойстваПоляРодителя; - - Для Индекс = ИндексПервогоПоля + 1 По ИменаПолей.Количество()-1 Цикл - Поле = ИменаПолей[Индекс]; - ТипПоля = УзелПоле.ТипыПоля[Индекс]; - Для Каждого Таблица Из УзелПоле.ТаблицыСледующегоПоля[Индекс-1] Цикл - ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, Таблица, Поле, - ТипПоля, ДополнительныйКонтекст, Истина, Истина); - КонецЦикла; - СвойстваПоляРодителя.ИмяПоляДляЗапроса = СвойстваПоляРодителя.ИмяПоляДляЗапроса + "." + Поле; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ДобавитьВедущиеСпискиПоЗначениямПолей. -Процедура ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, Таблица, Поле, ТипПоля, ДополнительныйКонтекст, - ЭтоОсновнаяТаблица = Ложь, ЭтоСсылочныйТипТаблицы = Неопределено) - - Если Не ЭтоОсновнаяТаблица - И СтрЧислоВхождений(Таблица, ".") = 2 Тогда - - СоставИмени = СтрРазделить(Таблица, "."); - ТабличнаяЧасть = СоставИмени[2]; - СоставИмени.Удалить(2); - ПолноеИмя = СтрСоединить(СоставИмени, "."); - Иначе - ТабличнаяЧасть = ""; - ПолноеИмя = Таблица; - КонецЕсли; - - Если ТипЗнч(ДополнительныйКонтекст.ГруппаТаблиц) <> Тип("Массив") - И ( ВРег(Поле) = ВРег("Ссылка") - Или ВРег(Поле) = ВРег("Ref")) Тогда // @Non-NLS-2 - - Если ЭтоСсылочныйТипТаблицы = Неопределено Тогда - СоставИмени = СтрРазделить(Таблица, "."); - ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - ЭтоСсылочныйТипТаблицы = ТипТаблицы.ЭтоСсылочныйТип; - КонецЕсли; - Если ЭтоСсылочныйТипТаблицы Тогда - Возврат; - КонецЕсли; - КонецЕсли; - - ОписаниеПолей = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Получить(ПолноеИмя); - ОписаниеСоединений = Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов.Получить(ПолноеИмя); - - Если ОписаниеПолей = Неопределено Тогда - Если ЭтоСсылочныйТипТаблицы = Неопределено Тогда - СоставИмени = СтрРазделить(Таблица, "."); - ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - ЭтоСсылочныйТипТаблицы = ТипТаблицы.ЭтоСсылочныйТип; - КонецЕсли; - ОписаниеПолей = Новый Структура; - ОписаниеПолей.Вставить("ЭтоСсылочныйТип", ЭтоСсылочныйТипТаблицы); - ОписаниеПолей.Вставить("ДляОтслеживания", Новый Структура("ПоляШапки, ТабличныеЧасти", - Новый Соответствие, Новый Соответствие)); - ОписаниеПолей.Вставить("ДляОтбора", Новый Структура("ПоляШапки, ТабличныеЧасти", - Новый Соответствие, Новый Соответствие)); - Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Вставить(ПолноеИмя, ОписаниеПолей); - - ОписаниеСоединений = Новый Структура("ПоляШапки, ТабличныеЧасти", Новый Соответствие, Новый Соответствие); - Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов.Вставить(ПолноеИмя, ОписаниеСоединений); - КонецЕсли; - - ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтслеживания, ТабличнаяЧасть, Поле, ТипПоля); - - Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда - СоединенияОтборов = ОписаниеСоединений.ТабличныеЧасти.Получить(ТабличнаяЧасть); - Если СоединенияОтборов = Неопределено Тогда - СоединенияОтборов = Новый Соответствие; - ОписаниеСоединений.ТабличныеЧасти.Вставить(ТабличнаяЧасть, СоединенияОтборов); - КонецЕсли; - Иначе - СоединенияОтборов = ОписаниеСоединений.ПоляШапки; - КонецЕсли; - - Если ДополнительныйКонтекст.СвойстваПоляРодителя <> Неопределено Тогда - Если СоставИмени = Неопределено Тогда - СоставИмени = СтрРазделить(Таблица, "."); - ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - КонецЕсли; - ТипСсылки = Новый ОписаниеТипов(ТипТаблицы.ЯзыкРусский + "Ссылка." + СоставИмени[1]); // @Non-NLS - ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтслеживания, "", "Ссылка", ТипСсылки); - ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтбора, "", "Ссылка", ТипСсылки); - ИмяПоляДляЗапроса = ДополнительныйКонтекст.СвойстваПоляРодителя.ИмяПоляДляЗапроса; - СоединениеОтбора = СоединенияОтборов.Получить(ВРег(ИмяПоляДляЗапроса)); - Если СоединениеОтбора = Неопределено Тогда - СоединениеОтбора = Новый Структура; - СоединениеОтбора.Вставить("ПолеИлиПсевдоним", ИмяПоляДляЗапроса); - СоединениеОтбора.Вставить("ПоляДляОтбора", "Ссылка"); - СоединениеОтбора.Вставить("ТабличнаяЧасть", ДополнительныйКонтекст.СвойстваПоляРодителя.ТабличнаяЧасть); - СоединениеОтбора.Вставить("ГруппаТаблиц", ДополнительныйКонтекст.ГруппаТаблиц); - СоединенияОтборов.Вставить(ВРег(ИмяПоляДляЗапроса), СоединениеОтбора); - КонецЕсли; - Иначе - Если ТипЗнч(ДополнительныйКонтекст.ГруппаТаблиц) = Тип("Массив") Тогда - СоединениеОтбора = СоединенияОтборов.Получить(ВРег(ДополнительныйКонтекст.ПсевдонимТаблицыПоля)); - Если СоединениеОтбора = Неопределено Тогда - СоединениеОтбора = Новый Структура; - СоединениеОтбора.Вставить("ПолеИлиПсевдоним", ДополнительныйКонтекст.ПсевдонимТаблицыПоля); - СоединениеОтбора.Вставить("ПоляДляОтбора", Новый Массив); - СоединениеОтбора.Вставить("ТабличнаяЧасть", Неопределено); - СоединениеОтбора.Вставить("ГруппаТаблиц", ДополнительныйКонтекст.ГруппаТаблиц); - СоединенияОтборов.Вставить(ВРег(ДополнительныйКонтекст.ПсевдонимТаблицыПоля), СоединениеОтбора); - КонецЕсли; - Если СоединениеОтбора.ПоляДляОтбора.Найти(Поле) = Неопределено - И ДополнительныйКонтекст.ПсевдонимТаблицыПоля = ДополнительныйКонтекст.ПсевдонимТаблицыУсловия Тогда - - СоединениеОтбора.ПоляДляОтбора.Добавить(Поле); - ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтбора, ТабличнаяЧасть, Поле, ТипПоля); - КонецЕсли; - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуру ДобавитьПолеВедущегоСпискаПоЗначениямПолей. -Процедура ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей, ТабличнаяЧасть, Поле, ТипПоля) - - Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда - Поля = ОписаниеПолей.ТабличныеЧасти.Получить(ТабличнаяЧасть); - Если Поля = Неопределено Тогда - Поля = Новый Соответствие; - ОписаниеПолей.ТабличныеЧасти.Вставить(ТабличнаяЧасть, Поля); - КонецЕсли; - Иначе - Поля = ОписаниеПолей.ПоляШапки; - КонецЕсли; - - Если Поля.Получить(Поле) <> Неопределено Тогда - Возврат; - КонецЕсли; - - Поля.Вставить(Поле, Новый ХранилищеЗначения(ТипПоля)); - -КонецПроцедуры - -// Для функции ПараметрыОграниченияПоСтруктуреОграничения. -// -// Возвращаемое значение: -// Структура: -// * Списки - Соответствие -// * КлючиЗапросовПоТипам - Соответствие -// * СоединенияОтборов - Соответствие -// * ТипСсылки - ОписаниеТипов -// -Функция ОписаниеВедущихСписковПоПолюСсылка() - - Описание = Новый Структура; - Описание.Вставить("Списки", Новый Соответствие); - Описание.Вставить("КлючиЗапросовПоТипам", Новый Соответствие); - Описание.Вставить("СоединенияОтборов", Новый Соответствие); - Описание.Вставить("ТипСсылки", Новый ОписаниеТипов); - - Возврат Описание; - -КонецФункции - -// Для процедуры ДобавитьСвойстваТиповПоля. -Процедура ДобавитьВедущийСписокПоПолюСсылка(ВедущиеСписки, ВедущийСписок, УзелПоле, СвойстваПоля, Контекст) - - СоставИмени = СтрРазделить(ВедущийСписок, "."); - ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - ИмяТипаСсылки = ТипТаблицы.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS - - ВедущиеСписки.ТипСсылки = Новый ОписаниеТипов(ВедущиеСписки.ТипСсылки, ИмяТипаСсылки); - ТипСсылки = Тип(ИмяТипаСсылки); - - Ключи = ВедущиеСписки.КлючиЗапросовПоТипам.Получить(ТипСсылки); - Если Ключи = Неопределено Тогда - Ключи = Новый Массив; - ВедущиеСписки.КлючиЗапросовПоТипам.Вставить(ТипСсылки, Ключи); - ВедущиеСписки.Списки.Вставить(ВедущийСписок, Истина); - КонецЕсли; - - Ключ = ВРег(СвойстваПоля.ИмяПоляДляЗапроса); - Если Ключи.Найти(Ключ) = Неопределено Тогда - Ключи.Добавить(Ключ); - КонецЕсли; - - ГруппаТаблиц = ?(СвойстваПоля.ЭтоПолеСписка, Неопределено, СвойстваПоля.ПсевдонимТаблицы); - - СоединениеОтбора = ВедущиеСписки.СоединенияОтборов.Получить(Ключ); - Если СоединениеОтбора = Неопределено Тогда - СоединениеОтбора = Новый Структура; - СоединениеОтбора.Вставить("ПолеИлиПсевдоним", СвойстваПоля.ИмяПоляДляЗапроса); - СоединениеОтбора.Вставить("ПоляДляОтбора", "Ссылка"); // @query-part-2 - СоединениеОтбора.Вставить("ТабличнаяЧасть", СвойстваПоля.ТабличнаяЧасть); - СоединениеОтбора.Вставить("ГруппаТаблиц", ГруппаТаблиц); - ВедущиеСписки.СоединенияОтборов.Вставить(Ключ, СоединениеОтбора); - КонецЕсли; - -КонецПроцедуры - -// Для функции ГруппыДополнительныхТаблиц. -Процедура ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка(ВедущийСписок, Описание, Группы, Контекст) - - СоединенияОтборов = Новый Массив; - Для Каждого СоединениеОтбора Из Описание.ПоляШапки Цикл - СоединенияОтборов.Добавить(ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); - КонецЦикла; - Описание.ПоляШапки = СоединенияОтборов; - - ТабличныеЧасти = Новый Соответствие; - Для Каждого ОписаниеТабличнойЧасти Из Описание.ТабличныеЧасти Цикл - СоединенияОтборов = Новый Массив; - ТабличныеЧасти.Вставить(ОписаниеТабличнойЧасти.Ключ, СоединенияОтборов); - Для Каждого СоединениеОтбора Из ОписаниеТабличнойЧасти.Значение Цикл - СоединенияОтборов.Добавить(ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); - КонецЦикла; - КонецЦикла; - Описание.ТабличныеЧасти = ТабличныеЧасти; - -КонецПроцедуры - -// Для функции ГруппыДополнительныхТаблиц. -Процедура ЗаполнитьОтборыВедущихСписковПоПолюСсылка(ВедущиеСписки, Группы, Контекст) - - СоединенияОтборов = Новый Соответствие; - Для Каждого СоединениеОтбора Из ВедущиеСписки.СоединенияОтборов Цикл - СоединенияОтборов.Вставить(СоединениеОтбора.Ключ, - ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); - КонецЦикла; - ВедущиеСписки.СоединенияОтборов = СоединенияОтборов; - -КонецПроцедуры - -// Для процедуры ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка. -Функция ТекстСоединенияОтбораПоЗначениямПолей(Условие, Группы, Контекст) - - Если Контекст.ЭтоСсылочныйТип Тогда - ДополнительноеУсловие = " - | И (&УточнениеПланаЗапроса)"; // @query-part-1 - Иначе - ДополнительноеУсловие = ?(Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей), " - | И (ТекущийСписок.Регистр = &ИдентификаторРегистра)", "") + " - | И (ТекущийСписок.ВариантДоступа = &ВариантДоступа) - | И (&УточнениеПланаЗапроса)"; // @query-part-1, @query-part-3 - КонецЕсли; - - Если Условие.ГруппаТаблиц = Неопределено Или ЗначениеЗаполнено(Условие.ТабличнаяЧасть) Тогда - ТекстСоединения = - "#ТекущиеДанныеДляОтбора КАК ТекущиеДанныеДляОтбора - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок - | ПО (" + Условие.ПолеИлиПсевдоним + " = ТекущиеДанныеДляОтбора." + Условие.ПоляДляОтбора + ")"; // @query-part-1 - Если ЗначениеЗаполнено(Условие.ТабличнаяЧасть) Тогда - ТекстСоединения = СтрЗаменить(ТекстСоединения, - "&ТекущийСписок", "&ТекущийСписок." + Условие.ТабличнаяЧасть); - ТекстСоединения = СтрЗаменить(ТекстСоединения, - "ТекущийСписок" + Условие.ТабличнаяЧасть + ".", "ТекущийСписок."); - КонецЕсли; - Возврат ТекстСоединения + ДополнительноеУсловие; - КонецЕсли; - - Если ТипЗнч(Условие.ГруппаТаблиц) = Тип("Строка") Тогда - ЭтоПолеУсловияСоединения = Ложь; - ПсевдонимПолейОтбора = Условие.ГруппаТаблиц; - Группа = Группы.НомераПоПсевдонимам.Получить(ПсевдонимПолейОтбора); - ГруппаТаблиц = Группы.ТаблицыПоГруппам.Получить(Группа); - Иначе - ЭтоПолеУсловияСоединения = Истина; - ГруппаТаблиц = Условие.ГруппаТаблиц; - ЗаменяемоеПоле = Условие.ПолеИлиПсевдоним; - ПсевдонимПолейОтбора = СтрРазделить(ЗаменяемоеПоле, ".")[0]; - КонецЕсли; - - Индекс = ГруппаТаблиц.Количество(); - ПерваяДополнительнаяТаблицаНайдена = Ложь; - ОбратнаяГруппаТаблиц = Новый Массив; - ТребуемыеПсевдонимы = Новый Соответствие; - - Пока Индекс >= 1 Цикл - Индекс = Индекс - 1; - ДополнительнаяТаблица = ГруппаТаблиц[Индекс]; - ТекущийПсевдоним = ДополнительнаяТаблица.Псевдоним; - Если Не ПерваяДополнительнаяТаблицаНайдена И ТекущийПсевдоним <> ПсевдонимПолейОтбора Тогда - Продолжить; - КонецЕсли; - ПерваяДополнительнаяТаблицаНайдена = Истина; - Если ТекущийПсевдоним <> ПсевдонимПолейОтбора - И ТребуемыеПсевдонимы.Получить(ДополнительнаяТаблица.Псевдоним) = Неопределено Тогда - Продолжить; - КонецЕсли; - СвойстваТаблицы = Новый Структура("Таблица, Псевдоним, ПоляУсловияСоединения", - ДополнительнаяТаблица.Таблица, ДополнительнаяТаблица.Псевдоним, Новый Массив); - ОбратнаяГруппаТаблиц.Добавить(СвойстваТаблицы); - Для Каждого ПараПолей Из ДополнительнаяТаблица.ПоляУсловияСоединения Цикл - ТребуемыеПсевдонимы.Вставить(ПараПолей.ПервоеПоле.Псевдоним, Истина); - ТребуемыеПсевдонимы.Вставить(ПараПолей.ВтороеПоле.Псевдоним, Истина); - СвойстваТаблицы.ПоляУсловияСоединения.Добавить( - Новый Структура(Новый ФиксированнаяСтруктура(ПараПолей))); - КонецЦикла; - КонецЦикла; - - ВспомогательнаяТаблица = Неопределено; - ПерваяТаблица = ОбратнаяГруппаТаблиц[0]; - ВсеПервыеПоляЗаменяемые = Истина; - - Если ЭтоПолеУсловияСоединения Тогда - Для Каждого ПараПолей Из ПерваяТаблица.ПоляУсловияСоединения Цикл - Если СтрНайти(ПараПолей.ПервоеПоле.Поле, ПерваяТаблица.Псевдоним + ".") > 0 - И СтрНайти(ПараПолей.ПервоеПоле.Поле, ЗаменяемоеПоле + ".") = 0 Тогда - ВсеПервыеПоляЗаменяемые = Ложь; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Если Не ЭтоПолеУсловияСоединения Или Не ВсеПервыеПоляЗаменяемые Тогда - ВспомогательнаяТаблица = Новый Структура("Таблица, Псевдоним, ПоляУсловияСоединения", - ПерваяТаблица.Таблица, "ТекущиеДанныеДляОтбора", Новый Массив); - ОбратнаяГруппаТаблиц.Вставить(0, ВспомогательнаяТаблица); - ПараПолей = Новый Структура("ПервоеПоле, ВтороеПоле"); - ВспомогательнаяТаблица.ПоляУсловияСоединения.Добавить(ПараПолей); - ПараПолей.ПервоеПоле = Новый Структура("Поле, Псевдоним", - Условие.ПолеИлиПсевдоним, "ТекущиеДанныеДляОтбора"); - ПараПолей.ВтороеПоле = Новый Структура("Поле, Псевдоним", - "ТекущиеДанныеДляОтбора." + Условие.ПоляДляОтбора, ПсевдонимПолейОтбора); - КонецЕсли; - - ТекстСоединения = - "#ТекущиеДанныеДляОтбора КАК ТекущиеДанныеДляОтбора"; - ОставшиесяПсевдонимы = Новый Соответствие; - ОставшиесяПсевдонимы.Вставить("ТекущийСписок", Новый Массив); - - Для Каждого ДополнительнаяТаблица Из ОбратнаяГруппаТаблиц Цикл - ОставшиесяПсевдонимы.Вставить(ДополнительнаяТаблица.Псевдоним, - Новый Массив(Новый ФиксированныйМассив(ДополнительнаяТаблица.ПоляУсловияСоединения))); - КонецЦикла; - - ПервыеПсевдонимы = Новый Соответствие; - Индекс = -1; - Для Каждого ДополнительнаяТаблица Из ОбратнаяГруппаТаблиц Цикл - Индекс = Индекс + 1; - - ПервыйПсевдоним = ДополнительнаяТаблица.Псевдоним; - ПоляУсловияСоединения = ОставшиесяПсевдонимы.Получить(ПервыйПсевдоним); - ОставшиесяПсевдонимы.Удалить(ПервыйПсевдоним); - ПервыеПсевдонимы.Вставить(ПервыйПсевдоним, Истина); - - Если Индекс >= ОбратнаяГруппаТаблиц.Количество() - 1 Тогда - ВторойПсевдоним = "ТекущийСписок"; - Иначе - ВторойПсевдоним = ОбратнаяГруппаТаблиц[Индекс + 1].Псевдоним; - КонецЕсли; - ОстальныеПоляУсловияСоединения = ОставшиесяПсевдонимы.Получить(ВторойПсевдоним); - Для Каждого ПараПолей Из ОстальныеПоляУсловияСоединения Цикл - ПоляУсловияСоединения.Добавить(ПараПолей); - КонецЦикла; - ОставшиесяПсевдонимы.Вставить(ВторойПсевдоним, Новый Массив); - - УсловияСоединения = Новый Массив; - Для Каждого ПараПолей Из ПоляУсловияСоединения Цикл - Если Не ЗначениеЗаполнено(ПараПолей.ПервоеПоле.Псевдоним) - И Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) Тогда - - УсловияСоединения.Добавить(ПараПолей.ПервоеПоле.Поле - + " = " + ПараПолей.ВтороеПоле.Поле); - - ИначеЕсли ПервыеПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним) <> Неопределено - И (Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) - Или ПараПолей.ВтороеПоле.Псевдоним = ВторойПсевдоним) - Или ПараПолей.ПервоеПоле.Псевдоним = ВторойПсевдоним - И Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) Тогда - - ПервоеПоле = ПараПолей.ПервоеПоле.Поле; - - Если ПервыеПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним) <> Неопределено - И ПараПолей.ПервоеПоле.Псевдоним = ПсевдонимПолейОтбора - И ВспомогательнаяТаблица = Неопределено - И СтрНачинаетсяС(ПервоеПоле, ЗаменяемоеПоле) Тогда - - КонецПоля = Сред(ПервоеПоле, СтрДлина(ЗаменяемоеПоле) + 1); - ПервоеПоле = "ТекущиеДанныеДляОтбора" - + ?(ЗаменяемоеПоле <> ПсевдонимПолейОтбора, ".Ссылка", "") + КонецПоля; // @query-part-2 - КонецЕсли; - Если СтрНачинаетсяС(ПервоеПоле, "ТекущиеДанныеДляОтбора.") Тогда - УсловияСоединения.Добавить(ПараПолей.ВтороеПоле.Поле + " = " + ПервоеПоле); - - ИначеЕсли СтрНачинаетсяС(ПараПолей.ВтороеПоле.Поле, "ТекущиеДанныеДляОтбора.") Тогда - УсловияСоединения.Добавить(ПервоеПоле + " = " + ПараПолей.ВтороеПоле.Поле); - - ИначеЕсли ПараПолей.ВтороеПоле.Псевдоним = ВторойПсевдоним Тогда - УсловияСоединения.Добавить(ПараПолей.ВтороеПоле.Поле + " = " + ПервоеПоле); - Иначе - УсловияСоединения.Добавить(ПервоеПоле + " = " + ПараПолей.ВтороеПоле.Поле); - КонецЕсли; - Иначе - ОставшиесяУсловия = ОставшиесяПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним); - Если ОставшиесяУсловия = Неопределено Тогда - ОставшиесяУсловия = ОставшиесяПсевдонимы.Получить(ПараПолей.ВтороеПоле.Псевдоним); - КонецЕсли; - ОставшиесяУсловия.Добавить(ПараПолей); - КонецЕсли; - КонецЦикла; - Если ВторойПсевдоним = "ТекущийСписок" Тогда - ТаблицаИПсевдоним = "&ТекущийСписок КАК ТекущийСписок"; - Иначе - СледующаяТаблица = ОбратнаяГруппаТаблиц[Индекс + 1]; - ТаблицаИПсевдоним = СледующаяТаблица.Таблица + " КАК " + СледующаяТаблица.Псевдоним; - КонецЕсли; - ТекстСоединения = ТекстСоединения + " - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ " + ТаблицаИПсевдоним + " - | ПО (" + СтрСоединить(УсловияСоединения, ") - | И (") + ")"; // @query-part-1, @query-part-2, @query-part-3 - КонецЦикла; - - Возврат ТекстСоединения + ДополнительноеУсловие; - -КонецФункции - - -// Для процедур ДобавитьОпорноеПоле, ДобавитьТипыИзмерения, ДобавитьСвойстваТиповПоля, -// ДобавитьПроверкуПоТипам и функции СвойстваПоля. -// -Функция ЭтоПростойТип(Тип) - - Возврат Тип = Тип("Булево") - Или Тип = Тип("Дата") - Или Тип = Тип("Строка") - Или Тип = Тип("Число") - Или Тип = Тип("УникальныйИдентификатор") - Или Тип = Тип("ХранилищеЗначения"); - -КонецФункции - -// Для функции ДобавитьСвойстваТиповПоля. -Функция ТипПроверяется(Узел, ПолноеИмя) - - Если Узел.Типы.Количество() = 0 Тогда - Возврат Истина; - КонецЕсли; - - ТипУказан = Ложь; - Для Каждого ИмяТаблицы Из Узел.Типы Цикл - Если ВРег(ИмяТаблицы) = ВРег(ПолноеИмя) Тогда - ТипУказан = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Возврат Узел.ПроверятьТипыКромеУказанных И Не ТипУказан - Или Не Узел.ПроверятьТипыКромеУказанных И ТипУказан; - -КонецФункции - -// Для функции ДобавитьСвойстваТиповПоля. -Функция ТипУточнен(Узел, ИмяТипаНаЯзыкеЗапросов) - - ТипУточнен = Ложь; - Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл - Если ВРег(УточнениеСравнения.Ключ) = ВРег(ИмяТипаНаЯзыкеЗапросов) Тогда - ТипУточнен = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - - Возврат ТипУточнен; - -КонецФункции - -// Для функции ДобавитьСвойстваТиповПоля. -Функция УточнениеТипа(Узел, ИмяТипаНаЯзыкеЗапросов) - - Уточнение = ""; - Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл - Если ВРег(УточнениеСравнения.Ключ) = ВРег(ИмяТипаНаЯзыкеЗапросов) Тогда - Уточнение = УточнениеСравнения.Значение; - Прервать; - КонецЕсли; - КонецЦикла; - - Возврат Уточнение; - -КонецФункции - -// Для функции СвойстваПоля. -Функция ТипЗначенияУзлаЗначениеИлиКонстанта(Узел) - - Если Узел.Узел = "Значение" Тогда - Возврат ТипСсылкиПоПолномуИмениПредопределенного(Узел.Имя); - КонецЕсли; - - Возврат ТипЗнч(Узел.Значение); - -КонецФункции - -// Для функций ТекстУсловияСоединения, СвойстваПоля, НаборПолейУсловияКогда и -// процедуры УточнитьСвойстваПоляСравнения. -// -Функция ВыражениеУзлаЗначениеИлиКонстанта(Узел) - - Если Узел.Узел = "Значение" Тогда - Выражение = "Значение(" + Узел.Имя + ")"; - - ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Булево") Тогда - Выражение = ?(Узел.Значение, "Истина", "Ложь"); - - ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Число") Тогда - Выражение = Формат(Узел.Значение, "ЧН=0; ЧГ="); - - ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Неопределено") Тогда - Выражение = "Неопределено"; - Иначе - Выражение = """" + Узел.Значение + """"; - КонецЕсли; - - Возврат Выражение; - -КонецФункции - -// Для функции ТипЗначенияУзлаЗначениеИлиКонстанта. -Функция ТипСсылкиПоПолномуИмениПредопределенного(ПолноеИмяПредопределенного) - - ЧастиИмени = СтрРазделить(ПолноеИмяПредопределенного, "."); - ЧастиИмени.Удалить(2); - - ПолноеИмя = СтрСоединить(ЧастиИмени, "."); - - Возврат ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); - -КонецФункции - -// Для функций СвойстваПоля, ТипСсылкиПоПолномуИмениПредопределенного. -Функция ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя) - - Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда - ИмяТипаСсылки = СтрЗаменить(ПолноеИмя, ".", "Ссылка."); // @Non-NLS-2 - Иначе - ИмяТипаСсылки = СтрЗаменить(ПолноеИмя, ".", "Ref."); - КонецЕсли; - - Возврат Тип(ИмяТипаСсылки); - -КонецФункции - -// Для функции КлючТаблицы. -Функция ТипКлючаЗаписиПоПолномуИмениМетаданных(ПолноеИмя) - - Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда - ИмяТипаКлючаЗаписи = СтрЗаменить(ПолноеИмя, ".", "КлючЗаписи."); // @Non-NLS-2 - Иначе - ИмяТипаКлючаЗаписи = СтрЗаменить(ПолноеИмя, ".", "RecordKey."); - КонецЕсли; - - Возврат Тип(ИмяТипаКлючаЗаписи); - -КонецФункции - -// Для функции КлючТаблицы. -Функция ТипНабораЗаписейПоПолномуИмениМетаданных(ПолноеИмя) - - Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда - ИмяТипаНабораЗаписей = СтрЗаменить(ПолноеИмя, ".", "НаборЗаписей."); // @Non-NLS-2 - Иначе - ИмяТипаНабораЗаписей = СтрЗаменить(ПолноеИмя, ".", "RecordSet."); - КонецЕсли; - - Возврат Тип(ИмяТипаНабораЗаписей); - -КонецФункции - -// Для функции КлючТаблицы. -Функция ТипМенеджераОбъектаПоПолномуИмениМетаданных(ПолноеИмя) - - Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда - ИмяТипаМенеджера = СтрЗаменить(ПолноеИмя, ".", "Менеджер."); // @Non-NLS-2 - Иначе - ИмяТипаМенеджера = СтрЗаменить(ПолноеИмя, ".", "Manager."); - КонецЕсли; - - Возврат Тип(ИмяТипаМенеджера); - -КонецФункции - -// Для функций ТипСсылкиПоПолномуИмениМетаданных, ТипКлючаЗаписиПоПолномуИмениМетаданных, -// ТипНабораЗаписейПоПолномуИмениМетаданных, ТипМенеджераОбъектаПоПолномуИмениМетаданных. -// -Функция ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) - - ПервыйСимвол = Лев(ПолноеИмя, 1); - - Возврат ПервыйСимвол > "А" - И ПервыйСимвол < "Я" - Или ПервыйСимвол > "а" - И ПервыйСимвол < "я"; // @Non-NLS-1, @Non-NLS-2, @Non-NLS-3, @Non-NLS-4 - -КонецФункции - -#КонецОбласти - -#Область ПараметрыОграниченияДоступаТекстыЗапросовДляСписка - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - Строка -// * Значение - Массив из Строка -// -Функция НовыеРеквизитыТаблицКлюча() - Возврат Новый Соответствие; -КонецФункции - -// Основная функция области, которая является второй частью -// функции ПараметрыОграниченияПоСтруктуреОграничения, но -// не используется при подготовке хранимых параметров ограничения доступа, -// а используется при вызове функции ПараметрыОграничения. -// -Процедура ДобавитьТекстыЗапросовВПараметрыОграничения(Результат) - - Контекст = Результат.Контекст; - Результат.Удалить("Контекст"); - - // Проверка прав Чтение и Изменение объекта или набора записей в базе данных. - Результат.Вставить("ТекстЗапросаПроверкиПравЧтениеИзменение"); - // Проверка права Чтение объекта или набора записей в базе данных. - Результат.Вставить("ТекстЗапросаПроверкиПраваЧтение"); - // Текст извлечения владельца из ссылки объекта. - Результат.Вставить("ПолеОбъектаВладельцаВЗапросеПроверкиПрав"); - // Получение прав пользователей на список элементов данных. - Результат.Вставить("ТекстЗапросаПравПользователей"); - - ДобавитьТекстЗапросаДатыСледующегоЭлементаДанных(Результат, Контекст); - ЗаполнитьЗапросыПравПользователей(Результат, Контекст); - - Если Результат.БезЗаписиКлючейДоступа Тогда - // Запрос объектов или отборов записей для удаления или установки пустых ключей. - Результат.Вставить("ТекстЗапросаУстаревшихЭлементовДанных"); - Результат.Вставить("ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных"); - Результат.Вставить("ТекстЗапросаПроверкиУстаревшихЭлементовДанных"); - Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанных"); - Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра"); - ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст); - - Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда - // Формирование запросов проверки прав. - ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст); - КонецЕсли; - - Возврат; - КонецЕсли; - - // Имена используемых таблиц ключа. - Результат.Вставить("ТаблицыКлюча"); - // Имена используемых реквизитов таблиц ключа. - Результат.Вставить("РеквизитыТаблицКлюча"); - - // Запрос объекта или отбора записей для вычисления диапазона требуемого размера. - Результат.Вставить("ТекстЗапросаДиапазонаЭлементовДанных"); - // Запрос объектов или отборов записей, у которых устарели ключи доступа. - Результат.Вставить("ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами"); - // Запрос проверки актуальности ключа доступа у объекта. - Результат.Вставить("ТекстЗапросаПроверкиКлючаДоступаОбъекта"); - // Запрос отборов записей, которых нет в регистре ключей доступа регистров при фоновом обновлении. - Результат.Вставить("ТекстЗапросаЭлементовДанныхБезКлючейДоступа"); - // Запрос отборов записей, которых нет в регистре ключей доступа регистров при записи нового набора. - Результат.Вставить("ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей"); - Результат.Вставить("ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей"); - // Запросы объектов или отборов записей, у которых устарели ключи доступа - // по составу изменений ведущих объектов (для точечного задания). - Результат.Вставить("ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам", Новый Соответствие); - // Запрос несуществующих объектов и отборов записей, которые не используются. - Результат.Вставить("ТекстЗапросаУстаревшихЭлементовДанных"); - Результат.Вставить("ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных"); - Результат.Вставить("ТекстЗапросаПроверкиУстаревшихЭлементовДанных"); - Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанных"); - Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра"); - - // Запрос текущих ключей доступа отборов записей регистра перед записью рассчитанных ключей доступа. - Результат.Вставить("ТекстЗапросаТекущихКлючейДоступаРегистра"); - - // Запрос значений объектов или отборов записей. - Результат.Вставить("ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа"); - // Запрос значений объектов в памяти. - Результат.Вставить("ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа"); - // Запрос значений из используемых ключей доступа для сравнения со значениями из объектов или отборов записей. - Результат.Вставить("ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения"); - // Запрос значений из всех ключей доступа для сравнения со значениями из объектов или - // отборов записей перед записью нового ключа. - Результат.Вставить("ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения"); - // Запрос проверки существования ключа доступа перед записью нового ключа. - Результат.Вставить("ТекстЗапросаСуществованияКлючейДляСравнения"); - - // Запрос ключей доступа для обновления пользователей и групп доступа, которым они разрешены. - Результат.Вставить("ТекстЗапросаКлючейДоступаДляОбновленияПрав"); - // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. - Результат.Вставить("ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав"); - // Запрос значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. - Результат.Вставить("ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав"); - // Запрос неиспользуемых ключей доступа для установки даты неиспользования или удаления. - Результат.Вставить("ТекстЗапросаУстаревшихКлючейДоступа"); - - Контекст.Вставить("ОтдельныйРегистр", Истина); // Уточнение регистра ключей для нессылочных типов. - - Контекст.Вставить("ТаблицыКлюча", Новый Массив); - Контекст.Вставить("РеквизитыТаблицКлюча", НовыеРеквизитыТаблицКлюча()); - Контекст.Вставить("ИспользуемыеПоляОсновнойТаблицы", ""); - Контекст.Вставить("ЧастиУсловияПроверки", Новый Массив); - Контекст.Вставить("ЧастиЗапросаЗначенийИзОбъектов", Новый Массив); - Контекст.Вставить("ЧастиЗапросаЗначенийИзОбъектовВПамяти", Новый Массив); - Контекст.Вставить("ЧастиЗапросаЗначенийИзКлючейДляСравнения", Новый Массив); - Контекст.Вставить("ЧастиЗапросаСуществованияКлючейДляСравнения", Новый Массив); - Контекст.Вставить("ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав", Новый Массив); - Контекст.Вставить("ЧастиУсловияВыбораПравВедущихКлючейДоступа", Новый Массив); - Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписков", Новый Массив); - Контекст.Вставить("ЧастиУсловияВыбораПравПоВладельцамНастроекПрав", Новый Массив); - Контекст.Вставить("ЧастиУсловияОтбораПоВедущимКлючамДоступа", Новый Массив); - Контекст.Вставить("ОписаниеЗапросовПроверкиПоВедущимОбъектам", Новый Соответствие); - - // Формирование запроса элементов данных с устаревшими ключами. - ЗаполнитьШаблоныЧастейЗапросаПроверки(Контекст); - ЗаполнитьИспользуемыеПоляОсновнойТаблицы(Контекст); - - Для НомерШапки = 0 По 2 Цикл - ДобавитьПроверкуШапкиКлюча(Контекст, НомерШапки); - КонецЦикла; - - Для НомерТабличнойЧастиКлюча = 1 По Контекст.КоличествоТабличныхЧастейКлюча Цикл - ДобавитьПроверкуТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча); - КонецЦикла; - СобратьЧастиЗапросаПроверки(Результат, Контекст); - - // Формирование запросов значений из элементов данных и из ключей. - Для НомерШапки = 0 По 2 Цикл - ДобавитьЗаполнениеШапкиКлюча(Контекст, НомерШапки); - КонецЦикла; - ДобавитьВыборКлючейБезПолейВШапке(Контекст); - - Для НомерТабличнойЧастиКлюча = 1 По Контекст.КоличествоТабличныхЧастейКлюча Цикл - ДобавитьЗаполнениеТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча); - КонецЦикла; - СобратьЧастиЗапросовЗаполнения(Результат, Контекст); - - Результат.ТаблицыКлюча = Контекст.ТаблицыКлюча; - Результат.РеквизитыТаблицКлюча = Контекст.РеквизитыТаблицКлюча; - - ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст); - - // Формирование запросов проверки прав. - ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст); - -КонецПроцедуры - -// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. -Процедура ЗаполнитьНедостающиеТипыОпорныхПолей(Результат, Контекст) - - Если Контекст.ЭтоСсылочныйТип Или Контекст.ИспользуетсяОграничениеПоВладельцу Тогда - Возврат; - КонецЕсли; - - Если ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда - Измерения = Метаданные.РегистрыСведений[Контекст.ИмяОтдельногоРегистраКлючей].Измерения; - Иначе - Измерения = Метаданные.РегистрыСведений.КлючиДоступаКРегистрам.Измерения; - КонецЕсли; - - НедостающиеТипы = Новый Соответствие; - Поля = Новый Соответствие; - СписокНедостающихТипов = Новый СписокЗначений; - СписокПолей = Новый СписокЗначений; - - КоличествоПолей = Контекст.ОпорныеПоля.ТипыИспользуемых.Количество(); - Индекс = 0; - Пока Индекс < КоличествоПолей Цикл - ТребуемыйТип = Контекст.ОпорныеПоля.ТипыИспользуемых.Получить(Индекс).Получить(); - ТипИзмерения = Измерения[СтрШаблон("Поле%1", Индекс + 1)].Тип; - НедостающийТип = Новый ОписаниеТипов(ТребуемыйТип, , ТипИзмерения.Типы()); - Для Каждого Тип Из НедостающийТип.Типы() Цикл - Если НедостающиеТипы.Получить(Тип) = Неопределено Тогда - НедостающиеТипы.Вставить(Тип, Истина); - СписокНедостающихТипов.Добавить(ИмяТипаСсылки(ИмяТипаНаЯзыкеЗапросов(Тип), - Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам)); - Поле = Контекст.ОпорныеПоля.Все.Получить(Индекс); - Если Поля.Получить(Поле) = Неопределено Тогда - Поля.Вставить(Поле, Истина); - СписокПолей.Добавить(Поле); - КонецЕсли; - КонецЕсли; - КонецЦикла; - Индекс = Индекс + 1; - КонецЦикла; - - Если СписокНедостающихТипов.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Результат.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей = Истина; - - СписокНедостающихТипов.СортироватьПоЗначению(); - Контекст.ОпорныеПоля.Вставить("НедостающиеТипы", СписокНедостающихТипов.ВыгрузитьЗначения()); - Контекст.ОпорныеПоля.Вставить("ПоляНедостающихТипов", СписокПолей.ВыгрузитьЗначения()); - - ДобавитьСвойствоВерсии(Контекст, Результат, "БезОбновленияВсехКомбинацийЗначенийОпорныхПолей"); - ДобавитьСвойствоВерсии(Контекст, Контекст.ОпорныеПоля, "НедостающиеТипы"); - ДобавитьСвойствоВерсии(Контекст, Контекст.ОпорныеПоля, "ПоляНедостающихТипов"); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьТекстЗапросаДатыСледующегоЭлементаДанных(Результат, Контекст) - - Если Не Результат.СписокСДатой И Не Результат.СписокСПериодом Тогда - Возврат; - КонецЕсли; - - Если Результат.СписокСДатой Тогда - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ТекущийСписок.Дата КАК Дата - |ИЗ - | &ТекущийСписок КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.Дата < &ДатаНачала - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Дата УБЫВ"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ТекущийСписок.Период КАК Период - |ИЗ - | &ТекущийСписок КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.Период < &ДатаНачала - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Период УБЫВ"; - Если Контекст.ИмяКоллекцииТипа = "РегистрыРасчета" Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ".Период", ".ПериодРегистрации"); // @query-part-1, @query-part-2 - КонецЕсли; - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); - - Результат.Вставить("ТекстЗапросаДатыСледующегоЭлементаДанных", ТекстЗапроса); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст) - - Если Результат.ЭтоСсылочныйТип Тогда - ТипСсылки = ?(ЗначениеЗаполнено(СтрПолучитьСтроку(Результат.Версия, 1)) - Или ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Результат.Список) <> Неопределено, - ТипСсылкиПоПолномуИмениМетаданных(Результат.Список), Неопределено); - ТипыСсылок = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ВладелецЗначенийКлючейДоступа"); - - Если ТипыСсылок.Получить(ТипСсылки) = Неопределено Тогда - ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); - ТекстЗапросаНекорректных = ПризнакПустогоЗапроса(); - - ИначеЕсли Результат.БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей Тогда - ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); - ТекстЗапросаНекорректных = // ТекстЗапросаНекорректныхЭлементовДанных - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, - | ИСТИНА КАК Удалить, - | ЛОЖЬ КАК Обновить - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - |ГДЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) - | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступаКОбъектам.Объект"; // @query-part-1 - - Иначе - Если Результат.ДляВнешнихПользователей Тогда - ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); - Иначе - ТекстЗапросаУстаревших = // ТекстЗапросаНекорректныхЭлементовДанных - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, - | ЛОЖЬ КАК Удалить, - | ЛОЖЬ КАК Обновить - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок - | ПО (ТекущийСписок.Ссылка = КлючиДоступаКОбъектам.Объект) - |ГДЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) - | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка - | И ТекущийСписок.Ссылка ЕСТЬ NULL - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступаКОбъектам.Объект"; // @query-part-1 - ТекстЗапросаУстаревших = СтрЗаменить(ТекстЗапросаУстаревших, "&ТекущийСписок", Результат.Список); - - ТекстЗапроса = // ТекстЗапросаПроверкиУстаревшихЭлементовДанных - "ВЫБРАТЬ - | ЭлементыДанных.ТекущаяСсылка КАК Объект - |ПОМЕСТИТЬ КлючиДоступаКОбъектам - |ИЗ - | &ЭлементыДанных КАК ЭлементыДанных - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка - |ИЗ - | КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок - | ПО (ТекущийСписок.Ссылка = КлючиДоступаКОбъектам.Объект) - |ГДЕ - | ТекущийСписок.Ссылка ЕСТЬ NULL - | И &УточнениеПланаЗапроса"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); - Результат.ТекстЗапросаПроверкиУстаревшихЭлементовДанных = ТекстЗапроса; - КонецЕсли; - Если Не Результат.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей - И Не Результат.БезЗаписиКлючейДоступа Тогда - ТекстЗапросаНекорректных = // ТекстЗапросаНекорректныхЭлементовДанных - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, - | ЛОЖЬ КАК Удалить, - | ИСТИНА КАК Обновить - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - |ГДЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) - | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка - | И КлючиДоступаКОбъектам.#КлючДоступаПользователей <> ЗНАЧЕНИЕ(Справочник.КлючиДоступа.ПустаяСсылка) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступаКОбъектам.Объект"; // @query-part-1 - ТекстЗапросаНекорректных = СтрЗаменить(ТекстЗапросаНекорректных, "#КлючДоступаПользователей", - ?(Результат.ДляВнешнихПользователей, "КлючДоступаПользователей", "КлючДоступаВнешнихПользователей")); - - ТекстЗапроса = // ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных - "ВЫБРАТЬ - | ЭлементыДанных.ТекущаяСсылка КАК ТекущаяСсылка - |ПОМЕСТИТЬ ЭлементыДанных - |ИЗ - | &ЭлементыДанных КАК ЭлементыДанных - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | КлючиДоступаКОбъектам.Объект КАК Объект, - | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, - | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей - |ИЗ - | ЭлементыДанных КАК ЭлементыДанных - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ЭлементыДанных.ТекущаяСсылка)"; - Результат.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных = ТекстЗапроса; - Иначе - ТекстЗапросаНекорректных = ПризнакПустогоЗапроса(); - КонецЕсли; - КонецЕсли; - ТекстЗапросаНекорректных = СтрЗаменить(ТекстЗапросаНекорректных, "&ТекущийСписок", Результат.Список); - Результат.ТекстЗапросаУстаревшихЭлементовДанных = ТекстЗапросаУстаревших; - Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапросаНекорректных; - Возврат; - КонецЕсли; - - ОпорныеПоляВыбора = "КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа"; - - Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда - ИмяРегистра = Результат.ИмяОтдельногоРегистраКлючей; - ОсновнойОтбор = "ИСТИНА"; // @query-part-1 - Иначе - ИмяРегистра = "КлючиДоступаКРегистрам"; - ОсновнойОтбор = "КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра"; - ОпорныеПоляВыбора = "КлючиДоступаКРегистрам.Регистр КАК Регистр, - | " + ОпорныеПоляВыбора; - КонецЕсли; - - ОтборПоВидуПользователей = "ВЫБОР - | КОГДА КлючиДоступаКРегистрам.ВариантДоступа = 0 - | ТОГДА ЛОЖЬ - | ИНАЧЕ КлючиДоступаКРегистрам.ВариантДоступа - (ВЫРАЗИТЬ(КлючиДоступаКРегистрам.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 - | КОНЕЦ = " + ?(Результат.ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ"); // @query-part-1 - - ОпорныеПоля = Контекст.ОпорныеПоля; - Если ОпорныеПоля = Неопределено Тогда - МаксимальноеКоличествоОпорныхПолей = - УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистра); - Иначе - МаксимальноеКоличествоОпорныхПолей = ОпорныеПоля.МаксимальноеКоличество; - КонецЕсли; - - ОпорныеПоляДляОтбора = "КлючиДоступаКРегистрам.ВариантДоступа >= &ВариантДоступа - | И (КлючиДоступаКРегистрам.ВариантДоступа > &ВариантДоступа - | ИЛИ КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа"; // @query-part-1 - ОпорныеПоляДляУпорядочения = "ВариантДоступа"; - СтрокаТабуляций = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(" ", - 2 + МаксимальноеКоличествоОпорныхПолей * 2); - - Для Номер = 1 По МаксимальноеКоличествоОпорныхПолей Цикл - // Поля для выбора. - ОпорныеПоляВыбора = ОпорныеПоляВыбора + СтрШаблон(", - | КлючиДоступаКРегистрам.Поле%1 КАК Поле%1", Номер); // @query-part-1 - - // Поля для отбора. - Если Номер = МаксимальноеКоличествоОпорныхПолей Тогда - Отбор = "КлючиДоступаКРегистрам.Поле%1 > &Поле%1"; // @query-part-1 - Иначе - Отбор = "(КлючиДоступаКРегистрам.Поле%1 > &Поле%1 - | ИЛИ КлючиДоступаКРегистрам.Поле%1 = &Поле%1"; // @query-part-1 - КонецЕсли; - ОпорныеПоляДляОтбора = ОпорныеПоляДляОтбора + ТекстСОтступом(" - |И " + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, 2 + Номер * 2)); // @query-part-1 - - // Поля для упорядочения. - ОпорныеПоляДляУпорядочения = ОпорныеПоляДляУпорядочения - + ?(ОпорныеПоляДляУпорядочения = "", "", ", ") + СтрШаблон("Поле%1", Номер); - КонецЦикла; - ОпорныеПоляДляОтбора = ОпорныеПоляДляОтбора - + УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", МаксимальноеКоличествоОпорныхПолей); - - Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда - // Запрос очистки общего регистра. - ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра - "ВЫБРАТЬ ПЕРВЫЕ 995 - | &ОпорныеПоляВыбора, - | ИСТИНА КАК Удалить, - | ЛОЖЬ КАК Обновить - |ИЗ - | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - |ГДЕ - | КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра - | И &ОтборПоВидуПользователей - | И &ОпорныеПоляДляОтбора - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляУпорядочения"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); - Результат.ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра = ТекстЗапроса; - КонецЕсли; - - Если Результат.БезЗаписиКлючейДоступа Тогда - Результат.ТекстЗапросаУстаревшихЭлементовДанных = ПризнакПустогоЗапроса(); - ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанных - "ВЫБРАТЬ ПЕРВЫЕ 995 - | &ОпорныеПоляВыбора, - | ИСТИНА КАК Удалить, - | ЛОЖЬ КАК Обновить - |ИЗ - | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам - |ГДЕ - | &ОсновнойОтбор - | И &ОтборПоВидуПользователей - | И &ОпорныеПоляДляОтбора - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляУпорядочения"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); - Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапроса; - Возврат; - КонецЕсли; - - КоличествоИспользуемыхОпорныхПолей = ОпорныеПоля.Используемые.Количество(); - Номер = 1; - ОпорныеПоляВыбораПриПроверке = ?(ОсновнойОтбор = "ИСТИНА", "", - "КлючиДоступаКРегистрам.Регистр КАК Регистр, - | ") + "КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа"; - ОпорныеПоляВыбораИзСписка = ""; - ОпорныеПоляДляСравнения = ""; - ОпорныеПоляДляСоединения = ?(ОсновнойОтбор = "ИСТИНА", "", - "(КлючиДоступаКРегистрам.Регистр = ЭлементыДанных.Регистр) - |И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = ЭлементыДанных.ВариантДоступа)"; - ОпорныеПоляДляОтбора2 = - "КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа - | И "; // @query-part-1 - УсловиеПроверкиПервогоПоля = ""; - ОпорныеПоляДляУпорядоченияПриПроверке = ""; - Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл - // Поля для выбора. - ОпорныеПоляВыбораПриПроверке = ОпорныеПоляВыбораПриПроверке + СтрШаблон(", - | КлючиДоступаКРегистрам.Поле%1 КАК Поле%1", Номер); // @query-part-1 - ОпорныеПоляВыбораИзСписка = ОпорныеПоляВыбораИзСписка + ?(ОпорныеПоляВыбораИзСписка = "", "", ", - | ") + СтрШаблон("ТекущийСписок.%1", ИмяОпорногоПоля); - - // Поля для отбора. - Если Номер = КоличествоИспользуемыхОпорныхПолей Тогда - Отбор = "КлючиДоступаКРегистрам.Поле%1 > &Поле%1"; // @query-part-1 - Иначе - Отбор = "(КлючиДоступаКРегистрам.Поле%1 > &Поле%1 - | ИЛИ КлючиДоступаКРегистрам.Поле%1 = &Поле%1"; // @query-part-1 - КонецЕсли; - ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + ТекстСОтступом(?(Номер = 1, "", " - |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 - - // Поля для сравнения и соединения. - ОпорныеПоляДляСравнения = ОпорныеПоляДляСравнения + ?(ОпорныеПоляДляСравнения = "", "", " - |И ") + СтрШаблон("(ТекущийСписок.%2 = КлючиДоступаКРегистрам.Поле%1)", Номер, ИмяОпорногоПоля); // @query-part-3 - ОпорныеПоляДляСоединения = ОпорныеПоляДляСоединения + ?(ОпорныеПоляДляСоединения = "", "", " - |И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ЭлементыДанных.Поле%1)", Номер); // @query-part-3 - - // Условие проверки по первому полю. - Если УсловиеПроверкиПервогоПоля = "" Тогда - УсловиеПроверкиПервогоПоля = СтрШаблон("ТекущийСписок.%1 ЕСТЬ NULL", ИмяОпорногоПоля); // @query-part-1 - КонецЕсли; - - // Поля для упорядочения. - ОпорныеПоляДляУпорядоченияПриПроверке = ОпорныеПоляДляУпорядоченияПриПроверке - + ?(ОпорныеПоляДляУпорядоченияПриПроверке = "", "", ", ") + СтрШаблон("Поле%1", Номер); - - Номер = Номер + 1; - КонецЦикла; - ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 - + УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", КоличествоИспользуемыхОпорныхПолей - 1); - - ТекстЗапроса = // ТекстЗапросаУстаревшихЭлементовДанных - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ОпорныеПоляВыбора1 - |ПОМЕСТИТЬ ЗначенияИспользуемыхОпорныхПолей - |ИЗ - | &ТекущийСписок КАК ТекущийСписок - | - |ИНДЕКСИРОВАТЬ ПО - | &ОпорныеПоляВыбора1 - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ ПЕРВЫЕ 995 - | &ОпорныеПоляВыбора2, - | ЛОЖЬ КАК Удалить, - | ЛОЖЬ КАК Обновить - |ИЗ - | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам - | ЛЕВОЕ СОЕДИНЕНИЕ ЗначенияИспользуемыхОпорныхПолей КАК ТекущийСписок - | ПО &ОпорныеПоляДляСравнения - |ГДЕ - | &ОсновнойОтбор - | И &ОпорныеПоляДляОтбора - | И &УсловиеПроверкиПервогоПоля - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляУпорядочения"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора1", ОпорныеПоляВыбораИзСписка); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора2", ОпорныеПоляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора2); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСравнения", - ТекстСОтступом(ОпорныеПоляДляСравнения, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиПервогоПоля", УсловиеПроверкиПервогоПоля); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядоченияПриПроверке); - - ВариантДоступаСтрокой = XMLСтрока(Контекст.ВариантДоступа); - ВариантДоступаСтрокой = ?(ЗначениеЗаполнено(ВариантДоступаСтрокой), ВариантДоступаСтрокой, "NULL"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойВариантДоступа", ВариантДоступаСтрокой); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); - - Результат.ТекстЗапросаУстаревшихЭлементовДанных = ТекстЗапроса; - - ТекстЗапроса = // ТекстЗапросаПроверкиУстаревшихЭлементовДанных - "ВЫБРАТЬ - | &ОпорныеПоляВыбораПриПроверке - |ПОМЕСТИТЬ КлючиДоступаКРегистрам - |ИЗ - | &КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | &ОпорныеПоляВыбораПриПроверке - |ИЗ - | КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок - | ПО &ОпорныеПоляДляСравнения - |ГДЕ - | &УсловиеПроверкиПервогоПоля - | И &УточнениеПланаЗапроса"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораПриПроверке", ОпорныеПоляВыбораПриПроверке); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСравнения", - ТекстСОтступом(ОпорныеПоляДляСравнения, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиПервогоПоля", УсловиеПроверкиПервогоПоля); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); - - Результат.ТекстЗапросаПроверкиУстаревшихЭлементовДанных = ТекстЗапроса; - - Если Номер <= МаксимальноеКоличествоОпорныхПолей Тогда - ПроверкаNULL = ""; - Для Счетчик = Номер По МаксимальноеКоличествоОпорныхПолей Цикл - ПроверкаNULL = ПроверкаNULL + ?(ПроверкаNULL = "", "", " - |ИЛИ ") + СтрШаблон("КлючиДоступаКРегистрам.Поле%1 <> ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)", Счетчик); // @query-part-3 - КонецЦикла; - Иначе - ПроверкаNULL = "ЛОЖЬ"; - КонецЕсли; - - ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанных - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 - | &ОпорныеПоляВыбора, - | НЕ КлючиДоступаКРегистрам.ВариантДоступа В (&ИспользуемыеВариантыДоступа) КАК Удалить, - | КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа - | И &ПроверкаNULL2 КАК Обновить - |ИЗ - | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам - |ГДЕ - | &ОсновнойОтбор - | И &ОтборПоВидуПользователей - | И &ОпорныеПоляДляОтбора - | И (НЕ КлючиДоступаКРегистрам.ВариантДоступа В (&ИспользуемыеВариантыДоступа) - | ИЛИ КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа - | И &ПроверкаNULL1) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляУпорядочения"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверкаNULL1", - "(" + ТекстСОтступом(ПроверкаNULL, " ") + ")"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверкаNULL2", - "(" + ТекстСОтступом(ПроверкаNULL, " ") + ")"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойВариантДоступа", ВариантДоступаСтрокой); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); - - ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); - ВариантыДоступаСтрокой = Новый Массив; - Если ИспользуемыеВариантыДоступа = Неопределено Тогда - ВариантыДоступаСтрокой.Добавить("NULL"); - Иначе - Для Каждого ИспользуемыйВариантДоступа Из ИспользуемыеВариантыДоступа Цикл - ВариантыДоступаСтрокой.Добавить(XMLСтрока(ИспользуемыйВариантДоступа.ВариантДоступа)); - КонецЦикла; - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИспользуемыеВариантыДоступа", - СтрСоединить(ВариантыДоступаСтрокой, ",")); - - Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапроса; - - ОпорныеПоляВыбораДляОбновления = ОпорныеПоляВыбора + ", - | КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа"; // @query-part-1 - - ТекстЗапроса = // ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных - "ВЫБРАТЬ - | &ОпорныеПоляВыбораПриПроверке - |ПОМЕСТИТЬ ЭлементыДанных - |ИЗ - | &ЭлементыДанных КАК КлючиДоступаКРегистрам - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | &ОпорныеПоляВыбораДляОбновления - |ИЗ - | ЭлементыДанных КАК ЭлементыДанных - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам - | ПО &ОпорныеПоляДляСоединения"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораПриПроверке", ОпорныеПоляВыбораПриПроверке); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораДляОбновления", ОпорныеПоляВыбораДляОбновления); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСоединения", - ТекстСОтступом(ОпорныеПоляДляСоединения, " ")); - - Результат.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных = ТекстЗапроса; - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ЗаполнитьИспользуемыеПоляОсновнойТаблицы(Контекст) - - Если Не ЗначениеЗаполнено(Контекст.ПоляТаблицОбъекта.Результат) Тогда - Возврат; - КонецЕсли; - - ОписаниеОсновнойТаблицы = Неопределено; - Для Каждого ОписаниеТаблицы Из Контекст.ПоляТаблицОбъекта.Результат Цикл - Если Не ЗначениеЗаполнено(ОписаниеТаблицы.ТабличнаяЧасть) Тогда - ОписаниеОсновнойТаблицы = ОписаниеТаблицы; - Прервать; - КонецЕсли; - КонецЦикла; - - Если ОписаниеОсновнойТаблицы = Неопределено Тогда - Возврат; - КонецЕсли; - - ДополнительныеПоля = ""; - Для Каждого ИмяПоля Из ОписаниеОсновнойТаблицы.Поля Цикл - Если ИмяПоля = "Ссылка" Тогда - Продолжить; - КонецЕсли; - ДополнительныеПоля = ДополнительныеПоля + СтрШаблон(", - |ТекущийСписок.%1 КАК %1", ИмяПоля); - КонецЦикла; - - Контекст.ИспользуемыеПоляОсновнойТаблицы = ДополнительныеПоля; - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ЗаполнитьШаблоныЧастейЗапросаПроверки(Контекст) - - Если Контекст.ЭтоСсылочныйТип Тогда - ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта(Контекст); - Иначе - ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра(Контекст); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьШаблоныЧастейЗапросаПроверки. -Процедура ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта(Контекст) - - Контекст.Вставить("ТекстЗапросаДиапазонаЭлементовДанных"); - Контекст.Вставить("ТекстЗапросаПроверки"); - Контекст.Вставить("ТекстЗапросаПроверкиСвязи"); - Контекст.Вставить("ТекстЗапросаПроверкиШапки"); - Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧасти"); - Контекст.Вставить("ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта"); - Контекст.Вставить("ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта"); - Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта"); - Контекст.Вставить("ТекстЗапросаТочечнойПроверки"); - Контекст.Вставить("ТекстЗапросаТочечнойПроверкиСвязи"); - Контекст.Вставить("ТекстЗапросаТочечнойПроверкиШапки"); - Контекст.Вставить("ТекстЗапросаТочечнойПроверкиТабличнойЧасти"); - - Если Контекст.СписокСДатой Тогда - Контекст.ТекстЗапросаДиапазонаЭлементовДанных = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ЭлементыДанных.Дата КАК ДатаНачалаДиапазона, - | ЭлементыДанных.Ссылка КАК СсылкаДатыНачалаДиапазона - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 993 - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК Ссылка - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ГДЕ - | ТекущийСписок.Дата >= &ДатаНачала - | И ТекущийСписок.Дата <= &ДатаОкончанияДиапазона - | И (ТекущийСписок.Дата < &ДатаОкончанияДиапазона - | ИЛИ ТекущийСписок.Дата = &ДатаОкончанияДиапазона - | И ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона) - | - | УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Дата УБЫВ, - | ТекущийСписок.Ссылка УБЫВ) КАК ЭлементыДанных - | - |УПОРЯДОЧИТЬ ПО - | ЭлементыДанных.Дата, - | ЭлементыДанных.Ссылка"; - - Контекст.ТекстЗапросаПроверки = - "ВЫБРАТЬ - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля1, - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа - |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 993 - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2 - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ГДЕ - | ТекущийСписок.Дата >= &ДатаНачалаДиапазона - | И (ТекущийСписок.Дата > &ДатаНачалаДиапазона - | ИЛИ ТекущийСписок.Дата = &ДатаНачалаДиапазона - | И ТекущийСписок.Ссылка >= &СсылкаДатыНачалаДиапазона) - | И ТекущийСписок.Дата <= &ДатаОкончанияДиапазона - | И (ТекущийСписок.Дата < &ДатаОкончанияДиапазона - | ИЛИ ТекущийСписок.Дата = &ДатаОкончанияДиапазона - | И ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона)) КАК ТекущийСписок - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК ТекущаяСсылка - |ИЗ - | &ЧастиЗапросаПроверки КАК ТекущийСписок - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Дата УБЫВ, - | ТекущийСписок.Ссылка УБЫВ"; // @query-part-1 - - Контекст.ТекстЗапросаПроверкиСвязи = - "ВЫБРАТЬ - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.ТекущийКлючДоступа ЕСТЬ NULL"; - - Контекст.ТекстЗапросаПроверкиШапки = - "ВЫБРАТЬ - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения - |ГДЕ - | &УсловиеЗапроса"; // @query-part-1 - - Контекст.ТекстЗапросаПроверкиТабличнойЧасти = - "ВЫБРАТЬ - | ТекущийСписок.Дата КАК Дата, - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения - | - |СГРУППИРОВАТЬ ПО - | ТекущийСписок.Дата, - | ТекущийСписок.Ссылка, - | ТекущийСписок.ТекущийКлючДоступа - | - |ИМЕЮЩИЕ - | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА - | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В - | (ВЫБРАТЬ - | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок - | ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ГДЕ - | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 - Иначе - Контекст.ТекстЗапросаДиапазонаЭлементовДанных = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ЭлементыДанных.Ссылка КАК СсылкаОкончанияДиапазона - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 993 - | ТекущийСписок.Ссылка КАК Ссылка - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ГДЕ - | ТекущийСписок.Ссылка > &СсылкаНачалаДиапазона - | - | УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Ссылка) КАК ЭлементыДанных - | - |УПОРЯДОЧИТЬ ПО - | ЭлементыДанных.Ссылка УБЫВ"; - - Контекст.ТекстЗапросаПроверки = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля1, - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа - |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 993 - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2 - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ГДЕ - | ТекущийСписок.Ссылка > &СсылкаНачалаДиапазона - | И ТекущийСписок.Ссылка <= &СсылкаОкончанияДиапазона) КАК ТекущийСписок - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка - |ИЗ - | &ЧастиЗапросаПроверки КАК ТекущийСписок - | - |УПОРЯДОЧИТЬ ПО - | ТекущийСписок.Ссылка"; // @query-part-1 - - Контекст.ТекстЗапросаПроверкиСвязи = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок - |ГДЕ - | ТекущийСписок.ТекущийКлючДоступа ЕСТЬ NULL"; - - Контекст.ТекстЗапросаПроверкиШапки = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения - |ГДЕ - | &УсловиеЗапроса"; // @query-part-1 - - Контекст.ТекстЗапросаПроверкиТабличнойЧасти = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения - | - |СГРУППИРОВАТЬ ПО - | ТекущийСписок.Ссылка, - | ТекущийСписок.ТекущийКлючДоступа - | - |ИМЕЮЩИЕ - | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА - | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В - | (ВЫБРАТЬ - | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок - | ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ГДЕ - | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 - КонецЕсли; - - Контекст.ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ТекущийСписок.Ссылка КАК Ссылка - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ГДЕ - | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) - |ГДЕ - | КлючиДоступаКОбъектам.Объект ЕСТЬ NULL"; - - Контекст.ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) - | ГДЕ - | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок #Соединения - |ГДЕ - | &УсловиеЗапроса"; // @query-part-1 - - Контекст.ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) - | ГДЕ - | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок #Соединения - | - |СГРУППИРОВАТЬ ПО - | ТекущийСписок.Ссылка, - | ТекущийСписок.ТекущийКлючДоступа - | - |ИМЕЮЩИЕ - | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА - | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В - | (ВЫБРАТЬ - | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок - | ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ГДЕ - | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 - - // Запросы точечной проверки. - Контекст.ТекстЗапросаТочечнойПроверки = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка - |ИЗ - | &ЧастиЗапросаПроверки КАК ТекущийСписок - |ГДЕ - | &УточнениеПланаЗапроса"; - - Контекст.ТекстЗапросаТочечнойПроверкиСвязи = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам - | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка)) КАК ТекущийСписок - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) - |ГДЕ - | КлючиДоступаКОбъектам.Объект ЕСТЬ NULL"; - - Контекст.ТекстЗапросаТочечнойПроверкиШапки = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам - | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка)) КАК ТекущийСписок #Соединения - |ГДЕ - | &УсловиеЗапроса"; // @query-part-1 - - Контекст.ТекстЗапросаТочечнойПроверкиТабличнойЧасти = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | (ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам - | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка)) КАК ТекущийСписок #Соединения - | - |СГРУППИРОВАТЬ ПО - | ТекущийСписок.Ссылка, - | ТекущийСписок.ТекущийКлючДоступа - | - |ИМЕЮЩИЕ - | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА - | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В - | (ВЫБРАТЬ - | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок - | ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ГДЕ - | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 - - Если Не Контекст.Свойство("ОписаниеЗапросовПроверкиПоВедущимОбъектам") Тогда - Возврат; - КонецЕсли; - - ТекстЗапроса = // ТекстЗапросаОберткиВыбораДанных - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 - | ТекущийСписок.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам - |ИЗ - | #ЗапросыВыбораДанных КАК ТекущийСписок"; - - Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаОберткиВыбораДанных", ТекстЗапроса); - - ШаблонЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 - | ТекущийСписок.Ссылка КАК Ссылка - |ИЗ - | "; // @query-part-1 - ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст); - -КонецПроцедуры - -// Для процедуры ЗаполнитьШаблоныЧастейЗапросаПроверки. -Процедура ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра(Контекст) - - ОпорныеПоля = Контекст.ОпорныеПоля; - ОпорныеПоля.Вставить("ДляВыбора", ""); - ОпорныеПоля.Вставить("ДляУпорядочения", ""); - - КоличествоИспользуемыхПолей = ОпорныеПоля.Используемые.Количество(); - ДобавлятьОтборПоПервомуПолю = КоличествоИспользуемыхПолей > 1 - И ОпорныеПоля.ТипыИспользуемых[0].Получить().Типы().Количество() = 1; - - // Для запроса новых комбинаций. - ОпорныеПоляДляВыбора = ""; - ОпорныеПоляУсловиеСоединения = ""; - ОпорныеПоляДляГруппировкиИлиУпорядочения = ""; - ОпорныеПоляДляОтбора1 = ""; // СписокСПериодом - ОпорныеПоляДляОтбора2 = ?(Не ДобавлятьОтборПоПервомуПолю, "", СтрШаблон( - "ТекущийРегистр.%2 >= &Поле%1 - | И ", 1, ОпорныеПоля.Используемые[0])); - - // Для запроса текущих ключей доступа. - УсловиеОтбора = ""; - ПоляОтбора = ""; - - Если Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда - Контекст.ОтдельныйРегистр = Ложь; - // Для запроса новых комбинаций. - ОпорныеПоляУсловиеСоединения = "(КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра)"; - // Для запроса текущих ключей доступа. - УсловиеОтбора = "ТекущийСписок.Регистр = &ИдентификаторРегистра"; - // Для запроса комбинаций с устаревшими ключами. - ПоляОтбора = "ТекущийСписок.Регистр = &ИдентификаторРегистра"; - КонецЕсли; - - // Для запроса новых комбинаций. - ОпорныеПоляУсловиеСоединения = ОпорныеПоляУсловиеСоединения + ?(ОпорныеПоляУсловиеСоединения = "", "", " - | И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа)"; // @query-part-3 - - // Для запроса текущих ключей доступа. - УсловиеОтбора = УсловиеОтбора + ?(УсловиеОтбора = "", "", " - | И ") + "ТекущийСписок.ВариантДоступа = &ВариантДоступа"; // @query-part-3 - - // Для запроса комбинаций с устаревшими ключами. - ПоляОтбора = ПоляОтбора + ?(ПоляОтбора = "", "", " - | И ") + "ТекущийСписок.ВариантДоступа = &ВариантДоступа"; // @query-part-3 - - ПоляДляВыбораДиапазона = ""; - - ПоляОтбора1 = ""; - ПоляОтбора2 = ""; - - СтрокаТабуляций = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(" ", - КоличествоИспользуемыхПолей * 3); - - Номер = 0; - Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл - Номер = Номер + 1; - - // Для запроса новых комбинаций. - ОпорныеПоляДляВыбора = ОпорныеПоляДляВыбора + ?(ОпорныеПоляДляВыбора = "", "", ", - | ") + СтрШаблон("ТекущийРегистр.%2 КАК Поле%1", Номер, ИмяОпорногоПоля); // @query-part-4 - - ОпорныеПоляУсловиеСоединения = ОпорныеПоляУсловиеСоединения + ?(ОпорныеПоляУсловиеСоединения = "", "", " - | И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ТекущийРегистр.%2)", Номер, ИмяОпорногоПоля); // @query-part-3 - - ОпорныеПоляДляГруппировкиИлиУпорядочения = ОпорныеПоляДляГруппировкиИлиУпорядочения - + ?(ОпорныеПоляДляГруппировкиИлиУпорядочения = "", "", ", ") + ИмяОпорногоПоля; - - Если Номер = КоличествоИспользуемыхПолей Тогда - Отбор = "ТекущийРегистр.%2 > &Поле%1"; // @query-part-1 - Иначе - Отбор = "(ТекущийРегистр.%2 > &Поле%1 - | ИЛИ ТекущийРегистр.%2 = &Поле%1"; // @query-part-1 - КонецЕсли; - Отбор = ТекстСОтступом(?(Номер = 1, "", " - |И ") + СтрШаблон(Отбор, Номер, ИмяОпорногоПоля), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 - ОпорныеПоляДляОтбора1 = ОпорныеПоляДляОтбора1 + Отбор; - ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + Отбор; - - // Для запроса текущих ключей доступа. - УсловиеОтбора = УсловиеОтбора + ?(УсловиеОтбора = "", "", " - | И ") + СтрШаблон("ТекущийСписок.Поле%1 = &Поле%1", Номер) + "_%1"; // @query-part-3 - - // Для запроса комбинаций с устаревшими ключами. - ОпорныеПоля.ДляВыбора = ОпорныеПоля.ДляВыбора + ?(ОпорныеПоля.ДляВыбора = "", "", ", - | ") + СтрШаблон("ТекущийСписок.Поле%1 КАК Поле%1", Номер); // @query-part-4 - - ПоляДляВыбораДиапазона = ПоляДляВыбораДиапазона + ?(ПоляДляВыбораДиапазона = "", "", ", - | ") + СтрШаблон("ЭлементыДанных.Поле%1 КАК Поле%1ОкончанияДиапазона", Номер); // @query-part-4 - - Если Номер = КоличествоИспользуемыхПолей Тогда - Отбор = "ТекущийСписок.Поле%1 > &Поле%1НачалаДиапазона"; // @query-part-1 - Иначе - Отбор = "(ТекущийСписок.Поле%1 > &Поле%1НачалаДиапазона - | ИЛИ ТекущийСписок.Поле%1 = &Поле%1НачалаДиапазона"; // @query-part-1 - КонецЕсли; - ПоляОтбора1 = ПоляОтбора1 + ТекстСОтступом(?(Номер = 1, "", " - |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 - - Если Номер = КоличествоИспользуемыхПолей Тогда - Отбор = "ТекущийСписок.Поле%1 <= &Поле%1ОкончанияДиапазона"; // @query-part-1 - Иначе - Отбор = "(ТекущийСписок.Поле%1 < &Поле%1ОкончанияДиапазона - | ИЛИ ТекущийСписок.Поле%1 = &Поле%1ОкончанияДиапазона"; // @query-part-1 - КонецЕсли; - ПоляОтбора2 = ПоляОтбора2 + ТекстСОтступом(?(Номер = 1, "", " - |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 - - ОпорныеПоля.ДляУпорядочения = ОпорныеПоля.ДляУпорядочения - + ?(ОпорныеПоля.ДляУпорядочения = "", "", ", ") + СтрШаблон("Поле%1", Номер); - КонецЦикла; - - Если КоличествоИспользуемыхПолей > 1 Тогда - Скобки = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", КоличествоИспользуемыхПолей - 1); - ОпорныеПоляДляОтбора1 = ОпорныеПоляДляОтбора1 + Скобки; - ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + Скобки; - ПоляОтбора1 = ПоляОтбора1 + Скобки; - ПоляОтбора2 = ПоляОтбора2 + Скобки; - КонецЕсли; - ПоляОтбора1 = ПоляОтбора + " - | И " + ПоляОтбора1; // @query-part-1 - ПоляОтбора2 = ПоляОтбора1 + " - | И " + ПоляОтбора2; // @query-part-1 - - // Запросы комбинаций с устаревшими ключами. - ТекстЗапроса = // ТекстЗапросаДиапазонаЭлементовДанных - "ВЫБРАТЬ ПЕРВЫЕ 1 - | &ПоляДляВыбораДиапазона - |ИЗ - | (ВЫБРАТЬ ПЕРВЫЕ 993 - | &ОпорныеПоляДляВыбора - | ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ГДЕ - | &ОпорныеПоляДляОтбора - | - | УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляУпорядочения) КАК ЭлементыДанных - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляОбратногоУпорядочения"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляДляВыбораДиапазона", ПоляДляВыбораДиапазона); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ТекстСОтступом(ОпорныеПоля.ДляВыбора, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ТекстСОтступом(ПоляОтбора1, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоля.ДляУпорядочения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОбратногоУпорядочения", - СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ",", " УБЫВ,") + " УБЫВ"); // @query-part-3, @query-part-4 - Контекст.Вставить("ТекстЗапросаДиапазонаЭлементовДанных", ТекстЗапроса); - - ТекстЗапроса = // ТекстЗапросаПроверки - "ВЫБРАТЬ ПЕРВЫЕ 993 - | &ОпорныеПоляДляВыбора, - | ТекущийСписок.КлючДоступа КАК ТекущийКлючДоступа - |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных - |ИЗ - | &ТекущийСписок КАК ТекущийСписок - |ГДЕ - | &ОпорныеПоляДляОтбора - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ОпорныеПоляДляВыбора - |ИЗ - | &ЧастиЗапросаПроверки КАК ТекущийСписок - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляУпорядочения"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ПоляОтбора2); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоля.ДляУпорядочения); - Контекст.Вставить("ТекстЗапросаПроверки", ТекстЗапроса); - - ТекстЗапроса = // ТекстЗапросаПроверкиШапки - "ВЫБРАТЬ - | &ОпорныеПоляДляВыбора - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения - |ГДЕ - | &УсловиеЗапроса"; // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - Контекст.Вставить("ТекстЗапросаПроверкиШапки", ТекстЗапроса); - - ТекстЗапроса = // ТекстЗапросаПроверкиТабличнойЧасти - "ВЫБРАТЬ - | &ОпорныеПоляДляВыбора - |ИЗ - | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения - | - |СГРУППИРОВАТЬ ПО - | &ОпорныеПоляДляГруппировки, - | ТекущийСписок.ТекущийКлючДоступа - | - |ИМЕЮЩИЕ - | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА - | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В - | (ВЫБРАТЬ - | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок - | ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ГДЕ - | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировки", - "ТекущийСписок." + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ", ", ", - | ТекущийСписок.")); - Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧасти", ТекстЗапроса); - - // Запросы точечной проверки. - ТекстЗапроса = // ТекстЗапросаТочечнойПроверки - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ОпорныеПоляДляВыбора - |ИЗ - | &ЧастиЗапросаПроверки КАК ТекущийСписок - |ГДЕ - | &УточнениеПланаЗапроса"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - Контекст.Вставить("ТекстЗапросаТочечнойПроверки", ТекстЗапроса); - - ТекстЗапроса = // ТекстЗапросаТочечнойПроверкиШапки - "ВЫБРАТЬ - | &ОпорныеПоляДляВыбора - |ИЗ - | ТекущийСписокПоВедущимОбъектам КАК ТекущийСписок #Соединения - |ГДЕ - | &УсловиеЗапроса"; // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - Контекст.Вставить("ТекстЗапросаТочечнойПроверкиШапки", ТекстЗапроса); - - ТекстЗапроса = // ТекстЗапросаПроверкиТабличнойЧасти - "ВЫБРАТЬ - | &ОпорныеПоляДляВыбора - |ИЗ - | ТекущийСписокПоВедущимОбъектам КАК ТекущийСписок #Соединения - | - |СГРУППИРОВАТЬ ПО - | &ОпорныеПоляДляГруппировки, - | ТекущийСписок.ТекущийКлючДоступа - | - |ИМЕЮЩИЕ - | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА - | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В - | (ВЫБРАТЬ - | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок - | ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ГДЕ - | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировки", - "ТекущийСписок." + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ", ", ", - | ТекущийСписок.")); - Контекст.Вставить("ТекстЗапросаТочечнойПроверкиТабличнойЧасти", ТекстЗапроса); - - ТекстЗапроса = // ТекстЗапросаОберткиВыбораДанныхДляТочечнойПроверкиКомбинаций - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 - | &ОпорныеПоляДляВыбора, - | ТекущийСписок.ТекущийКлючДоступа КАК ТекущийКлючДоступа - |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам - |ИЗ - | #ЗапросыВыбораДанных КАК ТекущийСписок"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаОберткиВыбораДанных", ТекстЗапроса); - - ШаблонЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 - | &ОпорныеПоляДляВыбора, - | ТекущийСписок.КлючДоступа КАК ТекущийКлючДоступа - |ИЗ - | "; // @query-part-1 - ШаблонЗапроса = СтрЗаменить(ШаблонЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); - ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст); - - // Запросы новых комбинаций значений полей. - Если Контекст.СписокСПериодом Тогда - ТекстЗапроса = // ТекстЗапросаНовыхКомбинаций - "ВЫБРАТЬ ПЕРВЫЕ 995 - | МАКСИМУМ(ТекущийРегистр.Период) КАК Период, - | &ОпорныеПоляДляВыбора - |ИЗ - | &ТекущийРегистр КАК ТекущийРегистр - | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК КлючиДоступаКРегистрам - | ПО &ОпорныеПоляУсловиеСоединения - |ГДЕ - | ТекущийРегистр.Период >= &ДатаНачала - | И ТекущийРегистр.Период <= &ДатаОкончания - | И (ТекущийРегистр.Период < &ДатаОкончания - | ИЛИ ТекущийРегистр.Период = &ДатаОкончания - | И &ОпорныеПоляДляОтбора) - | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL - | И &УточнениеПланаЗапроса - | - |СГРУППИРОВАТЬ ПО - | &ОпорныеПоляДляГруппировкиИлиУпорядочения - | - |УПОРЯДОЧИТЬ ПО - | Период УБЫВ, &ОпорныеПоляДляГруппировкиИлиУпорядочения"; - Если Контекст.ИмяКоллекцииТипа = "РегистрыРасчета" Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - ".Период", ".ПериодРегистрации"); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоляДляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляУсловиеСоединения", ОпорныеПоляУсловиеСоединения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ТекстСОтступом(ОпорныеПоляДляОтбора1, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировкиИлиУпорядочения", - ОпорныеПоляДляГруппировкиИлиУпорядочения); - Иначе - ТекстЗапроса = // ТекстЗапросаНовыхКомбинаций - "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 - | &ОпорныеПоляДляВыбора - |ИЗ - | &ТекущийРегистр КАК ТекущийРегистр - | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК КлючиДоступаКРегистрам - | ПО &ОпорныеПоляУсловиеСоединения - |ГДЕ - | &ОпорныеПоляДляОтбора - | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | &ОпорныеПоляДляГруппировкиИлиУпорядочения"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоляДляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляУсловиеСоединения", ОпорныеПоляУсловиеСоединения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора2); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировкиИлиУпорядочения", - ОпорныеПоляДляГруппировкиИлиУпорядочения); - КонецЕсли; - Контекст.Вставить("ТекстЗапросаНовыхКомбинаций", ТекстЗапроса); - - // Запрос текущих ключей доступа. - ТекстЗапроса = // ТекстЗапросаТекущихКлючейДоступа - "ВЫБРАТЬ ПЕРВЫЕ 2 - | ТекущийСписок.КлючДоступа КАК КлючДоступа - |ИЗ - | &ТекущийСписок КАК ТекущийСписок - |ГДЕ - | &УсловиеОтбора"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - Контекст.Вставить("ТекстЗапросаТекущихКлючейДоступа", ТекстЗапроса); - -КонецПроцедуры - -// Для процедур ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта, ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра. -Процедура ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст) - - ОписаниеЗапросов = Новый Соответствие; - Для Каждого СоединениеОтбора Из Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов Цикл - ОписаниеСоединения = СоединениеОтбора.Значение; - Поля = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Получить(СоединениеОтбора.Ключ); - ВедущаяТаблица = СоединениеОтбора.Ключ; - Если ОписаниеСоединения.ПоляШапки.Количество() > 0 Тогда - ОписаниеЗапросов.Вставить(ВедущаяТаблица, - ОписаниеЗапросовПроверкиПоВедущейТаблице(ОписаниеСоединения.ПоляШапки, - Поля.ДляОтбора.ПоляШапки, ВедущаяТаблица, ШаблонЗапроса, Контекст)); - КонецЕсли; - Для Каждого ОписаниеТабличнойЧасти Из ОписаниеСоединения.ТабличныеЧасти Цикл - ВедущаяТаблица = СоединениеОтбора.Ключ + "." + ОписаниеТабличнойЧасти.Ключ; - ТипыПолей = Поля.ДляОтбора.ТабличныеЧасти.Получить(ОписаниеТабличнойЧасти.Ключ); - ОписаниеЗапросов.Вставить(ВедущаяТаблица, - ОписаниеЗапросовПроверкиПоВедущейТаблице(ОписаниеТабличнойЧасти.Значение, - ТипыПолей, ВедущаяТаблица, ШаблонЗапроса, Контекст)); - КонецЦикла; - КонецЦикла; - Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ПоЗначениямПолей", ОписаниеЗапросов); - - ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков("ПоЗначениямСГруппами", ШаблонЗапроса, Контекст); - ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков("ПоКлючамДоступа", ШаблонЗапроса, Контекст); - -КонецПроцедуры - -// Для процедуры ДобавитьЗапросыПроверкиПоВедущимСпискам. -Функция ОписаниеЗапросовПроверкиПоВедущейТаблице(СоединенияОтборов, ТипыПолей, - ВедущаяТаблица, ШаблонЗапроса, Контекст) - - ВедущаяТаблицаБезТочек = СтрЗаменить(ВедущаяТаблица, ".", "_"); - - Поля = Новый Массив; - Для Каждого ОписаниеПоля Из ТипыПолей Цикл - Поля.Добавить(ОписаниеПоля.Ключ + " КАК " + ОписаниеПоля.Ключ); - КонецЦикла; - - ТекстЗапроса = // ТекстЗапросаПараметров - "ВЫБРАТЬ - | &ПоляТаблицы - |ПОМЕСТИТЬ #ВедущаяТаблицаБезТочек - |ИЗ - | &ВедущаяТаблицаБезТочек КАК ТекущиеДанныеДляОтбора"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляТаблицы", - "ТекущиеДанныеДляОтбора." + СтрСоединить(Поля, ", - | ТекущиеДанныеДляОтбора.")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ВедущаяТаблицаБезТочек", ВедущаяТаблицаБезТочек); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВедущаяТаблицаБезТочек", "&" + ВедущаяТаблицаБезТочек); - - ОписаниеЗапросов = Новый Структура; - ОписаниеЗапросов.Вставить("ТипыПолей", ТипыПолей); - ОписаниеЗапросов.Вставить("ТекстЗапросаПараметров", ТекстЗапроса); - ОписаниеЗапросов.Вставить("ТекстыЗапросовДанных", Новый Массив); - - Для Каждого СоединениеОтбора Из СоединенияОтборов Цикл - ТекстЗапроса = ШаблонЗапроса + ТекстСОтступом(СоединениеОтбора, " "); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТекущиеДанныеДляОтбора", ВедущаяТаблицаБезТочек); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - ОписаниеЗапросов.ТекстыЗапросовДанных.Добавить(ТекстЗапроса); - КонецЦикла; - - Возврат ОписаниеЗапросов; - -КонецФункции - -// Для процедуры ДобавитьЗапросыПроверкиПоВедущимСпискам. -Процедура ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков(ВидВедущегоСписка, ШаблонЗапроса, Контекст) - - Свойства = ?(ВидВедущегоСписка = "ПоКлючамДоступа", - Контекст.ВедущиеСпискиПоКлючамДоступа, Контекст.ВедущиеСпискиПоЗначениямСГруппами); - - Если Не ЗначениеЗаполнено(Свойства.СоединенияОтборов) Тогда - Возврат; - КонецЕсли; - - ИмяВременнойТаблицы = "ТекущиеДанныеДляОтбора" + ВидВедущегоСписка; - - ТекстЗапросаПараметров = - "ВЫБРАТЬ - | ТекущиеДанныеДляОтбора.Ссылка - |ПОМЕСТИТЬ #ИмяВременнойТаблицы - |ИЗ - | &ВидВедущегоСписка КАК ТекущиеДанныеДляОтбора"; - ТекстЗапросаПараметров = СтрЗаменить(ТекстЗапросаПараметров, "#ИмяВременнойТаблицы", ИмяВременнойТаблицы); - ТекстЗапросаПараметров = СтрЗаменить(ТекстЗапросаПараметров, "&ВидВедущегоСписка", "&" + ВидВедущегоСписка); - - ТекстыЗапросовПоКлючам = Новый Соответствие; - Для Каждого СоединениеОтбора Из Свойства.СоединенияОтборов Цикл - ТекстЗапроса = ШаблонЗапроса + ТекстСОтступом(СоединениеОтбора.Значение, " "); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТекущиеДанныеДляОтбора", ИмяВременнойТаблицы); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - ТекстыЗапросовПоКлючам.Вставить(СоединениеОтбора.Ключ, ТекстЗапроса); - КонецЦикла; - - ОписаниеЗапросов = Новый Структура; - ОписаниеЗапросов.Вставить("ТипСсылки", Новый ХранилищеЗначения(Свойства.ТипСсылки)); - ОписаниеЗапросов.Вставить("КлючиЗапросовПоТипам", Свойства.КлючиЗапросовПоТипам); - ОписаниеЗапросов.Вставить("ТекстыЗапросовПоКлючам", ТекстыЗапросовПоКлючам); - ОписаниеЗапросов.Вставить("ТекстЗапросаПараметров", ТекстЗапросаПараметров); - - Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить(ВидВедущегоСписка, ОписаниеЗапросов); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура СобратьЧастиЗапросаПроверки(Результат, Контекст) - - ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаДиапазонаЭлементовДанных, Контекст); - Результат.ТекстЗапросаДиапазонаЭлементовДанных = Контекст.ТекстЗапросаДиапазонаЭлементовДанных; - - ЧастиЗапроса1 = Новый Массив; - ЧастиЗапроса2 = Новый Массив; - ЧастиЗапроса3 = Новый Массив; - Если Контекст.ЭтоСсылочныйТип Тогда - ЧастиЗапроса1.Добавить(Контекст.ТекстЗапросаПроверкиСвязи); - ЧастиЗапроса2.Добавить(Контекст.ТекстЗапросаТочечнойПроверкиСвязи); - ЧастиЗапроса3.Добавить(Контекст.ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта); - КонецЕсли; - - Для Каждого ЧастьУсловияПроверки Из Контекст.ЧастиУсловияПроверки Цикл - ДобавитьЧастьЗапроса(ЧастиЗапроса1, ЧастьУсловияПроверки, Контекст, - Контекст.ТекстЗапросаПроверкиШапки, - Контекст.ТекстЗапросаПроверкиТабличнойЧасти); - - ДобавитьЧастьЗапроса(ЧастиЗапроса2, ЧастьУсловияПроверки, Контекст, - Контекст.ТекстЗапросаТочечнойПроверкиШапки, - Контекст.ТекстЗапросаТочечнойПроверкиТабличнойЧасти); - - Если Контекст.ЭтоСсылочныйТип Тогда - ДобавитьЧастьЗапроса(ЧастиЗапроса3, ЧастьУсловияПроверки, Контекст, - Контекст.ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта, - Контекст.ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта); - КонецЕсли; - КонецЦикла; - - ТекстЧастейЗапроса = СтрСоединить(ЧастиЗапроса1, ОбщегоНазначения.ТекстОбъединитьВсе()); - ТекстЗапроса = СтрЗаменить(Контекст.ТекстЗапросаПроверки, ",&ДополнительныеПоля1", - ТекстСОтступом(Контекст.ИспользуемыеПоляОсновнойТаблицы, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ДополнительныеПоля2", - ТекстСОтступом(Контекст.ИспользуемыеПоляОсновнойТаблицы, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ЧастиЗапросаПроверки", - "(" + ТекстСОтступом(ТекстЧастейЗапроса, " ") + ")"); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами = ТекстЗапроса; - - ТекстЧастейЗапроса = СтрСоединить(ЧастиЗапроса2, ОбщегоНазначения.ТекстОбъединитьВсе()); - ТекстЗапроса = СтрЗаменить(Контекст.ТекстЗапросаТочечнойПроверки, "&ЧастиЗапросаПроверки", - "(" + ТекстСОтступом(ТекстЧастейЗапроса, " ") + ")"); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаТочечнойПроверки", ТекстЗапроса); - - Результат.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам = - Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам; - - Если Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапроса = СтрСоединить(ЧастиЗапроса3, ОбщегоНазначения.ТекстОбъединитьВсе()); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаПроверкиКлючаДоступаОбъекта = ТекстЗапроса; - Иначе - ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаНовыхКомбинаций, Контекст); - Результат.ТекстЗапросаЭлементовДанныхБезКлючейДоступа = Контекст.ТекстЗапросаНовыхКомбинаций; - - ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаТекущихКлючейДоступа, Контекст); - Результат.ТекстЗапросаТекущихКлючейДоступаРегистра = Контекст.ТекстЗапросаТекущихКлючейДоступа; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры СобратьЧастиЗапросаПроверки. -Процедура ДобавитьЧастьЗапроса(ЧастиЗапроса, ЧастьУсловияПроверки, Контекст, - ТекстДляШапки, ТекстДляТабличнойЧасти) - - Если ЗначениеЗаполнено(ЧастьУсловияПроверки.ИмяТабличнойЧастиКлюча) Тогда - ТекущийТекст = ТекстДляТабличнойЧасти; - Иначе - ТекущийТекст = ТекстДляШапки; - КонецЕсли; - - ТекущийТекст = СтрЗаменить(ТекущийТекст, ",&ДополнительныеПоля2", - ТекстСОтступом(ЧастьУсловияПроверки.ДополнительныеПоля, " ")); - - ТекущийТекст = СтрЗаменить(ТекущийТекст, " #Соединения", " - | " + ТекстСОтступом(ЧастьУсловияПроверки.Соединения, " ")); - - ТекущийТекст = СтрЗаменить(ТекущийТекст, - "ТабличнаяЧасть?", ЧастьУсловияПроверки.ИмяТабличнойЧастиКлюча); - - ЧастиЗапроса.Добавить(СтрЗаменить(ТекущийТекст, - "&УсловиеЗапроса", ТекстСОтступом(ЧастьУсловияПроверки.Условие, " "))); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура СобратьЧастиЗапросовЗаполнения(Результат, Контекст) - - ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзОбъектов, - ОбщегоНазначения.РазделительПакетаЗапросов()); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа = ТекстЗапроса; - - Если ЗначениеЗаполнено(Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти) Тогда - ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти, - ОбщегоНазначения.РазделительПакетаЗапросов()); - ИмяВременнойТаблицы = СтрЗаменить(Контекст.Список, ".", "_"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок.", ИмяВременнойТаблицы + "_"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", ИмяВременнойТаблицы); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа = ТекстЗапроса; - КонецЕсли; - - ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения, - ОбщегоНазначения.РазделительПакетаЗапросов()); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения = ТекстЗапроса; - Результат.ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения = СтрЗаменить(ТекстЗапроса, - ".НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1)", ".Список = &Список"); // @query-part-1 - - ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения, - ОбщегоНазначения.РазделительПакетаЗапросов()); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаСуществованияКлючейДляСравнения = ТекстЗапроса; - - ДобавитьЧастьЗапросаВыбораПравВедущихКлючейДоступа(Контекст); - ДобавитьЧастьЗапросаВыбораПравВедущихСписков(Контекст); - ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав(Контекст); - ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав, - ОбщегоНазначения.РазделительПакетаЗапросов()); - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Результат.ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав = ТекстЗапроса; - - Результат.ТекстЗапросаКлючейДоступаДляОбновленияПрав = - ТекстЗапросаКлючейДоступаДляОбновленияПрав(Контекст); - - Результат.ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав = - ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав(Контекст); - - Результат.ТекстЗапросаУстаревшихКлючейДоступа = - ТекстЗапросаУстаревшихКлючейДоступа(Контекст); - -КонецПроцедуры - -// Для процедуры СобратьЧастиЗапросовЗаполнения. -Процедура ДобавитьЧастьЗапросаВыбораПравВедущихКлючейДоступа(Контекст) - - Если Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Если Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Количество() = 1 Тогда - УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа[0]; - Иначе - УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа, - Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваНаСпискиВедущихКлючейДоступа.Таблица КАК Список, - | ПраваНаСпискиВедущихКлючейДоступа.ГруппаДоступа КАК ГруппаДоступа, - | ПраваНаСпискиВедущихКлючейДоступа.ПравоИзменение КАК ПравоИзменение - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСпискиВедущихКлючейДоступа - |ГДЕ - | ПраваНаСпискиВедущихКлючейДоступа.Таблица В - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | СпискиВедущихКлючейДоступа.Список - | ИЗ - | Справочник.КлючиДоступа КАК СпискиВедущихКлючейДоступа - | ГДЕ - | &УсловиеОтбора) - | И &УточнениеПланаЗапроса - |ИТОГИ ПО - | Список"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", - СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "СпискиВедущихКлючейДоступа.Ссылка")); - - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - - ТекстЗапроса = - "ВЫБРАТЬ - | СпискиВедущихКлючейДоступа.Ссылка КАК КлючДоступа, - | СпискиВедущихКлючейДоступа.Список КАК Список - |ИЗ - | Справочник.КлючиДоступа КАК СпискиВедущихКлючейДоступа - |ГДЕ - | &УсловиеОтбора - | И &УточнениеПланаЗапроса"; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", - СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "СпискиВедущихКлючейДоступа.Ссылка")); - - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - - Если Не Контекст.РассчитыватьПраваПользователей Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, - | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, - | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение - |ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа - |ГДЕ - | ТИПЗНАЧЕНИЯ(ПраваНаКлючиДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа) - | И &УсловиеОтбора - | И &УточнениеПланаЗапроса - |ИТОГИ ПО - | КлючДоступа"; - ИначеЕсли Не Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, - | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, - | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение - |ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа - |ГДЕ - | &УсловиеОтбора - | И &УточнениеПланаЗапроса - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ПраваНаКлючиДоступа.КлючДоступа, - | ПраваНаКлючиДоступа.Пользователь.Пользователь, - | ПраваНаКлючиДоступа.ПравоИзменение - |ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК ПраваНаКлючиДоступа - |ГДЕ - | ПраваНаКлючиДоступа.ЭтоПраваНабораГрупп = ЛОЖЬ - | И ЕСТЬNULL(ПраваНаКлючиДоступа.Пользователь.Пользователь, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | И &УсловиеОтбора - |ИТОГИ ПО - | КлючДоступа"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, - | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, - | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение - |ИЗ - | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа - |ГДЕ - | &УсловиеОтбора - | И &УточнениеПланаЗапроса - | - |ОБЪЕДИНИТЬ ВСЕ - | - |ВЫБРАТЬ - | ПраваНаКлючиДоступа.КлючДоступа, - | ПраваНаКлючиДоступа.ВнешнийПользователь.Пользователь, - | ПраваНаКлючиДоступа.ПравоИзменение - |ИЗ - | РегистрСведений.КлючиДоступаВнешнихПользователей КАК ПраваНаКлючиДоступа - |ГДЕ - | ПраваНаКлючиДоступа.ЭтоПраваНабораГрупп = ЛОЖЬ - | И ЕСТЬNULL(ПраваНаКлючиДоступа.ВнешнийПользователь.Пользователь, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) - | И &УсловиеОтбора - |ИТОГИ ПО - | КлючДоступа"; - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", - СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "ПраваНаКлючиДоступа.КлючДоступа")); - - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - -КонецПроцедуры - -// Для процедуры СобратьЧастиЗапросовЗаполнения. -Процедура ДобавитьЧастьЗапросаВыбораПравВедущихСписков(Контекст) - - Если Контекст.ЧастиУсловияВыбораПравВедущихСписков.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Если Контекст.Свойство("ЧастиУсловияВыбораПравВедущихСписковСТипами") Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваНаСписки.Таблица КАК Список, - | ТИПЗНАЧЕНИЯ(ПраваНаСписки.Таблица.ЗначениеПустойСсылки) КАК ТипЗначения, - | ПраваНаСписки.ГруппаДоступа КАК ВладелецПрав, - | ПраваНаСписки.ПравоИзменение КАК ПравоИзменение - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСписки - |ГДЕ - | &УсловиеОтбора - | И &УточнениеПланаЗапроса - |ИТОГИ ПО - | Список"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваНаСписки.Таблица КАК Список, - | ПраваНаСписки.ГруппаДоступа КАК ВладелецПрав, - | ПраваНаСписки.ПравоИзменение КАК ПравоИзменение - |ИЗ - | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСписки - |ГДЕ - | &УсловиеОтбора - | И &УточнениеПланаЗапроса - |ИТОГИ ПО - | Список"; - КонецЕсли; - - Если Контекст.ЧастиУсловияВыбораПравВедущихСписков.Количество() = 1 Тогда - УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравВедущихСписков[0]; - Иначе - УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияВыбораПравВедущихСписков, - Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 - КонецЕсли; - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "ПраваНаСписки.Таблица"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - -КонецПроцедуры - -// Для процедуры СобратьЧастиЗапросовЗаполнения. -Процедура ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав(Контекст) - - Если Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - ТекстЗапроса = ТекстЗапросаВыбораПравПоВладельцамНастроекПрав(); - - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - Если Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Количество() = 1 Тогда - УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав[0]; - Иначе - УсловиеОтбора = СтрСоединить(Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав, - Символы.ПС + " ИЛИ "); // @query-part-1 - КонецЕсли; - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "НаследованиеНастроек.Объект"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", ТекстСОтступом(УсловиеОтбора, " ")); - - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - -КонецПроцедуры - -// Для процедуры ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав и -// функции ТекстЗапросаПравПользователейПоВладельцамНастроекПрав. -// -Функция ТекстЗапросаВыбораПравПоВладельцамНастроекПрав() - - Возврат - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаследованиеНастроек.Объект КАК Объект - |ПОМЕСТИТЬ ОбъектыСЗапрещениемЧтения - |ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияЧтения) - | И (&УсловиеОтбора) - | И (&УточнениеПланаЗапроса) - | - |ИНДЕКСИРОВАТЬ ПО - | Объект - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаследованиеНастроек.Объект КАК Объект - |ПОМЕСТИТЬ ОбъектыСЗапрещениемИзменения - |ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) - | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения) - | И (&УсловиеОтбора) - | И (&УточнениеПланаЗапроса) - | - |ИНДЕКСИРОВАТЬ ПО - | Объект - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НастройкиПравЧтения.Объект КАК Объект, - | НастройкиПравЧтения.Пользователь КАК Пользователь - |ПОМЕСТИТЬ НастройкиПравЧтения - |ИЗ - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаследованиеНастроек.Объект КАК Объект, - | ВЫБОР - | КОГДА НаследованиеНастроек.Объект В - | (ВЫБРАТЬ - | ОбъектыСЗапрещениемЧтения.Объект - | ИЗ - | ОбъектыСЗапрещениемЧтения) - | ТОГДА СоставыГруппПользователей.Пользователь - | ИНАЧЕ СоставыГруппПользователей.ГруппаПользователей - | КОНЕЦ КАК Пользователь, - | ИСТИНА КАК ЧтениеРазрешено, - | ЛОЖЬ КАК ЧтениеЗапрещено - | ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияЧтения) - | И (&УсловиеОтбора) - | И (&УточнениеПланаЗапроса) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) - | И (СоставыГруппПользователей.Используется) - | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаследованиеНастроек.Объект, - | СоставыГруппПользователей.Пользователь, - | ЛОЖЬ, - | ИСТИНА - | ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО (НаследованиеНастроек.Объект В - | (ВЫБРАТЬ - | ОбъектыСЗапрещениемЧтения.Объект - | ИЗ - | ОбъектыСЗапрещениемЧтения)) - | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияЧтения) - | И (&УсловиеОтбора) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) - | И (СоставыГруппПользователей.Используется) - | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор)) КАК НастройкиПравЧтения - | - |СГРУППИРОВАТЬ ПО - | НастройкиПравЧтения.Объект, - | НастройкиПравЧтения.Пользователь - | - |ИМЕЮЩИЕ - | МАКСИМУМ(НастройкиПравЧтения.ЧтениеРазрешено) = ИСТИНА И - | МАКСИМУМ(НастройкиПравЧтения.ЧтениеЗапрещено) = ЛОЖЬ - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НастройкиПравИзменения.Объект КАК Объект, - | НастройкиПравИзменения.Пользователь КАК Пользователь - |ПОМЕСТИТЬ НастройкиПравИзменения - |ИЗ - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаследованиеНастроек.Объект КАК Объект, - | ВЫБОР - | КОГДА НаследованиеНастроек.Объект В - | (ВЫБРАТЬ - | ОбъектыСЗапрещениемИзменения.Объект - | ИЗ - | ОбъектыСЗапрещениемИзменения) - | ТОГДА СоставыГруппПользователей.Пользователь - | ИНАЧЕ СоставыГруппПользователей.ГруппаПользователей - | КОНЕЦ КАК Пользователь, - | ИСТИНА КАК ИзменениеРазрешено, - | ЛОЖЬ КАК ИзменениеЗапрещено - | ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) - | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияИзменения) - | И (&УсловиеОтбора) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) - | И (СоставыГруппПользователей.Используется) - | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НастройкиПравЧтения КАК НастройкиПравЧтения - | ПО (НастройкиПравЧтения.Объект = НаследованиеНастроек.Объект) - | И (НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.ГруппаПользователей - | ИЛИ НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.Пользователь) - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ РАЗЛИЧНЫЕ - | НаследованиеНастроек.Объект, - | СоставыГруппПользователей.Пользователь, - | ЛОЖЬ, - | ИСТИНА - | ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО (НаследованиеНастроек.Объект В - | (ВЫБРАТЬ - | ОбъектыСЗапрещениемИзменения.Объект - | ИЗ - | ОбъектыСЗапрещениемИзменения)) - | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) - | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения) - | И (&УсловиеОтбора) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) - | И (СоставыГруппПользователей.Используется) - | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НастройкиПравЧтения КАК НастройкиПравЧтения - | ПО (НастройкиПравЧтения.Объект = НаследованиеНастроек.Объект) - | И (НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.ГруппаПользователей - | ИЛИ НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.Пользователь)) КАК НастройкиПравИзменения - | - |СГРУППИРОВАТЬ ПО - | НастройкиПравИзменения.Объект, - | НастройкиПравИзменения.Пользователь - | - |ИМЕЮЩИЕ - | МАКСИМУМ(НастройкиПравИзменения.ИзменениеРазрешено) = ИСТИНА И - | МАКСИМУМ(НастройкиПравИзменения.ИзменениеЗапрещено) = ЛОЖЬ - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | НастройкиПрав.Объект КАК ВладелецНастроекПрав, - | НастройкиПрав.Пользователь КАК ВладелецПрав, - | МАКСИМУМ(НастройкиПрав.ПравоИзменение) КАК ПравоИзменение - |ИЗ - | (ВЫБРАТЬ - | НастройкиПрав.Объект КАК Объект, - | НастройкиПрав.Пользователь КАК Пользователь, - | ЛОЖЬ КАК ПравоИзменение - | ИЗ - | НастройкиПравЧтения КАК НастройкиПрав - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ - | НастройкиПрав.Объект, - | НастройкиПрав.Пользователь, - | ИСТИНА - | ИЗ - | НастройкиПравИзменения КАК НастройкиПрав) КАК НастройкиПрав - | - |СГРУППИРОВАТЬ ПО - | НастройкиПрав.Объект, - | НастройкиПрав.Пользователь - |ИТОГИ ПО - | ВладелецНастроекПрав"; - -КонецФункции - -// Для процедуры СобратьЧастиЗапросовЗаполнения. -Функция ТекстЗапросаКлючейДоступаДляОбновленияПрав(Контекст) - - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Список = &Список - | И КлючиДоступа.СоставПолей = &СоставПолей - | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступа.Ссылка"; - - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедуры СобратьЧастиЗапросовЗаполнения. -Функция ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав(Контекст) - - Если Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Количество() = 0 Тогда - Возврат ""; - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступа.Ссылка КАК Ссылка - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Список = &Список - | И КлючиДоступа.СоставПолей = &СоставПолей - | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И &УсловиеОтбора - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступа.Ссылка"; - - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Если Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Количество() = 1 Тогда - УсловиеОтбора = Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа[0]; - Иначе - УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа, - Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедуры СобратьЧастиЗапросовЗаполнения. -Функция ТекстЗапросаУстаревшихКлючейДоступа(Контекст) - - Если Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапросаИспользуемых = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК КлючДоступа - |ПОМЕСТИТЬ ИспользуемыеКлючиДоступа - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - |ГДЕ - | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) - | И КлючиДоступаКОбъектам.#КлючДоступаПользователей > &ПоследнийКлючДоступа - | И &УточнениеПланаЗапроса - | - |ИНДЕКСИРОВАТЬ ПО - | КлючДоступа"; // @query-part - Иначе - ТекстЗапросаИспользуемых = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа - |ПОМЕСТИТЬ ИспользуемыеКлючиДоступа - |ИЗ - | &ТекущийСписок КАК КлючиДоступаКРегистрам - |ГДЕ - | КлючиДоступаКРегистрам.Регистр = &Список - | И КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа - | И КлючиДоступаКРегистрам.КлючДоступа > &ПоследнийКлючДоступа - | И &УточнениеПланаЗапроса - | - |ИНДЕКСИРОВАТЬ ПО - | КлючДоступа"; - Если ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда - ТекстЗапросаИспользуемых = СтрЗаменить(ТекстЗапросаИспользуемых, - "КлючиДоступаКРегистрам.Регистр = &Список - | И ", ""); // @query-part-1 - КонецЕсли; - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 995 - | КлючиДоступа.Ссылка КАК Ссылка, - | КлючиДоступа.Список КАК Список, - | КлючиДоступа.СоставПолей КАК СоставПолей, - | КлючиДоступа.Хеш КАК Хеш, - | НЕ ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL КАК Используется, - | КлючиДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(1, 1, 1) - | И КлючиДоступа.НеИспользуетсяС < &ДатаУстаревания КАК Удалить - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - | ЛЕВОЕ СОЕДИНЕНИЕ ИспользуемыеКлючиДоступа КАК ИспользуемыеКлючиДоступа - | ПО (ИспользуемыеКлючиДоступа.КлючДоступа = КлючиДоступа.Ссылка) - |ГДЕ - | КлючиДоступа.Список = &Список - | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа - | И ВЫБОР - | КОГДА КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | ТОГДА ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL - | ИНАЧЕ НЕ ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL - | ИЛИ КлючиДоступа.НеИспользуетсяС < &ДатаУстаревания - | КОНЕЦ - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | КлючиДоступа.Ссылка"; - - ТекстЗапроса = ТекстЗапросаИспользуемых - + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; - - ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); - Возврат ТекстЗапроса; - -КонецФункции - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ЗаполнитьЗапросыПравПользователей(Результат, Контекст) - - Если Контекст.БезОбъектаМетаданных - Или Не Контекст.ЭтоСсылочныйТип - И Контекст.ИмяКоллекцииТипа <> "РегистрыСведений" - И Контекст.ИмяКоллекцииТипа <> "РегистрыНакопления" - И Контекст.ИмяКоллекцииТипа <> "РегистрыБухгалтерии" - И Контекст.ИмяКоллекцииТипа <> "РегистрыРасчета" Тогда - Возврат; - КонецЕсли; - - Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); - ТекстыЗапросов = Новый Массив; - ЧастиЗапроса = Новый Массив; - - Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа - Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда - - ТекстЗапроса = - "ВЫБРАТЬ - | НаборыПользователей.Пользователь КАК ПользовательСПравом, - | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | ТекущаяТаблица КАК ТекущаяТаблица - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) - | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа - | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыПользователей - | ПО (НаборыПользователей.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) - | И (ВЫБОР - | КОГДА НаборыПользователей.Ссылка = РазрешенныеКлючиДоступа.Пользователь - | ТОГДА ИСТИНА - | ИНАЧЕ НаборыПользователей.РазрешенныйНаборГруппПользователей = РазрешенныеКлючиДоступа.Пользователь - | КОНЕЦ) - | И (&ОтборПользователей1)"; - ЧастиЗапроса.Добавить(ТекстЗапроса); - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ - | НаборыПользователей.Пользователь КАК ПользовательСПравом, - | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | ТекущаяТаблица КАК ТекущаяТаблица - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) - | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа - | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыПользователей - | ПО (НаборыПользователей.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) - | И (НаборыПользователей.РазрешенныйНаборГруппДоступа = РазрешенныеКлючиДоступа.НаборГруппДоступа) - | И (&ОтборПользователей1)"; - ЧастиЗапроса.Добавить(ТекстЗапроса); - - ТекстЗапроса = - "ВЫБРАТЬ - | &РазрешенныйПустойНаборГруппДоступа КАК ПользовательСПравом, - | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | ТекущаяТаблица КАК ТекущаяТаблица - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) - | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа - | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) - | И (РазрешенныеКлючиДоступа.НаборГруппДоступа = &РазрешенныйПустойНаборГруппДоступа)"; - ЧастиЗапроса.Добавить(ТекстЗапроса); - - ТекстыЗапросов = Новый Массив; - УсловиеПроверкиТипаВладельцаНастроекПрав1 = "ИСТИНА"; - УсловиеПроверкиТипаВладельцаНастроекПрав2 = "ИСТИНА"; - - Если Не Результат.ИспользуетсяОграничениеПоВладельцу Тогда - ТипыВладельцевНастроекПравПоля = Неопределено; - Иначе - ТипКонечногоПоля = Контекст.СвойстваПолей[0].ТипКонечногоПоля; - ТипыВладельцевНастроекПравПоля = Новый Соответствие; - Если Контекст.ОграничениеДоступаВключено Тогда - Для Каждого КлючИЗначение Из Контекст.ТипыВладельцевНастроекПрав Цикл - Если ТипКонечногоПоля.СодержитТип(КлючИЗначение.Ключ) Тогда - ТипыВладельцевНастроекПравПоля.Вставить(КлючИЗначение.Ключ, - ИмяТипаНаЯзыкеЗапросов(КлючИЗначение.Ключ)); - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если ТипыВладельцевНастроекПравПоля.Количество() = 0 Тогда - ТипыВладельцевНастроекПравПоля = Неопределено; - - ИначеЕсли ТипКонечногоПоля.Типы().Количество() = ТипыВладельцевНастроекПравПоля.Количество() Тогда - ЧастиЗапроса.Очистить(); - Иначе - Условие1 = ""; - Условие2 = ""; - Для Каждого СвойстваТипа Из ТипыВладельцевНастроекПравПоля Цикл - Условие1 = Условие1 + ?(Условие1 = "", "", " - | И ") + "ТИПЗНАЧЕНИЯ(&ПолеОбъекта) <> ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 - Условие2 = Условие2 + ?(Условие2 = "", "", " - | ИЛИ ") + "ТИПЗНАЧЕНИЯ(&ПолеОбъекта) = ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 - КонецЦикла; - УсловиеПроверкиТипаВладельцаНастроекПрав1 = Условие1; - УсловиеПроверкиТипаВладельцаНастроекПрав2 = Условие2; - КонецЕсли; - КонецЕсли; - - Если ЗначениеЗаполнено(ТипыВладельцевНастроекПравПоля) Тогда - ДобавитьТекстЗапросаПравПользователейПоВладельцамНастроекПрав(Контекст.ДляВнешнихПользователей, - ЧастиЗапроса, ТекстыЗапросов); - КонецЕсли; - - ТекстЗапроса = - "ВЫБРАТЬ - | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, - | МАКСИМУМ(ПраваПользователей.ПравоИзменение) КАК ПравоИзменение, - | ПраваПользователей.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ПользователиСПравамиНаЭлементыДанных - |ИЗ - | (#ЧастиЗапроса) КАК ПраваПользователей - | - |СГРУППИРОВАТЬ ПО - | ПраваПользователей.Ссылка, - | ПраваПользователей.ПользовательСПравом"; // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ЧастиЗапроса", - ТекстСОтступом(СтрСоединить(ЧастиЗапроса, ОбщегоНазначения.ТекстОбъединитьВсе()), " ")); - - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", - "РегистрСведений.КлючиДоступаВнешнихПользователей"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", - "РазрешенныеКлючиДоступа.ВнешнийПользователь"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", - "Справочник.ВнешниеПользователи"); - - Если Контекст.ЭтоСсылочныйТип - Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", - "КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей"); - КонецЕсли; - КонецЕсли; - - ТекстыЗапросов.Добавить(ТекстЗапроса); - ТекстЗапроса = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); - - Если Контекст.ЭтоСсылочныйТип - Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав1", - УсловиеПроверкиТипаВладельцаНастроекПрав1); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав2", - УсловиеПроверкиТипаВладельцаНастроекПрав2); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав3", - ТекстСОтступом(УсловиеПроверкиТипаВладельцаНастроекПрав2, " ")); - КонецЕсли; - - Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда - Если Контекст.ЭтоСсылочныйТип Тогда - ПолеОбъекта = "Ссылка." + Результат.ПолеВладельца.Имя; - Иначе - ЧастиПоляВладельца = СтрРазделить(Результат.ПолеВладельца.Имя, "."); - ЧастиПоляВладельца[0] = "Ссылка"; - ПолеОбъекта = СтрСоединить(ЧастиПоляВладельца, "."); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеОбъекта", "ТекущаяТаблица." + ПолеОбъекта); - - ИначеЕсли Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеОбъекта", "ТекущаяТаблица.Ссылка"); - - Иначе - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "КлючиДоступаКОбъектам.Объект = &ПолеОбъекта", - "КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)"); // @query-part-1, @query-part-2 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - " И (&УсловиеПроверкиТипаВладельцаНастроекПрав1)", - " И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) - | И (&ОтборПоИзмерениям)"); // @query-part-1 @query-part-2 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", - "КлючиДоступаКРегистрам.КлючДоступа"); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам", "КлючиДоступаКРегистрам"); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "ТекущаяТаблица КАК ТекущаяТаблица", - Контекст.Список + " КАК ТекущаяТаблица"); // @query-part-1, @query-part-2 - - УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст); - - УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, Контекст.Список); - КонецЕсли; - - Результат.ТекстЗапросаПравПользователей = ТекстЗапроса; - -КонецПроцедуры - -// Для процедуры ЗаполнитьЗапросыПравПользователей. -Процедура УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, ПолноеИмяРегистра) - - ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); - - ИзмеренияДляВыбора = Новый Массив; - ИзмеренияДляГруппировки = Новый Массив; - Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл - УточненноеИмя = УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ОписаниеПоля.Имя); - ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %2", ОписаниеПоля.Имя, УточненноеИмя)); - ИзмеренияДляГруппировки.Добавить(СтрШаблон("ПраваПользователей.%1,", УточненноеИмя)); - КонецЦикла; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущаяТаблица.Ссылка КАК Ссылка", - СтрСоединить(ИзмеренияДляВыбора, ", - | ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка КАК Ссылка", - СтрЗаменить(СтрСоединить(ИзмеренияДляВыбора, ", - | "), "ТекущаяТаблица.", "ПраваПользователей.")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка,", - СтрСоединить(ИзмеренияДляГруппировки, " - | ")); - -КонецПроцедуры - -// Для процедуры УстановитьПоляИзмеренийДляВыбораИГруппировки -Функция УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ИмяПоля) - - Если ВРег(ИмяПоля) = ВРег("ПользовательСПравом") - Или ВРег(ИмяПоля) = ВРег("ПравоИзменение") Тогда - Возврат ИмяПоля + "_"; - КонецЕсли; - - Возврат ИмяПоля; - -КонецФункции - -// Для процедуры ЗаполнитьЗапросыПравПользователей. -Процедура ДобавитьТекстЗапросаПравПользователейПоВладельцамНастроекПрав(ДляВнешнихПользователей, - ЧастиЗапроса, ТекстыЗапросов) - - ТекстЗапроса = ТекстЗапросаВыбораПравПоВладельцамНастроекПрав(); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УточнениеПланаЗапроса", "ИСТИНА"); - - Если ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); - КонецЕсли; - - УсловиеОтбора = - "НаследованиеНастроек.Объект В - | (ВЫБРАТЬ - | &ПолеОбъекта - | ИЗ - | ТекущаяТаблица КАК ТекущаяТаблица - | ГДЕ - | &УсловиеПроверкиТипаВладельцаНастроекПрав3)"; // @query-part-1 - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - - ЗапросыПакета = СтрРазделить(ТекстЗапроса, ";"); - ЗапросыПакета.Удалить(ЗапросыПакета.Количество() - 1); - ТекстыЗапросов.Добавить(СокрП(СтрСоединить(ЗапросыПакета, ";"))); - - ТекстЗапроса = - "ВЫБРАТЬ - | СоставыГруппПользователей.Пользователь КАК ПользовательСПравом, - | ЛОЖЬ КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | НастройкиПравЧтения КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица - | ПО (НастройкиПрав.Объект = &ПолеОбъекта) - | И (&УсловиеПроверкиТипаВладельцаНастроекПрав2) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И (&ОтборПользователей2)"; - ЧастиЗапроса.Добавить(ТекстЗапроса); - - ТекстЗапроса = - "ВЫБРАТЬ - | СоставыГруппПользователей.Пользователь КАК ПользовательСПравом, - | ИСТИНА КАК ПравоИзменение, - | ТекущаяТаблица.Ссылка КАК Ссылка - |ИЗ - | НастройкиПравИзменения КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица - | ПО (НастройкиПрав.Объект = &ПолеОбъекта) - | И (&УсловиеПроверкиТипаВладельцаНастроекПрав2) - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И (&ОтборПользователей2)"; - ЧастиЗапроса.Добавить(ТекстЗапроса); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст) - - Если Контекст.ИмяКоллекцииТипа = "ЖурналыДокументов" Тогда - Возврат; - КонецЕсли; - - Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); - - Если Контекст.ЭтоСсылочныйТип - Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда - - Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа - Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - |ГДЕ - | КлючиДоступаКОбъектам.Объект = &Объект - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа - | ГДЕ - | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей - | И РазрешенныеКлючиДоступа.Пользователь В (&РазрешенныйПользователь, &РазрешенныйНаборГруппПользователей) - | И РазрешенныеКлючиДоступа.ПравоИзменение) - | ИЛИ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа - | ГДЕ - | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей - | И РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа) - | И РазрешенныеКлючиДоступа.ПравоИзменение))"; - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", - "РегистрСведений.КлючиДоступаВнешнихПользователей"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", - "РазрешенныеКлючиДоступа.ВнешнийПользователь"); - КонецЕсли; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа - | ПО (КлючиДоступаКОбъектам.Объект = &Объект) - | И (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) - | И (РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа)) - | И (РазрешенныеКлючиДоступа.ПравоИзменение)"; - КонецЕсли; - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", - "КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей"); - КонецЕсли; - КонецЕсли; - - Если Не Результат.ИспользуетсяОграничениеПоВладельцу Тогда - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = ""; - Иначе - ТипКонечногоПоля = Контекст.СвойстваПолей[0].ТипКонечногоПоля; - ТипыВладельцевНастроекПравПоля = Новый Соответствие; - Если Контекст.ОграничениеДоступаВключено Тогда - Для Каждого КлючИЗначение Из Контекст.ТипыВладельцевНастроекПрав Цикл - Если ТипКонечногоПоля.СодержитТип(КлючИЗначение.Ключ) Тогда - ТипыВладельцевНастроекПравПоля.Вставить(КлючИЗначение.Ключ, - ИмяТипаНаЯзыкеЗапросов(КлючИЗначение.Ключ)); - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если ТипыВладельцевНастроекПравПоля.Количество() = 0 Тогда - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = ""; - - ИначеЕсли ТипКонечногоПоля.Типы().Количество() = ТипыВладельцевНастроекПравПоля.Количество() Тогда - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав(); - Иначе - Если Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ГДЕ - | ВЫБОР - | КОГДА &УсловиеПроверкиТипаВладельцаНастроекПрав - | ТОГДА &УсловиеСПроверкойПоВладельцамНастроекПрав - | ИНАЧЕ ИСТИНА В - | (&ТекстЗапросаСтандартнойПроверки) - | КОНЕЦ"; - Иначе - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ЛОЖЬ КАК ЗначениеЛожь - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | &ОтборПоИзмерениям - | И ВЫБОР - | КОГДА &УсловиеПроверкиТипаВладельцаНастроекПрав - | ТОГДА &УсловиеСПроверкойПоВладельцамНастроекПрав - | ИНАЧЕ ИСТИНА В - | (&ТекстЗапросаСтандартнойПроверки) - | КОНЕЦ"; - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, - "&ТекущаяТаблица", Контекст.Список) - КонецЕсли; - УсловиеПроверкиТипа = ""; - Для Каждого СвойстваТипа Из ТипыВладельцевНастроекПравПоля Цикл - УсловиеПроверкиТипа = УсловиеПроверкиТипа + ?(УсловиеПроверкиТипа = "", "", " - | ИЛИ ") + "ТИПЗНАЧЕНИЯ(&Объект) = ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 - КонецЦикла; - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, - "&УсловиеПроверкиТипаВладельцаНастроекПрав", - УсловиеПроверкиТипа); - - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, - "&УсловиеСПроверкойПоВладельцамНастроекПрав", - ТекстСОтступом(УсловиеИзЗапросаСПроверкойПоВладельцамНастроекПрав(), - " ")); - - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, - "&ТекстЗапросаСтандартнойПроверки", - ТекстСОтступом(ТекстЗапроса, " ")); - КонецЕсли; - КонецЕсли; - - Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда - Если Контекст.ЭтоСсылочныйТип Тогда - ПолеОбъекта = "ВЫРАЗИТЬ(&Объект КАК " + Контекст.Список + ")." + Результат.ПолеВладельца.Имя; // @query-part-1 - Результат.ПолеОбъектаВладельцаВЗапросеПроверкиПрав = ПолеОбъекта; - Иначе - ПолеОбъекта = "ТекущаяТаблица." + Результат.ПолеВладельца.Имя; - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Объект", ПолеОбъекта); - ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = - СтрЗаменить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, "&Объект", ПолеОбъекта); - - ИначеЕсли Не Контекст.ЭтоСсылочныйТип Тогда - - Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа - Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - |ГДЕ - | КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка) - | И КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1 - | И (ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа - | ГДЕ - | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа - | И РазрешенныеКлючиДоступа.Пользователь В (&РазрешенныйПользователь, &РазрешенныйНаборГруппПользователей) - | И РазрешенныеКлючиДоступа.ПравоИзменение) - | ИЛИ ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа - | ГДЕ - | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа - | И РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа) - | И РазрешенныеКлючиДоступа.ПравоИзменение))"; - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", - "РегистрСведений.КлючиДоступаВнешнихПользователей"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", - "РазрешенныеКлючиДоступа.ВнешнийПользователь"); - КонецЕсли; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа - | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) - | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) - | И (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа) - | И (РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа)) - | И (РазрешенныеКлючиДоступа.ПравоИзменение)"; - КонецЕсли; - - УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст); - - ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ТекущаяТаблицаПоле1 КАК Поле1 - |ИЗ - | &Список КАК ТекущаяТаблица - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) - | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) - |ГДЕ - | &ОтборПоИзмерениям - | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; - ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей = - "ВЫБРАТЬ - | &ТекущаяТаблицаПоле1 КАК ТекущаяТаблицаПоле1 - |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей - |ИЗ - | &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ТекущаяТаблицаПоле1 КАК Поле1 - |ИЗ - | КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица - | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам - | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) - | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) - |ГДЕ - | КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; - УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей, - Результат, Контекст, Истина); - УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей, - Результат, Контекст, Истина); - - Результат.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей = - ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей; - Результат.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей = - ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей; - КонецЕсли; - - Если Не Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапросаРегистра = - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ЛОЖЬ КАК ЗначениеЛожь - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | &ОтборПоИзмерениям - | И НЕ ИСТИНА В - | (&УсловиеЗапроса)"; - ТекстЗапросаРегистра = СтрЗаменить(ТекстЗапросаРегистра, "&ТекущаяТаблица", Контекст.Список); - ТекстЗапроса = СтрЗаменить(ТекстЗапросаРегистра, "&УсловиеЗапроса", ТекстСОтступом(ТекстЗапроса, " ")); - КонецЕсли; - - Если ЗначениеЗаполнено(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав) Тогда - Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = ТекстЗапросаСПроверкойПоВладельцамНастроекПрав; - Иначе - Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = ТекстЗапроса; - КонецЕсли; - - Если Не Результат.ОграничениеЧтенияОтключено Тогда - Результат.ТекстЗапросаПроверкиПраваЧтение = СтрЗаменить(ТекстЗапроса, - "РазрешенныеКлючиДоступа.ПравоИзменение", "Истина"); - КонецЕсли; - - Если Результат.ИспользуетсяОграничениеПоВладельцу - И Результат.ПолеВладельца.ИзменениеКакЧтение Тогда - - Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = Результат.ТекстЗапросаПроверкиПраваЧтение; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. -Функция УсловиеИзЗапросаСПроверкойПоВладельцамНастроекПрав() - - Строки = СтрРазделить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав(), Символы.ПС, ""); - Строки.Удалить(0); - Строки.Удалить(0); - Строки.Удалить(0); - - Возврат СокрЛП(СтрСоединить(Строки, Символы.ПС)); - -КонецФункции - -// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. -Функция ТекстЗапросаСПроверкойПоВладельцамНастроекПрав() - - Возврат - "ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА КАК ЗначениеИстина - |ГДЕ - | ИСТИНА В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ИСТИНА - | ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО - | НаследованиеНастроек.Объект = &Объект - | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав - | И НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияИзменения - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО - | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь - | И СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) - | И НЕ ЛОЖЬ В - | (ВЫБРАТЬ ПЕРВЫЕ 1 - | ЛОЖЬ - | ИЗ - | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек - | ПО - | НаследованиеНастроек.Объект = &Объект - | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель - | И НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав - | И НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей - | ПО - | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь - | И СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь)"; - -КонецФункции - -// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. -Процедура УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст, ДобавитьПоляВыбора = Ложь) - - Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "РегистрСведений.КлючиДоступаКРегистрам", - "РегистрСведений." + Результат.ИмяОтдельногоРегистраКлючей); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)", // @query-part-1 - "ИСТИНА"); - Иначе - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "ИдентификаторыОбъектовМетаданных.ПустаяСсылка", - УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных( - Контекст.Список)); - КонецЕсли; - - ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); - Если ИспользуемыеВариантыДоступа = Неопределено Тогда - ИспользуемыйВариантДоступа = НовыйИспользуемыйВариантДоступа(); - ИспользуемыйВариантДоступа.ВариантДоступа = Результат.ВариантДоступа; - ИспользуемыйВариантДоступа.ПоляСоединения = СтрСоединить(Результат.ОпорныеПоля.Используемые, ","); - ИспользуемыеВариантыДоступа = Новый Массив; - ИспользуемыеВариантыДоступа.Добавить(ИспользуемыйВариантДоступа); - КонецЕсли; - Если ДобавитьПоляВыбора Тогда - ИспользуемыйВариантДоступа = ИспользуемыеВариантыДоступа[0]; - ИспользуемыеВариантыДоступа = Новый Массив; - ИспользуемыеВариантыДоступа.Добавить(ИспользуемыйВариантДоступа); - КонецЕсли; - - УсловияОтбора = Новый Массив; - УсловияСоединения = Новый Массив; - Для Каждого ИспользуемыйВариантДоступа Из ИспользуемыеВариантыДоступа Цикл - Условие = Новый Массив; - ВариантДоступаСтрокой = XMLСтрока(ИспользуемыйВариантДоступа.ВариантДоступа); - ВариантДоступаСтрокой = ?(ЗначениеЗаполнено(ВариантДоступаСтрокой), ВариантДоступаСтрокой, "NULL"); - Условие.Добавить("КлючиДоступаКРегистрам.ВариантДоступа = " + ВариантДоступаСтрокой); - НомерПоля = 1; - ИменаПолей = СтрРазделить(ИспользуемыйВариантДоступа.ПоляСоединения, ",", Ложь); - Для Каждого ИмяПоля Из ИменаПолей Цикл - Условие.Добавить(СтрШаблон("КлючиДоступаКРегистрам.Поле%1 = ТекущаяТаблица.%2", НомерПоля, ИмяПоля)); - НомерПоля = НомерПоля + 1; - КонецЦикла; - Если ИспользуемыеВариантыДоступа.Количество() = 1 Тогда - УсловияОтбора.Добавить("И " + СтрСоединить(Условие, Символы.ПС + "И ")); // @query-part-1, @query-part-2 - УсловияСоединения.Добавить("И (" + СтрСоединить(Условие, ")" + Символы.ПС + "И (") + ")"); // @query-part-1, @query-part-3 - Иначе - УсловияОтбора.Добавить(СтрСоединить(Условие, Символы.ПС + " И ")); - УсловияСоединения.Добавить(СтрСоединить(Условие, Символы.ПС + " И ")); - КонецЕсли; - КонецЦикла; - - Если ИспользуемыеВариантыДоступа.Количество() = 1 Тогда - УсловиеОтбора = УсловияОтбора[0]; - УсловиеСоединения = УсловияСоединения[0]; - Иначе - УсловиеОтбора = "И (" + СтрСоединить(УсловияОтбора, Символы.ПС + " ИЛИ ") + ")"; // @query-part-1, @query-part-2 - УсловиеСоединения = "И (" + СтрСоединить(УсловияСоединения, Символы.ПС + " ИЛИ ") + ")"; // @query-part-1, @query-part-2 - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "И КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1", - ТекстСОтступом(СокрЛ(УсловиеОтбора), " ")); // @query-part-1 - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1)", - ТекстСОтступом(СокрЛ(УсловиеСоединения), " ")); // @query-part-1 - - Если Не ДобавитьПоляВыбора Тогда - Возврат; - КонецЕсли; - - ОпорныеПоля = ""; - ПоляВыбора = ""; - НомерПоля = 1; - Для Каждого Поле Из Результат.ОпорныеПоля.Используемые Цикл - ОпорныеПоля = ОпорныеПоля + ?(ОпорныеПоля = "", "", "," + Символы.ПС) - + СтрШаблон("ТекущаяТаблица.%1 КАК %1", Поле); // @query-part-4 - ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", "," + Символы.ПС) - + СтрШаблон("ТекущаяТаблица.%2 КАК Поле%1", НомерПоля, Поле); // @query-part-4 - НомерПоля = НомерПоля + 1; - КонецЦикла; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "&ТекущаяТаблицаПоле1 КАК ТекущаяТаблицаПоле1", - ТекстСОтступом(СокрЛ(ОпорныеПоля), " ")); // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, - "&ТекущаяТаблицаПоле1 КАК Поле1", - ТекстСОтступом(СокрЛ(ПоляВыбора), " ")); // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Список", Контекст.Список); - -КонецПроцедуры - -// Для функции СобратьЧастиЗапросов. -Процедура ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст) - - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователейКОбъекту", "КлючДоступаВнешнихПользователей"); - Иначе - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователейКОбъекту", "КлючДоступаПользователей"); - КонецЕсли; - - Если Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Контекст.Список); - - Если Контекст.ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступаВнешнихПользователей"); - Иначе - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступаПользователей"); - КонецЕсли; - Иначе - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистр", Контекст.Список); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок.Регистр = &ИдентификаторРегистра", "#1"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок.ВариантДоступа = &ВариантДоступа", "#2"); - Номер = 0; - Для Каждого ИмяОпорногоПоля Из Контекст.ОпорныеПоля.Используемые Цикл - Номер = Номер + 1; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, СтрШаблон("ТекущийСписок.%1", ИмяОпорногоПоля), - СтрШаблон("ТекущийСписок.Поле%1", Номер)); - КонецЦикла; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#1", "ТекущийСписок.Регистр = &ИдентификаторРегистра"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#2", "ТекущийСписок.ВариантДоступа = &ВариантДоступа"); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", ?(Контекст.ИмяОтдельногоРегистраКлючей = "", - "РегистрСведений.КлючиДоступаКРегистрам", "РегистрСведений." + Контекст.ИмяОтдельногоРегистраКлючей)); - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступа"); - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СоставПолей", Формат(Контекст.СоставПолей, "ЧН=0; ЧГ=")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВариантДоступа", XMLСтрока(Контекст.ВариантДоступа)); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДляВнешнихПользователей", - ?(Контекст.ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ")); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьПроверкуШапкиКлюча(Контекст, НомерШапки) - - ГруппаПолей = Контекст.ГруппыПолей.Получить(СтрШаблон("Шапка%1", НомерШапки)); - Если ГруппаПолей = Неопределено Тогда - Если НомерШапки > 0 Тогда - Возврат; - КонецЕсли; - СоединенияИПоля = Новый Структура("Соединения, Поля", "", ""); - Иначе - СоединенияИПоля = СоединенияИПоляПоТаблицам(ГруппаПолей, - Ложь, НомерШапки).Получить("ТекущийСписок"); - КонецЕсли; - - Если НомерШапки = 0 Тогда - Соединения = СоединенияИПоля.Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа КАК Шапка0 - |ПО (Шапка0.Ссылка = ТекущийСписок.ТекущийКлючДоступа)" - + ?(Контекст.СоставПолей = 0, " - | И (Шапка0.Список = &Список)", "") - + " - | И (Шапка0.СоставПолей = &СоставПолей)"; // @query-part-1, @query-part-2, @query-part-4 - Иначе - Соединения = СоединенияИПоля.Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа.Шапка КАК Шапка? - |ПО (Шапка?.Ссылка = ТекущийСписок.ТекущийКлючДоступа) - | И (Шапка?.НомерСтроки = &НомерШапки)"; // @query-part-1 - Соединения = СтрЗаменить(Соединения, "&НомерШапки", НомерШапки); - КонецЕсли; - - Соединения = СокрЛ(Соединения) + ТекстСОтступом(СоединенияИПоля.Поля, " "); - Условие = "Шапка?.Ссылка ЕСТЬ NULL"; // @query-part-1 - - Соединения = СтрЗаменить(Соединения, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); - Условие = СтрЗаменить(Условие, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); - - Контекст.ЧастиУсловияПроверки.Добавить(ЧастьУсловияПроверки(Соединения, Условие, - Контекст.ИспользуемыеПоляОсновнойТаблицы)); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьПроверкуТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча) - - ТаблицыПоГруппам = Контекст.ГруппыДополнительныхТаблиц.ТаблицыПоГруппам; - ГруппаДополнительныхТаблиц = ТаблицыПоГруппам.Получить(НомерТабличнойЧастиКлюча - - (Контекст.КоличествоТабличныхЧастейКлюча - ТаблицыПоГруппам.Количество())); - - ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); - ГруппаПолей = Контекст.ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); - - СоединенияИПоляПоТаблицам = СоединенияИПоляПоТаблицам(ГруппаПолей, Истина); - - Соединения = ""; - Поля = ""; - - Если ГруппаДополнительныхТаблиц = Неопределено Тогда - ПсевдонимТабличнойЧастиОбъекта = Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча); - Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить("ТекущийСписок"); - Иначе - ИмяТабличнойЧастиОбъекта = СтрЗаменить(ПсевдонимТабличнойЧастиОбъекта, "ТекущийСписок", ""); - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ПсевдонимТабличнойЧастиОбъекта); - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок." + ИмяТабличнойЧастиОбъекта + " КАК " + ПсевдонимТабличнойЧастиОбъекта + " - |ПО " + ПсевдонимТабличнойЧастиОбъекта + ".Ссылка = ТекущийСписок.Ссылка"; // @query-part-1, @query-part-2, @query-part-3, @query-part-4 - КонецЕсли; - Соединения = Соединения + СоединенияИПоля.Соединения; - Поля = СоединенияИПоля.Поля; - Иначе - Для Каждого ДополнительнаяТаблица Из ГруппаДополнительныхТаблиц Цикл - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " - |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3 - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ДополнительнаяТаблица.Псевдоним); - Если СоединенияИПоля = Неопределено Тогда - Продолжить; - КонецЕсли; - Соединения = Соединения + СоединенияИПоля.Соединения; - Поля = Поля + СоединенияИПоля.Поля; - КонецЦикла; - КонецЕсли; - - // Прямое соединение (проверка наличия требуемых записей в ключе). - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - |ПО (ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа)"; // @query-part - Соединения = СокрЛ(Соединения) + ТекстСОтступом(Поля, " "); - Условие = "ТабличнаяЧасть?.Ссылка ЕСТЬ NULL"; // @query-part-1 - - Соединения = СтрЗаменить(Соединения, "ТабличнаяЧасть?", ИмяТабличнойЧастиКлюча); - Условие = СтрЗаменить(Условие, "ТабличнаяЧасть?", ИмяТабличнойЧастиКлюча); - - ДополнительныеПоля = ""; - Если Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча) = Неопределено Тогда - ДополнительныеПоля = Контекст.ИспользуемыеПоляОсновнойТаблицы; - КонецЕсли; - - Контекст.ЧастиУсловияПроверки.Добавить(ЧастьУсловияПроверки(Соединения, - Условие, ДополнительныеПоля, ИмяТабличнойЧастиКлюча)); - -КонецПроцедуры - -// Для процедур ДобавитьПроверкуШапкиКлюча, ДобавитьПроверкуТабличнойЧастиКлюча. -// -// Возвращаемое значение: -// Структура: -// * Соединения - Строка -// * Условие - Строка -// * ДополнительныеПоля - Строка -// * ИмяТабличнойЧастиКлюча - Строка -// -Функция ЧастьУсловияПроверки(Соединения, Условие, ДополнительныеПоля, ИмяТабличнойЧастиКлюча = "") - - Результат = Новый Структура; - Результат.Вставить("Соединения", Соединения); - Результат.Вставить("Условие", Условие); - Результат.Вставить("ИмяТабличнойЧастиКлюча", ИмяТабличнойЧастиКлюча); - Результат.Вставить("ДополнительныеПоля", ДополнительныеПоля); - - Возврат Результат; - -КонецФункции - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьЗаполнениеШапкиКлюча(Контекст, НомерШапки) - - Если Не Контекст.ЭтоСсылочныйТип И НомерШапки = 0 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка, - | &ОпорныеПоляДляВыбора - |ПОМЕСТИТЬ ТекущийСписок - |ИЗ - | &ЗначенияОпорныхПолей КАК ТекущийСписок"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", Контекст.ОпорныеПоля.ДляВыбора); - Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); - - ИначеЕсли НомерШапки = 0 Тогда - Для Каждого ОписаниеТаблицы Из Контекст.ПоляТаблицОбъекта.Результат Цикл - ТекстЗапроса = - "ВЫБРАТЬ - | &ПоляТаблицы - | ПОМЕСТИТЬ #ПолноеИмяТаблицы - |ИЗ - | &ПолноеИмяТаблицы КАК ТекущаяТаблица"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляТаблицы", - "ТекущаяТаблица." + СтрСоединить(ОписаниеТаблицы.Поля, ", - | ТекущаяТаблица.")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ПолноеИмяТаблицы", ОписаниеТаблицы.ПолноеИмяТаблицы); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяТаблицы", "&" + ОписаниеТаблицы.ПолноеИмяТаблицы); - Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить(ТекстЗапроса); - КонецЦикла; - КонецЕсли; - - ГруппаПолей = Контекст.ГруппыПолей.Получить(СтрШаблон("Шапка%1", НомерШапки)); - Если ГруппаПолей = Неопределено Тогда - Возврат; - КонецЕсли; - ДобавитьОписаниеТаблицыКлюча(СтрШаблон("Шапка%1", НомерШапки), ГруппаПолей, Контекст); - - СоединенияИПоля = СоединенияИПоляПоТаблицам(ГруппаПолей, Ложь, - НомерШапки, Истина).Получить("ТекущийСписок"); - - // Выбор значений из объектов для поиска и создания ключей доступа. - Если Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляЗапроса - |ИЗ - | &ТекущийСписок КАК ТекущийСписок #Соединения - |ГДЕ - | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка,&ПоляЗапроса - |ИЗ - | ТекущийСписок КАК ТекущийСписок #Соединения - |ГДЕ - | &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка,&ОпорныеПоляДляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", Контекст.ОпорныеПоля.ДляУпорядочения); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляЗапроса", ТекстСОтступом(СоединенияИПоля.Поля, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(СоединенияИПоля.Соединения, " ")); - - Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); - Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить(ТекстЗапроса); - - // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. - Если НомерШапки = 0 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | Шапка0.Ссылка КАК ТекущаяСсылка,&Реквизиты - |ИЗ - | Справочник.КлючиДоступа КАК Шапка0 - |ГДЕ - | Шапка0.Хеш В(&Хеши) - | И Шапка0.Список = &Список - | И Шапка0.СоставПолей = &СоставПолей - | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И Шапка0.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка - |ИТОГИ ПО - | ТекущаяСсылка"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | Шапка?.Ссылка КАК ТекущаяСсылка,&Реквизиты - |ИЗ - | Справочник.КлючиДоступа.Шапка КАК Шапка? - |ГДЕ - | Шапка?.НомерСтроки = &НомерШапки - | И Шапка?.Ссылка.Хеш В(&Хеши) - | И Шапка?.Ссылка.Список = &Список - | И Шапка?.Ссылка.СоставПолей = &СоставПолей - | И Шапка?.Ссылка.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И Шапка?.Ссылка.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&НомерШапки", НомерШапки); - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(СоединенияИПоля.Реквизиты, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); - Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); - - // Проверка существования ключа доступа перед записью нового ключа. - Если НомерШапки = 0 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | Справочник.КлючиДоступа КАК Шапка0 - |ГДЕ - | Шапка0.Хеш = &Хеш - | И Шапка0.Список = &Список - | И Шапка0.СоставПолей = &СоставПолей - | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И &УточнениеПланаЗапроса"; - Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения.Добавить(ТекстЗапроса); - КонецЕсли; - - // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. - ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, НомерШапки); - - // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. - Если НомерШапки = 0 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | КлючиДоступа.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ПорцияКлючей - |ИЗ - | &КлючиДоступа КАК КлючиДоступа - | - |ИНДЕКСИРОВАТЬ ПО - | Ссылка"; - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - КонецЕсли; - - Если НомерШапки = 0 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты - |ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка0 - | ПО - | Шапка0.Ссылка = ПорцияКлючей.Ссылка - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | Ссылка - |ИТОГИ ПО - | Ссылка"; // @query-part - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты - |ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.Шапка КАК Шапка? - | ПО - | Шапка?.Ссылка = ПорцияКлючей.Ссылка - | И &УсловиеНомераШапки - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | Ссылка - |ИТОГИ ПО - | Ссылка"; // @query-part - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеНомераШапки", - СтрШаблон("Шапка%1.НомерСтроки = %1", НомерШапки)); - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(СоединенияИПоля.Реквизиты, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - - // Условие отбора прав ведущих ключей доступа. - ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВедущихКлючей"); - - // Условие отбора прав ведущих списков. - ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВедущихСписков"); - - // Условие отбора прав по владельцам настроек прав. - ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВладельцевНастроекПрав"); - -КонецПроцедуры - -// Для процедуры ДобавитьЗаполнениеШапкиКлюча. -Процедура ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, НазначениеУсловия) - - // Условие выбора прав ведущих ключей доступа. - Для Каждого СвойстваПоля Из ГруппаПолей Цикл - Если НазначениеУсловия = "ДляВедущихКлючей" - И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 - Или НазначениеУсловия = "ДляВедущихСписков" - И Не СвойстваПоля.ЕстьТипВедущегоСписка - Или НазначениеУсловия = "ДляВладельцевНастроекПрав" - И Не СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда - Продолжить; - КонецЕсли; - - Если НазначениеУсловия = "ДляВедущихСписков" - И СвойстваПоля.ТипыСохраненияЗначений.Количество() > 0 Тогда - - Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписковСТипами"); - УсловиеОтбора = - "#ПроверяемоеПоле В - | (ВЫБРАТЬ - | ЕСТЬNULL(ТипыКонфигурации.Ссылка, ЕСТЬNULL(ТипыРасширений.Ссылка, Шапка?.Реквизит?)) - | ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка? - | ПО - | Шапка?.Ссылка = ПорцияКлючей.Ссылка - | - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации - | ПО - | Шапка?.Реквизит? <> НЕОПРЕДЕЛЕНО - | И ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовМетаданных) - | И ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовРасширений) - | И ТИПЗНАЧЕНИЯ(ТипыКонфигурации.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) - | - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений - | ПО - | Шапка?.Реквизит? <> НЕОПРЕДЕЛЕНО - | И ТИПЗНАЧЕНИЯ(ТипыРасширений.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?))"; // @query-part-1 - Иначе - УсловиеОтбора = - "#ПроверяемоеПоле В - | (ВЫБРАТЬ - | Шапка?.Реквизит? - | ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка? - | ПО - | Шапка?.Ссылка = ПорцияКлючей.Ссылка)"; // @query-part-1 - КонецЕсли; - Если НомерШапки > 0 Тогда - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, - "Справочник.КлючиДоступа КАК Шапка?", "Справочник.КлючиДоступа.Шапка КАК Шапка?"); // @query-part-1, @query-part-2 - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, - "Шапка?.Ссылка = ПорцияКлючей.Ссылка", ТекстСОтступом( - "Шапка?.Ссылка = ПорцияКлючей.Ссылка" + СтрШаблон(" - | И Шапка?.НомерСтроки = %1", НомерШапки), " ")); // @query-part-3 - КонецЕсли; - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Реквизит?", СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); - - Если НазначениеУсловия = "ДляВедущихКлючей" Тогда - Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Добавить(УсловиеОтбора); - - ИначеЕсли НазначениеУсловия = "ДляВедущихСписков" Тогда - Контекст.ЧастиУсловияВыбораПравВедущихСписков.Добавить(УсловиеОтбора); - Иначе - Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Добавить(УсловиеОтбора); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьВыборКлючейБезПолейВШапке(Контекст) - - Если Контекст.ГруппыПолей.Получить("Шапка0") <> Неопределено Тогда - Возврат; - КонецЕсли; - - // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. - ТекстЗапроса = - "ВЫБРАТЬ - | КлючиДоступа.Ссылка КАК ТекущаяСсылка - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Хеш В(&Хеши) - | И КлючиДоступа.Список = &Список - | И КлючиДоступа.СоставПолей = &СоставПолей - | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка"; - - Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); - - // Проверка существования ключа доступа перед записью нового ключа. - ТекстЗапроса = - "ВЫБРАТЬ - | ИСТИНА КАК ЗначениеИстина - |ИЗ - | Справочник.КлючиДоступа КАК Шапка0 - |ГДЕ - | Шапка0.Хеш = &Хеш - | И Шапка0.Список = &Список - | И Шапка0.СоставПолей = &СоставПолей - | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И &УточнениеПланаЗапроса"; - Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения.Добавить(ТекстЗапроса); - - // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. - ТекстЗапроса = - "ВЫБРАТЬ - | КлючиДоступа.Ссылка КАК Ссылка - |ПОМЕСТИТЬ ПорцияКлючей - |ИЗ - | &КлючиДоступа КАК КлючиДоступа - | - |ИНДЕКСИРОВАТЬ ПО - | Ссылка"; - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - -КонецПроцедуры - -// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. -Процедура ДобавитьЗаполнениеТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча) - - ТаблицыПоГруппам = Контекст.ГруппыДополнительныхТаблиц.ТаблицыПоГруппам; - ГруппаДополнительныхТаблиц = ТаблицыПоГруппам.Получить(НомерТабличнойЧастиКлюча - - (Контекст.КоличествоТабличныхЧастейКлюча - ТаблицыПоГруппам.Количество())); - - ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); - ГруппаПолей = Контекст.ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); - - ДобавитьОписаниеТаблицыКлюча(ИмяТабличнойЧастиКлюча, ГруппаПолей, Контекст); - - СоединенияИПоляПоТаблицам = СоединенияИПоляПоТаблицам(ГруппаПолей, Истина, , Истина); - - // Выбор значений из объектов для поиска и создания ключей доступа. - Если ГруппаДополнительныхТаблиц = Неопределено Тогда - ПсевдонимТабличнойЧастиОбъекта = Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча); - Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить("ТекущийСписок"); - Иначе - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ПсевдонимТабличнойЧастиОбъекта); - КонецЕсли; - ПоляВыбора = СоединенияИПоля.Поля; - Соединения = СоединенияИПоля.Соединения; - ПоляУпорядочения = СоединенияИПоля.ПоляУпорядочения; - Реквизиты = СоединенияИПоля.Реквизиты; - Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора - |ИЗ - | &ТекущийСписок КАК ТекущийСписок #Соединения - |ГДЕ - | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка,&ПоляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - Иначе - ИмяТабличнойЧастиОбъекта = СтрЗаменить(ПсевдонимТабличнойЧастиОбъекта, "ТекущийСписок", ""); - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора - |ИЗ - | &ТекущийСписок КАК ТекущийСписок - | ЛЕВОЕ СОЕДИНЕНИЕ ИмяТабличнойЧастиОбъекта КАК ПсевдонимТабличнойЧастиОбъекта - | ПО (ПсевдонимТабличнойЧастиОбъекта.Ссылка = ТекущийСписок.Ссылка) #Соединения - |ГДЕ - | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка,&ПоляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПсевдонимТабличнойЧастиОбъекта", ПсевдонимТабличнойЧастиОбъекта); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИмяТабличнойЧастиОбъекта", "&ТекущийСписок." + ИмяТабличнойЧастиОбъекта); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); - Иначе - ПоляВыбора = ""; - Соединения = ""; - СоединенияВБазеДанных = ""; - СоединенияВПамяти = ""; - ПоляУпорядочения = ""; - Реквизиты = ""; - Для Каждого ДополнительнаяТаблица Из ГруппаДополнительныхТаблиц Цикл - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ДополнительнаяТаблица.Псевдоним); - ТекущееСоединение = " - |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " - |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3 - Соединения = Соединения + ТекущееСоединение; - Если Контекст.ЭтоСсылочныйТип Тогда - Если ВРег(Контекст.Список) = ВРег(ДополнительнаяТаблица.Таблица) Тогда - ДополнительноеИмя = "&ТекущийСписок"; - ИначеЕсли СтрНачинаетсяС(ВРег(ДополнительнаяТаблица.Таблица), ВРег(Контекст.Список) + ".") Тогда - ДополнительноеИмя = "&ТекущийСписок." + СтрРазделить(ДополнительнаяТаблица.Таблица, ".")[2]; - Иначе - ДополнительноеИмя = ДополнительнаяТаблица.Таблица; - КонецЕсли; - Если ДополнительноеИмя = ДополнительнаяТаблица.Таблица Тогда - СоединенияВБазеДанных = СоединенияВБазеДанных + ТекущееСоединение; - СоединенияВПамяти = СоединенияВПамяти + ТекущееСоединение; - Иначе - СоединенияВБазеДанных = СоединенияВБазеДанных + " - |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " - |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " ") + " - | И НЕ " + ДополнительнаяТаблица.Псевдоним + ".Ссылка В (&СсылкиНаОбъекты)"; // @query-part-1, @query-part-2, @query-part-3, @query-part-5, @query-part-6 - - СоединенияВПамяти = СоединенияВПамяти + " - |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительноеИмя + " КАК " + ДополнительнаяТаблица.Псевдоним + " - |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3, - КонецЕсли; - КонецЕсли; - Если СоединенияИПоля = Неопределено Тогда - Продолжить; - КонецЕсли; - Соединения = Соединения + СоединенияИПоля.Соединения; - Если Контекст.ЭтоСсылочныйТип Тогда - СоединенияВБазеДанных = СоединенияВБазеДанных + СоединенияИПоля.Соединения; - СоединенияВПамяти = СоединенияВПамяти + СоединенияИПоля.Соединения; - КонецЕсли; - ПоляВыбора = ПоляВыбора + СоединенияИПоля.Поля; - ПоляУпорядочения = ПоляУпорядочения + СоединенияИПоля.ПоляУпорядочения; - Реквизиты = Реквизиты + СоединенияИПоля.Реквизиты; - КонецЦикла; - Если Контекст.ЭтоСсылочныйТип Тогда - ТекстЗапроса = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора - |ИЗ - | &ТекущийСписок КАК ТекущийСписок #Соединения - |ГДЕ - | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка,&ПоляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); - - Если СоединенияВПамяти <> СоединенияВБазеДанных Тогда - // АПК:96-выкл - №434 Использование ОБЪЕДИНИТЬ допустимо, так как - // строки не должны повторятся и объем данных небольшой. - ТекстЗапросаВПамяти = - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора - |ИЗ - | &ТекущийСписок КАК ТекущийСписок #СоединенияВБазеДанных - |ГДЕ - | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) - | - |ОБЪЕДИНИТЬ - | - |ВЫБРАТЬ РАЗЛИЧНЫЕ - | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора - |ИЗ - | &ТекущийСписок КАК ТекущийСписок #СоединенияВПамяти - |ГДЕ - | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка,&ПоляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - // АПК:96-вкл. - ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); - ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, ",&ПоляУпорядочения", ПоляУпорядочения); - ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, " #СоединенияВБазеДанных", - ТекстСОтступом(СоединенияВБазеДанных, " ")); - ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, " #СоединенияВПамяти", - ТекстСОтступом(СоединенияВПамяти, " ")); - КонецЕсли; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка,&ПоляВыбора - |ИЗ - | ТекущийСписок КАК ТекущийСписок #Соединения - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка, &ПоляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part-1 - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляУпорядочения", - Контекст.ОпорныеПоля.ДляУпорядочения + ПоляУпорядочения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); - КонецЕсли; - КонецЕсли; - - Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); - Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить( - ?(ЗначениеЗаполнено(ТекстЗапросаВПамяти), ТекстЗапросаВПамяти, ТекстЗапроса)); - - // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. - ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, , НомерТабличнойЧастиКлюча); - - // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. - ТекстЗапроса = - "ВЫБРАТЬ - | ТабличнаяЧасть?.Ссылка КАК ТекущаяСсылка,&Реквизиты - |ИЗ - | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - |ГДЕ - | ТабличнаяЧасть?.Ссылка.Хеш В(&Хеши) - | И ТабличнаяЧасть?.Ссылка.Список = &Список - | И ТабличнаяЧасть?.Ссылка.СоставПолей = &СоставПолей - | И ТабличнаяЧасть?.Ссылка.ДляВнешнихПользователей = &ДляВнешнихПользователей - | И ТабличнаяЧасть?.Ссылка.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) - | И &УточнениеПланаЗапроса - | - |УПОРЯДОЧИТЬ ПО - | ТекущаяСсылка,&ПоляУпорядочения - |ИТОГИ ПО - | ТекущаяСсылка"; // @query-part - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(Реквизиты, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТабличнаяЧасть?", СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); - Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); - - // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. - ТекстЗапроса = - "ВЫБРАТЬ - | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты - |ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ПО - | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка - | - |УПОРЯДОЧИТЬ ПО - | Ссылка - |ИТОГИ ПО - | Ссылка"; // @query-part-1 - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(Реквизиты, " ")); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТабличнаяЧасть?", СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); - Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); - - // Условие отбора прав ведущих ключей доступа. - ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, - ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВедущихКлючей"); - - // Условие отбора прав ведущих списков. - ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, - ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВедущихСписков"); - - // Условие отбора прав по владельцам настроек прав. - ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, - ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВладельцевНастроекПрав"); - -КонецПроцедуры - -// Для процедуры ДобавитьЗаполнениеТабличнойЧастиКлюча. -Процедура ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, ГруппаПолей, - НомерТабличнойЧастиКлюча, НазначениеУсловия) - - Для Каждого СвойстваПоля Из ГруппаПолей Цикл - Если НазначениеУсловия = "ДляВедущихКлючей" - И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 - Или НазначениеУсловия = "ДляВедущихСписков" - И Не СвойстваПоля.ЕстьТипВедущегоСписка - Или НазначениеУсловия = "ДляВладельцевНастроекПрав" - И Не СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда - Продолжить; - КонецЕсли; - - Если НазначениеУсловия = "ДляВедущихСписков" - И СвойстваПоля.ТипыСохраненияЗначений.Количество() > 0 Тогда - - Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписковСТипами"); - УсловиеОтбора = - "#ПроверяемоеПоле В - | (ВЫБРАТЬ - | ЕСТЬNULL(ТипыКонфигурации.Ссылка, ЕСТЬNULL(ТипыРасширений.Ссылка, ТабличнаяЧасть?.Реквизит?)) - | ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ПО - | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка - | - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации - | ПО - | ТабличнаяЧасть?.Реквизит? <> НЕОПРЕДЕЛЕНО - | И ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовМетаданных) - | И ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовРасширений) - | И ТИПЗНАЧЕНИЯ(ТипыКонфигурации.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) - | - | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений - | ПО - | ТабличнаяЧасть?.Реквизит? <> НЕОПРЕДЕЛЕНО - | И ТИПЗНАЧЕНИЯ(ТипыРасширений.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?))"; // @query-part-1 - Иначе - УсловиеОтбора = - "#ПроверяемоеПоле В - | (ВЫБРАТЬ - | ТабличнаяЧасть?.Реквизит? - | ИЗ - | ПорцияКлючей КАК ПорцияКлючей - | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? - | ПО - | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка)"; // @query-part-1 - КонецЕсли; - - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "ТабличнаяЧасть?", - СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Реквизит?", - СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); - - Если НазначениеУсловия = "ДляВедущихКлючей" Тогда - Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Добавить(УсловиеОтбора); - - ИначеЕсли НазначениеУсловия = "ДляВедущихСписков" Тогда - Контекст.ЧастиУсловияВыбораПравВедущихСписков.Добавить(УсловиеОтбора); - Иначе - Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Добавить(УсловиеОтбора); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ДобавитьЗаполнениеШапкиКлюча, ДобавитьЗаполнениеТабличнойЧастиКлюча. -Процедура ДобавитьОписаниеТаблицыКлюча(ИмяТаблицыКлюча, ГруппаПолей, Контекст) - - ПоляТаблицыКлюча = Новый Массив; - - Для Каждого СвойстваПоля Из ГруппаПолей Цикл - ПоляТаблицыКлюча.Добавить(СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); - КонецЦикла; - - Контекст.ТаблицыКлюча.Добавить(ИмяТаблицыКлюча); - Контекст.РеквизитыТаблицКлюча.Вставить(ИмяТаблицыКлюча, ПоляТаблицыКлюча); - -КонецПроцедуры - -// Для процедуры ДобавитьЗаполнениеШапкиКлюча, ДобавитьЗаполнениеТабличнойЧастиКлюча. -Процедура ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, НомерШапки = 0, НомерТабличнойЧастиКлюча = 0) - - УсловиеОтбора = ""; - НомерРеквизита = ?(НомерШапки = 0, 0, 5); - - Для Каждого СвойстваПоля Из ГруппаПолей Цикл - НомерРеквизита = НомерРеквизита + 1; - - Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - - УсловиеОтбора = - "КлючиДоступа.Ссылка В - | (ВЫБРАТЬ - | Шапка?.Ссылка - | ИЗ - | Справочник.КлючиДоступа КАК Шапка? - | ГДЕ - | Шапка?.Значение? В (&ВедущиеКлючиДоступа))"; // @query-part-1 - - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Значение?", - СтрШаблон("Значение%1", НомерРеквизита)); - - Если НомерШапки > 0 Тогда - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, - "Справочник.КлючиДоступа КАК Шапка?", - "Справочник.КлючиДоступа.Шапка КАК Шапка?"); // @query-part-1, @query-part-2 - КонецЕсли; - - Если НомерТабличнойЧастиКлюча = 0 Тогда - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); - Иначе - ИмяТабличнойЧасти = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, " КАК", "." + ИмяТабличнойЧасти + " КАК"); // @query-part-1, @query-part-3 - УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", ИмяТабличнойЧасти); - КонецЕсли; - - Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Добавить(УсловиеОтбора); - КонецЦикла; - -КонецПроцедуры - -// Для процедур ДобавитьПроверкуШапкиКлюча, ДобавитьПроверкуТабличнойЧастиКлюча. -Функция СоединенияИПоляПоТаблицам(ГруппаПолей, ТабличнаяЧастьКлюча, НомерШапки = 0, ДляВыбораЗначений = Ложь) - - СоединенияИПоляПоТаблицам = Новый Соответствие; - НомерРеквизита = 1 + ?(НомерШапки = 0, 0, 5); - - Для Каждого СвойстваПоля Из ГруппаПолей Цикл - - СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(СвойстваПоля.ПсевдонимТаблицы); - Если СоединенияИПоля = Неопределено Тогда - СоединенияИПоля = Новый Структура; - СоединенияИПоля.Вставить("Соединения", ""); - СоединенияИПоля.Вставить("Поля", ""); - СоединенияИПоля.Вставить("ПоляУпорядочения", ""); - СоединенияИПоля.Вставить("Реквизиты", ""); - СоединенияИПоляПоТаблицам.Вставить(СвойстваПоля.ПсевдонимТаблицы, СоединенияИПоля); - КонецЕсли; - - Соединения = ""; - Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() > 0 Тогда - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам? - |ПО (КлючиДоступаКОбъектам?.Объект = #ИмяПоляДляЗапроса)"; // @query-part-1 - КонецЕсли; - - Если СвойстваПоля.ТипыСохраненияГруппЗначений.Количество() > 0 Тогда - Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначений? - |ПО (ГруппыЗначений?.ЗначениеДоступа = #ИмяПоляДляЗапроса) - | И (ГруппыЗначений?.ГруппаДанных = 0)"; // @query-part-1 - ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок.ГруппыДоступа КАК ГруппыЗначений? - |ПО (ГруппыЗначений?.Ссылка = #ИмяПоляДляЗапроса)"; // @query-part-1 - КонецЕсли; - КонецЕсли; - - Если СвойстваПоля.ТипыСохраненияТиповКонфигурации.Количество() > 0 Тогда - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации? - |ПО (#ИмяПоляДляЗапроса <> НЕОПРЕДЕЛЕНО) - | И (ТИПЗНАЧЕНИЯ(ТипыКонфигурации?.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса))"; // @query-part-1 - КонецЕсли; - - Если СвойстваПоля.ТипыСохраненияТиповРасширений.Количество() > 0 Тогда - Соединения = Соединения + " - |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений? - |ПО (#ИмяПоляДляЗапроса <> НЕОПРЕДЕЛЕНО) - | И (ТИПЗНАЧЕНИЯ(ТипыРасширений?.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса))"; // @query-part-1 - КонецЕсли; - - Поле = СравнениеПоля(СвойстваПоля); - - Если ДляВыбораЗначений Тогда - Поле = СтрЗаменить(Поле, "Шапка?.Значение? = ", ""); - Поле = СтрЗаменить(Поле, " ", " "); - Позиция = СтрДлина(Символы.ПС + "И ()"); // @query-part-1 - Поле = "," + Символы.ПС + Сред(Поле, Позиция, СтрДлина(Поле) - Позиция) + " КАК " + "Значение?"; // @query-part-2 - - СоединенияИПоля.ПоляУпорядочения = СоединенияИПоля.ПоляУпорядочения - + ", " + СтрШаблон("Значение%1", НомерРеквизита); - - СоединенияИПоля.Реквизиты = СоединенияИПоля.Реквизиты + СтрШаблон(", - |Шапка?.Значение%1 КАК Значение%1", НомерРеквизита); // @query-part-1 - КонецЕсли; - - ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "Значение?"); - ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ГруппыЗначений?"); - ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "КлючиДоступаКОбъектам?"); - ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ТипыКонфигурации?"); - ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ТипыРасширений?"); - - Соединения = СтрЗаменить(Соединения, "#ИмяПоляДляЗапроса", СвойстваПоля.ИмяПоляДляЗапроса); - Поле = СтрЗаменить(Поле, "#ИмяПоляДляЗапроса", СвойстваПоля.ИмяПоляДляЗапроса); - - Если ТабличнаяЧастьКлюча Тогда - Поле = СтрЗаменить(Поле, "Шапка?", "ТабличнаяЧасть?"); - СоединенияИПоля.Реквизиты = СтрЗаменить(СоединенияИПоля.Реквизиты, "Шапка?", "ТабличнаяЧасть?"); - КонецЕсли; - - СоединенияИПоля.Соединения = СоединенияИПоля.Соединения + Соединения; - СоединенияИПоля.Поля = СоединенияИПоля.Поля + Поле; - НомерРеквизита = НомерРеквизита + 1; - КонецЦикла; - - Возврат СоединенияИПоляПоТаблицам; - -КонецФункции - -// Для функции СоединенияИПоляПоТаблицам. -Функция СравнениеПоля(СвойстваПоля) - - КоличествоТиповПоля = СвойстваПоля.ТипКонечногоПоля.Типы().Количество(); - - БезЗначенияНеопределено = КоличествоТиповПоля = 1; - Если СвойстваПоля.Свойство("БезЗначенияNull") Тогда - БезЗначенияNull = СвойстваПоля.БезЗначенияNull; - Иначе - БезЗначенияNull = БезЗначенияNull(СвойстваПоля); - КонецЕсли; - - БезУточненияНеопределено = Не СвойстваПоля.ЕстьУточнениеНеопределено Или БезЗначенияНеопределено; - БезУточненияNull = Не СвойстваПоля.ЕстьУточнениеNull Или БезЗначенияNull; - - // Сохранение только ключей доступа. - Если СвойстваПоля.ТипыСохраненияПустойСсылки.Количество() = 0 - И БезУточненияНеопределено - И БезУточненияNull - И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = КоличествоТиповПоля Тогда - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(КлючиДоступаКОбъектам?.#КлючДоступаПользователейКОбъекту, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 - КонецЕсли; - - // Сохранение только групп значений доступа. - Если СвойстваПоля.ТипыСохраненияПустойСсылки.Количество() = 0 - И БезУточненияНеопределено - И БезУточненияNull - И СвойстваПоля.ТипыСохраненияГруппЗначений.Количество() = КоличествоТиповПоля Тогда - - Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаЗначенийДоступа, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 - ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаДоступа, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 - Иначе - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(ТекущийСписок.ГруппаДоступа, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 - КонецЕсли; - КонецЕсли; - - // Сохранение только значений. - Если Не ЕстьПростойТип(СвойстваПоля.ТипКонечногоПоля) - И КоличествоТиповПоля = 1 - И СвойстваПоля.ТипыСохраненияЗначений.Количество() = КоличествоТиповПоля Тогда - - Если БезЗначенияNull Тогда - Возврат " - |И (Шапка?.Значение? = #ИмяПоляДляЗапроса)"; // @query-part-1 - Иначе - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(#ИмяПоляДляЗапроса, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 - КонецЕсли; - КонецЕсли; - - // Сохранение одного ссылочного типа. - Если БезУточненияNull - И КоличествоТиповПоля = 1 - И СвойстваПоля.ТипыСохраненияТипов.Количество() = КоличествоТиповПоля - И СвойстваПоля.ТипыСохраненияТиповПростых.Количество() = 0 Тогда - - Если СвойстваПоля.ТипыСохраненияТиповРасширений.Количество() = 0 Тогда - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(ТипыКонфигурации?.Ссылка, - | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)))"; // @query-part-1 - ИначеЕсли СвойстваПоля.ТипыСохраненияТиповКонфигурации.Количество() = 0 Тогда - Возврат " - |И (Шапка?.Значение? = ЕСТЬNULL(ТипыРасширений?.Ссылка, - | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовРасширений.ПустаяСсылка)))"; // @query-part-1 - КонецЕсли; - КонецЕсли; - - // Сохранение одного простого типа. - Если БезУточненияNull - И КоличествоТиповПоля = 1 - И СвойстваПоля.ТипыСохраненияТиповПростых.Количество() = 1 Тогда - - Возврат " - |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный))"; // @query-part-1 - КонецЕсли; - - Если СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Количество() = КоличествоТиповПоля Тогда - Возврат " - |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипЗапрещенный))"; // @query-part-1 - КонецЕсли; - - // Сохранение только значения ТипРазрешенный. - Если СвойстваПоля.ТипыСохраненияТипаРазрешенный.Количество() = КоличествоТиповПоля Тогда - Возврат " - |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный))"; // @query-part-1 - КонецЕсли; - - СравнениеПоля = " - |И (ВЫБОР - | #СодержаниеВыбора - |КОНЕЦ)"; // @query-part-1 - СодержаниеВыбора = ""; - - СохранениеЗначенияБулево = СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип("Булево")) <> Неопределено; - - Если Не БезЗначенияNull - И Не (СохранениеЗначенияБулево И КоличествоТиповПоля = 1) Тогда - СодержаниеВыбора = СодержаниеВыбора + " - |КОГДА #ИмяПоляДляЗапроса ЕСТЬ NULL - | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)"; // @query-part-1 - КонецЕсли; - Если КоличествоТиповПоля > 1 Тогда - СодержаниеВыбора = СодержаниеВыбора + " - |КОГДА #ИмяПоляДляЗапроса = НЕОПРЕДЕЛЕНО - | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Неопределено)"; // @query-part-1 - КонецЕсли; - Если СохранениеЗначенияБулево Тогда - Если КоличествоТиповПоля > 1 Тогда - СодержаниеВыбора = СодержаниеВыбора + " - |КОГДА #ИмяПоляДляЗапроса - | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Истина) - |КОГДА НЕ #ИмяПоляДляЗапроса - | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Ложь)"; // @query-part-1 - Иначе - СодержаниеВыбора = СодержаниеВыбора + " - |КОГДА #ИмяПоляДляЗапроса - | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Истина) - |ИНАЧЕ Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Ложь)"; // @query-part-1 - КонецЕсли; - КонецЕсли; - - ПроверкиПоТипам = Новый СписокЗначений; - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповПростых, - "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный)"); // @query-part-1 - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияКлючейДоступа, - "Шапка?.Значение? = ЕСТЬNULL(КлючиДоступаКОбъектам?.#КлючДоступаПользователейКОбъекту, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 - - Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, - "Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаЗначенийДоступа, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 - ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, - "Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаДоступа, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 - Иначе - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, - "Шапка?.Значение? = ЕСТЬNULL(ТекущийСписок.ГруппаДоступа, - | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 - КонецЕсли; - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияЗначений, - "Шапка?.Значение? = #ИмяПоляДляЗапроса", , СохранениеЗначенияБулево); - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияПустойСсылки, - "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ПустаяСсылкаЛюбогоТипа)", - "ЭтоПроверкаПустойСсылки"); // @query-part-1 - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповКонфигурации, - "Шапка?.Значение? = ЕСТЬNULL(ТипыКонфигурации?.Ссылка, - | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка))"); // @query-part-1 - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповРасширений, - "Шапка?.Значение? = ЕСТЬNULL(ТипыРасширений?.Ссылка, - | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовРасширений.ПустаяСсылка))"); // @query-part-1 - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТипаЗапрещенный, - "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипЗапрещенный)"); // @query-part-1 - - ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТипаРазрешенный, - "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный)"); // @query-part-1 - - ПроверкиПоТипам.СортироватьПоПредставлению(); - - Для Каждого ПроверкаПоТипам Из ПроверкиПоТипам Цикл - Если ПроверкаПоТипам.Значение.Типы.Количество() = 0 Тогда - Продолжить; - КонецЕсли; - Если ПроверкиПоТипам.Индекс(ПроверкаПоТипам) < ПроверкиПоТипам.Количество() - 1 Тогда - ПроверкаТипов = ""; - Для Каждого Тип Из ПроверкаПоТипам.Значение.Типы Цикл - Если ЭтоПростойТип(Тип) Тогда - ИмяТипа = Строка(Тип); - Иначе - ИмяТипа = Метаданные.НайтиПоТипу(Тип).ПолноеИмя(); - КонецЕсли; - Если ПроверкаТипов <> "" Тогда - ПроверкаТипов = ПроверкаТипов + " - | ИЛИ "; - КонецЕсли; - ШаблонПроверки = ?(ПроверкаПоТипам.Значение.Свойство("ЭтоПроверкаПустойСсылки"), - "#ИмяПоляДляЗапроса = ЗНАЧЕНИЕ(#ИмяТипа.ПустаяСсылка)", - "ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса) = ТИП(#ИмяТипа)"); // @query-part-3 - ПроверкаТипов = ПроверкаТипов + СтрЗаменить(ШаблонПроверки, "#ИмяТипа", ИмяТипа); - КонецЦикла; - Проверка = " - |КОГДА #ПроверкаТипов - | ТОГДА #Проверка"; // @query-part-1 - Проверка = СтрЗаменить(Проверка, "#ПроверкаТипов", ПроверкаТипов); - Иначе - Проверка = " - |ИНАЧЕ #Проверка"; // @query-part-1 - КонецЕсли; - Проверка = СтрЗаменить(Проверка, "#Проверка", ПроверкаПоТипам.Значение.Проверка); - СодержаниеВыбора = СодержаниеВыбора + Проверка; - КонецЦикла; - - Возврат СтрЗаменить(СравнениеПоля, "#СодержаниеВыбора", ТекстСОтступом(СокрЛ(СодержаниеВыбора), " ")); - -КонецФункции - -// Для функции СравнениеПоля. -Процедура ДобавитьПроверкуПоТипам(ПроверкиПоТипам, ИсходныеТипы, Проверка, ДополнительноеСвойство = "", ПропуститьБулево = Ложь) - - Типы = Новый Массив; - Для Каждого Тип Из ИсходныеТипы Цикл - Если ПропуститьБулево И Тип = Тип("Булево") Тогда - Продолжить; - КонецЕсли; - Типы.Добавить(Тип); - КонецЦикла; - - Если Типы.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Структура = Новый Структура("Типы, Проверка", Типы, Проверка); - ПроверкиПоТипам.Добавить(Структура, Формат(Структура.Типы.Количество(), "ЧЦ=10; ЧВН=; ЧГ=")); - - Если ДополнительноеСвойство = "" Тогда - Возврат; - КонецЕсли; - - Структура.Вставить(ДополнительноеСвойство); - -КонецПроцедуры - -// Для функции ДобавитьПроверкуШапкиКлюча. -Процедура ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, Псевдоним) - - ПсевдонимСНомером = СтрЗаменить(Псевдоним, "?", НомерРеквизита); - - Соединения = СтрЗаменить(Соединения, Псевдоним, ПсевдонимСНомером); - Поле = СтрЗаменить(Поле, Псевдоним, ПсевдонимСНомером); - -КонецПроцедуры - -// Для функций ДобавитьПроверкуШапкиКлюча, СравнениеПоля. -Функция ТекстСОтступом(Текст, Отступ) - - Возврат СтрЗаменить(Текст, Символы.ПС, Символы.ПС + Отступ); - -КонецФункции - -// Для функции СравнениеПоля, ДобавитьОпорноеПоле. -Функция ЕстьПростойТип(ОписаниеТипов) - - Возврат ОписаниеТипов.СодержитТип(Тип("Булево")) - Или ОписаниеТипов.СодержитТип(Тип("Дата")) - Или ОписаниеТипов.СодержитТип(Тип("Строка")) - Или ОписаниеТипов.СодержитТип(Тип("Число")) - Или ОписаниеТипов.СодержитТип(Тип("УникальныйИдентификатор")) - Или ОписаниеТипов.СодержитТип(Тип("ХранилищеЗначения")); - -КонецФункции - -#КонецОбласти - -#КонецОбласти - -#Область ПреобразованиеТекстовОграниченийВСтруктуры - -// См. также УправлениеДоступом.РазобранноеОграничение. -// -// Возвращаемое значение: -// Структура: -// * ПоляТаблиц - см. НовыеПоляТаблиц -// * ВнутренниеДанные - см. НовыеВнутренниеДанные -// -Функция РазобранноеОграничение(ОсновнаяТаблица, ТекстОграничения) Экспорт - - ВнутренниеДанные = НовыеВнутренниеДанные(); - ВнутренниеДанные.Вставить("ОсновнаяТаблица", ОсновнаяТаблица); - ВнутренниеДанные.Вставить("ТекстОграничения", СокрЛП(ТекстОграничения)); - - ВнутренниеДанные.Вставить("СинтаксисЯзыка", УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка()); - ВнутренниеДанные.Вставить("ПоляТаблиц", НовыеПоляТаблиц()); - ВнутренниеДанные.Вставить("Псевдонимы", Новый Соответствие); - - ВнутренниеДанные.Вставить("ПоляКлючаДоступа", Новый Массив); - - ВнутренниеДанные.Вставить("ТаблицаНаборовСимволов", ТаблицаНаборовСимволов(ВнутренниеДанные)); - ВнутренниеДанные.Вставить("ЧастиОграничения", ЧастиОграничения(ВнутренниеДанные)); - - Результат = Новый Структура; - Результат.Вставить("ВнутренниеДанные", ВнутренниеДанные); - Результат.Вставить("ПоляТаблиц", ВнутренниеДанные.ПоляТаблиц); - - Возврат Результат; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ОсновнаяТаблица - Строка - таблица, которая ограничивается. -// * ТекстОграничения - Строка -// * СинтаксисЯзыка - см. СинтаксисЯзыка -// * ПоляТаблиц - см. НовыеПоляТаблиц -// * Псевдонимы - Соответствие -// * ПоляКлючаДоступа - Массив из см. НовоеПолеКлючаДоступа -// * ТаблицаНаборовСимволов - см. ТаблицаНаборовСимволов -// * ЧастиОграничения - см. ЧастиОграничения -// -Функция НовыеВнутренниеДанные() - - Возврат Новый Структура; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ОсновнаяТаблица - Строка - таблица, которая ограничивается. -// * ТекстОграничения - Строка -// * СинтаксисЯзыка - см. СинтаксисЯзыка -// * ПоляТаблиц - см. НовыеПоляТаблиц -// * Псевдонимы - Соответствие -// * ПоляКлючаДоступа - Массив из см. НовоеПолеКлючаДоступа -// * ТаблицаНаборовСимволов - см. ТаблицаНаборовСимволов -// * ЧастиОграничения - см. ЧастиОграничения -// * ЭтоУсловиеСоединения - Булево -// * ЭтоУсловиеКогда - Булево -// * ЭтоЗначениеТогдаИначе - Булево -// * КорневойУзел - см. ОписаниеУзла -// -Функция РасширенныеВнутренниеДанные(ВнутренниеДанные) - - ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ВнутренниеДанные); - Возврат Новый Структура(ФиксированныйКонтекст); - -КонецФункции - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - Строка - имя коллекции объектов метаданных, например, Справочники. -// * Значение - см. НовыйСоставКоллекции -// -Функция НовыеПоляТаблиц() - - Возврат Новый Соответствие; - -КонецФункции - -// Возвращаемое значение: -// Соответствие из КлючИЗначение: -// * Ключ - Строка - имя таблицы (объекта метаданных) в верхнем регистре. -// * Значение - см. НовыеСвойстваТаблицы -// -Функция НовыйСоставКоллекции() - - Возврат Новый Соответствие; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ТаблицаСуществует - Булево - Ложь (для заполнения Истина, если существует). -// * ЭтоОсновнаяТаблица - Булево -// * Источники - Массив -// * ПервоеПоле - Неопределено -// * Поля - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя реквизита в верхнем регистре, в том числе через точки, -// например, "ВЛАДЕЛЕЦ.ОРГАНИЗАЦИЯ", "ТОВАРЫ.НОМЕНКЛАТУРА". -// ** Значение - см. НовыеСвойстваПоля -// * Предопределенные - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя предопределенного элемента. -// ** Значение - см. НовыеСвойстваПредопределенного -// * Расширения - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя третьего имени таблицы, например, имя табличной части. -// ** Значение - см. НовыеСвойстваРасширения -// -Функция НовыеСвойстваТаблицы() - - Возврат Новый Структура; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ПолеСОшибкой - Число - 0 (для заполнения, если поле содержит ошибку, -// если 1, то ошибка в имени первой части поля, -// если 2, то ошибка в имени второй части поля, т.е. после первой точки). -// * ВидОшибки - Строка - "НеНайдено", "ТабличнаяЧастьБезПоля", -// "ТабличнаяЧастьПослеТочки". -// * Коллекция - Строка - пустая строка (для заполнения, если первая часть -// поля существует, т.е. часть поля до первой точки). Варианты: "Реквизиты", -// "ТабличныеЧасти", "СтандартныеРеквизиты", "СтандартныеТабличныеЧасти", -// "Измерения", "Ресурсы", "Графы", "ПризнакиУчета", "ПризнакиУчетаСубконто", -// "РеквизитыАдресации", "СпециальныеПоля". Специальные поля - это -// "Значение" - у таблиц "Константа.*", -// "Регистратор" и "Период" - у таблиц "Последовательность.*", -// "ОбъектПерерасчета", "ВидРасчета" у таблиц "РегистрРасчета.<Имя>.<ИмяПерерасчета>". -// Поля после первой точки могут относится только к коллекциям: "Реквизиты", -// "СтандартныеРеквизиты", "ПризнакиУчета", "РеквизитыАдресации". Для этих -// частей имени поля не требуется уточнять коллекцию. -// * СодержитТипы - Соответствие из КлючИЗначение: -// ** Ключ - Строка - полное имя ссылочной таблицы в верхнем регистре. -// ** Значение - Структура: -// *** ИмяТипа - Строка - имя типа, наличие которого нужно проверить. -// *** СодержитТип - Булево - Ложь (для заполнения Истина, -// если у поля последнего поля есть тип). -// * ПервыйИсточник - Структура: -// ** Ключ - СтрокаТаблицыЗначений - строка-источник первого поля. -// ** Значение - Строка - таблица -// -Функция НовыеСвойстваПоля() - - Возврат Новый Структура; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ИмяСуществует - Булево - Ложь (для заполнения Истина, если предопределенный есть). -// * Источники - Массив -// -Функция НовыеСвойстваПредопределенного() - - Возврат Новый Структура; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ТаблицаСуществует - Булево - Ложь (для заполнения Истина, если существует). -// * Источники - Массив -// * ПервоеПоле - Неопределено -// * Поля - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя реквизита в верхнем регистре, в том числе через точки, -// например, "ВЛАДЕЛЕЦ.ОРГАНИЗАЦИЯ", "ТОВАРЫ.НОМЕНКЛАТУРА". -// ** Значение - см. НовыеСвойстваПоля -// -Функция НовыеСвойстваРасширения() - - Возврат Новый Структура; - -КонецФункции - - -// Смотри также УправлениеДоступом.СтруктураОграничения -// -// Параметры: -// РазобранноеОграничение - см. РазобранноеОграничение -// -// Возвращаемое значение: -// Структура: -// * ОписаниеОшибок - см. ОписаниеОшибок -// * ДополнительныеТаблицы - Массив из см. НовоеОписаниеСоединения -// * ПсевдонимОсновнойТаблицы - Строка - заполнено, если указаны дополнительные таблицы. -// * ОграничениеЧтения - см. ОписаниеУзла -// * ОграничениеИзменения - см. ОписаниеУзла -// -Функция СтруктураОграничения(РазобранноеОграничение) Экспорт - - ВнутренниеДанные = РазобранноеОграничение.ВнутренниеДанные; - - ОтметитьНекорректныеИменаТаблицПолейИТиповПолей(РазобранноеОграничение.ПоляТаблиц, - ВнутренниеДанные); - - // Заполнение найденных ошибок. - ОписаниеОшибок = ОписаниеОшибок(); - - Таблица = ВнутренниеДанные.ТаблицаНаборовСимволов; - ОтборСтрокБезОшибок = Новый Структура("ТекстОшибки", ""); - Если Таблица.Количество() <> Таблица.НайтиСтроки(ОтборСтрокБезОшибок).Количество() Тогда - ОписаниеОшибок.ЕстьОшибки = Истина; - ТребуетсяДополнение = Ложь; - ДлинаНомераСтроки = СтрДлина(Формат(СтрЧислоСтрок(ВнутренниеДанные.ТекстОграничения), "ЧГ=")); - Для Каждого Строка Из Таблица Цикл - Если Строка.ТекстОшибки = "" Тогда - Продолжить; - КонецЕсли; - ДобавитьОшибку(Строка, ОписаниеОшибок, ВнутренниеДанные, ДлинаНомераСтроки); - Если Строка.ПозицияОшибки = -1 Тогда - ТребуетсяДополнение = Истина; - КонецЕсли; - КонецЦикла; - ОписаниеОшибок.Ограничение = ПронумерованныйТекстОграниченияСОтметкамиОшибок( - ВнутренниеДанные.ТекстОграничения, ОписаниеОшибок.Ошибки, ДлинаНомераСтроки); - Если ТребуетсяДополнение Тогда - ОписаниеОшибок.Дополнение = ОписаниеДопустимыхШаблонов(); - КонецЕсли; - КонецЕсли; - - ЧастиОграничения = ВнутренниеДанные.ЧастиОграничения; - - СтруктураОграничения = Новый Структура; - СтруктураОграничения.Вставить("ОписаниеОшибок", ОписаниеОшибок); - СтруктураОграничения.Вставить("ДополнительныеТаблицы", ЧастиОграничения.ДополнительныеТаблицы); - СтруктураОграничения.Вставить("ПсевдонимОсновнойТаблицы", ЧастиОграничения.ПсевдонимОсновнойТаблицы); - СтруктураОграничения.Вставить("ОграничениеЧтения", ЧастиОграничения.ОграничениеЧтения); - СтруктураОграничения.Вставить("ОграничениеИзменения", ЧастиОграничения.ОграничениеИзменения); - - // Дополнительные сведения для внутреннего использования. - ИмяТипаТаблицы = СтрРазделить(ВнутренниеДанные.ОсновнаяТаблица, ".")[0]; - СвойстваТипаТаблиц = ВнутренниеДанные.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); - - НовыеВнутренниеДанные = Новый Структура; - НовыеВнутренниеДанные.Вставить("ПоляКлючаДоступа", ВнутренниеДанные.ПоляКлючаДоступа); - НовыеВнутренниеДанные.Вставить("ЭтоСсылочныйТип", СвойстваТипаТаблиц.ЭтоСсылочныйТип); - НовыеВнутренниеДанные.Вставить("ИмяКоллекцииТипа", СвойстваТипаТаблиц.ИмяКоллекции); - НовыеВнутренниеДанные.Вставить("ТипыТаблицПоИменам", ВнутренниеДанные.СинтаксисЯзыка.ТипыТаблиц.ПоИменам); - - СтруктураОграничения.Вставить("ВнутренниеДанные", НовыеВнутренниеДанные); - - Для Каждого Строка Из ВнутренниеДанные.ТаблицаНаборовСимволов Цикл - Строка.Строки.Очистить(); - Строка.КонечнаяСтрока = Неопределено; - КонецЦикла; - ВнутренниеДанные.ТаблицаНаборовСимволов.Очистить(); - ВнутренниеДанные.ЧастиОграничения.Очистить(); - ВнутренниеДанные.Очистить(); - - Возврат СтруктураОграничения; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * ЕстьОшибки - Булево -// * ТекстОшибок - Строка -// * Ограничение - Строка -// * Ошибки - Массив из см. СвойстваОшибки -// * Дополнение - Строка -// -Функция ОписаниеОшибок() - - ОписаниеОшибок = Новый Структура; - ОписаниеОшибок.Вставить("ЕстьОшибки", Ложь); - ОписаниеОшибок.Вставить("ТекстОшибок", ""); - ОписаниеОшибок.Вставить("Ограничение", ""); - ОписаниеОшибок.Вставить("Ошибки", Новый Массив); - ОписаниеОшибок.Вставить("Дополнение", ""); - - Возврат ОписаниеОшибок; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * НомерСтроки - Число - номер строки текста ограничения, в которой найдена ошибка. -// * ПозицияВСтроке - Число - позиция в строке текста ограничения, в которой найдена ошибка. -// * ТекстОшибки - Строка - описание ошибки. -// * СтрокаОшибки - Строка - строка текста ограничения, в которой найдена ошибка. -// -Функция СвойстваОшибки() - - Возврат Новый Структура; - -КонецФункции - -// Формирует полный текст ошибок описания ограничения доступа с дополнением, -// который можно указать, как текст для вызова исключения. -// -// Параметры: -// ПолноеИмя - Строка - полное имя таблицы списка. -// ОписаниеОшибок - Структура - значение возвращаемое функцией СтруктураОграничения. -// ДляВнешнихПользователей - Булево - если передать Истина, тогда текст ошибки будет содержать -// назначение ограничения для внешних пользователей. -// -// Возвращаемое значение: -// Строка - текст для вызова исключения. -// -Функция ТекстОшибокДляВызоваИсключения(ПолноеИмя, ОписаниеОшибок, ДляВнешнихПользователей, ВМодулеМенеджера) - - Если Не ОписаниеОшибок.ЕстьОшибки Тогда - Возврат ""; - КонецЕсли; - - Если ОписаниеОшибок.Ошибки.Количество() = 1 Тогда - Уточнение = ""; - Если ВМодулеМенеджера = Неопределено Тогда - Если ДляВнешнихПользователей Тогда - ЗаголовокОшибки = - НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"":'"); - Иначе - ЗаголовокОшибки = - НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"":'"); - КонецЕсли; - ИначеЕсли ВМодулеМенеджера Тогда - Если ДляВнешнихПользователей Тогда - ЗаголовокОшибки = - НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"", - |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); - Иначе - ЗаголовокОшибки = - НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"", - |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); - КонецЕсли; - Уточнение = "ПриЗаполненииОграниченияДоступа"; - Иначе - Если ДляВнешнихПользователей Тогда - ЗаголовокОшибки = - НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"", - |указанному в процедуре %2:'"); - Иначе - ЗаголовокОшибки = - НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"", - |указанному в процедуре %2:'"); - КонецЕсли; - Уточнение = "УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа"; - КонецЕсли; - Иначе - Если ВМодулеМенеджера = Неопределено Тогда - Если ДляВнешнихПользователей Тогда - ЗаголовокОшибки = - НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"":'"); - Иначе - ЗаголовокОшибки = - НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"":'"); - КонецЕсли; - ИначеЕсли ВМодулеМенеджера Тогда - Если ДляВнешнихПользователей Тогда - ЗаголовокОшибки = - НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"", - |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); - Иначе - ЗаголовокОшибки = - НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"", - |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); - КонецЕсли; - Уточнение = "ПриЗаполненииОграниченияДоступа"; - Иначе - Если ДляВнешнихПользователей Тогда - ЗаголовокОшибки = - НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"", - |указанному в процедуре %2:'"); - Иначе - ЗаголовокОшибки = - НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"", - |указанному в процедуре %2:'"); - КонецЕсли; - Уточнение = "УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа"; - КонецЕсли; - КонецЕсли; - - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ЗаголовокОшибки, ПолноеИмя, Уточнение); - ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.ТекстОшибок; - ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.Ограничение; - - Если ЗначениеЗаполнено(ОписаниеОшибок.Дополнение) Тогда - ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.Дополнение; - КонецЕсли; - - Возврат Символы.ПС + ТекстОшибки + Символы.ПС; - -КонецФункции - -// Для функции СтруктураОграничения. -Процедура ДобавитьОшибку(Строка, ОписаниеОшибок, ВнутренниеДанные, ДлинаНомераСтроки) - - ПозицияВТексте = Строка.Позиция; - ПозицияОшибкиВКонцеСтроки = Ложь; - ТекстОграничения = ВнутренниеДанные.ТекстОграничения; - - Если Строка.ПозицияОшибки > 0 Тогда - ПозицияВТексте = ПозицияВТексте + Строка.ПозицияОшибки; - Если Строка.ПозицияОшибки = СтрДлина(Строка.Символы) Тогда - ПозицияВТексте = ПозицияВТексте - 1; - ПозицияОшибкиВКонцеСтроки = Истина; - КонецЕсли; - ИначеЕсли Строка.Позиция > СтрДлина(ТекстОграничения) Тогда - ПозицияВТексте = ПозицияВТексте - 1; - ПозицияОшибкиВКонцеСтроки = Истина; - КонецЕсли; - - Координаты = КоординатыПозицииВТексте(ТекстОграничения, ПозицияВТексте); - Координаты.ПозицияВСтроке = Координаты.ПозицияВСтроке + ?(ПозицияОшибкиВКонцеСтроки, 1, 0); - - СтрокаОшибки = СтрПолучитьСтроку(ТекстОграничения, Координаты.НомерСтроки); - СтрокаОшибки = Лев(СтрокаОшибки, Координаты.ПозицияВСтроке - 1) - + "<>" + Сред(СтрокаОшибки, Координаты.ПозицияВСтроке); - - Ошибка = СвойстваОшибки(); - Ошибка.Вставить("НомерСтроки", Координаты.НомерСтроки); - Ошибка.Вставить("ПозицияВСтроке", Координаты.ПозицияВСтроке); - Ошибка.Вставить("ТекстОшибки", Строка.ТекстОшибки); - Ошибка.Вставить("СтрокаОшибки", СтрокаОшибки); - - ОписаниеОшибок.Ошибки.Добавить(Ошибка); - - Если ЗначениеЗаполнено(ОписаниеОшибок.ТекстОшибок) Тогда - ОписаниеОшибок.ТекстОшибок = ОписаниеОшибок.ТекстОшибок + Символы.ПС + Символы.ПС; - КонецЕсли; - - ОписаниеОшибок.ТекстОшибок = ОписаниеОшибок.ТекстОшибок - + "{(" + Формат(Ошибка.НомерСтроки, "ЧЦ=" + ДлинаНомераСтроки + "; ЧВН=; ЧГ=") - + ", " + Формат(Ошибка.ПозицияВСтроке, "ЧГ=") + ")}:" - + " " + Ошибка.ТекстОшибки + Символы.ПС + Ошибка.СтрокаОшибки; - -КонецПроцедуры - -// Для функции СтруктураОграничения. -Функция ПронумерованныйТекстОграниченияСОтметкамиОшибок(ТекстОграничения, Ошибки, ДлинаНомераСтроки) - - КоличествоСтрок = СтрЧислоСтрок(ТекстОграничения); - СтрокиТекстаОграничений = Новый Массив; - - Для НомерСтроки = 1 По КоличествоСтрок Цикл - Строка = СтрПолучитьСтроку(ТекстОграничения, НомерСтроки); - СтрокиТекстаОграничений.Добавить(Строка); - КонецЦикла; - - Индекс = Ошибки.Количество() - 1; - Пока Индекс >= 0 Цикл - Ошибка = Ошибки[Индекс]; - Строка = СтрокиТекстаОграничений[Ошибка.НомерСтроки - 1]; - СтрокиТекстаОграничений[Ошибка.НомерСтроки - 1] = Лев(Строка, Ошибка.ПозицияВСтроке - 1) - + "<>" + Сред(Строка, Ошибка.ПозицияВСтроке); - Индекс = Индекс - 1; - КонецЦикла; - - Текст = ""; - НомерСтроки = 1; - - Для Каждого Строка Из СтрокиТекстаОграничений Цикл - Текст = Текст + ?(Текст = "", "", Символы.ПС) - + ?(СтрНайти(Строка, "<>") > 0, "*", " ") - + " " + Формат(НомерСтроки, "ЧЦ=" + ДлинаНомераСтроки + "; ЧВН=; ЧГ=") + " " + Строка; - НомерСтроки = НомерСтроки + 1; - КонецЦикла; - - Возврат Текст; - -КонецФункции - -// Для функции СтруктураОграничения. -Функция ОписаниеДопустимыхШаблонов() - - Если ВариантВстроенногоЯзыкаРусский() Тогда - Шаблон1 = - " РазрешитьЧтениеИзменение - | ГДЕ ..."; // @Non-NLS - - Шаблон2 = - " РазрешитьЧтение - | ГДЕ ... - | ; - | РазрешитьИзменениеЕслиРазрешеноЧтение - | ГДЕ ..."; // @Non-NLS - - Шаблон3 = - " ПрисоединитьДополнительныеТаблицы - | ЭтотСписок КАК <Псевдоним> - | ЛЕВОЕ СОЕДИНЕНИЕ ... - | ; - | РазрешитьЧтение - | ГДЕ ... - | ; - | РазрешитьИзменениеЕслиРазрешеноЧтение - | ГДЕ ..."; // @Non-NLS - Иначе - Шаблон1 = - " AllowReadWrite - | WHERE ..."; - - Шаблон2 = - " AllowRead - | WHERE ... - | ; - | AllowWriteIfAllowRead - | WHERE ..."; - - Шаблон3 = - " AttachAdditionalTables - | LIST AS - | LEFT/INNER JOIN ... - | ; - | AllowRead - | WHERE ... - | ; - | AllowWriteIfAllowRead - | WHERE ..."; - КонецЕсли; - - Описание = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ограничение может состоять из 1-3 частей в одном из 4 вариантов: - |1) одинаковое ограничение чтения и изменения: - |%1 - |2) разные ограничения чтения и изменения: - |%2 - |3) любой из вариантов выше с дополнительными таблицами, например: - |%3'"), - Шаблон1, Шаблон2, Шаблон3); - - Возврат Описание; - -КонецФункции - -// Для процедуры ДобавитьОшибку. -Функция КоординатыПозицииВТексте(Текст, ПозицияВТексте) - - Результат = Новый Структура; - Результат.Вставить("НомерСтроки", 0); - Результат.Вставить("ПозицияВСтроке", 0); - - КоличествоСтрок = СтрЧислоСтрок(Текст); - ПозицияНачалаСтроки = 1; - Для НомерСтроки = 1 По КоличествоСтрок Цикл - ДлинаТекущейСтроки = СтрДлина(СтрПолучитьСтроку(Текст, НомерСтроки)); - Если ПозицияВТексте < ПозицияНачалаСтроки + ДлинаТекущейСтроки Тогда - Прервать; - КонецЕсли; - ПозицияНачалаСтроки = ПозицияНачалаСтроки + ДлинаТекущейСтроки + 1; - КонецЦикла; - - Результат.НомерСтроки = НомерСтроки; - Результат.ПозицияВСтроке = ПозицияВТексте - ПозицияНачалаСтроки + 1; - - Возврат Результат; - -КонецФункции - -#Область ЛексическийАнализ - -// Для функции РазобранноеОграничение. -// Раскладывает текст в таблицу наборов символов, в которых: -// - нет символов отступа (пробелов, табуляций, переводов строки); -// - выделены символы произвольных строк и чисел; -// - определены ключевые слова и операции; -// - проверен формат имен и чисел; -// - добавлены ошибки с описанием. -// -// Параметры: -// ТекстОграничения - Строка - текст ограничения доступа. -// -// Возвращаемое значение: -// ТаблицаЗначений: -// * Символы - Строка - символ, пара символов или слово. -// * Позиция - Число - позиция символов в тексте ограничения. -// * Вид - Строка - "КлючевоеСлово", "Операция", "Имя", "Разделитель", -// "Число", "ПроизвольнаяСтрока", "НедопустимыйСимвол", "Конец". -// * Тип - Строка - тип для для видов "КлючевоеСлово" и "Операция". -// * Приоритет - Число - приоритет для видов "КлючевоеСлово" и "Операция". -// * Уточнение - Число - числовое значение для вида "Число". -// - Строка - имя для вида "КлючевоеСлово", строка символов для вида "ПроизвольнаяСтрока". -// * ЭтоРезерв - Булево - если Истина, значит это зарезервированная операция или ключевое слово. -// * ПозицияОшибки - Число - позиция ошибки в тексте ограничения, если текст ошибки не пустой. -// * ТекстОшибки - Строка - текст ошибки, если найдена ошибка. -// -Функция ТаблицаНаборовСимволов(ВнутренниеДанные) - - ТаблицаНаборовСимволов = Новый ТаблицаЗначений; - ТаблицаНаборовСимволов.Колонки.Добавить("Символы", Новый ОписаниеТипов("Строка")); - ТаблицаНаборовСимволов.Колонки.Добавить("Позиция", Новый ОписаниеТипов("Число")); - ТаблицаНаборовСимволов.Колонки.Добавить("Вид", Новый ОписаниеТипов("Строка")); - ТаблицаНаборовСимволов.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка")); - ТаблицаНаборовСимволов.Колонки.Добавить("Приоритет", Новый ОписаниеТипов("Число")); - ТаблицаНаборовСимволов.Колонки.Добавить("Уточнение", Новый ОписаниеТипов("Число, Строка")); - ТаблицаНаборовСимволов.Колонки.Добавить("ЭтоРезерв", Новый ОписаниеТипов("Булево")); - ТаблицаНаборовСимволов.Колонки.Добавить("ПозицияОшибки", Новый ОписаниеТипов("Число")); - ТаблицаНаборовСимволов.Колонки.Добавить("ТекстОшибки", Новый ОписаниеТипов("Строка")); - - ТекстОграничения = ВнутренниеДанные.ТекстОграничения; - - Если Не ЗначениеЗаполнено(ТекстОграничения) Тогда - Возврат ТаблицаНаборовСимволов; - КонецЕсли; - - ДлинаТекстаОграничения = СтрДлина(ТекстОграничения); - - СинтаксисЯзыка = ВнутренниеДанные.СинтаксисЯзыка; - СимволыЯзыка = СинтаксисЯзыка.СимволыЯзыка; - - ВидНабораСимволов = ""; // Слово, ПроизвольнаяСтрока, Операция. - ПозицияНабораСимволов = 0; - НаборСимволов = Новый Массив; - СтрокаТаблицы = Неопределено; - - Для НомерСимвола = 1 По ДлинаТекстаОграничения Цикл - Символ = Сред(ТекстОграничения, НомерСимвола, 1); - ТипСимвола = СимволыЯзыка.Получить(Символ); - // Сначала обработка символов слов, так как они встречаются наиболее часто. - Если ТипСимвола = "СимволСлова" И ВидНабораСимволов = "Слово" Тогда - НаборСимволов.Добавить(Символ); - Продолжить; - КонецЕсли; - // Обработка произвольной строки символов. - Если ВидНабораСимволов = "ПроизвольнаяСтрока" Тогда - Если ТипСимвола = "ОграничительСтроки" Тогда - Если Сред(ТекстОграничения, НомерСимвола + 1, 1) <> Символ Тогда - СтрокаТаблицы.Уточнение = СтрСоединить(НаборСимволов); - СтрокаТаблицы.Позиция = ПозицияНабораСимволов; - НаборСимволов = Новый Массив; - ВидНабораСимволов = ""; - Продолжить; - Иначе - НомерСимвола = НомерСимвола + 1; - КонецЕсли; - КонецЕсли; - НаборСимволов.Добавить(Символ); - Продолжить; - КонецЕсли; - Если ВидНабораСимволов = "Слово" Тогда - // Вначале цикла уже обработан случай, когда ТипСимвола = "СимволСлова", - // для остальных типов символов слово завершено и его нужно добавить в дерево. - ВидНабораСимволов = ""; - ДобавитьСловоВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, - НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); - НаборСимволов = Новый Массив; - КонецЕсли; - // Обработка набора составных разделителей. - Если ВидНабораСимволов = "Операция" Тогда - Если ТипСимвола = "СимволОперации" Тогда - НаборСимволов.Добавить(Символ); - Продолжить; - КонецЕсли; - ВидНабораСимволов = ""; - ДобавитьОперациюВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, - НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); - НаборСимволов = Новый Массив; - КонецЕсли; - // Обработка первого символа наборов символов. - Если ВидНабораСимволов = "" Тогда - Если ТипСимвола = "СимволСлова" Тогда - ВидНабораСимволов = "Слово"; - ПозицияНабораСимволов = НомерСимвола; - НаборСимволов.Добавить(Символ); - Продолжить; - КонецЕсли; - Если ТипСимвола = "СимволОперации" Тогда - ВидНабораСимволов = "Операция"; - ПозицияНабораСимволов = НомерСимвола; - НаборСимволов.Добавить(Символ); - Продолжить; - КонецЕсли; - Если ТипСимвола = "ОграничительСтроки" Тогда - ВидНабораСимволов = "ПроизвольнаяСтрока"; - ПозицияНабораСимволов = НомерСимвола; - СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); - СтрокаТаблицы.Символы = Символ; - СтрокаТаблицы.Вид = ВидНабораСимволов; - Продолжить; - КонецЕсли; - КонецЕсли; - // Обработка отдельных символов. - Если ТипСимвола = "Отступ" Тогда - Продолжить; - КонецЕсли; - Если ТипСимвола = "Разделитель" Тогда - СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); - СтрокаТаблицы.Символы = Символ; - СтрокаТаблицы.Позиция = НомерСимвола; - СтрокаТаблицы.Вид = "Разделитель"; - Продолжить; - КонецЕсли; - СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); - СтрокаТаблицы.Символы = Символ; - СтрокаТаблицы.Позиция = НомерСимвола; - СтрокаТаблицы.Вид = "НедопустимыйСимвол"; - СтрокаТаблицы.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недопустимый символ ""%1"" с кодом %2'"), Символ, КодСимвола(Символ)); - КонецЦикла; - - Если ВидНабораСимволов = "Слово" Тогда - ДобавитьСловоВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, - НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); - - ИначеЕсли ВидНабораСимволов = "Операция" Тогда - ДобавитьОперациюВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, - НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); - - ИначеЕсли ВидНабораСимволов = "ПроизвольнаяСтрока" Тогда - СтрокаТаблицы.Уточнение = СтрСоединить(НаборСимволов); - СтрокаТаблицы.Позиция = ПозицияНабораСимволов; - СтрокаТаблицы.ПозицияОшибки = НомерСимвола - ПозицияНабораСимволов; - СтрокаТаблицы.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не указан символ окончания произвольной строки %1'"), СтрокаТаблицы.Символы); - КонецЕсли; - - ПоследняяСтрока = ТаблицаНаборовСимволов.Добавить(); - ПоследняяСтрока.Позиция = СтрДлина(ТекстОграничения) + 1; - ПоследняяСтрока.Вид = "Конец"; // Для установки текста ошибки недостатка описания. - ТаблицаНаборовСимволов.Индексы.Добавить("Вид, Уточнение"); - - Возврат ТаблицаНаборовСимволов; - -КонецФункции - -// Для функции ТаблицаНаборовСимволов. -Процедура ДобавитьСловоВТаблицуНаборовСимволов(Таблица, - НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка) - - СтрокаСимволов = СтрСоединить(НаборСимволов); - СвойстваСлова = СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(СтрокаСимволов)); // См. СвойстваСлова - - НоваяСтрока = Таблица.Добавить(); - НоваяСтрока.Символы = СтрокаСимволов; - НоваяСтрока.Позиция = ПозицияНабораСимволов; - - Если СвойстваСлова <> Неопределено Тогда - НоваяСтрока.Вид = "КлючевоеСлово"; - НоваяСтрока.Тип = СвойстваСлова.Тип; - НоваяСтрока.Приоритет = СвойстваСлова.Приоритет; - НоваяСтрока.Уточнение = СвойстваСлова.Идентификатор; - НоваяСтрока.ЭтоРезерв = СвойстваСлова.ЭтоРезерв; - - Если СвойстваСлова.ЭтоРезерв Тогда - НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ключевое слово ""%1"" не поддерживается'"), СтрокаСимволов); - КонецЕсли; - Возврат; - КонецЕсли; - - // Слово является именем или числом. - СимволыЦифр = СинтаксисЯзыка.СимволыЦифр; - - Если НаборСимволов[0] = "." Тогда - Если НаборСимволов.Количество() > 1 Тогда - ЭтоЧисло = Ложь; - Иначе - НоваяСтрока.Вид = "Имя"; - НоваяСтрока.ТекстОшибки = НСтр("ru = 'Имя не может начинаться с точки'"); - Возврат; - КонецЕсли; - Иначе - ЭтоЧисло = СимволыЦифр.Получить(НаборСимволов[0]) <> Неопределено; - КонецЕсли; - - Если ЭтоЧисло Тогда - НоваяСтрока.Вид = "Число"; - НомерСимвола = 1; - Для Каждого Символ Из НаборСимволов Цикл - Если СимволыЦифр.Получить(Символ) = Неопределено Тогда - НоваяСтрока.ПозицияОшибки = НомерСимвола - 1; - НоваяСтрока.ТекстОшибки = НСтр("ru = 'Число может состоять только из цифр'"); - Возврат; - КонецЕсли; - НомерСимвола = НомерСимвола + 1; - КонецЦикла; - СимволыЧисла = Лев(СтрокаСимволов, НомерСимвола - 1); - Если СтрДлина(СимволыЧисла) > 16 Тогда - НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Слишком большое число ""%1""'"), СимволыЧисла); - Возврат; - КонецЕсли; - НоваяСтрока.Уточнение = Число(СимволыЧисла); - Иначе - НоваяСтрока.Вид = "Имя"; - ЧастиИмени = СтрРазделить(СтрокаСимволов, "."); - ПозицияЧастиИмени = 1; - Для Каждого ЧастьИмени Из ЧастиИмени Цикл - Если ЧастьИмени = "" И ПозицияЧастиИмени > 1 Тогда - НоваяСтрока.ПозицияОшибки = ПозицияЧастиИмени - 1; - НоваяСтрока.ТекстОшибки = НСтр("ru = 'После точки не указано имя'"); - Возврат; - ИначеЕсли СимволыЦифр.Получить(Лев(ЧастьИмени, 1)) <> Неопределено Тогда - НоваяСтрока.ПозицияОшибки = ПозицияЧастиИмени - 1; - НоваяСтрока.ТекстОшибки = НСтр("ru = 'После точки в имени не может следовать число'"); - Возврат; - КонецЕсли; - ПозицияЧастиИмени = ПозицияЧастиИмени + СтрДлина(ЧастьИмени) + 1; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - -// Для функции ТаблицаНаборовСимволов. -Процедура ДобавитьОперациюВТаблицуНаборовСимволов(Таблица, - НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка) - - СтрокаСимволов = СтрСоединить(НаборСимволов); - СвойстваОперации = СинтаксисЯзыка.ОперацииЯзыка.Получить(СтрокаСимволов); - - НоваяСтрока = Таблица.Добавить(); - НоваяСтрока.Символы = СтрокаСимволов; - НоваяСтрока.Позиция = ПозицияНабораСимволов; - НоваяСтрока.Вид = "Операция"; - НоваяСтрока.Тип = СвойстваОперации.Тип; - НоваяСтрока.Приоритет = СвойстваОперации.Приоритет; - НоваяСтрока.ЭтоРезерв = СвойстваОперации.ЭтоРезерв; - - Если СвойстваОперации = Неопределено Тогда - НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недопустимая операция ""%1""'"), СтрокаСимволов); - - ИначеЕсли СвойстваОперации.ЭтоРезерв Тогда - НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Операция ""%1"" не поддерживается'"), СтрокаСимволов); - КонецЕсли; - -КонецПроцедуры - -// Для функции РазобранноеОграничение и косвенно для многих других. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * СимволыЯзыка - см. СимволыЯзыка -// * СимволыЦифр - см. СимволыЦифр -// * ОперацииЯзыка - см. ОперацииЯзыка -// * СловаЯзыка - см. СловаЯзыка -// * ТипыТаблиц - см. ТипыТаблиц -// -Функция СинтаксисЯзыка() Экспорт - - СинтаксисЯзыка = Новый Структура; - СинтаксисЯзыка.Вставить("СимволыЯзыка", СимволыЯзыка()); - СинтаксисЯзыка.Вставить("СимволыЦифр", СимволыЦифр()); - СинтаксисЯзыка.Вставить("ОперацииЯзыка", ОперацииЯзыка()); - СинтаксисЯзыка.Вставить("СловаЯзыка", СловаЯзыка()); - СинтаксисЯзыка.Вставить("ТипыТаблиц", ТипыТаблиц()); - - Возврат Новый ФиксированнаяСтруктура(СинтаксисЯзыка); - -КонецФункции - -// Для функции СинтаксисЯзыка. -// -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - Строка - символ -// * Значение - Строка - вид символа -// -Функция СимволыЯзыка() - - СимволыЯзыка = Новый Соответствие; - - Для КодСимвола = КодСимвола("А") // @Non-NLS - По КодСимвола("Я") Цикл // @Non-NLS - - СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); - КонецЦикла; - Для КодСимвола = КодСимвола("а") // @Non-NLS - По КодСимвола("я") Цикл // @Non-NLS - - СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); - КонецЦикла; - Для КодСимвола = КодСимвола("A") По КодСимвола("Z") Цикл - - СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); - КонецЦикла; - Для КодСимвола = КодСимвола("a") По КодСимвола("z") Цикл - - СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); - КонецЦикла; - - СимволыЯзыка.Вставить("_", "СимволСлова"); - СимволыЯзыка.Вставить(".", "СимволСлова"); - - Для КодСимвола = КодСимвола("0") По КодСимвола("9") Цикл - СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); - КонецЦикла; - - СимволыЯзыка.Вставить(" ", "Отступ"); - СимволыЯзыка.Вставить(Символы.Таб, "Отступ"); - СимволыЯзыка.Вставить(Символы.ПС, "Отступ"); - - СимволыЯзыка.Вставить("""", "ОграничительСтроки"); - - СимволыЯзыка.Вставить("(", "Разделитель"); - СимволыЯзыка.Вставить(")", "Разделитель"); - СимволыЯзыка.Вставить(",", "Разделитель"); - СимволыЯзыка.Вставить(";", "Разделитель"); - СимволыЯзыка.Вставить("=", "СимволОперации"); - СимволыЯзыка.Вставить("<", "СимволОперации"); - СимволыЯзыка.Вставить(">", "СимволОперации"); - - // Не поддерживаются. - СимволыЯзыка.Вставить("+", "СимволОперации"); - СимволыЯзыка.Вставить("-", "СимволОперации"); - СимволыЯзыка.Вставить("*", "СимволОперации"); - СимволыЯзыка.Вставить("/", "СимволОперации"); - - Возврат Новый ФиксированноеСоответствие(СимволыЯзыка); - -КонецФункции - -// Для функции СинтаксисЯзыка. -// -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - Строка - символ -// * Значение - Булево - Истина -// -Функция СимволыЦифр() - - СимволыЦифр = Новый Соответствие; - - Для КодСимвола = КодСимвола("0") По КодСимвола("9") Цикл - СимволыЦифр.Вставить(Символ(КодСимвола), Истина); - КонецЦикла; - - Возврат Новый ФиксированноеСоответствие(СимволыЦифр); - -КонецФункции - -// Для функции СинтаксисЯзыка. -// -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - Строка - слово на русском и английском языках. -// * Значение - см. СвойстваСлова -// -Функция СловаЯзыка() - - Слова = Новый Соответствие; - - ДобавитьСловоЯзыка(Слова, "ПрисоединитьДополнительныеТаблицы", - "AttachAdditionalTables", "Начало", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ЭтотСписок", - "ThisList", "НачалоСписок", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "РазрешитьЧтениеИзменение", - "AllowReadUpdate", "Начало", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "РазрешитьЧтение", - "AllowRead", "Начало", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "РазрешитьИзменениеЕслиРазрешеноЧтение", - "AllowUpdateIfReadingAllowed", "Начало", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Где", - "Where", "НачалоГде"); // @Non-NLS - - ДобавитьСловоЯзыка(Слова, "Левое", - "Left", "Присоединение"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Соединение", - "Join", "Присоединение"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "По", - "On", "Присоединение"); // @Non-NLS - - ДобавитьСловоЯзыка(Слова, "И", - "And", "Соединитель", , 2); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Или", - "Or", "Соединитель", , 1); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "В", - "In", "Соединитель", , 5); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Как", - "As", "Соединитель"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Кроме", - "Except", "Соединитель"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Только", - "Only", "Соединитель"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Есть", - "Is", "Соединитель", , 7); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Не", - "Not", "Оператор", , 3); // @Non-NLS - - ДобавитьСловоЯзыка(Слова, "Выбор", - "Case", "СловоВыбора"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Когда", - "When", "СловоВыбора"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Тогда", - "Then", "СловоВыбора"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Иначе", - "Else", "СловоВыбора"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Конец", - "End", "СловоВыбора"); // @Non-NLS - - ДобавитьСловоЯзыка(Слова, "ЕстьNull", - "IsNull", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Выразить", - "Cast", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Значение", - "Value", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ТипЗначения", - "ValueType", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Тип", - "Type", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ЗначениеРазрешено", - "ValueAllowed", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ЧтениеОбъектаРазрешено", - "ObjectReadingAllowed", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ИзменениеОбъектаРазрешено", - "ObjectUpdateAllowed", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ЧтениеСпискаРазрешено", - "ListReadingAllowed", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ИзменениеСпискаРазрешено", - "ListUpdateAllowed", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ДляВсехСтрок", - "ForAllRows", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ДляОднойИзСтрок", - "ForAtLeastOneRow", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ЭтоАвторизованныйПользователь", - "IsAuthorizedUser", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ПравоДоступа", - "AccessRight", "Функция", Ложь); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "РольДоступна", - "IsInRole", "Функция", Ложь); // @Non-NLS - - ДобавитьСловоЯзыка(Слова, "ПустаяСсылка", - "EmptyRef", "ЗначениеСравнения"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Отключено", - "Disabled", "ЗначениеСравнения"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Неопределено", - "Undefined", "ЗначениеСравнения"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Null", - "Null", "ЗначениеСравнения"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Ложь", - "False", "ЗначениеУточнения"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Истина", - "True", "ЗначениеУточнения"); // @Non-NLS - - ДобавитьСловоЯзыка(Слова, "Строка", - "String", "ИмяТипа"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Число", - "Number", "ИмяТипа"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Дата", - "Date", "ИмяТипа"); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Булево", - "Boolean", "ИмяТипа"); // @Non-NLS - - // Неподдерживаемые, зарезервированные слова. - ДобавитьСловоЯзыка(Слова, "Выбрать", - "Select", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Первые", - "Top", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Различные", - "Distinct", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Из", - "From", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Внутреннее", - "Inner", "Присоединение", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Полное", - "Full", "Присоединение", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Сгруппировать", - "Group", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Имеющие", - "Having", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Упорядочить", - "Order", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Итоги", - "Totals", "Неопределен", , , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Год", - "Year", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Квартал", - "Quarter", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Месяц", - "Month", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ДеньГода", - "DayOfYear", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "День", - "Day", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Неделя", - "Week", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ДеньНедели", - "Weekday", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Час", - "Hour", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Минута", - "Minute", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Секунда", - "Second", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "НачалоПериода", - "BeginOfPeriod", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "КонецПериода", - "EndOfPeriod", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ДобавитьКДате", - "DateAdd", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "РазностьДат", - "DateDiff", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Сумма", - "Sum", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Минимум", - "Min", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Максимум", - "Max", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Среднее", - "Avg", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Количество", - "Count", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "Представление", - "Presentation", "Функция", Ложь, , Истина); // @Non-NLS - ДобавитьСловоЯзыка(Слова, "ПредставлениеСсылки", - "RefPresentation", "Функция", Ложь, , Истина); // @Non-NLS - - Возврат Новый ФиксированноеСоответствие(Слова); - -КонецФункции - -// Для функции СинтаксисЯзыка. -// -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - Строка - слово на русском и английском языках. -// * Значение - см. СвойстваСлова -// -Функция ОперацииЯзыка() - - ОперацииЯзыка = Новый Соответствие; - - ДобавитьСловоЯзыка(ОперацииЯзыка, "=", "=", "Соединитель", , 4); - ДобавитьСловоЯзыка(ОперацииЯзыка, "<>", "<>", "Соединитель", , 4); - - // Неподдерживаемые, зарезервированные операции. - ДобавитьСловоЯзыка(ОперацииЯзыка, "<", "<", "Соединитель", , 4, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, "<=", "<=", "Соединитель", , 4, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, ">", ">", "Соединитель", , 4, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, ">=", ">=", "Соединитель", , 4, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, "+", "+", "Соединитель", , 1, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, "-", "-", "Соединитель", , 1, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, "*", "*", "Соединитель", , 6, Истина); - ДобавитьСловоЯзыка(ОперацииЯзыка, "/", "/", "Соединитель", , 6, Истина); - - Возврат Новый ФиксированноеСоответствие(ОперацииЯзыка); - -КонецФункции - -// Для функций СловаЯзыка и ОперацииЯзыка. -Процедура ДобавитьСловоЯзыка(Слова, ЯзыкРусский, ЯзыкАнглийский, ТипСлова, - ВерхнийРегистр = Истина, Приоритет = 0, ЭтоРезерв = Ложь) - - СвойстваСлова = СвойстваСлова(ЯзыкРусский, - ЯзыкАнглийский, ТипСлова, ВерхнийРегистр, Приоритет, ЭтоРезерв); - - Слова.Вставить(ВРег(ЯзыкРусский), СвойстваСлова); - Слова.Вставить(ВРег(ЯзыкАнглийский), СвойстваСлова); - -КонецПроцедуры - -// Для процедуры ДобавитьСловоЯзыка. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * Идентификатор - Строка - слово языка на языке конфигурации (русском или английском). -// * ЯзыкРусский - Строка - слово языка на русском языке. -// * ЯзыкАнглийский - Строка - слово языка на английском языке. -// * Тип - Строка - имя типа слова. -// * ВерхнийРегистр - Булево -// * Приоритет - Число -// * ЭтоРезерв - Булево -// -Функция СвойстваСлова(ЯзыкРусский, ЯзыкАнглийский, ТипСлова, ВерхнийРегистр, Приоритет, ЭтоРезерв) - - СвойстваСлова = Новый Структура; - СвойстваСлова.Вставить("Идентификатор", ?(КодСимвола(Лев(ТипСлова, 1)) > 122, ЯзыкРусский, ЯзыкАнглийский)); - СвойстваСлова.Вставить("ЯзыкРусский", ЯзыкРусский); - СвойстваСлова.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); - СвойстваСлова.Вставить("Тип", ТипСлова); - СвойстваСлова.Вставить("ВерхнийРегистр", ВерхнийРегистр); - СвойстваСлова.Вставить("Приоритет", Приоритет); - СвойстваСлова.Вставить("ЭтоРезерв", ЭтоРезерв); - - Возврат Новый ФиксированнаяСтруктура(СвойстваСлова); - -КонецФункции - -// Для функции СинтаксисЯзыка. -// -// Возвращаемое значение: -// Структура: -// * ПоИменам - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя типа таблиц на русском и на английском языках. -// ** Значение - см. СвойстваТипаТаблиц -// * ПоКоллекциям - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя коллекции на языке конфигурации (русском или английском). -// ** Значение - см. СвойстваТипаТаблиц -// -Функция ТипыТаблиц() - - ТипыТаблиц = Новый Структура; - ТипыТаблиц.Вставить("ПоИменам", Новый Соответствие); - ТипыТаблиц.Вставить("ПоКоллекциям", Новый Соответствие); - - // Установка имен типов таблиц. - ДобавитьТипТаблиц(ТипыТаблиц, "ПланОбмена", - "ExchangePlan", "ПланыОбмена"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "КритерийОтбора", - "FilterCriterion", "КритерииОтбора"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Константы", - "Constants", ""); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Константа", - "Constant", "Константы"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Справочник", - "Catalog", "Справочники"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Последовательность", - "Sequence", "Последовательности"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Документ", - "Document", "Документы"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "ЖурналДокументов", - "DocumentJournal", "ЖурналыДокументов"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Перечисление", - "Enum", "Перечисления"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "ПланВидовХарактеристик", - "ChartOfCharacteristicTypes", "ПланыВидовХарактеристик"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "ПланСчетов", - "ChartOfAccounts", "ПланыСчетов"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "ПланВидовРасчета", - "ChartOfCalculationTypes", "ПланыВидовРасчета"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "РегистрСведений", - "InformationRegister", "РегистрыСведений"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "РегистрНакопления", - "AccumulationRegister", "РегистрыНакопления"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "РегистрБухгалтерии", - "AccountingRegister", "РегистрыБухгалтерии"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "РегистрРасчета", - "CalculationRegister", "РегистрыРасчета"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "БизнесПроцесс", - "BusinessProcess", "БизнесПроцессы"); // @Non-NLS - ДобавитьТипТаблиц(ТипыТаблиц, "Задача", - "Task", "Задачи"); // @Non-NLS - - // Установка основных свойств основных типов таблиц. - ИменаТиповТаблиц = "ПланОбмена,Справочник,Документ,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета,БизнесПроцесс,Задача"; - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЭтоСсылочныйТип", Истина); - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьОграничение", Истина); - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Разрешены"); - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Использование", "Разрешено"); - - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Разрешены"); - - ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ТабличныеЧасти", "Разрешены"); - - ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ВерсияДанных", - "DataVersion", "Запрещено"); // @Non-NLS - ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Представление", - "Presentation", "Запрещено"); // @Non-NLS - - ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Изменения", - "Changes", "Запрещено"); // @Non-NLS - - // Установка основных свойств регистров. - ИменаТиповТаблиц = "РегистрСведений,РегистрРасчета"; - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Ресурсы", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Разрешены"); - - ИменаТиповТаблиц = "РегистрНакопления,РегистрБухгалтерии"; - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Недопустимы"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Ресурсы", "Недопустимы"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Недопустимы"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Недопустимы"); - - ИменаТиповТаблиц = "РегистрСведений,РегистрНакопления,РегистрБухгалтерии,РегистрРасчета"; - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьОграничение", Истина); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Измерения", "Разрешены"); - - ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Изменения", - "Changes", "Запрещено"); // @Non-NLS - - // Установка некоторых из указанных ранее свойств для остальных типов таблиц. - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "Последовательность", "ЕстьОграничение", Истина); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Последовательность", "Измерения", "Разрешены"); - - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "ОбщиеРеквизиты", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "СтандартныеРеквизиты", "Разрешены"); - - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "Перечисление", "ЭтоСсылочныйТип", Истина); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Перечисление", "СтандартныеРеквизиты", "Разрешены"); - - ИменаТиповТаблиц = "Константа,РегистрСведений"; - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Использование", "Разрешено"); - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "КритерийОтбора", "Использование", "Недопустимо"); - - ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "Константа", "Изменения", - "Changes", - "Запрещено"); // @Non-NLS-2 - ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "РегистрСведений", "СрезПервых", - "SliceFirst", - "Недопустимо"); // @Non-NLS-2 - ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "РегистрСведений", "СрезПоследних", - "SliceLast", - "Недопустимо"); // @Non-NLS-2 - ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "БизнесПроцесс", "Точки", - "Points", - "Запрещено"); // @Non-NLS-2 - - // Установка специализированных свойств. - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "ПланСчетов", "ПризнакиУчетаСубконто", "Разрешены"); - - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "Графы", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ПланСчетов", "ПризнакиУчета", "Разрешены"); - ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Задача", "РеквизитыАдресации", "Разрешены"); - - ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, "ПланСчетов", "СтандартныеТабличныеЧасти", "Разрешены"); - ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, "ПланВидовРасчета", "СтандартныеТабличныеЧасти", "Разрешены"); - - ИменаТиповТаблиц = "Справочник,Перечисление,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета"; - УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьПредопределенные", Истина); - - // Уточнение стандартных полей типов таблиц. - ИменаТиповТаблиц = "Документ,РегистрСведений,РегистрНакопления,РегистрБухгалтерии"; - ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "МоментВремени", - "PointInTime", "Недопустимо"); // @Non-NLS - - ИменаТиповТаблиц = "Справочник,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета"; - ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ИмяПредопределенныхДанных", - "PredefinedDataName", "Запрещено"); // @Non-NLS - - ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Константа", "Значение", - "Value", - "Разрешено"); // @Non-NLS-2 - ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Последовательность", "Регистратор", - "Recorder", - "Разрешено"); // @Non-NLS-2 - ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Последовательность", "Период", - "Period", - "Разрешено"); // @Non-NLS-2 - ДобавитьПолеТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "Тип", - "Type", - "Недопустимо"); // @Non-NLS-2 - ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Перечисление", "Порядок", - "Order", - "Запрещено"); // @Non-NLS-2 - - Возврат ТипыТаблиц; - -КонецФункции - -// Для функции ТипыТаблиц. -Процедура ДобавитьТипТаблиц(ТипыТаблиц, ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции) - - СвойстваТипаТаблиц = СвойстваТипаТаблиц(ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции); - - ТипыТаблиц.ПоИменам.Вставить(ВРег(ЯзыкРусский), СвойстваТипаТаблиц); - ТипыТаблиц.ПоИменам.Вставить(ВРег(ЯзыкАнглийский), СвойстваТипаТаблиц); - - Если ЗначениеЗаполнено(ИмяКоллекции) Тогда - ТипыТаблиц.ПоКоллекциям.Вставить(ИмяКоллекции, СвойстваТипаТаблиц); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ДобавитьСловоЯзыка. -// -// Возвращаемое значение: -// ФиксированнаяСтруктура: -// * ИмяКоллекции - Строка - имя коллекции на языке конфигурации (русском или английском). -// * ЯзыкРусский - Строка - имя типа таблиц на русском языке. -// * ЯзыкАнглийский - Строка - имя типа таблиц на английском языке. -// * ЭтоСсылочныйТип - Булево -// * ЕстьОграничение - Булево -// * ЕстьПредопределенные - Булево -// * КоллекцииПолей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя коллекции полей на языке конфигурации (русском или английском). -// ** Значение - Строка - -// "Разрешены" - можно использовать без ограничений. -// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// -// * КоллекцииТабличныхЧастей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя коллекции табличных частей на языке конфигурации (русском или английском). -// ** Значение - Строка - -// "Разрешены" - можно использовать без ограничений. -// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// -// * ОбщиеРеквизиты - Строка - -// "Разрешены" - можно использовать без ограничений. -// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// "Отсутствуют" - не существуют у объекта метаданных. -// -// * ПризнакиУчетаСубконто - Строка - -// "Разрешены" - можно использовать без ограничений. -// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// "Отсутствуют" - не существуют у объекта метаданных. -// -// * УточнениеПолей - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя поля таблиц на русском и на английском языках. -// ** Значение - см. УточнениеПоля -// -// * УточнениеТаблиц - Соответствие из КлючИЗначение: -// ** Ключ - Строка - имя расширения таблиц на русском и на английском языках. -// ** Значение - см. УточнениеТаблиц -// -// * Использование - Строка - -// "Разрешено" - можно использовать без ограничений. -// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// "Запрещено" - запрещено присоединять, как дополнительную таблицу в ограничении доступа БСП. -// -Функция СвойстваТипаТаблиц(ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции) - - СвойстваТипаТаблиц = Новый Структура; - СвойстваТипаТаблиц.Вставить("ИмяКоллекции", ИмяКоллекции); - СвойстваТипаТаблиц.Вставить("ЯзыкРусский", ЯзыкРусский); - СвойстваТипаТаблиц.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); - СвойстваТипаТаблиц.Вставить("ЭтоСсылочныйТип", Ложь); - СвойстваТипаТаблиц.Вставить("ЕстьОграничение", Ложь); - СвойстваТипаТаблиц.Вставить("ЕстьПредопределенные", Ложь); - СвойстваТипаТаблиц.Вставить("КоллекцииПолей", Новый Соответствие); - СвойстваТипаТаблиц.Вставить("КоллекцииТабличныхЧастей", Новый Соответствие); - СвойстваТипаТаблиц.Вставить("ОбщиеРеквизиты", "Отсутствуют"); - СвойстваТипаТаблиц.Вставить("ПризнакиУчетаСубконто", "Отсутствуют"); - СвойстваТипаТаблиц.Вставить("УточнениеПолей", Новый Соответствие); - СвойстваТипаТаблиц.Вставить("УточнениеТаблиц", Новый Соответствие); - СвойстваТипаТаблиц.Вставить("Использование", "Запрещено"); - - Возврат СвойстваТипаТаблиц; - -КонецФункции - -// Для функции ТипыТаблиц. -Процедура УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, Свойство, Значение) - - Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл - СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); - СвойстваТипаТаблиц[Свойство] = Значение; - КонецЦикла; - -КонецПроцедуры - -// Для функции ТипыТаблиц. -Процедура ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ИмяКоллекции, Использование) - - Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл - СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); - СвойстваТипаТаблиц.КоллекцииПолей.Вставить(ИмяКоллекции, Использование); - КонецЦикла; - -КонецПроцедуры - -// Для функции ТипыТаблиц. -Процедура ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ИмяКоллекции, Использование) - - Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл - СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); - СвойстваТипаТаблиц.КоллекцииТабличныхЧастей.Вставить(ИмяКоллекции, Использование); - КонецЦикла; - -КонецПроцедуры - -// Для функции ТипыТаблиц. -Процедура ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ЯзыкРусский, ЯзыкАнглийский, Использование) - - Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл - УточнениеПоля = УточнениеПоля(ЯзыкРусский, ЯзыкАнглийский, Использование); - СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); - - СвойстваТипаТаблиц.УточнениеПолей.Вставить(ВРег(ЯзыкРусский), УточнениеПоля); - СвойстваТипаТаблиц.УточнениеПолей.Вставить(ВРег(ЯзыкАнглийский), УточнениеПоля); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ДобавитьПолеТипаТаблиц. -// -// Возвращаемое значение: -// Структура: -// * ЯзыкРусский - Строка - имя поля таблиц на русском языке. -// * ЯзыкАнглийский - Строка - имя поля таблиц на английском языке. -// * Использование - Строка - -// "Разрешено" - можно использовать без ограничений. -// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// "Запрещено" - запрещено использовать в ограничении доступа БСП. -// -Функция УточнениеПоля(ЯзыкРусский, ЯзыкАнглийский, Использование) - - УточнениеПоля = Новый Структура; - УточнениеПоля.Вставить("ЯзыкРусский", ЯзыкРусский); - УточнениеПоля.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); - УточнениеПоля.Вставить("Использование", Использование); - - Возврат УточнениеПоля; - -КонецФункции - -// Для функции ТипыТаблиц. -Процедура ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ЯзыкРусский, ЯзыкАнглийский, Использование) - - Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл - УточнениеТаблиц = УточнениеТаблиц(ЯзыкРусский, ЯзыкАнглийский, Использование); - СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); - - СвойстваТипаТаблиц.УточнениеТаблиц.Вставить(ВРег(ЯзыкРусский), УточнениеТаблиц); - СвойстваТипаТаблиц.УточнениеТаблиц.Вставить(ВРег(ЯзыкАнглийский), УточнениеТаблиц); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ДобавитьПолеТипаТаблиц. -// -// Возвращаемое значение: -// Структура: -// * ЯзыкРусский - Строка - имя расширения таблиц на русском языке. -// * ЯзыкАнглийский - Строка - имя расширения таблиц на английском языке. -// * Использование - Строка - -// "Разрешено" - можно использовать без ограничений. -// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. -// "Запрещено" - запрещено использовать в ограничении доступа БСП. -// -Функция УточнениеТаблиц(ЯзыкРусский, ЯзыкАнглийский, Использование) - - УточнениеТаблиц = Новый Структура; - УточнениеТаблиц.Вставить("ЯзыкРусский", ЯзыкРусский); - УточнениеТаблиц.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); - УточнениеТаблиц.Вставить("Использование", Использование); - - Возврат УточнениеТаблиц; - -КонецФункции - -#КонецОбласти - -#Область СинтаксическийАнализ - -// Для функции РазобранноеОграничение. -// -// Параметры: -// ВнутренниеДанные - см. НовыеВнутренниеДанные -// -// Возвращаемое значение: -// Структура: -// * ДополнительныеТаблицы - Массив из см. НовоеОписаниеСоединения -// * ПсевдонимОсновнойТаблицы - Строка -// * ОграничениеЧтения - Структура -// * ОграничениеИзменения - Структура -// -Функция ЧастиОграничения(ВнутренниеДанные) - - ЧастиОграничения = Новый Структура; - ЧастиОграничения.Вставить("ДополнительныеТаблицы", Новый Массив); - ЧастиОграничения.Вставить("ПсевдонимОсновнойТаблицы", ""); - ЧастиОграничения.Вставить("ОграничениеЧтения", Новый Структура); - ЧастиОграничения.Вставить("ОграничениеИзменения", Новый Структура); - - ТаблицаНаборовСимволов = ВнутренниеДанные.ТаблицаНаборовСимволов; - - Если ТаблицаНаборовСимволов.Количество() = 0 Тогда - Возврат ЧастиОграничения; - КонецЕсли; - - ТаблицаНаборовСимволов.Колонки.Добавить("Строки", Новый ОписаниеТипов("Массив")); - ТаблицаНаборовСимволов.Колонки.Добавить("КонечнаяСтрока"); - - // Разделение ограничения на основные части. - Строки = ТаблицаНаборовСимволов.НайтиСтроки(Новый Структура("Символы, Вид", ";", "Разделитель")); - - ИндексыСтрокРазделителя = Новый Массив; - Для Каждого Строка Из Строки Цикл - ИндексыСтрокРазделителя.Добавить(ТаблицаНаборовСимволов.Индекс(Строка)); - КонецЦикла; - ИндексыСтрокРазделителя.Добавить(ТаблицаНаборовСимволов.Количество() - 1); - - СвойстваЧастей = Новый Массив; // Массив из см. НовыеСвойстваЧасти - ИндексСтроки = 0; - Для Каждого ИндексСтрокиРазделителя Из ИндексыСтрокРазделителя Цикл - СтрокиЧасти = Новый Массив; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов - Пока ИндексСтроки < ИндексСтрокиРазделителя Цикл - СтрокаЧасти = ТаблицаНаборовСимволов[ИндексСтроки]; - Если СтрокаЧасти.Вид <> "НедопустимыйСимвол" Тогда - СтрокиЧасти.Добавить(СтрокаЧасти); - КонецЕсли; - ИндексСтроки = ИндексСтроки + 1; - КонецЦикла; - СтрокаРазделителя = ТаблицаНаборовСимволов[ИндексСтрокиРазделителя]; - Если СтрокиЧасти.Количество() = 0 Тогда - СтрокиЧасти.Добавить(СтрокаРазделителя); - КонецЕсли; - СвойстваЧасти = НовыеСвойстваЧасти(); - СвойстваЧасти.Вставить("Строки", СтрокиЧасти); - СвойстваЧасти.Вставить("СтрокаРазделителя", СтрокаРазделителя); - СвойстваЧастей.Добавить(СвойстваЧасти); - ПерваяСтрокаЧасти = СтрокиЧасти[0]; - Если ПерваяСтрокаЧасти.Вид = "КлючевоеСлово" - И ПерваяСтрокаЧасти.Тип = "Начало" Тогда - - СвойстваЧасти.Вставить("Имя", ПерваяСтрокаЧасти.Уточнение); - СвойстваЧасти.Вставить("Представление", ПерваяСтрокаЧасти.Символы); - - РазобратьЧастьОграничения(СвойстваЧасти, ВнутренниеДанные); - Иначе - СвойстваЧасти.Вставить("Имя", ""); - СвойстваЧасти.Вставить("Представление", ""); - КонецЕсли; - ИндексСтроки = ИндексСтрокиРазделителя + 1; - КонецЦикла; - - ДобавитьПсевдонимыПоУмолчанию(ВнутренниеДанные); - - // Анализ части 1. - СвойстваЧасти1 = СвойстваЧастей[0]; - - Если СвойстваЧасти1.Имя = "" Тогда - УстановитьОшибкуНачалаЧасти(СвойстваЧасти1, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'В начале первой части текста ограничения нет ни одного из ключевых слов - |""%1"", ""%2"", ""%3""'"), - "РазрешитьЧтениеИзменение,РазрешитьЧтение,ПрисоединитьДополнительныеТаблицы")); - Возврат ЧастиОграничения; - - ИначеЕсли СвойстваЧасти1.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда - УстановитьОшибкуНачалаЧасти(СвойстваЧасти1, - НСтр("ru = 'В начале первой части текста ограничения найдено недопустимое ключевое слово'")); - Возврат ЧастиОграничения; - - ИначеЕсли СвойстваЧастей.Количество() = 1 - И ( СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы" - Или СвойстваЧасти1.Имя = "РазрешитьЧтение" ) Тогда - - УстановитьОшибкуНачалаЧасти(ТаблицаНаборовСимволов, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Текст ограничения не может быть только из одной части - |с ключевым словом ""%1""'"), СвойстваЧасти1.Представление)); - Возврат ЧастиОграничения; - КонецЕсли; - - УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти1); - - Если СвойстваЧастей.Количество() < 2 Тогда - Возврат ЧастиОграничения; - КонецЕсли; - - // Анализ части 2. - СвойстваЧасти2 = СвойстваЧастей[1]; - - Если СвойстваЧасти1.Имя = "РазрешитьЧтениеИзменение" Тогда - УстановитьОшибкуНачалаЧасти(СвойстваЧасти1.СтрокаРазделителя, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Второй части текста ограничения не должно быть, когда - |в первой части указано ключевое слово ""%1""'"), СвойстваЧасти1.Представление)); - Возврат ЧастиОграничения; - КонецЕсли; - - Если СвойстваЧасти2.Имя = "" Тогда - Если СвойстваЧасти1.Имя = "РазрешитьЧтение" Тогда - УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'В начале второй части текста ограничения нет - |ключевого слова ""%1""'"), - "РазрешитьИзменениеЕслиРазрешеноЧтение")); - Иначе // СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы". - УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'В начале второй части текста ограничения нет ни одного из ключевых слов - |""%1"", ""%2""'"), - "РазрешитьЧтениеИзменение,РазрешитьЧтение")); - КонецЕсли; - Возврат ЧастиОграничения; - - ИначеЕсли СвойстваЧасти1.Имя = "РазрешитьЧтение" - И СвойстваЧасти2.Имя <> "РазрешитьИзменениеЕслиРазрешеноЧтение" - Или СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы" - И СвойстваЧасти2.Имя <> "РазрешитьЧтениеИзменение" - И СвойстваЧасти2.Имя <> "РазрешитьЧтение" Тогда - - УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, - НСтр("ru = 'В начале второй части текста ограничения найдено недопустимое ключевое слово'")); - Возврат ЧастиОграничения; - - ИначеЕсли СвойстваЧастей.Количество() = 2 - И СвойстваЧасти2.Имя = "РазрешитьЧтение" Тогда - - УстановитьОшибкуНачалаЧасти(ТаблицаНаборовСимволов, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Текст ограничения не может быть только из двух частей, когда - |во второй части указано ключевое слово ""%1""'"), СвойстваЧасти2.Представление)); - Возврат ЧастиОграничения; - КонецЕсли; - - УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти2); - - Если СвойстваЧастей.Количество() < 3 Тогда - Возврат ЧастиОграничения; - КонецЕсли; - - // Анализ части 3. - СвойстваЧасти3 = СвойстваЧастей[2]; - - Если СвойстваЧасти2.Имя = "РазрешитьЧтениеИзменение" Тогда - УстановитьОшибкуНачалаЧасти(СвойстваЧасти2.СтрокаРазделителя, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Третьей части текста ограничения не должно быть, когда - |во второй части указано ключевое слово ""%1""'"), СвойстваЧасти2.Представление)); - Возврат ЧастиОграничения; - КонецЕсли; - - Если СвойстваЧасти3.Имя = "" Тогда - УстановитьОшибкуНачалаЧасти(СвойстваЧасти3, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'В начале третьей части текста ограничения нет - |ключевого слово ""%1""'"), - "РазрешитьИзменениеЕслиРазрешеноЧтение")); - Возврат ЧастиОграничения; - - ИначеЕсли СвойстваЧасти2.Имя = "РазрешитьЧтение" - И СвойстваЧасти3.Имя <> "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда - - УстановитьОшибкуНачалаЧасти(СвойстваЧасти3, - НСтр("ru = 'В начале третьей части текста ограничения найдено недопустимое ключевое слово'")); - Возврат ЧастиОграничения; - КонецЕсли; - - УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти3); - - Возврат ЧастиОграничения; - -КонецФункции - -// Процедура: -// Родитель - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов -// - Структура -// Строка - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов -// Контекст - Структура: -// * Таблица - см. ТаблицаНаборовСимволов -// -Процедура СтрокаДобавить(Родитель, Строка, Контекст) - - Если ТипЗнч(Строка) = Тип("СтрокаТаблицыЗначений") Тогда - Родитель.Строки.Добавить(Контекст.ТаблицаНаборовСимволов.Индекс(Строка)); - Иначе - Родитель.Строки.Добавить(Строка); - КонецЕсли; - -КонецПроцедуры - -// Параметры: -// ОписаниеСтроки - Число - индекс таблицы значений. -// - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов -// - Структура - см. ДополнительнаяСтрока -// Контекст - Структура: -// * Таблица - см. ТаблицаНаборовСимволов -// -// Возвращаемое значение: -// см. ДополнительнаяСтрока -// -Функция СтрокаТаблицы(ОписаниеСтроки, Контекст) - - Если ТипЗнч(ОписаниеСтроки) = Тип("Число") Тогда - Строка = Контекст.ТаблицаНаборовСимволов[ОписаниеСтроки]; - Иначе - Строка = ОписаниеСтроки; - КонецЕсли; - - Возврат Строка; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// * СтрокаРазделителя - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов -// * Имя - Строка -// * Представление - Строка -// -Функция НовыеСвойстваЧасти() - - Возврат Новый Структура; - -КонецФункции - -// Возвращаемое значение: -// Структура: -// * Таблица - Строка -// * Псевдоним - Строка -// * УсловиеСоединения - см. ОписаниеУзла -// * ПсевдонимыТребуемыхТаблиц - Массив из Строка -// * ПоляУсловияСоединения - Массив из см. ПараПолейУсловияСоединения -// * ТекстУсловияСоединения - Строка -// -Функция НовоеОписаниеСоединения() - - Возврат Новый Структура; - -КонецФункции - - -// Возвращаемое значение: -// Структура: -// * Источник - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов -// -// * Узел - Строка - одна из строк "Поле", "Значение", "Константа", -// "И", "Или", "Не", "=", "<>", "В", "ЕстьNull", "Тип", "ТипЗначения", "Выбор", -// "ЗначениеРазрешено", "ЭтоАвторизованныйПользователь", -// "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено", -// "ЧтениеСпискаРазрешено", "ИзменениеСпискаРазрешено", -// "ДляВсехСтрок", "ДляОднойИзСтрок", -// "ПравоДоступа", "РольДоступна". -// -// Свойства узла Поле. -// * Имя - Строка - имя поля, например, "Организация" или "ОсновнаяОрганизация". -// * Таблица - Строка - имя таблицы этого поля (или пустая строка для основной таблицы). -// * Псевдоним - Строка - имя псевдонима присоединяемой таблицы этого поля (или пустая строка для основной таблицы), -// например, "РегистрСведенийНастройки" для поля "ОсновнаяОрганизация". -// * Выразить - Строка - имя таблицы (если используется), например, для описания поля в виде: -// "ВЫРАЗИТЬ(ВЫРАЗИТЬ(Владелец КАК Справочник.Файлы).ВладелецФайла КАК Справочник.Организации).Ссылка". -// * Вложение - Структура - узел Поле, содержащий вложенное действие ВЫРАЗИТЬ (с или без ЕстьNull). -// - Неопределено - нет вложенного поля. -// * ЕстьNull - Структура - узел Значение Или Константа, например, для описания выражения вида -// "ЕстьNULL(Владелец, Значение(Справочник.Файлы.ПустаяСсылка))". -// - Неопределено - если ЕстьNull не используется (в том числе, когда свойство Вложение заполнено). -// * ИмяИсточник - СтрокаТаблицыЗначений -// - Неопределено -// * ВыразитьИсточник - СтрокаТаблицыЗначений -// - Неопределено -// * ЕстьNullИсточник - СтрокаТаблицыЗначений -// - Неопределено -// -// Свойства узлов Значение и Тип. -// * Имя - Строка - имя значения, например, "Справочник.Организации.Основная", -// "Справочник.Организации.ПустаяСсылка", -// имя таблицы, например, "Справочник.Организации". -// -// Свойства узла Константа. -// * Значение - Булево -// - Число -// - Строка -// - Неопределено - Ложь, Истина, произвольное -// целое число до 16 разрядов или произвольная строка до 150 символов. -// -// Свойства узлов И, Или (любой узел, кроме Значение и Константа). -// * Аргументы - Массив из см. ОписаниеУзла -// -// Свойства узла Не (любой узел, кроме Значение и Константа). -// * Аргумент - см. ОписаниеУзла -// -// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узлов =, <> (ПервыйАргумент - узел Поле, -// ВторойАргумент - узел Значение, Константа, а узел Поле только для условия соединения). -// * ПервыйАргумент - см. ОписаниеУзла -// * ВторойАргумент - см. ОписаниеУзла -// -// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узла В (Искомое - узел Поле, Значения - узлы Значение и/или Константа). -// * Искомое - см. ОписаниеУзла -// * Значения - Массив из см. ОписаниеУзла -// -// Свойства узла ЕстьNull (узел Поле - выражение вида "<Поле> ЕСТЬ NULL"). -// * Аргумент - см. ОписаниеУзла -// -// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узла ТипЗначения (узел Поле). -// * Аргумент - см. ОписаниеУзла -// -// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узла Выбор -// В свойстве Выбор -// узел Поле -// Неопределено - условия содержат выражение, а не узел Значение -// В свойстве Когда -// Условие - узел Значение, если свойство Выбор указано, в противном случае -// узлы И, Или, Не, =, <>, В (распространяется на вложенное содержимое) -// Значение - узел, кроме Выбор -// В свойстве Иначе -// узел, кроме ВЫБОР и Значение (Поле и Константа может быть только типа Булево). -// * Выбор - см. ОписаниеУзла -// * Когда - Массив из Структура: -// ** Условие - см. ОписаниеУзла -// ** Значение - см. ОписаниеУзла -// * Иначе - см. ОписаниеУзла -// -// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) -// -// Свойства узлов ЗначениеРазрешено, ЭтоАвторизованныйПользователь, -// ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, -// ЧтениеСпискаРазрешено, ИзменениеСпискаРазрешено. -// В свойстве Поле - узел Поле. -// * Поле - см. ОписаниеУзла -// * Типы - Массив из Строка - полное имя таблицы -// * ПроверятьТипыКромеУказанных - Булево - если Истина, то все типы свойства Поле, -// кроме указанных в свойстве Типы. -// * УточненияСравнения - Соответствие из КлючИЗначение: -// ** Ключ - Строка - уточняемое значение "Неопределено", "Null", "ПустаяСсылка", -// <полное имя таблицы>, "Число", "Строка", "Дата", "Булево". -// ** Значение - Строка - результат "Ложь", "Истина". -// -// Свойства узлов ДляВсехСтрок, ДляОднойИзСтрок (любой узел). -// * Аргумент - см. ОписаниеУзла. -// -Функция ОписаниеУзла() - - Возврат Новый Структура; - -КонецФункции - -// Для функции ЧастиОграничения. -Процедура УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти) - - Если СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" - Или СвойстваЧасти.Имя = "РазрешитьЧтение" Тогда - - ИмяСвойства = "ОграничениеЧтения"; - - ИначеЕсли СвойстваЧасти.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда - - ИмяСвойства = "ОграничениеИзменения"; - - Иначе // ПрисоединитьДополнительныеТаблицы. - - ИмяСвойства = "ДополнительныеТаблицы"; - ЧастиОграничения.ПсевдонимОсновнойТаблицы = СвойстваЧасти.ПсевдонимОсновнойТаблицы; - КонецЕсли; - - ЧастиОграничения[ИмяСвойства] = СвойстваЧасти.Состав; - -КонецПроцедуры - -// Для функции ЧастиОграничения, процедур РазобратьДополнительныеТаблицы, РазобратьУсловиеОграничения. -// Параметры: -// СвойстваЧасти - см. НовыеСвойстваЧасти -// ТекстОшибки - Строка -// -Процедура УстановитьОшибкуНачалаЧасти(СвойстваЧасти, ТекстОшибки) - - Если ТипЗнч(СвойстваЧасти) = Тип("ТаблицаЗначений") Тогда - СтрокаСОшибкой = СвойстваЧасти[СвойстваЧасти.Количество() - 1]; - - ИначеЕсли ТипЗнч(СвойстваЧасти) = Тип("СтрокаТаблицыЗначений") Тогда - СтрокаСОшибкой = СвойстваЧасти; - Иначе - СтрокаСОшибкой = СвойстваЧасти.Строки[0]; - КонецЕсли; - - СтрокаСОшибкой.ТекстОшибки = ТекстОшибки; - - // Требуется описание вариантов первых ключевых слов частей. - СтрокаСОшибкой.ПозицияОшибки = -1; - -КонецПроцедуры - -// Для процедуры РазобратьСоединение. -// Параметры: -// Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// ИндексСтроки - Число -// ТекстОшибки - Строка -// -Процедура УстановитьОшибкуВнутриЧасти(Строки, ИндексСтроки, ТекстОшибки) - - Если ИндексСтроки < Строки.Количество() Тогда - СтрокаСОшибкой = Строки[ИндексСтроки]; - Иначе - СтрокаСОшибкой = Строки[ИндексСтроки - 1]; - // Ошибка в конце слова. - СтрокаСОшибкой.ПозицияОшибки = СтрДлина(СтрокаСОшибкой.Символы); - КонецЕсли; - - СтрокаСОшибкой.ТекстОшибки = ТекстОшибки; - -КонецПроцедуры - -// Для функции ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. -Процедура УстановитьОшибкуВСтроке(Строка, ТекстОшибки, ВКонцеСлова = Ложь, НомерСлова = 1) - - Если ЗначениеЗаполнено(Строка.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - Если ВКонцеСлова Тогда - Строка.ПозицияОшибки = СтрДлина(Строка.Символы); - - ИначеЕсли НомерСлова > 1 Тогда - СоставИмени = СтрРазделить(Строка.Символы, "."); - Если СоставИмени.Количество() > 1 Тогда - Строка.ПозицияОшибки = СтрДлина(СоставИмени[0]) + 1; - КонецЕсли; - КонецЕсли; - - Строка.ТекстОшибки = ТекстОшибки; - -КонецПроцедуры - -// Для функции ЧастиОграничения. -Процедура РазобратьЧастьОграничения(СвойстваЧасти, ВнутренниеДанные) - - Если СвойстваЧасти.Имя = "ПрисоединитьДополнительныеТаблицы" Тогда - СвойстваЧасти.Вставить("Состав", Новый Массив); - СвойстваЧасти.Вставить("ПсевдонимОсновнойТаблицы", ""); - РазобратьДополнительныеТаблицы(СвойстваЧасти, ВнутренниеДанные); - Иначе - СвойстваЧасти.Вставить("Состав", ОписаниеУзла()); - РазобратьУсловиеОграничения(СвойстваЧасти, ВнутренниеДанные); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьЧастьОграничения. -Процедура РазобратьДополнительныеТаблицы(СвойстваЧасти, ВнутренниеДанные) - - СтрокиЧасти = СвойстваЧасти.Строки; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов - - Если СтрокиЧасти.Количество() < 2 - Или СтрокиЧасти[1].Вид <> "КлючевоеСлово" - Или СтрокиЧасти[1].Уточнение <> "ЭтотСписок" Тогда - УстановитьОшибкуНачалаЧасти( - ?(СтрокиЧасти.Количество() < 3, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[1]), - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" нет - |ключевого слово ""%2""'"), - СвойстваЧасти.Представление, - КлючевоеСловоСУчетомЯзыка("ЭтотСписок", ВнутренниеДанные))); - Возврат; - КонецЕсли; - - ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти, СтрокиЧасти[1]); - - Если СтрокиЧасти.Количество() < 3 - Или СтрокиЧасти[2].Вид <> "КлючевоеСлово" - Или СтрокиЧасти[2].Уточнение <> "Как" Тогда - УстановитьОшибкуНачалаЧасти( - ?(СтрокиЧасти.Количество() < 3, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[2]), - ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'После ключевого слова ""%1"" нет ключевого слово ""%2""'"), - "ЭтотСписок,Как")); - Возврат; - КонецЕсли; - - Если СтрокиЧасти.Количество() < 4 - Или СтрокиЧасти[3].Вид <> "Имя" Тогда - УстановитьОшибкуНачалаЧасти( - ?(СтрокиЧасти.Количество() < 4, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[3]), - ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'После ключевого слова ""%1"" нет псевдонима'"), - "Как")); - Возврат; - КонецЕсли; - - УстановитьПсевдоним(СтрокиЧасти[3], СвойстваЧасти.ПсевдонимОсновнойТаблицы, ВнутренниеДанные); - - // Разделение описания на группы левых соединений. - Соединения = Новый Массив; - ТекущееСоединение = Новый Массив; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов - - Для Индекс = 4 По СтрокиЧасти.Количество()-1 Цикл - СтрокаЧасти = СтрокиЧасти[Индекс]; - - Если СтрокаЧасти.Вид = "КлючевоеСлово" - И СтрокаЧасти.Уточнение = "Левое" Тогда - - Если ТекущееСоединение.Количество() > 0 Тогда - Соединения.Добавить(ТекущееСоединение); - КонецЕсли; - ТекущееСоединение = Новый Массив; - ТекущееСоединение.Добавить(СтрокаЧасти); - - Если Индекс + 1 < СтрокиЧасти.Количество() - И СтрокиЧасти[Индекс + 1].Вид = "КлючевоеСлово" - И СтрокиЧасти[Индекс + 1].Уточнение = "Соединение" Тогда - - Индекс = Индекс + 1; - ТекущееСоединение.Добавить(СтрокиЧасти[Индекс]); - КонецЕсли; - - Продолжить; - КонецЕсли; - ТекущееСоединение.Добавить(СтрокаЧасти); - КонецЦикла; - - Если ТекущееСоединение.Количество() > 0 - Или Соединения.Количество() = 0 Тогда - - Соединения.Добавить(ТекущееСоединение); - КонецЕсли; - - ВнутренниеДанные.Вставить("ДоступныеПсевдонимы", - Новый Соответствие(Новый ФиксированноеСоответствие(ВнутренниеДанные.Псевдонимы))); - - Для Каждого Соединение Из Соединения Цикл - // Условие разбирается универсально (по максимуму возможностей) - // после чего устанавливаются ошибки на запрещенные возможности. - РазобратьСоединение(Соединение, СвойстваЧасти, ВнутренниеДанные); - КонецЦикла; - - // Продолжение разбора после заполнения псевдонимов всех дополнительных таблиц. - Для Каждого ОписаниеСоединения Из СвойстваЧасти.Состав Цикл - ВнутренниеДанные.ДоступныеПсевдонимы.Вставить(ВРег(ОписаниеСоединения.Псевдоним), Истина); - // Допустимы только простые условия: - // Поле1 = Поле2 [И Поле3 = Поле4] [И Поле5 = Константа]. - РазобратьПоляУсловияСоединенияИОтметитьЗапреты(ОписаниеСоединения, ВнутренниеДанные); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры РазобратьДополнительныеТаблицы. -// -// Параметры: -// Соединение - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура РазобратьСоединение(Соединение, СвойстваЧасти, ВнутренниеДанные) - - ОписаниеСоединения = НовоеОписаниеСоединения(); - ОписаниеСоединения.Вставить("Таблица", ""); - ОписаниеСоединения.Вставить("Псевдоним", ""); - ОписаниеСоединения.Вставить("УсловиеСоединения", Неопределено); - - Если Соединение[0].Вид <> "КлючевоеСлово" - Или Соединение[0].Уточнение <> "Левое" Тогда - УстановитьОшибкуВнутриЧасти(Соединение, 0, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'Нет ключевого слова ""%1""'"), "Левое")); - - Если Соединение[0].Вид <> "КлючевоеСлово" - Или Соединение[0].Уточнение <> "Внутреннее" - И Соединение[0].Уточнение <> "Полное" Тогда - - Возврат; - КонецЕсли; - КонецЕсли; - - Если Соединение.Количество() < 2 - Или Соединение[1].Вид <> "КлючевоеСлово" - Или Соединение[1].Уточнение <> "Соединение" Тогда - УстановитьОшибкуВнутриЧасти(Соединение, 1, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" нет ключевого слова ""%2""'"), - Соединение[0].Символы, - КлючевоеСловоСУчетомЯзыка("Соединение", ВнутренниеДанные))); - Возврат; - КонецЕсли; - - Если Соединение.Количество() < 3 - Или Соединение[2].Вид <> "Имя" Тогда - УстановитьОшибкуВнутриЧасти(Соединение, 2, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" нет имени таблицы'"), - Соединение[1].Символы)); - Возврат; - КонецЕсли; - - УстановитьИмяТаблицы(Соединение[2], ОписаниеСоединения, ВнутренниеДанные); - - Если Соединение.Количество() < 4 - Или Соединение[3].Вид <> "КлючевоеСлово" - Или Соединение[3].Уточнение <> "Как" Тогда - УстановитьОшибкуВнутриЧасти(Соединение, 3, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'После имени таблицы нет ключевого слова ""%1""'"), "Как")); - Возврат; - КонецЕсли; - - Если Соединение.Количество() < 5 - Или Соединение[4].Вид <> "Имя" Тогда - УстановитьОшибкуВнутриЧасти(Соединение, 4, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'После ключевого слова ""%1"" нет псевдонима таблицы'"), "Как")); - Возврат; - КонецЕсли; - - УстановитьПсевдоним(Соединение[4], ОписаниеСоединения, ВнутренниеДанные); - - Если Соединение.Количество() < 6 - Или Соединение[5].Вид <> "КлючевоеСлово" - Или Соединение[5].Уточнение <> "По" Тогда - УстановитьОшибкуВнутриЧасти(Соединение, 5, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'После псевдонима таблицы нет ключевого слова ""%1""'"), "По")); - Возврат; - КонецЕсли; - - Условие = Новый Массив(Новый ФиксированныйМассив(Соединение)); - Для Индекс = 0 По 5 Цикл - Условие.Удалить(0); - КонецЦикла; - - РазобратьУсловие(Условие, ОписаниеСоединения.УсловиеСоединения, ВнутренниеДанные); - - СвойстваЧасти.Состав.Добавить(ОписаниеСоединения); - -КонецПроцедуры - -// Для процедуры РазобратьДополнительныеТаблицы. -Процедура РазобратьПоляУсловияСоединенияИОтметитьЗапреты(ОписаниеСоединения, ВнутренниеДанные) - - // Отметка некорректных аргументов операций и запрещенных возможностей. - ОбщиеУзлы = Новый Соответствие(УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( - "Поле,Значение,Константа,И,=", Ложь)); - - ОбщиеУзлы.Вставить("Поле", Новый Структура("Выразить, Вложение, ЕстьNull", Ложь, Ложь, Ложь)); - - ДоступныеУзлы = Новый Структура; - ДоступныеУзлы.Вставить("Общие", ОбщиеУзлы); - ДоступныеУзлы.Вставить("УзлыКогда", ОбщиеУзлы); - ДоступныеУзлы.Вставить("УзлыТогдаИначе", ОбщиеУзлы); - - Контекст = РасширенныеВнутренниеДанные(ВнутренниеДанные); - Контекст.Вставить("ЭтоУсловиеСоединения", Истина); - Контекст.Вставить("ЭтоУсловиеКогда", Ложь); - Контекст.Вставить("ЭтоЗначениеТогдаИначе", Ложь); - Контекст.Вставить("КорневойУзел", ОписаниеСоединения.УсловиеСоединения); - - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(ОписаниеСоединения.УсловиеСоединения, - ДоступныеУзлы, Контекст); - - УдалитьСвойствоИсточник(ОписаниеСоединения.УсловиеСоединения); - -КонецПроцедуры - -// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. -// -// Параметры: -// Список - Строка - список имен узлов через запятую. -// ЭтоСписокИсключений - Булево - если Истина, добавить узлы, кроме указанных. -// -// Возвращаемое значение: -// ФиксированноеСоответствие из КлючИЗначение: -// * Ключ - Строка - имя узла -// * Значение - Булево -// - Структура: -// ** Выразить - Булево -// ** Вложение - Булево -// ** ЕстьNull - Булево -// -Функция УзлыДляПроверкиДоступности(Список, ЭтоСписокИсключений) Экспорт - - ВсеУзлы = Новый Соответствие; - ВсеУзлы.Вставить("Поле", Новый Структура("Выразить, Вложение, ЕстьNull", Истина, Истина, Истина)); - ВсеУзлы.Вставить("Значение", Истина); - ВсеУзлы.Вставить("Константа", Истина); - ВсеУзлы.Вставить("И", Истина); - ВсеУзлы.Вставить("Или", Истина); - ВсеУзлы.Вставить("Не", Истина); - ВсеУзлы.Вставить("=", Истина); - ВсеУзлы.Вставить("<>", Истина); - ВсеУзлы.Вставить("В", Истина); - ВсеУзлы.Вставить("ЕстьNull", Истина); - ВсеУзлы.Вставить("Тип", Истина); - ВсеУзлы.Вставить("ТипЗначения", Истина); - ВсеУзлы.Вставить("Выбор", Истина); - ВсеУзлы.Вставить("ЗначениеРазрешено", Истина); - ВсеУзлы.Вставить("ЭтоАвторизованныйПользователь", Истина); - ВсеУзлы.Вставить("ЧтениеОбъектаРазрешено", Истина); - ВсеУзлы.Вставить("ИзменениеОбъектаРазрешено", Истина); - ВсеУзлы.Вставить("ЧтениеСпискаРазрешено", Истина); - ВсеУзлы.Вставить("ИзменениеСпискаРазрешено", Истина); - ВсеУзлы.Вставить("ДляВсехСтрок", Истина); - ВсеУзлы.Вставить("ДляОднойИзСтрок", Истина); - ВсеУзлы.Вставить("ПравоДоступа", Истина); - ВсеУзлы.Вставить("РольДоступна", Истина); - - МассивУзлов = СтрРазделить(Список, ",", Ложь); - Узлы = Новый Соответствие; - - Для Каждого Узел Из ВсеУзлы Цикл - Если ЭтоСписокИсключений Тогда - Если МассивУзлов.Найти(Узел.Ключ) = Неопределено Тогда - Узлы.Вставить(Узел.Ключ, Узел.Значение); - КонецЕсли; - Иначе - Если МассивУзлов.Найти(Узел.Ключ) <> Неопределено Тогда - Узлы.Вставить(Узел.Ключ, Узел.Значение); - КонецЕсли; - КонецЕсли; - КонецЦикла; - - Возврат Новый ФиксированноеСоответствие(Узлы); - -КонецФункции - -// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. -// -// Параметры: -// Условие - см. ОписаниеУзла -// ДоступныеУзлы - Структура -// Контекст - см. РасширенныеВнутренниеДанные -// Родитель - см. ОписаниеУзла -// -Процедура ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие, ДоступныеУзлы, Контекст, Родитель = Неопределено) - - Если Не ЗначениеЗаполнено(Условие) Тогда - Возврат; - КонецЕсли; - - Если Контекст.ЭтоУсловиеКогда Тогда - ТекущиеДоступныеУзлы = ДоступныеУзлы.УзлыКогда; - - ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда - ТекущиеДоступныеУзлы = ДоступныеУзлы.УзлыТогдаИначе; - Иначе - ТекущиеДоступныеУзлы = ДоступныеУзлы.Общие; - КонецЕсли; - - ДоступностьУзла = ТекущиеДоступныеУзлы.Получить(Условие.Узел); - - Если ДоступностьУзла = Неопределено Тогда - УстановитьОшибкуУзелЗапрещен(Условие.Источник, Контекст); - КонецЕсли; - - Если Условие.Узел = "Поле" Тогда - - Если Не Контекст.ЭтоУсловиеСоединения Тогда - ПолеКлючаДоступа = НовоеПолеКлючаДоступа(); - ПолеКлючаДоступа.Вставить("Поле", Условие); - ПолеКлючаДоступа.Вставить("Чтение", Контекст.Чтение); - ПолеКлючаДоступа.Вставить("Изменение", Контекст.Изменение); - Контекст.ПоляКлючаДоступа.Добавить(ПолеКлючаДоступа); - КонецЕсли; - - ВыделитьПсевдонимПоля(Условие, Контекст); - - Если Не ДоступностьУзла.Выразить - И Условие.Выразить <> Неопределено Тогда - - УстановитьОшибкуУзелЗапрещен(Условие.Источник, Контекст); - - ИначеЕсли Не ДоступностьУзла.Вложение - И Условие.Вложение <> Неопределено Тогда - - УстановитьОшибкуУзелЗапрещен(Условие.Вложение.Источник, Контекст); - - ИначеЕсли Не ДоступностьУзла.ЕстьNull - И Условие.ЕстьNull <> Неопределено Тогда - - УстановитьОшибкуУзелЗапрещен(Условие.ЕстьNullИсточник, Контекст); - КонецЕсли; - - ИначеЕсли Условие.Узел = "И" - Или Условие.Узел = "Или" Тогда - - Для Каждого Аргумент Из Условие.Аргументы Цикл - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Аргумент, ДоступныеУзлы, Контекст); - КонецЦикла; - - ИначеЕсли Условие.Узел = "Не" - Или Условие.Узел = "ЕстьNull" - Или Условие.Узел = "ДляВсехСтрок" - Или Условие.Узел = "ДляОднойИзСтрок" Тогда - - // Проверка корректности параметра. - Если Условие.Узел = "ЕстьNull" - И ( Условие.Аргумент = Неопределено - Или Условие.Аргумент.Узел <> "Поле" ) Тогда - - УстановитьОшибкуВСтроке(Условие.Источник, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Операция ""%1"" допустима только после поля'"), - Условие.Источник.Символы)); - КонецЕсли; - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Аргумент, ДоступныеУзлы, Контекст); - - ИначеЕсли Условие.Узел = "=" - Или Условие.Узел = "<>" Тогда - - СочетанияУзлов = Новый Соответствие; - СочетанияУзлов.Вставить("Значение", ",Поле,"); - СочетанияУзлов.Вставить("Константа", ",Поле,Константа,"); - - Если Контекст.ЭтоУсловиеСоединения Тогда - СочетанияУзлов.Вставить("Поле", ",Поле,Значение,Константа,"); - Иначе - СочетанияУзлов.Вставить("Поле", ",Значение,Константа,"); - СочетанияУзлов.Вставить("Тип", ",ТипЗначения,"); - СочетанияУзлов.Вставить("ТипЗначения", ",Тип,"); - КонецЕсли; - - СочетанияПервогоАргумента = СочетанияУзлов.Получить(Условие.ПервыйАргумент.Узел); - СочетанияВторогоАргумента = СочетанияУзлов.Получить(Условие.ВторойАргумент.Узел); - - ОшибкаВПервомАргументе = СочетанияПервогоАргумента = Неопределено; - ОшибкаВоВторомАргументе = СочетанияВторогоАргумента = Неопределено - Или СочетанияПервогоАргумента <> Неопределено - И СтрНайти(СочетанияПервогоАргумента, "," + Условие.ВторойАргумент.Узел + ",") = 0; - - Если ОшибкаВПервомАргументе Или ОшибкаВоВторомАргументе Тогда - Если Контекст.ЭтоУсловиеСоединения Тогда - ТекстОшибки = - НСтр("ru = 'Операция ""%1"" допустима только для поля с полем, значением или константой'"); - Иначе - ТекстОшибки = - НСтр("ru = 'Операция ""%1"" допустима только для поля со значением или константой, - |а также для типа значения с типом'"); - КонецЕсли; - Если ОшибкаВПервомАргументе Тогда - УсловиеПервыйАргумент = Условие.ПервыйАргумент; // См. ОписаниеУзла - УстановитьОшибкуВСтроке(УсловиеПервыйАргумент.Источник, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - ТекстОшибки, Условие.Источник.Символы), - Истина); - КонецЕсли; - Если ОшибкаВоВторомАргументе Тогда - УсловиеВторойАргумент = Условие.ВторойАргумент; // См. ОписаниеУзла - УстановитьОшибкуВСтроке(УсловиеВторойАргумент.Источник, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - ТекстОшибки, Условие.Источник.Символы)); - КонецЕсли; - КонецЕсли; - - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.ПервыйАргумент, ДоступныеУзлы, Контекст, Условие); - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.ВторойАргумент, ДоступныеУзлы, Контекст, Условие); - - ИначеЕсли Условие.Узел = "В" Тогда - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Искомое, ДоступныеУзлы, Контекст); - Для Каждого Значение Из Условие.Значения Цикл - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Значение, ДоступныеУзлы, Контекст); - КонецЦикла; - - ИначеЕсли Условие.Узел = "ТипЗначения" - Или Условие.Узел = "Тип" Тогда - - Если Родитель = Неопределено - Или Родитель.Узел <> "=" - И Родитель.Узел <> "<>" Тогда - - УстановитьОшибкуВСтроке(Условие.Источник, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Функция ""%1"" допустима только в операциях ""="" и ""<>""'"), - Условие.Источник.Символы)); - КонецЕсли; - - Если Условие.Узел = "ТипЗначения" Тогда - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Аргумент, ДоступныеУзлы, Контекст); - КонецЕсли; - - ИначеЕсли Условие.Узел = "Выбор" Тогда - Если Условие.Выбор <> Неопределено Тогда - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Выбор, ДоступныеУзлы, Контекст); - КонецЕсли; - ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(Контекст); - КонтекстКогда = Новый Структура(ФиксированныйКонтекст); - КонтекстКогда.ЭтоУсловиеКогда = Истина; - КонтекстТогдаИначе = Новый Структура(ФиксированныйКонтекст); - КонтекстТогдаИначе.ЭтоЗначениеТогдаИначе = Истина; - - Для Каждого Когда Из Условие.Когда Цикл - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Когда.Условие, ДоступныеУзлы, КонтекстКогда); - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Когда.Значение, ДоступныеУзлы, КонтекстТогдаИначе); - КонецЦикла; - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Иначе, ДоступныеУзлы, КонтекстТогдаИначе); - - ИначеЕсли Условие.Узел = "ЗначениеРазрешено" - Или Условие.Узел = "ЭтоАвторизованныйПользователь" - Или Условие.Узел = "ЧтениеОбъектаРазрешено" - Или Условие.Узел = "ИзменениеОбъектаРазрешено" - Или Условие.Узел = "ЧтениеСпискаРазрешено" - Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда - - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Поле, ДоступныеУзлы, Контекст); - ОтметитьПовторыТиповСредиПроверяемыхИУточняемых(Условие, Контекст); - - // Добавление типов, наличие которых нужно проверить у полей. - Поле = Условие.Поле; // См. ОписаниеУзла - Уточнения = Новый Соответствие; - Для Каждого УточнениеСравнения Из Условие.УточненияСравнения Цикл - Если ТипЗнч(УточнениеСравнения.Ключ) <> Тип("СтрокаТаблицыЗначений") Тогда - Уточнения.Вставить(УточнениеСравнения.Ключ, УточнениеСравнения.Значение); - Продолжить; - КонецЕсли; - Уточнения.Вставить(УточнениеСравнения.Ключ.Символы, УточнениеСравнения.Значение); - ДобавитьТребуемоеПолеТаблицы(Контекст, Поле.Таблица, Поле.Имя, Поле.ИмяИсточник, - УточнениеСравнения.Ключ.Символы, УточнениеСравнения.Ключ); - КонецЦикла; - - // Удаление источников типов. - Условие.УточненияСравнения = Уточнения; - - Типы = Новый Массив; - Для Каждого Тип Из Условие.Типы Цикл - Типы.Добавить(Тип.Символы); - КонецЦикла; - Условие.Типы = Типы; - КонецЕсли; - -КонецПроцедуры - -// Возвращаемое значение: -// Структура: -// * Поле - см. ОписаниеУзла -// * Чтение - Булево -// * Родители - Массив из см. ОписаниеУзла -// -Функция НовоеПолеКлючаДоступа() - - Возврат Новый Структура; - -КонецФункции - -// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. -Процедура ВыделитьПсевдонимПоля(УзелПоле, Контекст) - - Если УзелПоле.Вложение <> Неопределено Тогда - Вложение = УзелПоле.Вложение; - ВыделитьПсевдонимПоля(Вложение, Контекст); - Если ЗначениеЗаполнено(Вложение.Выразить) Тогда - УзелПоле.Таблица = Вложение.Выразить; - КонецЕсли; - - ИначеЕсли Не ЗначениеЗаполнено(УзелПоле.Имя) Тогда - Возврат; - Иначе - СоставИмени = СтрРазделить(УзелПоле.Имя, "."); - Если СоставИмени.Количество() > 1 Тогда - Свойства = Контекст.Псевдонимы.Получить(ВРег(СоставИмени[0])); - Если Свойства <> Неопределено Тогда - УзелПоле.Псевдоним = Свойства.Псевдоним; - СоставИмени.Удалить(0); - УзелПоле.Имя = СтрСоединить(СоставИмени, "."); - Если ЗначениеЗаполнено(Свойства.Таблица) Тогда - УзелПоле.Таблица = Свойства.Таблица; - КонецЕсли; - КонецЕсли; - КонецЕсли; - Если Контекст.ЭтоУсловиеСоединения Тогда - Если Не ЗначениеЗаполнено(УзелПоле.Псевдоним) Тогда - УстановитьОшибкуВСтроке(УзелПоле.ИмяИсточник, - НСтр("ru = 'В условии соединения перед именем поля требуется псевдоним'")); - ИначеЕсли Контекст.ДоступныеПсевдонимы.Получить(ВРег(УзелПоле.Псевдоним)) = Неопределено Тогда - УстановитьОшибкуВСтроке(УзелПоле.ИмяИсточник, - НСтр("ru = 'Нельзя указывать псевдоним из следующего соединения'")); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда - ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, УзелПоле.Выразить, УзелПоле.ВыразитьИсточник); - КонецЕсли; - - ДобавитьТребуемоеПолеТаблицы(Контекст, УзелПоле.Таблица, УзелПоле.Имя, УзелПоле.ИмяИсточник, - УзелПоле.Выразить, УзелПоле.ВыразитьИсточник, УзелПоле); - -КонецПроцедуры - -// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. -Процедура УдалитьСвойствоИсточник(Условие) - - Если ТипЗнч(Условие) = Тип("СтрокаТаблицыЗначений") Тогда - ТекстОшибки = НСтр("ru = 'Не все источники наборов символов удалены'"); - ВызватьИсключение ТекстОшибки; - - ИначеЕсли ТипЗнч(Условие) <> Тип("Структура") Тогда - Возврат; - КонецЕсли; - - Если Условие.Свойство("Источник") Тогда - Условие.Удалить("Источник"); - КонецЕсли; - - Если Условие.Свойство("ИмяИсточник") Тогда - Условие.Удалить("ИмяИсточник"); - КонецЕсли; - - Если Условие.Свойство("ВыразитьИсточник") Тогда - Условие.Удалить("ВыразитьИсточник"); - КонецЕсли; - - Если Условие.Свойство("ЕстьNullИсточник") Тогда - Условие.Удалить("ЕстьNullИсточник"); - КонецЕсли; - - Для Каждого КлючИЗначение Из Условие Цикл - Значение = КлючИЗначение.Значение; - - Если ТипЗнч(Значение) = Тип("Массив") Тогда - Для Каждого Элемент Из Значение Цикл - УдалитьСвойствоИсточник(Элемент); - КонецЦикла; - - ИначеЕсли ТипЗнч(Значение) = Тип("Соответствие") Тогда - Для Каждого КлючИЗначение Из Значение Цикл - УдалитьСвойствоИсточник(КлючИЗначение.Ключ); - УдалитьСвойствоИсточник(КлючИЗначение.Значение); - КонецЦикла; - Иначе - УдалитьСвойствоИсточник(Значение); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. -Процедура УстановитьОшибкуУзелЗапрещен(Строка, Контекст) - - Если Строка.Тип = "Функция" Тогда - Если Контекст.ЭтоУсловиеСоединения Тогда - ШаблонОшибки = НСтр("ru = 'Функция ""%1"" запрещена в условии соединения'"); - - ИначеЕсли Контекст.ЭтоУсловиеКогда Тогда - ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Функция ""%3"" запрещена в условии ограничения в операции ""%1"" в предложении ""%2""'"), - "Выбор,Когда", Строка.Символы); - - ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда - ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Функция ""%4"" запрещена в условии ограничения в операции ""%1"" в предложениях ""%2"" и ""%3""'"), - "Выбор,Тогда,Иначе", Строка.Символы); - Иначе - ШаблонОшибки = НСтр("ru = 'Функция ""%1"" запрещена в условии ограничения'"); - КонецЕсли; - Иначе - Если Контекст.ЭтоУсловиеСоединения Тогда - ШаблонОшибки = НСтр("ru = 'Операция ""%1"" запрещена в условии соединения'"); - - ИначеЕсли Контекст.ЭтоУсловиеКогда Тогда - ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Операция ""%3"" запрещена в условии ограничения в операции ""%1"" в предложении ""%2""'"), - "Выбор,Когда", Строка.Символы); - - ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда - ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Операция ""%4"" запрещена в условии ограничения в операции ""%1"" в предложениях ""%2"" и ""%3""'"), - "Выбор,Тогда,Иначе", Строка.Символы); - Иначе - ШаблонОшибки = НСтр("ru = 'Операция ""%1"" запрещена в условии ограничения'"); - КонецЕсли; - КонецЕсли; - - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - ШаблонОшибки, Строка.Символы)); - -КонецПроцедуры - -// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. -Процедура ОтметитьПовторыТиповСредиПроверяемыхИУточняемых(Узел, Контекст) - - ТипыВСписке = Новый Соответствие; - - Для Каждого ТипВСписке Из Узел.Типы Цикл - Если ТипыВСписке.Получить(ВРег(ТипВСписке.Символы)) = Неопределено Тогда - ТипыВСписке.Вставить(ВРег(ТипВСписке.Символы), Истина); - Иначе - УстановитьОшибкуВСтроке(ТипВСписке, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Тип ""%1"" уже указан'"), ТипВСписке.Символы)); - КонецЕсли; - КонецЦикла; - - УточняемыеТипы = Новый Соответствие; - - Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл - Если ТипЗнч(УточнениеСравнения.Ключ) <> Тип("СтрокаТаблицыЗначений") Тогда - Продолжить; - КонецЕсли; - ИсточникТипа = УточнениеСравнения.Ключ; - - Если Не Узел.ПроверятьТипыКромеУказанных - И ТипыВСписке.Получить(ВРег(ИсточникТипа.Символы)) <> Неопределено Тогда - - УстановитьОшибкуВСтроке(ИсточникТипа, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Тип ""%2"" уже указан среди типов ключевого слова ""%1""'"), - "Только", - ИсточникТипа.Символы)); - - ИначеЕсли Узел.ПроверятьТипыКромеУказанных - И ТипыВСписке.Получить(ВРег(ИсточникТипа.Символы)) = Неопределено Тогда - - УстановитьОшибкуВСтроке(ИсточникТипа, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Тип ""%2"" не указан среди типов ключевого слова ""%1""'"), - "Кроме", - ИсточникТипа.Символы)); - - ИначеЕсли УточняемыеТипы.Получить(ВРег(ИсточникТипа.Символы)) <> Неопределено Тогда - УстановитьОшибкуВСтроке(ИсточникТипа, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Уточнение типа ""%1"" уже указано'"), ИсточникТипа.Символы)); - Иначе - УточняемыеТипы.Вставить(ВРег(ИсточникТипа.Символы), Истина); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры РазобратьЧастьОграничения. -// -// Параметры: -// СвойстваЧасти - см. НовыеСвойстваЧасти -// ВнутренниеДанные - см. НовыеВнутренниеДанные -// -Процедура РазобратьУсловиеОграничения(СвойстваЧасти, ВнутренниеДанные) - - СтрокиЧасти = СвойстваЧасти.Строки; - ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти); - - Если СтрокиЧасти.Количество() < 2 - Или СтрокиЧасти[1].Вид <> "КлючевоеСлово" - Или СтрокиЧасти[1].Уточнение <> "Где" Тогда - УстановитьОшибкуНачалаЧасти( - ?(СтрокиЧасти.Количество() < 2, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[1]), - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" нет - |ключевого слова ""%2""'"), - СвойстваЧасти.Представление, - КлючевоеСловоСУчетомЯзыка("Где", ВнутренниеДанные))); - Возврат; - КонецЕсли; - - Условие = Новый Массив(Новый ФиксированныйМассив(СтрокиЧасти)); - Для Индекс = 0 По 1 Цикл - Условие.Удалить(0); - КонецЦикла; - - РазобратьУсловие(Условие, СвойстваЧасти.Состав, ВнутренниеДанные); - - // Отметка некорректных параметров операций и неподдерживаемого функционала. - ОбщиеУзлы = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности("", Истина); - - УзлыКогда = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( - "Поле,Значение,Константа,И,Или,Не,=,<>,В,ЕстьNull,Тип,ТипЗначения", Ложь); - - УзлыТогдаИначе = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( - "Выбор,ДляВсехСтрок,ДляОднойИзСтрок", Истина); - - ДоступныеУзлы = Новый Структура; - ДоступныеУзлы.Вставить("Общие", ОбщиеУзлы); - ДоступныеУзлы.Вставить("УзлыКогда", УзлыКогда); - ДоступныеУзлы.Вставить("УзлыТогдаИначе", УзлыТогдаИначе); - - ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ВнутренниеДанные); - Контекст = Новый Структура(ФиксированныйКонтекст); - Контекст.Вставить("ЭтоУсловиеСоединения", Ложь); - Контекст.Вставить("ЭтоУсловиеКогда", Ложь); - Контекст.Вставить("ЭтоЗначениеТогдаИначе", Ложь); - Контекст.Вставить("КорневойУзел", СвойстваЧасти.Состав); - Контекст.Вставить("Чтение", - СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" - Или СвойстваЧасти.Имя = "РазрешитьЧтение"); - Контекст.Вставить("Изменение", - СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" - Или СвойстваЧасти.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение"); - - ДобавитьПсевдонимыПоУмолчанию(Контекст); - - ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(СвойстваЧасти.Состав, ДоступныеУзлы, Контекст); - - УдалитьСвойствоИсточник(СвойстваЧасти.Состав); - -КонецПроцедуры - -// Для процедур ЧастиОграничения, РазобратьУсловиеОграничения. -Процедура ДобавитьПсевдонимыПоУмолчанию(Контекст); - - Если Контекст.Псевдонимы.Количество() > 0 Тогда - Возврат; - КонецЕсли; - - Контекст.Псевдонимы.Вставить(ВРег("ЭтотСписок"), Новый Структура("Псевдоним, Таблица", "ЭтотСписок")); - Контекст.Псевдонимы.Вставить(ВРег("ThisList"), Новый Структура("Псевдоним, Таблица", "ThisList")); - -КонецПроцедуры - -// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. -// -// Параметры: -// Условие - Массив из СтрокаТаблицыЗначений -// Состав - см. ОписаниеУзла -// ВнутренниеДанные - см. НовыеВнутренниеДанные -// -Процедура РазобратьУсловие(Условие, Состав, ВнутренниеДанные) - - ВыраженияВСкобкахВоВложениях = ВыраженияВСкобкахВоВложениях(Условие, ВнутренниеДанные); - - ФункцииСВыражениямиВСкобках = ФункцииСВыражениямиВСкобках( - ВыраженияВСкобкахВоВложениях, ВнутренниеДанные); - - ВыраженияВыборКогдаТогдаВоВложениях = ВыраженияВыборКогдаТогдаВоВложениях( - ФункцииСВыражениямиВСкобках, ВнутренниеДанные); - - Условие = ВыраженияВыборКогдаТогдаВоВложениях; - - РазобратьВыражение(Условие, Состав, ВнутренниеДанные, Ложь); - - ОбъединитьВложенныеЛогическиеОперации(Состав); - -КонецПроцедуры - -// Для процедуры РазобратьУсловие. -Процедура ОбъединитьВложенныеЛогическиеОперации(Состав) - - Если Состав = Неопределено Тогда - Возврат; - КонецЕсли; - - Если Состав.Узел = "И" - Или Состав.Узел = "Или" Тогда - - Индекс = Состав.Аргументы.Количество() - 1; - Пока Индекс >= 0 Цикл - - Аргумент = Состав.Аргументы[Индекс]; - ОбъединитьВложенныеЛогическиеОперации(Аргумент); - - Если Аргумент.Узел = Состав.Узел Тогда - Состав.Аргументы.Удалить(Индекс); - ВложенныйИндекс = Аргумент.Аргументы.Количество() - 1; - Пока ВложенныйИндекс >= 0 Цикл - Состав.Аргументы.Вставить(Индекс, Аргумент.Аргументы[ВложенныйИндекс]); - ВложенныйИндекс = ВложенныйИндекс - 1; - КонецЦикла; - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - КонецЕсли; - -КонецПроцедуры - - -// Для процедур РазобратьУсловие, РазобратьФункцию, РазобратьВыбор. -// -// Параметры: -// Условие - Массив из см. СтрокаТаблицы.ОписаниеСтроки -// -Процедура РазобратьВыражение(Условие, Состав, ТекущийКонтекст, ВложенноеВыражение = Истина) - - ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ТекущийКонтекст); - Контекст = Новый Структура(ФиксированныйКонтекст); - Контекст.Вставить("Вложения", Новый Массив); - Контекст.Вставить("Описание"); - Контекст.Вставить("Строка"); - - Для Каждого ОписаниеСтроки Из Условие Цикл - Строка = СтрокаТаблицы(ОписаниеСтроки, ТекущийКонтекст); - Контекст.Строка = Строка; - - Если Строка.Вид = "Имя" - Или Строка.Вид = "Число" - Или Строка.Вид = "ПроизвольнаяСтрока" - Или Строка.Вид = "КлючевоеСлово" - И ( Строка.Уточнение = "Истина" - Или Строка.Уточнение = "Ложь" - Или Строка.Уточнение = "Неопределено" ) Тогда - - НовоеОписание = ОписаниеУзлаПолеИлиУзлаКонстанта(Строка); - ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); - - ИначеЕсли Строка.Вид = "КлючевоеСлово" Тогда - - Если Строка.Тип = "Функция" - Или Строка.Уточнение = "В" Тогда - - Если Строка.Тип = "Функция" Тогда - РазобратьФункцию(Контекст); - Иначе - РазобратьСоединительВ(Контекст); - КонецЕсли; - - ИначеЕсли Строка.Тип = "Соединитель" Тогда - РазобратьСоединитель(Контекст); - - ИначеЕсли Строка.Тип = "Оператор" Тогда - РазобратьОператор(Контекст); - - ИначеЕсли Строка.Тип = "СловоВыбора" Тогда - РазобратьВыбор(Контекст); - Иначе - РазобратьОшибочноеКлючевоеСлово(Контекст); - КонецЕсли; - - ИначеЕсли Строка.Вид = "Операция" Тогда - РазобратьСоединитель(Контекст, Истина); - - ИначеЕсли Строка.Вид = "Разделитель" Тогда - Если Строка.Символы = "(" Тогда - НовоеОписание = Неопределено; // См. ОписаниеУзла - РазобратьВыражение(Строка.Строки, НовоеОписание, Контекст); - ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); - Если НовоеОписание <> Неопределено Тогда - НовоеОписание.Источник.Приоритет = 99; - КонецЕсли; - Иначе - Контекст.Описание = Неопределено; - УстановитьОшибкуВСтроке(Строка, - НСтр("ru = 'Запятая может использоваться только для разделения параметров функций'")); - КонецЕсли; - Иначе - Контекст.Описание = Неопределено; - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); - КонецЕсли; - - Если Контекст.Описание = Неопределено Тогда - // Возникала ошибка, останавливающая дальнейший разбор (предотвращение ложных срабатываний). - Прервать; - КонецЕсли; - КонецЦикла; - - Если Контекст.Описание = Неопределено Тогда - Если ВложенноеВыражение Тогда - Состав = Новый Структура("Источник, Узел, Значение", Строка, "Константа", Ложь); - Иначе - Состав = Неопределено; - КонецЕсли; - - ИначеЕсли Контекст.Вложения.Количество() = 0 Тогда - Состав = Контекст.Описание; - Иначе - Состав = Контекст.Вложения[Контекст.Вложения.Количество() - 1]; - КонецЕсли; - -КонецПроцедуры - -// Для процедур РазобратьВыражение, РазобратьПервыйПараметрПроверочнойФункции, -// РазобратьПараметрыФункцииТипЗначения, РазобратьВыбор и -// для функции ОписаниеУзлаПолеИзФункцииЕстьNull. -// -Функция ОписаниеУзлаПолеИлиУзлаКонстанта(Строка) - - // <Имя поля>, <Число>, <Произвольная строка>, Истина, Ложь, Неопределено. - - Если Строка.Вид = "Имя" Тогда - НовоеОписание = ОписаниеУзлаПоле(Строка); - НовоеОписание.Имя = Строка.Символы; - НовоеОписание.ИмяИсточник = Строка; - Иначе - СвойстваУзла = "Источник, Узел, Значение"; - НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Константа"); - - Если Строка.Вид = "КлючевоеСлово" Тогда - Если Строка.Уточнение = "Истина" Тогда - НовоеОписание.Значение = Истина; - - ИначеЕсли Строка.Уточнение = "Ложь" Тогда - НовоеОписание.Значение = Ложь; - - Иначе // Строка.Вид = "Неопределено". - НовоеОписание.Значение = Неопределено; - КонецЕсли; - Иначе // "Число" или "ПроизвольнаяСтрока". - НовоеОписание.Значение = Строка.Уточнение; - КонецЕсли; - КонецЕсли; - - Возврат НовоеОписание; - -КонецФункции - -// Для функций ОписаниеУзлаПолеИлиУзлаКонстанта, ОписаниеУзлаПолеИзФункцииВыразить, ОписаниеУзлаПолеИзФункцииЕстьNull. -Функция ОписаниеУзлаПоле(Строка) - - СвойстваУзла = "Источник, Узел, Имя, Таблица, Псевдоним, Выразить, Вложение, ЕстьNull"; - НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Поле"); - - НовоеОписание.Вставить("ИмяИсточник", Неопределено); - НовоеОписание.Вставить("ВыразитьИсточник", Неопределено); - НовоеОписание.Вставить("ЕстьNullИсточник", Неопределено); - - Возврат НовоеОписание; - -КонецФункции - -// Для процедуры РазобратьВыражение. -Процедура РазобратьСоединитель(Контекст, ЭтоОперация = Ложь) - - // И, Или, Как, Кроме, Только, Есть и любая операция =, <>, ... - // Ключевое слово В разбирается отдельно в процедуре "РазобратьСоединительВ". - - Строка = Контекст.Строка; // СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов - - НовоеОписание = Новый Структура("Источник, Узел", Строка, - ?(Строка.Вид = "Операция", Строка.Символы, Строка.Уточнение)); - - Если Строка.Уточнение = "И" - Или Строка.Уточнение = "Или" Тогда - - НовоеОписание.Вставить("Аргументы", Новый Массив); - НовоеОписание.Аргументы.Добавить(Неопределено); - ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Аргументы[0]); - - ИначеЕсли Строка.Уточнение = "Есть" Тогда - НовоеОписание.Узел = "ЕстьNull"; - НовоеОписание.Вставить("Аргумент", Неопределено); - ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Аргумент); - // Проверка корректности параметров выполняется - // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. - - ИначеЕсли Строка.Вид = "Операция" Тогда - НовоеОписание.Вставить("ПервыйАргумент", Неопределено); - НовоеОписание.Вставить("ВторойАргумент", Неопределено); - ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.ПервыйАргумент); - // Проверка корректности аргументов выполняется - // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. - - ИначеЕсли Строка.Уточнение = "Как" - Или Строка.Уточнение = "Кроме" - Или Строка.Уточнение = "Только" Тогда - - Контекст.Описание = Неопределено; - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ключевое слово ""%1"" может использоваться только в параметрах функций'"), Строка.Символы)); - Иначе - Контекст.Описание = Неопределено; - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьВыражение. -Процедура РазобратьСоединительВ(Контекст) - - Строка = Контекст.Строка; - - НовоеОписание = Новый Структура("Источник, Узел", Строка, Строка.Уточнение); - НовоеОписание.Вставить("Искомое", Неопределено); - НовоеОписание.Вставить("Значения", Новый Массив); - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - - Для Каждого ОписаниеПараметра Из СоставПараметров Цикл - СтрокиОписанияПараметра = ОписаниеПараметра.Строки; // Массив Из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов - Для Каждого Подстрока Из СтрокиОписанияПараметра Цикл - - РазобратьЗначениеСоединителяВ(Контекст, Подстрока, НовоеОписание); - - Если ОписаниеПараметра.Строки[0] <> Подстрока Тогда - УстановитьОшибкуВСтроке(Подстрока, НСтр("ru = 'Перед параметром не указана запятая'")); - КонецЕсли; - - КонецЦикла; - КонецЦикла; - - ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Искомое); - - Если НовоеОписание.Искомое.Узел <> "Поле" Тогда - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Операцию ""%1"" можно указывать только после имени поля'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьСоединительВ. -Процедура РазобратьЗначениеСоединителяВ(Контекст, Подстрока, НовоеОписание) - - Строка = Контекст.Строка; - - Если Подстрока.Вид = "Число" - Или Подстрока.Вид = "ПроизвольнаяСтрока" Тогда - - ОписаниеКонстанты = Новый Структура("Источник, Узел", Подстрока, "Константа"); - ОписаниеКонстанты.Вставить("Значение", Подстрока.Уточнение); - НовоеОписание.Значения.Добавить(ОписаниеКонстанты); - - ИначеЕсли Подстрока.Вид = "КлючевоеСлово" Тогда - - Если Подстрока.Уточнение = "Значение" Тогда - НовыйКонтекст = НовыйКонтекст(Контекст, Подстрока, Неопределено); - РазобратьФункцию(НовыйКонтекст); - Если НовыйКонтекст.Описание <> Неопределено Тогда - НовоеОписание.Значения.Добавить(НовыйКонтекст.Описание); - КонецЕсли; - Иначе - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В списке значений операции ""%1"" ключевое слово ""%2"" недопустимо'"), - Строка.Символы, Подстрока.Символы)); - КонецЕсли; - - ИначеЕсли Подстрока.Вид = "Имя" Тогда - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В списке значений операции ""%1"" имя поля недопустимо'"), Строка.Символы)); - - ИначеЕсли Подстрока.Символы = "(" Тогда - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В списке значений операции ""%1"" скобки допустимы только для параметров функции'"), Строка.Символы)); - Иначе - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В списке значений операции ""%1"" можно указывать только значения'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьЗначениеСоединителяВ. -Функция НовыйКонтекст(Контекст, Строка = null, Описание = null) - - ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(Контекст); - НовыйКонтекст = Новый Структура(ФиксированныйКонтекст); - - Если Строка <> null Тогда - НовыйКонтекст.Строка = Строка; - КонецЕсли; - - Если Описание <> null Тогда - НовыйКонтекст.Описание = Описание; - КонецЕсли; - - Возврат НовыйКонтекст; - -КонецФункции - -// Для процедур РазобратьСоединитель, РазобратьСоединительВ, ВставитьСоединительСУчетомПриоритета. -Процедура ДобавитьСоединитель(Контекст, НовоеОписание, ПервыйАргумент); - - // Добавляемый соединитель: И, Или, В, Есть и любая операция (=, <>, ...). - - Описание = Контекст.Описание; // См. ОписаниеУзла - - Если Описание = Неопределено Тогда - Контекст.Описание = НовоеОписание; - - ИначеЕсли Описание.Узел = "И" - Или Описание.Узел = "Или" Тогда - - Если Описание.Аргументы.Количество() = 1 Тогда - Описание.Аргументы.Добавить(Неопределено); - ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.Аргументы[1]); - КонецЕсли; - ВставитьСоединительСУчетомПриоритета(Контекст, - Описание.Аргументы[1], НовоеОписание, ПервыйАргумент); - - ИначеЕсли Описание.Узел = "Не" Тогда - Если Не ЗначениеЗаполнено(Описание.Аргумент) Тогда - ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.Аргумент); - КонецЕсли; - ВставитьСоединительСУчетомПриоритета(Контекст, - Описание.Аргумент, НовоеОписание, ПервыйАргумент); - - ИначеЕсли Описание.Источник.Вид = "Операция" Тогда - Если Не ЗначениеЗаполнено(Описание.ВторойАргумент) Тогда - ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.ВторойАргумент, Ложь); - КонецЕсли; - ВставитьСоединительСУчетомПриоритета(Контекст, - Описание.ВторойАргумент, НовоеОписание, ПервыйАргумент); - - ИначеЕсли СтрНайти(",Поле,Значение,Константа,В,ЕстьNull,Выбор,", "," + Описание.Узел + ",") > 0 - Или Описание.Источник.Тип = "Функция" Тогда - // Второй аргумент операции В уже разобран в процедуре РазобратьСоединительВ. - // Второй аргумент Null операции Есть уже разобран в функции ФункцииСВыражениямиВСкобках. - // Остальные узлы не имеют второго аргумента. - ВставитьСоединительСУчетомПриоритета(Контекст, Неопределено, НовоеОписание, ПервыйАргумент); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не определена обработка узла ""%1""'"), Описание.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ДобавитьСоединитель. -Процедура ОбработатьПропущенныйАргументПослеСоединителя(Контекст, ВторойАргумент, ЛогическаяОперация = Истина) - - Описание = Контекст.Описание; // См. ОписаниеУзла - - УстановитьОшибкуВСтроке(Описание.Источник, - ?(ЛогическаяОперация, - НСтр("ru = 'Не указан аргумент после логической операции'"), - НСтр("ru = 'Не указан аргумент после операции'")), - Истина); - - ВторойАргумент = Новый Структура("Источник, Узел, Значение", Контекст.Строка, "Константа", Истина); - -КонецПроцедуры - -// Для процедур ДобавитьСоединитель, ОбработатьПропущеннуюЛогическуюОперацию. -Процедура ВставитьСоединительСУчетомПриоритета(Контекст, - ПоследнийАргументОписания, НовоеОписание, ПервыйАргументНовогоОписания) - - Вложения = Контекст.Вложения; - Описание = Контекст.Описание; // См. ОписаниеУзла - - Если ПоследнийАргументОписания <> Неопределено - И Контекст.Строка.Приоритет >= Описание.Источник.Приоритет Тогда - - // Замена аргумента текущего узла на соединитель (случай "А Или Б И ..."). - ПервыйАргументНовогоОписания = ПоследнийАргументОписания; - ПоследнийАргументОписания = НовоеОписание; - - Вложения.Вставить(0, Контекст.Описание); - Контекст.Описание = НовоеОписание; - Возврат; - КонецЕсли; - - Если Вложения.Количество() = 0 Тогда - // Вложение текущего узла, как первого аргумента соединителя (случай "А И Б Или ..."). - ПервыйАргументНовогоОписания = Контекст.Описание; - Контекст.Описание = НовоеОписание; - Возврат; - КонецЕсли; - - // Вложение предыдущего узла, как первого аргумента соединителя (случай "А И Не Б Или ..."). - Контекст.Описание = Вложения[0]; - Вложения.Удалить(0); - - ДобавитьСоединитель(Контекст, НовоеОписание, ПервыйАргументНовогоОписания); - -КонецПроцедуры - -// Для процедуры РазобратьВыражение. -Процедура РазобратьОператор(Контекст) - - // Оператор Не. - - НовоеОписание = Новый Структура("Источник, Узел, Аргумент", - Контекст.Строка, Контекст.Строка.Уточнение); - - ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); - - Контекст.Вложения.Вставить(0, Контекст.Описание); - Контекст.Описание = НовоеОписание; - -КонецПроцедуры - -// Для процедур РазобратьВыражение, РазобратьЗначениеСоединителяВ. -Процедура РазобратьФункцию(Контекст) - - Строка = Контекст.Строка; - - НовоеОписание = Новый Структура("Источник, Узел", Строка, Строка.Уточнение); - - Если Строка.Уточнение = "ЗначениеРазрешено" - Или Строка.Уточнение = "ЧтениеОбъектаРазрешено" - Или Строка.Уточнение = "ИзменениеОбъектаРазрешено" - Или Строка.Уточнение = "ЧтениеСпискаРазрешено" - Или Строка.Уточнение = "ИзменениеСпискаРазрешено" - Или Строка.Уточнение = "ЭтоАвторизованныйПользователь" Тогда - - РазобратьПараметрыПроверочнойФункции(Контекст, НовоеОписание); - - ИначеЕсли Строка.Уточнение = "ДляВсехСтрок" - Или Строка.Уточнение = "ДляОднойИзСтрок" Тогда - - ОписаниеВыражения = Неопределено; - РазобратьВыражение(Строка.Строки, ОписаниеВыражения, Контекст); - НовоеОписание.Вставить("Аргумент", ОписаниеВыражения); - - ИначеЕсли Строка.Уточнение = "Значение" Тогда - РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, Истина, Контекст); - - ИначеЕсли Строка.Уточнение = "Тип" Тогда - РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, Ложь, Контекст); - - ИначеЕсли Строка.Уточнение = "ТипЗначения" Тогда - РазобратьПараметрыФункцииТипЗначения(Контекст, НовоеОписание); - - ИначеЕсли Строка.Уточнение = "ЕстьNull" Тогда - НовоеОписание = ОписаниеУзлаПолеИзФункцииЕстьNull(Контекст.Строка, Контекст); - - ИначеЕсли Строка.Уточнение = "Выразить" Тогда - НовоеОписание = ОписаниеУзлаПолеИзФункцииВыразить(Контекст.Строка, Контекст); - - ИначеЕсли Строка.Уточнение = "ПравоДоступа" Тогда - РазобратьПараметрыФункцииПравоДоступа(Строка, НовоеОписание, Контекст); - - ИначеЕсли Строка.Уточнение = "РольДоступна" Тогда - РазобратьПараметрыФункцииРольДоступна(Строка, НовоеОписание, Контекст); - - ИначеЕсли Не Строка.ЭтоРезерв Тогда - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не определена обработка функции ""%1""'"), Строка.Уточнение); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - - ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); - -КонецПроцедуры - -// Для процедуры РазобратьФункцию. -Процедура РазобратьПараметрыПроверочнойФункции(Контекст, НовоеОписание) - - Строка = Контекст.Строка; - - НовоеОписание.Вставить("Поле", Неопределено); - НовоеОписание.Вставить("Типы", Новый Массив); - НовоеОписание.Вставить("ПроверятьТипыКромеУказанных", Ложь); - НовоеОписание.Вставить("УточненияСравнения", Новый Соответствие); - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - КонецЕсли; - - РазобратьПервыйПараметрПроверочнойФункции(Контекст, СоставПараметров[0], НовоеОписание); - - Для Индекс = 1 По СоставПараметров.Количество() - 1 Цикл - РазобратьДополнительныйПараметрПроверочнойФункции(Контекст, - СоставПараметров[Индекс], НовоеОписание); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры РазобратьПараметрыПроверочнойФункции. -// -// Параметры: -// ПервыйПараметр - Структура: -// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура РазобратьПервыйПараметрПроверочнойФункции(Контекст, ПервыйПараметр, НовоеОписание) - - Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.Поле = ОписаниеУзлаПолеИлиУзлаКонстанта(ПервыйПараметр.Строки[0]); - - ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" - И ПервыйПараметр.Строки[0].Уточнение = "Выразить" Тогда - - НовоеОписание.Поле = ОписаниеУзлаПолеИзФункцииВыразить(ПервыйПараметр.Строки[0], Контекст); - - ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" - И ПервыйПараметр.Строки[0].Уточнение = "ЕстьNull" Тогда - - НовоеОписание.Поле = ОписаниеУзлаПолеИзФункцииЕстьNull(ПервыйПараметр.Строки[0], Контекст); - Иначе - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Первым параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), - "Выразить,ЕстьNull")); - Возврат; - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() < 2 Тогда - Возврат; - КонецЕсли; - - Если ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" - И ПервыйПараметр.Строки[0].Уточнение = "Выразить" - И НовоеОписание.Поле.Вложение = Неопределено Тогда - - УстановитьОшибкуВСтроке(СтрокаТаблицы(ПервыйПараметр.Строки[0].КонечнаяСтрока, Контекст), - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После вложенной функции ""%3"" должно быть указано имя поля через точку, - |если в параметре функции ""%4"" используется ключевое слово ""%1"" или ""%2""'"), - "Только,Кроме", - ПервыйПараметр.Строки[0].Символы, - Контекст.Строка.Символы), - Истина); - КонецЕсли; - - Если ПервыйПараметр.Строки[1].Вид <> "КлючевоеСлово" - Или ( ПервыйПараметр.Строки[1].Уточнение <> "Только" - И ПервыйПараметр.Строки[1].Уточнение <> "Кроме" ) Тогда - - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После описания поля может быть указано, либо ключевое слово ""%1"", либо ""%2""'"), - "Только,Кроме")); - Возврат; - КонецЕсли; - - Если ПервыйПараметр.Строки[1].Уточнение = "Кроме" Тогда - НовоеОписание.ПроверятьТипыКромеУказанных = Истина; - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() < 3 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" не указан тип (имя таблицы)'"), ПервыйПараметр.Строки[1].Символы)); - Возврат; - КонецЕсли; - - Если ПервыйПараметр.Строки[2].Вид <> "Имя" - И ПервыйПараметр.Строки[2].Символы <> "(" Тогда - - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[2], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" должен быть указан, либо тип (имя таблицы), либо список типов в скобках'"), - ПервыйПараметр.Строки[1].Символы)); - Возврат; - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() > 3 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[3], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Перед параметром функции ""%1"" не указана запятая'"), Контекст.Строка.Символы)); - КонецЕсли; - - Если ПервыйПараметр.Строки[2].Вид = "Имя" Тогда - НовоеОписание.Типы.Добавить(ПервыйПараметр.Строки[2]); - ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, ПервыйПараметр.Строки[2].Символы, ПервыйПараметр.Строки[2]); - Возврат; - КонецЕсли; - - СоставПараметров = ПараметрыРазделенныеЗапятыми(ПервыйПараметр.Строки[2], Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - КонецЕсли; - - Для Каждого Параметр Из СоставПараметров Цикл - - Если Параметр.Строки[0].Вид = "Имя" - И Параметр.Строки.Количество() < 2 Тогда - - НовоеОписание.Типы.Добавить(Параметр.Строки[0]); - Иначе - УстановитьОшибкуВСтроке(Параметр.Строки[?(Параметр.Строки.Количество() < 2, 0, 1)], - НСтр("ru = 'В списке типов могут быть указаны только имена таблицы через запятую'")); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры РазобратьПараметрыПроверочнойФункции. -// -// Параметры: -// Параметр - Структура: -// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура РазобратьДополнительныйПараметрПроверочнойФункции(Контекст, Параметр, НовоеОписание) - - Если Параметр.Строки[0].Вид = "Имя" - Или Параметр.Строки[0].Вид = "КлючевоеСлово" - И ( Параметр.Строки[0].Тип = "ЗначениеСравнения" - Или Параметр.Строки[0].Тип = "ИмяТипа" ) Тогда - - Если Параметр.Строки[0].Вид = "Имя" Тогда - ЗначениеСравнения = Параметр.Строки[0]; - ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, Параметр.Строки[0].Символы, Параметр.Строки[0]); - Иначе - ЗначениеСравнения = Параметр.Строки[0].Уточнение; - КонецЕсли; - Иначе - УстановитьОшибкуВСтроке(Параметр.Строки[0], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Дополнительным параметром может быть тип (имя таблицы), - |""%1"", ""%2"", ""%3"", ""%4"", ""%5"", ""%6"" и ""%7""'"), - "ПустаяСсылка,Неопределено,Null,Число,Строка,Дата,Булево")); - Возврат; - КонецЕсли; - - Если Параметр.Строки.Количество() < 2 Тогда - Если Параметр.Строки[0].Вид = "Имя" Тогда - Шаблон = НСтр("ru = 'После типа (имени таблицы) ""%2"" должно быть указано ключевое слово ""%1""'"); - Иначе - Шаблон = НСтр("ru = 'После ключевого слова ""%2"" должно быть указано ключевое слово ""%1""'"); - КонецЕсли; - УстановитьОшибкуВСтроке(Параметр.Строки[0], ПодставитьКлючевыеСловаВСтроку(Контекст, - Шаблон, "Как", Параметр.Строки[0].Символы), - Истина); - Возврат; - КонецЕсли; - - Если Параметр.Строки[1].Вид <> "КлючевоеСлово" - Или Параметр.Строки[1].Уточнение <> "Как" Тогда - - Если Параметр.Строки[0].Вид = "Имя" Тогда - Шаблон = НСтр("ru = 'После типа (имени таблицы) ""%2"" должно быть указано ключевое слово ""%1""'"); - Иначе - Шаблон = НСтр("ru = 'После ключевого слова ""%2"" должно быть указано ключевое слово ""%1""'"); - КонецЕсли; - УстановитьОшибкуВСтроке(Параметр.Строки[1], ПодставитьКлючевыеСловаВСтроку(Контекст, - Шаблон, "Как", Параметр.Строки[0].Символы)); - Возврат; - КонецЕсли; - - Если Параметр.Строки.Количество() < 3 Тогда - УстановитьОшибкуВСтроке(Параметр.Строки[1], ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%4"" не указано значение уточнения ""%1"", ""%2"" или ""%3""'"), - "Ложь,Истина,Пусто", - Параметр.Строки[1].Символы), - Истина); - Возврат; - КонецЕсли; - - Если Параметр.Строки[2].Вид <> "КлючевоеСлово" - Или Параметр.Строки[2].Тип <> "ЗначениеУточнения" Тогда - - УстановитьОшибкуВСтроке(Параметр.Строки[2], ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%4"" должно быть указано значение уточнения ""%1"", ""%2"" или ""%3""'"), - "Ложь,Истина,Пусто", - Параметр.Строки[1].Символы)); - Иначе - НовоеОписание.УточненияСравнения.Вставить(ЗначениеСравнения, Параметр.Строки[2].Уточнение); - КонецЕсли; - - Если Параметр.Строки.Количество() > 3 Тогда - УстановитьОшибкуВСтроке(Параметр.Строки[3], - НСтр("ru = 'Перед параметром не указана запятая или лишний параметр'")); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьФункцию. -Процедура РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, ЭтоФункцияЗначение, Контекст) - - НовоеОписание.Вставить("Имя", Неопределено); - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - КонецЕсли; - - Параметр = СоставПараметров[0]; - Если Параметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.Имя = Параметр.Строки[0].Символы; - - Если ЭтоФункцияЗначение Тогда - ДобавитьТребуемыйПредопределенныйЭлемент(Контекст, НовоеОписание.Имя, Параметр.Строки[0]); - Иначе - ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, НовоеОписание.Имя, Параметр.Строки[0]); - КонецЕсли; - - ИначеЕсли ЭтоФункцияЗначение Тогда - УстановитьОшибкуВСтроке(Параметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В функции ""%1"" можно указать только имя предопределенного значения'"), Строка.Символы)); - - ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" - И Параметр.Строки[0].Тип = "ИмяТипа" Тогда - - НовоеОписание.Имя = Параметр.Строки[0].Уточнение; - Иначе - УстановитьОшибкуВСтроке(Параметр.Строки[0], ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'В функции ""%5"" можно указать имя таблицы или ""%1"", ""%2"", ""%3"" и ""%4""'"), - "Число,Строка,Дата,Булево", - Строка.Символы)); - КонецЕсли; - - Если Параметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьФункцию. -Процедура РазобратьПараметрыФункцииРольДоступна(Строка, НовоеОписание, Контекст) - - НовоеОписание.Вставить("ИмяРоли", Неопределено); - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - КонецЕсли; - - Параметр = СоставПараметров[0]; - Если Параметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.ИмяРоли = Параметр.Строки[0].Символы; - - ПроверитьИмяРоли(НовоеОписание.ИмяРоли, Параметр.Строки[0]); - Иначе - УстановитьОшибкуВСтроке(Параметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В функции ""%1"" можно указать только имя роли'"), Строка.Символы)); - КонецЕсли; - - Если Параметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьФункцию. -Процедура РазобратьПараметрыФункцииПравоДоступа(Строка, НовоеОписание, Контекст) - - НовоеОписание.Вставить("ИмяПрава", Неопределено); - НовоеОписание.Вставить("ПолноеИмяОбъектаМетаданных", Неопределено); - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - КонецЕсли; - - ПервыйПараметр = СоставПараметров[0]; - Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.ИмяПрава = ПервыйПараметр.Строки[0].Символы; - Иначе - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В функции ""%1"" в первом параметре можно указать только имя права'"), Строка.Символы)); - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Перед параметром ""%1"" функции ""%2"" не указана запятая'"), - ПервыйПараметр.Строки[1].Символы, - Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() < 2 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" должно быть два параметра'"), Строка.Символы)); - Возврат; - КонецЕсли; - - ВторойПараметр = СоставПараметров[1]; - Если ВторойПараметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.ПолноеИмяОбъектаМетаданных = ВторойПараметр.Строки[0].Символы; - - ПроверитьИмяПраваОбъектаМетаданных(НовоеОписание.ИмяПрава, ПервыйПараметр.Строки[0], - НовоеОписание.ПолноеИмяОбъектаМетаданных, ВторойПараметр.Строки[0]); - Иначе - УстановитьОшибкуВСтроке(ВторойПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В функции ""%1"" во втором параметре можно указать только полное имя объекта метаданных'"), - Строка.Символы)); - КонецЕсли; - - Если ВторойПараметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(ВторойПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() > 2 Тогда - УстановитьОшибкуВСтроке(СоставПараметров[2].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьФункцию. -Процедура РазобратьПараметрыФункцииТипЗначения(Контекст, НовоеОписание) - - Строка = Контекст.Строка; - НовоеОписание.Вставить("Аргумент", Неопределено); - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - КонецЕсли; - - Параметр = СоставПараметров[0]; - - Если Параметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.Аргумент = ОписаниеУзлаПолеИлиУзлаКонстанта(Параметр.Строки[0]); - - ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" - И Параметр.Строки[0].Уточнение = "Выразить" Тогда - - НовоеОписание.Аргумент = ОписаниеУзлаПолеИзФункцииВыразить(Параметр.Строки[0], Контекст); - - ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" - И Параметр.Строки[0].Уточнение = "ЕстьNull" Тогда - - НовоеОписание.Аргумент = ОписаниеУзлаПолеИзФункцииЕстьNull(Параметр.Строки[0], Контекст); - Иначе - УстановитьОшибкуВСтроке(Параметр.Строки[0], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), - "Выразить,ЕстьNull")); - Возврат; - КонецЕсли; - - Если Параметр.Строки[0].Вид = "КлючевоеСлово" - И Параметр.Строки[0].Уточнение = "Выразить" - И НовоеОписание.Аргумент.Вложение = Неопределено Тогда - - УстановитьОшибкуВСтроке(СтрокаТаблицы(Параметр.Строки[0].КонечнаяСтрока, Контекст), - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После вложенной функции ""%1"" должно быть указано имя поля через точку'"), - Параметр.Строки[0].Символы), - Истина); - КонецЕсли; - - Если Параметр.Строки.Количество() < 2 Тогда - Возврат; - КонецЕсли; - - Если Параметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедур РазобратьФункцию, РазобратьПервыйПараметрПроверочнойФункции, РазобратьПараметрыФункцииТипЗначения. -Функция ОписаниеУзлаПолеИзФункцииВыразить(Строка, Контекст) - - НовоеОписание = ОписаниеУзлаПоле(Строка); - - Если Строка.Строки.Количество() > 0 Тогда - ПоследняяСтрока = СтрокаТаблицы(Строка.Строки[Строка.Строки.Количество() - 1], Контекст); - Если ПоследняяСтрока.Тип = "ДополнениеКВыразить" Тогда - Строка.Строки.Удалить(Строка.Строки.Количество() - 1); - НовоеОписание.Имя = Сред(ПоследняяСтрока.Символы, 2); - НовоеОписание.ИмяИсточник = ПоследняяСтрока; - НовоеОписание.Вложение = ОписаниеУзлаПолеИзФункцииВыразить(Строка, Контекст); - Возврат НовоеОписание; - КонецЕсли; - КонецЕсли; - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - Возврат НовоеОписание; - КонецЕсли; - - ПервыйПараметр = СоставПараметров[0]; - - Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.Имя = ПервыйПараметр.Строки[0].Символы; - НовоеОписание.ИмяИсточник = ПервыйПараметр.Строки[0]; - - ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" - И ПервыйПараметр.Строки[0].Уточнение = "Выразить" Тогда - - НовоеОписание.Вложение = ОписаниеУзлаПолеИзФункцииВыразить(ПервыйПараметр.Строки[0], Контекст); - Если НовоеОписание.Вложение.Вложение = Неопределено Тогда - УстановитьОшибкуВСтроке(СтрокаТаблицы(ПервыйПараметр.Строки[0].КонечнаяСтрока, Контекст), - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После вложенной функции ""%1"" должно быть указано имя поля через точку'"), - ПервыйПараметр.Строки[0].Символы), - Истина); - Иначе - НовоеОписание = НовоеОписание.Вложение; - КонецЕсли; - - ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" - И ПервыйПараметр.Строки[0].Уточнение = "ЕстьNull" Тогда - - НовоеОписание = ОписаниеУзлаПолеИзФункцииЕстьNull(ПервыйПараметр.Строки[0], Контекст); - Иначе - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Первым параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), - "Выразить,ЕстьNull")); - Возврат НовоеОписание; - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() < 2 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После описания поля должно быть указано ключевое слово ""%1""'"), "Как"), Истина); - Возврат НовоеОписание; - КонецЕсли; - - Если ПервыйПараметр.Строки[1].Вид <> "КлючевоеСлово" - Или ПервыйПараметр.Строки[1].Уточнение <> "Как" Тогда - - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], - ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После описания поля должно быть указано ключевое слово ""%1""'"), "Как")); - Возврат НовоеОписание; - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() < 3 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" не указан тип (имя таблицы)'"), ПервыйПараметр.Строки[1].Символы)); - Возврат НовоеОписание; - КонецЕсли; - - Если ПервыйПараметр.Строки[2].Вид <> "Имя" Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[2], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" должен быть указан тип (имя таблицы)'"), - ПервыйПараметр.Строки[1].Символы)); - Иначе - НовоеОписание.Выразить = ПервыйПараметр.Строки[2].Символы; - НовоеОписание.ВыразитьИсточник = ПервыйПараметр.Строки[2]; - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() > 3 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[3], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); - КонецЕсли; - - Возврат НовоеОписание; - -КонецФункции - -// Для процедур РазобратьФункцию, РазобратьПервыйПараметрПроверочнойФункции, -// РазобратьПараметрыФункцииТипЗначения и -// для функции ОписаниеУзлаПолеИзФункцииВыразить. -// -Функция ОписаниеУзлаПолеИзФункцииЕстьNull(Строка, Контекст) - - НовоеОписание = ОписаниеУзлаПоле(Строка); - НовоеОписание.ЕстьNullИсточник = Строка; - - СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); - - Если СоставПараметров.Количество() = 0 Тогда - // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. - Возврат НовоеОписание; - КонецЕсли; - - ПервыйПараметр = СоставПараметров[0]; - - Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда - НовоеОписание.Имя = ПервыйПараметр.Строки[0].Символы; - НовоеОписание.ИмяИсточник = ПервыйПараметр.Строки[0]; - Иначе - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Первым параметром функции ""%1"" может быть только имя поля'"), Строка.Символы)); - КонецЕсли; - - Если ПервыйПараметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Перед параметром функции ""%1"" не указана запятая'"), Строка.Символы)); - Возврат НовоеОписание; - КонецЕсли; - - Если СоставПараметров.Количество() < 2 Тогда - УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" должно быть два параметра'"), Строка.Символы)); - Возврат НовоеОписание; - КонецЕсли; - - ВторойПараметр = СоставПараметров[1]; - - Если ВторойПараметр.Строки[0].Вид = "Число" - Или ВторойПараметр.Строки[0].Вид = "ПроизвольнаяСтрока" - Или ВторойПараметр.Строки[0].Вид = "КлючевоеСлово" - И ( ВторойПараметр.Строки[0].Уточнение = "Истина" - Или ВторойПараметр.Строки[0].Уточнение = "Ложь" - Или ВторойПараметр.Строки[0].Уточнение = "Неопределено" - Или ВторойПараметр.Строки[0].Уточнение = "Значение" ) Тогда - - Если ВторойПараметр.Строки[0].Уточнение = "Значение" Тогда - НовоеОписание.ЕстьNull = Новый Структура("Источник, Узел", - ВторойПараметр.Строки[0], ВторойПараметр.Строки[0].Уточнение); - - РазобратьПараметрыФункцииЗначениеИлиФункцииТип(ВторойПараметр.Строки[0], НовоеОписание.ЕстьNull, Истина, Контекст); - Иначе - НовоеОписание.ЕстьNull = ОписаниеУзлаПолеИлиУзлаКонстанта(ВторойПараметр.Строки[0]); - КонецЕсли; - Иначе - УстановитьОшибкуВСтроке(ВторойПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" второй параметр может быть, либо предопределенным значением, либо константой'"), - Строка.Символы)); - КонецЕсли; - - Если ВторойПараметр.Строки.Количество() > 1 Тогда - УстановитьОшибкуВСтроке(ВторойПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); - КонецЕсли; - - Если СоставПараметров.Количество() > 2 Тогда - УстановитьОшибкуВСтроке(СоставПараметров[2].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" должно быть только два параметра'"), Строка.Символы)); - КонецЕсли; - - Возврат НовоеОписание; - -КонецФункции - -// Для процедур РазобратьСоединительВ, РазобратьПараметрыПроверочнойФункции, -// РазобратьПараметрыФункцииЗначениеИлиФункцииТип, РазобратьПараметрыФункцииТипЗначения и -// для функций ОписаниеУзлаПолеИзФункцииВыразить, ОписаниеУзлаПолеИзФункцииЕстьNull. -// -// Параметры: -// ОписаниеСтроки - см. СтрокаТаблицы.ОписаниеСтроки -// -// Возвращаемое значение: -// Массив из Структура: -// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Функция ПараметрыРазделенныеЗапятыми(ОписаниеСтроки, Контекст) - - СоставПараметров = Новый Массив; - Строка = СтрокаТаблицы(ОписаниеСтроки, Контекст); - - Если Строка.Строки.Количество() = 0 Тогда - Возврат СоставПараметров; - КонецЕсли; - - ОписаниеПараметра = Новый Структура("Строки, КонечнаяСтрока", Новый Массив); - ПредыдущаяПодстрокаЭтоЧастьАргумента = Ложь; - - Для Каждого ОписаниеПодстроки Из Строка.Строки Цикл - Подстрока = СтрокаТаблицы(ОписаниеПодстроки, Контекст); - Если Подстрока.Символы = "," Тогда - Если Не ПредыдущаяПодстрокаЭтоЧастьАргумента Тогда - Если Строка.Строки[0] = ОписаниеПодстроки Тогда - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Перед запятой не указан параметр'"), Подстрока.Символы)); - ОписаниеПараметра.Строки.Добавить(ДополнительнаяСтрока(Подстрока, "")); - Иначе - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Пропущен параметр или лишняя запятая'"), Подстрока.Символы)); - КонецЕсли; - КонецЕсли; - Если ОписаниеПараметра.Строки.Количество() > 0 Тогда - СоставПараметров.Добавить(ОписаниеПараметра); - ОписаниеПараметра.КонечнаяСтрока = Подстрока; - КонецЕсли; - ОписаниеПараметра = Новый Структура("Строки, КонечнаяСтрока", Новый Массив); - ПредыдущаяПодстрокаЭтоЧастьАргумента = Ложь; - Продолжить; - КонецЕсли; - - ПредыдущаяПодстрокаЭтоЧастьАргумента = Истина; - - ОписаниеПараметра.Строки.Добавить(Подстрока); - КонецЦикла; - - Если ОписаниеПараметра.Строки.Количество() > 0 Тогда - СоставПараметров.Добавить(ОписаниеПараметра); - ОписаниеПараметра.КонечнаяСтрока = СтрокаТаблицы(Строка.КонечнаяСтрока, Контекст); - Иначе - УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Лишняя запятая или после запятой не указан параметр'"), Подстрока.Символы), Истина); - КонецЕсли; - - Возврат СоставПараметров; - -КонецФункции - -// Для процедуры РазобратьВыражение. -// -// Параметры: -// Контекст - Структура: -// * Строка - Структура: -// ** Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура РазобратьВыбор(Контекст) - - Строка = Контекст.Строка; - - СвойстваУзла = "Источник, Узел, Выбор, Когда, Иначе"; - НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Выбор"); - НовоеОписание.Когда = Новый Массив; - - ПропуститьАнализКогда = Ложь; - - Выбор = СтрокаТаблицы(Строка.Строки[0], Контекст); - Если Выбор.Строки.Количество() > 0 Тогда - ПерваяСтрокаВыбора = СтрокаТаблицы(Выбор.Строки[0], Контекст); - Если ПерваяСтрокаВыбора.Вид = "Имя" Тогда - НовоеОписание.Выбор = ОписаниеУзлаПолеИлиУзлаКонстанта(ПерваяСтрокаВыбора); - Иначе - ПропуститьАнализКогда = Истина; - УстановитьОшибкуВСтроке(ПерваяСтрокаВыбора, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Когда аргумент ключевого слова ""%1"" указан, то это может быть только имя поля'"), - Строка.Символы)); - КонецЕсли; - КонецЕсли; - - Индекс = 1; - Пока Истина Цикл - СледующаяСтрока = СтрокаТаблицы(Строка.Строки[Индекс], Контекст); - Если СледующаяСтрока.Уточнение <> "Когда" Тогда - Прервать; - КонецЕсли; - ОписаниеКогдаТогда = Новый Структура("Условие, Значение"); - НовоеОписаниеКогда = НовоеОписание.Когда; // Массив - НовоеОписаниеКогда.Добавить(ОписаниеКогдаТогда); - - Когда = СледующаяСтрока; - - Если Не ПропуститьАнализКогда Тогда - ПерваяПодстрокаКогда = ?(Когда.Строки.Количество() = 0, Неопределено, - СтрокаТаблицы(Когда.Строки[0], Контекст)); - - Если НовоеОписание.Выбор = Неопределено Тогда - РазобратьВыражение(Когда.Строки, ОписаниеКогдаТогда.Условие, Контекст); - - ИначеЕсли Когда.Строки.Количество() = 0 Тогда - Если ЗначениеЗаполнено(Когда.Символы) Тогда - УстановитьОшибкуВСтроке(Когда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Так как после ключевого слова ""%1"" указано поле, то после ключевого слова ""%2"" - |должно быть указано, либо предопределенное значение, либо константа'"), - Строка.Символы, - Когда.Символы)); - КонецЕсли; - - ИначеЕсли ПерваяПодстрокаКогда.Вид = "Число" - Или ПерваяПодстрокаКогда.Вид = "ПроизвольнаяСтрока" - Или ПерваяПодстрокаКогда.Вид = "КлючевоеСлово" - И ( ПерваяПодстрокаКогда.Уточнение = "Истина" - Или ПерваяПодстрокаКогда.Уточнение = "Ложь" - Или ПерваяПодстрокаКогда.Уточнение = "Неопределено" - Или ПерваяПодстрокаКогда.Уточнение = "Значение" ) Тогда - - Если ПерваяПодстрокаКогда.Уточнение = "Значение" Тогда - ОписаниеКогдаТогда.Условие = Новый Структура("Источник, Узел", - ПерваяПодстрокаКогда, ПерваяПодстрокаКогда.Уточнение); - - РазобратьПараметрыФункцииЗначениеИлиФункцииТип(ПерваяПодстрокаКогда, - ОписаниеКогдаТогда.Условие, Истина, Контекст); - Иначе - ОписаниеКогдаТогда.Условие = ОписаниеУзлаПолеИлиУзлаКонстанта(ПерваяПодстрокаКогда); - КонецЕсли; - ИначеЕсли ЗначениеЗаполнено(Когда.Символы) Тогда - УстановитьОшибкуВСтроке(ПерваяПодстрокаКогда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Так как после ключевого слова ""%1"" указано поле, то после ключевого слова ""%2"" - |должно быть указано, либо предопределенное значение, либо константа'"), - Строка.Символы, - Когда.Символы)); - КонецЕсли; - КонецЕсли; - - СоставТогда = СтрокаТаблицы(Строка.Строки[Индекс + 1], Контекст); - Если СоставТогда.Строки.Количество() > 0 Тогда - РазобратьВыражение(СоставТогда.Строки, ОписаниеКогдаТогда.Значение, Контекст); - - ИначеЕсли ЗначениеЗаполнено(СоставТогда.Символы) Тогда - УстановитьОшибкуВСтроке(ПерваяПодстрокаКогда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" должно быть указано логическое выражение'"), СоставТогда.Символы)); - КонецЕсли; - - Индекс = Индекс + 2; - КонецЦикла; - - РазобратьВыражение(СледующаяСтрока.Строки, НовоеОписание.Иначе, Контекст); - - ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); - -КонецПроцедуры - -// Для процедуры РазобратьВыражение. -Процедура РазобратьОшибочноеКлючевоеСлово(Контекст) - - Строка = Контекст.Строка; - Контекст.Описание = Неопределено; - - Если Строка.Тип = "Неопределен" Тогда - // Для зарезервированных слов ошибка уже установлена. - Возврат; - КонецЕсли; - - Если Строка.Тип = "ЗначениеСравнения" Тогда - Если Строка.Уточнение = "Отключено" Тогда - // "Отключено". - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Значение ""%1"" может использоваться только как уточняемое значение - |в параметрах функции ""%2""'"), - Строка.Символы, - КлючевоеСловоСУчетомЯзыка("ЗначениеРазрешено", Контекст))); - Иначе - // "ПустаяСсылка" или "Null". - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Значение ""%1"" может использоваться только как уточняемое значение - |в параметрах функций проверки разрешений'"), - Строка.Символы)); - КонецЕсли; - - ИначеЕсли Строка.Тип = "ИмяТипа" Тогда - // "Число", "Строка", "Дата", "Булево". - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Имя типа ""%1"" может использоваться только, как параметр функции ""%2"" или - |как уточняемое значение в параметрах функций проверки разрешений'"), - Строка.Символы, - "Тип")); - Иначе - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); - КонецЕсли; - -КонецПроцедуры - -// Для процедур РазобратьВыражение, РазобратьОператор, РазобратьФункцию, РазобратьВыбор. -Процедура ДобавитьАргументФункциюВыборОператор(Контекст, ДобавляемоеОписание) - - // Текущий узел: Любой. - // Добавляемое описание: Поле, Значение, Константа, Не, Выбор, любая функция. - - Описание = Контекст.Описание; // См. ОписаниеУзла - - Если Описание = Неопределено Тогда - Контекст.Описание = ДобавляемоеОписание; - - ИначеЕсли Описание.Узел = "И" - Или Описание.Узел = "Или" Тогда - - Если Описание.Аргументы.Количество() = 1 Тогда - Описание.Аргументы.Добавить(ДобавляемоеОписание); - Иначе - ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.Аргументы[1], ДобавляемоеОписание); - КонецЕсли; - - ИначеЕсли Описание.Узел = "Не" Тогда - - Если Не ЗначениеЗаполнено(Описание.Аргумент) Тогда - Описание.Аргумент = ДобавляемоеОписание; - Иначе - ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.Аргумент, ДобавляемоеОписание); - КонецЕсли; - - ИначеЕсли Описание.Источник.Вид = "Операция" Тогда - - Если Не ЗначениеЗаполнено(Описание.ВторойАргумент) Тогда - Описание.ВторойАргумент = ДобавляемоеОписание; - // Проверка корректности аргументов выполняется - // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. - Иначе - ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.ВторойАргумент, ДобавляемоеОписание); - КонецЕсли; - - ИначеЕсли СтрНайти(",Поле,Значение,Константа,В,ЕстьNull,Выбор,", "," + Описание.Узел + ",") > 0 - Или Описание.Источник.Тип = "Функция" Тогда - // Второй аргумент операции В уже разобран в процедуре РазобратьСоединительВ. - // Второй аргумент Null операции Есть уже разобран в функции ФункцииСВыражениямиВСкобках. - // Остальные узлы не имеют второго аргумента. - ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Неопределено, ДобавляемоеОписание); - Иначе - ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не определена обработка узла ""%1""'"), Описание.Узел); - ВызватьИсключение ТекстОшибки; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ДобавитьАргументФункциюВыборОператор -Процедура ОбработатьПропущеннуюЛогическуюОперацию(Контекст, ПоследнийАргументОписания, ДобавляемоеОписание) - - УстановитьОшибкуВСтроке(Контекст.Строка, НСтр("ru = 'Не указана логическая операция'")); - - // Восстановление. - ДополнительнаяСтрока = ДополнительнаяСтрока(Контекст.Строка, "И", Контекст); - - НовоеОписание = Новый Структура("Источник, Узел, Аргументы", ДополнительнаяСтрока, "И", Новый Массив); - НовоеОписание.Аргументы.Добавить(); - - ТекущаяСтрока = Контекст.Строка; - Контекст.Строка = ДополнительнаяСтрока; - - ВставитьСоединительСУчетомПриоритета(Контекст, - ПоследнийАргументОписания, НовоеОписание, НовоеОписание.Аргументы[0]); - - Контекст.Строка = ТекущаяСтрока; - - НовоеОписание.Аргументы.Добавить(ДобавляемоеОписание); - -КонецПроцедуры - -// Для процедуры РазобратьУсловие. -// -// Возвращаемое значение: -// Массив из СтрокаТаблицыЗначений -// -Функция ВыраженияВСкобкахВоВложениях(Строки, Контекст) - - Результат = Новый Массив; - - ТекущееВложение = Новый Структура("Строки", Результат); - Вложения = Новый Массив; - Вложения.Добавить(ТекущееВложение); - - Для Каждого Строка Из Строки Цикл - Если Строка.Символы = "(" Тогда - ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); - - ИначеЕсли Строка.Символы = ")" Тогда - Если Вложения.Количество() = 1 Тогда - УстановитьОшибкуВСтроке(Строка, - НСтр("ru = 'Указана закрывающаяся скобка до открывающейся скобки'")); - Иначе - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст, Строка); - КонецЕсли; - Иначе - СтрокаДобавить(ТекущееВложение, Строка, Контекст); - КонецЕсли; - КонецЦикла; - - Пока Вложения.Количество() > 1 Цикл - ИндексПоследнегоВложения = Вложения.Количество() - 1; - Вложение = Вложения[ИндексПоследнегоВложения]; - Вложение.КонечнаяСтрока = Строка; - Вложения.Удалить(ИндексПоследнегоВложения); - УстановитьОшибкуВСтроке(Вложение, - НСтр("ru = 'Указана открывающаяся скобка без закрывающейся скобки'"), Истина); - КонецЦикла; - - Возврат Результат; - -КонецФункции - -// Для процедуры РазобратьУсловие. -// -// Параметры: -// Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Функция ВыраженияВыборКогдаТогдаВоВложениях(Строки, Контекст) - - Результат = Новый Массив; - - ТекущееВложение = Новый Структура("Строки, Уточнение", Результат, ""); - Вложения = Новый Массив; - Вложения.Добавить(ТекущееВложение); - - Для Каждого ОписаниеСтроки Из Строки Цикл - Строка = СтрокаТаблицы(ОписаниеСтроки, Контекст); - - Если Строка.Вид <> "КлючевоеСлово" - Или Строка.Тип <> "СловоВыбора" Тогда - - Если ТекущееВложение.Уточнение = "Выбор" Тогда - СтрокаДобавить(СтрокаТаблицы(ТекущееВложение.Строки[0], Контекст), Строка, Контекст); - Иначе - СтрокаДобавить(ТекущееВложение, Строка, Контекст); - Если Строка.Символы = "(" Тогда - Строка.Строки = ВыраженияВыборКогдаТогдаВоВложениях(Строка.Строки, Контекст); - КонецЕсли; - КонецЕсли; - ИначеЕсли Строка.Уточнение = "Выбор" Тогда - Если Вложения.Количество() = 1 Тогда - // Стандартная обработка после условия. - Иначе - Если ТекущееВложение.Уточнение = "Выбор" Тогда - УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Выбор,Когда"), Истина); - ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда", Контекст); - КонецЕсли; - КонецЕсли; - ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); - ТекущееВложение.Строки.Добавить(ДополнительнаяСтрока(ТекущееВложение, "Выбор", Контекст)); - - ИначеЕсли Строка.Уточнение = "Когда" Тогда - - Если Вложения.Количество() = 1 Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Когда,Выбор")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда - // Стандартная обработка после условия. - - ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда - УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Когда,Тогда"), Истина); - ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Тогда", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - - Иначе // ТекущееВложение.Уточнение = "Иначе" - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" должно быть до ключевого слова ""%2""'"), "Когда,Иначе")); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - КонецЕсли; - ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); - - ИначеЕсли Строка.Уточнение = "Тогда" Тогда - - Если Вложения.Количество() = 1 Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Тогда,Выбор,Когда")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Тогда,Когда")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда - // Стандартная обработка после условия. - - ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда - УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Тогда,Когда"), Истина); - ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда", Контекст); - - Иначе // ТекущееВложение.Уточнение = "Иначе" - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" должно быть до ключевого слова ""%2""'"), "Тогда,Иначе")); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда", Контекст); - КонецЕсли; - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); - - ИначеЕсли Строка.Уточнение = "Иначе" Тогда - - Если Вложения.Количество() = 1 Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"" и ""%4""'"), "Иначе,Выбор,Когда,Тогда")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда,Тогда", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Иначе,Когда,Тогда")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда,Тогда", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Иначе,Тогда")); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Тогда", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда - // Стандартная обработка после условия. - - Иначе // ТекущееВложение.Уточнение = "Иначе" - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано повторно'"), "Иначе")); - КонецЕсли; - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); - - Иначе // Строка.Уточнение = "Конец" - - Если Вложения.Количество() = 1 Тогда - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"", ""%4"" и ""%5""'"), "Конец,Выбор,Когда,Тогда,Иначе")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда,Тогда,Иначе", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"" и ""%4""'"), "Конец,Когда,Тогда,Иначе")); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда,Тогда,Иначе", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Конец,Тогда,Иначе")); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Тогда,Иначе", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Конец,Иначе")); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Иначе", Контекст); - - Иначе // ТекущееВложение.Уточнение = "Иначе". - // Стандартная обработка после условия. - КонецЕсли; - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - КонецЕсли; - КонецЦикла; - - Пока Вложения.Количество() > 1 Цикл - ТекущееВложение = Вложения[Вложения.Количество() - 1]; - - Если ТекущееВложение.Уточнение = "Выбор" Тогда - ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"", ""%3"", ""%4"" и ""%5""'"), "Выбор,Когда,Тогда,Иначе,Конец"); - ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда,Тогда,Иначе", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда - ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"", ""%3"", ""%4""'"), "Когда,Тогда,Иначе,Конец"); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Тогда,Иначе", Контекст); - - ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда - ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"" и ""%3""'"), "Тогда,Иначе,Конец"); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Иначе", Контекст); - - Иначе // ТекущееВложение.Уточнение = "Иначе" - ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, - НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слово ""%2""'"), "Иначе,Конец"); - КонецЕсли; - УстановитьОшибкуВСтроке(ТекущееВложение, ТекстОшибки, Истина); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); - КонецЦикла; - - Возврат Результат; - -КонецФункции - -// Для процедуры РазобратьУсловие. -// -// Параметры: -// Строки - Массив из см. СтрокаТаблицы.ОписаниеСтроки -// -Функция ФункцииСВыражениямиВСкобках(Строки, ВнутренниеДанные) - - Результат = Новый Массив; - СтрокаРезультата = Новый Структура("Строки", Результат); - - КоличествоСтрок = Строки.Количество(); - - Строка = Неопределено; - Индекс = 0; - Пока Индекс < КоличествоСтрок Цикл - ПредыдущаяСтрока = Строка; // СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов - Строка = СтрокаТаблицы(Строки[Индекс], ВнутренниеДанные); - - Если Строка.Символы = "(" Тогда - Строка.Строки = ФункцииСВыражениямиВСкобках(Строка.Строки, ВнутренниеДанные); - - ИначеЕсли Строка.Вид = "КлючевоеСлово" - И ( Строка.Тип = "Функция" - Или Строка.Уточнение = "В" ) Тогда - - СледующаяСтрока = ?(Индекс + 1 < Строки.Количество(), - СтрокаТаблицы(Строки[Индекс + 1], ВнутренниеДанные), Неопределено); - - Если Индекс + 1 < Строки.Количество() - И СледующаяСтрока.Символы = "(" Тогда - - Индекс = Индекс + 1; - Строка.Строки = ФункцииСВыражениямиВСкобках(СледующаяСтрока.Строки, ВнутренниеДанные); - Строка.КонечнаяСтрока = СледующаяСтрока.КонечнаяСтрока; - - Если Строка.Строки.Количество() = 0 Тогда - Если Строка.Тип = "Функция" Тогда - УстановитьОшибкуВСтроке(Строки[Индекс], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У функции ""%1"" не указано ни одного параметра'"), Строка.Символы), Истина); - Иначе - УстановитьОшибкуВСтроке(Строки[Индекс], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В списке значений операции ""%1"" не указано ни одного значения'"), Строка.Символы), Истина); - КонецЕсли; - КонецЕсли; - Иначе - Строка.Строки = Новый Массив; - Если Строка.Тип = "Функция" Тогда - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После функции ""%1"" не указаны параметры в скобках'"), Строка.Символы), Истина); - Иначе - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'После ключевого слова ""%1"" не указаны значения в скобках'"), Строка.Символы), Истина); - КонецЕсли; - КонецЕсли; - - ИначеЕсли Строка.Вид = "КлючевоеСлово" - И Строка.Уточнение = "Есть" Тогда - - СледующаяСтрока = ?(Индекс + 1 < Строки.Количество(), - СтрокаТаблицы(Строки[Индекс + 1], ВнутренниеДанные), Неопределено); - - Если Индекс + 1 < Строки.Количество() - И СледующаяСтрока.Вид = "КлючевоеСлово" - И СледующаяСтрока.Уточнение = "Null" Тогда - - Индекс = Индекс + 1; - СтрокаДобавить(Строка, СледующаяСтрока, ВнутренниеДанные); - Иначе - Строка.Строки = Новый Массив; - УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, - НСтр("ru = 'После ключевого слова ""%2"" не указано ключевое слово ""%1""'"), - "Null", - Строка.Символы), - Истина); - КонецЕсли; - - ИначеЕсли Строка.Вид = "Имя" - И СтрНачинаетсяС(Строка.Символы, ".") - И ПредыдущаяСтрока <> Неопределено Тогда - - Если ПредыдущаяСтрока <> Неопределено - И ПредыдущаяСтрока.Вид = "КлючевоеСлово" - И ПредыдущаяСтрока.Уточнение = "Выразить" Тогда - - Строка.Тип = "ДополнениеКВыразить"; - СтрокаДобавить(ПредыдущаяСтрока, Строка, ВнутренниеДанные); - Индекс = Индекс + 1; - Продолжить; - Иначе - УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Имя поля не может начинаться с символа "".""'"), Строка.Символы)); - КонецЕсли; - КонецЕсли; - - СтрокаДобавить(СтрокаРезультата, Строка, ВнутренниеДанные); - Индекс = Индекс + 1; - КонецЦикла; - - Возврат Результат; - -КонецФункции - -// Для функций ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. -Процедура ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст) - - СтрокаДобавить(ТекущееВложение, Строка, Контекст); - ТекущееВложение = Строка; - Вложения.Добавить(ТекущееВложение); - -КонецПроцедуры - -// Для функций ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. -Процедура УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст, КонечнаяСтрока = Неопределено) - - Если КонечнаяСтрока = Неопределено Тогда - Если ТекущееВложение.Строки.Количество() = 0 Тогда - КонечнаяСтрока = ТекущееВложение; - Иначе - КонечнаяСтрока = СтрокаТаблицы(ТекущееВложение.Строки[ТекущееВложение.Строки.Количество() - 1], Контекст); - Если КонечнаяСтрока.КонечнаяСтрока <> Неопределено Тогда - КонечнаяСтрока = СтрокаТаблицы(КонечнаяСтрока.КонечнаяСтрока, Контекст); - КонецЕсли; - КонецЕсли; - КонецЕсли; - - ТекущееВложение.КонечнаяСтрока = Контекст.ТаблицаНаборовСимволов.Индекс(КонечнаяСтрока); - - ИндексПоследнегоВложения = Вложения.Количество() - 1; - Вложения.Удалить(ИндексПоследнегоВложения); - ТекущееВложение = Вложения[ИндексПоследнегоВложения - 1]; - -КонецПроцедуры - -// Для функции ВыраженияВыборКогдаТогдаВоВложениях. -Процедура ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, СписокНедостающихСлов, Контекст) - - НедостающиеСлова = СтрРазделить(СписокНедостающихСлов, ",", Ложь); - - Для Каждого НедостающееСлово Из НедостающиеСлова Цикл - НоваяСтрока = ДополнительнаяСтрока(Строка, НедостающееСлово, Контекст); - ТекущееВложение.Строки.Добавить(НоваяСтрока); - - Если НедостающееСлово = "Выбор" Тогда - ТекущееВложение = НоваяСтрока; - Вложения.Добавить(ТекущееВложение); - КонецЕсли; - КонецЦикла; - - Если НедостающееСлово <> "Выбор" Тогда - ТекущееВложение = НоваяСтрока; - Вложения.Добавить(ТекущееВложение); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ОбработатьПропущеннуюЛогическуюОперацию, ВыраженияВыборКогдаТогдаВоВложениях, -// ВосстановитьСтруктуруВыбора и для функции ПараметрыРазделенныеЗапятыми. -// -// Возвращаемое значение: -// Структура: -// * Символы - Строка -// * Вид - Строка -// * Тип - Строка -// * Приоритет - Число -// * Уточнение - Строка -// * Строки - Массив из Число - индексы строк ТаблицаНаборовСимволов -// * КонечнаяСтрока - Число - индекс строки ТаблицаНаборовСимволов -// * ПозицияОшибки - Число -// * ТекстОшибки - Строка -// -Функция ДополнительнаяСтрока(Строка, Уточнение = "", Контекст = Неопределено) - - НоваяСтрока = Новый Структура; - НоваяСтрока.Вставить("Символы"); - НоваяСтрока.Вставить("Вид"); - НоваяСтрока.Вставить("Тип"); - НоваяСтрока.Вставить("Приоритет"); - НоваяСтрока.Вставить("Уточнение", Уточнение); - НоваяСтрока.Вставить("Строки", Новый Массив); - НоваяСтрока.Вставить("КонечнаяСтрока"); - НоваяСтрока.Вставить("ПозицияОшибки"); - НоваяСтрока.Вставить("ТекстОшибки"); - - СвойстваСлова = ?(Контекст = Неопределено, - Неопределено, Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(Уточнение))); - - Если СвойстваСлова <> Неопределено Тогда - НоваяСтрока.Вид = "КлючевоеСлово"; - НоваяСтрока.Тип = СвойстваСлова.Тип; - НоваяСтрока.Приоритет = СвойстваСлова.Приоритет; - КонецЕсли; - - Возврат НоваяСтрока; - -КонецФункции - -// Для процедур РазобратьДополнительныеТаблицы, РазобратьУсловиеОграничения. -// -// Параметры: -// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти, ИсключаемаяСтрока = Неопределено) - - Для Каждого Строка Из СтрокиЧасти Цикл - Если Строка = ИсключаемаяСтрока - Или Строка.Вид <> "КлючевоеСлово" - Или Строка.Уточнение <> "ЭтотСписок" Тогда - Продолжить; - КонецЕсли; - Строка.Вид = "Имя"; - Строка.Уточнение = ""; - КонецЦикла; - -КонецПроцедуры - -// Для процедур РазобратьДополнительныеТаблицы, РазобратьСоединение. -// -// Параметры: -// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура УстановитьПсевдоним(СтрокаЧасти, ОписаниеСоединения, ВнутренниеДанные) - - Если ЗначениеЗаполнено(СтрокаЧасти.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - ПозицияТочки = СтрНайти(СтрокаЧасти.Символы, "."); - Если ПозицияТочки > 0 Тогда - СтрокаЧасти.ПозицияОшибки = ПозицияТочки - 1; - СтрокаЧасти.ТекстОшибки = - НСтр("ru = 'Псевдоним не может содержать символа "".""'"); - - ИначеЕсли ТипЗнч(ОписаниеСоединения) = Тип("Строка") Тогда - ОписаниеСоединения = СтрокаЧасти.Символы; - ВнутренниеДанные.Псевдонимы.Вставить(ВРег(СтрокаЧасти.Символы), - Новый Структура("Псевдоним, Таблица", СтрокаЧасти.Символы)); - Иначе - ОписаниеСоединения.Псевдоним = СтрокаЧасти.Символы + "Псевдоним"; - Если ВнутренниеДанные.Псевдонимы.Получить(ВРег(СтрокаЧасти.Символы)) = Неопределено Тогда - Если ЗначениеЗаполнено(ОписаниеСоединения.Таблица) Тогда - ВнутренниеДанные.Псевдонимы.Вставить(ВРег(СтрокаЧасти.Символы), - Новый Структура("Псевдоним, Таблица", - ОписаниеСоединения.Псевдоним, ОписаниеСоединения.Таблица)); - КонецЕсли; - Иначе - СтрокаЧасти.ТекстОшибки = НСтр("ru = 'Псевдоним повторяется'"); - КонецЕсли; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры РазобратьСоединение. -// -// Параметры: -// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов -// -Процедура УстановитьИмяТаблицы(СтрокаЧасти, ОписаниеСоединения, ВнутренниеДанные) - - Если ЗначениеЗаполнено(СтрокаЧасти.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - Если СтрНачинаетсяС(СтрокаЧасти.Символы, ".") Тогда - СтрокаЧасти.ТекстОшибки = - НСтр("ru = 'Имя таблицы не может начинаться с символа "".""'"); - Возврат; - КонецЕсли; - - Если СтрЧислоВхождений(СтрокаЧасти.Символы, ".") > 2 Тогда - - ПозицияТочки = СтрНайти(СтрокаЧасти.Символы, "."); - ПозицияТочки = ПозицияТочки + СтрНайти(Сред(СтрокаЧасти.Символы, ПозицияТочки + 1), "."); - - ПозицияТочки = ПозицияТочки + СтрНайти(Сред(СтрокаЧасти.Символы, ПозицияТочки + 1), "."); - СтрокаЧасти.ТекстОшибки = - НСтр("ru = 'Полное имя таблицы не может содержать более двух символов "".""'"); - - СтрокаЧасти.ПозицияОшибки = ПозицияТочки - 1; - Возврат; - КонецЕсли; - - ОписаниеСоединения.Таблица = СтрокаЧасти.Символы; - - ДобавитьТребуемуюТаблицуКакИсточникДанных(ВнутренниеДанные, ОписаниеСоединения.Таблица, СтрокаЧасти); - -КонецПроцедуры - -// Для процедуры УстановитьИмяТаблицы. -Процедура ДобавитьТребуемуюТаблицуКакИсточникДанных(Контекст, Таблица, Источник) - - Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); - - Если СвойстваИмени.ЧислоЧастейИмени < 2 - Или СвойстваИмени.ЧислоЧастейИмени > 3 Тогда - УстановитьОшибкуВСтроке(Источник, - НСтр("ru = 'В имени присоединяемой таблицы должна быть одна или две точки'")); - Возврат; - КонецЕсли; - - Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), СвойстваИмени.ИмяТипа, Таблица)); - Возврат; - КонецЕсли; - - Если СвойстваИмени.ЧислоЧастейИмени = 3 Тогда - СвойстваУточнения = СвойстваИмени.СвойстваТипаТаблиц.УточнениеТаблиц.Получить( - ВРег(СвойстваИмени.Расширение)); - - Если СвойстваУточнения <> Неопределено - И СвойстваУточнения.Использование <> "Разрешено" Тогда - - Если СвойстваУточнения.Использование = "Недопустимо" Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Недопустимо использовать таблицы ""%1"" группы таблиц ""%2""'"), - СвойстваИмени.Расширение, СвойстваИмени.ИмяТипа)); - Иначе - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Запрещено присоединять таблицы ""%1"" группы таблиц ""%2""'"), - СвойстваИмени.Расширение, СвойстваИмени.ИмяТипа)); - КонецЕсли; - Возврат; - КонецЕсли; - КонецЕсли; - - Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); - Свойства.Источники.Добавить(Источник); - -КонецПроцедуры - -// Для процедур ВыделитьПсевдонимПоля, РазобратьПервыйПараметрПроверочнойФункции, -// РазобратьДополнительныйПараметрПроверочнойФункции, РазобратьПараметрыФункцииЗначениеИлиФункцииТип. -// -Процедура ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, Таблица, Источник) - - Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); - - Если СвойстваИмени.ЧислоЧастейИмени <> 2 Тогда - УстановитьОшибкуВСтроке(Источник, - НСтр("ru = 'В имени таблицы, указанной в качестве типа, должна быть одна точка'")); - Возврат; - КонецЕсли; - - Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), СвойстваИмени.ИмяТипа, Таблица)); - Возврат; - КонецЕсли; - - Если Не СвойстваИмени.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Группа таблиц ""%1"" не входит в состав ссылочных типов'"), СвойстваИмени.ИмяТипа, Таблица)); - Возврат; - КонецЕсли; - - Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); - Свойства.Источники.Добавить(Источник); - -КонецПроцедуры - -// Для процедуры РазобратьПараметрыФункцииЗначениеИлиФункцииТип. -Процедура ДобавитьТребуемыйПредопределенныйЭлемент(Контекст, ПолноеИмяПредопределенного, Источник) - - Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - СвойстваИмени = СвойстваИмениТаблицы(Контекст, ПолноеИмяПредопределенного); - - Если СвойстваИмени.ЧислоЧастейИмени <> 3 Тогда - УстановитьОшибкуВСтроке(Источник, - НСтр("ru = 'В имени предопределенного значения должно быть две точки'")); - Возврат; - КонецЕсли; - - Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), - СвойстваИмени.ИмяТипа, - СвойстваИмени.ИмяТипа + "." + СвойстваИмени.ИмяБезТипа)); - Возврат; - КонецЕсли; - - Если Не СвойстваИмени.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Группа таблиц ""%1"" не входит в состав ссылочных типов'"), СвойстваИмени.ИмяТипа)); - Возврат; - КонецЕсли; - - СвойстваСлова = Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(СвойстваИмени.Расширение)); // См. СвойстваСлова - - Если Не СвойстваИмени.СвойстваТипаТаблиц.ЕстьПредопределенные - И Не СвойстваИмени.ИмяТипа = "Перечисление" - И ( СвойстваСлова = Неопределено - Или СвойстваСлова.Идентификатор <> "ПустаяСсылка") Тогда - - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'В группе таблиц ""%1"" нет предопределенных элементов'"), СвойстваИмени.ИмяТипа)); - Возврат; - КонецЕсли; - - СвойстваИмениТаблицы = СвойстваИмениТаблицы(Контекст, СвойстваИмени.ИмяТипа + "." + СвойстваИмени.ИмяБезТипа); - Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмениТаблицы, Истина); - - СвойстваПредопределенного = Свойства.Предопределенные.Получить(ВРег(СвойстваИмени.Расширение)); - Если СвойстваПредопределенного = Неопределено Тогда - СвойстваПредопределенного = НовыеСвойстваПредопределенного(); - СвойстваПредопределенного.Вставить("ИмяСуществует", Ложь); - СвойстваПредопределенного.Вставить("Источники", Новый Массив); - Свойства.Предопределенные.Вставить(ВРег(СвойстваИмени.Расширение), СвойстваПредопределенного); - КонецЕсли; - СвойстваПредопределенного.Источники.Добавить(Источник); - -КонецПроцедуры - -// Для процедуры РазобратьПараметрыФункцииРольДоступна. -Процедура ПроверитьИмяРоли(ИмяРоли, Источник) - - Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - Если СтрНайти(ИмяРоли, ".") > 0 Тогда - УстановитьОшибкуВСтроке(Источник, - НСтр("ru = 'В имени роли не должно быть точек'")); - Возврат; - КонецЕсли; - - Если Метаданные.Роли.Найти(ИмяРоли) = Неопределено Тогда - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Роль ""%1"" отсутствует в метаданных'"), ИмяРоли)); - Возврат; - КонецЕсли; - -КонецПроцедуры - -Процедура ПроверитьИмяПраваОбъектаМетаданных(ИмяПрава, ИсточникПрава, ИмяОбъекта, ИсточникОбъекта) - - Если ЗначениеЗаполнено(ИсточникПрава.ТекстОшибки) - Или ИсточникОбъекта <> Неопределено - И ЗначениеЗаполнено(ИсточникОбъекта.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - Если СтрНайти(ИмяПрава, ".") > 0 Тогда - УстановитьОшибкуВСтроке(ИсточникПрава, - НСтр("ru = 'В имени права не должно быть точек'")); - Возврат; - КонецЕсли; - - ИмяСтандартногоРеквизита = Неопределено; - ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава(ИмяОбъекта, ИмяСтандартногоРеквизита); - Если ОбъектМетаданных = Неопределено Тогда - УстановитьОшибкуВСтроке(ИсточникОбъекта, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Объект метаданных ""%1"" не существует'"), ИмяОбъекта)); - Возврат; - КонецЕсли; - - ТекстОшибки = ""; - Попытка - ПравоДоступа(ИмяПрава, ОбъектМетаданных, , ИмяСтандартногоРеквизита); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); - КонецПопытки; - - Если ЗначениеЗаполнено(ТекстОшибки) Тогда - УстановитьОшибкуВСтроке(ИсточникПрава, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось проверить право ""%1"" объекта метаданных ""%2"" по причине: - |%3'"), ИмяПрава, ИмяОбъекта, ТекстОшибки)); - Возврат; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПроверитьИмяПраваОбъектаМетаданных -Функция ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава(ПолноеИмя, ИмяСтандартногоРеквизита = Неопределено) - - ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); - Если ОбъектМетаданных <> Неопределено Тогда - Возврат ОбъектМетаданных; - КонецЕсли; - - ЧастиИмени = СтрРазделить(ПолноеИмя, "."); - Если ЧастиИмени.Количество() < 4 Тогда - Возврат Неопределено; - КонецЕсли; - - ИмяОсновногоОбъектаМетаданных = ЧастиИмени[0] + "." + ЧастиИмени[1]; - ОсновнойОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОсновногоОбъектаМетаданных); - Если ОсновнойОбъектМетаданных = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - - Если ВРег(ЧастиИмени[2]) = ВРег("СтандартнаяТабличнаяЧасть") - Или ВРег(ЧастиИмени[2]) = ВРег("StandardTabularSection") Тогда // @Non-NLS - - Свойства = Новый Структура("СтандартныеТабличныеЧасти"); - ЗаполнитьЗначенияСвойств(Свойства, ОсновнойОбъектМетаданных); - Если Свойства.СтандартныеТабличныеЧасти = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - ИмяСтандартнойТабличнойЧасти = ЧастиИмени[3]; - Для Каждого СтандартнаяТабличнаяЧасть Из Свойства.СтандартныеТабличныеЧасти Цикл - Если ВРег(СтандартнаяТабличнаяЧасть.Имя) = ВРег(ИмяСтандартнойТабличнойЧасти) Тогда - СтандартныеРеквизиты = СтандартнаяТабличнаяЧасть.СтандартныеРеквизиты; - Прервать; - КонецЕсли; - КонецЦикла; - Если СтандартныеРеквизиты = Неопределено - Или ЧастиИмени.Количество() <> 6 Тогда - Возврат Неопределено; - КонецЕсли; - ЧастиИмени.Удалить(0); - ЧастиИмени.Удалить(0); - ВладелецСтандартныхРеквизитов = СтандартнаяТабличнаяЧасть; - Иначе - ВладелецСтандартныхРеквизитов = ОсновнойОбъектМетаданных; - КонецЕсли; - - Если ВРег(ЧастиИмени[2]) <> ВРег("СтандартныйРеквизит") - И ВРег(ЧастиИмени[2]) <> ВРег("StandardAttribute") Тогда // @Non-NLS - Возврат Неопределено; - КонецЕсли; - - Свойства = Новый Структура("СтандартныеРеквизиты"); - ЗаполнитьЗначенияСвойств(Свойства, ВладелецСтандартныхРеквизитов); - Если Свойства.СтандартныеРеквизиты = Неопределено Тогда - Возврат Неопределено; - КонецЕсли; - ИмяСтандартногоРеквизита = ЧастиИмени[3]; - СтандартныеРеквизиты = Свойства.СтандартныеРеквизиты; // ОписанияСтандартныхРеквизитов - - Для Каждого СтандартныйРеквизит Из СтандартныеРеквизиты Цикл - Если ВРег(СтандартныйРеквизит.Имя) = ВРег(ИмяСтандартногоРеквизита) Тогда - Если ЗначениеЗаполнено(ИмяСтандартнойТабличнойЧасти) Тогда - ИмяСтандартногоРеквизита = ИмяСтандартнойТабличнойЧасти + "." + ИмяСтандартногоРеквизита; - КонецЕсли; - Возврат ОсновнойОбъектМетаданных; - КонецЕсли; - КонецЦикла; - - Возврат Неопределено; - -КонецФункции - -// Для процедур ОтметитьНекорректныеАргументыИЗапрещенныеУзлы, ВыделитьПсевдонимПоля, -// ДобавитьТипыВидовДоступаПользователиИВнешниеПользователиДляПроверкиОтсутствия. -// -Процедура ДобавитьТребуемоеПолеТаблицы(Контекст, Таблица, ИмяПоля, Источник, - ТипПоля = "", ИсточникТипаПоля = Неопределено, УзелПоле = Неопределено) - - Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); - Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда - - Если СвойстваИмени.ЭтоОсновнаяТаблица - И Не Контекст.Свойство("ОшибкаНаПервоеПолеОсновнойТаблицыУстановлена") Тогда - - Контекст.Вставить("ОшибкаНаПервоеПолеОсновнойТаблицыУстановлена"); - УстановитьОшибкуВСтрокеИмениПоля(Контекст, Источник, - НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , - Контекст.ОсновнаяТаблица); - КонецЕсли; - - Возврат; - КонецЕсли; - - Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); - - СвойстваПоля = Свойства.Поля.Получить(ВРег(ИмяПоля)); - Если СвойстваПоля = Неопределено Тогда - СвойстваПоля = НовыеСвойстваПоля(); - СвойстваПоля.Вставить("ПолеСОшибкой", 0); - СвойстваПоля.Вставить("ВидОшибки", ""); - СвойстваПоля.Вставить("Коллекция", ""); - СвойстваПоля.Вставить("СодержитТипы", Новый Соответствие); - СвойстваПоля.Вставить("Источники", Новый Соответствие); - СвойстваПоля.Вставить("УзлыПоле", Новый Массив); - Свойства.Поля.Вставить(ВРег(ИмяПоля), СвойстваПоля); - - Если Свойства.Свойство("ПервоеПоле") - И Свойства.ПервоеПоле = Неопределено - И Источник <> Неопределено Тогда - - СвойстваПоля.Вставить("ПервыйИсточник", Новый Структура("Ключ,Значение", Источник, Таблица)); - Свойства.ПервоеПоле = СвойстваПоля; - КонецЕсли; - КонецЕсли; - СвойстваПоля.Источники.Вставить(Источник, Таблица); - Если УзелПоле <> Неопределено Тогда - СвойстваПоля.УзлыПоле.Добавить(УзелПоле); - КонецЕсли; - - Если Не ЗначениеЗаполнено(ТипПоля) Тогда - Возврат; - КонецЕсли; - - Если ТипЗнч(ИсточникТипаПоля) = Тип("СтрокаТаблицыЗначений") - И ЗначениеЗаполнено(ИсточникТипаПоля.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - СвойстваТипа = СвойстваПоля.СодержитТипы.Получить(ВРег(ТипПоля)); - Если СвойстваТипа = Неопределено Тогда - СоставИмени = СтрРазделить(ТипПоля, "."); - СвойстваТипаТаблиц = Контекст.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0])); - Если СвойстваТипаТаблиц = Неопределено Тогда - ИмяТипа = ТипПоля; - ИмяКоллекцииТипа = ""; - ИмяОбъектаКоллекцииТипа = ""; - Иначе - ИмяТипа = СвойстваТипаТаблиц.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS - ИмяКоллекцииТипа = СвойстваТипаТаблиц.ИмяКоллекции; - ИмяОбъектаКоллекцииТипа = СоставИмени[1]; - КонецЕсли; - СвойстваТипа = Новый Структура; - СвойстваТипа.Вставить("СодержитТип", Ложь); - СвойстваТипа.Вставить("ИмяТипа", ИмяТипа); - СвойстваТипа.Вставить("ИмяКоллекцииТипа", ИмяКоллекцииТипа); - СвойстваТипа.Вставить("ИмяОбъектаКоллекцииТипа", ИмяОбъектаКоллекцииТипа); - СвойстваТипа.Вставить("Источники", Новый Соответствие); - СвойстваПоля.СодержитТипы.Вставить(ВРег(ТипПоля), СвойстваТипа); - КонецЕсли; - СвойстваТипа.Источники.Вставить(ИсточникТипаПоля, Источник); - -КонецПроцедуры - -// Для процедур ДобавитьТребуемуюТаблицуКакИсточникДанных, ДобавитьТребуемуюТаблицуКакСсылочныйТип, -// ДобавитьТребуемыйПредопределенныйЭлемент, ДобавитьТребуемоеПолеТаблицы. -// -Функция СвойстваИмениТаблицы(Контекст, ПолноеИмя) - - Если ЗначениеЗаполнено(ПолноеИмя) Тогда - Таблица = ПолноеИмя; - Иначе - Таблица = Контекст.ОсновнаяТаблица; - КонецЕсли; - - СоставИмени = СтрРазделить(Таблица, ".", Ложь); - - Свойства = Новый Структура; - Свойства.Вставить("ЧислоЧастейИмени", СоставИмени.Количество()); - Свойства.Вставить("ИмяТипа", СоставИмени[0]); - Свойства.Вставить("ИмяБезТипа", ?(СоставИмени.Количество() > 1, СоставИмени[1], Неопределено)); - Свойства.Вставить("Расширение", ?(СоставИмени.Количество() = 3, СоставИмени[2], Неопределено)); - Свойства.Вставить("ЭтоОсновнаяТаблица", ВРег(Таблица) = ВРег(Контекст.ОсновнаяТаблица)); - Свойства.Вставить("СвойстваТипаТаблиц", - Контекст.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0]))); - - Возврат Свойства; - -КонецФункции - -// Для процедур ДобавитьТребуемуюТаблицуКакИсточникДанных, ДобавитьТребуемуюТаблицуКакСсылочныйТип, -// ДобавитьТребуемыйПредопределенныйЭлемент, ДобавитьТребуемоеПолеТаблицы. -// -Функция СвойстваТребуемойТаблицы(Контекст, СвойстваИмени, БезРасширения = Ложь) - - ИмяКоллекции = СвойстваИмени.СвойстваТипаТаблиц.ИмяКоллекции; - - СоставКоллекции = Контекст.ПоляТаблиц.Получить(ИмяКоллекции); - Если СоставКоллекции = Неопределено Тогда - СоставКоллекции = НовыйСоставКоллекции(); - Контекст.ПоляТаблиц.Вставить(ИмяКоллекции, СоставКоллекции); - КонецЕсли; - - Свойства = СоставКоллекции.Получить(ВРег(СвойстваИмени.ИмяБезТипа)); - Если Свойства = Неопределено Тогда - Свойства = НовыеСвойстваТаблицы(); - Свойства.Вставить("ТаблицаСуществует", Ложь); - Свойства.Вставить("ЭтоОсновнаяТаблица", СвойстваИмени.ЭтоОсновнаяТаблица); - Свойства.Вставить("Источники", Новый Массив); - Свойства.Вставить("Поля", Новый Соответствие); - Свойства.Вставить("Предопределенные", Новый Соответствие); - Свойства.Вставить("Расширения", Новый Соответствие); - Если СвойстваИмени.ЭтоОсновнаяТаблица И СвойстваИмени.Расширение = Неопределено Тогда - Свойства.Вставить("ПервоеПоле"); - КонецЕсли; - СоставКоллекции.Вставить(ВРег(СвойстваИмени.ИмяБезТипа), Свойства); - КонецЕсли; - - Если СвойстваИмени.Расширение = Неопределено Или БезРасширения Тогда - Возврат Свойства; - КонецЕсли; - - СвойстваРасширения = Свойства.Расширения.Получить(ВРег(СвойстваИмени.Расширение)); - Если СвойстваРасширения = Неопределено Тогда - СвойстваРасширения = НовыеСвойстваРасширения(); - СвойстваРасширения.Вставить("ТаблицаСуществует", Ложь); - СвойстваРасширения.Вставить("Источники", Новый Массив); - СвойстваРасширения.Вставить("Поля", Новый Соответствие); - Если СвойстваИмени.ЭтоОсновнаяТаблица Тогда - СвойстваРасширения.Вставить("ПервоеПоле"); - КонецЕсли; - Свойства.Расширения.Вставить(ВРег(СвойстваИмени.Расширение), СвойстваРасширения); - КонецЕсли; - - Возврат СвойстваРасширения; - -КонецФункции - -// Для процедур и функций ЧастиОграничения, РазобратьДополнительныеТаблицы, РазобратьСоединение, -// РазобратьУсловиеОграничения, ВыраженияВыборКогдаТогдаВоВложениях. -// -Функция ПодставитьКлючевыеСловаВСтроку(Контекст, Строка, СписокСлов, ПараметрОдин = "", ПараметрДва = "", ПараметрТри = "") - - Слова = СтрРазделить(СписокСлов, ",", Ложь); - СловаДляПодстановки = Новый Соответствие; - - Для Каждого Слово Из Слова Цикл - СловаДляПодстановки.Вставить(Слова.Найти(Слово), - КлючевоеСловоСУчетомЯзыка(СокрЛП(Слово), Контекст)); - КонецЦикла; - - Индекс = СловаДляПодстановки.Количество(); - СловаДляПодстановки.Вставить(Индекс, ПараметрОдин); - СловаДляПодстановки.Вставить(Индекс + 1, ПараметрДва); - СловаДляПодстановки.Вставить(Индекс + 2, ПараметрТри); - - Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Строка, - СловаДляПодстановки[0], СловаДляПодстановки[1], СловаДляПодстановки[2], - СловаДляПодстановки[3], СловаДляПодстановки[4], СловаДляПодстановки[5], - СловаДляПодстановки[6], СловаДляПодстановки[7], СловаДляПодстановки[8]); - -КонецФункции - -// Для процедур РазобратьДополнительныеТаблицы, РазобратьСоединение, РазобратьУсловиеОграничения. -Функция КлючевоеСловоСУчетомЯзыка(ИдентификаторСлова, Контекст) - - СвойстваСлова = Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(ИдентификаторСлова)); - - Если ВариантВстроенногоЯзыкаРусский() Тогда - Слово = СвойстваСлова.ЯзыкРусский; - Иначе - Слово = СвойстваСлова.ЯзыкАнглийский; - КонецЕсли; - - Если СвойстваСлова.ВерхнийРегистр Тогда - Слово = ВРег(Слово); - КонецЕсли; - - Возврат Слово; - -КонецФункции - -#КонецОбласти - -#Область АнализИменТаблицИПолейТаблиц - -// Проверка таблиц, полей таблиц и типов полей, найденных при разборе текста ограничения. -// Аналогичная процедура реализуется в СППР. -// -// Параметры: -// РазобранноеОграничение - см. РазобранноеОграничение -// -Процедура ПроверитьТаблицыПоляИТипыПолей(РазобранноеОграничение) - - Контекст = Новый Структура; - Контекст.Вставить("ТипыТаблиц", УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц); - - Для Каждого ТипТаблиц Из РазобранноеОграничение.ПоляТаблиц Цикл - КоллекцияТаблиц = Метаданные[ТипТаблиц.Ключ]; // КоллекцияОбъектовМетаданных - - Для Каждого ПоляТаблицы Из ТипТаблиц.Значение Цикл - - МетаданныеТаблицы = КоллекцияТаблиц.Найти(ПоляТаблицы.Ключ); - Если МетаданныеТаблицы = Неопределено Тогда - Продолжить; - КонецЕсли; - ПоляТаблицы.Значение.ТаблицаСуществует = Истина; - - Контекст.Вставить("МетаданныеТаблицы", МетаданныеТаблицы); - Контекст.Вставить("СвойстваТипаТаблиц", Контекст.ТипыТаблиц.ПоКоллекциям.Получить(ТипТаблиц.Ключ)); - Контекст.Вставить("ЭтоОсновнаяТаблица", ПоляТаблицы.Значение.ЭтоОсновнаяТаблица); - - Для Каждого ПолеТаблицы Из ПоляТаблицы.Значение.Поля Цикл - ОписаниеПоля = Новый Структура; - ОписаниеПоля.Вставить("СоставИмени", СтрРазделить(ПолеТаблицы.Ключ, ".")); - ОписаниеПоля.Вставить("Свойства", ПолеТаблицы.Значение); - ОписаниеПоля.Вставить("ТипПоля", Новый ОписаниеТипов); - ПроверитьПолеТаблицы(ОписаниеПоля, Контекст); - Если ОписаниеПоля.Свойства.ПолеСОшибкой = 0 Тогда - ПроверитьТипыПоля(ОписаниеПоля, Контекст); - КонецЕсли; - КонецЦикла; - - ПроверитьРасширенияТаблицы(ПоляТаблицы, Контекст); - ПроверитьПредопределенныеЗначенияТаблицы(ПоляТаблицы, Контекст); - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедур ПроверитьТаблицыПоляИТипыПолей, ПроверитьСледующееПолеЧерезТочку. -Процедура ПроверитьПолеТаблицы(ОписаниеПоля, Контекст, Индекс = 0, ПервыйВызов = Истина) - - СоставИмени = ОписаниеПоля.СоставИмени; - СвойстваПоля = ОписаниеПоля.Свойства; - - УточнениеПоля = Контекст.СвойстваТипаТаблиц.УточнениеПолей.Получить(ВРег(СоставИмени[Индекс])); - - Если УточнениеПоля <> Неопределено - И УточнениеПоля.Использование <> "Разрешено" Тогда - - СвойстваПоля.ПолеСОшибкой = Индекс + 1; - СвойстваПоля.ВидОшибки = УточнениеПоля; - Возврат; - КонецЕсли; - - Свойства = СвойстваПоляИлиТабличнойЧасти(СоставИмени[Индекс], Контекст, Индекс = 0); - Если Свойства = Неопределено Тогда - СвойстваПоля.ПолеСОшибкой = Индекс + 1; - СвойстваПоля.ВидОшибки = "НеНайдено"; - Возврат; - КонецЕсли; - Если Индекс = 0 Тогда - СвойстваПоля.Коллекция = Свойства.Коллекция; - КонецЕсли; - - Если Свойства.ЭтоТабличнаяЧасть Тогда - Если Индекс > 0 Тогда - СвойстваПоля.ПолеСОшибкой = Индекс + 1; - СвойстваПоля.ВидОшибки = "ТабличнаяЧастьПослеТочки"; - Возврат; - КонецЕсли; - Если Не Контекст.ЭтоОсновнаяТаблица Тогда - СвойстваПоля.ПолеСОшибкой = Индекс + 1; - СвойстваПоля.ВидОшибки = "ТабличнаяЧастьДополнительнойТаблицы"; - Возврат; - КонецЕсли; - Если Индекс + 1 = СоставИмени.Количество() Тогда - СвойстваПоля.ПолеСОшибкой = Индекс + 1; - СвойстваПоля.ВидОшибки = "ТабличнаяЧастьБезПоля"; - Возврат; - КонецЕсли; - Индекс = Индекс + 1; - Свойства = СвойстваПоляТабличнойЧасти(СоставИмени[Индекс], - Свойства.Метаданные, Свойства.Коллекция, Контекст.МетаданныеТаблицы); - Если Свойства = Неопределено Тогда - СвойстваПоля.ПолеСОшибкой = Индекс + 1; - СвойстваПоля.ВидОшибки = "НеНайдено"; - Возврат; - КонецЕсли; - КонецЕсли; - - ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, Свойства, Контекст); - - Если ПервыйВызов Тогда - ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля); - КонецЕсли; - -КонецПроцедуры - -// Для процедур ПроверитьПолеТаблицы и ПроверитьРасширенияТаблицы. -Процедура ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст) - - ДобавитьТипыПоляДополнительно(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст); - - Индекс = Индекс + 1; - Если Индекс = ОписаниеПоля.СоставИмени.Количество() Тогда - ОписаниеПоля.ТипПоля = Новый ОписаниеТипов(ОписаниеПоля.ТипПоля, СвойстваТекущегоПоля.Тип.Типы()); - Возврат; - КонецЕсли; - - СвойстваПоля = ОписаниеПоля.Свойства; - ПолеНайдено = Ложь; - - Если ОписаниеПоля.Свойство("ТаблицыСледующегоПоля") Тогда - // См. процедуру ДобавитьТипыПоляДополнительно. - Если ОписаниеПоля.ТаблицыСледующегоПоля.Количество() < Индекс + 1 Тогда - ТаблицыСледующегоПоля = Новый Массив; - ОписаниеПоля.ТаблицыСледующегоПоля.Добавить(ТаблицыСледующегоПоля); - Иначе - ТаблицыСледующегоПоля = ОписаниеПоля.ТаблицыСледующегоПоля[Индекс]; - КонецЕсли; - КонецЕсли; - - Для Каждого Тип Из СвойстваТекущегоПоля.Тип.Типы() Цикл - Если Не ОбщегоНазначения.ЭтоСсылка(Тип) Тогда - Продолжить; - КонецЕсли; - СвойстваПоля.ПолеСОшибкой = 0; - СвойстваПоля.ВидОшибки = ""; - - // Сохранение текущего контекста. - ТекущиеМетаданныеТаблицы = Контекст.МетаданныеТаблицы; - ТекущиеСвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; - - Контекст.МетаданныеТаблицы = Метаданные.НайтиПоТипу(Тип); - ПолноеИмя = Контекст.МетаданныеТаблицы.ПолноеИмя(); - СоставПолногоИмени = СтрРазделить(ПолноеИмя, ".", Ложь); - Контекст.СвойстваТипаТаблиц = Контекст.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставПолногоИмени[0])); - - ТекущийИндекс = Индекс; - ПроверитьПолеТаблицы(ОписаниеПоля, Контекст, ТекущийИндекс, Ложь); - - // Восстановление текущего контекста. - Контекст.МетаданныеТаблицы = ТекущиеМетаданныеТаблицы; - Контекст.СвойстваТипаТаблиц = ТекущиеСвойстваТипаТаблиц; - - Если СвойстваПоля.ПолеСОшибкой = 0 Тогда - ПолеНайдено = Истина; - Если ТаблицыСледующегоПоля <> Неопределено Тогда - // См. процедуру ДобавитьТипыПоляДополнительно. - ТаблицыСледующегоПоля.Добавить(ПолноеИмя); - КонецЕсли; - ИначеЕсли СвойстваПоля.ВидОшибки <> "НеНайдено" Тогда - Возврат; - КонецЕсли; - КонецЦикла; - - Если ПолеНайдено Тогда - СвойстваПоля.ПолеСОшибкой = 0; - СвойстваПоля.ВидОшибки = ""; - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПроверитьПолеТаблицы. -Функция СвойстваПоляИлиТабличнойЧасти(ИмяПоляИлиТабличнойЧасти, Контекст, ЭтоПервоеПоле) - - Результат = Новый Структура; - Результат.Вставить("ЭтоТабличнаяЧасть", Ложь); - Результат.Вставить("Коллекция"); - Результат.Вставить("Метаданные"); - Результат.Вставить("Тип"); - - МетаданныеТаблицы = Контекст.МетаданныеТаблицы; - СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; - - Для Каждого КоллекцияТабличныхЧастей Из СвойстваТипаТаблиц.КоллекцииТабличныхЧастей Цикл - Если КоллекцияТабличныхЧастей.Ключ = "СтандартныеТабличныеЧасти" Тогда - СтандартныеТабличныеЧасти = МетаданныеТаблицы.СтандартныеТабличныеЧасти; // ОписанияСтандартныхТабличныхЧастей - Для Каждого СтандартнаяТабличнаяЧасть Из СтандартныеТабличныеЧасти Цикл - Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег(СтандартнаяТабличнаяЧасть.Имя) Тогда - Результат.Метаданные = СтандартнаяТабличнаяЧасть; - Прервать; - КонецЕсли; - КонецЦикла; - Иначе - Результат.Метаданные = МетаданныеТаблицы[КоллекцияТабличныхЧастей.Ключ].Найти(ИмяПоляИлиТабличнойЧасти); - КонецЕсли; - Если Результат.Метаданные <> Неопределено Тогда - Результат.ЭтоТабличнаяЧасть = Истина; - Результат.Коллекция = КоллекцияТабличныхЧастей.Ключ; - Возврат Результат; - КонецЕсли; - КонецЦикла; - - Для Каждого КоллекцияПолей Из СвойстваТипаТаблиц.КоллекцииПолей Цикл - Если КоллекцияПолей.Ключ = "СтандартныеРеквизиты" Тогда - Номер = 0; - СтандартныеРеквизиты = МетаданныеТаблицы.СтандартныеРеквизиты; // ОписанияСтандартныхРеквизитов - Для Каждого СтандартныйРеквизит Из СтандартныеРеквизиты Цикл - Номер = Номер + 1; - Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда - Результат.Метаданные = СтандартныйРеквизит; - Прервать; - КонецЕсли; - КонецЦикла; - Иначе - Результат.Метаданные = МетаданныеТаблицы[КоллекцияПолей.Ключ].Найти(ИмяПоляИлиТабличнойЧасти); - КонецЕсли; - Если Результат.Метаданные <> Неопределено Тогда - Результат.Коллекция = КоллекцияПолей.Ключ; - Если Результат.Коллекция = "Графы" Тогда - Результат.Тип = Новый ОписаниеТипов; - МетаданныеГрафыЖурнала = Результат.Метаданные; // ОбъектМетаданныхГрафа - Для Каждого МетаданныеСсылки Из МетаданныеГрафыЖурнала.Ссылки Цикл - Результат.Тип = Новый ОписаниеТипов(Результат.Тип, МетаданныеСсылки.Тип.Типы()); - КонецЦикла; - Иначе - Результат.Тип = Результат.Метаданные.Тип; - КонецЕсли; - Возврат Результат; - КонецЕсли; - КонецЦикла; - - Если СвойстваТипаТаблиц.ОбщиеРеквизиты <> "Отсутствуют" Тогда - Результат.Метаданные = Метаданные.ОбщиеРеквизиты.Найти(ИмяПоляИлиТабличнойЧасти); - Если Результат.Метаданные <> Неопределено Тогда - Результат.Коллекция = "ОбщиеРеквизиты"; - Результат.Тип = Результат.Метаданные.Тип; - Возврат Результат; - КонецЕсли; - КонецЕсли; - - Если СвойстваТипаТаблиц.ИмяКоллекции = "Константы" Тогда - - Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Значение") - Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Value") Тогда - - Результат.Коллекция = "СпециальныеПоля"; - Результат.Тип = МетаданныеТаблицы.Тип; - Результат.Вставить("ОсновнойПорядок", "001"); // См. процедуру ДобавитьОсновнойПорядокПоля. - Возврат Результат; - КонецЕсли; - - ИначеЕсли СвойстваТипаТаблиц.ИмяКоллекции = "Последовательности" Тогда - - Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Период") - Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Period") Тогда - - Результат.Коллекция = "СпециальныеПоля"; - Результат.Тип = Новый ОписаниеТипов("Дата"); - Результат.Вставить("ОсновнойПорядок", "001"); // См. процедуру ДобавитьОсновнойПорядокПоля. - Возврат Результат; - КонецЕсли; - - Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Регистратор") - Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Recorder") Тогда - - Результат.Коллекция = "СпециальныеПоля"; - Результат.Тип = Новый ОписаниеТипов; - МетаданныеПоследовательности = МетаданныеТаблицы; // ОбъектМетаданныхПоследовательность - Для Каждого ДокументМетаданные Из МетаданныеПоследовательности.Документы Цикл - Результат.Тип = Новый ОписаниеТипов(Результат.Тип, "ДокументСсылка." + ДокументМетаданные.Имя); - КонецЦикла; - Результат.Вставить("ОсновнойПорядок", "002"); // См. процедуру ДобавитьОсновнойПорядокПоля. - Возврат Результат; - КонецЕсли; - КонецЕсли; - - Возврат Неопределено; - -КонецФункции - -// Для процедур ПроверитьРасширенияТаблицы, ПроверитьПолеТаблицы. -Функция СвойстваПоляТабличнойЧасти(ИмяПоляТабличнойЧасти, МетаданныеТабличнойЧасти, ИмяКоллекции, МетаданныеТаблицы) - - Результат = Новый Структура; - Результат.Вставить("Тип"); - Результат.Вставить("ИмяТабличнойЧасти", МетаданныеТабличнойЧасти.Имя); - - Если ВРег(ИмяПоляТабличнойЧасти) = ВРег("Ссылка") - Или ВРег(ИмяПоляТабличнойЧасти) = ВРег("Ref") Тогда - - Для Каждого СтандартныйРеквизит Из МетаданныеТаблицы.СтандартныеРеквизиты Цикл - Если ВРег(ИмяПоляТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда - Результат.Тип = СтандартныйРеквизит.Тип; - Возврат Результат; - КонецЕсли; - КонецЦикла; - КонецЕсли; - - Для Каждого СтандартныйРеквизит Из МетаданныеТабличнойЧасти.СтандартныеРеквизиты Цикл - Если ВРег(ИмяПоляТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда - Результат.Тип = СтандартныйРеквизит.Тип; - Возврат Результат; - КонецЕсли; - КонецЦикла; - - Если ИмяКоллекции = "ТабличныеЧасти" Тогда - МетаданныеПоля = МетаданныеТабличнойЧасти.Реквизиты.Найти(ИмяПоляТабличнойЧасти); - Если МетаданныеПоля <> Неопределено Тогда - Результат.Тип = МетаданныеПоля.Тип; - Результат.Вставить("МетаданныеТабличнойЧасти", МетаданныеТабличнойЧасти); - Возврат Результат; - КонецЕсли; - КонецЕсли; - - Возврат Неопределено; - -КонецФункции - -// Для процедур ПроверитьРасширенияТаблицы, ПроверитьПолеТаблицы. -Функция СвойстваПоляПерерасчета(ИмяПоляПерерасчета, МетаданныеПерерасчета, МетаданныеТаблицы) - - Результат = Новый Структура; - Результат.Вставить("Тип"); - Результат.Вставить("Коллекция"); - Результат.Вставить("Метаданные"); - - Если ВРег(ИмяПоляПерерасчета) = ВРег("ОбъектПерерасчета") - Или ВРег(ИмяПоляПерерасчета) = ВРег("RecalculationObject") Тогда - - ИмяПоля = "Регистратор"; - - ИначеЕсли ВРег(ИмяПоляПерерасчета) = ВРег("ВидРасчета") - Или ВРег(ИмяПоляПерерасчета) = ВРег("CalculationType") Тогда - - ИмяПоля = "ВидРасчета"; - КонецЕсли; - - МетаданныеРегистра = МетаданныеТаблицы; // ОбъектМетаданныхРегистрРасчета - Если ЗначениеЗаполнено(ИмяПоля) Тогда - Для Каждого СтандартныйРеквизит Из МетаданныеРегистра.СтандартныеРеквизиты Цикл - Если ВРег(ИмяПоля) = ВРег(СтандартныйРеквизит.Имя) Тогда - Результат.Коллекция = "СтандартныеРеквизиты"; - Результат.Метаданные = СтандартныйРеквизит; - Результат.Тип = СтандартныйРеквизит.Тип; - Возврат Результат; - КонецЕсли; - КонецЦикла; - Возврат Неопределено; - КонецЕсли; - - МетаданныеПоля = МетаданныеПерерасчета.Измерения.Найти(ИмяПоляПерерасчета); - Если МетаданныеПоля <> Неопределено Тогда - Результат.Тип = МетаданныеПоля.ИзмерениеРегистра.Тип; - Результат.Коллекция = "СпециальныеПоля"; - Номер = 200 + МетаданныеРегистра.Измерения.Индекс(МетаданныеПоля) + 1; - Результат.Вставить("ОсновнойПорядок", Номер); // См. процедуру ДобавитьОсновнойПорядокПоля. - Возврат Результат; - КонецЕсли; - - Возврат Неопределено; - -КонецФункции - -// Для процедуры ПроверитьПолеТаблицы. -Процедура ДобавитьТипыПоляДополнительно(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст) - - // Дополнительный сбор типов для использования в служебных процедурах. - - // Расширение свойств узла Поле для использования в служебных процедурах. - Если Индекс = 0 Или Индекс = 1 И СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда - Если ОписаниеПоля.СоставИмени.Количество() > 1 Тогда - ОписаниеПоля.Вставить("ТаблицыСледующегоПоля", Новый Массив); - Если Индекс = 1 Тогда - ОписаниеПоля.ТаблицыСледующегоПоля.Добавить(Неопределено); - КонецЕсли; - КонецЕсли; - Если Индекс = 0 И Не Контекст.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда - ДобавитьОсновнойПорядокПоля(СвойстваТекущегоПоля, Контекст); - КонецЕсли; - КонецЕсли; - - Для Каждого УзелПоле Из ОписаниеПоля.Свойства.УзлыПоле Цикл - Если СвойстваТекущегоПоля.Свойство("ОсновнойПорядок") - И Не УзелПоле.Свойство("ОсновнойПорядок") Тогда - УзелПоле.Вставить("ОсновнойПорядок", СвойстваТекущегоПоля.ОсновнойПорядок); - КонецЕсли; - Если ОписаниеПоля.Свойство("ТаблицыСледующегоПоля") - И Не УзелПоле.Свойство("ТаблицыСледующегоПоля") Тогда - УзелПоле.Вставить("ТаблицыСледующегоПоля", ОписаниеПоля.ТаблицыСледующегоПоля); - КонецЕсли; - Если Не УзелПоле.Свойство("ТипыПоля") Тогда - УзелПоле.Вставить("ТипыПоля", Новый Массив); - УстановитьПолеСодержитNull(УзелПоле, СвойстваТекущегоПоля, Контекст); - КонецЕсли; - Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") - И ВРег(СвойстваТекущегоПоля.ИмяТабличнойЧасти) = ВРег(ОписаниеПоля.СоставИмени[0]) Тогда - - УзелПоле.ТипыПоля.Добавить(СвойстваТекущегоПоля.ИмяТабличнойЧасти); - КонецЕсли; - Если Индекс > УзелПоле.ТипыПоля.Количество() - 1 Тогда - УзелПоле.ТипыПоля.Добавить(СвойстваТекущегоПоля.Тип); - КонецЕсли; - УзелПоле.ТипыПоля[Индекс] = Новый ОписаниеТипов(УзелПоле.ТипыПоля[Индекс], - СвойстваТекущегоПоля.Тип.Типы()); - КонецЦикла; - - // Добавление типов поля строкой для проверки изменения в служебных процедурах. - ПолноеИмяПоля = Контекст.СвойстваТипаТаблиц.ЯзыкРусский + "." + ВРег(Контекст.МетаданныеТаблицы.Имя); - - Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда - ПолноеИмяПоля = ПолноеИмяПоля + "." + ВРег(СвойстваТекущегоПоля.ИмяТабличнойЧасти); - КонецЕсли; - - ПолноеИмяПоля = ПолноеИмяПоля + "." + ОписаниеПоля.СоставИмени[Индекс]; - - Если Не ОписаниеПоля.Свойство("ВсеПоля") Тогда - ОписаниеПоля.Вставить("ВсеПоля", Новый Соответствие); - ОписаниеПоля.Вставить("ТипыВсехПолей", Новый СписокЗначений); - КонецЕсли; - Если ОписаниеПоля.ВсеПоля.Получить(ПолноеИмяПоля) <> Неопределено Тогда - Возврат; - КонецЕсли; - ОписаниеПоля.ВсеПоля.Вставить(ПолноеИмяПоля, Истина); - - ТипыСтрокой = СтрокаДанныхДляХеширования(СвойстваТекущегоПоля.Тип); - ОписаниеПоля.ТипыВсехПолей.Добавить(ТипыСтрокой, ПолноеИмяПоля); - -КонецПроцедуры - -// Для процедуры ПроверитьПолеТаблицы. -Процедура ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля) - - Если ОписаниеПоля.ТипыВсехПолей.Количество() > 1 Тогда - ОписаниеПоля.ТипыВсехПолей.СортироватьПоПредставлению(); - КонецЕсли; - ТипыСтрокой = СтрСоединить(ОписаниеПоля.ТипыВсехПолей.ВыгрузитьЗначения(), Символы.ПС); - УзлыПоле = ОписаниеПоля.Свойства.УзлыПоле; - - Для Каждого УзелПоле Из УзлыПоле Цикл - УзелПоле.Вставить("ТипыСтрокой", ТипыСтрокой); - КонецЦикла; - - ОписаниеПоля.Удалить("ВсеПоля"); - ОписаниеПоля.Удалить("ТипыВсехПолей"); - -КонецПроцедуры - -// Для процедуры ДобавитьТипыПоляДополнительно. -Процедура ДобавитьОсновнойПорядокПоля(СвойстваТекущегоПоля, Контекст) - - Если СвойстваТекущегоПоля.Коллекция = "СпециальныеПоля" Тогда - Возврат; // Установлен в функции СвойстваПоляИлиТабличнойЧасти. - КонецЕсли; - - МетаданныеТаблицы = Контекст.МетаданныеТаблицы; // ОбъектМетаданныхРегистрСведений - МетаданныеПоля = СвойстваТекущегоПоля.Метаданные; - - Если СвойстваТекущегоПоля.Коллекция = "СтандартныеРеквизиты" Тогда - Индекс = 0; - Для Каждого СтандартныйРеквизит Из МетаданныеТаблицы.СтандартныеРеквизиты Цикл - Если СтандартныйРеквизит = МетаданныеПоля Тогда - Прервать; - КонецЕсли; - Индекс = Индекс + 1; - КонецЦикла; - Номер = 100 + Индекс + 1; - - ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Измерения" Тогда - Номер = 200 + МетаданныеТаблицы.Измерения.Индекс(МетаданныеПоля) + 1; - - ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Ресурсы" Тогда - Номер = 300 + МетаданныеТаблицы.Ресурсы.Индекс(МетаданныеПоля) + 1; - - ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Реквизиты" Тогда - Номер = 400 + МетаданныеТаблицы.Реквизиты.Индекс(МетаданныеПоля) + 1; - - ИначеЕсли СвойстваТекущегоПоля.Коллекция = "ОбщиеРеквизиты" Тогда - Номер = 500 + Метаданные.ОбщиеРеквизиты.Индекс(МетаданныеПоля) + 1; - КонецЕсли; - - СвойстваТекущегоПоля.Вставить("ОсновнойПорядок", Строка(Номер)); - -КонецПроцедуры - -// Для процедуры ДобавитьТипыПоляДополнительно. -Процедура УстановитьПолеСодержитNull(УзелПоле, СвойстваТекущегоПоля, Контекст) - - Если Контекст.СвойстваТипаТаблиц.ИмяКоллекции <> "Справочники" - И Контекст.СвойстваТипаТаблиц.ИмяКоллекции <> "ПланыВидовХарактеристик" - Или Не Контекст.МетаданныеТаблицы.Иерархический Тогда - - Возврат; - КонецЕсли; - - Если Контекст.СвойстваТипаТаблиц.ИмяКоллекции = "Справочники" - И Контекст.МетаданныеТаблицы.ВидИерархии - <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда - - Возврат; - КонецЕсли; - - Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда - Если СвойстваТекущегоПоля.Свойство("МетаданныеТабличнойЧасти") - И СвойстваТекущегоПоля.МетаданныеТабличнойЧасти.Использование - <> Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда - - УзелПоле.Вставить("ПолеСодержитNull"); - КонецЕсли; - - Возврат; - КонецЕсли; - - Если СвойстваТекущегоПоля.Коллекция = "Реквизиты" - И СвойстваТекущегоПоля.Метаданные.Использование - <> Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда - - УзелПоле.Вставить("ПолеСодержитNull"); - КонецЕсли; - -КонецПроцедуры - -// Для процедуры ПроверитьТаблицыПоляИТипыПолей. -Процедура ПроверитьРасширенияТаблицы(ПоляТаблицы, Контекст) - - СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; - - Если СвойстваТипаТаблиц.КоллекцииТабличныхЧастей.Количество() = 0 - И СвойстваТипаТаблиц.ИмяКоллекции <> "РегистрыРасчета" Тогда - Возврат; - КонецЕсли; - - МетаданныеТаблицы = Контекст.МетаданныеТаблицы; - - Для Каждого РасширениеТаблицы Из ПоляТаблицы.Значение.Расширения Цикл - - Если СвойстваТипаТаблиц.ИмяКоллекции = "РегистрыРасчета" Тогда - МетаданныеРасширения = МетаданныеТаблицы.Перерасчеты.Найти(РасширениеТаблицы.Ключ); - Иначе - Для Каждого КоллекцияТабличныхЧастей Из СвойстваТипаТаблиц.КоллекцииТабличныхЧастей Цикл - Если КоллекцияТабличныхЧастей.Ключ = "СтандартныеТабличныеЧасти" Тогда - СтандартныеТабличныеЧасти = МетаданныеТаблицы.СтандартныеТабличныеЧасти; // ОписанияСтандартныхТабличныхЧастей - Для Каждого СтандартнаяТабличнаяЧасть Из СтандартныеТабличныеЧасти Цикл - Если ВРег(РасширениеТаблицы.Ключ) = ВРег(СтандартнаяТабличнаяЧасть.Имя) Тогда - МетаданныеРасширения = СтандартнаяТабличнаяЧасть; - Прервать; - КонецЕсли; - КонецЦикла; - Иначе - МетаданныеРасширения = МетаданныеТаблицы[КоллекцияТабличныхЧастей.Ключ].Найти(РасширениеТаблицы.Ключ); - КонецЕсли; - Если МетаданныеРасширения <> Неопределено Тогда - Прервать; - КонецЕсли; - КонецЦикла; - КонецЕсли; - Если МетаданныеРасширения = Неопределено Тогда - Продолжить; - КонецЕсли; - РасширениеТаблицы.Значение.ТаблицаСуществует = Истина; - - Для Каждого ПолеТаблицы Из РасширениеТаблицы.Значение.Поля Цикл - ОписаниеПоля = Новый Структура; - ОписаниеПоля.Вставить("СоставИмени", СтрРазделить(ПолеТаблицы.Ключ, ".")); - ОписаниеПоля.Вставить("Свойства", ПолеТаблицы.Значение); - ОписаниеПоля.Вставить("ТипПоля", Новый ОписаниеТипов); - - Индекс = 0; - Если СвойстваТипаТаблиц.ИмяКоллекции = "РегистрыРасчета" Тогда - СвойстваПоля = СвойстваПоляПерерасчета(ОписаниеПоля.СоставИмени[Индекс], - МетаданныеРасширения, МетаданныеТаблицы); - Иначе - СвойстваПоля = СвойстваПоляТабличнойЧасти(ОписаниеПоля.СоставИмени[Индекс], - МетаданныеРасширения, КоллекцияТабличныхЧастей.Ключ, МетаданныеТаблицы); - КонецЕсли; - - Если СвойстваПоля = Неопределено Тогда - ОписаниеПоля.Свойства.ПолеСОшибкой = Индекс + 1; - ОписаниеПоля.Свойства.ВидОшибки = "НеНайдено"; - Продолжить; - КонецЕсли; - ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, СвойстваПоля, Контекст); - ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля); - Если ОписаниеПоля.Свойства.ПолеСОшибкой = 0 Тогда - ПроверитьТипыПоля(ОписаниеПоля, Контекст); - КонецЕсли; - КонецЦикла; - - КонецЦикла; - -КонецПроцедуры - -// Для процедур ПроверитьТаблицыПоляИТипыПолей и ПроверитьРасширенияТаблицы. -Процедура ПроверитьТипыПоля(ОписаниеПоля, Контекст) - - ОписаниеТиповПоля = ОписаниеПоля.ТипПоля; - - Для Каждого ОписаниеТипа Из ОписаниеПоля.Свойства.СодержитТипы Цикл - СвойстваТипа = ОписаниеТипа.Значение; - Если ЗначениеЗаполнено(СвойстваТипа.ИмяКоллекцииТипа) - И Метаданные[СвойстваТипа.ИмяКоллекцииТипа].Найти(СвойстваТипа.ИмяОбъектаКоллекцииТипа) = Неопределено Тогда - Продолжить; - КонецЕсли; - Тип = Тип(ОписаниеТипа.Значение.ИмяТипа); - СвойстваТипа.СодержитТип = ОписаниеТиповПоля.СодержитТип(Тип); - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ПроверитьТаблицыПоляИТипыПолей. -// -// Параметры: -// ПоляТаблицы - см. НовыйСоставКоллекции -// -Процедура ПроверитьПредопределенныеЗначенияТаблицы(ПоляТаблицы, Контекст) - - СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; - - СвойстваТаблицы = ПоляТаблицы.Значение; // см. НовыеСвойстваТаблицы - Если СвойстваТаблицы.Предопределенные.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - Если СвойстваТипаТаблиц.ЕстьПредопределенные Тогда - МетаданныеТаблицы = Контекст.МетаданныеТаблицы; - - Если СвойстваТипаТаблиц.ИмяКоллекции = "Перечисления" Тогда - ИменаПредопределенных = Новый Массив; - Для Каждого ЗначениеПеречисления Из МетаданныеТаблицы.ЗначенияПеречисления Цикл - ТекущееЗначениеПеречисления = ЗначениеПеречисления; // ОбъектМетаданныхЗначениеПеречисления - ИменаПредопределенных.Добавить(ТекущееЗначениеПеречисления.Имя); - КонецЦикла; - Иначе - ИменаПредопределенных = Новый Массив(МетаданныеТаблицы.ПолучитьИменаПредопределенных()); - КонецЕсли; - Иначе - ИменаПредопределенных = Новый Массив; - КонецЕсли; - - ИменаПредопределенных.Добавить("ПустаяСсылка"); - ИменаПредопределенных.Добавить("EmptyRef"); - - Для Каждого Предопределенный Из СвойстваТаблицы.Предопределенные Цикл - Для Каждого ИмяПредопределенного Из ИменаПредопределенных Цикл - Если ВРег(ИмяПредопределенного) = Предопределенный.Ключ Тогда - Предопределенный.Значение.ИмяСуществует = Истина; - Прервать; - КонецЕсли; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - - -// Для функции СтруктураОграничения. -Процедура ОтметитьНекорректныеИменаТаблицПолейИТиповПолей(ПоляТаблиц, Контекст) - - Для Каждого ТипТаблиц Из ПоляТаблиц Цикл - Для Каждого ОписаниеТаблицы Из ТипТаблиц.Значение Цикл - СвойстваТаблицы = ОписаниеТаблицы.Значение; // см. НовыеСвойстваТаблицы - - Если Не СвойстваТаблицы.ТаблицаСуществует Тогда - Для Каждого Источник Из СвойстваТаблицы.Источники Цикл - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует таблица ""%1""'"), Источник.Символы), , 2); - КонецЦикла; - Если СвойстваТаблицы.Свойство("ПервоеПоле") - И СвойстваТаблицы.ПервоеПоле.ПервыйИсточник <> Неопределено Тогда - - УстановитьОшибкуВСтрокеИмениПоля(Контекст, СвойстваТаблицы.ПервоеПоле.ПервыйИсточник.Ключ, - НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , - СвойстваТаблицы.ПервоеПоле.ПервыйИсточник.Значение); - КонецЕсли; - Для Каждого ОписаниеПредопределенного Из СвойстваТаблицы.Предопределенные Цикл - Для Каждого Источник Из ОписаниеПредопределенного.Значение.Источники Цикл - СоставИмени = СтрРазделить(Источник.Символы, "."); - - УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Предопределенное значение не существует, так как указана несуществующая таблица ""%1""'"), - СоставИмени[0] + "." + СоставИмени[1]), , 2); - КонецЦикла; - КонецЦикла; - Продолжить; - КонецЕсли; - - Для Каждого ОписаниеПредопределенного Из СвойстваТаблицы.Предопределенные Цикл - СвойстваПредопределенного = ОписаниеПредопределенного.Значение; - Если СвойстваПредопределенного.ИмяСуществует Тогда - Продолжить; - КонецЕсли; - Для Каждого Источник Из СвойстваПредопределенного.Источники Цикл - СоставИмени = СтрРазделить(Источник.Символы, "."); - Источник.ПозицияОшибки = СтрДлина(СоставИмени[0] + "." + СоставИмени[1]) + 1; - Источник.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует предопределенное значение ""%1""'"), СоставИмени[2]); - КонецЦикла; - КонецЦикла; - - Для Каждого ОписаниеПоля Из СвойстваТаблицы.Поля Цикл - ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст); - КонецЦикла; - - Для Каждого ОписаниеРасширения Из СвойстваТаблицы.Расширения Цикл - СвойстваРасширения = ОписаниеРасширения.Значение; - Если Не СвойстваРасширения.ТаблицаСуществует Тогда - Для Каждого Источник Из СвойстваРасширения.Источники Цикл - УстановитьОшибкуВСтроке(Источник, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не существует таблица ""%1""'"), Источник.Символы), , 2); - КонецЦикла; - Если СвойстваРасширения.Свойство("ПервоеПоле") - И СвойстваРасширения.ПервоеПоле.ПервыйИсточник <> Неопределено Тогда - - УстановитьОшибкуВСтрокеИмениПоля(Контекст, СвойстваРасширения.ПервоеПоле.ПервыйИсточник.Ключ, - НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , - СвойстваРасширения.ПервоеПоле.ПервыйИсточник.Значение); - КонецЕсли; - Продолжить; - КонецЕсли; - Для Каждого ОписаниеПоля Из СвойстваРасширения.Поля Цикл - ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст); - КонецЦикла; - КонецЦикла; - - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОтметитьНекорректныеИменаТаблицПолейИТиповПолей. -Процедура ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст) - - СвойстваПоля = ОписаниеПоля.Значение; - Если СвойстваПоля.ПолеСОшибкой = 1 Тогда - Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл - ВКонце = Ложь; - Если СвойстваПоля.ВидОшибки = "ТабличнаяЧастьБезПоля" Тогда - ВКонце = Истина; - ШаблонОшибки = НСтр("ru = 'Не указано поле после табличной части ""%1"" таблицы ""%2""'"); - - ИначеЕсли СвойстваПоля.ВидОшибки = "ТабличнаяЧастьДополнительнойТаблицы" Тогда - ШаблонОшибки = НСтр("ru = 'Табличная часть ""%1"" не поддерживается для дополнительной таблицы ""%2""'"); - - ИначеЕсли СвойстваПоля.ВидОшибки = "Недопустимо" Тогда - ШаблонОшибки = НСтр("ru = 'Недопустимо использовать поле ""%1"" таблицы ""%2""'"); - - ИначеЕсли СвойстваПоля.ВидОшибки = "Запрещено" Тогда - ШаблонОшибки = НСтр("ru = 'Запрещено использовать поле ""%1"" таблицы ""%2""'"); - Иначе - ШаблонОшибки = НСтр("ru = 'Не существует поле ""%1"" таблицы ""%2""'"); - КонецЕсли; - УстановитьОшибкуВСтрокеИмениПоля(Контекст, - ОписаниеИсточника.Ключ, ШаблонОшибки, 1, Истина, ОписаниеИсточника.Значение, ВКонце); - КонецЦикла; - Возврат; - КонецЕсли; - - Если СвойстваПоля.ПолеСОшибкой > 1 Тогда - Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл - Если СвойстваПоля.ВидОшибки = "ТабличнаяЧастьПослеТочки" Тогда - ШаблонОшибки = НСтр("ru = 'Табличная часть ""%1"" не поддерживается ""через точку"" от поля'"); - - ИначеЕсли СвойстваПоля.ВидОшибки = "Недопустимо" Тогда - ШаблонОшибки = НСтр("ru = 'Недопустимо использовать поле ""%1""'"); - - ИначеЕсли СвойстваПоля.ВидОшибки = "Запрещено" Тогда - ШаблонОшибки = НСтр("ru = 'Запрещено использовать поле ""%1""'"); - Иначе - ШаблонОшибки = НСтр("ru = 'Не существует поле ""%1""'"); - КонецЕсли; - УстановитьОшибкуВСтрокеИмениПоля(Контекст, - ОписаниеИсточника.Ключ, ШаблонОшибки, СвойстваПоля.ПолеСОшибкой, Истина); - КонецЦикла; - Возврат; - КонецЕсли; - - СоставИмени = СтрРазделить(ОписаниеПоля.Ключ, "."); - Если СоставИмени.Количество() > 1 - И ( СоставИмени[1] = ВРег("Ссылка") - Или СоставИмени[1] = ВРег("Ref") ) - И СвойстваПоля.Коллекция <> "ТабличныеЧасти" - И СвойстваПоля.Коллекция <> "СтандартныеТабличныеЧасти" Тогда - - Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл - ШаблонОшибки = НСтр("ru = 'Поле ""%1"" избыточно указывать ""через точку"" от любого поля'"); - УстановитьОшибкуВСтрокеИмениПоля(Контекст, - ОписаниеИсточника.Ключ, ШаблонОшибки, 2, Истина); - КонецЦикла; - Возврат; - КонецЕсли; - - Для Каждого ОписаниеТипа Из СвойстваПоля.СодержитТипы Цикл - СвойстваТипа = ОписаниеТипа.Значение; - Для Каждого ОписаниеИсточника Из ОписаниеТипа.Значение.Источники Цикл - Если ТипЗнч(ОписаниеИсточника.Ключ) = Тип("СтрокаТаблицыЗначений") Тогда - Если Не СвойстваТипа.СодержитТип Тогда - УстановитьОшибкуВСтроке(ОписаниеИсточника.Ключ, - СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'У поля ""%1"" не существует тип ""%2""'"), - ОписаниеИсточника.Значение.Символы, - ОписаниеИсточника.Ключ.Символы), - , 2); - КонецЕсли; - КонецЕсли; - КонецЦикла; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОтметитьНекорректныеИменаТаблицПолейИТиповПолей. -Процедура УстановитьОшибкуВСтрокеИмениПоля(Контекст, Строка, ШаблонОшибки, ПолеСОшибкой, - ВставитьИмя = Ложь, Таблица = Null, ВКонце = Ложь) - - Если ЗначениеЗаполнено(Строка.ТекстОшибки) Тогда - Возврат; - КонецЕсли; - - Если ТипЗнч(ВставитьИмя) = Тип("Строка") Тогда - СоставИмени = СтрРазделить(ВставитьИмя, "."); - ВставитьИмя = Истина; - Иначе - СоставИмени = СтрРазделить(Строка.Символы, "."); - КонецЕсли; - - Если СоставИмени.Количество() > 1 - И Контекст.Псевдонимы.Получить(ВРег(СоставИмени[0])) <> Неопределено Тогда - - Строка.ПозицияОшибки = СтрДлина(СоставИмени[0]) + 1; - СоставИмени.Удалить(0); - КонецЕсли; - - Для Номер = 1 По ПолеСОшибкой - 1 Цикл - Строка.ПозицияОшибки = Строка.ПозицияОшибки + СтрДлина(СоставИмени[0]) + 1; - СоставИмени.Удалить(0); - КонецЦикла; - Если ВКонце Тогда - Строка.ПозицияОшибки = Строка.ПозицияОшибки + СтрДлина(СоставИмени[0]); - КонецЕсли; - ИмяПоля = СоставИмени[0]; - - Если ВставитьИмя И Таблица <> Null Тогда - Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, - ИмяПоля, ?(ЗначениеЗаполнено(Таблица), Таблица, Контекст.ОсновнаяТаблица)); - - ИначеЕсли ВставитьИмя Тогда - Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, ИмяПоля); - - ИначеЕсли Таблица <> Null Тогда - Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, - ?(ЗначениеЗаполнено(Таблица), Таблица, Контекст.ОсновнаяТаблица)); - Иначе - Строка.ТекстОшибки = ШаблонОшибки; - КонецЕсли; - -КонецПроцедуры - -#КонецОбласти - -#КонецОбласти - -#Область ОбновлениеПрогрессаОбновленияДоступа - -// Возвращаемое значение: -// Структура: -// * СтрокиСписков - Соответствие -// * СвойстваСписков - Соответствие -// * КоличествоКлючей - Число -// * ДатаПоследнегоОбновления - Дата -// -Функция НовыеХранимыеДанныеОбновленияПрогресса() Экспорт - - ХранимыеДанные = Новый Структура; - ХранимыеДанные.Вставить("СтрокиСписков", Новый Соответствие); - ХранимыеДанные.Вставить("СвойстваСписков", Новый Соответствие); - ХранимыеДанные.Вставить("КоличествоКлючей", 0); - ХранимыеДанные.Вставить("ДатаПоследнегоОбновления", '00010101'); - - Возврат ХранимыеДанные; - -КонецФункции - -// Параметры: -// Контекст - Структура: -// * Версия - Число -// * ХранимыеДанные - см. НовыеХранимыеДанныеОбновленияПрогресса -// * РассчитыватьПоКоличествуДанных - Булево -// * ПоказыватьОбработанныеСписки - Булево -// * ЭтоПовторноеОбновлениеПрогресса - Булево -// * ВсегоОбновлено - Число -// * ПериодОбновленияПрогресса - Число -// * АвтообновлениеПрогресса - Булево -// * ДобавленныеСтроки - Массив -// * УдаленныеСтроки - Соответствие -// * ИзмененныеСтроки - Соответствие -// * ОбновлениеДоступаВыполняется - Булево -// -// АдресРезультата - Строка -// -Процедура ОбновитьПрогрессВФоне(Контекст, АдресРезультата) Экспорт - - ТекстОшибки = Неопределено; - - Если Контекст.Свойство("Версия") И Контекст.Версия = 1 Тогда - Попытка - ОбновитьПрогресс(Контекст); - Исключение - ИнформацияОбОшибке = ИнформацияОбОшибке(); - Если Не СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда - ВызватьИсключение; - КонецЕсли; - ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); - КонецПопытки; - Иначе - ТекстОшибки = НСтр("ru = 'Версия приложения обновлена, перезапустите клиентский сеанс.'"); - КонецЕсли; - - Если ТекстОшибки <> Неопределено Тогда - Контекст.Вставить("ИнформацияОбОшибке", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( - НСтр("ru = 'Не удалось обновить прогресс по причине: - |%1'"), ТекстОшибки)); - КонецЕсли; - - ПоместитьВоВременноеХранилище(Контекст, АдресРезультата); - -КонецПроцедуры - -Процедура ОбновитьПрогресс(Контекст) - - ДатаНачалаОбновленияПрогресса = ТекущаяДатаСеанса(); - ДлительныеОперации.СообщитьПрогресс(0); // Обновление прогресса выполняется. - - СтрокиСписков = Контекст.ХранимыеДанные.СтрокиСписков; - СвойстваСписков = Контекст.ХранимыеДанные.СвойстваСписков; - Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда - Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = '00010101'; - КонецЕсли; - - ДействующиеПараметры = Неопределено; // См. ДействующиеПараметрыОграниченияДоступа - ИдентификаторыТаблиц = ИдентификаторыСписковСОграничением(ДействующиеПараметры); - - Если Контекст.ПоказыватьОбработанныеСписки Тогда - Для Каждого КлючИЗначение Из ИдентификаторыТаблиц Цикл - Если СтрокиСписков.Получить(КлючИЗначение.Значение) <> Неопределено Тогда - Продолжить; - КонецЕсли; - ДобавитьНовуюСтрокуСписка(Контекст, КлючИЗначение.Значение, КлючИЗначение.Ключ); - КонецЦикла; - КонецЕсли; - - Запрос = Новый Запрос; - Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДатаПриПродолжении()); - Запрос.УстановитьПараметр("ДатаПоследнегоОбновления", Контекст.ХранимыеДанные.ДатаПоследнегоОбновления); - Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", - ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); - - Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = ДатаНачалаОбновленияПрогресса; - - ТекстыЗапросов = Новый Массив; - ТекстыЗапросов.Добавить( - "ВЫБРАТЬ - | ВсеСпискиОбновления.Список КАК Список, - | МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеЭлементов) КАК ОбновлениеЭлементов, - | МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеКлючейДоступа) КАК ОбновлениеКлючейДоступа - |ИЗ - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | ОбновлениеКлючейДоступаКДанным.Список КАК Список, - | ИСТИНА КАК ОбновлениеЭлементов, - | ЛОЖЬ КАК ОбновлениеКлючейДоступа - | ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным - | - | ОБЪЕДИНИТЬ ВСЕ - | - | ВЫБРАТЬ РАЗЛИЧНЫЕ - | ОбновлениеКлючейДоступаПользователей.Список, - | ЛОЖЬ, - | ИСТИНА - | ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей) КАК ВсеСпискиОбновления - | - |СГРУППИРОВАТЬ ПО - | ВсеСпискиОбновления.Список"); - - ТекстыЗапросов.Добавить( - "ВЫБРАТЬ РАЗЛИЧНЫЕ - | ОбновлениеКлючей.Список КАК Список - |ПОМЕСТИТЬ ИзмененныеСпискиКлючейДоступаКДанным - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей - |ГДЕ - | ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления - | И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО - | - |ИНДЕКСИРОВАТЬ ПО - | Список - |; - | - |//////////////////////////////////////////////////////////////////////////////// - |ВЫБРАТЬ - | ОбновлениеКлючей.Список КАК Список, - | ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей, - | ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор КАК ЭтоОсновнаяЗапись, - | МАКСИМУМ(ОбновлениеКлючей.РазмерЗадания) КАК РазмерЗадания, - | МАКСИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МаксимальнаяДатаИзменения, - | МИНИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МинимальнаяДатаИзменения - |ИЗ - | ИзмененныеСпискиКлючейДоступаКДанным КАК ИзмененныеСписки - | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей - | ПО (ОбновлениеКлючей.Список = ИзмененныеСписки.Список) - | - |СГРУППИРОВАТЬ ПО - | ОбновлениеКлючей.Список, - | ОбновлениеКлючей.ДляВнешнихПользователей, - | ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор - |ИТОГИ ПО - | Список, - | ДляВнешнихПользователей"); - - ТекстыЗапросов.Добавить(СтрЗаменить(СтрЗаменить(ТекстыЗапросов[1], - "ИзмененныеСпискиКлючейДоступаКДанным", - "ИзмененныеСпискиКлючейДоступаПользователей"), - "РегистрСведений.ОбновлениеКлючейДоступаКДанным", - "РегистрСведений.ОбновлениеКлючейДоступаПользователей")); - - Если Контекст.РассчитыватьПоКоличествуДанных Тогда - ТекстыЗапросов.Добавить( - "ВЫБРАТЬ - | ОбновлениеКлючей.Список КАК Список, - | ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей, - | ОбновлениеКлючей.ПараметрыЗадания КАК ПараметрыЗадания - |ИЗ - | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей - |ГДЕ - | ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления - | И ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор - | И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО - |ИТОГИ ПО - | Список"); - - ТекстыЗапросов.Добавить(СтрЗаменить(ТекстыЗапросов[3], - "РегистрСведений.ОбновлениеКлючейДоступаКДанным", - "РегистрСведений.ОбновлениеКлючейДоступаПользователей")); - - ТекстыЗапросов.Добавить( - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа"); - КонецЕсли; - - Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - - ВсеСпискиОбновления = РезультатыЗапроса[0].Выгрузить(); - НовыеСписки = Новый Массив; - - Для Каждого СписокОбновления Из ВсеСпискиОбновления Цикл - Если Не ЗначениеЗаполнено(СписокОбновления.Список) Тогда - Продолжить; - КонецЕсли; - Строка = СтрокиСписков.Получить(СписокОбновления.Список); - Если Строка = Неопределено Тогда - НовыеСписки.Добавить(СписокОбновления.Список); - КонецЕсли; - КонецЦикла; - - Если НовыеСписки.Количество() > 0 Тогда - ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(НовыеСписки, Ложь); - Для Каждого НовыйСписок Из НовыеСписки Цикл - ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(НовыйСписок); - Если ОбъектМетаданных = Неопределено Тогда - Продолжить; - ИначеЕсли ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда - ИмяТаблицы = ОбъектМетаданных.ПолноеИмя(); - Иначе - ИмяТаблицы = ""; - КонецЕсли; - ДобавитьНовуюСтрокуСписка(Контекст, НовыйСписок, ИмяТаблицы); - КонецЦикла; - КонецЕсли; - - СтрокиОбновленияКоличестваЭлементов = Новый Массив; - СтрокиОбновленияКоличестваКлючейДоступа = Новый Массив; - УдаляемыеСтроки = Новый Массив; - Для Каждого КлючИЗначение Из СтрокиСписков Цикл - Строка = КлючИЗначение.Значение; - СписокОбновления = ВсеСпискиОбновления.Найти(Строка.Список, "Список"); - Если СписокОбновления = Неопределено И Не Контекст.ПоказыватьОбработанныеСписки Тогда - УдаляемыеСтроки.Добавить(Строка); - Продолжить; - КонецЕсли; - СвойстваСписка = СвойстваСписков.Получить(Строка.Список); - Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеЭлементов Тогда - СвойстваСписка.РазмерЗаданияОбновленияЭлементов = 0; - СвойстваСписка.ПоследнийОбновленныйЭлемент = Null; - СвойстваСписка.РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей = 0; - СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей = Null; - Строка.ДоляОбработанныхЭлементовДляПользователей = 1; - Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = 1; - Если Контекст.РассчитыватьПоКоличествуДанных Тогда - Если Строка.ОбработаноЭлементов <> 100 Тогда - СтрокиОбновленияКоличестваЭлементов.Добавить(Строка); - КонецЕсли; - Иначе - ОбнулитьКоличествоЭлементов(Строка, Контекст); - КонецЕсли; - ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст); - КонецЕсли; - Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеКлючейДоступа Тогда - СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступа = 0; - СвойстваСписка.ПоследнийОбновленныйКлючДоступа = Null; - СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей = 0; - СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей = Null; - Строка.ДоляОбработанныхКлючейДоступаДляПользователей = 1; - Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = 1; - Если Контекст.РассчитыватьПоКоличествуДанных Тогда - Если Строка.ОбработаноКлючейДоступа <> 100 Тогда - СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка); - КонецЕсли; - Иначе - ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); - КонецЕсли; - ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст); - КонецЕсли; - Если СписокОбновления = Неопределено Тогда - ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, '00010101', Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, МаксимальнаяДата(), Строка, Контекст); - КонецЕсли; - КонецЦикла; - - Для Каждого УдаляемаяСтрока Из УдаляемыеСтроки Цикл - СтрокиСписков.Удалить(УдаляемаяСтрока.Список); - СвойстваСписков.Удалить(УдаляемаяСтрока.Список); - Индекс = Контекст.ДобавленныеСтроки.Найти(УдаляемаяСтрока); - Если Индекс <> Неопределено Тогда - Контекст.ДобавленныеСтроки.Удалить(Индекс); - Продолжить; - КонецЕсли; - Контекст.УдаленныеСтроки.Вставить(УдаляемаяСтрока.Список, Истина); - КонецЦикла; - - Если Контекст.РассчитыватьПоКоличествуДанных Тогда - ВыборкаПоСпискам = РезультатыЗапроса[5].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); - Пока ВыборкаПоСпискам.Следующий() Цикл - СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список); - Если СвойстваСписка = Неопределено Тогда - Продолжить; - КонецЕсли; - ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать(); - Пока ВыборкаПоВидамПользователей.Следующий() Цикл - Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлементДляВнешнихПользователей"; - Иначе - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлемент"; - КонецЕсли; - Если СвойстваСписка[ИмяПоляПараметровЗадания] <> Истина Тогда - СвойстваСписка[ИмяПоляПараметровЗадания] = ВыборкаПоВидамПользователей.ПараметрыЗадания; - КонецЕсли; - КонецЦикла; - КонецЦикла; - ВыборкаПоСпискам = РезультатыЗапроса[6].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); - Пока ВыборкаПоСпискам.Следующий() Цикл - СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список); - Если СвойстваСписка = Неопределено Тогда - Продолжить; - КонецЕсли; - ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать(); - Пока ВыборкаПоВидамПользователей.Следующий() Цикл - Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей"; - Иначе - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступа"; - КонецЕсли; - Если СвойстваСписка[ИмяПоляПараметровЗадания] <> Истина Тогда - СвойстваСписка[ИмяПоляПараметровЗадания] = ВыборкаПоВидамПользователей.ПараметрыЗадания; - КонецЕсли; - КонецЦикла; - КонецЦикла; - КонецЕсли; - - СпискиОбновленияЭлементов = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого ОписаниеОбновления Из СпискиОбновленияЭлементов.Строки Цикл - Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список); - Если Строка = Неопределено Тогда - Продолжить; - КонецЕсли; - СвойстваСписка = СвойстваСписков.Получить(Строка.Список); - ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Истина, Контекст); - Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда - Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхЭлементовДляПользователей, - Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры); - ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, Обработано, Строка, Контекст); - ОбнулитьКоличествоЭлементов(Строка, Контекст); - - ИначеЕсли Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда - СтрокиОбновленияКоличестваЭлементов.Добавить(Строка); - КонецЕсли; - КонецЦикла; - - СпискиОбновленияКлючейДоступа = РезультатыЗапроса[4].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); - Для Каждого ОписаниеОбновления Из СпискиОбновленияКлючейДоступа.Строки Цикл - Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список); - Если Строка = Неопределено Тогда - Продолжить; - КонецЕсли; - СвойстваСписка = СвойстваСписков.Получить(Строка.Список); - ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Ложь, Контекст); - Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда - Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхКлючейДоступаДляПользователей, - Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры); - ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, Обработано, Строка, Контекст); - ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); - - ИначеЕсли Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда - СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка); - КонецЕсли; - КонецЦикла; - - Индекс = Контекст.ДобавленныеСтроки.Количество() - 1; - Пока Индекс >= 0 Цикл - Если Не ЗначениеЗаполнено(Контекст.ДобавленныеСтроки[Индекс].ИмяТаблицы) Тогда - Контекст.ДобавленныеСтроки.Удалить(Индекс); - КонецЕсли; - Индекс = Индекс - 1; - КонецЦикла; - - Если Контекст.РассчитыватьПоКоличествуДанных Тогда - КоличествоКлючей = РезультатыЗапроса[7].Выгрузить()[0].Количество; - Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда - Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл - СтрокиОбновленияКоличестваЭлементов.Добавить(ОписаниеСтроки.Значение); - СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение); - КонецЦикла; - ИначеЕсли Контекст.ХранимыеДанные.КоличествоКлючей <> КоличествоКлючей Тогда - Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл - Если СтрокиОбновленияКоличестваКлючейДоступа.Найти(ОписаниеСтроки.Значение) = Неопределено Тогда - СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение); - КонецЕсли; - КонецЦикла; - КонецЕсли; - Контекст.ХранимыеДанные.КоличествоКлючей = КоличествоКлючей; - Иначе - Контекст.ХранимыеДанные.КоличествоКлючей = 0; - КонецЕсли; - - Если Контекст.РассчитыватьПоКоличествуДанных Тогда - ТекущийКонтекст = Новый Структура; - ТекущийКонтекст.Вставить("ДобавленныеСтроки", Контекст.ДобавленныеСтроки); - ТекущийКонтекст.Вставить("ИзмененныеСтроки", Контекст.ИзмененныеСтроки); - ТекущийКонтекст.Вставить("СвойстваСписков", СвойстваСписков); - ТекущийКонтекст.Вставить("СтрокиСписков", СтрокиСписков); - ТекущийКонтекст.Вставить("ДействующиеПараметры", ДействующиеПараметры); - ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваЭлементов", СтрокиОбновленияКоличестваЭлементов); - ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваКлючейДоступа", СтрокиОбновленияКоличестваКлючейДоступа); - ТекущийКонтекст.Вставить("ИдентификаторыТаблиц", ИдентификаторыТаблиц); - ТекущийКонтекст.Вставить("ХранимыеДанные", Контекст.ХранимыеДанные); - ВсегоОбновлено = 100; - РассчитатьВсегоОбновленоПоКоличествуДанных(ТекущийКонтекст, ВсегоОбновлено); - Иначе - Если Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда - Контекст.ХранимыеДанные.Удалить("КоличествоЭлементовПоСпискам"); - Контекст.ХранимыеДанные.Удалить("КоличествоКлючейДоступаПоСпискам"); - КонецЕсли; - ВсегоКоличество = ИдентификаторыТаблиц.Количество(); - Если СтрокиСписков.Количество() > ВсегоКоличество Тогда - ВсегоКоличество = СтрокиСписков.Количество(); - КонецЕсли; - ВсегоОбновлено = (100 + 100) * (ВсегоКоличество - СтрокиСписков.Количество()); - Для Каждого КлючИЗначение Из СтрокиСписков Цикл - Строка = КлючИЗначение.Значение; - ВсегоОбновлено = ВсегоОбновлено + Строка.ОбработаноЭлементов + Строка.ОбработаноКлючейДоступа; - КонецЦикла; - ВсегоОбновлено = ВсегоОбновлено / 2 / ВсегоКоличество; - КонецЕсли; - Если ВсегоОбновлено > 100 Тогда - ВсегоОбновлено = 100; - КонецЕсли; - Контекст.ВсегоОбновлено = Цел(ВсегоОбновлено); - - ВремяОбновления = ТекущаяДатаСеанса() - ДатаНачалаОбновленияПрогресса; - - Если Контекст.ЭтоПовторноеОбновлениеПрогресса - И ВремяОбновления > Контекст.ПериодОбновленияПрогресса Тогда - - Контекст.ПериодОбновленияПрогресса = ВремяОбновления; - Иначе - Контекст.Удалить("ПериодОбновленияПрогресса"); - КонецЕсли; - - Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса И ВремяОбновления > 60 Тогда - Контекст.АвтообновлениеПрогресса = Ложь; - Иначе - Контекст.Удалить("АвтообновлениеПрогресса"); - КонецЕсли; - -КонецПроцедуры - -Процедура ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, ЭтоОбработкаЭлементов, Контекст) - - Для Каждого СвойстваОбновления Из ОписаниеОбновления.Строки Цикл - Если ЭтоОбработкаЭлементов Тогда - Если СвойстваОбновления.ДляВнешнихПользователей Тогда - ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей"; - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлементДляВнешнихПользователей"; - ИмяПоляДоли = "ДоляОбработанныхЭлементовДляВнешнихПользователей"; - Иначе - ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияЭлементов"; - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлемент"; - ИмяПоляДоли = "ДоляОбработанныхЭлементовДляПользователей"; - КонецЕсли; - Иначе - Если СвойстваОбновления.ДляВнешнихПользователей Тогда - ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей"; - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей"; - ИмяПоляДоли = "ДоляОбработанныхКлючейДоступаДляВнешнихПользователей"; - Иначе - ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияКлючейДоступа"; - ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступа"; - ИмяПоляДоли = "ДоляОбработанныхКлючейДоступаДляПользователей"; - КонецЕсли; - КонецЕсли; - РазмерЗаданияОсновнаяЗапись = СвойстваСписка[ИмяПоляРазмераЗадания]; - РазмерЗаданияНовыеЗаписи = 0; - Для Каждого СвойстваЗадания Из СвойстваОбновления.Строки Цикл - Если СвойстваЗадания.ЭтоОсновнаяЗапись Тогда - Если СвойстваЗадания.МаксимальнаяДатаИзменения > Строка.ПоследнееОбновление Тогда - ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, - СвойстваЗадания.МаксимальнаяДатаИзменения, Строка, Контекст); - КонецЕсли; - РазмерЗаданияОсновнаяЗапись = СвойстваЗадания.РазмерЗадания; - Иначе - Если СвойстваЗадания.МинимальнаяДатаИзменения < Строка.ПервоеПланированиеОбновления Тогда - ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, - СвойстваЗадания.МинимальнаяДатаИзменения, Строка, Контекст); - КонецЕсли; - РазмерЗаданияНовыеЗаписи = СвойстваЗадания.РазмерЗадания; - КонецЕсли; - КонецЦикла; - СвойстваСписка[ИмяПоляРазмераЗадания] = РазмерЗаданияОсновнаяЗапись; - Если РазмерЗаданияНовыеЗаписи >= РазмерЗаданияОсновнаяЗапись Тогда - СвойстваСписка[ИмяПоляПараметровЗадания] = Истина; - ТекущийРазмерЗадания = РазмерЗаданияНовыеЗаписи; - Иначе - ТекущийРазмерЗадания = РазмерЗаданияОсновнаяЗапись; - Если СвойстваСписка[ИмяПоляПараметровЗадания] = Истина Тогда - СвойстваСписка[ИмяПоляПараметровЗадания] = Null; - КонецЕсли; - КонецЕсли; - Если ТекущийРазмерЗадания = 1 Тогда - Строка[ИмяПоляДоли] = 0.99; - ИначеЕсли ТекущийРазмерЗадания = 2 Тогда - Строка[ИмяПоляДоли] = 0.90; - Иначе - Строка[ИмяПоляДоли] = 0.00; - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -Функция ОбработаноПоДолям(ДоляОбработанныхДляПользователей, ДоляОбработанныхДляВнешнихПользователей, ИмяТаблицы, ДействующиеПараметры) - - ЕстьКлючиДляПользователей = Ложь; - ЕстьКлючиДляВнешнихПользователей = Ложь; - Версии = ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ИмяТаблицы); - Если ЗначениеЗаполнено(Версии) Тогда - ЕстьКлючиДляПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 1)); - ЕстьКлючиДляВнешнихПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 2)); - КонецЕсли; - - Если ДоляОбработанныхДляПользователей < 1 Тогда - ЕстьКлючиДляПользователей = Истина; - КонецЕсли; - Если ДоляОбработанныхДляВнешнихПользователей < 1 Тогда - ЕстьКлючиДляВнешнихПользователей = Истина; - КонецЕсли; - - Если ЕстьКлючиДляПользователей И ЕстьКлючиДляВнешнихПользователей Тогда - Обработано = Цел((ДоляОбработанныхДляПользователей - + ДоляОбработанныхДляВнешнихПользователей) / 2 * 100); - - ИначеЕсли ЕстьКлючиДляПользователей Тогда - Обработано = Цел(ДоляОбработанныхДляПользователей * 100); - Иначе - Обработано = Цел(ДоляОбработанныхДляВнешнихПользователей * 100); - КонецЕсли; - - Возврат Обработано; - -КонецФункции - -Процедура ОбнулитьКоличествоЭлементов(Строка, Контекст); - - ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементов, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементовДляПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементовДляВнешнихПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяЭлементовДляПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяЭлементовДляПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей, 0, Строка, Контекст); - -КонецПроцедуры - -Процедура ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); - - ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступа, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступаДляПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяКлючейДоступаДляПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяКлючейДоступаДляПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); - -КонецПроцедуры - -Процедура ДобавитьНовуюСтрокуСписка(Контекст, Список, ИмяТаблицы) - - Строка = Новый Структура; - Строка.Вставить("Список", Список); - Строка.Вставить("СписокПредставление", Строка(Список)); - Строка.Вставить("ИмяТаблицы", ИмяТаблицы); - Строка.Вставить("ОбработаноЭлементов", 0); - Строка.Вставить("ОбработаноКлючейДоступа", 0); - Строка.Вставить("КоличествоЭлементов", 0); - Строка.Вставить("КоличествоКлючейДоступа", 0); - Строка.Вставить("КоличествоОбработанныхЭлементов", 0); - Строка.Вставить("КоличествоОбработанныхКлючейДоступа", 0); - Строка.Вставить("ПоследнееОбновление", '00010101'); - Строка.Вставить("ПервоеПланированиеОбновления", МаксимальнаяДата()); - - Строка.Вставить("КоличествоЭлементовДляПользователей", 0); - Строка.Вставить("ДоляОбработанныхЭлементовДляПользователей", 1); - Строка.Вставить("КоличествоЭлементовДляВнешнихПользователей", 0); - Строка.Вставить("ДоляОбработанныхЭлементовДляВнешнихПользователей", 1); - Строка.Вставить("КоличествоКлючейДоступаДляПользователей", 0); - Строка.Вставить("ДоляОбработанныхКлючейДоступаДляПользователей", 1); - Строка.Вставить("КоличествоКлючейДоступаДляВнешнихПользователей", 0); - Строка.Вставить("ДоляОбработанныхКлючейДоступаДляВнешнихПользователей", 1); - - Строка.Вставить("КоличествоОставшихсяЭлементовДляПользователей", 0); - Строка.Вставить("ДоляОставшихсяЭлементовДляПользователей", 0); - Строка.Вставить("КоличествоОставшихсяЭлементовДляВнешнихПользователей", 0); - Строка.Вставить("ДоляОставшихсяЭлементовДляВнешнихПользователей", 0); - Строка.Вставить("КоличествоОставшихсяКлючейДоступаДляПользователей", 0); - Строка.Вставить("ДоляОставшихсяКлючейДоступаДляПользователей", 0); - Строка.Вставить("КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей", 0); - Строка.Вставить("ДоляОставшихсяКлючейДоступаДляВнешнихПользователей", 0); - - Контекст.ХранимыеДанные.СтрокиСписков.Вставить(Список, Строка); - ДобавленныеСтроки = Контекст.ДобавленныеСтроки; // Массив - ДобавленныеСтроки.Добавить(Строка); - - Свойства = Новый Структура; - Свойства.Вставить("РазмерЗаданияОбновленияЭлементов", 0); - Свойства.Вставить("ПоследнийОбновленныйЭлемент", Null); - Свойства.Вставить("РазмерЗаданияОбновленияКлючейДоступа", 0); - Свойства.Вставить("ПоследнийОбновленныйКлючДоступа", Null); - - Свойства.Вставить("РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей", 0); - Свойства.Вставить("ПоследнийОбновленныйЭлементДляВнешнихПользователей", Null); - Свойства.Вставить("РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей", 0); - Свойства.Вставить("ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей", Null); - - Контекст.ХранимыеДанные.СвойстваСписков.Вставить(Список, Свойства); - -КонецПроцедуры - -// Параметры: -// Контекст - Структура: -// * ДобавленныеСтроки - Массив -// * ИзмененныеСтроки - Соответствие -// * СвойстваСписков - Соответствие -// * СтрокиСписков - Соответствие -// * ДействующиеПараметры - см. ДействующиеПараметрыОграниченияДоступа -// * СтрокиОбновленияКоличестваЭлементов - Массив -// * СтрокиОбновленияКоличестваКлючейДоступа - Массив -// * ИдентификаторыТаблиц - см. ОбщегоНазначения.ИдентификаторыОбъектовМетаданных -// * ХранимыеДанные - см. НовыеХранимыеДанныеОбновленияПрогресса -// * ТипыТаблицПоИменам - Соответствие -// -// ВсегоОбновлено - Число -// -Процедура РассчитатьВсегоОбновленоПоКоличествуДанных(Контекст, ВсегоОбновлено) - - ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; - Контекст.Вставить("ТипыТаблицПоИменам", ТипыТаблицПоИменам); - - Если Не Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда - ЗаполнитьКоличествоЭлементовИКлючейДоступаПоСпискам(Контекст); - КонецЕсли; - - ОбновитьКоличествоЭлементовИКлючейДоступа(Контекст); - - КоличествоЭлементовПоСпискам = Контекст.ХранимыеДанные.КоличествоЭлементовПоСпискам; - КоличествоКлючейДоступаПоСпискам = Контекст.ХранимыеДанные.КоличествоКлючейДоступаПоСпискам; - - ОбщееКоличествоЭлементов = 0; - Для Каждого КлючИЗначение Из КоличествоЭлементовПоСпискам Цикл - ОбщееКоличествоЭлементов = ОбщееКоличествоЭлементов + КлючИЗначение.Значение; - КонецЦикла; - ОбщееКоличествоЭлементов = ?(ОбщееКоличествоЭлементов = 0, 100, ОбщееКоличествоЭлементов); - - ОбщееКоличествоКлючейДоступа = 0; - Для Каждого КлючИЗначение Из КоличествоКлючейДоступаПоСпискам Цикл - ОбщееКоличествоКлючейДоступа = ОбщееКоличествоКлючейДоступа + КлючИЗначение.Значение; - КонецЦикла; - ОбщееКоличествоКлючейДоступа = ?(ОбщееКоличествоКлючейДоступа = 0, 100, ОбщееКоличествоКлючейДоступа); - - ВсегоОбновленоЭлементов = 0; - ВсегоОбновленоКлючейДоступа = 0; - - ДобавкаОбщегоКоличестваЭлементов = 0; - ДобавкаОбщегоКоличестваКлючейДоступа = 0; - - ИменаТаблицСОбновлениемЭлементов = Новый Соответствие; - ИменаТаблицСОбновлениемКлючейДоступа = Новый Соответствие; - - Для Каждого КлючИЗначение Из Контекст.СтрокиСписков Цикл - Строка = КлючИЗначение.Значение; - - КоличествоЭлементов = КоличествоЭлементовПоСпискам.Получить(КлючИЗначение.Значение.ИмяТаблицы); - Если КоличествоЭлементов = Неопределено Тогда - Если КоличествоЭлементовПоСпискам.Количество() = 0 Тогда - Добавка = 1; - Иначе - Добавка = Цел(ОбщееКоличествоЭлементов / КоличествоЭлементовПоСпискам.Количество() / 10); - Добавка = ?(Добавка = 0, 1, Добавка); - КонецЕсли; - ДобавкаОбщегоКоличестваЭлементов = ДобавкаОбщегоКоличестваЭлементов + Добавка; - ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + 100 * Добавка; - Иначе - ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + Строка.ОбработаноЭлементов * КоличествоЭлементов; - ИменаТаблицСОбновлениемЭлементов.Вставить(КлючИЗначение.Значение.ИмяТаблицы, Истина); - КонецЕсли; - - КоличествоКлючейДоступа = КоличествоКлючейДоступаПоСпискам.Получить(КлючИЗначение.Значение.ИмяТаблицы); - Если КоличествоКлючейДоступа = Неопределено Тогда - Если КоличествоКлючейДоступаПоСпискам.Количество() = 0 Тогда - Добавка = 1; - Иначе - Добавка = Цел(ОбщееКоличествоКлючейДоступа / КоличествоКлючейДоступаПоСпискам.Количество() / 10); - Добавка = ?(Добавка = 0, 1, Добавка); - КонецЕсли; - ДобавкаОбщегоКоличестваКлючейДоступа = ДобавкаОбщегоКоличестваКлючейДоступа + Добавка; - ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + 100 * Добавка; - Иначе - ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + Строка.ОбработаноКлючейДоступа * КоличествоКлючейДоступа; - ИменаТаблицСОбновлениемКлючейДоступа.Вставить(КлючИЗначение.Значение.ИмяТаблицы, Истина); - КонецЕсли; - КонецЦикла; - - КоличествоОбновленныхЭлементов = 0; - Для Каждого КлючИЗначение Из КоличествоЭлементовПоСпискам Цикл - Если ИменаТаблицСОбновлениемЭлементов.Получить(КлючИЗначение.Ключ) = Неопределено Тогда - КоличествоОбновленныхЭлементов = КоличествоОбновленныхЭлементов + КлючИЗначение.Значение; - КонецЕсли; - КонецЦикла; - ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + КоличествоОбновленныхЭлементов * 100; - - КоличествоОбновленныхКлючейДоступа = 0; - Для Каждого КлючИЗначение Из КоличествоКлючейДоступаПоСпискам Цикл - Если ИменаТаблицСОбновлениемКлючейДоступа.Получить(КлючИЗначение.Ключ) = Неопределено Тогда - КоличествоОбновленныхКлючейДоступа = КоличествоОбновленныхКлючейДоступа + КлючИЗначение.Значение; - КонецЕсли; - КонецЦикла; - ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + КоличествоОбновленныхКлючейДоступа * 100; - - ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов - / (ОбщееКоличествоЭлементов + ДобавкаОбщегоКоличестваЭлементов); - - ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа - / (ОбщееКоличествоКлючейДоступа + ДобавкаОбщегоКоличестваКлючейДоступа); - - ВсегоОбновлено = (ВсегоОбновленоЭлементов + ВсегоОбновленоКлючейДоступа) / 2; - -КонецПроцедуры - -Процедура ЗаполнитьКоличествоЭлементовИКлючейДоступаПоСпискам(Контекст) - - КоличествоЭлементовПоСпискам = Новый Соответствие; - КоличествоКлючейДоступаПоСпискам = Новый Соответствие; - Контекст.ХранимыеДанные.Вставить("КоличествоЭлементовПоСпискам", КоличествоЭлементовПоСпискам); - Контекст.ХранимыеДанные.Вставить("КоличествоКлючейДоступаПоСпискам", КоличествоКлючейДоступаПоСпискам); - - ОписаниеЗапроса = Новый Структура("Запрос, ТекстыПакетаЗапросов", Новый Запрос, Новый Массив); - - ОбновляемыеТаблицы = Новый Соответствие; - ИдентификаторыТаблиц = Контекст.ИдентификаторыТаблиц; - Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл - Если ИдентификаторыТаблиц.Получить(Строка.ИмяТаблицы) = Строка.Список Тогда - ОбновляемыеТаблицы.Вставить(Строка.ИмяТаблицы, Строка.Список); - КонецЕсли; - КонецЦикла; - Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл - Если ИдентификаторыТаблиц.Получить(Строка.ИмяТаблицы) = Строка.Список Тогда - ОбновляемыеТаблицы.Вставить(Строка.ИмяТаблицы, Строка.Список); - КонецЕсли; - КонецЦикла; - - Индекс = 0; - ИменаТаблиц = Новый Массив; - Для Каждого КлючИЗначение Из Контекст.ИдентификаторыТаблиц Цикл - Если ОбновляемыеТаблицы.Получить(КлючИЗначение.Ключ) = КлючИЗначение.Значение Тогда - Продолжить; - КонецЕсли; - ИменаТаблиц.Добавить(КлючИЗначение.Ключ); - Строка = Новый Структура("Список, ИмяТаблицы", КлючИЗначение.Значение, КлючИЗначение.Ключ); - ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); - ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); - ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Ложь); - ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Истина); - КонецЦикла; - - Если ОписаниеЗапроса.ТекстыПакетаЗапросов.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - РезультатыЗапроса = ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса); - - Индекс = 0; - Для Каждого ИмяТаблицы Из ИменаТаблиц Цикл - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - КоличествоЭлементовДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - КоличествоЭлементовДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - КоличествоЭлементовПоСпискам[ИмяТаблицы] = КоличествоЭлементовДляПользователей - + КоличествоЭлементовДляВнешнихПользователей; - - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - КоличествоКлючейДоступаДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - КоличествоКлючейДоступаДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - КоличествоКлючейДоступаПоСпискам[ИмяТаблицы] = КоличествоКлючейДоступаДляПользователей - + КоличествоКлючейДоступаДляВнешнихПользователей; - КонецЦикла; - -КонецПроцедуры - -Процедура ОбновитьКоличествоЭлементовИКлючейДоступа(Контекст) - - ОписаниеЗапроса = Новый Структура("Запрос, ТекстыПакетаЗапросов", Новый Запрос, Новый Массив); - Индекс = 0; - Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл - ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); - ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); - ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); - ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); - КонецЦикла; - Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл - ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Ложь); - ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Истина); - ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); - ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); - КонецЦикла; - - Если ОписаниеЗапроса.ТекстыПакетаЗапросов.Количество() = 0 Тогда - Возврат; - КонецЕсли; - - РезультатыЗапроса = ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса); - - КоличествоЭлементовПоСпискам = Контекст.ХранимыеДанные.КоличествоЭлементовПоСпискам; - КоличествоКлючейДоступаПоСпискам = Контекст.ХранимыеДанные.КоличествоКлючейДоступаПоСпискам; - ВерсииОграниченийСписков = Контекст.ДействующиеПараметры.ВерсииОграниченийСписков; - ТипыТаблицПоИменам = Контекст.ТипыТаблицПоИменам; - - Индекс = 0; - Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - Строка.КоличествоЭлементовДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - Строка.КоличествоЭлементовДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - КоличествоЭлементов = Строка.КоличествоЭлементовДляПользователей + Строка.КоличествоЭлементовДляВнешнихПользователей; - Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда - КоличествоЭлементовПоСпискам.Вставить(Строка.ИмяТаблицы, КоличествоЭлементов); - КонецЕсли; - - Если КоличествоЭлементов = 0 Тогда - ОбнулитьКоличествоЭлементов(Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст); - Индекс = Индекс + 2; - Иначе - СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); - ЕстьКлючиДляПользователей = Ложь; - ЕстьКлючиДляВнешнихПользователей = Ложь; - Версии = ВерсииОграниченийСписков.Получить(Строка.ИмяТаблицы); - Если ЗначениеЗаполнено(Версии) Тогда - ЕстьКлючиДляПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 1)); - ЕстьКлючиДляВнешнихПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 2)); - КонецЕсли; - СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); - СвойстваТипа = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - - ОбновитьКоличество(РезультатыЗапроса[Индекс], - СвойстваСписка.ПоследнийОбновленныйЭлемент, - Строка.КоличествоОставшихсяЭлементовДляПользователей, - Строка.КоличествоЭлементовДляПользователей, - Строка.ДоляОставшихсяЭлементовДляПользователей, - Строка.ДоляОбработанныхЭлементовДляПользователей); - Индекс = Индекс + 1; - КоличествоОбработанныхЭлементов = - Строка.КоличествоЭлементовДляПользователей - - Строка.КоличествоОставшихсяЭлементовДляПользователей; - - ОбновитьКоличество(РезультатыЗапроса[Индекс], - СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей, - Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей, - Строка.КоличествоЭлементовДляВнешнихПользователей, - Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей, - Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей); - Индекс = Индекс + 1; - КоличествоОбработанныхЭлементов = КоличествоОбработанныхЭлементов - + Строка.КоличествоЭлементовДляВнешнихПользователей - - Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей; - - КоличествоЭлементов = Строка.КоличествоЭлементовДляПользователей + Строка.КоличествоЭлементовДляВнешнихПользователей; - Если ЕстьКлючиДляПользователей И ЕстьКлючиДляВнешнихПользователей И СвойстваТипа.ЭтоСсылочныйТип Тогда - КоличествоЭлементов = КоличествоЭлементов / 2; - КоличествоОбработанныхЭлементов = КоличествоОбработанныхЭлементов / 2; - КонецЕсли; - ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементов, КоличествоЭлементов, Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, - Цел(КоличествоОбработанныхЭлементов), Строка, Контекст); - Если Строка.КоличествоОбработанныхЭлементов > Строка.КоличествоЭлементов Тогда - ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, - Строка.КоличествоЭлементов, Строка, Контекст); - КонецЕсли; - ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, ?(Строка.КоличествоЭлементов = 0, 100, - Цел(Строка.КоличествоОбработанныхЭлементов / Строка.КоличествоЭлементов * 100)), Строка, Контекст); - КонецЕсли; - КонецЦикла; - - Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - Строка.КоличествоКлючейДоступаДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - Выборка = РезультатыЗапроса[Индекс].Выбрать(); - Строка.КоличествоКлючейДоступаДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); - Индекс = Индекс + 1; - - КоличествоКлючейДоступа = Строка.КоличествоКлючейДоступаДляПользователей - + Строка.КоличествоКлючейДоступаДляВнешнихПользователей; - ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступа, КоличествоКлючейДоступа, Строка, Контекст); - Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда - КоличествоКлючейДоступаПоСпискам.Вставить(Строка.ИмяТаблицы, КоличествоКлючейДоступа); - КонецЕсли; - - Если Строка.КоличествоКлючейДоступа = 0 Тогда - ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); - ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст); - Индекс = Индекс + 2; - Иначе - СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); - - ОбновитьКоличество(РезультатыЗапроса[Индекс], - СвойстваСписка.ПоследнийОбновленныйКлючДоступа, - Строка.КоличествоОставшихсяКлючейДоступаДляПользователей, - Строка.КоличествоКлючейДоступаДляПользователей, - Строка.ДоляОставшихсяКлючейДоступаДляПользователей, - Строка.ДоляОбработанныхКлючейДоступаДляПользователей); - Индекс = Индекс + 1; - КоличествоОбработанныхКлючейДоступа = - Строка.КоличествоКлючейДоступаДляПользователей - - Строка.КоличествоОставшихсяКлючейДоступаДляПользователей; - - ОбновитьКоличество(РезультатыЗапроса[Индекс], - СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей, - Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей, - Строка.КоличествоКлючейДоступаДляВнешнихПользователей, - Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей, - Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей); - Индекс = Индекс + 1; - КоличествоОбработанныхКлючейДоступа = КоличествоОбработанныхКлючейДоступа - + Строка.КоличествоКлючейДоступаДляВнешнихПользователей - - Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей; - - ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, - Цел(КоличествоОбработанныхКлючейДоступа), Строка, Контекст); - Если Строка.КоличествоОбработанныхКлючейДоступа > Строка.КоличествоКлючейДоступа Тогда - ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, - Строка.КоличествоКлючейДоступа, Строка, Контекст); - КонецЕсли; - ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, - Цел(Строка.КоличествоОбработанныхКлючейДоступа / Строка.КоличествоКлючейДоступа * 100), Строка, Контекст); - КонецЕсли; - КонецЦикла; - -КонецПроцедуры - -// Для процедуры ОбновитьКоличествоЭлементовИКлючейДоступа. -Процедура ОбновитьКоличество(РезультатЗапроса, ПоследнийОбновленный, - КоличествоОставшихся, Количество, ДоляОставшихся, ДоляОбработанных) - - Если ПоследнийОбновленный = Null Или ПоследнийОбновленный = Истина Тогда - НовоеКоличествоОставшихся = -1; - Иначе - Выборка = РезультатЗапроса.Выбрать(); - НовоеКоличествоОставшихся = ?(Выборка.Следующий(), Выборка.Количество, 0); - КонецЕсли; - - Если НовоеКоличествоОставшихся = -1 Тогда - ДоляОставшихся = 0; - НовоеКоличествоОставшихся = 0; - КонецЕсли; - - Если ТипЗнч(НовоеКоличествоОставшихся) = Тип("Число") Тогда - КоличествоОставшихся = Цел(Количество * (1 - ДоляОбработанных - ДоляОставшихся) + 0.99) - + Цел(НовоеКоличествоОставшихся * ДоляОставшихся); - КонецЕсли; - -КонецПроцедуры - -// Возвращаемое значение: -// Массив из РезультатЗапроса -// -Функция ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса) - - РезультатыПакетаЗапросов = Новый Массив; - - ТекстыПорцииЗапросов = Новый Массив; - Для Каждого ТекстЗапроса Из ОписаниеЗапроса.ТекстыПакетаЗапросов Цикл - Если ТекстыПорцииЗапросов.Количество() = 200 Тогда - // @skip-check query-in-loop - Порционная обработка данных - ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса); - ТекстыПорцииЗапросов = Новый Массив; - КонецЕсли; - ТекстыПорцииЗапросов.Добавить(ТекстЗапроса); - КонецЦикла; - ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса); - - Возврат РезультатыПакетаЗапросов; - -КонецФункции - -Процедура ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса) - - Запрос = ОписаниеЗапроса.Запрос; - - Запрос.Текст = СтрСоединить(ТекстыПорцииЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); - РезультатыЗапроса = Запрос.ВыполнитьПакет(); - Запрос.Текст = ""; - - Для Каждого РезультатЗапроса Из РезультатыЗапроса Цикл - РезультатыПакетаЗапросов.Добавить(РезультатЗапроса); - КонецЦикла; - -КонецПроцедуры - -Процедура ОбновитьЗначениеВСтроке(СтароеЗначение, НовоеЗначение, Строка, Контекст) - - Если СтароеЗначение = НовоеЗначение Тогда - Возврат; - КонецЕсли; - СтароеЗначение = НовоеЗначение; - - Если Контекст.ДобавленныеСтроки.Найти(Строка) = Неопределено - И Контекст.ИзмененныеСтроки.Получить(Строка) = Неопределено Тогда - - Контекст.ИзмененныеСтроки.Вставить(Строка.Список, Строка); - КонецЕсли; - -КонецПроцедуры - -Процедура ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) - - Версии = Контекст.ДействующиеПараметры.ВерсииОграниченийСписков.Получить(Строка.ИмяТаблицы); - - Если ЗначениеЗаполнено(Версии) - И ЗначениеЗаполнено(Строка.ИмяТаблицы) - Или Строка.ИмяТаблицы = "Справочник.НаборыГруппДоступа" Тогда - - СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); - СвойстваТипа = Контекст.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - Если СвойстваТипа.ЭтоСсылочныйТип Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица"; - Иначе - ТекстЗапроса = ТекстЗапросаКоличестваЭлементовРегистра(Контекст, Строка, Индекс, ДляВнешнихПользователей); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", Строка.ИмяТаблицы); - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | 0 КАК Количество"; - КонецЕсли; - - ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); - Индекс = Индекс + 1; - -КонецПроцедуры - -Функция ТекстЗапросаКоличестваЭлементовРегистра(Контекст, Строка, Индекс, ДляВнешнихПользователей) - - Если ДляВнешнихПользователей Тогда - ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; - Иначе - ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; - КонецЕсли; - Свойства = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Строка.ИмяТаблицы); - - Если Свойства = Неопределено - Или Свойства.ОпорныеПоля = Неопределено - Или Свойства.ОпорныеПоля.Используемые.Количество() = 0 Тогда - - Возврат - "ВЫБРАТЬ - | 0 КАК Количество"; - КонецЕсли; - - ПоляВыбора = ""; - Для Каждого ИмяПоля Из Свойства.ОпорныеПоля.Используемые Цикл - ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", ", - | ") + "ТекущаяТаблица." + ИмяПоля; - КонецЦикла; - - Если Свойства.ОпорныеПоля.Используемые.Количество() = 1 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ &ПоляВыбора) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ПоляВыбора КАК ПоляВыбора - | ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица) КАК Комбинации"; - ПоляВыбора = ТекстСОтступом(ПоляВыбора, " "); - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляВыбора", ПоляВыбора); - - Возврат ТекстЗапроса; - -КонецФункции - -Процедура ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) - - СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); - СпискиСДатой = Контекст.ДействующиеПараметры.СпискиСДатой; - - Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда - СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); - СвойстваТипа = Контекст.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); - Иначе - СвойстваСписка = Неопределено; - КонецЕсли; - - Если СвойстваСписка = Неопределено Тогда - ПараметрыЗадания = Неопределено; - - ИначеЕсли ДляВнешнихПользователей Тогда - ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей; - Иначе - ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйЭлемент; - КонецЕсли; - - Если ТипЗнч(ПараметрыЗадания) <> Тип("ХранилищеЗначения") Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | НЕОПРЕДЕЛЕНО КАК Количество"; - Иначе - ДолиКоличестваЭлементов = Новый Структура("Обработанных, Оставшихся", 0, 1); - ПараметрыЗадания = ПараметрыЗадания.Получить(); - - Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") - И ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") - И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент) = Тип("Структура") - И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ВидКлючаДанных") - И ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных) <> Неопределено - И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("КлючДанных") - И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ОбработатьУстаревшиеЭлементы") - И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы) = Тип("Булево") Тогда - - ПоследнийОбновленныйЭлемент = ПараметрыЗадания.ПоследнийОбновленныйЭлемент; - Иначе - ПоследнийОбновленныйЭлемент = Новый Структура; - ПоследнийОбновленныйЭлемент.Вставить("ВидКлючаДанных", "ЭлементыДанныхСУстаревшимиКлючами"); - ПоследнийОбновленныйЭлемент.Вставить("КлючДанных"); - КонецЕсли; - - УсловиеОтбора = ""; - Если СвойстваТипа.ЭтоСсылочныйТип Тогда - КлючДанных = ПоследнийОбновленныйЭлемент.КлючДанных; - Если СпискиСДатой.Получить(Строка.ИмяТаблицы) <> Неопределено Тогда - - Если ПоследнийОбновленныйЭлемент.Свойство("Дата") - И ТипЗнч(ПоследнийОбновленныйЭлемент.Дата) = Тип("Дата") Тогда - - ИмяПараметра = "ПоследняяДата" + Формат(Индекс, "ЧГ="); - УсловиеОтбора = "ТекущаяТаблица.Дата <= &" + ИмяПараметра; - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийОбновленныйЭлемент.Дата); - КонецЕсли; - - ИначеЕсли ЗначениеЗаполнено(КлючДанных) Тогда - ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(КлючДанных)); - Если ОбъектМетаданных <> Неопределено - И ОбъектМетаданных.ПолноеИмя() = Строка.ИмяТаблицы Тогда - - ИмяПараметра = "ПоследняяСсылка" + Формат(Индекс, "ЧГ="); - УсловиеОтбора = "ТекущаяТаблица.Ссылка > &" + ИмяПараметра; - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, КлючДанных); - КонецЕсли; - КонецЕсли; - Если ЗначениеЗаполнено(УсловиеОтбора) Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - |ГДЕ - | &УсловиеОтбора"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | -1 КАК Количество"; - КонецЕсли; - ЗаполнитьДолиКоличествоЭлементовСсылочногоТипа(ДолиКоличестваЭлементов, - ПоследнийОбновленныйЭлемент, Строка.ИмяТаблицы); - Иначе - Если ДляВнешнихПользователей Тогда - ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; - Иначе - ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; - КонецЕсли; - СвойстваОграничения = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Строка.ИмяТаблицы); - - Если СвойстваОграничения <> Неопределено Тогда - ИспользуемыеВариантыДоступа = ДополнительныйКонтекст.ОсновныеВариантыДоступа.Получить(Строка.ИмяТаблицы); - Если ИспользуемыеВариантыДоступа = Неопределено Тогда - СвойстваОграничения = Неопределено; - Иначе - СвойстваОграничения = Новый Структура(СвойстваОграничения); - СвойстваОграничения.Вставить("ВариантДоступа", ИспользуемыеВариантыДоступа[0].ВариантДоступа); - КонецЕсли; - КонецЕсли; - - ЗаполнитьДолиКоличестваЭлементовРегистра(ДолиКоличестваЭлементов, - ПоследнийОбновленныйЭлемент, СвойстваОграничения); - - ТекстЗапроса = ТекстЗапросаКоличестваОставшихсяЭлементовРегистра(ОписаниеЗапроса, Строка, Индекс, - ДляВнешнихПользователей, ПоследнийОбновленныйЭлемент, СвойстваОграничения, СвойстваТипа); - КонецЕсли; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", Строка.ИмяТаблицы); - - Если ДляВнешнихПользователей Тогда - Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = ДолиКоличестваЭлементов.Обработанных; - Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей = ДолиКоличестваЭлементов.Оставшихся; - Иначе - Строка.ДоляОбработанныхЭлементовДляПользователей = ДолиКоличестваЭлементов.Обработанных; - Строка.ДоляОставшихсяЭлементовДляПользователей = ДолиКоличестваЭлементов.Оставшихся; - КонецЕсли; - КонецЕсли; - - ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); - Индекс = Индекс + 1; - -КонецПроцедуры - -Процедура ЗаполнитьДолиКоличествоЭлементовСсылочногоТипа(ДолиКоличестваЭлементов, Элемент, ИмяТаблицы) - - Если ИмяТаблицы = "Справочник.НаборыГруппДоступа" Тогда - Если Элемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.0; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.1; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.2; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - - ИначеЕсли Элемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.3; - ДолиКоличестваЭлементов.Оставшихся = 0.2; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.5; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - - ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.6; - ДолиКоличестваЭлементов.Оставшихся = 0.3; - - Иначе // УстаревшиеЭлементы. - ДолиКоличестваЭлементов.Обработанных = 0.9; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - КонецЕсли; - Возврат; - КонецЕсли; - - Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда - ДолиКоличестваЭлементов.Обработанных = 0.0; - ДолиКоличестваЭлементов.Оставшихся = 0.9; - Иначе // УстаревшиеЭлементы. - ДолиКоличестваЭлементов.Обработанных = 0.9; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - КонецЕсли; - -КонецПроцедуры - -Функция ТекстЗапросаКоличестваОставшихсяЭлементовРегистра(ОписаниеЗапроса, Строка, Индекс, - ДляВнешнихПользователей, ПоследнийОбновленныйЭлемент, СвойстваОграничения, СвойстваТипа) - - ВидКлючаДанных = ПоследнийОбновленныйЭлемент.ВидКлючаДанных; - КлючДанных = ПоследнийОбновленныйЭлемент.КлючДанных; - - Если СвойстваОграничения = Неопределено - Или СвойстваОграничения.ОпорныеПоля = Неопределено - Или СвойстваОграничения.ОпорныеПоля.Используемые.Количество() = 0 - Или ТипЗнч(КлючДанных) <> Тип("Структура") - Или ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" - И (Не ПоследнийОбновленныйЭлемент.Свойство("Дата") - Или ТипЗнч(ПоследнийОбновленныйЭлемент.Дата) <> Тип("Дата")) - Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" - И СвойстваОграничения.ОпорныеПоля.Используемые.Количество() <> КлючДанных.Количество() - Или ВидКлючаДанных <> "ЭлементыБезКлючейПоПериоду" - И ВидКлючаДанных <> "ЭлементыБезКлючейПоЗначениямПолей" - И СвойстваОграничения.ОпорныеПоля.Используемые.Количество() > КлючДанных.Количество() Тогда - - Возврат - "ВЫБРАТЬ - | -1 КАК Количество"; - КонецЕсли; - - ПоляВыбора = ""; - УсловиеОтбора = ""; - УсловиеСоединения = ""; - - Если ЗначениеЗаполнено(СвойстваОграничения.ИмяОтдельногоРегистраКлючей) Тогда - ИмяРегистраКлючей = СвойстваОграничения.ИмяОтдельногоРегистраКлючей; - Иначе - ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; - ИмяПараметра = "ИдентификаторРегистра" + Формат(Индекс, "ЧГ="); - УсловиеСоединения = "(КлючиДоступаКРегистрам.Регистр = &" + ИмяПараметра + ")"; - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); - КонецЕсли; - - ОпорныеПоля = СвойстваОграничения.ОпорныеПоля; - ОтборПоТипуПользователей = XMLСтрока(СвойстваОграничения.ВариантДоступа); - УсловиеСоединения = УсловиеСоединения + ?(УсловиеСоединения = "", "", " - | И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = " + ОтборПоТипуПользователей + ")"; // @query-part-3 - - НомерПоля = 1; - Для Каждого ИмяПоля Из ОпорныеПоля.Используемые Цикл - ИмяПоляВКлючеДанных = СтрШаблон("Поле%1", НомерПоля); - ИмяПараметра = ИмяПоля + Формат(Индекс, "ЧГ="); - - УсловиеСоединения = УсловиеСоединения + ?(УсловиеСоединения = "", "", " - | И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ТекущаяТаблица.%2)", НомерПоля, ИмяПоля); // @query-part-3 - - Отбор = ""; - Для ТекущийИндекс = 0 По НомерПоля - 2 Цикл - ТекущееИмяПоля = ОпорныеПоля.Используемые[ТекущийИндекс]; - ТекущееИмяПараметра = ТекущееИмяПоля + Формат(Индекс, "ЧГ="); - Отбор = Отбор + ?(Отбор = "", "", " - | И ") + "ТекущаяТаблица." + ТекущееИмяПоля + " = &" + ТекущееИмяПараметра; // @query-part-3 - КонецЦикла; - Отбор = Отбор + ?(Отбор = "", "", " - | И ") + "ТекущаяТаблица." + ИмяПоля + " > &" + ИмяПараметра; // @query-part-3 - - УсловиеОтбора = УсловиеОтбора + ?(НомерПоля = 1, ?(ОпорныеПоля.Используемые.Количество() > 1, "(", "") + Отбор, " - | ИЛИ " + ТекстСОтступом(Отбор, " ")); // @query-part-3 - - Если КлючДанных.Свойство(ИмяПоляВКлючеДанных) Тогда - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, КлючДанных[ИмяПоляВКлючеДанных]); - Иначе - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Неопределено); - КонецЕсли; - ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", ", - | ") + "ТекущаяТаблица." + ИмяПоля; - НомерПоля = НомерПоля + 1; - КонецЦикла; - - Если ОпорныеПоля.Используемые.Количество() > 1 Тогда - УсловиеОтбора = УсловиеОтбора + ")"; - КонецЕсли; - - Если ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда - ИмяПоляПериода = ?(СвойстваТипа.ИмяКоллекции = "РегистрыРасчета", "ПериодРегистрации", "Период"); - ИмяПараметра = ИмяПоляПериода + Формат(Индекс, "ЧГ="); - УсловиеОтбора = "(ТекущаяТаблица." + ИмяПоляПериода + " < &" + ИмяПараметра + " - | ИЛИ ТекущаяТаблица." - + ИмяПоляПериода + " = &" + ИмяПараметра + " - | И " + ТекстСОтступом(УсловиеОтбора, " ") + ")"; // @query-part-3, @query-part-5 - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийОбновленныйЭлемент.Дата); - КонецЕсли; - - Если СвойстваОграничения.ОпорныеПоля.Используемые.Количество() = 1 Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ &ПоляВыбора) КАК Количество - |ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - | ЛЕВОЕ СОЕДИНЕНИЕ ТекущийСписок КАК КлючиДоступаКРегистрам - | ПО (&УсловиеСоединения) - |ГДЕ - | &УсловиеОтбора - | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | (ВЫБРАТЬ РАЗЛИЧНЫЕ - | &ПоляВыбора КАК ПоляВыбора - | ИЗ - | &ТекущаяТаблица КАК ТекущаяТаблица - | ЛЕВОЕ СОЕДИНЕНИЕ ТекущийСписок КАК КлючиДоступаКРегистрам - | ПО (&УсловиеСоединения) - | ГДЕ - | &УсловиеОтбора - | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL) КАК Комбинации"; - ПоляВыбора = ТекстСОтступом(ПоляВыбора, " "); - УсловиеОтбора = ТекстСОтступом(УсловиеОтбора, " "); - КонецЕсли; - - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "(&УсловиеСоединения)", УсловиеСоединения); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляВыбора", ПоляВыбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок", "РегистрСведений." + ИмяРегистраКлючей); - - Возврат ТекстЗапроса; - -КонецФункции - -Процедура ЗаполнитьДолиКоличестваЭлементовРегистра(ДолиКоличестваЭлементов, Элемент, СвойстваОграничения) - - Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.0; - ДолиКоличестваЭлементов.Оставшихся = 0.5; - - ИначеЕсли Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" - Или Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.5; - ДолиКоличестваЭлементов.Оставшихся = 0.4; - - ИначеЕсли Элемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда - - Если СвойстваОграничения <> Неопределено - И ЗначениеЗаполнено(СвойстваОграничения.ИмяОтдельногоРегистраКлючей) Тогда - - ДолиКоличестваЭлементов.Обработанных = 0.90; - ДолиКоличестваЭлементов.Оставшихся = 0.09; - Иначе - ДолиКоличестваЭлементов.Обработанных = 0.9; - ДолиКоличестваЭлементов.Оставшихся = 0.1; - КонецЕсли; - - Иначе // НекорректныеЭлементы или НекорректныеЭлементыОбщегоРегистра. - ДолиКоличестваЭлементов.Обработанных = 0.99; - ДолиКоличестваЭлементов.Оставшихся = 0.01; - КонецЕсли; - -КонецПроцедуры - -Процедура ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, ДляВнешнихПользователей) - - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(КлючиДоступа.Ссылка) КАК Количество - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | КлючиДоступа.Список = &Список - | И КлючиДоступа.ДляВнешнихПользователей = ЛОЖЬ"; - - ИмяПараметра = "СписокКлючей" + Формат(Индекс, "ЧГ="); - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Список", "&" + ИмяПараметра); - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); - - Если ДляВнешнихПользователей Тогда - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ЛОЖЬ", "ИСТИНА"); - КонецЕсли; - - ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); - Индекс = Индекс + 1; - -КонецПроцедуры - -Процедура ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) - - СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); - - Если СвойстваСписка = Неопределено Тогда - ПараметрыЗадания = Неопределено; - - ИначеЕсли ДляВнешнихПользователей Тогда - ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей; - Иначе - ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйКлючДоступа; - КонецЕсли; - - Если ТипЗнч(ПараметрыЗадания) <> Тип("ХранилищеЗначения") Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | НЕОПРЕДЕЛЕНО КАК Количество"; - Иначе - ДолиКоличестваКлючейДоступа = Новый Структура("Обработанных, Оставшихся", 0, 1); - ПараметрыЗадания = ПараметрыЗадания.Получить(); - - Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") - И ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") - И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент) = Тип("Структура") - И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ВидКлючаДанных") - И ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных) <> Неопределено - И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("КлючДанных") Тогда - - ПоследнийКлючДоступа = ПараметрыЗадания.ПоследнийОбновленныйЭлемент.КлючДанных; - ЗаполнитьДолиКоличестваКлючейДоступа(ДолиКоличестваКлючейДоступа, - ПараметрыЗадания.ПоследнийОбновленныйЭлемент); - КонецЕсли; - УсловиеОтбора = ""; - Если ТипЗнч(ПоследнийКлючДоступа) = Тип("СправочникСсылка.КлючиДоступа") Тогда - ИмяПараметра = "СписокОбработанныхКлючей" + Формат(Индекс, "ЧГ="); - УсловиеОтбора = "КлючиДоступа.Список = &" + ИмяПараметра; - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); - - УсловиеОтбора = УсловиеОтбора + " - | И КлючиДоступа.ДляВнешнихПользователей = " + ?(ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ"); // @query-part-1 - - ИмяПараметра = "ПоследнийКлючДоступа" + Формат(Индекс, "ЧГ="); - УсловиеОтбора = УсловиеОтбора + " - | И КлючиДоступа.Ссылка > &" + ИмяПараметра; // @query-part-1 - ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийКлючДоступа); - КонецЕсли; - - Если ЗначениеЗаполнено(УсловиеОтбора) Тогда - ТекстЗапроса = - "ВЫБРАТЬ - | КОЛИЧЕСТВО(*) КАК Количество - |ИЗ - | Справочник.КлючиДоступа КАК КлючиДоступа - |ГДЕ - | &УсловиеОтбора"; - ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); - Иначе - ТекстЗапроса = - "ВЫБРАТЬ - | -1 КАК Количество"; - КонецЕсли; - - Если ДляВнешнихПользователей Тогда - Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = ДолиКоличестваКлючейДоступа.Обработанных; - Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей = ДолиКоличестваКлючейДоступа.Оставшихся; - Иначе - Строка.ДоляОбработанныхКлючейДоступаДляПользователей = ДолиКоличестваКлючейДоступа.Обработанных; - Строка.ДоляОставшихсяКлючейДоступаДляПользователей = ДолиКоличестваКлючейДоступа.Оставшихся; - КонецЕсли; - КонецЕсли; - - ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); - Индекс = Индекс + 1; - -КонецПроцедуры - -Процедура ЗаполнитьДолиКоличестваКлючейДоступа(ДолиКоличестваКлючейДоступа, Элемент) - - Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиПравами" Тогда - ДолиКоличестваКлючейДоступа.Обработанных = 0.0; - ДолиКоличестваКлючейДоступа.Оставшихся = 0.9; - Иначе // УстаревшиеЭлементы. - ДолиКоличестваКлючейДоступа.Обработанных = 0.9; - ДолиКоличестваКлючейДоступа.Оставшихся = 0.1; - КонецЕсли; - -КонецПроцедуры - -// Параметры: -// ДействующиеПараметры - см. ДействующиеПараметрыОграниченияДоступа -// -// Возвращаемое значение: -// см. ОбщегоНазначения.ИдентификаторыОбъектовМетаданных -// -Функция ИдентификаторыСписковСОграничением(ДействующиеПараметры) - - ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); - - Списки = Новый Массив; - Для Каждого ОписаниеВерсии Из ДействующиеПараметры.ВерсииОграниченийСписков Цикл - Списки.Добавить(ОписаниеВерсии.Ключ); - КонецЦикла; - - Возврат ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки, Ложь); - -КонецФункции - -Функция ТекущаяДатаНаСервере() Экспорт - - // АПК:143-выкл - №643.2.1 Требуется ТекущаяДата сервера, а не ТекущаяДатаСеанса, - // так как именно ТекущаяДата записывается в журнал регистрации. - Возврат ТекущаяДата(); - // АПК:143-вкл. - -КонецФункции - -#КонецОбласти - -#КонецОбласти - +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2024, ООО 1С-Софт +// Все права защищены. Эта программа и сопроводительные материалы предоставляются +// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0) +// Текст лицензии доступен по ссылке: +// https://creativecommons.org/licenses/by/4.0/legalcode +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +#Область СлужебныйПрограммныйИнтерфейс + +#Область ОсновныеПроцедурыИФункции + +// Добавляет пользователя в группу доступа, соответствующую поставляемому профилю. +// Группа доступа определяется по идентификатору ссылки поставляемого профиля. +// Если группа доступа не будет найдена, она будет создана. +// +// Параметры: +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей - участник, которого нужно включить в группу доступа. +// +// ПоставляемыйПрофиль - Строка - строка идентификатора поставляемого профиля. +// - СправочникСсылка.ПрофилиГруппДоступа - ссылка на профиль, который +// создан по описанию в модуле УправлениеДоступомПереопределяемый +// в процедуре ПриЗаполненииПоставляемыхПрофилейГруппДоступа. +// Профили с непустым списком видов доступа не поддерживаются. +// Профиль групп доступа Администратор не поддерживается. +// +Процедура ВключитьПользователяВГруппуДоступа(Пользователь, ПоставляемыйПрофиль) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.ВключитьПользователяВГруппуДоступа"); + + ОбработатьСвязьПользователяСГруппойДоступа(Пользователь, ПоставляемыйПрофиль, Истина); + +КонецПроцедуры + +// Обновляет состав пользователей указанных групп исполнителей. +// +// Требуется вызывать при изменении состава пользователей у групп исполнителей, +// например, у групп исполнителей задач. +// +// В качестве значений параметра передается группы исполнителей, состав которых изменился. +// +// Параметры: +// ГруппыИсполнителей - СправочникСсылка.ГруппыИсполнителейЗадач - одна группа, +// - Массив из СправочникСсылка.ГруппыИсполнителейЗадач - несколько групп, +// - Неопределено - без отбора. +// +Процедура ОбновитьПользователейГруппИсполнителей(ГруппыИсполнителей = Неопределено) Экспорт + + Если ТипЗнч(ГруппыИсполнителей) = Тип("Массив") И ГруппыИсполнителей.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Параметры = Новый Структура; + Параметры.Вставить("ГруппыИсполнителей", ГруппыИсполнителей); + + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); + +КонецПроцедуры + +// Проверяет существование вида доступа с указанным именем. +// Применяется для автоматизации условного встраивания подсистем. +// +// Параметры: +// ИмяВидаДоступа - Строка - имя вида доступа. +// +// Возвращаемое значение: +// Структура: +// +Функция ВидДоступаСуществует(ИмяВидаДоступа) Экспорт + + Возврат СвойстваВидаДоступа(ИмяВидаДоступа) <> Неопределено; + +КонецФункции + +// Возвращает вид интерфейса пользователя для настройки доступа. +// +// Возвращаемое значение: +// Булево +// +Функция УпрощенныйИнтерфейсНастройкиПравДоступа() Экспорт + + УпрощенныйИнтерфейс = Ложь; + УправлениеДоступомПереопределяемый.ПриОпределенииИнтерфейсаНастройкиДоступа(УпрощенныйИнтерфейс); + + Возврат УпрощенныйИнтерфейс = Истина; + +КонецФункции + +// Возвращает массив разрешенных значений указанных типов в рамках всех групп доступа. +// Используется в процедуре НастроитьОтборыДинамическогоСписка для ускорения открытия динамических списков. +// +// Параметры: +// Таблица - Строка - полное имя объекта метаданных, например, "Документ.РасходнаяНакладная". +// ТипЗначений - Тип - тип значений доступа, разрешенные значения которых нужно вернуть. +// - Массив - массив указанных выше типов. +// +// Значения - Неопределено - не учитывать. +// - Массив - массив значений типов, указанных в параметре ТипЗначений. +// +// Пользователь - Неопределено - вернуть разрешенные значения для авторизованного пользователя. +// - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи - вернуть +// разрешенные значения для указанного пользователя. +// +// ВернутьВсе - Булево - если установить Истина, тогда будут возвращены все значение даже тогда, +// когда их более 100. +// +// Возвращаемое значение: +// Неопределено - либо все значения разрешены для типов, указанных в параметре ТипЗначений, +// либо (когда ВернутьВсе = Ложь) количество разрешенных значений превышает 100. +// Массив - ссылки разрешенных значений указанных типов. +// +Функция РазрешенныеЗначенияДляДинамическогоСписка(Таблица, ТипЗначений, Значения = Неопределено, Пользователь = Неопределено, ВернутьВсе = Ложь) Экспорт + + Если ТипЗнч(ТипЗначений) <> Тип("Массив") Тогда + ТипыЗначений = Новый Массив; + ТипыЗначений.Добавить(ТипЗначений); + + ИначеЕсли ТипЗначений.Количество() = 0 Тогда + Возврат Неопределено; + Иначе + ТипыЗначений = ТипЗначений; + КонецЕсли; + + УстановитьПривилегированныйРежим(Истина); + + ТекстЗапросаЗначенийБезГрупп = + "ВЫБРАТЬ ПЕРВЫЕ 101 + | ЗначенияБезГрупп.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | &ЗначениеПустойСсылки КАК Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ЗначенияБезПустойСсылки.Ссылка + | ИЗ + | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ЗначенияБезГрупп + |ГДЕ + | ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ГруппыДоступаПользователя КАК ГруппыДоступа + | ГДЕ + | ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступа КАК Значения + | ГДЕ + | Значения.ГруппаДоступа = ГруппыДоступа.Ссылка + | И Значения.ЗначениеДоступа = ЗначенияБезГрупп.Ссылка) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ = ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ГДЕ + | ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступа.Ссылка + | И ТИПЗНАЧЕНИЯ(ЗначенияПоУмолчанию.ТипЗначенийДоступа) = ТИПЗНАЧЕНИЯ(ЗначенияБезГрупп.Ссылка) + | И ЗначенияПоУмолчанию.ВсеРазрешены = ЛОЖЬ) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ) + | И ЗначенияБезГрупп.Ссылка В(&Значения)"; + + Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда + ТекстЗапросаЗначенийБезГрупп = СтрЗаменить(ТекстЗапросаЗначенийБезГрупп, "ПЕРВЫЕ 101", ""); // @query-part-1 + КонецЕсли; + Если ТипЗнч(Значения) <> Тип("Массив") Тогда + ТекстЗапросаЗначенийБезГрупп = СтрЗаменить(ТекстЗапросаЗначенийБезГрупп, "ЗначенияБезГрупп.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 + КонецЕсли; + + ТекстЗапросаЗначенийСГруппами = + "ВЫБРАТЬ ПЕРВЫЕ 101 + | ЗначенияСГруппами.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | &ЗначениеПустойСсылки КАК Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ЗначенияБезПустойСсылки.Ссылка + | ИЗ + | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ЗначенияСГруппами + |ГДЕ + | ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ГруппыДоступаПользователя КАК ГруппыДоступа + | ГДЕ + | ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступа КАК Значения + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначений + | ПО + | Значения.ГруппаДоступа = ГруппыДоступа.Ссылка + | И Значения.ЗначениеДоступа = ГруппыЗначений.ГруппаЗначенийДоступа + | И ГруппыЗначений.ЗначениеДоступа = ЗначенияСГруппами.Ссылка) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ = ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ГДЕ + | ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступа.Ссылка + | И ТИПЗНАЧЕНИЯ(ЗначенияПоУмолчанию.ТипЗначенийДоступа) = ТИПЗНАЧЕНИЯ(ЗначенияСГруппами.Ссылка) + | И ЗначенияПоУмолчанию.ВсеРазрешены = ЛОЖЬ) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ) + | И ЗначенияСГруппами.Ссылка В(&Значения)"; + + Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда + ТекстЗапросаЗначенийСГруппами = СтрЗаменить(ТекстЗапросаЗначенийСГруппами, "ПЕРВЫЕ 101", ""); // @query-part-1 + КонецЕсли; + Если ТипЗнч(Значения) <> Тип("Массив") Тогда + ТекстЗапросаЗначенийСГруппами = СтрЗаменить(ТекстЗапросаЗначенийСГруппами, "ЗначенияСГруппами.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 + КонецЕсли; + + ТекстЗапросаВсеЗначения = + "ВЫБРАТЬ ПЕРВЫЕ 101 + | ВсеЗначения.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | &ЗначениеПустойСсылки КАК Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ЗначенияБезПустойСсылки.Ссылка + | ИЗ + | &ТаблицаЗначенийДоступа КАК ЗначенияБезПустойСсылки) КАК ВсеЗначения + |ГДЕ + | ВсеЗначения.Ссылка В(&Значения)"; + + Если ТипЗнч(Значения) = Тип("Массив") Или ВернутьВсе Тогда + ТекстЗапросаВсеЗначения = СтрЗаменить(ТекстЗапросаВсеЗначения, "ПЕРВЫЕ 101", ""); // @query-part-1 + КонецЕсли; + Если ТипЗнч(Значения) <> Тип("Массив") Тогда + ТекстЗапросаВсеЗначения = СтрЗаменить(ТекстЗапросаВсеЗначения, "ВсеЗначения.Ссылка В(&Значения)", "ИСТИНА"); // @query-part-1 + КонецЕсли; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ТекстЗапроса = ""; + Если Пользователь <> Неопределено Тогда + АвторизованныйПользователь = Пользователь; + Иначе + АвторизованныйПользователь = Пользователи.АвторизованныйПользователь(); + КонецЕсли; + ДобавитьТекущегоПользователя = Ложь; + ЕстьИспользуемыеВидыДоступа = Ложь; + ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); + + Для Каждого ТекущийТип Из ТипыЗначений Цикл + Свойства = СвойстваВидовДоступа.ПоТипамЗначений.Получить(ТекущийТип); // См. СвойстваВидаДоступа + Если Свойства = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Тип ""%1"" не является типом значений доступа'"), Строка(ТекущийТип)); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ИспользуемыеВидыДоступа.Получить(Свойства.Ссылка) = Неопределено Тогда + ТекущийТекстЗапроса = ТекстЗапросаВсеЗначения; + Иначе + Если СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами.Получить(ТекущийТип) = Неопределено Тогда + ТекущийТекстЗапроса = ТекстЗапросаЗначенийБезГрупп; + Иначе + ТекущийТекстЗапроса = ТекстЗапросаЗначенийСГруппами; + КонецЕсли; + ЕстьИспользуемыеВидыДоступа = Истина; + КонецЕсли; + ТаблицаЗначенийДоступа = Метаданные.НайтиПоТипу(ТекущийТип).ПолноеИмя(); + ТекущийТекстЗапроса = СтрЗаменить(ТекущийТекстЗапроса, "&ТаблицаЗначенийДоступа", ТаблицаЗначенийДоступа); + ТекущийТекстЗапроса = СтрЗаменить(ТекущийТекстЗапроса, "&ЗначениеПустойСсылки", + "ЗНАЧЕНИЕ(" + ТаблицаЗначенийДоступа + ".ПустаяСсылка)"); // @query-part-2 + Если ЗначениеЗаполнено(ТекстЗапроса) Тогда + ОбъединитьЗапросСЗапросом(ТекстЗапроса, ТекущийТекстЗапроса); + Иначе + ТекстЗапроса = ТекущийТекстЗапроса; + КонецЕсли; + Если ТекущийТип = ТипЗнч(АвторизованныйПользователь) Тогда + ДобавитьТекущегоПользователя = Истина; + КонецЕсли; + КонецЦикла; + + Если Не ЕстьИспользуемыеВидыДоступа Тогда + Возврат Неопределено; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИмяОсновнойТаблицыСписка", Таблица); + Запрос.УстановитьПараметр("АвторизованныйПользователь", АвторизованныйПользователь); + Запрос.Текст = ТекстЗапросаГруппДоступа(); + Если ТипЗнч(Значения) = Тип("Массив") Тогда + Запрос.УстановитьПараметр("Значения", Значения); + КонецЕсли; + + ДобавитьЗапросВПакет(Запрос.Текст, ТекстЗапроса); + + Выгрузка = Запрос.Выполнить().Выгрузить(); + + Если ТипЗнч(Значения) <> Тип("Массив") + И Не ВернутьВсе + И Выгрузка.Количество() > 100 Тогда + + Возврат Неопределено; + КонецЕсли; + + РазрешенныеЗначения = Выгрузка.ВыгрузитьКолонку("Ссылка"); + + Если ДобавитьТекущегоПользователя Тогда + РазрешенныеЗначения.Добавить(АвторизованныйПользователь); + КонецЕсли; + + Возврат РазрешенныеЗначения; + +КонецФункции + +// Добавляет администраторов системы в группу доступа, +// связанную с предопределенным профилем ОткрытиеВнешнихОтчетовИОбработок. +// +Процедура УстановитьПравоОткрытияВнешнихОтчетовИОбработок(ОткрытиеРазрешено) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.УстановитьПравоОткрытияВнешнихОтчетовИОбработок"); + + СвойстваПрофиля = ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок(); + СвойстваПрофиля.Вставить("Ссылка", Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( + СвойстваПрофиля.Имя, Истина)); + + ИдентификаторРоли = ОбщегоНазначения.ИдентификаторОбъектаМетаданных( + Метаданные.Роли.ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок); + + // В упрощенном интерфейсе группу доступа создавать не требуется (только профиль). + УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); + Если Не УпрощенныйИнтерфейс Тогда + ГруппаПрофиля = ГруппаДоступаОткрытиеВнешнихОтчетовИОбработок(СвойстваПрофиля); + КонецЕсли; + + Если ОткрытиеРазрешено Тогда + // Включение администраторов в группы доступа с этим профилем. + РольАдминистратора = Метаданные.Роли.АдминистраторСистемы; + ПользователиИБ = ПользователиИнформационнойБазы.ПолучитьПользователей(); + СоставПользователей = Новый Массив; + Для Каждого ПользовательИБ Из ПользователиИБ Цикл + Если ПользовательИБ.Роли.Содержит(РольАдминистратора) Тогда + Пользователь = Справочники.Пользователи.НайтиПоРеквизиту( + "ИдентификаторПользователяИБ", + ПользовательИБ.УникальныйИдентификатор); + Если Пользователь = Неопределено Тогда + Продолжить; + КонецЕсли; + Если УпрощенныйИнтерфейс Тогда + // В упрощенном интерфейсе каждый администратор включаются в отдельную группу. + УправлениеДоступом.ВключитьПрофильПользователю(Пользователь, СвойстваПрофиля.Ссылка); + Иначе + // В расширенном интерфейсе администраторы включаются в одну группу, связанную с предопределенным профилем. + СоставПользователей.Добавить(Пользователь); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Не УпрощенныйИнтерфейс Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаПрофиля); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ГруппаДоступаОбъект = ГруппаПрофиля.ПолучитьОбъект(); + Для Каждого Пользователь Из СоставПользователей Цикл + Если ГруппаДоступаОбъект.Пользователи.Найти(Пользователь, "Пользователь") = Неопределено Тогда + ГруппаДоступаОбъект.Пользователи.Добавить().Пользователь = Пользователь; + КонецЕсли; + КонецЦикла; + Если ГруппаДоступаОбъект.Модифицированность() Тогда + ГруппаДоступаОбъект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + Иначе + // Удаление роли из всех профилей, за исключением предопределенного. + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПрофилиГруппДоступаРоли.Ссылка + |ИЗ + | Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиГруппДоступаРоли + |ГДЕ + | ПрофилиГруппДоступаРоли.Роль = &Роль + | И ПрофилиГруппДоступаРоли.Ссылка <> &ИсключаемыйПрофиль"; + Запрос.УстановитьПараметр("Роль", ИдентификаторРоли); + Запрос.УстановитьПараметр("ИсключаемыйПрофиль", СвойстваПрофиля.Ссылка); + МассивПрофилей = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + Для Каждого Профиль Из МассивПрофилей Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Профиль); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПрофильОбъект = Профиль.ПолучитьОбъект(); + Найденные = ПрофильОбъект.Роли.НайтиСтроки(Новый Структура("Роль", ИдентификаторРоли)); + Для Каждого СтрокаТаблицы Из Найденные Цикл + ПрофильОбъект.Роли.Удалить(СтрокаТаблицы); + КонецЦикла; + ПрофильОбъект.Записать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + + // Очистка состава групп доступа, связанных с предопределенным профилем. + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &Профиль"; + Запрос.УстановитьПараметр("Профиль", СвойстваПрофиля.Ссылка); + МассивГрупп = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + Для Каждого ГруппаДоступа Из МассивГрупп Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступа); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ГруппаДоступаОбъект = ГруппаДоступа.ПолучитьОбъект(); + ГруппаДоступаОбъект.Пользователи.Очистить(); + ГруппаДоступаОбъект.Записать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Только для внутреннего использования. +Процедура ПриРегистрацииИспользованияВерсииРасширенийВНеразделенномСеансе() Экспорт + + Если ТекущийРежимЗапуска() = Неопределено + Или ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей(); + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// Булево +// +Функция ВариантВстроенногоЯзыкаРусский() Экспорт + + Возврат Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский; + +КонецФункции + +// Обновляет список ролей пользователей информационной базы +// по их текущим принадлежностям к группам доступа. +// Пользователи с ролью "ПолныеПрава" игнорируется. +// +// Параметры: +// ОписаниеПользователей - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - Массив - значений указанных выше типов. +// - Неопределено - обновить роли всех пользователей. +// - Тип - по которому будет найден объект метаданных: +// если будет найден Справочник.ВнешниеПользователи, +// то будут обновлены роли всех внешних пользователей, +// иначе будут обновлены роли всех пользователей. +// +// ПарольПользователяСервиса - Строка - пароль для авторизации в менеджере сервиса. +// +// ЕстьИзменения - Булево - возвращаемое значение. В этот параметр возвращается +// значение Истина, если производилась запись, иначе не изменяется. +// +Процедура ОбновитьРолиПользователей(Знач ОписаниеПользователей = Неопределено, + Знач ПарольПользователяСервиса = Неопределено, + ЕстьИзменения = Ложь) Экспорт + + Если НЕ ПользователиСлужебный.ЗапретРедактированияРолей() Тогда + // Роли устанавливаются механизмами подсистем Пользователи и ВнешниеПользователи. + Возврат; + КонецЕсли; + + Если ОписаниеПользователей = Неопределено Тогда + МассивПользователей = Неопределено; + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + + ИначеЕсли ТипЗнч(ОписаниеПользователей) = Тип("Массив") Тогда + МассивПользователей = ОписаниеПользователей; + Если МассивПользователей.Количество() = 0 Тогда + Возврат; + ИначеЕсли МассивПользователей.Количество() = 1 Тогда + Пользователи.НайтиНеоднозначныхПользователейИБ(МассивПользователей[0]); + Иначе + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + КонецЕсли; + + ИначеЕсли ТипЗнч(ОписаниеПользователей) = Тип("Тип") Тогда + МассивПользователей = ОписаниеПользователей; + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + Иначе + МассивПользователей = Новый Массив; + МассивПользователей.Добавить(ОписаниеПользователей); + Пользователи.НайтиНеоднозначныхПользователейИБ(ОписаниеПользователей); + КонецЕсли; + + УстановитьПривилегированныйРежим(Истина); + + ТекущиеСвойстваПользователей = ТекущиеСвойстваПользователей(МассивПользователей); + + // Параметры проверки в цикле. + ВсеРоли = ПользователиСлужебный.ВсеРоли().Соответствие; + ИдентификаторыПользователейИБ = ТекущиеСвойстваПользователей.ИдентификаторыПользователейИБ; + НовыеРолиПользователей = ТекущиеСвойстваПользователей.РолиПользователей; + ИдентификаторыРолей = ТекущиеСвойстваПользователей.ИдентификаторыРолей; + ИменаРолей = ТекущиеСвойстваПользователей.ИменаРолей; + ОбязательныеРолиАдминистратора = ТекущиеСвойстваПользователей.ОбязательныеРолиАдминистратора; + ДополнительныеРолиАдминистратора = ТекущиеСвойстваПользователей.ДополнительныеРолиАдминистратора; + Администраторы = ТекущиеСвойстваПользователей.Администраторы; + РазделениеВключено = ОбщегоНазначения.РазделениеВключено(); + НеобходимоОбновлениеИБ = ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы(); + ИдентификаторТекущегоПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор; + + // Будущий итог после цикла. + НовыеАдминистраторыИБ = Новый Соответствие; + ОбновляемыеПользователиИБ = Новый Соответствие; + НекорректныеРоли = НовыеНекорректныеРоли(НовыеРолиПользователей); + + Для Каждого ОписаниеПользователя Из ИдентификаторыПользователейИБ Цикл + + ТекущийПользователь = ОписаниеПользователя.Пользователь; + ИдентификаторПользователяИБ = ОписаниеПользователя.ИдентификаторПользователяИБ; + НовыйАдминистраторИБ = Ложь; + + // Поиск пользователя ИБ. + Если ТипЗнч(ИдентификаторПользователяИБ) = Тип("УникальныйИдентификатор") Тогда + ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( + ИдентификаторПользователяИБ); + Иначе + ПользовательИБ = Неопределено; + КонецЕсли; + + Если ПользовательИБ = Неопределено + Или Не ЗначениеЗаполнено(ПользовательИБ.Имя) Тогда + Продолжить; + КонецЕсли; + + Если НеобходимоОбновлениеИБ + И ИдентификаторПользователяИБ = ИдентификаторТекущегоПользователяИБ Тогда + Продолжить; + КонецЕсли; + + Отказ = Ложь; + ИнтеграцияПодсистемБСП.ПриОбновленииРолейПользователяИБ(ИдентификаторПользователяИБ, Отказ); + Если Отказ Тогда + Продолжить; + КонецЕсли; + + Отбор = Новый Структура("Пользователь", ТекущийПользователь); + НовыеРоли = НовыеРолиПользователей.Скопировать( + НовыеРолиПользователей.НайтиСтроки(Отбор), "Роль, РольСсылка"); + + НовыеРоли.Индексы.Добавить("РольСсылка"); + + Если Администраторы[ТекущийПользователь] <> Неопределено Тогда + ТекущиеНовыеРоли = НовыеРоли; + НовыеРоли = ТекущиеНовыеРоли.Скопировать(Новый Массив); + Для Каждого КлючИЗначение Из ОбязательныеРолиАдминистратора Цикл + НовыеРоли.Добавить().РольСсылка = КлючИЗначение.Значение; + КонецЦикла; + Для Каждого КлючИЗначение Из ДополнительныеРолиАдминистратора Цикл + Если ТекущиеНовыеРоли.Найти(КлючИЗначение.Значение, "РольСсылка") = Неопределено Тогда + Продолжить; + КонецЕсли; + НовыеРоли.Добавить().РольСсылка = КлючИЗначение.Значение; + КонецЦикла; + КонецЕсли; + + НедоступныеРоли = ПользователиСлужебный.НедоступныеРолиПоТипуПользователя( + ТипЗнч(ТекущийПользователь) = Тип("СправочникСсылка.ВнешниеПользователи")); + + // Проверка старых ролей. + РолиДляДобавления = Новый Соответствие; + РолиДляУдаления = Новый Соответствие; + + Для Каждого Роль Из ПользовательИБ.Роли Цикл + ИмяРоли = Роль.Имя; + РольСсылка = ИдентификаторыРолей.Получить(ИмяРоли); + Если РольСсылка = Неопределено Тогда + КлючРоли = Справочники.ИдентификаторыОбъектовМетаданных.КлючОбъектаМетаданныхРоль(Роль); + РольСсылка = ИдентификаторыРолей.Получить(КлючРоли); + КонецЕсли; + Строка = НовыеРоли.Найти(РольСсылка, "РольСсылка"); + Если Строка = Неопределено Тогда + РолиДляУдаления.Вставить(ИмяРоли, Роль); + Иначе + Если РазделениеВключено И НедоступныеРоли.Получить(ИмяРоли) <> Неопределено Тогда + Строка.Роль = ИмяРоли; + ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Ложь); + РолиДляУдаления.Вставить(ИмяРоли, Роль); + КонецЕсли; + НовыеРоли.Удалить(Строка); + КонецЕсли; + КонецЦикла; + + // Проверка новых ролей. + Для Каждого Строка Из НовыеРоли Цикл + Строка.Роль = ИменаРолей.Получить(Строка.РольСсылка); + + Если ВсеРоли.Получить(Строка.Роль) = Неопределено Тогда + ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Истина); + Продолжить; + КонецЕсли; + + Если НедоступныеРоли.Получить(Строка.Роль) <> Неопределено Тогда + ДобавитьНекорректнуюРоль(НекорректныеРоли, Строка, ТекущийПользователь, Ложь); + Продолжить; + КонецЕсли; + + РолиДляДобавления.Вставить(Строка.Роль, Истина); + + Если Строка.Роль = "АдминистраторСистемы" Тогда + НовыйАдминистраторИБ = Истина; + КонецЕсли; + КонецЦикла; + + // Завершение обработки текущего пользователя. + Если РолиДляДобавления.Количество() = 0 + И РолиДляУдаления.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + + ИзмененияРолей = Новый Структура; + ИзмененияРолей.Вставить("ПользовательСсылка", ТекущийПользователь); + ИзмененияРолей.Вставить("ПользовательИБ", ПользовательИБ); + ИзмененияРолей.Вставить("РолиДляДобавления", РолиДляДобавления); + ИзмененияРолей.Вставить("РолиДляУдаления", РолиДляУдаления); + + Если НовыйАдминистраторИБ Тогда + НовыеАдминистраторыИБ.Вставить(ТекущийПользователь, ИзмененияРолей); + Иначе + ОбновляемыеПользователиИБ.Вставить(ТекущийПользователь, ИзмененияРолей); + КонецЕсли; + + ЕстьИзменения = Истина; + КонецЦикла; + + ЗарегистрироватьНекорректныеРоли(НекорректныеРоли); + + // Добавление новых администраторов. + Если НовыеАдминистраторыИБ.Количество() > 0 Тогда + ОбновитьРолиПользователейИБ(НовыеАдминистраторыИБ, ПарольПользователяСервиса); + КонецЕсли; + + // Удаление старых администраторов и обновление остальных пользователей. + Если ОбновляемыеПользователиИБ.Количество() > 0 Тогда + ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса); + КонецЕсли; + + ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей(); + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// Булево +// +Функция ПоддерживаетсяРегистрацияИзмененийПраваДоступа() Экспорт + Возврат Истина; +КонецФункции + +// Возвращаемое значение: +// Строка +// +Функция ИмяСобытияИзменениеУчастниковГруппДоступаДляЖурналаРегистрации() Экспорт + + Возврат НСтр("ru = 'Управление доступом.Изменение участников групп доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()); + +КонецФункции + +// Возвращаемое значение: +// Строка +// +Функция ИмяСобытияИзменениеРазрешенныхЗначенийДляЖурналаРегистрации() Экспорт + + Возврат НСтр("ru = 'Управление доступом.Изменение разрешенных значений'", + ОбщегоНазначения.КодОсновногоЯзыка()); + +КонецФункции + +// Возвращаемое значение: +// Строка +// +Функция ИмяСобытияИзменениеРолейПрофилейДляЖурналаРегистрации() Экспорт + + Возврат НСтр("ru = 'Управление доступом.Изменение ролей профилей'", + ОбщегоНазначения.КодОсновногоЯзыка()); + +КонецФункции + +// См. СвойстваВидовДоступа +Функция СвойстваВсехВидовДоступа() Экспорт + Возврат СвойстваВидовДоступа(); +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПолноеИмяФормыСпискаГруппДоступа - Строка +// * ПолноеИмяФормыЭлементаГруппДоступа - Строка +// * ПолноеИмяФормыСпискаПрофилей - Строка +// * ПолноеИмяФормыЭлементаПрофилей - Строка +// * ТипСправочникСсылкаГруппыДоступа - Тип +// * ТипСправочникСсылкаПрофилиГруппДоступа - Тип +// * ТипыЗначенийДоступа - Массив из Тип +// +Функция ПараметрыДляОтчетов() Экспорт + + Результат = Новый Структура; + Результат.Вставить("ПолноеИмяФормыСпискаГруппДоступа", "Справочник.ГруппыДоступа.Форма.ФормаСписка"); + Результат.Вставить("ПолноеИмяФормыЭлементаГруппДоступа", "Справочник.ГруппыДоступа.Форма.ФормаЭлемента"); + Результат.Вставить("ПолноеИмяФормыСпискаПрофилей", "Справочник.ПрофилиГруппДоступа.Форма.ФормаСписка"); + Результат.Вставить("ПолноеИмяФормыЭлементаПрофилей", "Справочник.ПрофилиГруппДоступа.Форма.ФормаЭлемента"); + Результат.Вставить("ТипСправочникСсылкаГруппыДоступа", Тип("СправочникСсылка.ГруппыДоступа")); + Результат.Вставить("ТипСправочникСсылкаПрофилиГруппДоступа", Тип("СправочникСсылка.ПрофилиГруппДоступа")); + Результат.Вставить("ТипыЗначенийДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип.Типы()); + + Возврат Результат; + +КонецФункции + +#КонецОбласти + +#Область УниверсальноеОграничение + +Функция ОграничиватьДоступНаУровнеЗаписейУниверсально(СУчетомКонстантыОграничениеДоступаНаУровнеЗаписей = Истина, + КогдаПервоеОбновлениеДоступаЗавершилось = Ложь, ОбновлятьПараметрыСеансаКогдаТребуется = Истина) Экспорт + + Если СУчетомКонстантыОграничениеДоступаНаУровнеЗаписей Тогда + Значение = КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + + Если ОбновлятьПараметрыСеансаКогдаТребуется + И (Значение <> УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() + Или Значение + И Не ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально + И КонстантаПервоеОбновлениеДоступаЗавершилось()) Тогда + + ОбновитьПараметрыСеанса(); + Значение = УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + КонецЕсли; + + Возврат Значение + И (Не КогдаПервоеОбновлениеДоступаЗавершилось + Или КонстантаПервоеОбновлениеДоступаЗавершилось()); + КонецЕсли; + + Если ОбновлятьПараметрыСеансаКогдаТребуется + И Не ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа.Полное + И Не ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально Тогда + + ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); + Если ПоследняяПроверка.Дата + 3 <= ТекущаяДатаСеанса() Тогда + + Значение = КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + Если Значение И КонстантаПервоеОбновлениеДоступаЗавершилось() + Или Значение <> УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + + ОбновитьПараметрыСеанса(); + Значение = УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); + КонецЕсли; + ПоследняяПроверка.Дата = ТекущаяДатаСеанса(); + КонецЕсли; + КонецЕсли; + + Если Не КогдаПервоеОбновлениеДоступаЗавершилось Тогда + Возврат УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + КонецЕсли; + + Возврат ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально; + +КонецФункции + +Функция КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально() Экспорт + + Значение = Константы.ОграничиватьДоступНаУровнеЗаписейУниверсально.Получить(); + + Если Не Значение И Не ВариантВстроенногоЯзыкаРусский() Тогда + Значение = Истина; + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + МенеджерЗначения = СлужебныйМенеджерЗначения( + Константы.ОграничиватьДоступНаУровнеЗаписейУниверсально); + МенеджерЗначения.Значение = Значение; + МенеджерЗначения.Записать(); + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +// Устанавливает использование регламентного задания ОбновлениеДоступа. +// +// Параметры: +// Использование - Булево - Истина, если задание нужно включить, иначе Ложь. +// БезПроверкиВыполненияОбновленияИБ - Булево +// +Процедура УстановитьОбновлениеДоступа(Использование, БезПроверкиВыполненияОбновленияИБ = Ложь) Экспорт + + Если Использование + И Не БезПроверкиВыполненияОбновленияИБ + И ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда + + Возврат; // После обновления ИБ задание включается безусловно. + КонецЕсли; + + Если Использование Тогда + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(); + Если ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + Если Использование Тогда + ВключитьЗадание = ?(ОбщегоНазначения.ИнформационнаяБазаФайловая(), + ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь, Ложь, Ложь), + ОграничиватьДоступНаУровнеЗаписейУниверсально()); + Иначе + ВключитьЗадание = Ложь; + КонецЕсли; + + Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); + Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); + + ТребуетсяИзменение = Ложь; + Для Каждого Задание Из Задания Цикл + Если ВключитьЗадание <> Задание.Использование Тогда + ТребуетсяИзменение = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Если Не ТребуетсяИзменение Тогда + Возврат; + КонецЕсли; + + Если ВключитьЗадание И ЭтоСеансФоновогоОбновленияДоступа() Тогда + Возврат; + КонецЕсли; + + Если МонопольныйРежим() + Или Не ТранзакцияАктивна() + Или ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + + ИзменитьРегламентноеЗаданиеОбновленияДоступа(ВключитьЗадание); + + ИначеЕсли ВключитьЗадание Тогда + ФоновыеЗадания.Выполнить("УправлениеДоступомСлужебный.ВключитьРегламентноеЗаданиеОбновленияДоступа",,, + НСтр("ru = 'Управление доступом: Включение регламентного задания обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка())); + Иначе + ФоновыеЗадания.Выполнить("УправлениеДоступомСлужебный.ОтключитьРегламентноеЗаданиеОбновленияДоступа",,, + НСтр("ru = 'Управление доступом: Отключение регламентного задания обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка())); + КонецЕсли; + +КонецПроцедуры + +// Возвращает ошибки текстов ограничений доступа объектов без учета зависимостей между объектами. +// Тексты проверяются в режиме максимальных ограничений (как будто включены все виды ограничений). +// Функция должна вызываться перед функцией НастройкиВнедрения, чтобы собрать весь пакет ошибок. +// +// Возвращаемое значение: +// Массив из Структура: +// * ПолноеИмя - Строка - полное имя объекта метаданных. +// * ТекстОшибки - Строка - текст ошибки в ограничении доступа. +// +Функция ОшибкиОграниченийДоступа() Экспорт + + Ошибки = Новый Массив; + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Истина, Ложь); + + Попытка + СпискиСОграничением = УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Списки с ограничением доступа некорректно указаны + |в процедуре %1 + |общего модуля %2 по причине: + | + |%3'"), + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + ОбъектОшибки = "ОбщийМодуль.УправлениеДоступомПереопределяемый"; + Ошибки.Добавить(Новый Структура("ПолноеИмя, ТекстОшибки", ОбъектОшибки, ТекстОшибки)); + Возврат Ошибки; + КонецПопытки; + + ТекстыОшибок = Новый Соответствие; + ОбщийКонтекст.Вставить("СпискиСОграничением", СпискиСОграничением); + ОбщийКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); + + Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + Попытка + ТекстОшибки = ОшибкаОграниченияДоступа(ОбщийКонтекст, ПолноеИмя); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Если ЗначениеЗаполнено(ТекстОшибки) И ТекстыОшибок.Получить(ТекстОшибки) = Неопределено Тогда + ТекстыОшибок.Вставить(ТекстОшибки, Истина); + Ошибки.Добавить(Новый Структура("ПолноеИмя, ТекстОшибки", ПолноеИмя, ТекстОшибки)); + КонецЕсли; + КонецЦикла; + + Возврат Ошибки; + +КонецФункции + +// Возвращает настройки внедрения для инструментов разработчика. +// +// Параметры: +// ДействующиеПараметры - Неопределено - значение по умолчанию. +// - Структура - только для вызова из функции РезультатПроверкиОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ОграниченияВРолях - Структура: +// ** ДляПользователей - Соответствие из КлючИЗначение: +// *** Ключ - Строка - полное имя объекта метаданных (списка). Имя коллекции на английском. +// В форме объекта должна вставка ПриЧтенииНаСервере. +// *** Значение - Структура: +// **** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, +// если Ложь, тогда используется шаблон #ДляРегистра. +// **** Параметры - Массив из Строка - параметры шаблона (для объекта 1, для регистра 6). +// Например, имя поля "Владелец" или опорного поля регистра "Организация". +// ** ДляВнешнихПользователей - Соответствие из КлючИЗначение - как для пользователей выше: +// *** Ключ - Строка - полное имя объекта метаданных (списка). Имя коллекции на английском. +// В форме объекта должна вставка ПриЧтенииНаСервере. +// *** Значение - Структура: +// **** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, +// если Ложь, тогда используется шаблон #ДляРегистра. +// **** Параметры - Массив из Строка - параметры шаблона (для объекта 1, для регистра 6). +// Например, имя поля "Владелец" или опорного поля регистра "Организация". +// +// * ПредопределенныеИдентификаторы - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя требуемого предопределенного элемента справочника +// ИдентификаторыОбъектовМетаданных или ИдентификаторыОбъектовРасширений +// в формате "<ИмяСправочника>.<ИмяПредопределенного>". +// ** Значение - Строка - полное имя соответствующего объекта метаданных. +// +// * ВладельцыЗначенийКлючейДоступа - Структура - для группы определяемых типов: +// ** Ссылки - Массив из Строка - полные имена типов ссылки (имя коллекции на английском). +// ** Документы - Массив из Строка - полные имена типов объекта (имя коллекции на английском). +// ** Объекты - Массив из Строка - то же, что в предыдущем пункте. +// ** НаборыЗаписей - Массив из Строка - то же, что в предыдущем пункте. +// ** НаборыЗаписейРегистраРасчета - Массив из Строка - то же, что в предыдущем пункте. +// +// * ЗначенияДоступа - Массив из Строка - полные имена типов ссылки (имя коллекции на английском). +// Для дополнения определяемого типа ЗначениеДоступа. +// +// * ТипыИзмеренийРегистровКлючей - Соответствие из КлючИЗначение: +// Для измерений с именем Поле регистра КлючиДоступаКРегистрам и регистров КлючиДоступаКРегистру<*>: +// ** Ключ - Строка - имя регистра. +// ** Значение - Структура: +// *** ИменаТипов - Массив из Строка - полные имена типов (на английском). +// *** ПоляРегистров - Соответствие из КлючИЗначение: +// **** Ключ - Строка - полное имя регистра, который ограничивается. +// **** Значение - Массив из Структура: +// ***** Поле - Строка - имя поля регистра. +// ***** Тип - ОписаниеТипов - типы поля регистра. +// Порядок полей в массиве соответствуют +// служебным полям Поле1, Поле2, ... +// *** ПоляРегистровПоТипам - Соответствие из КлючИЗначение: +// **** Ключ - Строка - полное имя типа (на английском). +// **** Значение - Массив из Строка - полные имена полей, например, +// "РегистрСведений.ДополнительныеСведения.Свойство". +// +Функция НастройкиВнедрения(ДействующиеПараметры = Неопределено) Экспорт + + ОграниченияВРолях = Новый Структура; + ОграниченияВРолях.Вставить("ДляПользователей", Новый Соответствие); + ОграниченияВРолях.Вставить("ДляВнешнихПользователей", Новый Соответствие); + + ВладельцыЗначенийКлючейДоступа = Новый Структура; + ВладельцыЗначенийКлючейДоступа.Вставить("Ссылки", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("Документы", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("Объекты", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("НаборыЗаписей", Новый Массив); + ВладельцыЗначенийКлючейДоступа.Вставить("НаборыЗаписейРегистраРасчета", Новый Массив); + + ПредопределенныеИдентификаторы = Новый Соответствие; + ЗначенияДоступа = Новый Массив; + ТипыИзмеренийРегистровКлючей = Новый Соответствие; + ТипыИзмеренийРегистраКлючей(ТипыИзмеренийРегистровКлючей, "КлючиДоступаКРегистрам"); + + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + ЗначенияДоступа.Добавить(ИмяТипаСсылкиXML(Метаданные.Справочники.КлючиДоступа.ПолноеИмя(), ТипыТаблицПоИменам)); + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + Для Каждого ОписаниеВозможныхПрав Из ВозможныеПрава.ПоПолнымИменам Цикл + ЗначенияДоступа.Добавить(ИмяТипаСсылкиXML(ОписаниеВозможныхПрав.Ключ, ТипыТаблицПоИменам)); + КонецЦикла; + + Если ДействующиеПараметры = Неопределено Тогда + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Истина); + НовыеХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст); + ДействующиеПараметры = Новый Структура(НовыеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); // см. НоваяСтруктураХранимыхПараметровЗаписи + КонецЕсли; + + Контекст = Новый Структура; + Контекст.Вставить("ПредопределенныеИдентификаторы", ПредопределенныеИдентификаторы); + Контекст.Вставить("ТипыИзмеренийРегистровКлючей", ТипыИзмеренийРегистровКлючей); + Контекст.Вставить("ТипыТаблицПоИменам", ТипыТаблицПоИменам); + + ДобавленныеСписки = Новый Соответствие; + Для Каждого ОписаниеВерсии Из ДействующиеПараметры.ВерсииОграниченийСписков Цикл + ПолноеИмя = ОписаниеВерсии.Ключ; + ПолноеИмяXML = ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам); + ИмяТипаСсылкиXML = ИмяТипаСсылкиXML(ПолноеИмя, ТипыТаблицПоИменам); + ИмяТипаОбъектаXML = ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам); + + Если ЗначениеЗаполнено(ИмяТипаСсылкиXML) Тогда + ВладельцыЗначенийКлючейДоступа.Ссылки.Добавить(ИмяТипаСсылкиXML); + КонецЕсли; + + ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа); + ДобавленныеСписки.Вставить(ВРег(ПолноеИмя), Истина); + + Если ОписаниеВерсии.Значение = Неопределено Тогда + Продолжить; + КонецЕсли; + + ДобавитьОграниченияВРолях(ПолноеИмяXML, + ПолноеИмя, + ОграниченияВРолях.ДляПользователей, + ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков, + Контекст); + + ДобавитьОграниченияВРолях(ПолноеИмяXML, + ПолноеИмя, + ОграниченияВРолях.ДляВнешнихПользователей, + ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков, + Контекст); + КонецЦикла; + + Для Каждого ВедущийСписок Из ДействующиеПараметры.ВедущиеСписки Цикл + ПолноеИмя = ВедущийСписок.Ключ; + Если ДобавленныеСписки.Получить(ВРег(ПолноеИмя)) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ИмяТипаОбъектаXML = ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам); + ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа); + КонецЦикла; + + Настройки = Новый Структура; + Настройки.Вставить("ОграниченияВРолях", ОграниченияВРолях); + Настройки.Вставить("ПредопределенныеИдентификаторы", ПредопределенныеИдентификаторы); + Настройки.Вставить("ВладельцыЗначенийКлючейДоступа", ВладельцыЗначенийКлючейДоступа); + Настройки.Вставить("ЗначенияДоступа", ЗначенияДоступа); + Настройки.Вставить("ТипыИзмеренийРегистровКлючей", ТипыИзмеренийРегистровКлючей); + + Возврат Настройки; + +КонецФункции + +// Возвращает результат проверки ограничения доступа для инструмента разработчика. +// +// Параметры: +// ПолноеИмя - Строка - полное имя объекта метаданных. +// ДополнительныеПараметры - Неопределено - проверить и вернуть текущее ограничение. +// - Структура: +// * Текст - Строка - новый текст ограничения для пользователей. +// * ТекстДляВнешнихПользователей - Строка - новый текст ограничения для внешних пользователей. +// * УчитыватьЗависимости - Булево - учитывать зависимости между ограничениями объектов. +// * ВсеВидыДоступаИспользуются - Неопределено - вычислить по текущим настройками. +// - Булево - Истина (по умолчанию) - используются все, +// Ложь - не используется ни одного. +// +// Возвращаемое значение: +// Структура: +// * ОшибкаОписанияОграничения - Строка - если не пустая, то описание ограничения не удалось получить. +// Если при этом УчитыватьЗависимости = Истина, то это текст первой ошибки при получении всех описаний. +// +// * ТекстВМодулеМенеджера - Неопределено - когда заполнена ОшибкаОписанияОграничения. +// - Булево - возвращает место размещения текста ограничения, +// когда Истина - в модуле менеджера, иначе в переопределяемом модуле. +// +// * ДляПользователей - Структура: +// ** ПроверяемоеОграничение - Неопределено +// - Строка - проверенный текст ограничения. +// ** ОписаниеОшибок - см. ОписаниеОшибок +// ** ОшибкаФормированияПараметровОграничения - Неопределено +// - Строка - текст ошибки. +// ** ОшибкаФормированияТекстовЗапросов - Неопределено +// - Строка - текст ошибки. +// ** ОграничениеПоВладельцуВозможно - Неопределено +// - Булево - свойство проверенного ограничения. +// ** ОграничениеПоВладельцуИспользуется - Неопределено +// - Булево - когда УчитыватьЗависимости указано Истина. +// ** ОграниченияВРолях - Неопределено +// - Структура: +// *** ШаблонДляОбъекта - Булево - если Истина, тогда используется шаблон #ДляОбъекта, +// если Ложь, тогда используется шаблон #ДляРегистра. +// *** Параметры - Массив - параметры шаблона (для объекта 1, для регистра 6): +// **** Значение - Строка - например, имя поля "Владелец" или +// опорного поля регистра "Организация". +// ** ОграничениеВМодуле - Неопределено +// - Строка - текст ограничения, который установлен в конфигурации. +// ** ПоВладельцуБезЗаписиКлючейДоступа - Неопределено +// - Булево - настройка ограничения, +// установленная в конфигурации. +// +// * ДляВнешнихПользователей - Структура - со свойствами, как ДляПользователей. +// +// * ВладелецЗначенийКлючейДоступа - Строка - типы для одноименного определяемого типа. +// * ВладелецЗначенийКлючейДоступаОбъект - Строка - типы для одноименного определяемого типа. +// * ВладелецЗначенийКлючейДоступаНаборЗаписей - Строка - типы для одноименного определяемого типа. +// * ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета - Строка - типы для одноименного определяемого типа. +// * ПолеРегистраКлючейДоступаКРегистрам - Строка - типы для одноименного определяемого типа. +// * ЗначениеДоступа - Строка - типы для одноименного определяемого типа. +// +// * ТипыИзмеренийОтдельногоРегистраКлючей - Неопределено +// - Структура: +// ** ИмяРегистраСведений - Строка - имя регистра ключей доступа. +// ** ТипыИзмерений - Строка - типы для соответствующих измерений регистра. +// +// * ПредопределенныйИдентификатор - Неопределено +// - Структура: +// ** ИмяСправочника - Строка - имя справочника идентификаторы объектов метаданных (или расширений). +// ** ИмяПредопределенного - Строка - имя предопределенного в справочнике. +// +Функция РезультатПроверкиОграниченияДоступа(ПолноеИмя, ДополнительныеПараметры = Неопределено) Экспорт + + Возврат РезультатПроверкиОграниченияДоступаОбъекта(ПолноеИмя, ДополнительныеПараметры); + +КонецФункции + +// Добавляет обновление доступа для указанных списков или всех списков. +// +// Параметры: +// Списки - Неопределено - запланировать полное обновление доступа. +// - Строка - полное имя объекта метаданных. +// - СправочникСсылка.ИдентификаторыОбъектовМетаданных - идентификатор. +// - Массив +// - ФиксированныйМассив - значения типов указанные выше, кроме Неопределено. +// +// ПараметрыПланирования - см. ПараметрыПланированияОбновленияДоступа +// +Процедура ЗапланироватьОбновлениеДоступа(Списки = Неопределено, ПараметрыПланирования = Неопределено) Экспорт + + Если ПараметрыПланирования = Неопределено Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Не ПараметрыПланирования.КлючиДоступаКДанным + И Не ПараметрыПланирования.РазрешенныеКлючиДоступа Тогда + + Возврат; + КонецЕсли; + + ИдентификаторыРегистров = Новый Массив; + ИдентификаторыСписковКлючей = Новый Массив; + + Если Списки = Неопределено Тогда + Если ПараметрыПланирования.ВерсииОграниченийСписков = Неопределено Тогда + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + ВерсииОграниченийСписков = Новый Соответствие(ДействующиеПараметры.ВерсииОграниченийСписков); + Иначе + ВерсииОграниченийСписков = Новый Соответствие(Новый ФиксированноеСоответствие( + ПараметрыПланирования.ВерсииОграниченийСписков)); + КонецЕсли; + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("РазрешенныйКлючДоступа", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа()); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) КАК ТипСсылки + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаКДанным.Регистр КАК Регистр + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКДанным + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступа.Список КАК Список + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Ссылка <> &РазрешенныйКлючДоступа"; + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + ИдентификаторыРегистров = РезультатыЗапроса[1].Выгрузить().ВыгрузитьКолонку("Регистр"); + ИдентификаторыСписковКлючей = РезультатыЗапроса[2].Выгрузить().ВыгрузитьКолонку("Список"); + + Выборка = РезультатыЗапроса[0].Выбрать(); + ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповСсылокДопустимыхОбъектов(); + ЕстьНедопустимыйТип = Ложь; + Пока Выборка.Следующий() Цикл + Если ТипЗнч(Выборка.ТипСсылки) <> Тип("Тип") Тогда + Продолжить; + ИначеЕсли Выборка.ТипСсылки = Тип("Неопределено") + Или Не ДопустимыеТипы.СодержитТип(Выборка.ТипСсылки) Тогда + ЕстьНедопустимыйТип = Истина; + Продолжить; + КонецЕсли; + ОбъектМетаданных = Метаданные.НайтиПоТипу(Выборка.ТипСсылки); + Если ОбъектМетаданных = Неопределено Тогда + Продолжить; + КонецЕсли; + ВерсииОграниченийСписков.Вставить(ОбъектМетаданных.ПолноеИмя(), Истина); + КонецЦикла; + ВерсииОграниченийСписков.Вставить("Справочник.НаборыГруппДоступа", Истина); + Если ЕстьНедопустимыйТип Тогда + ИдентификаторыРегистров.Добавить(Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка()); + КонецЕсли; + + СпискиДляОбновления = Новый Массив; + Для Каждого КлючИЗначение Из ВерсииОграниченийСписков Цикл + СпискиДляОбновления.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + + // При планировании полного обновления добавляются: + // а) списки с ограничением, + // б) списки, которые пишут ключи доступа для ограничений по полю-владельцу, + // в) списки без ограничения, для которых есть записи в регистрах ключей доступа к данным, + // в) списки, для которых рассчитываются разрешенные ключи доступа, + // г) списки без расчета разрешенных ключей доступа, для которых есть записи в регистрах + // разрешенных ключей доступа. + + ИначеЕсли ТипЗнч(Списки) <> Тип("Массив") + И ТипЗнч(Списки) <> Тип("ФиксированныйМассив") Тогда + + СпискиДляОбновления = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Списки); + Иначе + СпискиДляОбновления = Списки; + КонецЕсли; + + Если СпискиДляОбновления.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + СпискиПоИдентификаторам = Новый Соответствие; + Если ТипЗнч(СпискиДляОбновления[0]) = Тип("Строка") Тогда + ИдентификаторыСписков = ?(ПараметрыПланирования.ИдентификаторыВсехСписков = Неопределено, + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(СпискиДляОбновления, Списки <> Неопределено), + ПараметрыПланирования.ИдентификаторыВсехСписков); + Для Каждого ПолноеИмя Из СпискиДляОбновления Цикл + Идентификатор = ИдентификаторыСписков.Получить(ПолноеИмя); + Если Идентификатор <> Неопределено И Идентификатор <> Null Тогда + СпискиПоИдентификаторам.Вставить(Идентификатор, ПолноеИмя); + ИначеЕсли Списки <> Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не найден идентификатор объекта метаданных ""%1"".'"), ПолноеИмя); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого Идентификатор Из СпискиДляОбновления Цикл + СпискиПоИдентификаторам.Вставить(Идентификатор, ""); + КонецЦикла; + КонецЕсли; + + Если ЗначениеЗаполнено(ИдентификаторыРегистров) + Или ЗначениеЗаполнено(ИдентификаторыСписковКлючей) Тогда + + Для Каждого ИдентификаторРегистра Из ИдентификаторыРегистров Цикл + Если ИдентификаторРегистра = Неопределено Тогда + СпискиПоИдентификаторам.Вставить( + Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка(), ""); + КонецЕсли; + СпискиПоИдентификаторам.Вставить(ИдентификаторРегистра, ""); + КонецЦикла; + Для Каждого ИдентификаторРазрешенных Из ИдентификаторыСписковКлючей Цикл + СпискиПоИдентификаторам.Вставить(ИдентификаторРазрешенных, ""); + КонецЦикла; + КонецЕсли; + + ИдентификаторСправочникаНаборыГруппДоступа = + СлужебныйИдентификатор("Справочник.НаборыГруппДоступа"); + + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + КлючУникальностиЗаписей = Новый УникальныйИдентификатор; + + ЭтоТочечноеЗадание = Ложь; + ПараметрыЗадания = Новый Структура; + РазмерЗадания = 3; + + Если ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов Тогда + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + УстановитьВидКлючаДанных(ПараметрыЗадания, "УстаревшиеЭлементы"); + ДатаПоследнегоОбновленногоЭлемента = '00010101'; + РазмерЗадания = 2; + Иначе + ВедущийОбъект = ПараметрыПланирования.ВедущийОбъект; // См. ОписаниеВедущегоОбъекта + Если ВедущийОбъект <> Неопределено + И Не ( ВедущийОбъект.Свойство("ПоДаннымКэшаРасчетаПрав") + Или ВедущийОбъект.Свойство("ПоКлючамДоступа") + Или ВедущийОбъект.Свойство("ПоЗначениямСГруппами") + Или ВедущийОбъект.Свойство("ПоЗначениямПолей") + И ТипЗнч(ВедущийОбъект.ПоЗначениямПолей.СоставИзменений) = Тип("ТаблицаЗначений") ) Тогда + ВедущийОбъект = Неопределено; + КонецЕсли; + Если ВедущийОбъект <> Неопределено Тогда + ЭтоТочечноеЗадание = Истина; + ПараметрыПланирования = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыПланирования)); + ПараметрыПланирования.Вставить("ЭтоТочечноеЗадание"); + РазмерЗадания = 1; + ПараметрыЗадания.Вставить("ТочечноеЗадание", ВедущийОбъект); + КонецЕсли; + ДатаПоследнегоОбновленногоЭлемента = ?(ПараметрыПланирования.ЭтоПродолжениеОбновления, + МаксимальнаяДатаПриПродолжении(), МаксимальнаяДата()); + КонецЕсли; + Если ПараметрыЗадания.Количество() = 0 Тогда + ПараметрыЗадания = Неопределено; + КонецЕсли; + ХранилищеПараметровЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); + + ОбновлениеКлючейДоступаКДанным = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + ОбновлениеКлючейДоступаПользователей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаПользователей); + + Для Каждого ОписаниеСписка Из СпискиПоИдентификаторам Цикл + ИдентификаторСписка = ОписаниеСписка.Ключ; + + Если ПараметрыПланирования.КлючиДоступаКДанным Тогда + Если ПараметрыПланирования.ДляПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаКДанным.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = ДатаПоследнегоОбновленногоЭлемента; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + Если ПараметрыПланирования.ДляВнешнихПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаКДанным.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Истина; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = ДатаПоследнегоОбновленногоЭлемента; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + КонецЕсли; + + Если ИдентификаторСписка = ИдентификаторСправочникаНаборыГруппДоступа Тогда + Продолжить; + КонецЕсли; + + Если ПараметрыПланирования.РазрешенныеКлючиДоступа Тогда + Если ПараметрыПланирования.ДляПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаПользователей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + Если ПараметрыПланирования.ДляВнешнихПользователей Тогда + НоваяЗапись = ОбновлениеКлючейДоступаПользователей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальностиЗаписей; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Истина; + НоваяЗапись.ТочечноеЗадание = ЭтоТочечноеЗадание; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = РазмерЗадания; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + + Если ОбновлениеКлючейДоступаКДанным.Количество() > 0 Тогда + ОбновлениеКлючейДоступаКДанным.Записать(Ложь); + КонецЕсли; + + Если ОбновлениеКлючейДоступаПользователей.Количество() > 0 Тогда + ОбновлениеКлючейДоступаПользователей.Записать(Ложь); + КонецЕсли; + + ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, + ПараметрыПланирования, Списки = Неопределено); + + Если ОбновлениеКлючейДоступаКДанным.Количество() > 0 + Или ОбновлениеКлючейДоступаПользователей.Количество() > 0 Тогда + + УстановитьОбновлениеДоступа(Истина); + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Конструктор структуры дополнительных параметров для процедуры ЗапланироватьОбновлениеДоступа. +// +// Возвращаемое значение: +// Структура: +// * КлючиДоступаКДанным - Булево - по умолчанию Истина - запланировать обновление ключей доступа +// к данным. +// * РазрешенныеКлючиДоступа - Булево - по умолчанию Истина - запланировать обновление ключей доступа +// пользователей и групп доступа. +// * ДляПользователей - Булево - по умолчанию Истина - запланировать обновление для пользователей. +// * ДляВнешнихПользователей - Булево - по умолчанию значение константы ИспользоватьВнешнихПользователей +// запланировать обновление для внешних пользователей. +// +Функция ПараметрыПланированияОбновленияДоступа(ВычислитьДляВнешнихПользователей = Истина) Экспорт + + ДляВнешнихПользователей = ?(ВычислитьДляВнешнихПользователей, + Константы.ИспользоватьВнешнихПользователей.Получить(), Истина); + + Результат = Новый Структура; + Результат.Вставить("КлючиДоступаКДанным", Истина); + Результат.Вставить("РазрешенныеКлючиДоступа", Истина); + Результат.Вставить("ДляПользователей", Истина); + Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Результат.Вставить("ВедущийОбъект", Неопределено); + Результат.Вставить("ВерсииОграниченийСписков", Неопределено); + Результат.Вставить("ИдентификаторыВсехСписков", Неопределено); + Результат.Вставить("Описание", ""); + Результат.Вставить("ЭтоПродолжениеОбновления", Ложь); + Результат.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); + + Возврат Результат; + +КонецФункции + +// Параметры: +// Описание - Строка - имя процедуры, которая вызвала планирование, +// используемое для расширенной регистрации в журнале. +// ЗапуститьОбновление - Булево - если Истина, то планирование будет +// негарантированным, так как при наличии транзакции +// выполняется в фоне "как есть" для возможности запуска обновления. +// +Процедура ЗапланироватьОбновлениеПараметровОграниченияДоступа(Описание, ЗапуститьОбновление = Ложь) Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Возврат; + КонецЕсли; + + Если Не ТранзакцияАктивна() Или Не ЗапуститьОбновление Тогда + ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа(Описание, ЗапуститьОбновление); + Возврат; + КонецЕсли; + + ПараметрыПроцедуры = Новый Массив; + ПараметрыПроцедуры.Добавить(Описание); + ПараметрыПроцедуры.Добавить(ЗапуститьОбновление); + + ФоновыеЗадания.Выполнить( + "УправлениеДоступомСлужебный.ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа", + ПараметрыПроцедуры,, НСтр("ru = 'Управление доступом: планирование обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка())); + +КонецПроцедуры + +// Только для процедуры ЗапланироватьОбновлениеПараметровОграниченияДоступа. +Процедура ЗаписатьПланированиеОбновленияПараметровОграниченияДоступа(Описание, ЗапуститьОбновление) Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Возврат; + КонецЕсли; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.Описание = Описание; + + Идентификатор = СлужебныйИдентификатор("РегистрСведений.ПараметрыОграниченияДоступа"); + Если Идентификатор <> Null Тогда + ЗапланироватьОбновлениеДоступа(Идентификатор, ПараметрыПланирования); + Если ЗапуститьОбновление Тогда + ЗапуститьОбновлениеДоступа(); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Запускает обновление доступа, если оно запланировано и еще не запущено. +Процедура ЗапуститьОбновлениеДоступа() Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь) + Или МонопольныйРежим() + Или ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(Истина) + И Не ЕстьЗапланированныеТочечныеЗадания() Тогда + Возврат; + КонецЕсли; + + ЗапуститьОбновлениеДоступаНаУровнеЗаписей(,, Истина); + +КонецПроцедуры + +// Только для внутреннего использования. +Процедура ОбновитьДоступПослеОбновленияИнформационнойБазы(ВыполнитьОтложенноеОбновлениеСейчас) Экспорт + + Если ОбщегоНазначения.РазделениеВключено() + И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + Если ВыполнитьОтложенноеОбновлениеСейчас + И ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + + ВыполнитьОбновлениеДоступаНаУровнеЗаписей(Истина, Ложь, 0, Истина); + КонецЕсли; + +КонецПроцедуры + +// Для функции ПраваРолейРасширений и функции ЗаполнитьВсеПараметрыРаботыРасширений +// модуля менеджера регистра сведений ПараметрыРаботыВерсийРасширений. +// +Процедура УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Включить) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; + ИмяСвойства = "ЗаписьПараметровОграниченияДоступаВТекущемСеансе"; + + Если Не Включить И Не ТекущиеПараметры.Свойство(ИмяСвойства) Тогда + Возврат; + КонецЕсли; + + НовыеПараметры = Новый Структура(ТекущиеПараметры); + + Если Включить Тогда + Если Не НовыеПараметры.Свойство(ИмяСвойства) Тогда + НовыеПараметры.Вставить(ИмяСвойства, 0); + КонецЕсли; + НовыеПараметры[ИмяСвойства] = НовыеПараметры[ИмяСвойства] + 1; + Иначе + НовыеПараметры[ИмяСвойства] = НовыеПараметры[ИмяСвойства] - 1; + Если НовыеПараметры[ИмяСвойства] < 1 Тогда + НовыеПараметры.Удалить(ИмяСвойства); + КонецЕсли; + КонецЕсли; + + ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(НовыеПараметры); + + УстановитьПривилегированныйРежим(Ложь); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытийПодсистемКонфигурации + +// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами. +Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт + Объекты.Вставить(Метаданные.Справочники.ГруппыДоступа.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке"); + Объекты.Вставить(Метаданные.Справочники.ПрофилиГруппДоступа.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке"); +КонецПроцедуры + +// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса. +Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт + + Обработчики.Вставить("ОграничениеДоступаНаУровнеЗаписейИспользуется", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВидыДоступаБезГруппДляЗначенияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВидыДоступаСОднойГруппойДляЗначенияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВидыДоступаСОтключеннымИспользованием", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВсеВидыДоступаКромеСпециальных", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТаблицыСОтдельнымиНастройкамиПрав", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТипыЗначенийДоступаСГруппами", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТипыВладельцевНастроекПрав", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ТаблицыРасширенийСОграничениемДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + +#Область УниверсальноеОграничение + + Обработчики.Вставить("ОграничениеДоступаНаУровнеЗаписейУниверсально", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ОтключениеОбновленияКлючейДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ВерсииШаблоновОграниченияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйНаборГруппДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйПустойНаборГруппДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйНаборГруппПользователей", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("РазрешенныйПользователь", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ОбщиеПараметрыШаблоновОграниченияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОграничениемПоПолям", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОграничениемЧерезКлючиДоступаПользователей", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("СпискиСОтключеннымОграничениемЧтения", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + + Обработчики.Вставить("ПараметрыОграниченияДоступа", + "УправлениеДоступомСлужебный.УстановкаПараметровСеанса"); + +#КонецОбласти + +КонецПроцедуры + +// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий +Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт + + Настройка = Настройки.Добавить(); + Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа; + Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ОграничиватьДоступНаУровнеЗаписей; + + Настройка = Настройки.Добавить(); + Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей; + Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ОграничиватьДоступНаУровнеЗаписейУниверсально; + +КонецПроцедуры + +// Обновляет вспомогательные данные, которые зависят только от конфигурации. +// Записывает изменения этих данных по версиям конфигурации(если изменения есть), +// чтобы использовать эти изменения при обновлении остальных вспомогательных данных, +// например, в обработчике ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации. +// +Процедура ОбновитьПараметрыОграниченияДоступа(ЕстьИзменения = Неопределено) Экспорт + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". + РегистрыСведений.ПраваРолей.ОбновитьДанныеРегистра(ЕстьИзменения); + + // ЗависимостиПравДоступа + РегистрыСведений.ЗависимостиПравДоступа.ОбновитьДанныеРегистра(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". + ОбновитьОписаниеСвойствВидовДоступа(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". + РегистрыСведений.НастройкиПравОбъектов.ОбновитьВозможныеПраваДляНастройкиПравОбъектов(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". + Справочники.ПрофилиГруппДоступа.ОбновитьОписаниеПоставляемыхПрофилей(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". + Справочники.ПрофилиГруппДоступа.ОбновитьСоставПредопределенныхПрофилей(ЕстьИзменения); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". + РегистрыСведений.ПараметрыОграниченияДоступа.ОбновитьВерсиюТекстовОграниченияДоступа(ЕстьИзменения); + +КонецПроцедуры + +// Обновляет описание свойств видов доступа в параметрах работы программы. +// +// Параметры: +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +Процедура ОбновитьОписаниеСвойствВидовДоступа(ЕстьИзменения = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); + НовоеЗначение = Кэш.ХешСуммы; + + НачатьТранзакцию(); + Попытка + ЕстьТекущиеИзменения = Ложь; + СтароеЗначение = Неопределено; + + СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы( + "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа", + НовоеЗначение, ЕстьТекущиеИзменения, СтароеЗначение); + + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + + ЕстьИзмененияТиповГруппИЗначенийДоступа = + НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа + <> СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа; + + СтандартныеПодсистемыСервер.ДобавитьИзмененияПараметраРаботыПрограммы( + "СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа", + ?(ЕстьИзмененияТиповГруппИЗначенийДоступа, + Новый ФиксированнаяСтруктура("ЕстьИзменения", Истина), + Новый ФиксированнаяСтруктура()) ); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЕстьТекущиеИзменения Тогда + ЕстьИзменения = Истина; + КонецЕсли; + +КонецПроцедуры + +// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления. +Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт + + // Обработчики обновления неразделенных данных. + Обработчик = Обработчики.Добавить(); + Обработчик.ОбщиеДанные = Истина; + Обработчик.УправлениеОбработчиками = Истина; + Обработчик.Приоритет = 1; + Обработчик.Версия = "*"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ЗаполнитьОбработчикиРазделенныхДанных"; + + // Обработчики обновления разделенных данных. + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "*"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации"; + + // Должен выполнятся после обработчика ЗаполнитьИдентификаторыПоставляемыхДанных. + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "1.0.0.1"; + Обработчик.НачальноеЗаполнение = Истина; + Обработчик.Процедура = "Справочники.ГруппыДоступа.ЗаполнитьПрофильГруппыДоступаАдминистраторы"; + Обработчик.РежимВыполнения = "Монопольно"; + Обработчик.ВыполнятьВГруппеОбязательных = Истина; + Обработчик.Приоритет = 1; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "2.4.1.1"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьДанныеПрофиляОткрытиеВнешнихОтчетовИОбработок"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.ВыполнятьВГруппеОбязательных = Истина; + Обработчик.Приоритет = 1; + + Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда + Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика(); + НоваяСтрока = Обработчик.ПриоритетыВыполнения.Добавить(); + НоваяСтрока.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + НоваяСтрока.Порядок = "До"; + КонецЕсли; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.1.3.135"; + Обработчик.Процедура = "РегистрыСведений.ГруппыЗначенийДоступа.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + Обработчик.РежимВыполнения = "Отложенно"; + Обработчик.Комментарий = НСтр("ru = 'Обновление вспомогательных данных.'"); + Обработчик.Идентификатор = Новый УникальныйИдентификатор("b3cb643e-d5cf-40b7-9db3-6315a88c063d"); + Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.ГруппыЗначенийДоступа.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; + Обработчик.ЧитаемыеОбъекты = "РегистрСведений.ГруппыЗначенийДоступа"; + Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ГруппыЗначенийДоступа"; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.0.2.174"; + Обработчик.Процедура = "РегистрыСведений.НастройкиПравОбъектов.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + Обработчик.РежимВыполнения = "Отложенно"; + Обработчик.Комментарий = НСтр("ru = 'Обновление вспомогательных данных настроек прав.'"); + Обработчик.Идентификатор = Новый УникальныйИдентификатор("40d1c62f-c3f1-4608-8985-2dc618c3d758"); + Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.НастройкиПравОбъектов.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; + Обработчик.ЧитаемыеОбъекты = "РегистрСведений.НастройкиПравОбъектов"; + Обработчик.ИзменяемыеОбъекты = "РегистрСведений.НастройкиПравОбъектов"; + + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.1.10.80"; + Обработчик.Процедура = "Справочники.ГруппыДоступа.ОбработатьДанныеДляПереходаНаНовуюВерсию"; + Обработчик.РежимВыполнения = "Отложенно"; + Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = Истина; + Обработчик.Комментарий = НСтр("ru = 'Удаляет служебных пользователей из групп доступа.'"); + Обработчик.Идентификатор = Новый УникальныйИдентификатор("4795e622-6115-4abc-a8de-cf2e838b7ea2"); + Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы"; + Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ГруппыДоступа.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию"; + Обработчик.ЧитаемыеОбъекты = "Справочник.ГруппыДоступа"; + Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ТаблицыГруппДоступа,РегистрСведений.ЗначенияГруппДоступа,РегистрСведений.ЗначенияГруппДоступаПоУмолчанию"; + + // Должен выполнятся до прикладных обработчиков обновления. + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "3.1.11.49"; + Обработчик.Процедура = "РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.ВыполнятьВГруппеОбязательных = Истина; + Обработчик.Приоритет = 1; + +КонецПроцедуры + +// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек +// +// Параметры: +// Объекты - Массив из ОбъектМетаданных +// +Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт + + Объекты.Добавить(Метаданные.Справочники.ПрофилиГруппДоступа); + Объекты.Добавить(Метаданные.Справочники.ГруппыДоступа); + +КонецПроцедуры + +// См. ОбновлениеИнформационнойБазыБСП.ПослеОбновленияИнформационнойБазы. +Процедура ПослеОбновленияИнформационнойБазы(Знач ПредыдущаяВерсия, Знач ТекущаяВерсия, + Знач ВыполненныеОбработчики, ВыводитьОписаниеОбновлений, МонопольныйРежим) Экспорт + + Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); + + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); + УстановитьОбновлениеДоступа(Истина, Истина); + +КонецПроцедуры + +// См. ОбновлениеИнформационнойБазыПереопределяемый.ПриЗаполненииОбъектовПланируемыхКУдалению. +Процедура ПриЗаполненииОбъектовПланируемыхКУдалению(Объекты) Экспорт + + // РегистрСведений.ЗависимостиПравДоступа.ТипВедущейТаблицы + ЗависимостиПравДоступа = РегистрыСведений.ЗависимостиПравДоступа.ЗависимостиПравДоступа(); + ТипыВедущихТаблиц = Новый Массив; + Для Каждого Строка Из ЗависимостиПравДоступа Цикл + ТипыВедущихТаблиц.Добавить(ТипЗнч(Строка.ТипВедущейТаблицы)); + КонецЦикла; + ТребуемыйТипВедущейТаблицы = Новый ОписаниеТипов(ТипыВедущихТаблиц); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВедущейТаблицы, + Метаданные.РегистрыСведений.ЗависимостиПравДоступа.Измерения.ТипВедущейТаблицы); + + Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + НастройкиВнедрения = НастройкиВнедрения(); + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + СлужебныеТипы = Новый Массив; + СлужебныеТипы.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + СлужебныеТипы.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + СлужебныеТипы.Добавить(Тип("ПеречислениеСсылка.ДополнительныеЗначенияДоступа")); + + // ОпределяемыйТип.ЗначениеДоступа + ТипыГруппИЗначений = Новый Массив; + Для Каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамГруппИЗначений Цикл + ТипыГруппИЗначений.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов( + СтрСоединить(НастройкиВнедрения.ЗначенияДоступа, ",")); + ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов(ТребуемыйТипЗначенияДоступа, ТипыГруппИЗначений); + ТребуемыйТипЗначенияДоступа = Новый ОписаниеТипов(ТребуемыйТипЗначенияДоступа, СлужебныеТипы); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ЗначенияГруппДоступа.Измерения.ЗначениеДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию.Измерения.ТипЗначенийДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ГруппыЗначенийДоступа.Измерения.ЗначениеДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ГруппыЗначенийДоступа.Измерения.ГруппаЗначенийДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ИспользуемыеВидыДоступа.Измерения.ТипЗначенийДоступа); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.ИспользуемыеВидыДоступаПоТаблицам.Измерения.ТипЗначенийДоступа); + + // ОпределяемыйТип.ВладелецНастроекПрав + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ТипыВладельцевНастроекПрав = Новый Массив; + Для Каждого ВладелецПрав Из ВозможныеПрава.ТипыВладельцев Цикл + ТипыВладельцевНастроекПрав.Добавить(ТипЗнч(ВладелецПрав)); + КонецЦикла; + ТребуемыйТипВладельцаНастроекПрав = Новый ОписаниеТипов(ТипыВладельцевНастроекПрав); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, + Метаданные.РегистрыСведений.НастройкиПравОбъектов.Измерения.Объект); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, + Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.Измерения.Объект); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипВладельцаНастроекПрав, + Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.Измерения.Родитель); + + // ОпределяемыйТип.ВладелецЗначенийКлючейДоступа + ДобавитьОбъектПланируемыйКУдалению(Объекты, + Новый ОписаниеТипов(СтрСоединить(НастройкиВнедрения.ВладельцыЗначенийКлючейДоступа.Ссылки, ",")), + Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект); + + // ОпределяемыйТип.ПолеРегистраКлючейДоступаКРегистрам + Для Каждого ОписаниеРегистровКлючей Из НастройкиВнедрения.ТипыИзмеренийРегистровКлючей Цикл + ИмяРегистраКлючей = ОписаниеРегистровКлючей.Ключ; + МетаданныеРегистраКлючей = Метаданные.РегистрыСведений[ИмяРегистраКлючей]; + КоличествоПолей = УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистраКлючей); + ТребуемыйТипПоля = Новый ОписаниеТипов(СтрСоединить(ОписаниеРегистровКлючей.Значение.ИменаТипов, ",")); + ТребуемыйТипПоля = Новый ОписаниеТипов(ТребуемыйТипПоля, СлужебныеТипы); + Для НомерПоля = 1 По КоличествоПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипПоля, + МетаданныеРегистраКлючей.Измерения[ИмяПоля]); + КонецЦикла; + КонецЦикла; + + // РегистрСведений.НаборыЗначенийДоступа.Объект + ТипыОбъектовПодписок = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа"); + ТипыСсылокОбъектовПодписок = Новый Массив; + Для Каждого КлючИЗначение Из ТипыОбъектовПодписок Цикл + МетаданныеОбъекта = Метаданные.НайтиПоТипу(КлючИЗначение.Ключ); + МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъекта.ПолноеИмя()); + ПустаяСсылка = МенеджерОбъекта.ПустаяСсылка(); + ТипыСсылокОбъектовПодписок.Добавить(ТипЗнч(ПустаяСсылка)); + КонецЦикла; + ТребуемыйТипТаблицСЗаписьюНаборовЗначенийДоступа = Новый ОписаниеТипов( + Новый ОписаниеТипов(ТипыСсылокОбъектовПодписок),, СлужебныеТипы); + + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипТаблицСЗаписьюНаборовЗначенийДоступа, + Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект); + + // РегистрСведений.НаборыЗначенийДоступа.ЗначениеДоступа + ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыйТипЗначенияДоступа, + Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.ЗначениеДоступа); + +КонецПроцедуры + +// Параметры: +// ИзменениеЯзыков - см. МультиязычностьСервер.ОписаниеСтарыхИНовыхНастроекЯзыков +// +Процедура ПриИзмененииЯзыкаИнформационнойБазы(ИзменениеЯзыков) Экспорт + + Справочники.ПрофилиГруппДоступа.ПриИзмененииЯзыкаИнформационнойБазы(ИзменениеЯзыков); + +КонецПроцедуры + +// Заполняет структуру параметров, необходимых для работы клиентского кода +// конфигурации. +// +// Параметры: +// Параметры - Структура - структура параметров. +// +Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт + + Параметры.Вставить("УпрощенныйИнтерфейсНастройкиПравДоступа", + УпрощенныйИнтерфейсНастройкиПравДоступа()); + +КонецПроцедуры + +// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок. +Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт + + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ГруппыЗначенийДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗависимостиПравДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗначенияГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.НаборыЗначенийДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ПраваРолей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ТаблицыГруппДоступа); + + ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(ИсключенияПоискаСсылок); + +КонецПроцедуры + +// Объекты с отложенным удалением. +// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок +// +// Параметры: +// ИсключенияПоискаСсылок - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.ИсключенияПоискаСсылок +// +Процедура ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(ИсключенияПоискаСсылок) Экспорт + + ИсключенияПоискаСсылок.Добавить(Метаданные.Справочники.КлючиДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.Справочники.НаборыГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаВнешнихПользователей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаКОбъектам); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаКРегистрам); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.КлючиДоступаПользователей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ОбновлениеКлючейДоступаПользователей); + ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа); + + Для Каждого РегистрСведений Из Метаданные.РегистрыСведений Цикл + Если СтрНачинаетсяС(ВРег(РегистрСведений.Имя), ВРег("КлючиДоступаКРегистру")) Тогда + ИсключенияПоискаСсылок.Добавить(РегистрСведений); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Вызывается при загрузке ссылок предопределенных элементов в процессе загрузки важных данных. +// Позволяет выполнить действия по исправлению или регистрации сведений о не уникальности +// предопределенных элементов, а также позволяет отказаться от продолжения, если это недопустимо. +// +// Параметры: +// Объект - СправочникОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект - +// объект предопределенного элемента после записи которого обнаружено наличие не уникальности. +// ЗаписатьВЖурнал - Булево - возвращаемое значение. Если указать Ложь, тогда сведения о не уникальности не будут +// добавлены в журнал регистрации в общем сообщении. +// Нужно установить Ложь, если не уникальность была устранена автоматически. +// Отказ - Булево - возвращаемое значение. Если указать Истина, будет вызвано общее исключение, +// содержащее все причины отказа. +// ОписаниеОтказа - Строка - возвращаемое значение. Если Отказ установлен в Истина, то описание будет добавлено +// в список причин невозможности продолжения. +// +Процедура ПриОбнаруженииНеУникальностиПредопределенного(Объект, ЗаписатьВЖурнал, Отказ, ОписаниеОтказа) Экспорт + + Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") + И Объект.ИмяПредопределенныхДанных = "Администратор" Тогда + + ЗаписатьВЖурнал = Ложь; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка); + Запрос.УстановитьПараметр("ИмяПредопределенныхДанных", "Администратор"); + Запрос.Текст = + "ВЫБРАТЬ + | ПрофилиГруппДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + |ГДЕ + | ПрофилиГруппДоступа.Ссылка <> &Ссылка + | И ПрофилиГруппДоступа.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; + + Выборка = Запрос.Выполнить().Выбрать(); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + + Пока Выборка.Следующий() Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект(); + ТекущийОбъект.ИмяПредопределенныхДанных = ""; + ТекущийОбъект.ИдентификаторПоставляемыхДанных = ""; + ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + + ИначеЕсли ТипЗнч(Объект) = Тип("СправочникОбъект.ГруппыДоступа") + И Объект.ИмяПредопределенныхДанных = "Администраторы" Тогда + + ЗаписатьВЖурнал = Ложь; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИмяПредопределенныхДанных", "Администраторы"); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступаПользователи.Пользователь + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + |ГДЕ + | ГруппыДоступаПользователи.Ссылка.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; + ВсеПользователи = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Пользователь"); + + Записать = Ложь; + Для каждого Пользователь Из ВсеПользователи Цикл + Если Объект.Пользователи.Найти(Пользователь, "Пользователь") = Неопределено Тогда + Объект.Пользователи.Добавить().Пользователь = Пользователь; + Записать = Истина; + КонецЕсли; + КонецЦикла; + + Если Записать Тогда + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + КонецЕсли; + + Запрос.УстановитьПараметр("Ссылка", Объект.Ссылка); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Ссылка <> &Ссылка + | И ГруппыДоступа.ИмяПредопределенныхДанных = &ИмяПредопределенныхДанных"; + + Выборка = Запрос.Выполнить().Выбрать(); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + + Пока Выборка.Следующий() Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ТекущийОбъект = Выборка.Ссылка.ПолучитьОбъект(); + ТекущийОбъект.ИмяПредопределенныхДанных = ""; + ОбновлениеИнформационнойБазы.ЗаписатьДанные(ТекущийОбъект); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// См. ОбменДаннымиПереопределяемый.ПриНастройкеПодчиненногоУзлаРИБ. +Процедура ПриНастройкеПодчиненногоУзлаРИБ() Экспорт + + // Роли расширений назначаются независимо во всех РИБ-узлах. + Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширенийВоВсехПрофиляхГруппДоступа(); + + // Администраторы назначаются независимо во всех РИБ-узлах. + Справочники.ГруппыДоступа.УдалитьУчастниковГруппыДоступаАдминистраторыБезПользователяИБ(); + + Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); + Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.Описание = "ПриНастройкеПодчиненногоУзлаРИБ"; + ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); + КонецЕсли; + +КонецПроцедуры + +// См. ПользователиСлужебный.ПриЗаполненииВидовРегистрируемыхСсылок. +Процедура ПриЗаполненииВидовРегистрируемыхСсылок(ВидыСсылок) Экспорт + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ОграничиватьДоступНаУровнеЗаписей"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("Булево"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписейИзменениеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ИспользуемыеВидыДоступа"; + ВидСсылок.ДопустимыеТипы = Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип; + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ИспользуемыеВидыДоступаИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ПрофилиГруппДоступа"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ПрофилиГруппДоступа"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ПрофилиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ПрофилиГруппДоступаРоли"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( + "СправочникСсылка.ИдентификаторыОбъектовМетаданных,СправочникСсылка.ИдентификаторыОбъектовРасширений"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ПрофилиГруппДоступаРолиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступа"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ГруппыДоступа"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступаРоли"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( + "СправочникСсылка.ИдентификаторыОбъектовМетаданных,СправочникСсылка.ИдентификаторыОбъектовРасширений"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаРолиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступаПользователи"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов( + "СправочникСсылка.Пользователи,СправочникСсылка.ВнешниеПользователи"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаПользователиИзмененныеПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ГруппыДоступаЗначенийСИерархией"; + ВидСсылок.ДопустимыеТипы = Новый ОписаниеТипов("СправочникСсылка.ГруппыДоступа"); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ГруппыДоступаЗначенийСИерархиейИзмененныхПриЗагрузке"; + + ВидСсылок = ВидыСсылок.Добавить(); + ВидСсылок.Имя = "ЗначенияДоступа"; + ВидСсылок.ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ТипыСсылокИзЗначениеДоступаОбъект(); + ВидСсылок.ИмяПараметраРаботыРасширений = + "СтандартныеПодсистемы.УправлениеДоступом.ЗначенияДоступаИзмененныеПриЗагрузке"; + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхГлавному. +Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель) Экспорт + + ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Ложь, Ложь); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному. +Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель) Экспорт + + ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Истина, СозданиеНачальногоОбраза); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного. +Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт + + ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Ложь); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПриПолученииДанныхОтПодчиненного. +Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Отправитель) Экспорт + + ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, Истина); + +КонецПроцедуры + +// См. СтандартныеПодсистемыСервер.ПослеПолученияДанных. +Процедура ПослеПолученияДанных(Отправитель, Отказ, ПолучениеИзГлавногоУзла) Экспорт + + Если ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() Тогда + Возврат; + КонецЕсли; + + ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); + +КонецПроцедуры + +// См. описание в процедуре ЗаполнитьВсеПараметрыРаботыРасширений +// модуля менеджера регистра сведений ПараметрыРаботыВерсийРасширений. +// +Процедура ПриЗаполненииВсехПараметровРаботыРасширений() Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); + + Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда + // Обновление выполняется в процедуре + // ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации + // или ПриНастройкеПодчиненногоУзлаРИБ. + Возврат; + КонецЕсли; + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); + ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". + РегистрыСведений.НастройкиПравОбъектов.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". + Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); + Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". + Справочники.ГруппыДоступа.ПометитьНаУдалениеГруппыДоступаПомеченныхПрофилей(); + + // Если были нештатные ситуации и обновление не завершилось. + ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных(); + + // Обновление ролей пользователей ИБ после таких изменений расширений, + // которые приводят к рассогласованию ролей между пользователями ИБ и профилями, + // но не меняют состав ролей профилей. + ОбновитьРолиПользователей(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "ПриЗаполненииВсехПараметровРаботыРасширений"); + +КонецПроцедуры + +// Параметры: +// * Задание - РегламентноеЗадание +// +Процедура ПередЗапускомРегламентногоЗаданияНеВФоне(Задание) Экспорт + + Если Задание.Метаданные <> Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей Тогда + Возврат; + КонецЕсли; + + Задание.Параметры.Добавить(Истина); + Задание.Параметры.Добавить(Истина); + +КонецПроцедуры + +// Обработчики событий подсистемы Пользователи. + +// См. ПользователиПереопределяемый.ПриОпределенииНастроек. +Процедура ПриОпределенииНастроек(Настройки) Экспорт + + // Роли устанавливаются автоматически по данным групп доступа + // через связь: ПользователиГруппыДоступа -> Профиль -> РолиПрофиля. + Настройки.РедактированиеРолей = Ложь; + +КонецПроцедуры + +// См. ПользователиПереопределяемый.ИзменитьДействияВФорме. +Процедура ПриОпределенииДействийВФорме(Знач ПользовательИлиГруппа, Знач ДействияВФорме) Экспорт + + ДействияВФорме.Роли = ""; + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПослеЗаписиАдминистратораПриАвторизации. +Процедура ПослеЗаписиАдминистратораПриАвторизации(Комментарий) Экспорт + + Комментарий = + НСтр("ru = 'Выполнен запуск от имени пользователя с ролью ""Полные права"", + |который не зарегистрирован в списке пользователей. + |Выполнена автоматическая регистрация в списке пользователей. + |Пользователь добавлен в группу доступа Администраторы. + | + |Для ведения списка и настройки прав пользователей предназначен список Пользователи, + |режим конфигурирования 1С:Предприятия для этого использовать не следует.'"); + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПослеУстановкиПользователяИБ. +Процедура ПослеУстановкиПользователяИБ(Ссылка, ПарольПользователяСервиса) Экспорт + + ОбновитьРолиПользователей(Ссылка, ПарольПользователяСервиса); + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + КонецЕсли; + ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Ссылка),, Истина); + КонецЕсли; + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПриОпределенииТекстаВопросаПередЗаписьюПервогоАдминистратора. +Процедура ПриОпределенииТекстаВопросаПередЗаписьюПервогоАдминистратора(ТекстВопроса) Экспорт + + ТекстВопроса = + НСтр("ru = 'В список пользователей приложения добавляется первый пользователь, + |поэтому он будет автоматически включен в группу доступа Администраторы. + |Продолжить?'") + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПриСозданииАдминистратора. +Процедура ПриСозданииИлиАвторизацииАдминистратора(Администратор, Уточнение) Экспорт + + Если ТипЗнч(Администратор) <> Тип("СправочникСсылка.Пользователи") Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Пользователь", Администратор); + Запрос.УстановитьПараметр("ГруппаДоступаАдминистраторы", + УправлениеДоступом.ГруппаДоступаАдминистраторы()); + Запрос.Текст = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + |ГДЕ + | ГруппыДоступаПользователи.Ссылка = &ГруппаДоступаАдминистраторы + | И ГруппыДоступаПользователи.Пользователь = &Пользователь + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ИСТИНА + |ИЗ + | Справочник.Пользователи КАК Пользователи + |ГДЕ + | Пользователи.Служебный + | И Пользователи.Ссылка = &Пользователь"; + + Если Не Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + + КомментарийДляЖурнала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Пользователь ""%1"" добавлен в группу доступа Администраторы по причине: + |%2'"), + Администратор, + Уточнение); + + ГруппаДоступаАдминистраторы = УправлениеДоступом.ГруппаДоступаАдминистраторы(); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступаАдминистраторы); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = ГруппаДоступаАдминистраторы.ПолучитьОбъект(); + ЗаблокироватьДанныеДляРедактирования(Объект.Ссылка, Объект.ВерсияДанных); + Если Объект.Пользователи.Найти(Администратор, "Пользователь") = Неопределено Тогда + Объект.Пользователи.Добавить().Пользователь = Администратор; + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Автоматическое изменение группы доступа Администраторы'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + Метаданные.Справочники.Пользователи, + Администратор, + КомментарийДляЖурнала, + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + КонецЕсли; + РазблокироватьДанныеДляРедактирования(Объект.Ссылка); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// См. ИнтеграцияПодсистемБСП.ПослеОбновленияСоставовГруппПользователей. +Процедура ПослеОбновленияСоставовГруппПользователей(УчастникиИзменений, ИзмененныеГруппы) Экспорт + + Параметры = Новый Структура; + Параметры.Вставить("Пользователи", УчастникиИзменений); + Параметры.Вставить("ГруппыПользователей", ИзмененныеГруппы); + + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); + + ОбновитьРолиПользователей(УчастникиИзменений); + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(УчастникиИзменений); + ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(ИзмененныеГруппы); + КонецЕсли; + +КонецПроцедуры + +// Доопределяет действия, необходимые после изменении объекта авторизации внешнего пользователя. +// +// Параметры: +// ОбъектыАвторизации - Массив из ОпределяемыйТип.ВнешнийПользователь - новый объект авторизации и +// старый объект авторизации (если есть). +// - Неопределено - все объекты авторизации. +// +Процедура ПослеИзмененияОбъектаАвторизацииВнешнегоПользователя(ОбъектыАвторизации) Экспорт + + Параметры = Новый Структура; + Параметры.Вставить("ОбъектыАвторизации", ОбъектыАвторизации); + + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппировкиПользователей(Параметры); + +КонецПроцедуры + +// Выполняет копирование прав от одного пользователя другому. +Процедура ПриКопированииПравНовомуПользователю(Источник, Приемник) Экспорт + + Если ТранзакцияАктивна() + И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("Справочник.ГруппыДоступа"); + // АПК:1320-выкл - №499, №783.1.3 Допустимо вызывать блокировку во внешней транзакции для файловой ИБ. + // Требуется для предотвращения взаимоблокировки: ниже запрос, который ставит неявную + // разделяемую блокировку и далее блокировка усиливается до исключительной явным вызовом, + // что приводит к взаимоблокировке в некоторых случаях. + Блокировка.Заблокировать(); + // АПК:1320-вкл. + КонецЕсли; + + УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Пользователь", Источник); + + Если УпрощенныйИнтерфейс Тогда + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Профиль КАК Профиль + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО + | ГруппыДоступа.Пользователь = &Пользователь + | И ГруппыДоступаПользователи.Ссылка = ГруппыДоступа.Ссылка + | И ГруппыДоступаПользователи.Пользователь = &Пользователь"; + Иначе + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + |ГДЕ + | ГруппыДоступаПользователи.Пользователь = &Пользователь"; + КонецЕсли; + + РезультатЗапроса = Запрос.Выполнить(); + Если РезультатЗапроса.Пустой() Тогда + Возврат; + КонецЕсли; + + Выборка = РезультатЗапроса.Выбрать(); + + Если Не УпрощенныйИнтерфейс Тогда + Блокировка = Новый БлокировкаДанных(); + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.ИсточникДанных = РезультатЗапроса; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "ГруппаДоступа"); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Если УпрощенныйИнтерфейс Тогда + Пока Выборка.Следующий() Цикл + УправлениеДоступом.ВключитьОтключитьПрофильПользователя(Приемник, Выборка.Профиль, Истина, Источник); + КонецЦикла; + Иначе + Блокировка.Заблокировать(); + Пока Выборка.Следующий() Цикл + ГруппаДоступаОбъект = Выборка.ГруппаДоступа.ПолучитьОбъект(); // СправочникОбъект.ГруппыДоступа + Если ГруппаДоступаОбъект.Пользователи.Найти(Приемник, "Пользователь") = Неопределено Тогда + Строка = ГруппаДоступаОбъект.Пользователи.Добавить(); + Строка.Пользователь = Приемник; + ГруппаДоступаОбъект.Записать(); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Обработчики событий подсистемы ВариантыОтчетов. + +// См. ВариантыОтчетовПереопределяемый.НастроитьВариантыОтчетов. +Процедура ПриНастройкеВариантовОтчетов(Настройки) Экспорт + + МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов"); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПраваДоступа); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.АнализПравДоступа); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПраваРолей); + МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.УчастникиГруппДоступа); + +КонецПроцедуры + +// См. ВариантыОтчетовПереопределяемый.ПередДобавлениемКомандОтчетов. +Процедура ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка) Экспорт + + Отчеты.АнализПравДоступа.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); + Отчеты.ПраваРолей.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); + Отчеты.УчастникиГруппДоступа.ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка); + +КонецПроцедуры + +// Обработчики событий подсистемы РассылкаОтчетов. + +// См. РассылкаОтчетовПереопределяемый.ОпределитьИсключаемыеОтчеты +Процедура ПриОпределенииИсключаемыхОтчетов(ИсключаемыеОтчеты) Экспорт + + ИсключаемыеОтчеты.Добавить(Метаданные.Отчеты.ПраваДоступа); + +КонецПроцедуры + +// Обработчики событий подсистемы КонтрольВеденияУчета. + +// См. ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовИсключаемыхИзПроверки +Процедура ПриОпределенииОбъектовИсключаемыхИзПроверки(Объекты) Экспорт + ПриДобавленииИсключенийПоискаСсылокДопускающихУдаление(Объекты); +КонецПроцедуры + +// Обработчики событий подсистемы УправлениеДоступом. + +// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа. +Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт + + Списки.Вставить(Метаданные.Справочники.ПрофилиГруппДоступа, Истина); + Списки.Вставить(Метаданные.Справочники.ГруппыДоступа, Истина); + +КонецПроцедуры + +// Обработчики событий библиотеки ТехнологияСервиса. + +// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных +Процедура ПриРегистрацииОбработчиковВыгрузкиДанных(ТаблицаОбработчиков) Экспорт + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.Справочники.ПрофилиГруппДоступа; + Обработчик.Обработчик = Справочники.ПрофилиГруппДоступа; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.Справочники.ГруппыДоступа; + Обработчик.Обработчик = Справочники.ГруппыДоступа; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ЗначенияГруппДоступа; + Обработчик.Обработчик = РегистрыСведений.ЗначенияГруппДоступа; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + + Обработчик = ТаблицаОбработчиков.Добавить(); + Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию; + Обработчик.Обработчик = РегистрыСведений.ЗначенияГруппДоступаПоУмолчанию; + Обработчик.ПередВыгрузкойОбъекта = Истина; + Обработчик.Версия = "1.0.0.1"; + +КонецПроцедуры + +// Процедуры и функция для подсистемы Пользователи. + +Функция ТекстЗапросаГруппДоступаПриИзмененииУчастниковГруппПользователей() Экспорт + + Возврат + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | УчастникиГруппДоступа.Ссылка КАК ГруппаДоступа, + | УчастникиГруппДоступа.Пользователь КАК Участник, + | УчастникиГруппДоступа.СрокДействия КАК СрокДействия + |ПОМЕСТИТЬ УчастникиГруппДоступа + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ЛЕВОЕ СОЕДИНЕНИЕ ИзмененияСоставов КАК ИзмененияСоставовГрупп + | ПО (ИзмененияСоставовГрупп.ГруппаПользователей = УчастникиГруппДоступа.Пользователь) + | ЛЕВОЕ СОЕДИНЕНИЕ ИзмененияСоставов КАК ИзмененияАктивностиПользователей + | ПО (ИзмененияАктивностиПользователей.Пользователь = УчастникиГруппДоступа.Пользователь) + | И (ИзмененияАктивностиПользователей.ГруппаПользователей = &ГруппаВсеПользователи) + |ГДЕ + | (НЕ ИзмененияСоставовГрупп.ГруппаПользователей ЕСТЬ NULL + | ИЛИ НЕ ИзмененияАктивностиПользователей.Пользователь ЕСТЬ NULL) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | УчастникиГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | УчастникиГруппДоступа.Участник КАК Участник, + | УчастникиГруппДоступа.СрокДействия КАК СрокДействия + |ИЗ + | УчастникиГруппДоступа КАК УчастникиГруппДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК ГруппаДоступа, + | ПРЕДСТАВЛЕНИЕ(ГруппыДоступа.Ссылка) КАК Представление, + | ГруппыДоступа.ПометкаУдаления КАК ПометкаУдаления, + | ГруппыДоступа.Профиль КАК Профиль, + | ПРЕДСТАВЛЕНИЕ(ГруппыДоступа.Профиль) КАК ПредставлениеПрофиля, + | ЕСТЬNULL(ГруппыДоступа.Профиль.ПометкаУдаления, ИСТИНА) КАК ПометкаУдаленияПрофиля + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Ссылка В + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | УчастникиГруппДоступа.ГруппаДоступа + | ИЗ + | УчастникиГруппДоступа КАК УчастникиГруппДоступа)"; + +КонецФункции + +// Процедуры и функции подсистемы ЦентрМониторинга. + +// Возвращает текст запроса для сбора статистической информации об использовании профилей групп доступа и ролей. +// +// Возвращаемое значение: +// Строка +// +Функция ТекстЗапросаИспользованияРолей() Экспорт + + Возврат + "ВЫБРАТЬ + | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, + | СведенияОПользователях.Пользователь КАК Пользователь, + | ВЫБОР + | КОГДА РАЗНОСТЬДАТ(СведенияОПользователях.ДатаПоследнейАктивности, &ТекущаяДата, ДЕНЬ) <= 7 + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ КАК АктивныхЗаНеделю, + | ВЫБОР + | КОГДА РАЗНОСТЬДАТ(СведенияОПользователях.ДатаПоследнейАктивности, &ТекущаяДата, ДЕНЬ) <= 30 + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ КАК АктивныхЗаМесяц + |ПОМЕСТИТЬ ВТСоставыГруппИАктивность + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОПользователях КАК СведенияОПользователях + | ПО СоставыГруппПользователей.Пользователь = СведенияОПользователях.Пользователь + |ГДЕ + | СоставыГруппПользователей.Используется + | И НЕ СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ = &ПустойУИД + | + |ИНДЕКСИРОВАТЬ ПО + | ГруппаПользователей, + | Пользователь + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ПрофилиГруппДоступа.Ссылка КАК Профиль, + | ПрофилиГруппДоступа.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, + | ПрофилиГруппДоступа.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен, + | ПрофилиГруппДоступа.Наименование КАК Наименование, + | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа, + | ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = НЕОПРЕДЕЛЕНО КАК ОбщаяГруппаДоступа, + | ГруппыДоступаПользователи.Пользователь КАК ПользовательТЧ, + | СоставыГруппПользователей.Пользователь КАК ПользовательРС, + | СоставыГруппПользователей.АктивныхЗаНеделю КАК АктивныхЗаНеделю, + | СоставыГруппПользователей.АктивныхЗаМесяц КАК АктивныхЗаМесяц + |ПОМЕСТИТЬ ВТДанныеПрофилей + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТСоставыГруппИАктивность КАК СоставыГруппПользователей + | ПО ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + | ПО (ПрофилиГруппДоступа.Ссылка = ГруппыДоступаПользователи.Ссылка.Профиль) + | И (НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления) + |ГДЕ + | НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления + | + |СГРУППИРОВАТЬ ПО + | ПрофилиГруппДоступа.Ссылка, + | ПрофилиГруппДоступа.Наименование, + | ГруппыДоступаПользователи.Пользователь, + | СоставыГруппПользователей.Пользователь, + | СоставыГруппПользователей.АктивныхЗаНеделю, + | СоставыГруппПользователей.АктивныхЗаМесяц, + | ГруппыДоступаПользователи.Ссылка, + | ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка) + | ИЛИ ГруппыДоступаПользователи.Ссылка.Пользователь = НЕОПРЕДЕЛЕНО, + | ПрофилиГруппДоступа.ИдентификаторПоставляемыхДанных, + | ПрофилиГруппДоступа.ПоставляемыйПрофильИзменен + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.Наименование КАК Наименование, + | ВТДанныеПрофилей.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, + | ВТДанныеПрофилей.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен + |ПОМЕСТИТЬ Профили + |ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Профили.Профиль КАК Профиль, + | СУММА(ВЫБОР + | КОГДА НЕ ПрофилиГруппДоступаВидыДоступа.ВидДоступа ЕСТЬ NULL + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ВсегоВидовДоступа, + | СУММА(ВЫБОР + | КОГДА ЕСТЬNULL(ПрофилиГруппДоступаВидыДоступа.Предустановленный, ЛОЖЬ) + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ПредустановленныхВидовДоступа + |ПОМЕСТИТЬ ВидыДоступа + |ИЗ + | Профили КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.ВидыДоступа КАК ПрофилиГруппДоступаВидыДоступа + | ПО Профили.Профиль = ПрофилиГруппДоступаВидыДоступа.Ссылка + | + |СГРУППИРОВАТЬ ПО + | Профили.Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Вложенный.Профиль КАК Профиль, + | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Вложенный.ГруппаДоступа) КАК ГруппаДоступа, + | СУММА(ВЫБОР + | КОГДА НЕ Вложенный.ОбщаяГруппаДоступа + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ПерсональнаяГруппа + |ПОМЕСТИТЬ ГруппыДоступа + |ИЗ + | (ВЫБРАТЬ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.ГруппаДоступа КАК ГруппаДоступа, + | ВТДанныеПрофилей.ОбщаяГруппаДоступа КАК ОбщаяГруппаДоступа + | ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + | СГРУППИРОВАТЬ ПО + | ВТДанныеПрофилей.Профиль, + | ВТДанныеПрофилей.ГруппаДоступа, + | ВТДанныеПрофилей.ОбщаяГруппаДоступа) КАК Вложенный + | + |СГРУППИРОВАТЬ ПО + | Вложенный.Профиль + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Вложенный.Профиль КАК Профиль, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательТЧ ССЫЛКА Справочник.ГруппыПользователей + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ГруппПользователей, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательТЧ ССЫЛКА Справочник.ГруппыВнешнихПользователей + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ГруппВнешнихПользователей + |ПОМЕСТИТЬ ГруппыПользователей + |ИЗ + | (ВЫБРАТЬ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.ПользовательТЧ КАК ПользовательТЧ + | ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + | СГРУППИРОВАТЬ ПО + | ВТДанныеПрофилей.Профиль, + | ВТДанныеПрофилей.ПользовательТЧ) КАК Вложенный + | + |СГРУППИРОВАТЬ ПО + | Вложенный.Профиль + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Вложенный.Профиль КАК Профиль, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательРС ССЫЛКА Справочник.Пользователи + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК Пользователи, + | СУММА(ВЫБОР + | КОГДА Вложенный.ПользовательРС ССЫЛКА Справочник.ВнешниеПользователи + | ТОГДА 1 + | ИНАЧЕ 0 + | КОНЕЦ) КАК ВнешниеПользователи, + | СУММА(Вложенный.АктивныхЗаНеделю) КАК АктивныхЗаНеделю, + | СУММА(Вложенный.АктивныхЗаМесяц) КАК АктивныхЗаМесяц + |ПОМЕСТИТЬ ПользователиПрофиля + |ИЗ + | (ВЫБРАТЬ + | ВТДанныеПрофилей.Профиль КАК Профиль, + | ВТДанныеПрофилей.ПользовательРС КАК ПользовательРС, + | СУММА(ВТДанныеПрофилей.АктивныхЗаНеделю) КАК АктивныхЗаНеделю, + | СУММА(ВТДанныеПрофилей.АктивныхЗаМесяц) КАК АктивныхЗаМесяц + | ИЗ + | ВТДанныеПрофилей КАК ВТДанныеПрофилей + | + | СГРУППИРОВАТЬ ПО + | ВТДанныеПрофилей.Профиль, + | ВТДанныеПрофилей.ПользовательРС) КАК Вложенный + | + |СГРУППИРОВАТЬ ПО + | Вложенный.Профиль + | + |ИНДЕКСИРОВАТЬ ПО + | Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Профили.Профиль КАК Профиль, + | Профили.Наименование КАК Наименование, + | Профили.ИдентификаторПоставляемыхДанных КАК ИдентификаторПоставляемыхДанных, + | Профили.ПоставляемыйПрофильИзменен КАК ПоставляемыйПрофильИзменен, + | ЕСТЬNULL(ГруппыДоступа.ГруппаДоступа, 0) КАК ГруппаДоступа, + | ЕСТЬNULL(ГруппыДоступа.ПерсональнаяГруппа, 0) КАК ПерсональнаяГруппа, + | ЕСТЬNULL(ГруппыПользователей.ГруппПользователей, 0) КАК ГруппПользователей, + | ЕСТЬNULL(ГруппыПользователей.ГруппВнешнихПользователей, 0) КАК ГруппВнешнихПользователей, + | ЕСТЬNULL(ПользователиПрофиля.Пользователи, 0) КАК Пользователи, + | ЕСТЬNULL(ПользователиПрофиля.ВнешниеПользователи, 0) КАК ВнешниеПользователи, + | ЕСТЬNULL(ПользователиПрофиля.АктивныхЗаНеделю, 0) КАК АктивныхЗаНеделю, + | ЕСТЬNULL(ПользователиПрофиля.АктивныхЗаМесяц, 0) КАК АктивныхЗаМесяц, + | ЕСТЬNULL(ВидыДоступа.ВсегоВидовДоступа, 0) КАК ВсегоВидовДоступа, + | ЕСТЬNULL(ВидыДоступа.ПредустановленныхВидовДоступа, 0) КАК ПредустановленныхВидовДоступа + |ИЗ + | Профили КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ ПользователиПрофиля КАК ПользователиПрофиля + | ПО Профили.Профиль = ПользователиПрофиля.Профиль + | ЛЕВОЕ СОЕДИНЕНИЕ ГруппыПользователей КАК ГруппыПользователей + | ПО Профили.Профиль = ГруппыПользователей.Профиль + | ЛЕВОЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа + | ПО Профили.Профиль = ГруппыДоступа.Профиль + | ЛЕВОЕ СОЕДИНЕНИЕ ВидыДоступа КАК ВидыДоступа + | ПО Профили.Профиль = ВидыДоступа.Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | Профили.Профиль КАК Профиль, + | ЕСТЬNULL(ПрофилиГруппДоступаРоли.Роль.Имя, """") КАК РольИмя + |ИЗ + | Профили КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиГруппДоступаРоли + | ПО Профили.Профиль = ПрофилиГруппДоступаРоли.Ссылка + | И (Профили.ИдентификаторПоставляемыхДанных = &ПустойУИД + | ИЛИ Профили.ПоставляемыйПрофильИзменен) + | + |УПОРЯДОЧИТЬ ПО + | Профиль"; + +КонецФункции + +// Проверяет доступность общей команды НастроитьПрава. +// +// Возвращаемое значение: +// Булево +// +Функция ДоступнаКомандаНастройкиПрав() Экспорт + Возврат ПравоДоступа("Просмотр", Метаданные.ОбщиеКоманды.НастроитьПрава); +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных. +Процедура ПередВыгрузкойОбъекта(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт + + // Роли расширений назначаются независимо в коробке и в сервисе. + Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширений(Объект); + КонецЕсли; + + // В модели сервиса право открытия внешних отчетов и обработок не используется для пользователей областей данных, + // поэтому проверка применяется только при переходе Коробка -> Сервис. + Если ОбщегоНазначения.РазделениеВключено() Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(Объект) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + Профиль = Объект; + + ИначеЕсли ТипЗнч(Объект) = Тип("СправочникОбъект.ГруппыДоступа") И Не Объект.ЭтоГруппа Тогда + Профиль = Объект.Профиль; + Иначе + Возврат; + КонецЕсли; + + Если ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(Профиль) Тогда + Отказ = Истина; + КонецЕсли; + +КонецПроцедуры + +// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных. +Процедура ПередВыгрузкойНабораЗаписей(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт + + // В модели сервиса право открытия внешних отчетов и обработок не используется для пользователей областей данных, + // поэтому проверка применяется только при переходе Коробка -> Сервис. + Если ОбщегоНазначения.РазделениеВключено() Тогда + Возврат; + КонецЕсли; + + ГруппыДоступа = ГруппыДоступаПрофиляОткрытиеВнешнихОтчетовИОбработок(); + + Индекс = Объект.Количество() - 1; + Пока Индекс >= 0 Цикл + Если ГруппыДоступа.Найти(Объект[Индекс].ГруппаДоступа) <> Неопределено Тогда + Объект.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + +КонецПроцедуры + +// Параметры: +// ИмяПараметра - Строка +// УстановленныеПараметры - Массив из Строка +// +Процедура УстановкаПараметровСеанса(ИмяПараметра, УстановленныеПараметры) Экспорт + +#Область УниверсальноеОграничение + Если ИмяПараметра = "ПараметрыОграниченияДоступа" Тогда + ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(Новый Структура); + УстановленныеПараметры.Добавить("ПараметрыОграниченияДоступа"); + Возврат; + КонецЕсли; + + Если ИмяПараметра = "ОтключениеОбновленияКлючейДоступа" Тогда + ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа = НовоеОтключениеОбновленияКлючейДоступа(); + УстановленныеПараметры.Добавить("ОтключениеОбновленияКлючейДоступа"); + Возврат; + КонецЕсли; + + УниверсальноеОграничение = ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина, Ложь); + + Если ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально" + Или ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально <> УниверсальноеОграничение Тогда + + ПередИзменениемПараметровСеансаДляШаблонов( + Новый Структура("ОграничениеДоступаНаУровнеЗаписейУниверсально", УниверсальноеОграничение), + ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально"); + + ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейУниверсально = УниверсальноеОграничение; + КонецЕсли; + + УстановленныеПараметры.Добавить("ОграничениеДоступаНаУровнеЗаписейУниверсально"); + Если ИмяПараметра = "ОграничениеДоступаНаУровнеЗаписейУниверсально" Тогда + Возврат; + КонецЕсли; +#КонецОбласти + + // Для корректной работы препроцессора в ограничениях доступа, требуется инициализации всех + // параметров сеанса, которые могут быть востребованы в работе препроцессора. + ОграничиватьДоступНаУровнеЗаписей = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + ИнформационнаяБазаЗаблокированаДляОбновления = ЗначениеЗаполнено( + ОбновлениеИнформационнойБазыСлужебный.ИнформационнаяБазаЗаблокированаДляОбновления(Ложь)); + +#Область УниверсальноеОграничение + Если Не ОграничиватьДоступНаУровнеЗаписей + Или Не УниверсальноеОграничение + Или ИнформационнаяБазаЗаблокированаДляОбновления Тогда + + ПараметрыСеанса.СпискиСОтключеннымОграничениемЧтения = + ?(ИнформационнаяБазаЗаблокированаДляОбновления + Или Не УниверсальноеОграничение, "Неопределено", "Все"); + + ПустойНаборГруппДоступа = Справочники.НаборыГруппДоступа.ПустаяСсылка(); + + ПараметрыСеанса.ВерсииШаблоновОграниченияДоступа = ВерсииШаблоновОграниченияДоступа(); + ПараметрыСеанса.РазрешенныйНаборГруппДоступа = ПустойНаборГруппДоступа; + ПараметрыСеанса.РазрешенныйПустойНаборГруппДоступа = ПустойНаборГруппДоступа; + ПараметрыСеанса.РазрешенныйНаборГруппПользователей = ПустойНаборГруппДоступа; + ПараметрыСеанса.РазрешенныйПользователь = ПустойНаборГруппДоступа; + ПараметрыСеанса.ОбщиеПараметрыШаблоновОграниченияДоступа = ""; + ПараметрыСеанса.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = ""; + ПараметрыСеанса.СпискиСОграничениемЧерезКлючиДоступаПользователей = ""; + ПараметрыСеанса.СпискиСОграничениемПоПолям = ""; + + УстановленныеПараметры.Добавить("СпискиСОтключеннымОграничениемЧтения"); + УстановленныеПараметры.Добавить("ВерсииШаблоновОграниченияДоступа"); + УстановленныеПараметры.Добавить("РазрешенныйНаборГруппДоступа"); + УстановленныеПараметры.Добавить("РазрешенныйПустойНаборГруппДоступа"); + УстановленныеПараметры.Добавить("РазрешенныйНаборГруппПользователей"); + УстановленныеПараметры.Добавить("РазрешенныйПользователь"); + УстановленныеПараметры.Добавить("ОбщиеПараметрыШаблоновОграниченияДоступа"); + УстановленныеПараметры.Добавить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа"); + УстановленныеПараметры.Добавить("СпискиСОграничениемЧерезКлючиДоступаПользователей"); + УстановленныеПараметры.Добавить("СпискиСОграничениемПоПолям"); + КонецЕсли; +#КонецОбласти + + Если Не ОграничиватьДоступНаУровнеЗаписей + Или УниверсальноеОграничение + Или ИнформационнаяБазаЗаблокированаДляОбновления Тогда + + ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейИспользуется = + ?(ИнформационнаяБазаЗаблокированаДляОбновления + Или УниверсальноеОграничение, "", Ложь); + + ПараметрыСеанса.ВсеВидыДоступаКромеСпециальных = ""; + ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием = ""; + ПараметрыСеанса.ВидыДоступаБезГруппДляЗначенияДоступа = ""; + ПараметрыСеанса.ВидыДоступаСОднойГруппойДляЗначенияДоступа = ""; + + ПараметрыСеанса.ТипыЗначенийДоступаСГруппами + = Новый ФиксированныйМассив(Новый Массив); + + ПараметрыСеанса.ТаблицыСОтдельнымиНастройкамиПрав = ""; + + ПараметрыСеанса.ИдентификаторыТаблицСОтдельнымиНастройкамиПрав + = Новый ФиксированныйМассив(Новый Массив); + + ПараметрыСеанса.ТипыВладельцевНастроекПрав + = Новый ФиксированныйМассив(Новый Массив); + + ПараметрыСеанса.ТаблицыРасширенийСОграничениемДоступа = ""; + + УстановленныеПараметры.Добавить("ОграничениеДоступаНаУровнеЗаписейИспользуется"); + УстановленныеПараметры.Добавить("ВсеВидыДоступаКромеСпециальных"); + УстановленныеПараметры.Добавить("ВидыДоступаСОтключеннымИспользованием"); + УстановленныеПараметры.Добавить("ВидыДоступаБезГруппДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ВидыДоступаСОднойГруппойДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ТипыЗначенийДоступаСГруппами"); + УстановленныеПараметры.Добавить("ТаблицыСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ТипыВладельцевНастроекПрав"); + УстановленныеПараметры.Добавить("ТаблицыРасширенийСОграничениемДоступа"); + КонецЕсли; + + Если ИнформационнаяБазаЗаблокированаДляОбновления Тогда + Возврат; + КонецЕсли; + +#Область УниверсальноеОграничение + Если УниверсальноеОграничение Тогда + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь, Истина); + Возврат; + КонецЕсли; +#КонецОбласти + + Если Не ОграничиватьДоступНаУровнеЗаписей Тогда + Возврат; + КонецЕсли; + + ПараметрыСеанса.ОграничениеДоступаНаУровнеЗаписейИспользуется = Истина; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.АвторизованныйПользователь()); + Запрос.Текст = + "ВЫБРАТЬ + | ЗначенияПоУмолчанию.ТипЗначенийДоступа КАК ТипЗначений + |ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Ссылка = ЗначенияПоУмолчанию.ГруппаДоступа) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) + | И (СоставыГруппПользователей.Пользователь = &ТекущийПользователь) + | + |СГРУППИРОВАТЬ ПО + | ЗначенияПоУмолчанию.ТипЗначенийДоступа + | + |ИМЕЮЩИЕ + | МИНИМУМ(ЗначенияПоУмолчанию.ВсеРазрешеныБезИсключений) = ИСТИНА"; + + ТипыЗначенийВсеРазрешеныБезИсключений = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ТипЗначений"); + + // Установка параметров ВсеВидыДоступаКромеСпециальных, ВидыДоступаСОтключеннымИспользованием. + ВсеВидыДоступаКромеСпециальных = Новый Массив; + ВидыДоступаСОтключеннымИспользованием = Новый Массив; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); + + Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл + ВсеВидыДоступаКромеСпециальных.Добавить(СвойстваВидаДоступа.Имя); + + Если ИспользуемыеВидыДоступа.Получить(СвойстваВидаДоступа.Ссылка) = Неопределено + Или ТипыЗначенийВсеРазрешеныБезИсключений.Найти(СвойстваВидаДоступа.Ссылка) <> Неопределено Тогда + + ВидыДоступаСОтключеннымИспользованием.Добавить(СвойстваВидаДоступа.Имя); + КонецЕсли; + КонецЦикла; + + ПараметрыСеанса.ВсеВидыДоступаКромеСпециальных = ВсеКомбинацииВидовДоступа(ВсеВидыДоступаКромеСпециальных); + + УстановленныеПараметры.Добавить("ВсеВидыДоступаКромеСпециальных"); + + ВсеВидыДоступаКромеСпециальныхОтключены = (ВсеВидыДоступаКромеСпециальных.Количество() + = ВидыДоступаСОтключеннымИспользованием.Количество()); + + Если ВсеВидыДоступаКромеСпециальныхОтключены Тогда + ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием = "Все"; + Иначе + ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием + = ВсеКомбинацииВидовДоступа(ВидыДоступаСОтключеннымИспользованием); + КонецЕсли; + + УстановленныеПараметры.Добавить("ВидыДоступаСОтключеннымИспользованием"); + + // Установка параметров ВидыДоступаБезГруппДляЗначенияДоступа, + // ВидыДоступаСОднойГруппойДляЗначенияДоступа, ТипыЗначенийДоступаСГруппами. + ПараметрыСеанса.ВидыДоступаБезГруппДляЗначенияДоступа = + ВсеКомбинацииВидовДоступа(СвойстваВидовДоступа.БезГруппДляЗначенияДоступа); + ПараметрыСеанса.ВидыДоступаСОднойГруппойДляЗначенияДоступа = + ВсеКомбинацииВидовДоступа(СвойстваВидовДоступа.СОднойГруппойДляЗначенияДоступа); + + ТипыЗначенийДоступаСГруппами = Новый Массив; + Для каждого КлючИЗначение Из СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами Цикл + ТипыЗначенийДоступаСГруппами.Добавить(КлючИЗначение.Значение); + КонецЦикла; + ПараметрыСеанса.ТипыЗначенийДоступаСГруппами = Новый ФиксированныйМассив(ТипыЗначенийДоступаСГруппами); + + УстановленныеПараметры.Добавить("ВидыДоступаБезГруппДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ВидыДоступаСОднойГруппойДляЗначенияДоступа"); + УстановленныеПараметры.Добавить("ТипыЗначенийДоступаСГруппами"); + + // Установка параметров ТаблицыСОтдельнымиНастройкамиПрав, + // ИдентификаторыТаблицСОтдельнымиНастройкамиПрав, ТипыВладельцевНастроекПрав. + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ОтдельныеТаблицы = ВозможныеПрава.ОтдельныеТаблицы; + ТаблицыСОтдельнымиНастройкамиПрав = ""; + ИдентификаторыТаблицСОтдельнымиНастройкамиПрав = Новый Массив; + Для каждого КлючИЗначение Из ОтдельныеТаблицы Цикл + ТаблицыСОтдельнымиНастройкамиПрав = ТаблицыСОтдельнымиНастройкамиПрав + + "|" + КлючИЗначение.Значение + ";" + Символы.ПС; + ИдентификаторыТаблицСОтдельнымиНастройкамиПрав.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + + ПараметрыСеанса.ТаблицыСОтдельнымиНастройкамиПрав = ТаблицыСОтдельнымиНастройкамиПрав; + + ПараметрыСеанса.ИдентификаторыТаблицСОтдельнымиНастройкамиПрав = + Новый ФиксированныйМассив(ИдентификаторыТаблицСОтдельнымиНастройкамиПрав); + + ПараметрыСеанса.ТипыВладельцевНастроекПрав = ВозможныеПрава.ТипыВладельцев; + + ПолныеИмена = Справочники.ИдентификаторыОбъектовРасширений.ПолныеИменаТаблицСДанными(); + ТаблицыРасширений = СтрСоединить(ПолныеИмена, ";" + Символы.ПС + "|"); + ТаблицыРасширений = ?(ТаблицыРасширений = "", "", "|" + ТаблицыРасширений + ";" + Символы.ПС); + + ПараметрыСеанса.ТаблицыРасширенийСОграничениемДоступа = ТаблицыРасширений; + + УстановленныеПараметры.Добавить("ТаблицыСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ИдентификаторыТаблицСОтдельнымиНастройкамиПрав"); + УстановленныеПараметры.Добавить("ТипыВладельцевНастроекПрав"); + УстановленныеПараметры.Добавить("ТаблицыРасширенийСОграничениемДоступа"); + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Стандартное - Булево +// * Полное - Булево +// * ВложенныеОтключения - ФиксированныйМассив +// * ИзмененныеСписки - ХранилищеЗначения +// +Функция НовоеОтключениеОбновленияКлючейДоступа() Экспорт + + Свойства = Новый Структура; + Свойства.Вставить("Стандартное", Ложь); + Свойства.Вставить("Полное", Ложь); + Свойства.Вставить("ВложенныеОтключения", Новый ФиксированныйМассив(Новый Массив)); + Свойства.Вставить("ИзмененныеСписки", Новый ХранилищеЗначения(Новый Соответствие)); + + Возврат Новый ФиксированнаяСтруктура(Свойства); + +КонецФункции + +// Только для внутреннего использования. +Процедура ОбновитьПараметрыСеанса() Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + УстановленныеПараметры = Новый Массив; + УстановкаПараметровСеанса("", УстановленныеПараметры); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + ОбновитьПовторноИспользуемыеЗначения(); + +КонецПроцедуры + +// Проверка группы доступа Администраторы перед записью. +Процедура ПроверитьНаличиеПользователяИБВГруппеДоступаАдминистраторы(ПользователиГруппы, ОписаниеОшибки) Экспорт + + Пользователи.НайтиНеоднозначныхПользователейИБ(Неопределено); + + // Проверка пустого списка пользователей ИБ в группе доступа Администраторы. + УстановитьПривилегированныйРежим(Истина); + НайденДействующийАдминистратор = Ложь; + + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + + Если Не ЗначениеЗаполнено(ОписаниеПользователя.Пользователь) + Или ТипЗнч(ОписаниеПользователя.Пользователь) <> Тип("СправочникСсылка.Пользователи") + И ТипЗнч(ОписаниеПользователя.Пользователь) <> Тип("СправочникСсылка.Пользователи") Тогда + Продолжить; + КонецЕсли; + + ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( + ОписаниеПользователя.Пользователь.ИдентификаторПользователяИБ); + + Если ПользовательИБ <> Неопределено + И Пользователи.ВходВПрограммуРазрешен(ПользовательИБ) Тогда + + НайденДействующийАдминистратор = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Если НЕ НайденДействующийАдминистратор Тогда + ОписаниеОшибки = + НСтр("ru = 'В группе доступа Администраторы + |должен быть хотя бы один пользователь, + |которому разрешен вход в приложение.'"); + КонецЕсли; + +КонецПроцедуры + +// См. УправлениеДоступом.ЕстьОграничениеТаблицыПоВидуДоступа +Функция ЕстьОграничениеТаблицыПоВидуДоступа(Таблица, ВидДоступа, ВсеВидыДоступа) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + ВидыДоступаСОтключеннымИспользованием = ПараметрыСеанса.ВидыДоступаСОтключеннымИспользованием; + Если ВидыДоступаСОтключеннымИспользованием = "Все" + Или СтрНайти(ВидыДоступаСОтключеннымИспользованием, "," + ВидДоступа + ",") > 0 Тогда + Возврат Ложь; + КонецЕсли; + + МассивВидовДоступа = СтрРазделить(ВсеВидыДоступа, ",", Ложь); + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в функции %1 общего модуля %2.'"), + "ЕстьОграничениеТаблицыПоВидуДоступа", "УправлениеДоступом") + + Символы.ПС; + + СвойстваВидаДоступа = СвойстваВидовДоступа.ПоИменам.Получить(ВидДоступа); + Если СвойстваВидаДоступа = Неопределено Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует вид доступа ""%1"", указанный в параметре %2.'"), + ВидДоступа, "ВидДоступа"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + ВидДоступаСсылка = СвойстваВидаДоступа.Ссылка; + + ВсеВидыДоступаТаблицыСОтключеннымИспользованием = Истина; + ИспользованиеВидовДоступа = Новый Соответствие; + ВидДоступаУказанВоВсехВидахДоступа = Ложь; + + Для Каждого ТекущийВидДоступа Из МассивВидовДоступа Цикл + ТекущийВидДоступа = СокрЛП(ТекущийВидДоступа); + СвойстваВидаДоступа = СвойстваВидовДоступа.ПоИменам.Получить(ТекущийВидДоступа); + Если СвойстваВидаДоступа = Неопределено Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует вид доступа ""%1"", указанный в параметре + |%2: ""%3"".'"), + ТекущийВидДоступа, "ВсеВидыДоступа", ВсеВидыДоступа); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + Если СвойстваВидаДоступа.Имя = ВидДоступа Тогда + ВидДоступаУказанВоВсехВидахДоступа = Истина; + КонецЕсли; + Используется = СтрНайти(ВидыДоступаСОтключеннымИспользованием, "," + СвойстваВидаДоступа.Имя + ",") = 0; + ИспользованиеВидовДоступа.Вставить(СвойстваВидаДоступа.Ссылка, Используется); + Если Используется Тогда + ВсеВидыДоступаТаблицыСОтключеннымИспользованием = Ложь; + КонецЕсли; + КонецЦикла; + + Если Не ВидДоступаУказанВоВсехВидахДоступа Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Вид доступа ""%1"", указанный в параметре %2 не существует в параметре + |%3: ""%4"".'"), + ВидДоступа, "ВидДоступа", "ВсеВидыДоступа", ВсеВидыДоступа); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если ВсеВидыДоступаТаблицыСОтключеннымИспользованием Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИмяОсновнойТаблицыСписка", Таблица); + Запрос.УстановитьПараметр("АвторизованныйПользователь", Пользователи.АвторизованныйПользователь()); + + Запрос.Текст = ТекстЗапросаГруппДоступа(); + + ТекстЗапроса = + "ВЫБРАТЬ + | ЗначенияПоУмолчанию.ГруппаДоступа КАК ГруппаДоступа, + | ЗначенияПоУмолчанию.ТипЗначенийДоступа КАК ВидДоступа + |ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияПоУмолчанию + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступаПользователя КАК ГруппыДоступаПользователя + | ПО ЗначенияПоУмолчанию.ГруппаДоступа = ГруппыДоступаПользователя.Ссылка + |ГДЕ + | НЕ ЗначенияПоУмолчанию.ВсеРазрешеныБезИсключений + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | ГруппыДоступаПользователи.Ссылка = ЗначенияПоУмолчанию.ГруппаДоступа + | И ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | И СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь)"; + + ДобавитьЗапросВПакет(Запрос.Текст, ТекстЗапроса); + Выборка = Запрос.Выполнить().Выбрать(); + + НастроенныеВидыДоступаГруппДоступа = Новый Соответствие; + ЕстьГруппаДоступаСОграничениемПоВидуДоступа = Ложь; + + Пока Выборка.Следующий() Цикл + НастроенныеВидыДоступа = НастроенныеВидыДоступаГруппДоступа.Получить(Выборка.ГруппаДоступа); + Если НастроенныеВидыДоступа = Неопределено Тогда + НастроенныеВидыДоступа = Новый Соответствие; + НастроенныеВидыДоступаГруппДоступа.Вставить(Выборка.ГруппаДоступа, НастроенныеВидыДоступа); + КонецЕсли; + Если ИспользованиеВидовДоступа.Получить(Выборка.ВидДоступа) = Неопределено Тогда + Продолжить; + КонецЕсли; + НастроенныеВидыДоступа.Вставить(Выборка.ВидДоступа, Истина); + Если Выборка.ВидДоступа = ВидДоступаСсылка Тогда + ЕстьГруппаДоступаСОграничениемПоВидуДоступа = Истина; + КонецЕсли; + КонецЦикла; + + ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа = Ложь; + + Для Каждого ОписаниеГруппыДоступа Из НастроенныеВидыДоступаГруппДоступа Цикл + НастроенныеВидыДоступа = ОписаниеГруппыДоступа.Значение; + ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа = Истина; + Для Каждого ОписаниеИспользованияВидаДоступа Из ИспользованиеВидовДоступа Цикл + Если Не ОписаниеИспользованияВидаДоступа.Значение Тогда + Продолжить; // Не используется. + КонецЕсли; + Если НастроенныеВидыДоступа.Получить(ОписаниеИспользованияВидаДоступа.Ключ) = Неопределено Тогда + Продолжить; // ВсеРазрешеныБезИсключений или ограничения по виду доступа нет. + КонецЕсли; + ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа = Ложь; + Прервать; + КонецЦикла; + Если ВсеВидыДоступаТаблицыБезОграниченийВГруппеДоступа Тогда + ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Если ЕстьГруппаДоступаБезОграниченийПоВсемВидамДоступа Тогда + Возврат Ложь; + КонецЕсли; + + Возврат ЕстьГруппаДоступаСОграничениемПоВидуДоступа; + +КонецФункции + +// Параметры: +// Объекты - см. ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению.Объекты +// ПолноеИмяИзмерения - см. ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению.Объект +// ТребуемыеТипы - ОписаниеТипов +// УказанныеТипы - ОписаниеТипов +// +Процедура ДобавитьОбъектПланируемыйКУдалению(Объекты, ТребуемыеТипы, МетаданныеИзмерения) + + Если ТребуемыеТипы.Типы().Количество() = 0 Тогда + ЛишниеТипы = МетаданныеИзмерения.Тип; + Иначе + ЛишниеТипы = Новый ОписаниеТипов(МетаданныеИзмерения.Тип,, ТребуемыеТипы.Типы()); + КонецЕсли; + + Если ЛишниеТипы.Типы().Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ЧастиИмени = СтрРазделить(МетаданныеИзмерения.ПолноеИмя(), "."); + ЧастиИмени.Удалить(2); + + ОбновлениеИнформационнойБазы.ДобавитьОбъектПланируемыйКУдалению(Объекты, + СтрСоединить(ЧастиИмени, "."), ЛишниеТипы); + +КонецПроцедуры + +#Область ОбработчикиПодписокНаСобытия + +// Обработчик подписки ОбновитьГруппыЗначенийДоступаПередЗаписью: +// - проверяет изменение родителя и готовит группы доступа, в которых +// нужно обновить значения доступа, выбранные с учетом иерархии. +// +Процедура ОбновитьГруппыЗначенийДоступаПередЗаписью(Знач Источник, Отказ) Экспорт + + // АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал. + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) + Или Источник.ОбменДанными.Загрузка + И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + Если ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() + Или Не Источник.ОбменДанными.Загрузка Тогда + + Если Не ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + УправлениеДоступом.УстановитьБлокировкуПередЗаписьюВФайловойИБ(, Истина); + КонецЕсли; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + СтарыеЗначения = Новый Структура; + Если СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(ТипЗнч(Источник)) <> Неопределено Тогда + СтарыеЗначения.Вставить("Родитель", ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "Родитель")); + КонецЕсли; + Свойства = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипЗнч(Источник)); + Если Свойства <> Неопределено + И Свойства.ТипГруппЗначений <> Тип("Неопределено") + И ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() Тогда + + ИмяПоля = ?(Свойства.НесколькоГруппЗначений, "ГруппыДоступа", "ГруппаДоступа"); + Попытка + ЗначениеПоля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, ИмяПоля); + Исключение + ИменаТаблиц = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Источник.Метаданные().ПолноеИмя()); + ПоТипамСсылокДляОбновления = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления; + РегистрыСведений.ГруппыЗначенийДоступа.ПроверитьМетаданныеТаблиц(ИменаТаблиц, ПоТипамСсылокДляОбновления); + ВызватьИсключение; + КонецПопытки; + СтарыеЗначения.Вставить(ИмяПоля, ЗначениеПоля); + КонецЕсли; + Если ЗначениеЗаполнено(СтарыеЗначения) Тогда + Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомСтарыеЗначения", СтарыеЗначения); + КонецЕсли; + КонецЕсли; + // АПК:75-вкл + + Если Источник.ОбменДанными.Загрузка Тогда + Возврат; + КонецЕсли; + + Если Свойства <> Неопределено Тогда + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(Источник); + КонецЕсли; + +КонецПроцедуры + +// Обработчик подписки ОбновитьГруппыЗначенийДоступаПриЗаписи: +// - вызывает метод записи групп значений доступа в +// регистр сведений ГруппыЗначенийДоступа для требуемых объектов метаданных, +// - обновляет значения групп доступа, выбранные с учетом иерархии. +// +Процедура ОбновитьГруппыЗначенийДоступаПриЗаписи(Источник) Экспорт + + // АПК:75-выкл проверка ОбменДанными.Загрузка должна быть после записи изменений в журнал. + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) + Или Источник.ОбменДанными.Загрузка + И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда + Возврат; + КонецЕсли; + + Если ПользователиСлужебный.РегистрироватьИзмененияПравДоступа() + И Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомСтарыеЗначения") Тогда + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеРазрешенныхЗначений(Источник, + Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + КонецЕсли; + // АПК:75-вкл + + Если Источник.ОбменДанными.Загрузка Тогда + Возврат; + КонецЕсли; + + Если Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомСтарыеЗначения") + И Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения.Свойство("Родитель") + И Источник.Родитель <> Источник.ДополнительныеСвойства.УправлениеДоступомСтарыеЗначения.Родитель Тогда + + ГруппыДоступа = ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипЗнч(Источник.Ссылка)); + РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(ГруппыДоступа); + КонецЕсли; + +КонецПроцедуры + +// Обработчик подписки ОбновитьГруппыВладельцевНастроекПрав на событие ПередЗаписью: +// - вызывает метод записи иерархии владельцев настроек прав объектов в +// регистр сведений НаследованиеНастроекПравОбъектов для требуемых объектов метаданных. +// +Процедура ОбновитьГруппыВладельцевНастроекПрав(Знач Объект, Отказ) Экспорт + + Если Объект.ОбменДанными.Загрузка Тогда + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда + Возврат; + КонецЕсли; + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ВозможныеПраваПоТипам = ВозможныеПрава.ПоТипам; + + Если ВозможныеПраваПоТипам.Получить(ТипЗнч(Объект)) <> Неопределено Тогда + РегистрыСведений.НаследованиеНастроекПравОбъектов.ОбновитьДанныеРегистра(Объект); + КонецЕсли; + +КонецПроцедуры + +// Обработчик подписки ЗаписатьНаборыЗначенийДоступа на событие ПриЗаписи +// вызывает метод записи значений доступа объекта в РегистрСведений.НаборыЗначенийДоступа. +// Возможен случай использования подсистемы "УправлениеДоступом", когда +// указанной подписки не существует, если наборы значений доступа не применяются. +// +Процедура ЗаписатьНаборыЗначенийДоступаПриЗаписи(Знач Объект, Отказ) Экспорт + + // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, + // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. + // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная + // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. + Если Объект.ОбменДанными.Загрузка + И НЕ Объект.ДополнительныеСвойства.Свойство("ЗаписатьНаборыЗначенийДоступа") Тогда + + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда + Возврат; + КонецЕсли; + + ЗаписатьНаборыЗначенийДоступа(Объект, , Объект.ДополнительныеСвойства.Свойство( + "ЗаписьНаборовЗначенийДоступаПриОбновленииИБ")); + +КонецПроцедуры + +// Обработчик подписки ЗаписатьЗависимыеНаборыЗначенийДоступа события ПриЗаписи +// вызывает перезапись зависимых наборов значений доступа в регистре сведений НаборыЗначенийДоступа. +// +// Возможен случай использования подсистемы "УправлениеДоступом", когда +// указанной подписки не существует, если зависимые наборы значений доступа не применяются. +// +Процедура ЗаписатьЗависимыеНаборыЗначенийДоступаПриЗаписи(Знач Объект, Отказ) Экспорт + + // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, + // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. + // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная + // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. + Если Объект.ОбменДанными.Загрузка + И НЕ Объект.ДополнительныеСвойства.Свойство("ЗаписатьЗависимыеНаборыЗначенийДоступа") Тогда + + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Объект) Тогда + Возврат; + КонецЕсли; + + ЗаписатьЗависимыеНаборыЗначенийДоступа(Объект, Объект.ДополнительныеСвойства.Свойство( + "ЗаписьНаборовЗначенийДоступаПриОбновленииИБ")); + +КонецПроцедуры + +// Обработчик подписок ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей* на событие ПередЗаписью +// вызывает заполнение значений доступа табличной части объекта НаборыЗначенийДоступа, +// когда для ограничения доступа к самому объекту используется шаблон #ПоНаборамЗначений. +// Возможен случай использования подсистемы Управление доступом, когда +// указанной подписки не существует, если для указанной цели наборы не применяются. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередЗаписью. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// +// РежимЗаписи - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда тип параметра Источник - ДокументОбъект. +// +// РежимПроведения - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда тип параметра Источник - ДокументОбъект. +// +Процедура ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей(Источник, Отказ = Неопределено, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт + + // Проверка ОбменДанными.Загрузка пропускается только в тех случаях, + // когда дополнительно установлено свойство ЗаписатьНаборыЗначенийДоступа. + // В этом случае при записи ведущего объекта для корректной работы его RLS выполняется программная + // запись подчиненного объекта для обновления служебной табличной части НаборыЗначенийДоступа. + Если Источник.ОбменДанными.Загрузка + И НЕ Источник.ДополнительныеСвойства.Свойство("ЗаписатьНаборыЗначенийДоступа") Тогда + Возврат; + КонецЕсли; + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда + Возврат; + КонецЕсли; + + Если НЕ ( ПривилегированныйРежим() + И Источник.ДополнительныеСвойства.Свойство( + "НаборыЗначенийДоступаТабличнойЧастиЗаполнены")) Тогда + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() + И Не ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + + Если Источник.ЭтоНовый() Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + Иначе + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + КонецЕсли; + + Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Источник); + ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); + Источник.НаборыЗначенийДоступа.Загрузить(Таблица); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиРегламентныхЗаданий + +// Обработчик регламентного задания ЗаполнениеДанныхДляОграниченияДоступа. +Процедура ЗаполнениеДанныхДляОграниченияДоступаОбработчикЗадания() Экспорт + + ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания( + Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа); + + ЗаполнениеДанныхДляОграниченияДоступа(); + +КонецПроцедуры + +// Выполняет последовательное заполнение и обновление данных, необходимых для работы +// подсистемы УправленияДоступом в режиме ограничения доступа на уровне записей. +// +// При включенном режиме ограничения доступа на уровне записей заполняет наборы +// значений доступа. Заполнение выполняется частями при каждом запуске, пока все +// наборы значений доступа не будут заполнены. +// При отключении режима ограничения доступа на уровне записей наборы значений доступа +// (заполненные ранее) удаляются при перезаписи объектов, а не все сразу. +// Независимо от режима ограничения доступа на уровне записей обновляет кэш-реквизиты. +// После завершения всех обновлений и заполнений отключает использование регламентного задания. +// +// Сведения о состоянии работы записываются в журнал регистрации. +// +// Возможно вызывать программно, например, при обновлении информационной базы. +// Также для целей обновления есть форма Справочник.ГруппыДоступа.ОбновлениеДанныхОграниченияДоступа, +// с помощью которой можно сделать интерактивное обновление данных ограничения доступа +// при обновлении информационной базы. +// +Процедура ЗаполнениеДанныхДляОграниченияДоступа(КоличествоДанных = 0, ТолькоКэшРеквизиты = Ложь, ЕстьИзменения = Неопределено) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.ЗаполнениеДанныхДляОграниченияДоступа"); + + УстановитьПривилегированныйРежим(Истина); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами; + + Если Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() И НЕ ТолькоКэшРеквизиты Тогда + + // Заполнение групп значений доступа в регистре сведений ГруппыЗначенийДоступа. + Для Каждого ИмяТаблицы Из ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления Цикл + + Пока КоличествоДанных < 10000 Цикл + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | ТекущаяТаблица.Ссылка + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа + | ПО ТекущаяТаблица.Ссылка = ГруппыЗначенийДоступа.ЗначениеДоступа + | И (ГруппыЗначенийДоступа.ГруппаДанных = 0) + |ГДЕ + | ГруппыЗначенийДоступа.ЗначениеДоступа ЕСТЬ NULL"; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", ИмяТаблицы); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", ИмяТаблицы); + // @skip-check query-in-loop - Порционная обработка данных + Значения = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + Если Не ЗначениеЗаполнено(Значения) Тогда + Прервать; + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(Значения, ЕстьИзменения); + КоличествоДанных = КоличествоДанных + Значения.Количество(); + Если Значения.Количество() < 1000 Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + Если КоличествоДанных < 10000 Тогда + Продолжить; + КонецЕсли; + + Прервать; + + КонецЦикла; + + Если КоличествоДанных < 10000 Тогда + // Обновление оставшихся неактуальных записей, если есть. + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьДанныеРегистра(ЕстьИзменения); + КонецЕсли; + + Если КоличествоДанных < 10000 И Не УправлениеДоступом.ПроизводительныйВариант() Тогда + + // Заполнение регистра сведений НаборыЗначенийДоступа. + ТипыОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа"); + + Для каждого ОписаниеТипа Из ТипыОбъектов Цикл + Тип = ОписаниеТипа.Ключ; + + Если КоличествоДанных < 10000 И Тип <> Тип("Строка") Тогда + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 10000 + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.НаборыЗначенийДоступа КАК РегистрСведенийНаборыЗначенийДоступа + | ПО ТекущаяТаблица.Ссылка = РегистрСведенийНаборыЗначенийДоступа.Объект + |ГДЕ + | РегистрСведенийНаборыЗначенийДоступа.Объект ЕСТЬ NULL "; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Метаданные.НайтиПоТипу(Тип).ПолноеИмя()); + // @skip-check query-in-loop - Порционная обработка данных + Выборка = Запрос.Выполнить().Выбрать(); + КоличествоДанных = КоличествоДанных + Выборка.Количество(); + + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьНаборыЗначенийДоступа(Выборка.Ссылка, ЕстьИзменения); + КонецЦикла; + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + + // Обновление кэш-реквизитов в наборах значений доступа. + Если КоличествоДанных < 10000 И Не УправлениеДоступом.ПроизводительныйВариант() Тогда + + ТипыЗначенийДоступа = СвойстваВидовДоступа.ПоТипамЗначений; + ТипыЗначенийДоступаСГруппами = СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами; + + ТаблицаТиповЗначений = Новый ТаблицаЗначений; + ТаблицаТиповЗначений.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + Для каждого КлючИЗначение Из ТипыЗначенийДоступа Цикл + ТаблицаТиповЗначений.Добавить().ТипЗначений = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); + КонецЦикла; + + ТаблицаТиповЗначенийСГруппами = Новый ТаблицаЗначений; + ТаблицаТиповЗначенийСГруппами.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + Для каждого КлючИЗначение Из ТипыЗначенийДоступаСГруппами Цикл + ТаблицаТиповЗначенийСГруппами.Добавить().ТипЗначений = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТаблицаТиповЗначений", ТаблицаТиповЗначений); + Запрос.УстановитьПараметр("ТаблицаТиповЗначенийСГруппами", ТаблицаТиповЗначенийСГруппами); + Запрос.Текст = + "ВЫБРАТЬ + | ТаблицаТипов.ТипЗначений + |ПОМЕСТИТЬ ТаблицаТиповЗначений + |ИЗ + | &ТаблицаТиповЗначений КАК ТаблицаТипов + | + |ИНДЕКСИРОВАТЬ ПО + | ТаблицаТипов.ТипЗначений + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ТаблицаТипов.ТипЗначений + |ПОМЕСТИТЬ ТаблицаТиповЗначенийСГруппами + |ИЗ + | &ТаблицаТиповЗначенийСГруппами КАК ТаблицаТипов + | + |ИНДЕКСИРОВАТЬ ПО + | ТаблицаТипов.ТипЗначений + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 10000 + | НаборыЗначенийДоступа.Объект, + | НаборыЗначенийДоступа.НомерНабора, + | НаборыЗначенийДоступа.ЗначениеДоступа, + | НаборыЗначенийДоступа.Уточнение, + | НаборыЗначенийДоступа.Чтение, + | НаборыЗначенийДоступа.Изменение + |ИЗ + | РегистрСведений.НаборыЗначенийДоступа КАК НаборыЗначенийДоступа + |ГДЕ + | ВЫБОР + | КОГДА НаборыЗначенийДоступа.СтандартноеЗначение <> ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ТаблицаТиповЗначений КАК ТаблицаТиповЗначений + | ГДЕ + | ТИПЗНАЧЕНИЯ(ТаблицаТиповЗначений.ТипЗначений) = ТИПЗНАЧЕНИЯ(НаборыЗначенийДоступа.ЗначениеДоступа)) + | ТОГДА ИСТИНА + | КОГДА НаборыЗначенийДоступа.СтандартноеЗначение = ИСТИНА + | ТОГДА НаборыЗначенийДоступа.ЗначениеБезГрупп = ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | ТаблицаТиповЗначенийСГруппами КАК ТаблицаТиповЗначенийСГруппами + | ГДЕ + | ТИПЗНАЧЕНИЯ(ТаблицаТиповЗначенийСГруппами.ТипЗначений) = ТИПЗНАЧЕНИЯ(НаборыЗначенийДоступа.ЗначениеДоступа)) + | ИНАЧЕ НаборыЗначенийДоступа.ЗначениеБезГрупп = ИСТИНА + | КОНЕЦ"; + Выборка = Запрос.Выполнить().Выбрать(); + КоличествоДанных = КоличествоДанных + Выборка.Количество(); + + Пока Выборка.Следующий() Цикл + МенеджерЗаписи = РегистрыСведений.НаборыЗначенийДоступа.СоздатьМенеджерЗаписи(); + ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка); + + ТипЗначенияДоступа = ТипЗнч(Выборка.ЗначениеДоступа); + + Если ТипыЗначенийДоступа.Получить(ТипЗначенияДоступа) <> Неопределено Тогда + МенеджерЗаписи.СтандартноеЗначение = Истина; + Если ТипыЗначенийДоступаСГруппами.Получить(ТипЗначенияДоступа) = Неопределено Тогда + МенеджерЗаписи.ЗначениеБезГрупп = Истина; + КонецЕсли; + КонецЕсли; + + МенеджерЗаписи.Записать(); + ЕстьИзменения = Истина; + КонецЦикла; + КонецЕсли; + + Если КоличествоДанных < 10000 Тогда + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + , + , + НСтр("ru = 'Завершено заполнение данных для ограничения доступа.'"), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + + УстановитьЗаполнениеДанныхДляОграниченияДоступа(Ложь); + Иначе + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + , + , + НСтр("ru = 'Выполнена запись части данных для ограничения доступа.'"), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + КонецЕсли; + +КонецПроцедуры + +// Устанавливает использование регламентного задания заполнения данных управления доступом. +// +// Параметры: +// Использование - Булево - Истина, если задание нужно включить, иначе Ложь. +// +Процедура УстановитьЗаполнениеДанныхДляОграниченияДоступа(Знач Использование) Экспорт + + РегламентныеЗаданияСервер.УстановитьИспользованиеПредопределенногоРегламентногоЗадания( + Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа, Использование); + +КонецПроцедуры + +#КонецОбласти + +#Область ПроцедурыИФункцииДляРаботыСВидамиДоступа + +// Возвращает Истина, если вид доступа включен по функциональным опциям для всех сеансов. +// +// Параметры: +// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. +// - Строка - имя вида доступа. +// +// Возвращаемое значение: +// Булево +// +Функция ВидДоступаИспользуется(Знач ВидДоступа) Экспорт + + Если Не УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда + Возврат Ложь; + КонецЕсли; + + СвойстваВидаДоступа = СвойстваВидаДоступа(ВидДоступа); + Если СвойстваВидаДоступа = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТипЗначенийДоступа", СвойстваВидаДоступа.Ссылка); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа + |ГДЕ + | ИспользуемыеВидыДоступа.ТипЗначенийДоступа = &ТипЗначенийДоступа + | И ИспользуемыеВидыДоступа.Используется = ИСТИНА"; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Используется = Не Запрос.Выполнить().Пустой(); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Возврат Используется; + +КонецФункции + +// Параметры: +// БезУчетаОграниченияДоступа - Булево +// +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. +// * Значение - Булево - значение Истина. +// +Функция ИспользуемыеВидыДоступа(БезУчетаОграниченияДоступа = Ложь) Экспорт + + Результат = Новый Соответствие; + + Если Не БезУчетаОграниченияДоступа + И Не УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда + Возврат Результат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ИспользуемыеВидыДоступа.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа + |ГДЕ + | ИспользуемыеВидыДоступа.Используется = ИСТИНА"; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Выборка = Запрос.Выполнить().Выбрать(); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + Пока Выборка.Следующий() Цикл + Если СвойстваВидовДоступа.ПоСсылкам.Получить(Выборка.ТипЗначенийДоступа) = Неопределено Тогда + Продолжить; + КонецЕсли; + Результат.Вставить(Выборка.ТипЗначенийДоступа, Истина); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Возвращает свойства вида доступа или всех видов доступа. +// +// Параметры: +// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа вида доступа. +// - Строка - имя вида доступа. +// +// Возвращаемое значение: +// Структура: +// * Имя - Строка +// * Ссылка - ОпределяемыйТип.ЗначениеДоступа +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// * ДополнительныеТипы - ФиксированныйМассив из см. ДополнительныйТипВидаДоступа +// * ТипыВыбираемыхЗначений - ФиксированныйМассив из Тип +// Неопределено +// +Функция СвойстваВидаДоступа(ВидДоступа) Экспорт + + Свойства = СвойстваВидовДоступа(); + + Если ТипЗнч(ВидДоступа) = Тип("Строка") Тогда + СвойстваВидаДоступа = Свойства.ПоИменам.Получить(ВидДоступа); + Иначе + СвойстваВидаДоступа = Свойства.ПоСсылкам.Получить(ВидДоступа); + КонецЕсли; + + Возврат СвойстваВидаДоступа; + +КонецФункции + +#КонецОбласти + +#Область ПроцедурыИФункцииДляРаботыСНаборамиЗначенийДоступа + +// Возвращает новые наборы для заполнения табличной части. +// +// Параметры: +// Объект - ОпределяемыйТип.ВладелецСОграничениемПоНаборамЗначенийДоступаОбъект +// - ОпределяемыйТип.ВладелецСОграничениемПоНаборамЗначенийДоступаДокумент +// +// Возвращаемое значение: +// см. УправлениеДоступом.ТаблицаНаборыЗначенийДоступа +// +Функция ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект) + + ТипЗначенияОбъект = ТипЗнч(Объект); + + Если Объект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |У объекта типа ""%1"" + |не существует табличная часть %2.'"), + ТипЗначенияОбъект, "НаборыЗначенийДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Таблица = УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(); + + Если НЕ УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() Тогда + Возврат Таблица; + КонецЕсли; + + УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(Объект, Таблица); + + УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( + Таблица, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); + + Возврат Таблица; + +КонецФункции + +// Выполняет обновление наборов значений доступа объекта, если они изменились. +// Наборы обновляются в табличной части (если используется) и +// в регистре сведений НаборыЗначенийДоступа. +// +// Параметры: +// СсылкаИлиОбъект - ЛюбаяСсылка +// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - ссылка или объект, +// для которого записываются наборы значений доступа. +// +// ЕстьИзменения - Булево +// - Неопределено +// +// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// +Процедура ОбновитьНаборыЗначенийДоступа(СсылкаИлиОбъект, ЕстьИзменения = Неопределено, ОбновлениеИБ = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + Объект = ?(СсылкаИлиОбъект = СсылкаИлиОбъект.Ссылка, СсылкаИлиОбъект.ПолучитьОбъект(), СсылкаИлиОбъект); + СсылкаНаОбъект = Объект.Ссылка; + ТипЗначенияОбъект = ТипЗнч(Объект); + + НаборыЗаписываются = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ НаборыЗаписываются Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписке на событие %2.'"), + ТипЗначенияОбъект, + "ЗаписатьНаборыЗначенийДоступа"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип.Типы().Найти(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка при записи наборов значений доступа: + |в регистре сведений %1 в измерении %2 + |не задан тип ""%3""'"), + "НаборыЗначенийДоступа", + "Объект", + ТипЗнч(СсылкаНаОбъект)); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если СсылкаНаОбъект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") <> Неопределено Тогда + // Обновление объекта требуется. + Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект); + + Если НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаОбъект, Таблица) Тогда + ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); + + Объект.ДополнительныеСвойства.Вставить("ЗаписатьНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("ЗаписатьЗависимыеНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("НаборыЗначенийДоступаТабличнойЧастиЗаполнены"); + Объект.НаборыЗначенийДоступа.Загрузить(Таблица); + Если ОбновлениеИБ Тогда + Объект.ДополнительныеСвойства.Вставить("ЗаписьНаборовЗначенийДоступаПриОбновленииИБ"); + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + Иначе + Объект.ОбменДанными.Загрузка = Истина; + // АПК:1327-выкл - №783.1.4.1 Допустимо оставить запись без + // предварительной управляемой блокировки объекта, так как только + // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. + Объект.Записать(); + // АПК:1327-вкл. + КонецЕсли; + ЕстьИзменения = Истина; + КонецЕсли; + КонецЕсли; + + // Обновление объекта не требуется или объект уже обновлен. + ЗаписатьНаборыЗначенийДоступа(Объект, ЕстьИзменения, ОбновлениеИБ); + +КонецПроцедуры + +// Заполняет вспомогательные данные, ускоряющие работу шаблонов ограничений доступа. +// Выполняется перед записью в регистр НаборыЗначенийДоступа. +// +// Параметры: +// СсылкаНаОбъект - ЛюбаяСсылка - ссылка на объект для которого заполняются наборы значений доступа. +// Таблица - ТаблицаЗначений +// ДобавитьКэшРеквизиты - Булево +// +Процедура ПодготовитьНаборыЗначенийДоступаКЗаписи(СсылкаНаОбъект, Таблица, ДобавитьКэшРеквизиты = Ложь) Экспорт + + Если ДобавитьКэшРеквизиты Тогда + + Таблица.Колонки.Добавить("Объект", Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип); + Таблица.Колонки.Добавить("СтандартноеЗначение", Новый ОписаниеТипов("Булево")); + Таблица.Колонки.Добавить("ЗначениеБезГрупп", Новый ОписаниеТипов("Булево")); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ТипыЗначенийДоступаСГруппами = СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами; + ТипыЗначенийДоступа = СвойстваВидовДоступа.ПоТипамЗначений; + КонецЕсли; + + // Нормализация ресурсов Чтение, Изменение. + НомерНабора = -1; + Для каждого Строка Из Таблица Цикл + + Если ДобавитьКэшРеквизиты Тогда + // Установка значения измерения Объект. + Строка.Объект = СсылкаНаОбъект; + + ТипЗначенияДоступа = ТипЗнч(Строка.ЗначениеДоступа); + + Если ТипыЗначенийДоступа.Получить(ТипЗначенияДоступа) <> Неопределено Тогда + Строка.СтандартноеЗначение = Истина; + Если ТипыЗначенийДоступаСГруппами.Получить(ТипЗначенияДоступа) = Неопределено Тогда + Строка.ЗначениеБезГрупп = Истина; + КонецЕсли; + КонецЕсли; + + КонецЕсли; + + // Очистка флажков прав и соответствующих им вторичных данных + // для всех строк каждого набора, кроме первой строки. + Если НомерНабора = Строка.НомерНабора Тогда + Строка.Чтение = Ложь; + Строка.Изменение = Ложь; + Иначе + НомерНабора = Строка.НомерНабора; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти + +#Область ПроцедурыИФункцииДляДействийПриИзмененийНастроекПодсистемы + +// Если необходимо, включает заполнение данных для ограничения доступа и +// обновляет некоторые данные сразу. +// +// Вызывается из обработчика ПриЗаписи константы ОграничиватьДоступаНаУровнеЗаписей. +// +Процедура ПриИзмененииОграниченияДоступаНаУровнеЗаписей(ОграничениеДоступаНаУровнеЗаписейВключено) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(, Истина); + РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); + + Если ОграничениеДоступаНаУровнеЗаписейВключено Тогда + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Заполнение данных для ограничения доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + , + , + НСтр("ru = 'Начато заполнение данных для ограничения доступа.'"), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + + УстановитьЗаполнениеДанныхДляОграниченияДоступа(Истина); + КонецЕсли; + + Если ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина) Тогда + + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "ПриИзмененииОграниченияДоступаНаУровнеЗаписей"); + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + ПараметрыПланирования.Описание = "ОграничиватьДоступНаУровнеЗаписейПриЗаписи"; + ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); + + УстановитьОбновлениеДоступа(Истина); + КонецЕсли; + + ОбновитьПараметрыСеанса(); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбслуживаниеТаблицВидыДоступаИЗначенияДоступаВФормахРедактирования + +// Заполняет вспомогательные данные, требуемые для работы формы, +// которые не зависят от содержания объекта или заполняются для нового объекта. +// +// Форма должна содержать реквизиты, указанные ниже. +// Реквизиты отмеченные символом & заполняются автоматически, но их нужно создать в форме. +// Реквизиты отмеченные символом # должны быть созданы в форме, если +// в форме будет создан реквизит ТекущаяГруппаДоступа (см. ниже). +// Реквизиты отмеченные символом @ будут созданы автоматически. +// +// ТекущаяГруппаДоступа - необязательный реквизит, +// если не создан в форме, тогда не используется. +// +// ВидыДоступа - Таблица с полями: +// #ГруппаДоступа - СправочникСсылка.ГруппыДоступа, +// ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, +// Предустановленный - Булево (только для профиля), +// ВсеРазрешены - Булево, +// &ВидДоступаПредставление - Строка - представление настройки, +// &ВсеРазрешеныПредставление - Строка - представление настройки, +// @Используется - Булево. +// +// ЗначенияДоступа - Таблица с полями: +// #ГруппаДоступа - СправочникСсылка.ГруппыДоступа, +// &ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, +// ЗначениеДоступа - ОпределяемыйТип.ЗначениеДоступа, +// &НомерСтрокиПоВиду - Число. +// +// &ИспользоватьВнешнихПользователей - Булево - реквизит будет создан, если нет в форме. +// &НадписьВидДоступа - Строка - представление текущего вида доступа в форме. +// @ЭтоПрофильГруппДоступа - Булево. +// @ТекущийВидДоступа - ОпределяемыйТип.ЗначениеДоступа. +// @ТекущиеТипыВыбираемыхЗначений - СписокЗначений. +// @ТекущийТипВыбираемыхЗначений - ОпределяемыйТип.ЗначениеДоступа. +// @ИмяРеквизитаХранилищаТаблиц - Строка. +// @ВидДоступаПользователи - ОпределяемыйТип.ЗначениеДоступа. +// @ВидДоступаВнешниеПользователи - ОпределяемыйТип.ЗначениеДоступа. +// +// @ВсеВидыДоступа - Таблица с полями: +// @Ссылка - ОпределяемыйТип.ЗначениеДоступа, +// @Представление - Строка, +// @Используется - Булево. +// +// @ПредставленияВсеРазрешены - Таблица с полями: +// @Имя - Строка, +// @Представление - Строка. +// +// @ВсеТипыВыбираемыхЗначений - Таблица с полями: +// @ВидДоступа - ОпределяемыйТип.ЗначениеДоступа, +// @ТипЗначений - ОпределяемыйТип.ЗначениеДоступа, +// @ПредставлениеТипа - Строка, +// @ИмяТаблицы - Строка, +// @ИерархияЭлементов - Булево. +// +// Параметры: +// Форма - см. УправлениеДоступомСлужебныйКлиентСервер.ПараметрыФормыРедактированияРазрешенныхЗначений +// +// ЭтоПрофиль - Булево - указывает, что возможна настройка видов доступа +// в том числе представление настройки содержит 4 значения, а не 2. +// +// ИмяРеквизитаХранилищаТаблиц - Строка - содержащая, например, строку "Объект", которая +// содержит таблицы ВидыДоступа и ЗначенияДоступа (см. ниже). +// Если указана пустая строка, тогда считается, +// что таблицы хранятся в реквизитах формы. +// +Процедура ПриСозданииНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ЭтоПрофиль = Ложь, ИмяРеквизитаХранилищаТаблиц = "Объект") Экспорт + + ДобавитьРеквизитыВспомогательныхДанныхВФорму(Форма, ИмяРеквизитаХранилищаТаблиц); + + Форма.ИмяРеквизитаХранилищаТаблиц = ИмяРеквизитаХранилищаТаблиц; + Форма.ЭтоПрофильГруппДоступа = ЭтоПрофиль; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + // Заполнение типов значений доступа всех видов доступа. + Для каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл + Для каждого Тип Из СвойстваВидаДоступа.ТипыВыбираемыхЗначений Цикл + МассивТипов = Новый Массив; + МассивТипов.Добавить(Тип); + ОписаниеТипа = Новый ОписаниеТипов(МассивТипов); + + МетаданныеТипа = Метаданные.НайтиПоТипу(Тип); + Если Метаданные.Перечисления.Найти(МетаданныеТипа.Имя) = МетаданныеТипа Тогда + ПредставлениеТипа = МетаданныеТипа.Представление(); + Иначе + ПредставлениеТипа = ?(ЗначениеЗаполнено(МетаданныеТипа.ПредставлениеОбъекта), + МетаданныеТипа.ПредставлениеОбъекта, + МетаданныеТипа.Представление()); + КонецЕсли; + + НоваяСтрока = Форма.ВсеТипыВыбираемыхЗначений.Добавить(); + НоваяСтрока.ВидДоступа = СвойстваВидаДоступа.Ссылка; + НоваяСтрока.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + НоваяСтрока.ПредставлениеТипа = ПредставлениеТипа; + НоваяСтрока.ИмяТаблицы = МетаданныеТипа.ПолноеИмя(); + НоваяСтрока.ИерархияЭлементов = СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(Тип) <> Неопределено; + КонецЦикла; + КонецЦикла; + + Форма.ВидДоступаПользователи = Справочники.Пользователи.ПустаяСсылка(); + Форма.ВидДоступаВнешниеПользователи = Справочники.ВнешниеПользователи.ПустаяСсылка(); + Форма.ИспользоватьВнешнихПользователей = ВнешниеПользователи.ИспользоватьВнешнихПользователей(); + + ЗаполнитьТаблицуВсеВидыДоступаВФорме(Форма); + + ЗаполнитьТаблицуПредставленияВсеРазрешеныВФорме(Форма, ЭтоПрофиль); + + ОформитьТаблицуВидыДоступаВФорме(Форма); + + ОформитьТаблицуЗначенияДоступаВФорме(Форма); + + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); + УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); + + ОбновитьОтображениеНеиспользуемыхВидовДоступа(Форма, Истина); + + // Настройка параметров выбора значения доступа. + ПараметрыВыбора = Новый Массив; + ПараметрыВыбора.Добавить(Новый ПараметрВыбора("ЭтоВыборЗначенияДоступа", Истина)); + Форма.Элементы.ЗначенияДоступаЗначениеДоступа.ПараметрыВыбора = Новый ФиксированныйМассив(ПараметрыВыбора); + +КонецПроцедуры + +// При повторном чтении заполняет или обновляет вспомогательные данные, +// требуемые для работы формы, которые зависят от содержания объекта. +// +Процедура ПриПовторномЧтенииНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект) Экспорт + + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект); + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); + + УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); + + УправлениеДоступомСлужебныйКлиентСервер.ПриИзмененииТекущегоВидаДоступа(Форма, Ложь); + +КонецПроцедуры + +// Удаляет лишние значения доступа перед записью. +// Лишние значения доступа могут появиться, если заменить или удалить вид доступа, +// для которого введены значения доступа. +// +Процедура ПередЗаписьюНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект) Экспорт + + УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект); + УдалитьЛишниеЗначенияДоступа(Форма); + +КонецПроцедуры + +// Обновляет свойства видов доступа. +Процедура ПослеЗаписиНаСервереФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект, ПараметрыЗаписи) Экспорт + + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект); + УдалитьНесуществующиеВидыИЗначенияДоступа(Форма); + + УправлениеДоступомСлужебныйКлиентСервер.ЗаполнитьСвойстваВидовДоступаВФорме(Форма); + +КонецПроцедуры + +// Скрывает или показывает неиспользуемые виды доступа. +Процедура ОбновитьОтображениеНеиспользуемыхВидовДоступа(Форма, ПриСозданииНаСервере = Ложь) Экспорт + + Элементы = Форма.Элементы; + + Если Не ПриСозданииНаСервере Тогда + Элементы.ПоказыватьНеИспользуемыеВидыДоступа.Пометка = + НЕ Элементы.ПоказыватьНеИспользуемыеВидыДоступа.Пометка; + КонецЕсли; + + Отбор = УправлениеДоступомСлужебныйКлиентСервер.ОтборВТаблицахФормыРедактированияРазрешенныхЗначений( + Форма); + + Если Не Элементы.ПоказыватьНеиспользуемыеВидыДоступа.Пометка Тогда + Отбор.Вставить("Используется", Истина); + КонецЕсли; + + Элементы.ВидыДоступа.ОтборСтрок = Новый ФиксированнаяСтруктура(Отбор); + + Элементы.ВидыДоступаВидДоступаПредставление.СписокВыбора.Очистить(); + + Для каждого Строка Из Форма.ВсеВидыДоступа Цикл + + Если Не Элементы.ПоказыватьНеиспользуемыеВидыДоступа.Пометка + И Не Строка.Используется Тогда + + Продолжить; + КонецЕсли; + + Элементы.ВидыДоступаВидДоступаПредставление.СписокВыбора.Добавить(Строка.Представление); + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти + +#Область УниверсальныеПроцедурыИФункции + +// Только для внутреннего использования. +Процедура УстановитьУсловиеОтбораВЗапросе(Знач Запрос, Знач Значения, Знач ИмяПараметраЗначений, Знач ИмяПараметраУсловияОтбораИмяПоля) Экспорт + + Если Значения = Неопределено Тогда + + ИначеЕсли ТипЗнч(Значения) <> Тип("Массив") + И ТипЗнч(Значения) <> Тип("ФиксированныйМассив") Тогда + + Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения); + + ИначеЕсли Значения.Количество() = 1 Тогда + Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения[0]); + Иначе + Запрос.УстановитьПараметр(ИмяПараметраЗначений, Значения); + КонецЕсли; + + Для НомерСтроки = 1 По СтрЧислоСтрок(ИмяПараметраУсловияОтбораИмяПоля) Цикл + ТекущаяСтрока = СтрПолучитьСтроку(ИмяПараметраУсловияОтбораИмяПоля, НомерСтроки); + Если НЕ ЗначениеЗаполнено(ТекущаяСтрока) Тогда + Продолжить; + КонецЕсли; + ИндексРазделителя = СтрНайти(ТекущаяСтрока, ":"); + Если ИндексРазделителя = 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка при выполнении процедуры %1. + | + |В параметре %2 не существует разделитель (двоеточие) + |в следующей строке формата ""%3"" + |""%4"".'"), + "УправлениеДоступом.УстановитьУсловиеОтбораВЗапросе", + "ИмяПараметраУсловияОтбораИмяПоля", + "<ИмяПараметраУсловия>:<ИмяПоля>", + ТекущаяСтрока); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + ИмяПараметраУсловияОтбора = Лев(ТекущаяСтрока, ИндексРазделителя-1); + ИмяПоля = Сред(ТекущаяСтрока, ИндексРазделителя+1); + Если Значения = Неопределено Тогда + УсловиеОтбора = "Истина"; + + ИначеЕсли ТипЗнч(Значения) <> Тип("Массив") + И ТипЗнч(Значения) <> Тип("ФиксированныйМассив") Тогда + + УсловиеОтбора = ИмяПоля + " = &" + ИмяПараметраЗначений; + + ИначеЕсли Значения.Количество() = 1 Тогда + УсловиеОтбора = ИмяПоля + " = &" + ИмяПараметраЗначений; + Иначе + УсловиеОтбора = ИмяПоля + " В (&" + ИмяПараметраЗначений + ")"; + КонецЕсли; + Запрос.Текст = СтрЗаменить(Запрос.Текст, ИмяПараметраУсловияОтбора, УсловиеОтбора); + КонецЦикла; + +КонецПроцедуры + +// Обновляет набор записей в базе данных, +// если записи набора отличаются от записей в базе данных. +// +// Параметры: +// Данные - Структура: +// * НаборЗаписей - РегистрСведенийНаборЗаписей - пустой или прочитанный с заданным отбором или без. +// - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. +// +// * НовыеЗаписи - ТаблицаЗначений - в формате регистра. +// +// * ПоляСравнения - Строка - содержит список полей по значениям которых требуется вычислять +// отличие записей набора. Например, "Измерение1, Измерение2, Ресурс1", +// а реквизит ДатаИзмерения не входит в список. +// +// * ПолеОтбора - Неопределено - записывается весь регистр или +// отбор уже задан в наборе записей. +// Строка - имя поля по которому нужно установить отбор. +// +// * ЗначениеОтбора - Отбор - значение, которое будет установлено в качестве отбора +// по полю отбора, если поле отбора задано. +// +// * НаборЗаписейПрочитан - Булево - если Истина, тогда не заданный набор записей уже содержит +// прочитанные записи блокировка данных этих записей установлена и +// транзакция открыта. +// +// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, +// а лишь выявить необходимость записи и установить +// свойство ЕстьИзменения. +// +// * ДополнительныеСвойства - Структура +// - Неопределено - если Структура, тогда в +// объекты <Регистр*>НаборЗаписей в свойство ДополнительныеСвойства +// будут вставлены все параметры структуры. +// +// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций +// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления +// общего модуля ОбновлениеИнформационнойБазы. +// +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +// ИзмененныеЗаписи - Неопределено - никаких действий, иначе +// возвращает таблицу значений в формате регистра с полем ВидИзмененияСтроки +// типа Число (-1 запись удалена, 1 запись добавлена). +// +Процедура ОбновитьНаборЗаписей(Знач Данные, ЕстьИзменения = Неопределено, ИзмененныеЗаписи = Неопределено) Экспорт + + ВсеПараметры = Новый Структура; + ВсеПараметры.Вставить("НаборЗаписей"); + ВсеПараметры.Вставить("НовыеЗаписи"); + ВсеПараметры.Вставить("ПоляСравнения"); + ВсеПараметры.Вставить("ПолеОтбора"); + ВсеПараметры.Вставить("ЗначениеОтбора"); + ВсеПараметры.Вставить("НаборЗаписейПрочитан", Ложь); + ВсеПараметры.Вставить("БезПерезаписи", Ложь); + ВсеПараметры.Вставить("ТолькоПроверка", Ложь); + ВсеПараметры.Вставить("ДополнительныеСвойства"); + ВсеПараметры.Вставить("ОбновлениеИБ", + ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() + Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); + + ЗаполнитьПараметры(Данные, ВсеПараметры, "НаборЗаписей, НовыеЗаписи"); + + ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(Данные.НаборЗаписей)).ПолноеИмя(); + МенеджерРегистра = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмяРегистра); + Если Данные.НаборЗаписей = МенеджерРегистра Тогда + НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей(); // РегистрСведенийНаборЗаписей + Иначе + НаборЗаписей = Данные.НаборЗаписей; // РегистрСведенийНаборЗаписей + КонецЕсли; + НовыеЗаписи = Данные.НовыеЗаписи; + ПолеОтбора = Данные.ПолеОтбора; + ЗначениеОтбора = Данные.ЗначениеОтбора; + + Если ЗначениеЗаполнено(ПолеОтбора) Тогда + УстановитьОтбор(НаборЗаписей.Отбор[ПолеОтбора], ЗначениеОтбора); + КонецЕсли; + + Если НЕ Данные.НаборЗаписейПрочитан Тогда + ЗаблокироватьОбластьНабораЗаписей(НаборЗаписей, ПолноеИмяРегистра); + НаборЗаписей.Прочитать(); + КонецЕсли; + + Данные.ПоляСравнения = ?(Данные.ПоляСравнения = Неопределено, + ПоляНабораЗаписей(НаборЗаписей), Данные.ПоляСравнения); + + Если Данные.БезПерезаписи Тогда + НаборЗаписи = МенеджерРегистра.СоздатьНаборЗаписей(); + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); + ОтборЗаписи = Новый Структура(ОписаниеКлючаЗаписи.СписокПолей); + ПоляОстальныхИзмерений = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + Если ОписаниеПоля.Имя <> ПолеОтбора Тогда + ПоляОстальныхИзмерений.Добавить(ОписаниеПоля.Имя); + КонецЕсли; + КонецЦикла; + УдаляемыеЗаписи = Новый ТаблицаЗначений; + Для каждого Поле Из ПоляОстальныхИзмерений Цикл + УдаляемыеЗаписи.Колонки.Добавить(Поле); + КонецЦикла; + Данные.НовыеЗаписи = НовыеЗаписи.Скопировать(); + НовыеЗаписи = Данные.НовыеЗаписи; + КонецЕсли; + + ЕстьТекущиеИзменения = Ложь; + Если ИзмененныеЗаписи = Неопределено Тогда + Если НаборЗаписей.Количество() = НовыеЗаписи.Количество() ИЛИ Данные.БезПерезаписи Тогда + Отбор = Новый Структура(Данные.ПоляСравнения); + НовыеЗаписи.Индексы.Добавить(Данные.ПоляСравнения); + Для Каждого Запись Из НаборЗаписей Цикл + ЗаполнитьЗначенияСвойств(Отбор, Запись); + НайденныеСтроки = НовыеЗаписи.НайтиСтроки(Отбор); + Если НайденныеСтроки.Количество() = 0 Тогда + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + Если Данные.БезПерезаписи Тогда + ЗаполнитьЗначенияСвойств(ОтборЗаписи, Запись); + Если НовыеЗаписи.НайтиСтроки(ОтборЗаписи).Количество() = 0 Тогда + ЗаполнитьЗначенияСвойств(УдаляемыеЗаписи.Добавить(), ОтборЗаписи); + КонецЕсли; + Иначе + Прервать; + КонецЕсли; + ИначеЕсли Данные.БезПерезаписи Тогда + НовыеЗаписи.Удалить(НайденныеСтроки[0]); + КонецЕсли; + КонецЦикла; + Если Данные.БезПерезаписи И НовыеЗаписи.Количество() > 0 Тогда + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + КонецЕсли; + Иначе + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + КонецЕсли; + Иначе + Если НаборЗаписей.Количество() <> НовыеЗаписи.Количество() Тогда + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + КонецЕсли; + Если НаборЗаписей.Количество() > НовыеЗаписи.Количество() Тогда + ИзмененныеЗаписи = НаборЗаписей.Выгрузить(); + ИскомыеЗаписи = НовыеЗаписи; + ВидИзмененияСтроки = -1; + Иначе + ИзмененныеЗаписи = НовыеЗаписи.Скопировать(); + ИскомыеЗаписи = НаборЗаписей.Выгрузить(); + ВидИзмененияСтроки = 1; + КонецЕсли; + ИзмененныеЗаписи.Колонки.Добавить("ВидИзмененияСтроки", Новый ОписаниеТипов("Число")); + ИзмененныеЗаписи.ЗаполнитьЗначения(ВидИзмененияСтроки, "ВидИзмененияСтроки"); + ВидИзмененияСтроки = ?(ВидИзмененияСтроки = 1, -1, 1); + Отбор = Новый Структура(Данные.ПоляСравнения); + + Для каждого Строка Из ИскомыеЗаписи Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Строки = ИзмененныеЗаписи.НайтиСтроки(Отбор); + Если Строки.Количество() = 0 Тогда + НоваяСтрока = ИзмененныеЗаписи.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Отбор); + НоваяСтрока.ВидИзмененияСтроки = ВидИзмененияСтроки; + ЕстьТекущиеИзменения = Истина; + ЕстьИзменения = Истина; + Иначе + ИзмененныеЗаписи.Удалить(Строки[0]); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если ЕстьТекущиеИзменения Тогда + Если Данные.ТолькоПроверка Тогда + Возврат; + КонецЕсли; + Если Данные.БезПерезаписи Тогда + УстановитьДополнительныеСвойства(НаборЗаписи, Данные.ДополнительныеСвойства); + Для каждого Строка Из УдаляемыеЗаписи Цикл + Если ЗначениеЗаполнено(ПолеОтбора) Тогда + УстановитьОтбор(НаборЗаписи.Отбор[ПолеОтбора], ЗначениеОтбора); + КонецЕсли; + Для каждого Поле Из ПоляОстальныхИзмерений Цикл + УстановитьОтбор(НаборЗаписи.Отбор[Поле], Строка[Поле]); + КонецЦикла; + ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписи); + КонецЦикла; + НаборЗаписи.Добавить(); + Для каждого Строка Из НовыеЗаписи Цикл + Если ЗначениеЗаполнено(ПолеОтбора) Тогда + УстановитьОтбор(НаборЗаписи.Отбор[ПолеОтбора], ЗначениеОтбора); + КонецЕсли; + Для каждого Поле Из ПоляОстальныхИзмерений Цикл + УстановитьОтбор(НаборЗаписи.Отбор[Поле], Строка[Поле]); + КонецЦикла; + ЗаполнитьЗначенияСвойств(НаборЗаписи[0], Строка); + ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписи); + КонецЦикла; + Иначе + УстановитьДополнительныеСвойства(НаборЗаписей, Данные.ДополнительныеСвойства); + НаборЗаписей.Загрузить(НовыеЗаписи); + ЗаписатьОбъектИлиНаборЗаписей(Данные, НаборЗаписей); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Обновляет строки регистра с отбором по нескольким значениям для одного или +// для двух измерений регистра, выполняется проверка наличия изменений, +// если изменений нет, перезапись не производится. +// +// Параметры: +// Данные - Структура: +// * МенеджерРегистра - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. +// +// * НовыеЗаписи - ТаблицаЗначений - в формате регистра. +// +// * ПоляСравнения - Строка - содержит список полей по значениям которых требуется +// вычислять отличие записей набора, например, "Измерение1, Измерение2, +// Ресурс1", а реквизит ДатаИзменения не входит в список. +// +// * ИмяПервогоИзмерения - Неопределено - нет отбора по измерению. +// - Строка - содержит имя первого измерения, для которого задано +// несколько значений. +// +// * ЗначенияПервогоИзмерения - Неопределено - нет отбора по измерению, аналогично, +// ИмяПервогоИзмерения = Неопределено. +// - ЛюбаяСсылка - содержит одно значение отбора регистра для +// обновляемых записей. +// - Массив - содержит массив значений отбора регистра для +// обновляемых записей, пустой массив - значит +// действий не требуется. +// +// * ИмяВторогоИзмерения - Неопределено +// - Строка - аналогично ИмяПервогоИзмерения. +// * ЗначенияВторогоИзмерения - Неопределено +// - ЛюбаяСсылка +// - Массив - аналогично ЗначенияПервогоИзмерения. +// * ИмяТретьегоИзмерения - Неопределено +// - Строка - аналогично ИмяПервогоИзмерения. +// * ЗначенияТретьегоИзмерения - Неопределено +// - ЛюбаяСсылка +// - Массив - аналогично ЗначенияПервогоИзмерения. +// +// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, +// а лишь выявить необходимость записи и установить +// свойство ЕстьИзменения. +// +// * ДополнительныеСвойства - Неопределено +// - Структура - если Структура, тогда в +// объекты <Регистр*>НаборЗаписей в свойство +// ДополнительныеСвойства будут вставлены все параметры структуры. +// +// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций +// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления +// общего модуля ОбновлениеИнформационнойБазы. +// +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +Процедура ОбновитьНаборыЗаписей(Знач Данные, ЕстьИзменения) + + ВсеПараметры = Новый Структура; + ВсеПараметры.Вставить("МенеджерРегистра"); + ВсеПараметры.Вставить("НовыеЗаписи"); + ВсеПараметры.Вставить("ПоляСравнения"); + ВсеПараметры.Вставить("ИмяПервогоИзмерения"); + ВсеПараметры.Вставить("ЗначенияПервогоИзмерения"); + ВсеПараметры.Вставить("ИмяВторогоИзмерения"); + ВсеПараметры.Вставить("ЗначенияВторогоИзмерения"); + ВсеПараметры.Вставить("ИмяТретьегоИзмерения"); + ВсеПараметры.Вставить("ЗначенияТретьегоИзмерения"); + ВсеПараметры.Вставить("НовыеЗаписиСодержатТолькоРазличия", Ложь); + ВсеПараметры.Вставить("ФиксированныйОтбор"); + ВсеПараметры.Вставить("ТолькоПроверка", Ложь); + ВсеПараметры.Вставить("ДополнительныеСвойства"); + ВсеПараметры.Вставить("ОбновлениеИБ", + ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() + Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); + + ЗаполнитьПараметры(Данные, ВсеПараметры, "МенеджерРегистра, НовыеЗаписи"); + + // Предварительная обработка параметров. + + Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяПервогоИзмерения, Данные.ЗначенияПервогоИзмерения) Тогда + ЕстьИзменения = Истина; + Возврат; + КонецЕсли; + Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяВторогоИзмерения, Данные.ЗначенияВторогоИзмерения) Тогда + ЕстьИзменения = Истина; + Возврат; + КонецЕсли; + Если НЕ ГруппаПараметровИзмеренияОбработана(Данные.ИмяТретьегоИзмерения, Данные.ЗначенияТретьегоИзмерения) Тогда + ЕстьИзменения = Истина; + Возврат; + КонецЕсли; + + УпорядочитьГруппыПараметровИзмерений(Данные); + + // Проверка и обновление данных. + Данные.Вставить("НаборЗаписей", Данные.МенеджерРегистра.СоздатьНаборЗаписей()); + Данные.Вставить("МетаданныеРегистра", Метаданные.НайтиПоТипу(ТипЗнч(Данные.НаборЗаписей))); + Данные.Вставить("ПолноеИмяРегистра", Данные.МетаданныеРегистра.ПолноеИмя()); + + Если Данные.НовыеЗаписиСодержатТолькоРазличия Тогда + Данные.Вставить("НаборДляОднойЗаписи", Данные.МенеджерРегистра.СоздатьНаборЗаписей()); + КонецЕсли; + + Если Данные.ФиксированныйОтбор <> Неопределено Тогда + Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[КлючИЗначение.Ключ], КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + Если Данные.НовыеЗаписиСодержатТолькоРазличия Тогда + + Если Данные.ИмяПервогоИзмерения = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректные параметры в процедуре %1.'"), + "ОбновитьНаборыЗаписей"); + ВызватьИсключение ТекстОшибки; + Иначе + Если Данные.ИмяВторогоИзмерения = Неопределено Тогда + ЗаписьНесколькимиНаборами = Ложь; + Иначе + ЗаписьНесколькимиНаборами = ЗаписьНесколькимиНаборами(Данные, + Новый Структура, Данные.ИмяПервогоИзмерения, Данные.ЗначенияПервогоИзмерения); + КонецЕсли; + + Если ЗаписьНесколькимиНаборами Тогда + СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения; + Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); + + КоличествоПоЗначениямПервогоИзмерения = Данные.КоличествоПоЗначениям; + + Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл + Отбор = Новый Структура(Данные.ИмяПервогоИзмерения, ПервоеЗначение); + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); + + Если Данные.ИмяТретьегоИзмерения = Неопределено Тогда + ЗаписьНесколькимиНаборами = Ложь; + Иначе + // @skip-check query-in-loop - Порционная обработка данных + ЗаписьНесколькимиНаборами = ЗаписьНесколькимиНаборами(Данные, + Отбор, Данные.ИмяВторогоИзмерения, Данные.ЗначенияВторогоИзмерения); + КонецЕсли; + + Если ЗаписьНесколькимиНаборами Тогда + Для каждого ВтороеЗначение Из Данные.ЗначенияВторогоИзмерения Цикл + Отбор.Вставить(Данные.ИмяВторогоИзмерения, ВтороеЗначение); + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения], ВтороеЗначение); + + // Обновление по трем измерениям. + ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Отбор, ЕстьИзменения); + КонецЦикла; + Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения].Использование = Ложь; + Иначе + // Обновление по двум измерениям. + Данные.Вставить("КоличествоПоЗначениям", КоличествоПоЗначениямПервогоИзмерения); + ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Отбор, ЕстьИзменения); + КонецЕсли; + КонецЦикла; + Иначе + // Обновление по одному измерению. + ПрочитатьКоличествоДляЧтения(Данные); + ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Данные, Новый Структура, ЕстьИзменения); + КонецЕсли; + КонецЕсли; + Иначе + Если Данные.ИмяПервогоИзмерения = Неопределено Тогда + // Обновление всех записей. + + ТекущиеДанные = Новый Структура("НаборЗаписей, НовыеЗаписи, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + + ИначеЕсли Данные.ИмяВторогоИзмерения = Неопределено Тогда + // Обновление по одному измерению. + Отбор = Новый Структура(Данные.ИмяПервогоИзмерения); + Для каждого Значение Из Данные.ЗначенияПервогоИзмерения Цикл + + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], Значение); + Отбор[Данные.ИмяПервогоИзмерения] = Значение; + + Если Данные.ЗначенияПервогоИзмерения.Количество() <> 1 Тогда + НовыеЗаписиНабора = Данные.НовыеЗаписи; + Иначе + НовыеЗаписиНабора = Данные.НовыеЗаписи.Скопировать(Отбор); + КонецЕсли; + + ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); + + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + КонецЦикла; + + ИначеЕсли Данные.ИмяТретьегоИзмерения = Неопределено Тогда + // Обновление по двум измерениям. + СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения; + Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); + Отбор = Новый Структура(СписокПолей); + + Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); + Отбор[Данные.ИмяПервогоИзмерения] = ПервоеЗначение; + + ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям( + Данные, + Отбор, + СписокПолей, + Данные.ИмяВторогоИзмерения, + Данные.ЗначенияВторогоИзмерения, + ЕстьИзменения); + КонецЦикла; + Иначе + // Обновление по трем измерениям. + СписокПолей = Данные.ИмяПервогоИзмерения + ", " + Данные.ИмяВторогоИзмерения + ", " + Данные.ИмяТретьегоИзмерения; + Данные.НовыеЗаписи.Индексы.Добавить(СписокПолей); + Отбор = Новый Структура(СписокПолей); + + Для каждого ПервоеЗначение Из Данные.ЗначенияПервогоИзмерения Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяПервогоИзмерения], ПервоеЗначение); + Отбор[Данные.ИмяПервогоИзмерения] = ПервоеЗначение; + + Для каждого ВтороеЗначение Из Данные.ЗначенияВторогоИзмерения Цикл + УстановитьОтбор(Данные.НаборЗаписей.Отбор[Данные.ИмяВторогоИзмерения], ВтороеЗначение); + Отбор[Данные.ИмяВторогоИзмерения] = ВтороеЗначение; + + ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям( + Данные, + Отбор, + СписокПолей, + Данные.ИмяВторогоИзмерения, + Данные.ЗначенияВторогоИзмерения, + ЕстьИзменения); + КонецЦикла; + КонецЦикла; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Обновляет регистр сведений по данным в таблице значений ИзмененияСтрок. +// +// Параметры: +// Данные - Структура: +// +// * МенеджерРегистра - РегистрСведенийМенеджер - менеджер регистра для создания набора записей. +// +// * ИзмененияСоставаСтрок - ТаблицаЗначений - содержащей поля регистра и +// поле ВидИзмененияСтроки (Число): +// " 1" - значит, что строку нужно добавить, +// "-1" - значит, что строку нужно удалить. +// +// * ФиксированныйОтбор - Структура - содержащая имя измерения в ключе и значение +// отбора в значении. Может быть указана, когда измерений +// более 3-х и заранее известно, что по измерениям сверх 3-х +// будет единственное значение. Измерения указанные в +// фиксированном отборе не используются при формировании +// наборов записей для выполнения обновления. +// +// * ИзмеренияОтбора - Строка - измерений перечисленных через запятую, которые +// нужно использовать при формировании наборов записей +// для выполнения обновления (не более 3-х). Не указанные +// измерения будут превращены в фиксированный отбор, +// если по ним все значения совпадают. +// +// * ТолькоПроверка - Булево - если Истина, тогда не выполнять запись, +// а лишь выявить необходимость записи и установить +// свойство ЕстьИзменения. +// +// * ДополнительныеСвойства - Неопределено +// - Структура - если Структура, тогда в +// объекты <Регистр*>НаборЗаписей в свойство +// ДополнительныеСвойства будут вставлены все параметры структуры. +// +// * ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// Если свойство не вставлено, то значение вычисляется по "Или" с помощью функций +// ВыполняетсяОбновлениеИнформационнойБазы и ЭтоВызовИзОбработчикаОбновления +// общего модуля ОбновлениеИнформационнойБазы. +// +// ЕстьИзменения - Булево - возвращаемое значение. Если производилась запись, +// устанавливается Истина, иначе не изменяется. +// +Процедура ОбновитьРегистрСведений(Знач Данные, ЕстьИзменения = Неопределено) Экспорт + + Если Данные.ИзмененияСоставаСтрок.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ВсеПараметры = Новый Структура; + ВсеПараметры.Вставить("МенеджерРегистра"); + ВсеПараметры.Вставить("ИзмененияСоставаСтрок"); + ВсеПараметры.Вставить("ФиксированныйОтбор", Новый Структура); + ВсеПараметры.Вставить("ИзмеренияОтбора"); + ВсеПараметры.Вставить("ТолькоПроверка", Ложь); + ВсеПараметры.Вставить("ДополнительныеСвойства"); + ВсеПараметры.Вставить("ОбновлениеИБ", + ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы() + Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления()); + + ЗаполнитьПараметры(Данные, ВсеПараметры, "МенеджерРегистра, ИзмененияСоставаСтрок"); + + МетаданныеРегистра = Метаданные.НайтиПоТипу(ТипЗнч(Данные.МенеджерРегистра.ПустойКлюч())); + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(МетаданныеРегистра.ПолноеИмя()); + + Если Данные.ИзмеренияОтбора <> Неопределено Тогда + Данные.ИзмеренияОтбора = Новый Структура(Данные.ИзмеренияОтбора); + КонецЕсли; + + МассивИзмеренийОтбора = Новый Массив; + ЗначенияИзмеренийОтбора = Новый Структура; + ИзмерениеБезФиксированногоОтбора = Новый Структура; + + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + Поле = ОписаниеПоля.Имя; + Если Не Данные.ФиксированныйОтбор.Свойство(Поле) Тогда + Значения = ЗначенияКолонкиТаблицы(Данные.ИзмененияСоставаСтрок, Поле); + + Если Значения.Количество() = 1 Тогда + Данные.ФиксированныйОтбор.Вставить(Поле, Значения[0]); + Продолжить; + КонецЕсли; + + Если Данные.ИзмеренияОтбора = Неопределено + Или Данные.ИзмеренияОтбора.Свойство(Поле) Тогда + + МассивИзмеренийОтбора.Добавить(Поле); + ЗначенияИзмеренийОтбора.Вставить(Поле, Значения); + + ИначеЕсли Не ЗначениеЗаполнено(ИзмерениеБезФиксированногоОтбора) Тогда + ИзмерениеБезФиксированногоОтбора.Вставить("Поле", Поле); + ИзмерениеБезФиксированногоОтбора.Вставить("Значения", Значения); + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если МассивИзмеренийОтбора.Количество() = 0 Тогда + Если ЗначениеЗаполнено(ИзмерениеБезФиксированногоОтбора) Тогда + Поле = ИзмерениеБезФиксированногоОтбора.Поле; + Значения = ИзмерениеБезФиксированногоОтбора.Значения; + КонецЕсли; + МассивИзмеренийОтбора.Добавить(Поле); + ЗначенияИзмеренийОтбора.Вставить(Поле, Значения); + КонецЕсли; + + Данные.Вставить("ИмяПервогоИзмерения", МассивИзмеренийОтбора[0]); + Данные.Вставить("ЗначенияПервогоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяПервогоИзмерения]); + + Если МассивИзмеренийОтбора.Количество() > 1 Тогда + Данные.Вставить("ИмяВторогоИзмерения", МассивИзмеренийОтбора[1]); + Данные.Вставить("ЗначенияВторогоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяВторогоИзмерения]); + Иначе + Данные.Вставить("ИмяВторогоИзмерения", Неопределено); + Данные.Вставить("ЗначенияВторогоИзмерения", Неопределено); + КонецЕсли; + + Если МассивИзмеренийОтбора.Количество() > 2 Тогда + Данные.Вставить("ИмяТретьегоИзмерения", МассивИзмеренийОтбора[2]); + Данные.Вставить("ЗначенияТретьегоИзмерения", ЗначенияИзмеренийОтбора[Данные.ИмяТретьегоИзмерения]); + Иначе + Данные.Вставить("ИмяТретьегоИзмерения", Неопределено); + Данные.Вставить("ЗначенияТретьегоИзмерения", Неопределено); + КонецЕсли; + + Данные.Вставить("ПоляСравнения", ОписаниеКлючаЗаписи.СписокПолей); + Данные.Вставить("НовыеЗаписиСодержатТолькоРазличия", Истина); + Данные.Вставить("НовыеЗаписи", Данные.ИзмененияСоставаСтрок); + Данные.Удалить("ИзмененияСоставаСтрок"); + Данные.Удалить("ИзмеренияОтбора"); + + ОбновитьНаборыЗаписей(Данные, ЕстьИзменения); + +КонецПроцедуры + +// Возвращает пустую ссылку объекта метаданных ссылочного типа. +// +// Параметры: +// ОписаниеОбъектаМетаданных - ОбъектМетаданных, +// - Тип - по которому можно найти объект метаданных, +// - Строка - полное имя объекта метаданных. +// Возвращаемое значение: +// ЛюбаяСсылка +// +Функция ПустаяСсылкаОбъектаМетаданных(ОписаниеОбъектаМетаданных) Экспорт + + Если ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("ОбъектМетаданных") Тогда + ОбъектМетаданных = ОписаниеОбъектаМетаданных; + + ИначеЕсли ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("Тип") Тогда + ОбъектМетаданных = Метаданные.НайтиПоТипу(ОписаниеОбъектаМетаданных); + Иначе + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ОписаниеОбъектаМетаданных); + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в функции %1 + |общего модуля %2. + | + |Неверный параметр %3.'"), + "ПустаяСсылкаОбъектаМетаданных", + "УправлениеДоступомСлужебный", + "ОписаниеОбъектаМетаданных"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ПустаяСсылка = Неопределено; + Попытка + МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя()); + ПустаяСсылка = МенеджерОбъекта.ПустаяСсылка(); + Исключение + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в функции %1 + |общего модуля %2. + | + |Не удалось получить пустую ссылка для объекта метаданных + |""%3"".'"), + "ПустаяСсылкаОбъектаМетаданных", + "УправлениеДоступомСлужебный", + ОбъектМетаданных.ПолноеИмя()); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецПопытки; + + Возврат ПустаяСсылка; + +КонецФункции + +#КонецОбласти + +#Область ПрочиеПроцедурыИФункции + +// Создает запрос выбора различий между строками регистра в заданной области данных +// (на основе отборов в параметре ПоляИОтбор). +// +// Параметры: +// ТекстЗапросаВыбораНовых - Строка. +// +// ПоляИОтбор - Массив из Структура - со свойствами "ИмяПоля", ИмяПараметраУсловияОтбора. +// +// ПолноеИмяРегистра - Строка - запрос старых формируется автоматически. +// - Неопределено - запрос старых берется из следующего параметра. +// +// ТекстЗапросовВременныхТаблиц - Строка - запрос временных таблиц, если требуется. +// +// ТекстЗапросаВыбораСтарых - Строка - запрос старых, с учетом нестандартных отборов. +// - Неопределено - когда полное имя регистра определено. +// +// Возвращаемое значение: +// Строка - текст запроса +// +Функция ТекстЗапросаВыбораИзменений(ТекстЗапросаВыбораНовых, + ПоляИОтбор, + ПолноеИмяРегистра = Неопределено, + ТекстЗапросовВременныхТаблиц = Неопределено, + ТекстЗапросаВыбораСтарых = Неопределено) Экспорт + + // Подготовка текста запроса старых данных. + Если ПолноеИмяРегистра <> Неопределено Тогда + ТекстЗапросаВыбораСтарых = + "ВЫБРАТЬ + | &ВыбираемыеПоля, + | &ПодстановкаПоляВидИзмененияСтроки + |ИЗ + | ПолноеИмяРегистра КАК СтарыеДанные + |ГДЕ + | &УсловияОтбора"; + КонецЕсли; + + ВыбираемыеПоля = ""; + УсловияОтбора = "ИСТИНА"; + Для Каждого ОписаниеПоля Из ПоляИОтбор Цикл + // Сборка выбираемых полей. + ВыбираемыеПоля = ВыбираемыеПоля + СтрЗаменить( + " + | СтарыеДанные.Поле,", + "Поле", + КлючИЗначение(ОписаниеПоля).Ключ); + + // Сборка условий отбора. + Если ЗначениеЗаполнено(КлючИЗначение(ОписаниеПоля).Значение) Тогда + УсловияОтбора = УсловияОтбора + СтрЗаменить( + " + | И &ИмяПараметраУсловияОтбора", "&ИмяПараметраУсловияОтбора", // @query-part-1 + КлючИЗначение(ОписаниеПоля).Значение); + КонецЕсли; + КонецЦикла; + + ТекстЗапросаВыбораСтарых = + СтрЗаменить(ТекстЗапросаВыбораСтарых, "&ВыбираемыеПоля,", ВыбираемыеПоля); + + ТекстЗапросаВыбораСтарых = + СтрЗаменить(ТекстЗапросаВыбораСтарых, "&УсловияОтбора", УсловияОтбора); + + ТекстЗапросаВыбораСтарых = + СтрЗаменить(ТекстЗапросаВыбораСтарых, "ПолноеИмяРегистра", ПолноеИмяРегистра); + + Если СтрНайти(ТекстЗапросаВыбораСтарых, "&ПодстановкаПоляВидИзмененияСтроки") = 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в значении параметра %1 + |процедуры %2 модуля %3. + | + |В тексте запроса отсутствует строка ""%4"".'"), + "ТекстЗапросаВыбораСтарых", + "ТекстЗапросаВыбораИзменений", + "УправлениеДоступомСлужебный", + "&ПодстановкаПоляВидИзмененияСтроки"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ТекстЗапросаВыбораСтарых = СтрЗаменить( + ТекстЗапросаВыбораСтарых, "&ПодстановкаПоляВидИзмененияСтроки", "-1 КАК ВидИзмененияСтроки"); + + Если СтрНайти(ТекстЗапросаВыбораНовых, "&ПодстановкаПоляВидИзмененияСтроки") = 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в значении параметра %1 + |процедуры %2 модуля %3. + | + |В тексте запроса отсутствует строка ""%1"".'"), + "ТекстЗапросаВыбораНовых", + "ТекстЗапросаВыбораИзменений", + "УправлениеДоступомСлужебный", + "&ПодстановкаПоляВидИзмененияСтроки"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ТекстЗапросаВыбораНовых = СтрЗаменить( + ТекстЗапросаВыбораНовых, "&ПодстановкаПоляВидИзмененияСтроки", "1 КАК ВидИзмененияСтроки"); + + // Подготовка текста запроса выбора изменений. + ТекстЗапроса = + "ВЫБРАТЬ + | &ВыбираемыеПоля, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | ТекстЗапросаВыбораНовыхИСтарыхСтрок КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | &ПоляГруппировки + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0"; + + ТекстЗапросаВыбораНовыхИСтарыхСтрок = + " (" + ТекстЗапросаВыбораНовых + " + | + | ОБЪЕДИНИТЬ ВСЕ + | + | " + ТекстЗапросаВыбораСтарых + ")"; // @query-part-2 + + ВыбираемыеПоля = ""; + ПоляГруппировки = ""; + Для Каждого ОписаниеПоля Из ПоляИОтбор Цикл + // Сборка выбираемых полей. + ВыбираемыеПоля = ВыбираемыеПоля + СтрЗаменить( + " + | ВсеСтроки.Поле,", + "Поле", + КлючИЗначение(ОписаниеПоля).Ключ); + + // Сборка полей соединения. + ПоляГруппировки = ПоляГруппировки + СтрЗаменить( + " + | ВсеСтроки.Поле,", + "Поле", + КлючИЗначение(ОписаниеПоля).Ключ); + КонецЦикла; + ПоляГруппировки = Лев(ПоляГруппировки, СтрДлина(ПоляГруппировки)-1); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВыбираемыеПоля,", ВыбираемыеПоля); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляГруппировки", ПоляГруппировки); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекстЗапросаВыбораНовыхИСтарыхСтрок", ТекстЗапросаВыбораНовыхИСтарыхСтрок); + + Если ЗначениеЗаполнено(ТекстЗапросовВременныхТаблиц) Тогда + ТекстЗапроса = ТекстЗапросовВременныхТаблиц + + " + |; + |" + ТекстЗапроса; + КонецЕсли; + + Возврат ТекстЗапроса; + +КонецФункции + +Функция ПоддерживаетсяУправлениеДоступомВМоделиСервиса() Экспорт + + Возврат ОбщегоНазначения.ПодсистемаСуществует( + "СтандартныеПодсистемы.РаботаВМоделиСервиса.УправлениеДоступомВМоделиСервиса"); + +КонецФункции + +Функция ПоддерживаетсяНастройкаПравПользователейБТС() Экспорт + + Если Не ПоддерживаетсяУправлениеДоступомВМоделиСервиса() Тогда + Возврат Ложь; + КонецЕсли; + + МодульУправлениеДоступомСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль( + "УправлениеДоступомСлужебныйВМоделиСервиса"); + + Возврат МодульУправлениеДоступомСлужебныйВМоделиСервиса.ПоддерживаетсяНастройкаПравПользователейБТС(); + +КонецФункции + +#КонецОбласти + +#Область ОбновлениеИнформационнойБазы + +// Заполняет обработчик разделенных данных, зависимый от изменения неразделенных данных. +// +// Параметры: +// Параметры - Структура - структура параметров обработчиков: +// * РазделенныеОбработчики - см. ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления +// +Процедура ЗаполнитьОбработчикиРазделенныхДанных(Параметры = Неопределено) Экспорт + + Если Параметры <> Неопределено И ЕстьИзмененияПараметровОграниченияДоступа() Тогда + Обработчики = Параметры.РазделенныеОбработчики; + Обработчик = Обработчики.Добавить(); + Обработчик.Версия = "*"; + Обработчик.РежимВыполнения = "Оперативно"; + Обработчик.Процедура = "УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации"; + КонецЕсли; + +КонецПроцедуры + +// Обновляет вспомогательные данные, которые зависят от конфигурации частично. +// +// Обновляется при наличии изменений конфигурации, записанных в параметры +// ограничения доступа при обновлении базы данных на текущую версию конфигурации. +// +Процедура ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации(Параметры = Неопределено) Экспорт + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей". + РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистраПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа". + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(); + ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов". + РегистрыСведений.НастройкиПравОбъектов.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей". + Справочники.ПрофилиГруппДоступа.ОбновитьПоставляемыеПрофилиПоИзменениямКонфигурации(); + Справочники.ПрофилиГруппДоступа.ОбновитьНепоставляемыеПрофилиПоИзменениямКонфигурации(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа". + Справочники.ГруппыДоступа.ПометитьНаУдалениеГруппыДоступаПомеченныхПрофилей(); + + // Параметр "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа". + РегистрыСведений.ПараметрыОграниченияДоступа.ЗапланироватьОбновлениеДоступаПоИзменениямКонфигурации(); + +КонецПроцедуры + +// Обновляет настройки и включает регламентное задание. +Процедура ВключитьЗаполнениеДанныхДляОграниченияДоступа() Экспорт + + Использование = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + + Если ОбщегоНазначения.РазделениеВключено() Тогда + УстановитьЗаполнениеДанныхДляОграниченияДоступа(Использование); + Иначе + Расписание = Новый РасписаниеРегламентногоЗадания; + Расписание.ПериодНедель = 1; + Расписание.ПериодПовтораДней = 1; + Расписание.ПериодПовтораВТечениеДня = 300; + Расписание.ПаузаПовтора = 90; + + ЗаданиеМетаданные = Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа; + Задание = РегламентныеЗаданияСервер.ПолучитьРегламентноеЗадание(ЗаданиеМетаданные); + + Задание.Использование = Использование; + Задание.Расписание = Расписание; + + Задание.ИнтервалПовтораПриАварийномЗавершении + = ЗаданиеМетаданные.ИнтервалПовтораПриАварийномЗавершении; + + Задание.КоличествоПовторовПриАварийномЗавершении + = ЗаданиеМетаданные.КоличествоПовторовПриАварийномЗавершении; + + Задание.Записать(); + КонецЕсли; + +КонецПроцедуры + +// Обновляет данные профиля "ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок". +Процедура ОбновитьДанныеПрофиляОткрытиеВнешнихОтчетовИОбработок() Экспорт + + УникальныйИдентификаторПрофиля = Новый УникальныйИдентификатор( + ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок()); + + Ссылка = Справочники.ПрофилиГруппДоступа.ПолучитьСсылку(УникальныйИдентификаторПрофиля); + Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ссылка") = Неопределено Тогда + Возврат; + КонецЕсли; + СсылкаПометитьНаУдаление = Ложь; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка); + + Если ОбщегоНазначения.РазделениеВключено() Тогда + СсылкаПометитьНаУдаление = Истина; + Иначе + ОписаниеПрофиля = ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок(); + ПоставляемыйПрофильСсылка = Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( + ОписаниеПрофиля.Имя); + + Если Ссылка <> ПоставляемыйПрофильСсылка Тогда + Если ПоставляемыйПрофильСсылка <> Неопределено Тогда + СсылкаПометитьНаУдаление = Истина; + Иначе + // Установка идентификатора поставляемых данных. + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПрофильОбъект = Ссылка.ПолучитьОбъект(); + ПрофильОбъект.ИдентификаторПоставляемыхДанных = УникальныйИдентификаторПрофиля; + ПрофильОбъект.Комментарий = ""; + ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ПрофильОбъект, Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если СсылкаПометитьНаУдаление Тогда + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПрофильОбъект = Ссылка.ПолучитьОбъект(); + ПрофильОбъект.ПометкаУдаления = Истина; + ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ПрофильОбъект, Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + ГруппыПрофиля = ГруппыПрофиля(Ссылка, Ложь); + Для Каждого СсылкаГруппы Из ГруппыПрофиля Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаГруппы); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ГруппаОбъект = СсылкаГруппы.ПолучитьОбъект(); + ГруппаОбъект.ПометкаУдаления = Истина; + ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ГруппаОбъект, Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Только для внутреннего использования. +Процедура ОбновитьВспомогательныеДанныеГруппДоступа(Параметры) Экспорт + + Справочники.ГруппыДоступа.ОбновитьВспомогательныеДанныеГруппДоступа(Параметры); + +КонецПроцедуры + +#КонецОбласти + +#Область ВспомогательныеПроцедурыИФункции + +// Возвращаемое значение: +// см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Функция ПраваРолейРасширений() Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ПраваРолейРасширений = Неопределено; + + УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Истина); + Попытка + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(ПраваРолейРасширений); + Исключение + УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Ложь); + ВызватьИсключение; + КонецПопытки; + УстановитьЗаписьПараметровОграниченияДоступаВТекущемСеансе(Ложь); + + Возврат ПраваРолейРасширений; + +КонецФункции + +// Параметры: +// ПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Процедура ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(ПраваРолейРасширений = Неопределено) + + ПустыеПраваРолейРасширений = РегистрыСведений.ПраваРолей.ТаблицаПравРолей(Истина, Истина, Истина); + + Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда + МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер"); + Если МодульОбменДаннымиСервер.НастройкаПодчиненногоУзлаРИБ() Тогда + ПраваРолейРасширений = ПустыеПраваРолейРасширений; + Возврат; + КонецЕсли; + КонецЕсли; + + // Заполнение прав ролей расширений, которые состоят + // из изменений прав на объекты конфигурации и прав на объекты расширений. + УстановитьНовыеПраваРолейРасширений = Ложь; + Если ЗначениеЗаполнено(ПараметрыСеанса.ПодключенныеРасширения) Тогда + ХранилищеПравРолейРасширений = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения( + "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей"); // ХранилищеЗначения + + Если ХранилищеПравРолейРасширений = Неопределено Тогда + ПраваРолейРасширений = Неопределено; + Иначе + ПраваРолейРасширений = ЗначениеИзХранилища(ХранилищеПравРолейРасширений); + Если Не ЭтоПраваРолейРасширений(ПраваРолейРасширений, ПустыеПраваРолейРасширений) Тогда + ПраваРолейРасширений = Неопределено; + КонецЕсли; + КонецЕсли; + Если ПраваРолейРасширений = Неопределено Тогда + Запрос = РегистрыСведений.ПраваРолей.ЗапросИзменений(Истина); + ПраваРолейРасширений = Запрос.Выполнить().Выгрузить(); + УстановитьНовыеПраваРолейРасширений = Истина; + КонецЕсли; + Иначе + ПраваРолейРасширений = ПустыеПраваРолейРасширений; + КонецЕсли; + + // Проверка необходимости обновления регистра ТаблицыГруппДоступа. + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ПараметрыОбновленияТаблицГруппДоступа"; + ПараметрыОбновления = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + + Если ТипЗнч(ПараметрыОбновления) <> Тип("Структура") + Или Не ПараметрыОбновления.Свойство("ПоследниеПраваРолейРасширений") + Или Не ЭтоПраваРолейРасширений(ПараметрыОбновления.ПоследниеПраваРолейРасширений, ПустыеПраваРолейРасширений) Тогда + + ТребуетсяОбновление = Истина; + ПоследниеПраваРолейРасширений = Неопределено; + Иначе + ПоследниеПраваРолейРасширений = ПараметрыОбновления.ПоследниеПраваРолейРасширений; + ТребуетсяОбновление = ПраваРолейРасширенийИзменились(ПраваРолейРасширений, ПоследниеПраваРолейРасширений); + КонецЕсли; + + Если Не ТребуетсяОбновление Тогда + Если УстановитьНовыеПраваРолейРасширений Тогда; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения( + "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей", + Новый ХранилищеЗначения(ПраваРолейРасширений)); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПоследниеПраваРолейРасширений = Неопределено Тогда + // Так как последние права ролей расширений недоступны, требуется обновить весь регистр. + ОбъектыСИзменениемПравДляОбновления = Неопределено; + Иначе + ТекущиеОбъектыСИзменениемПрав = РегистрыСведений.ПраваРолей.ИзмененныеОбъектыМетаданных( + ПраваРолейРасширений.Скопировать()); + + ПоследниеОбъектыСИзменениемПрав = РегистрыСведений.ПраваРолей.ИзмененныеОбъектыМетаданных( + ПоследниеПраваРолейРасширений.Скопировать()); + + ОбъектыСИзменениемПравДляОбновления = Новый Массив(ТекущиеОбъектыСИзменениемПрав); + Для Каждого Идентификатор Из ПоследниеОбъектыСИзменениемПрав Цикл + ОбъектыСИзменениемПравДляОбновления.Добавить(Идентификатор); + КонецЦикла; + КонецЕсли; + + НовыеПараметрыОбновления = Новый Структура; + НовыеПараметрыОбновления.Вставить("ПоследниеПраваРолейРасширений", ПраваРолейРасширений); + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + Если Не ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + // Предварительное кэширование в файловой ИБ вне транзакции для предотвращения конфликтов блокировок. + УправлениеДоступомСлужебныйПовтИсп.ПрофильАдминистратор(); + ПроверитьОбъектыНастроекДоступа(); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + Если УжеИзменен Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + Если УстановитьНовыеПраваРолейРасширений Тогда; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения( + "СтандартныеПодсистемы.УправлениеДоступом.ПраваРолей", + Новый ХранилищеЗначения(ПраваРолейРасширений)); + КонецЕсли; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + НовыеПараметрыОбновления, Истина); + РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра(, ОбъектыСИзменениемПравДляОбновления); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. +// +// Параметры: +// ПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// ПустыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Функция ЭтоПраваРолейРасширений(ПраваРолейРасширений, ПустыеПраваРолейРасширений) + + Если ТипЗнч(ПраваРолейРасширений) <> Тип("ТаблицаЗначений") Тогда + Возврат Ложь; + КонецЕсли; + + Если ПраваРолейРасширений.Колонки.Количество() <> ПустыеПраваРолейРасширений.Колонки.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого Колонка Из ПустыеПраваРолейРасширений.Колонки Цикл + НайденнаяКолонка = ПраваРолейРасширений.Колонки.Найти(Колонка.Имя); + Если НайденнаяКолонка = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + Если Колонка.ТипЗначения <> НайденнаяКолонка.ТипЗначения Тогда + Возврат Ложь; + КонецЕсли; + КонецЦикла; + + Возврат Истина; + +КонецФункции + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. +// +// Параметры: +// НовыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// СтарыеПраваРолейРасширений - см. РегистрыСведений.ПраваРолей.ТаблицаПравРолей +// +Функция ПраваРолейРасширенийИзменились(НовыеПраваРолейРасширений, СтарыеПраваРолейРасширений) + + Если НовыеПраваРолейРасширений.Количество() <> СтарыеПраваРолейРасширений.Количество() Тогда + Возврат Истина; + КонецЕсли; + + Отбор = Новый Структура; + Поля = Новый Массив; + Для Каждого Колонка Из НовыеПраваРолейРасширений.Колонки Цикл + Поля.Добавить(Колонка.Имя); + Отбор.Вставить(Колонка.Имя); + КонецЦикла; + СтарыеПраваРолейРасширений.Индексы.Добавить(СтрСоединить(Поля, ",")); + + Для Каждого Строка Из НовыеПраваРолейРасширений Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Если СтарыеПраваРолейРасширений.НайтиСтроки(Отбор).Количество() <> 1 Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +Процедура ПриИзмененииНаборовЗначенийДоступа(Знач СсылкаНаОбъект, ОбновлениеИБ = Ложь) + + СсылкиНаЗависимыеОбъекты = Новый Массив; + + УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа( + СсылкаНаОбъект, СсылкиНаЗависимыеОбъекты); + + Для каждого СсылкаНаЗависимыйОбъект Из СсылкиНаЗависимыеОбъекты Цикл + + Если СсылкаНаЗависимыйОбъект.Метаданные().ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда + // Изменение объекта не требуется. + // @skip-check query-in-loop - Порционная обработка данных + ЗаписатьНаборыЗначенийДоступа(СсылкаНаЗависимыйОбъект, , ОбновлениеИБ); + Иначе + // Изменение объекта требуется. + Объект = СсылкаНаЗависимыйОбъект.ПолучитьОбъект(); + Таблица = ПолучитьНаборыЗначенийДоступаТабличнойЧасти(Объект); + Если НЕ НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаЗависимыйОбъект, Таблица) Тогда + Продолжить; + КонецЕсли; + ПодготовитьНаборыЗначенийДоступаКЗаписи(Неопределено, Таблица, Ложь); + Попытка + ЗаблокироватьДанныеДляРедактирования(СсылкаНаЗависимыйОбъект, Объект.ВерсияДанных); + Объект.ДополнительныеСвойства.Вставить("ЗаписатьНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("ЗаписатьЗависимыеНаборыЗначенийДоступа"); + Объект.ДополнительныеСвойства.Вставить("НаборыЗначенийДоступаТабличнойЧастиЗаполнены"); + Объект.НаборыЗначенийДоступа.Загрузить(Таблица); + Если ОбновлениеИБ Тогда + Объект.ДополнительныеСвойства.Вставить("ЗаписьНаборовЗначенийДоступаПриОбновленииИБ"); + ОбновлениеИнформационнойБазы.ЗаписатьДанные(Объект); + Иначе + Объект.ОбменДанными.Загрузка = Истина; + // АПК:1327-выкл - №783.1.4.1 Допустимо оставить запись без + // предварительной управляемой блокировки объекта, так как только + // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. + Объект.Записать(); + // АПК:1327-вкл. + КонецЕсли; + РазблокироватьДанныеДляРедактирования(СсылкаНаЗависимыйОбъект); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить зависимый набор значений доступа объекта + |""%1"" по причине: + | + |%2'"), + Строка(СсылкаНаЗависимыйОбъект), + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)); + ВызватьИсключение ТекстОшибки; + КонецПопытки; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Функция ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок() + + Возврат "1b3472f6-4d87-11e6-8264-5404a6a6895d"; + +КонецФункции + +Функция ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(Профиль) Экспорт + + Если ТипЗнч(Профиль) = Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда + ИдентификаторПрофиля = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Профиль, "ИдентификаторПоставляемыхДанных"); + + ИначеЕсли Не Профиль.ЭтоГруппа Тогда + ИдентификаторПрофиля = Профиль.ИдентификаторПоставляемыхДанных; + Иначе + Возврат Ложь; + КонецЕсли; + + Возврат ВРег(Строка(ИдентификаторПрофиля)) = ВРег(ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок()); + +КонецФункции + +Функция ГруппыДоступаПрофиляОткрытиеВнешнихОтчетовИОбработок() + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторПоставляемыхДанных", + Новый УникальныйИдентификатор(ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок())); + + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль.ИдентификаторПоставляемыхДанных = &ИдентификаторПоставляемыхДанных"; + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +Функция ОписаниеПрофиляОткрытиеВнешнихОтчетовИОбработок() Экспорт + + ОписаниеПрофиля = УправлениеДоступом.НовоеОписаниеПрофиляГруппДоступа(); + ОписаниеПрофиля.Имя = "ОткрытиеВнешнихОтчетовИОбработок"; + ОписаниеПрофиля.Родитель = "ДополнительныеПрофили"; + ОписаниеПрофиля.Идентификатор = ИдентификаторПрофиляОткрытиеВнешнихОтчетовИОбработок(); + + ОписаниеПрофиля.Наименование = + НСтр("ru = 'Открытие внешних отчетов и обработок'", ОбщегоНазначения.КодОсновногоЯзыка()); + + ОписаниеПрофиля.Описание = + НСтр("ru = 'Предоставляет право открытия внешних отчетов и обработок из меню ""Файл - Открыть"". + |Состав ролей профиля не рекомендуется изменять.'"); + + ОписаниеПрофиля.Роли.Добавить("ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок"); + + Возврат ОписаниеПрофиля; + +КонецФункции + +Функция ГруппаДоступаОткрытиеВнешнихОтчетовИОбработок(СвойстваПрофиля) + + // Поиск по идентификатору. + УникальныйИдентификатор = Новый УникальныйИдентификатор("f6929bcb-532f-11e6-a20f-5404a6a6895d"); + Ссылка = Справочники.ГруппыДоступа.ПолучитьСсылку(УникальныйИдентификатор); + СсылкаСуществует = (ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Ссылка") <> Неопределено); + Если СсылкаСуществует Тогда + Возврат Ссылка; + КонецЕсли; + + // Поиск по профилю. + ГруппыПрофиля = ГруппыПрофиля(СвойстваПрофиля.Ссылка, Неопределено); + Если ГруппыПрофиля.Количество() > 0 Тогда + Возврат ГруппыПрофиля[0]; + КонецЕсли; + + // Создание группы. + ГруппаДоступаОбъект = Справочники.ГруппыДоступа.СоздатьЭлемент(); + ГруппаДоступаОбъект.УстановитьСсылкуНового(Ссылка); + ГруппаДоступаОбъект.Наименование = СвойстваПрофиля.Наименование; + ГруппаДоступаОбъект.Профиль = СвойстваПрофиля.Ссылка; + ГруппаДоступаОбъект.Комментарий = + НСтр("ru = 'Предоставляет право открытия внешних отчетов и обработок из меню ""Файл - Открыть"".'", + ОбщегоНазначения.КодОсновногоЯзыка()); + + ГруппаДоступаОбъект.Записать(); // Важно, чтобы созданная группа "уехала" в подчиненный узел. + + Возврат ГруппаДоступаОбъект.Ссылка; + +КонецФункции + +Функция ГруппыПрофиля(СсылкаПрофиля, ПометкаУдаления) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &Профиль + | И ГруппыДоступа.ПометкаУдаления = &ПометкаУдаления + | + |УПОРЯДОЧИТЬ ПО + | ГруппыДоступа.ПометкаУдаления"; + + Запрос.УстановитьПараметр("Профиль", СсылкаПрофиля); + + Если ПометкаУдаления = Неопределено Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "И ГруппыДоступа.ПометкаУдаления = &ПометкаУдаления", ""); // @query-part-1 + Иначе + Запрос.УстановитьПараметр("ПометкаУдаления", ПометкаУдаления); + КонецЕсли; + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +// Для функция РазрешенныеЗначенияДляДинамическогоСписка, ЕстьОграничениеПоВидуДоступа. +Функция ТекстЗапросаГруппДоступа() + + Возврат + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ГруппыДоступаПользователя + |ИЗ + | Справочник.ИдентификаторыОбъектовМетаданных КАК СвойстваТекущейТаблицы + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа + | ПО (СвойстваТекущейТаблицы.ПолноеИмя = &ИмяОсновнойТаблицыСписка) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ГДЕ + | ТаблицыГруппДоступа.Таблица = СвойстваТекущейТаблицы.Ссылка + | И ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступа.Ссылка)) + | И (ГруппыДоступа.Ссылка В + | (ВЫБРАТЬ + | ГруппыДоступаПользователи.Ссылка КАК ГруппаДоступа + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь + | И СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь))"; + +КонецФункции + +// Для процедур ОбновитьНаборЗаписей, ОбновитьНаборыЗаписей, ОбновитьРегистрСведений. +Процедура ЗаполнитьПараметры(ВходныеПараметры, Знач ВсеПараметры, Знач ОбязательныеПараметры = "") + + Если ТипЗнч(ВходныеПараметры) = Тип("Структура") Тогда + Параметры = ВходныеПараметры; + ИначеЕсли ВходныеПараметры = Неопределено Тогда + Параметры = Новый Структура; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректный тип набора свойств ""%1"". + |Допустимые типы: %2, %3.'"), + ТипЗнч(ВходныеПараметры), "Структура", "Неопределено"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Для каждого КлючИЗначение Из Параметры Цикл + Если Не ВсеПараметры.Свойство(КлючИЗначение.Ключ) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Указан несуществующий параметр %1'"), + КлючИЗначение.Ключ); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ВсеПараметры[КлючИЗначение.Ключ] = Параметры[КлючИЗначение.Ключ]; + КонецЦикла; + + Если ЗначениеЗаполнено(ОбязательныеПараметры) Тогда + ОбязательныеПараметры = Новый Структура(ОбязательныеПараметры); + + Для каждого КлючИЗначение Из ОбязательныеПараметры Цикл + Если Не Параметры.Свойство(КлючИЗначение.Ключ) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не указан обязательный параметр %1'"), + КлючИЗначение.Ключ); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ВходныеПараметры = ВсеПараметры; + +КонецПроцедуры + +// Для процедур ПриОтправкеДанныхГлавному, ПриОтправкеДанныхПодчиненному, +// ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного. +// +Функция ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) + + Возврат ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ПраваРолей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗависимостиПравДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ТаблицыГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗначенияГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ЗначенияГруппДоступаПоУмолчанию") + Или ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.КлючиДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("СправочникОбъект.НаборыГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаВнешнихПользователей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаНаборовГруппДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаКОбъектам") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаКРегистрам") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.КлючиДоступаПользователей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ОбновлениеКлючейДоступаКДанным") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ОбновлениеКлючейДоступаПользователей") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ПараметрыОграниченияДоступа") + Или ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступаПоТаблицам") + Или ТипЗнч(ЭлементДанных) = Тип("КонстантаМенеджерЗначения.ПервоеОбновлениеДоступаЗавершилось"); + +КонецФункции + +// Для процедур ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного +Процедура ПриОтправкеДанных(ЭлементДанных, ОтправкаЭлемента, Подчиненному, СозданиеНачальногоОбраза) + + Если СозданиеНачальногоОбраза Тогда // Отправка подчиненному узлу. + // Частичное изменение объектов при создании начального образа не поддерживается, + // обработку смотри в процедуре ПриНастройкеПодчиненногоУзлаРИБ. + // + // Роли расширений назначаются независимо во всех РИБ-узлах. + // Администраторы назначаются независимо во всех РИБ-узлах. + Возврат; + КонецЕсли; + + // Стандартная обработка не переопределяется. + Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить + Или ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда + Возврат; + КонецЕсли; + + Если ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) Тогда + ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать; + Возврат; + КонецЕсли; + + Если Подчиненному Тогда + Возврат; + КонецЕсли; + + ТипЭлемента = ТипЗнч(ЭлементДанных); + + // Профиль и группа доступа открытия внешних отчетов и обработок + // недоступны в сервисе, но доступны в автономном рабочем месте. + Если ОбщегоНазначения.ЭтоАвтономноеРабочееМесто() + И ( ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") + И ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(ЭлементДанных) + Или ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") + И Не ЭлементДанных.ЭтоГруппа + И ЭтоПрофильОткрытиеВнешнихОтчетовИОбработок(ЭлементДанных.Профиль) ) Тогда + + ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать; + КонецЕсли; + + // Роли расширений назначаются независимо во всех РИБ-узлах. + Если ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + Справочники.ПрофилиГруппДоступа.УдалитьРолиРасширений(ЭлементДанных); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПриПолученииДанныхОтГлавного, ПриПолученииДанныхОтПодчиненного +Процедура ПриПолученииДанных(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад, ОтПодчиненного) + + // Стандартная обработка не переопределяется. + Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда + Возврат; + КонецЕсли; + + Если ОбъектПодсистемыУправлениеДоступомТолькоДляСозданияНачальногоОбраза(ЭлементДанных) Тогда + ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; + Возврат; + КонецЕсли; + + ТипЭлемента = ТипЗнч(ЭлементДанных); + + Если ОтПодчиненного И ОбщегоНазначения.РазделениеВключено() Тогда + Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") + Или ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписейУниверсально") + Или ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") + Или ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ГруппыЗначенийДоступа") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НаборыЗначенийДоступа") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НаследованиеНастроекПравОбъектов") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.НастройкиПравОбъектов") + Или ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступа") Тогда + // Получение данных из автономного рабочего места пропускается, а для соответствия + // данных в узлах, текущие данные отправляются обратно в автономное рабочее место. + ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; + ОтправкаНазад = Истина; + Возврат; + КонецЕсли; + + ИначеЕсли ОтПодчиненного Тогда + Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") + Или ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписейУниверсально") Тогда + // Получение данных из подчиненного узла пропускается, а для соответствия + // данных в узлах, текущие данные отправляются обратно в автономное рабочее место. + ОтправкаНазад = Истина; + ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать; + Возврат; + КонецЕсли; + КонецЕсли; + + Если ТипЭлемента = Тип("КонстантаМенеджерЗначения.ОграничиватьДоступНаУровнеЗаписей") Тогда + Константы.ОграничиватьДоступНаУровнеЗаписей.СоздатьМенеджерЗначения().ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипЭлемента = Тип("РегистрСведенийНаборЗаписей.ИспользуемыеВидыДоступа") Тогда + РегистрыСведений.ИспользуемыеВидыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипЭлемента = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда + // Роли расширений назначаются независимо во всех РИБ-узлах. + Справочники.ПрофилиГруппДоступа.ВосстановитьСоставРолейРасширений(ЭлементДанных); + // Регистрация измененного профиля для обновления вспомогательных данных. + Справочники.ПрофилиГруппДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипЭлемента = Тип("СправочникОбъект.ГруппыДоступа") Тогда + // Администраторы назначаются независимо во всех РИБ-узлах. + Справочники.ГруппыДоступа.ВосстановитьСоставУчастниковГруппыДоступаАдминистраторы(ЭлементДанных); + // Регистрация измененной группы доступа для обновления вспомогательных данных. + Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли Метаданные.ОпределяемыеТипы.ЗначениеДоступаОбъект.Тип.СодержитТип(ТипЭлемента) Тогда + // Регистрация измененных значений доступа для обновления вспомогательных данных после загрузки. + ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных); + КонецЕсли; + + Если ТипЭлемента <> Тип("УдалениеОбъекта") Тогда + Возврат; + КонецЕсли; + + ЭлементДанных = ЭлементДанных; // УдалениеОбъекта + ТипСсылки = ТипЗнч(ЭлементДанных.Ссылка); + + Если ТипСсылки = Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда + // Регистрация измененного профиля для обновления вспомогательных данных после загрузки. + Справочники.ПрофилиГруппДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + + ИначеЕсли ТипСсылки = Тип("СправочникСсылка.ГруппыДоступа") Тогда + // Регистрация измененной группы доступа для обновления вспомогательных данных после загрузки. + Справочники.ГруппыДоступа.ЗарегистрироватьИзменениеПриПолученииДанных(ЭлементДанных); + КонецЕсли; + + // Регистрация измененных значений доступа для обновления вспомогательных данных после загрузки. + Если УправлениеДоступомСлужебныйПовтИсп.ТипыСсылокИзЗначениеДоступаОбъект().СодержитТип(ТипСсылки) Тогда + ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПриПолученииДанныхОтГлавногоИлиОтПодчиненного. +Процедура ЗарегистрироватьЗначенияДоступаИзмененныеПриПолученииДанных(ЭлементДанных) + + УстановитьПривилегированныйРежим(Истина); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами; + ТипСсылки = ТипЗнч(ЭлементДанных.Ссылка); + + Если ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипСсылки) = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ЭлементДанных) = Тип("УдалениеОбъекта") Тогда + РегистрироватьГруппыДоступа = Истина; + СсылкаОбъекта = ЭлементДанных.Ссылка; + Иначе + РегистрироватьГруппыДоступа = ЭлементДанных.ЭтоНовый(); + СсылкаОбъекта = ПользователиСлужебный.СсылкаОбъекта(ЭлементДанных); + КонецЕсли; + + ПользователиСлужебный.ЗарегистрироватьСсылки("ЗначенияДоступа", СсылкаОбъекта); + + Если СвойстваВидовДоступа.ПоТипамЗначенийСИерархией.Получить(ТипСсылки) <> Неопределено Тогда + Если Не РегистрироватьГруппыДоступа Тогда + СтарыйРодитель = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЭлементДанных.Ссылка, "Родитель"); + Если ЭлементДанных.Родитель <> СтарыйРодитель Тогда + РегистрироватьГруппыДоступа = Истина; + КонецЕсли; + КонецЕсли; + Если РегистрироватьГруппыДоступа Тогда + ГруппыДоступа = ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипСсылки); + ПользователиСлужебный.ЗарегистрироватьСсылки("ГруппыДоступаЗначенийСИерархией", ГруппыДоступа); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПослеПолученияДанных, ПослеОбновленияИнформационнойБазы. +Процедура ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных() + + РегистрыСведений.ПараметрыРаботыВерсийРасширений.ЗаблокироватьДляИзмененияВФайловойИБ(); + + УстановитьПривилегированныйРежим(Истина); + Константы.ОграничиватьДоступНаУровнеЗаписей.СоздатьМенеджерЗначения().ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + РегистрыСведений.ИспользуемыеВидыДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + Справочники.ПрофилиГруппДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + Справочники.ГруппыДоступа.ОбработатьИзменениеЗарегистрированноеПриПолученииДанных(); + ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных(); + +КонецПроцедуры + +// Для процедуры ОбновитьВспомогательныеДанныеЭлементовИзмененныхПриПолученииДанных. +Процедура ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных() + + ОчисткаРегистрации = Новый Массив; + + ОбработатьЗарегистрированноеИзменениеЗначенийДоступа("ЗначенияДоступа", ОчисткаРегистрации); + ОбработатьЗарегистрированноеИзменениеИерархииЗначенийДоступа("ГруппыДоступаЗначенийСИерархией", + ОчисткаРегистрации); + + Для Каждого ИмяВидаСсылок Из ОчисткаРегистрации Цикл + ПользователиСлужебный.ЗарегистрироватьСсылки(ИмяВидаСсылок, Null); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных. +Процедура ОбработатьЗарегистрированноеИзменениеЗначенийДоступа(ИмяВидаСсылок, ОчисткаРегистрации) + + ЗначенияДоступа = ПользователиСлужебный.ЗарегистрированныеСсылки(ИмяВидаСсылок); + + Если ЗначенияДоступа.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если ЗначенияДоступа.Количество() = 1 И ЗначенияДоступа[0] = Неопределено Тогда + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(); + Иначе + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьГруппыЗначенийДоступа(ЗначенияДоступа); + КонецЕсли; + + ОчисткаРегистрации.Добавить(ИмяВидаСсылок); + +КонецПроцедуры + +// Для процедуры ОбработатьИзменениеЗначенийДоступаЗарегистрированноеПриПолученииДанных. +Процедура ОбработатьЗарегистрированноеИзменениеИерархииЗначенийДоступа(ИмяВидаСсылок, ОчисткаРегистрации) + + ГруппыДоступа = ПользователиСлужебный.ЗарегистрированныеСсылки(ИмяВидаСсылок); + + Если ГруппыДоступа.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если ГруппыДоступа.Количество() = 1 И ГруппыДоступа[0] = Неопределено Тогда + РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(); + Иначе + РегистрыСведений.ЗначенияГруппДоступа.ОбновитьДанныеРегистра(ГруппыДоступа); + КонецЕсли; + + ОчисткаРегистрации.Добавить(ИмяВидаСсылок); + +КонецПроцедуры + +// Для процедур ВключитьПользователяВГруппуДоступа. +Функция ОбработатьСвязьПользователяСГруппойДоступа(Пользователь, ПоставляемыйПрофиль, Включить = Неопределено) + + Если ТипЗнч(Пользователь) <> Тип("СправочникСсылка.Пользователи") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ГруппыПользователей") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ВнешниеПользователи") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ГруппыВнешнихПользователей") Тогда + + Возврат Ложь; + КонецЕсли; + + ИдентификаторПоставляемогоПрофиля = Неопределено; + + Если ТипЗнч(ПоставляемыйПрофиль) = Тип("Строка") Тогда + Если СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(ПоставляемыйПрофиль) Тогда + + ИдентификаторПоставляемогоПрофиля = ПоставляемыйПрофиль; + + ПоставляемыйПрофиль = Справочники.ПрофилиГруппДоступа.ПоставляемыйПрофильПоИдентификатору( + ИдентификаторПоставляемогоПрофиля,, Истина); + Иначе + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Если ТипЗнч(ПоставляемыйПрофиль) <> Тип("СправочникСсылка.ПрофилиГруппДоступа") Тогда + Возврат Ложь; + КонецЕсли; + + Если ИдентификаторПоставляемогоПрофиля = Неопределено Тогда + ИдентификаторПоставляемогоПрофиля = + Справочники.ПрофилиГруппДоступа.ИдентификаторПоставляемогоПрофиля(ПоставляемыйПрофиль); + КонецЕсли; + + Если ИдентификаторПоставляемогоПрофиля = Справочники.ПрофилиГруппДоступа.ИдентификаторПрофиляАдминистратор() Тогда + Возврат Ложь; + КонецЕсли; + + СвойстваПрофиля = Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля(ИдентификаторПоставляемогоПрофиля); + + Если СвойстваПрофиля = Неопределено + ИЛИ СвойстваПрофиля.ВидыДоступа.Количество() <> 0 Тогда + + Возврат Ложь; + КонецЕсли; + + ГруппаДоступа = Неопределено; + + Если УпрощенныйИнтерфейсНастройкиПравДоступа() Тогда + + Если ТипЗнч(Пользователь) <> Тип("СправочникСсылка.Пользователи") + И ТипЗнч(Пользователь) <> Тип("СправочникСсылка.ВнешниеПользователи") Тогда + + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Профиль", ПоставляемыйПрофиль); + Запрос.УстановитьПараметр("Пользователь", Пользователь); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &Профиль + | И ГруппыДоступа.Пользователь = &Пользователь"; + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + ГруппаДоступа = Выборка.Ссылка; + КонецЕсли; + + Если ГруппаДоступа = Неопределено Тогда + Если Включить <> Истина Тогда + Возврат Ложь; + Иначе + ГруппаДоступа = Справочники.ГруппыДоступа.СоздатьЭлемент(); + ГруппаДоступа.Наименование = СвойстваПрофиля.Наименование; + ГруппаДоступа.Профиль = ПоставляемыйПрофиль; + ГруппаДоступа.Пользователь = Пользователь; + ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; + ГруппаДоступа.Записать(); + Возврат Истина; + КонецЕсли; + КонецЕсли; + Иначе + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПоставляемыйПрофиль", ПоставляемыйПрофиль); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка, + | ГруппыДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль = &ПоставляемыйПрофиль + | + |УПОРЯДОЧИТЬ ПО + | ГруппыДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля УБЫВ"; + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + ГруппаДоступа = Выборка.Ссылка; // СправочникСсылка.ГруппыДоступа - + КонецЕсли; + + Если ГруппаДоступа = Неопределено Тогда + Если Включить <> Истина Тогда + Возврат Ложь; + Иначе + ГруппаДоступа = Справочники.ГруппыДоступа.СоздатьЭлемент(); + ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля = Истина; + ГруппаДоступа.Наименование = СвойстваПрофиля.Наименование; + ГруппаДоступа.Профиль = ПоставляемыйПрофиль; + ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; + ГруппаДоступа.Записать(); + Возврат Истина; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Ссылка", ГруппаДоступа); + Запрос.УстановитьПараметр("Пользователь", Пользователь); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппы + |ГДЕ + | УчастникиГруппы.Ссылка = &Ссылка + | И УчастникиГруппы.Пользователь = &Пользователь"; + ПользовательНайден = НЕ Запрос.Выполнить().Пустой(); + + Если Включить = Неопределено Тогда + Возврат ПользовательНайден; + КонецЕсли; + + Если Включить И ПользовательНайден Тогда + Возврат Истина; + КонецЕсли; + + Если НЕ Включить И НЕ ПользовательНайден Тогда + Возврат Истина; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаДоступа); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + ГруппаДоступа = ГруппаДоступа.ПолучитьОбъект(); + + Если НЕ УпрощенныйИнтерфейсНастройкиПравДоступа() + И НЕ ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля Тогда + + ГруппаДоступа.ОсновнаяГруппаДоступаПоставляемогоПрофиля = Истина; + КонецЕсли; + + Если Включить Тогда + ГруппаДоступа.Пользователи.Добавить().Пользователь = Пользователь; + Иначе + Отбор = Новый Структура("Пользователь", Пользователь); + Строки = ГруппаДоступа.Пользователи.НайтиСтроки(Отбор); + Для каждого Строка Из Строки Цикл + ГруппаДоступа.Пользователи.Удалить(Строка); + КонецЦикла; + КонецЕсли; + + ГруппаДоступа.Записать(); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Возврат Истина; + +КонецФункции + +// Для процедуры ЗаписатьНаборыЗначенийДоступаПриЗаписи. + +// Перезаписывает наборы значений доступа проверяемого объекта +// в РегистрСведений.НаборыЗначенийДоступа, используя процедуру +// УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(). +// +// Процедура вызывается из УправлениеДоступомСлужебный.ЗаписатьНаборыЗначенийДоступа(), +// но может быть вызвана из любого места, например, +// при включении ограничения доступа на уровне записей. +// +// Вызывает процедуру прикладного разработчика +// УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа(), +// которая используется для перезаписи зависимых наборов значений доступа. +// +// Параметры: +// Объект - ЛюбаяСсылка +// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - +// В случае вызова с клиента можно передать только ссылку, а нужен объект. +// Если получена ссылка, то по ней будет получен объект. +// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// +Процедура ЗаписатьНаборыЗначенийДоступа(Знач Объект, ЕстьИзменения = Неопределено, ОбновлениеИБ = Ложь) + + УстановитьПривилегированныйРежим(Истина); + + // Если передача параметра Объект производилась с клиента на сервер, + // то передавалась ссылка, и объект требуется получить. + Объект = ?(Объект = Объект.Ссылка, Объект.ПолучитьОбъект(), Объект); + СсылкаНаОбъект = Объект.Ссылка; + ТипЗначенияОбъект = ТипЗнч(Объект); + + НаборыЗаписываются = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ НаборыЗаписываются Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписках на события %2.'"), + ТипЗначенияОбъект, + "ЗаписатьНаборыЗначенийДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ВозможныеТипыОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы( + "РегистрСведений.НаборыЗначенийДоступа.Измерение.Объект"); + + Если ВозможныеТипыОбъектов.Получить(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка при записи наборов значений доступа: + |в регистре сведений %1 в измерении %2 + |не задан тип ""%3"".'"), + "НаборыЗначенийДоступа", + "Объект", + ТипЗнч(СсылкаНаОбъект)); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() + И Не УправлениеДоступом.ПроизводительныйВариант() Тогда + + Если Метаданные.НайтиПоТипу(ТипЗначенияОбъект).ТабличныеЧасти.Найти("НаборыЗначенийДоступа") = Неопределено Тогда + + Таблица = УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(); + УправлениеДоступом.ЗаполнитьНаборыЗначенийДоступа(Объект, Таблица); + + УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( + Таблица, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); + Иначе + ТабличнаяЧастьЗаполняется = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей + |ЗаполнитьНаборыЗначенийДоступаТабличныхЧастейДокументов").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ ТабличнаяЧастьЗаполняется Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписках на события %2.'"), + ТипЗначенияОбъект, + "ЗаполнитьНаборыЗначенийДоступаТабличныхЧастей"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + // Записан объект с уже заполненной табличной частью НаборыЗначенийДоступа. + Таблица = Объект.НаборыЗначенийДоступа.Выгрузить(); + КонецЕсли; + + ПодготовитьНаборыЗначенийДоступаКЗаписи(СсылкаНаОбъект, Таблица, Истина); + + Данные = Новый Структура; + Данные.Вставить("МенеджерРегистра", РегистрыСведений.НаборыЗначенийДоступа); + Данные.Вставить("ФиксированныйОтбор", Новый Структура("Объект", СсылкаНаОбъект)); + Данные.Вставить("НовыеЗаписи", Таблица); + Данные.Вставить("ОбновлениеИБ", ОбновлениеИБ); + + НачатьТранзакцию(); + Попытка + ОбновитьНаборыЗаписей(Данные, ЕстьИзменения); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЕстьИзменения = Истина Тогда + ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); + КонецЕсли; + Иначе + Запрос = Новый Запрос( + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.НаборыЗначенийДоступа КАК НаборыЗначенийДоступа + |ГДЕ + | НаборыЗначенийДоступа.Объект = &СсылкаНаОбъект"); + + Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект); + + // АПК:1328-выкл - №648.1.1 Допустимо чтение без предварительной + // управляемой разделяемой блокировки объекта, так как только + // для RLS в формате БСП 2.х (устарело) и ни разу не вызывало проблем. + Если НЕ Запрос.Выполнить().Пустой() Тогда + // АПК:1328-вкл. + + // Очистка устаревшего набора. + // Запись нового набора будет выполнена регламентным заданием, + // после включения ограничения на уровне записей. + НаборЗаписей = РегистрыСведений.НаборыЗначенийДоступа.СоздатьНаборЗаписей(); + НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект); + НаборЗаписей.Записать(); + ЕстьИзменения = Истина; + + // Очистка устаревших зависимых наборов. + ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаписатьЗависимыеНаборыЗначенийДоступаПриЗаписи. + +// Перезаписывает наборы значений доступа зависимых объектов. +// +// Процедура вызывается из УправлениеДоступомСлужебный.ЗаписатьЗависимыеНаборыЗначенийДоступа(), +// состав типов подписки дополняет (без пересечения) состав типов подписки ЗаписатьНаборыЗначенийДоступа, +// теми типами, для которых выполнять запись наборов в регистр сведений НаборыЗначенийДоступа +// не требуется, но сами наборы входят в состав других наборов, например, наборы некоторых файлов +// из справочника "Файлы" могут входить в состав некоторых бизнес-процессов "Задание", созданных +// на основании файлов, при этом наборы файлов записывать в регистр не требуется. +// +// Вызывает процедуру прикладного разработчика +// УправлениеДоступомПереопределяемый.ПриИзмененииНаборовЗначенийДоступа(), +// которая используется для перезаписи зависимых наборов значений доступа, +// то есть организуется рекурсия. +// +// Параметры: +// Объект - ЛюбаяСсылка +// - ОпределяемыйТип.ВладелецНаборовЗначенийДоступаОбъект - +// В случае вызова с клиента можно передать только ссылку, а нужен объект. +// Если получена ссылка, то по ней будет получен объект. +// +// ОбновлениеИБ - Булево - если Истина, то необходимо выполнять запись данных, +// не выполняя лишних, избыточных действий с данными. +// См. ОбновлениеИнформационнойБазы.ЗаписатьДанные. +// +Процедура ЗаписатьЗависимыеНаборыЗначенийДоступа(Знач Объект, ОбновлениеИБ = Ложь) + + УстановитьПривилегированныйРежим(Истина); + + // Если передача параметра Объект производилась с клиента на сервер, + // то передавалась ссылка, и объект требуется получить. + Объект = ?(Объект = Объект.Ссылка, Объект.ПолучитьОбъект(), Объект); + СсылкаНаОбъект = Объект.Ссылка; + ТипЗначенияОбъект = ТипЗнч(Объект); + + ЭтоВедущийОбъект = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия( + "ЗаписатьЗависимыеНаборыЗначенийДоступа").Получить(ТипЗначенияОбъект) <> Неопределено; + + Если НЕ ЭтоВедущийОбъект Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неверные параметры. + |Тип объекта ""%1"" + |не существует в подписке на события %2.'"), + ТипЗначенияОбъект, + "ЗаписатьЗависимыеНаборыЗначенийДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ПриИзмененииНаборовЗначенийДоступа(СсылкаНаОбъект, ОбновлениеИБ); + +КонецПроцедуры + +// Для процедур ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации и +// ЗаполнитьОбработчикиРазделенныхДанных. + +// Проверяет были ли изменения неразделенных данных для какой-нибудь области данных. +Функция ЕстьИзмененияПараметровОграниченияДоступа() + + УстановитьПривилегированныйРежим(Истина); + + Параметры = Новый Массив; + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ОбъектыМетаданныхПравРолей"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ОписаниеПоставляемыхПрофилей"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ПредопределенныеПрофилиГруппДоступа"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа"); + Параметры.Добавить("СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"); + + Для Каждого Параметр Из Параметры Цикл + + ПоследниеИзменения = СтандартныеПодсистемыСервер.ИзмененияПараметраРаботыПрограммы(Параметр); + + Если ПоследниеИзменения = Неопределено + ИЛИ ПоследниеИзменения.Количество() > 0 Тогда + + Возврат Истина; + КонецЕсли; + + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ОбновитьРолиПользователей. + +// Для тестирования. +// +// Параметры: +// ДополнительныеРоли - Соответствие из КлючИЗначение: +// * Ключ - Строка - имя роли, которую можно назначить администратору. +// * Значение - Булево - Истина. +// +Процедура ПриПодготовкеДополнительныхРолейАдминистратора(ДополнительныеРоли) + Возврат; +КонецПроцедуры + +Функция ТекущиеСвойстваПользователей(МассивПользователей) + + Запрос = Новый Запрос; + + Запрос.УстановитьПараметр("ГруппаДоступаАдминистраторы", + УправлениеДоступом.ГруппаДоступаАдминистраторы()); + + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Если МассивПользователей = Неопределено Тогда + Запрос.Текст = + "ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.Пользователи КАК Пользователи + |ГДЕ + | Пользователи.Служебный = ЛОЖЬ + | И Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ВнешниеПользователи.Ссылка, + | ВнешниеПользователи.ИдентификаторПользователяИБ + |ИЗ + | Справочник.ВнешниеПользователи КАК ВнешниеПользователи + |ГДЕ + | ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + + ИначеЕсли ТипЗнч(МассивПользователей) = Тип("Тип") Тогда + Если Метаданные.НайтиПоТипу(МассивПользователей) = Метаданные.Справочники.ВнешниеПользователи Тогда + Запрос.Текст = + "ВЫБРАТЬ + | ВнешниеПользователи.Ссылка КАК Пользователь, + | ВнешниеПользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.ВнешниеПользователи КАК ВнешниеПользователи + |ГДЕ + | ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + Иначе + Запрос.Текст = + "ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.Пользователи КАК Пользователи + |ГДЕ + | Пользователи.Служебный = ЛОЖЬ + | И Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + КонецЕсли; + Иначе + ИсходныеПользователи = Новый ТаблицаЗначений; + ИсходныеПользователи.Колонки.Добавить("Пользователь", Новый ОписаниеТипов( + "СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи")); + + Для каждого Пользователь Из МассивПользователей Цикл + ИсходныеПользователи.Добавить().Пользователь = Пользователь; + КонецЦикла; + + Запрос.УстановитьПараметр("ИсходныеПользователи", ИсходныеПользователи); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ИсходныеПользователи.Пользователь + |ПОМЕСТИТЬ ИсходныеПользователи + |ИЗ + | &ИсходныеПользователи КАК ИсходныеПользователи + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | Справочник.Пользователи КАК Пользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсходныеПользователи КАК ИсходныеПользователи + | ПО Пользователи.Ссылка = ИсходныеПользователи.Пользователь + | И (Пользователи.Служебный = ЛОЖЬ) + | И (Пользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор) + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ВнешниеПользователи.Ссылка, + | ВнешниеПользователи.ИдентификаторПользователяИБ + |ИЗ + | Справочник.ВнешниеПользователи КАК ВнешниеПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИсходныеПользователи КАК ИсходныеПользователи + | ПО ВнешниеПользователи.Ссылка = ИсходныеПользователи.Пользователь + | И (ВнешниеПользователи.ИдентификаторПользователяИБ <> &ПустойИдентификатор) + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | Пользователи.Ссылка КАК Пользователь, + | Пользователи.ИдентификаторПользователяИБ + |ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи + | ПО (ГруппыДоступаПользователи.Ссылка = &ГруппаДоступаАдминистраторы) + | И ГруппыДоступаПользователи.Пользователь = Пользователи.Ссылка + | И (НЕ Пользователи.ПометкаУдаления) + | И (НЕ Пользователи.Недействителен) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ПроверяемыеПользователи.Пользователь, + | ПроверяемыеПользователи.ИдентификаторПользователяИБ + |ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПроверяемыеПользователи.Пользователь КАК Пользователь, + | ГруппыДоступаПользователи.Ссылка.Профиль КАК Профиль + |ПОМЕСТИТЬ ПрофилиПользователей + |ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО ПроверяемыеПользователи.Пользователь = СоставыГруппПользователей.Пользователь + | И (СоставыГруппПользователей.Используется) + | И (&ИсключитьВнешнихПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь) + | И (НЕ ГруппыДоступаПользователи.Ссылка.ПометкаУдаления) + | И (НЕ ГруппыДоступаПользователи.Ссылка.Профиль.ПометкаУдаления) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПрофилиПользователей.Пользователь, + | Роли.Роль КАК РольСсылка + |ИЗ + | ПрофилиПользователей КАК ПрофилиПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК Роли + | ПО (Роли.Ссылка = ПрофилиПользователей.Профиль) + |ГДЕ + | Роли.Роль <> НЕОПРЕДЕЛЕНО"; + + Запрос.Текст = Запрос.Текст + " + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |" + ТекстЗапроса; + + Если Константы.ИспользоватьВнешнихПользователей.Получить() Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИсключитьВнешнихПользователей", "ИСТИНА"); + Иначе + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ИсключитьВнешнихПользователей", + "ТИПЗНАЧЕНИЯ(ПроверяемыеПользователи.Пользователь) = ТИП(Справочник.Пользователи)"); // @query-part-2 + КонецЕсли; + + РезультатыЗапросов = Запрос.ВыполнитьПакет(); + ПоследнийРезультат = РезультатыЗапросов.Количество()-1; + Итог = Новый Структура; + + Итог.Вставить("Администраторы", Новый Соответствие); + + Для каждого Строка Из РезультатыЗапросов[ПоследнийРезультат-3].Выгрузить() Цикл + Итог.Администраторы.Вставить(Строка.Пользователь, Истина); + КонецЦикла; + + Итог.Вставить("ИдентификаторыПользователейИБ", РезультатыЗапросов[ПоследнийРезультат-2].Выгрузить()); + + Если ПользователиСлужебный.СостояниеДоВызоваАвторизоватьТекущегоПользователя(Истина) Тогда + Отбор = Новый Структура("ИдентификаторПользователяИБ", + ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор); + НайденныеСтроки = Итог.ИдентификаторыПользователейИБ.НайтиСтроки(Отбор); + Если ЗначениеЗаполнено(НайденныеСтроки) Тогда + Итог.Администраторы.Вставить(НайденныеСтроки[0].Пользователь, Истина); + КонецЕсли; + КонецЕсли; + + Итог.Вставить("РолиПользователей", РезультатыЗапросов[ПоследнийРезультат].Выгрузить()); + Итог.РолиПользователей.Колонки.Добавить("Роль", Новый ОписаниеТипов("Строка")); + Итог.РолиПользователей.Индексы.Добавить("Пользователь"); + + РолиВсехПользователей = Итог.РолиПользователей.Скопировать(, "РольСсылка"); + РолиВсехПользователей.Свернуть("РольСсылка"); + ИдентификаторыРолей = РолиВсехПользователей.ВыгрузитьКолонку("РольСсылка"); + ПроверитьАктуальностьНовыхРолейПользователейВСеансе(ИдентификаторыРолей); + МетаданныеРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИдентификаторыРолей, Ложь); + + ИдентификаторыРолей = Новый Соответствие; + ИменаРолей = Новый Соответствие; + БезОбъектовМетаданных = Новый Массив; + Для Каждого ОписаниеРоли Из МетаданныеРолей Цикл + Если ТипЗнч(ОписаниеРоли.Значение) = Тип("ОбъектМетаданных") Тогда + ИмяРоли = ОписаниеРоли.Значение.Имя; + ИдентификаторыРолей.Вставить(ИмяРоли, ОписаниеРоли.Ключ); + ИменаРолей.Вставить(ОписаниеРоли.Ключ, ИмяРоли); + Иначе + БезОбъектовМетаданных.Добавить(ОписаниеРоли.Ключ); + КонецЕсли; + КонецЦикла; + + Если ЗначениеЗаполнено(БезОбъектовМетаданных) Тогда + ДобавитьИдентификаторыРолейБезОбъектовМетаданных(БезОбъектовМетаданных, ИдентификаторыРолей); + КонецЕсли; + + ОбязательныеРолиАдминистратора = Новый Соответствие; + ОбязательныеРолиАдминистратора.Вставить("ПолныеПрава"); + Если Не ОбщегоНазначения.РазделениеВключено() Тогда + ОбязательныеРолиАдминистратора.Вставить("АдминистраторСистемы"); + КонецЕсли; + СтандартныеРолиРасширений = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСтандартныхРолейРасширенийСеанса().РолиСеанса; + ДополнительныеРолиАдминистратора = Новый Соответствие(СтандартныеРолиРасширений.ДополнительныеРолиАдминистратора); + ПриПодготовкеДополнительныхРолейАдминистратора(ДополнительныеРолиАдминистратора); + ДополнительныеРолиАдминистратора.Вставить("ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок"); + + ПолныеИменаРолей = Новый Массив; + ДобавитьИменаРолей(ОбязательныеРолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей); + ДобавитьИменаРолей(ДополнительныеРолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей); + Если ЗначениеЗаполнено(ПолныеИменаРолей) Тогда + ДобавитьИдентификаторыРолей(ПолныеИменаРолей, ИдентификаторыРолей, ИменаРолей); + КонецЕсли; + + ЗаполнитьИдентификаторыРолей(ОбязательныеРолиАдминистратора, ИдентификаторыРолей, ИменаРолей); + ЗаполнитьИдентификаторыРолей(ДополнительныеРолиАдминистратора, ИдентификаторыРолей); + + Итог.Вставить("ИдентификаторыРолей", ИдентификаторыРолей); + Итог.Вставить("ИменаРолей", ИменаРолей); + + Итог.Вставить("ОбязательныеРолиАдминистратора", ОбязательныеРолиАдминистратора); + Итог.Вставить("ДополнительныеРолиАдминистратора", ДополнительныеРолиАдминистратора); + + Возврат Итог; + +КонецФункции + +// Для функции ТекущиеСвойстваПользователей. +Процедура ПроверитьАктуальностьНовыхРолейПользователейВСеансе(ИдентификаторыРолей) + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ИдентификаторыРолей"; + ЗначениеСеанса = УправлениеДоступомСлужебныйПовтИсп.ИдентификаторыРолейСеанса(); + + ТекущееЗначение = ПоследниеИдентификаторыРолей(ИмяПараметра); + + Если ТекущееЗначение.ХешСумма = ЗначениеСеанса.ХешСумма Тогда + Возврат; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + ТекущееЗначение = ПоследниеИдентификаторыРолей(ИмяПараметра, УжеИзменен); + Если ТекущееЗначение.ХешСумма <> ЗначениеСеанса.ХешСумма Тогда + ПропуститьОбновление = Ложь; + Если УжеИзменен Тогда + Попытка + ПроверитьАктуальностьМетаданных(); + Исключение + ИдентификаторыСеанса = ЗначениеСеанса.ИдентификаторыРолей; + ТекущиеИдентификаторы = ТекущееЗначение.ИдентификаторыРолей; + Для Каждого ИдентификаторРоли Из ИдентификаторыРолей Цикл + ЕстьВТекущих = ТекущиеИдентификаторы.Получить(ИдентификаторРоли) <> Неопределено; + ЕстьВСеансе = ИдентификаторыСеанса.Получить(ИдентификаторРоли) <> Неопределено; + Если ЕстьВТекущих <> ЕстьВСеансе Тогда + ВызватьИсключение; + КонецЕсли; + КонецЦикла; + ПропуститьОбновление = Истина; + КонецПопытки; + КонецЕсли; + Если Не ПропуститьОбновление Тогда + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ЗначениеСеанса, Истина); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ДобавитьИменаРолей(РолиАдминистратора, ПолныеИменаРолей, ИдентификаторыРолей) + + Для Каждого КлючИЗначение Из РолиАдминистратора Цикл + Если ИдентификаторыРолей.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда + Продолжить; + КонецЕсли; + МетаданныеРоли = Метаданные.Роли.Найти(КлючИЗначение.Ключ); + Если МетаданныеРоли = Неопределено Тогда + Продолжить; + КонецЕсли; + ПолноеИмяРоли = МетаданныеРоли.ПолноеИмя(); + Если ПолныеИменаРолей.Найти(ПолноеИмяРоли) = Неопределено Тогда + ПолныеИменаРолей.Добавить(ПолноеИмяРоли); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ДобавитьИдентификаторыРолей(ПолныеИменаРолей, ИдентификаторыРолей, ИменаРолей) + + ДополнительныеИдентификаторыРолей = + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИменаРолей, Ложь); + + Для Каждого КлючИЗначение Из ДополнительныеИдентификаторыРолей Цикл + ИдентификаторРоли = КлючИЗначение.Значение; + Если ИдентификаторРоли = Неопределено Тогда + Продолжить; + КонецЕсли; + ИмяРоли = СтрРазделить(КлючИЗначение.Ключ, ".")[1]; + ИдентификаторыРолей.Вставить(ИмяРоли, ИдентификаторРоли); + ИменаРолей.Вставить(ИдентификаторРоли, ИмяРоли); + КонецЦикла; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ДобавитьИдентификаторыРолейБезОбъектовМетаданных(БезОбъектовМетаданных, ИдентификаторыРолей) + + КлючиРолей = Справочники.ИдентификаторыОбъектовМетаданных.КлючиРолей(БезОбъектовМетаданных); + + Для Каждого КлючИЗначение Из КлючиРолей Цикл + Если ЗначениеЗаполнено(КлючИЗначение.Значение) Тогда + ИдентификаторыРолей.Вставить(КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции ТекущиеСвойстваПользователей. +Процедура ЗаполнитьИдентификаторыРолей(РолиАдминистратора, ИдентификаторыРолей, ИменаРолей = Неопределено) + + НовыеРолиАдминистратора = Новый Соответствие; + + Для Каждого КлючИЗначение Из РолиАдминистратора Цикл + ИмяРоли = КлючИЗначение.Ключ; + ИдентификаторРоли = ИдентификаторыРолей.Получить(ИмяРоли); + Если ИдентификаторРоли = Неопределено Тогда + Если ИменаРолей <> Неопределено Тогда + ИдентификаторРоли = Справочники.ИдентификаторыОбъектовМетаданных.ПолучитьСсылку(); + ИдентификаторыРолей.Вставить(ИмяРоли, ИдентификаторРоли); + ИменаРолей.Вставить(ИдентификаторРоли, ИмяРоли); + Иначе + Продолжить; + КонецЕсли; + КонецЕсли; + НовыеРолиАдминистратора.Вставить(ИмяРоли, ИдентификаторРоли); + КонецЦикла; + + РолиАдминистратора = НовыеРолиАдминистратора; + +КонецПроцедуры + +// См. УправлениеДоступомСлужебныйПовтИсп.ИдентификаторыРолейСеанса +Функция ПоследниеИдентификаторыРолей(ИмяПараметра, УжеИзменен = Ложь) + + Значение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + Если ТипЗнч(Значение) <> Тип("ФиксированнаяСтруктура") + Или Не Значение.Свойство("ХешСумма") + Или Не Значение.Свойство("ИдентификаторыРолей") + Или ТипЗнч(Значение.ИдентификаторыРолей) <> Тип("ФиксированноеСоответствие") Тогда + + Значение = Новый Структура("ХешСумма, ИдентификаторыРолей", "", Новый Соответствие); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +// Параметры: +// НовыеРолиПользователей - ТаблицаЗначений +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// * РольСсылка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * Роль - Строка - имя роли. +// +Функция НовыеНекорректныеРоли(НовыеРолиПользователей) + + Результат = НовыеРолиПользователей.Скопировать( + Новый Массив, "Пользователь, Роль, РольСсылка"); + + Результат.Колонки.Добавить("ЭтоНенайденнаяРоль", Новый ОписаниеТипов("Булево")); + + Возврат Результат; + +КонецФункции + +// Параметры: +// НекорректныеРоли - см. НовыеНекорректныеРоли +// ОписаниеРоли - СтрокаТаблицыЗначений +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// +Процедура ДобавитьНекорректнуюРоль(НекорректныеРоли, ОписаниеРоли, Пользователь, ЭтоНенайденнаяРоль) + + НоваяСтрока = НекорректныеРоли.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ОписаниеРоли); + НоваяСтрока.Пользователь = Пользователь; + НоваяСтрока.ЭтоНенайденнаяРоль = ЭтоНенайденнаяРоль; + +КонецПроцедуры + +// Параметры: +// НекорректныеРоли - см. НовыеНекорректныеРоли +// +Процедура ЗарегистрироватьНекорректныеРоли(НекорректныеРоли) + + Если Не ЗначениеЗаполнено(НекорректныеРоли) Тогда + Возврат; + КонецЕсли; + + ЗаполнитьИменаНенайденныхРолей(НекорректныеРоли); + + ПрофилиНекорректныхРолей = ПрофилиПользователейСРолями(НекорректныеРоли); + ПрофилиНекорректныхРолей.Индексы.Добавить("Пользователь, РольСсылка"); + Отбор = Новый Структура("Пользователь, РольСсылка"); + + Для Каждого НекорректнаяРоль Из НекорректныеРоли Цикл + ЗаполнитьЗначенияСвойств(Отбор, НекорректнаяРоль); + Строки = ПрофилиНекорректныхРолей.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + Если НекорректнаяРоль.ЭтоНенайденнаяРоль Тогда + ЗарегистрироватьНенайденнуюРоль(НекорректнаяРоль, Строка.Профиль); + Иначе + ЗарегистрироватьНедоступнуюРоль(НекорректнаяРоль, Строка.Профиль); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗарегистрироватьНекорректныеРоли. +Процедура ЗаполнитьИменаНенайденныхРолей(НекорректныеРоли) + + Отбор = Новый Структура("ЭтоНенайденнаяРоль", Истина); + Строки = НекорректныеРоли.НайтиСтроки(Отбор); + Если Не ЗначениеЗаполнено(Строки) Тогда + Возврат; + КонецЕсли; + НенайденныеРоли = НекорректныеРоли.Скопировать(Строки, "РольСсылка"); + Ссылки = НенайденныеРоли.ВыгрузитьКолонку("РольСсылка"); + + Результат = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(Ссылки, + Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.Имя.Имя); + + Для Каждого Строка Из Строки Цикл + Строка.Роль = Результат.Получить(Строка.РольСсылка); + Если Не ЗначениеЗаполнено(Строка.Роль) Тогда + Строка.Роль = Строка(Строка.РольСсылка); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ЗарегистрироватьНедоступнуюРоль(ОписаниеРоли, Профиль) + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Роль недоступна пользователю'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка, + Метаданные.Справочники.ПрофилиГруппДоступа, + Профиль, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При обновлении ролей пользователя ""%1"" + |роль ""%2"" + |%3 + |профиля групп доступа ""%4"" + |%5 + |недоступна пользователю.'"), + Строка(ОписаниеРоли.Пользователь), + ОписаниеРоли.Роль, + ПолучитьНавигационнуюСсылку(ОписаниеРоли.РольСсылка), + Строка(Профиль), + ПолучитьНавигационнуюСсылку(Профиль)), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +Процедура ЗарегистрироватьНенайденнуюРоль(ОписаниеРоли, Профиль) + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Роль не найдена в метаданных'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка, + Метаданные.Справочники.ПрофилиГруппДоступа, + Профиль, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При обновлении ролей пользователя ""%1"" + |роль ""%2"" + |%3 + |профиля групп доступа ""%4"" + |%5 + |не существует в метаданных.'"), + Строка(ОписаниеРоли.Пользователь), + ОписаниеРоли.Роль, + ПолучитьНавигационнуюСсылку(ОписаниеРоли.РольСсылка), + Строка(Профиль), + ПолучитьНавигационнуюСсылку(Профиль)), + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +Процедура ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса) + + ВнешняяТранзакцияАктивна = ТранзакцияАктивна(); + ИзмененныеПользователи = Новый Массив; + СообщатьВМенеджерСервиса = ОбщегоНазначения.РазделениеВключено() + И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ПользователиВМоделиСервиса"); + + Для Каждого КлючИЗначение Из ОбновляемыеПользователиИБ Цикл + РолиДляДобавления = КлючИЗначение.Значение.РолиДляДобавления; + РолиДляУдаления = КлючИЗначение.Значение.РолиДляУдаления; + ПользовательИБ = КлючИЗначение.Значение.ПользовательИБ; + ПользовательСсылка = КлючИЗначение.Значение.ПользовательСсылка; + ИзмененныеПользователи.Добавить(ПользовательСсылка); + + Если СообщатьВМенеджерСервиса Тогда + БылиПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава); + БылиПраваНаВход = Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь); + КонецЕсли; + + Для Каждого КлючИЗначение Из РолиДляДобавления Цикл + ПользовательИБ.Роли.Добавить(Метаданные.Роли[КлючИЗначение.Ключ]); + КонецЦикла; + + Для Каждого КлючИЗначение Из РолиДляУдаления Цикл + ПользовательИБ.Роли.Удалить(КлючИЗначение.Значение); + КонецЦикла; + + НачатьТранзакцию(); + Попытка + ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, + ПользовательИБ, БылиПолныеПрава, БылиПраваНаВход, ПарольПользователяСервиса, ВнешняяТранзакцияАктивна); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + + Если ВнешняяТранзакцияАктивна Тогда + РегистрыСведений.СведенияОПользователях.ОбновитьДанныеРегистра(ИзмененныеПользователи); + КонецЕсли; + +КонецПроцедуры + +Процедура ОтключитьУВсехРасширенийФлажокИспользоватьОсновныеРолиДляВсехПользователей() + + Отбор = Новый Структура("ИспользоватьОсновныеРолиДляВсехПользователей", Истина); + Расширения = РасширенияКонфигурации.Получить(Отбор); + РазделениеВключено = ОбщегоНазначения.РазделениеВключено(); + ТекущаяОбластьДействия = ?(ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных(), + ОбластьДействияРасширенияКонфигурации.РазделениеДанных, + ОбластьДействияРасширенияКонфигурации.ИнформационнаяБаза); + + Для Каждого Расширение Из Расширения Цикл + Если Не Расширение.ИспользоватьОсновныеРолиДляВсехПользователей + Или РазделениеВключено + И Расширение.ОбластьДействия <> ТекущаяОбластьДействия Тогда + Продолжить; + КонецЕсли; + Справочники.ВерсииРасширений.ОтключитьПредупрежденияБезопасности(Расширение); + Справочники.ВерсииРасширений.ОтключитьИспользованиеОсновныхРолейДляВсехПользователей(Расширение); + // АПК:280-выкл - №499.3.4 Допустимо пропустить обработку исключения, так как + // это не останавливающая операция и будет выполнена успешно при очередном обновлении ролей. + // Запись расширения не является транзакционной операцией, поэтому не создает ошибок в транзакции. + Попытка + Расширение.Записать(); + Исключение + // Обработка не требуется. + КонецПопытки; + // АПК:280-вкл. + КонецЦикла; + +КонецПроцедуры + +// Параметры: +// НекорректныеРоли - см. НовыеНекорректныеРоли +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// * РольСсылка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * Профиль - СправочникСсылка.ПрофилиГруппДоступа +// +Функция ПрофилиПользователейСРолями(НекорректныеРоли) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("НекорректныеРоли", НекорректныеРоли); + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | НекорректныеРоли.Пользователь КАК Пользователь, + | НекорректныеРоли.РольСсылка КАК РольСсылка + |ПОМЕСТИТЬ НекорректныеРоли + |ИЗ + | &НекорректныеРоли КАК НекорректныеРоли + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь, + | РольСсылка + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | НекорректныеРоли.Пользователь КАК Пользователь, + | НекорректныеРоли.РольСсылка КАК РольСсылка, + | Роли.Ссылка КАК Профиль + |ИЗ + | НекорректныеРоли КАК НекорректныеРоли + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.Пользователь = НекорректныеРоли.Пользователь) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) + | И (НЕ ГруппыДоступаПользователи.Ссылка.ПометкаУдаления) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК Роли + | ПО (Роли.Ссылка = ГруппыДоступаПользователи.Ссылка.Профиль) + | И (НЕ Роли.Ссылка.ПометкаУдаления) + | И (Роли.Роль = НекорректныеРоли.РольСсылка)"; + + Возврат Запрос.Выполнить().Выгрузить(); + +КонецФункции + +// Для процедуры ОбновитьРолиПользователейИБ. +Процедура ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, ПользовательИБ, + БылиПолныеПрава, БылиПраваНаВход, ПарольПользователяСервиса, ВнешняяТранзакцияАктивна) + + ПользователиСлужебный.ЗаписатьПользователяИнформационнойБазы(ПользовательИБ, + ТипЗнч(ПользовательСсылка) = Тип("СправочникСсылка.ВнешниеПользователи"), + ПользовательСсылка, + ?(ВнешняяТранзакцияАктивна, Null, Ложь)); + + Если БылиПолныеПрава = Неопределено Тогда + Возврат; + КонецЕсли; + + ЕстьПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава); + ЕстьПраваНаВход = Пользователи.ЕстьПраваДляВходаВПрограмму(ПользовательИБ,, Ложь); + + Если ЕстьПолныеПрава = БылиПолныеПрава + И ЕстьПраваНаВход = БылиПраваНаВход + Или Не Пользователи.ВходВПрограммуРазрешен(ПользовательИБ) Тогда + Возврат; + КонецЕсли; + + МодульПользователиСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ПользователиСлужебныйВМоделиСервиса"); + + Если ЕстьПолныеПрава <> БылиПолныеПрава Тогда + Если ПарольПользователяСервиса = Неопределено Тогда + Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда + МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса"); + СеансЗапущенБезРазделителей = МодульРаботаВМоделиСервиса.СеансЗапущенБезРазделителей(); + Иначе + СеансЗапущенБезРазделителей = Истина; + КонецЕсли; + Если Не СеансЗапущенБезРазделителей Тогда + УпрощенныйИнтерфейс = УпрощенныйИнтерфейсНастройкиПравДоступа(); + + Если БылиПолныеПрава Тогда + Шаблон = НСтр("ru = 'Для отключения административного доступа пользователю ""%1"" требуется пароль текущего пользователя сервиса ""%2"".'"); + Иначе + Шаблон = НСтр("ru = 'Для установки административного доступа пользователю ""%1"" требуется пароль текущего пользователя сервиса ""%2"".'"); + КонецЕсли; + + Если БылиПолныеПрава И УпрощенныйИнтерфейс Тогда + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке пользователя при отключении ему профиля Администратор.'"); + ИначеЕсли Не БылиПолныеПрава И УпрощенныйИнтерфейс Тогда + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке пользователя при включении ему профиля Администратор.'"); + ИначеЕсли БылиПолныеПрава Тогда + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке группы доступа Администраторы или в карточке пользователя при исключении его из группы доступа Администраторы.'"); + Иначе + Уточнение = НСтр("ru = 'Это действие может быть выполнено только в карточке группы доступа Администраторы или в карточке пользователя при включении его в группу доступа Администраторы.'"); + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, + ПользовательИБ.Имя, ПользователиИнформационнойБазы.ТекущийПользователь().Имя); + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + Уточнение; + + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Иначе + МодульПользователиСлужебныйВМоделиСервиса.ЗаписатьПользователяСервиса(ПользовательСсылка, + Ложь, ПарольПользователяСервиса); + Возврат; + КонецЕсли; + КонецЕсли; + + Если ЕстьПраваНаВход <> БылиПраваНаВход Тогда + МодульПользователиСлужебныйВМоделиСервиса.СообщитьИзмененЗапускПриложения(ПользовательСсылка, + ПользовательИБ); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ТекстЗапросаВыбораИзменений. + +Функция КлючИЗначение(Структура) + + Для Каждого КлючИЗначение Из Структура Цикл + Возврат КлючИЗначение; + КонецЦикла; + + Возврат ""; + +КонецФункции + +// Для процедур ОбновитьНаборЗаписей, ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям. + +Процедура ЗаписатьОбъектИлиНаборЗаписей(Данные, ОбъектИлиНаборЗаписей) + + Если Данные.ОбновлениеИБ Тогда + ОбновлениеИнформационнойБазы.ЗаписатьДанные(ОбъектИлиНаборЗаписей); + Иначе + ОбъектИлиНаборЗаписей.Записать(); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьНаборЗаписей и ОбновитьНаборыЗаписей. + +Функция ГруппаПараметровИзмеренияОбработана(ИмяИзмерения, ЗначенияИзмерения) + + Если ИмяИзмерения = Неопределено Тогда + ЗначенияИзмерения = Неопределено; + + ИначеЕсли ЗначенияИзмерения = Неопределено Тогда + ИмяИзмерения = Неопределено; + + ИначеЕсли ТипЗнч(ЗначенияИзмерения) <> Тип("Массив") + И ТипЗнч(ЗначенияИзмерения) <> Тип("ФиксированныйМассив") Тогда + + ЗначениеИзмерения = ЗначенияИзмерения; + ЗначенияИзмерения = Новый Массив; + ЗначенияИзмерения.Добавить(ЗначениеИзмерения); + + ИначеЕсли ЗначенияИзмерения.Количество() = 0 Тогда + Возврат Ложь; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +Процедура УпорядочитьГруппыПараметровИзмерений(Данные) + + Если Данные.ИмяВторогоИзмерения = Неопределено Тогда + Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; + Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; + Данные.ИмяТретьегоИзмерения = Неопределено; + Данные.ЗначенияТретьегоИзмерения = Неопределено; + КонецЕсли; + + Если Данные.ИмяПервогоИзмерения = Неопределено Тогда + Данные.ИмяПервогоИзмерения = Данные.ИмяВторогоИзмерения; + Данные.ЗначенияПервогоИзмерения = Данные.ЗначенияВторогоИзмерения; + Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; + Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; + Данные.ИмяТретьегоИзмерения = Неопределено; + Данные.ЗначенияТретьегоИзмерения = Неопределено; + КонецЕсли; + + Если Данные.ЗначенияВторогоИзмерения <> Неопределено + И Данные.ЗначенияТретьегоИзмерения <> Неопределено + И Данные.ЗначенияВторогоИзмерения.Количество() + > Данные.ЗначенияТретьегоИзмерения.Количество() Тогда + + ИмяИзмерения = Данные.ИмяВторогоИзмерения; + ЗначенияИзмерения = Данные.ЗначенияВторогоИзмерения; + + Данные.ИмяВторогоИзмерения = Данные.ИмяТретьегоИзмерения; + Данные.ЗначенияВторогоИзмерения = Данные.ЗначенияТретьегоИзмерения; + Данные.ИмяТретьегоИзмерения = ИмяИзмерения; + Данные.ЗначенияТретьегоИзмерения = ЗначенияИзмерения; + КонецЕсли; + + Если Данные.ЗначенияПервогоИзмерения <> Неопределено + И Данные.ЗначенияВторогоИзмерения <> Неопределено + И Данные.ЗначенияПервогоИзмерения.Количество() + > Данные.ЗначенияВторогоИзмерения.Количество() Тогда + + ИмяИзмерения = Данные.ИмяПервогоИзмерения; + ЗначенияИзмерения = Данные.ЗначенияПервогоИзмерения; + + Данные.ИмяПервогоИзмерения = Данные.ИмяВторогоИзмерения; + Данные.ЗначенияПервогоИзмерения = Данные.ЗначенияВторогоИзмерения; + Данные.ИмяВторогоИзмерения = ИмяИзмерения; + Данные.ЗначенияВторогоИзмерения = ЗначенияИзмерения; + КонецЕсли; + +КонецПроцедуры + +Функция ПоляНабораЗаписей(НаборЗаписей) + + ПоляСравнения = ""; + Таблица = НаборЗаписей.Выгрузить(Новый Массив); + Для каждого Колонка Из Таблица.Колонки Цикл + ПоляСравнения = ПоляСравнения + "," + Колонка.Имя; + КонецЦикла; + ПоляСравнения = Сред(ПоляСравнения, 2); + + Возврат ПоляСравнения; + +КонецФункции + +Процедура ОбновитьНовыеЗаписиНабораПоВсемНовымЗаписям(Знач Данные, Знач Отбор, Знач СписокПолей, + Знач ИмяИзмерения, Знач ЗначенияИзмерения, ЕстьИзменения) + + ЗаблокироватьОбластьНабораЗаписей(Данные.НаборЗаписей, Данные.ПолноеИмяРегистра); + + Данные.НаборЗаписей.Прочитать(); + НовыеЗаписиНабора = Данные.НаборЗаписей.Выгрузить(); + НовыеЗаписиНабора.Индексы.Добавить(СписокПолей); + + Для каждого Значение Из ЗначенияИзмерения Цикл + Отбор[ИмяИзмерения] = Значение; + Для каждого НайденнаяЗапись Из НовыеЗаписиНабора.НайтиСтроки(Отбор) Цикл + НовыеЗаписиНабора.Удалить(НайденнаяЗапись); + КонецЦикла; + Для каждого НайденнаяЗапись Из Данные.НовыеЗаписи.НайтиСтроки(Отбор) Цикл + ЗаполнитьЗначенияСвойств(НовыеЗаписиНабора.Добавить(), НайденнаяЗапись); + КонецЦикла; + КонецЦикла; + + ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); + ТекущиеДанные.Вставить("НаборЗаписейПрочитан", Истина); + + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + +КонецПроцедуры + +Процедура ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям(Знач Данные, Знач Отбор, ЕстьИзменения) + + // Получение количества записей для чтения. + + Если Отбор.Количество() = 0 Тогда + ТекущиеНовыеЗаписи = Данные.НовыеЗаписи.Скопировать(); // ТаблицаЗначений + КоличествоДляЧтения = Данные.КоличествоДляЧтения; + Иначе + ТекущиеНовыеЗаписи = Данные.НовыеЗаписи.Скопировать(Отбор); // ТаблицаЗначений + + КоличествоПоЗначениям = Данные.КоличествоПоЗначениям; // ТаблицаЗначений + ИмяПоля = КоличествоПоЗначениям.Колонки[0].Имя; + СтрокаКоличества = Данные.КоличествоПоЗначениям.Найти(Отбор[ИмяПоля], ИмяПоля); + КоличествоДляЧтения = ?(СтрокаКоличества = Неопределено, 0, СтрокаКоличества.Количество); + КонецЕсли; + + ОтборНовойЗаписи = Новый Структура("ВидИзмененияСтроки, " + Данные.ПоляСравнения, 1); + ТекущиеНовыеЗаписи.Индексы.Добавить("ВидИзмененияСтроки, " + Данные.ПоляСравнения); + + КлючиЗаписей = ТекущиеНовыеЗаписи.Скопировать(, "ВидИзмененияСтроки, " + Данные.ПоляСравнения); + КлючиЗаписей.Свернуть("ВидИзмененияСтроки, " + Данные.ПоляСравнения); + КлючиЗаписей.Свернуть(Данные.ПоляСравнения, "ВидИзмененияСтроки"); + + ОтборПоКлючуЗаписи = Новый Структура(Данные.ПоляСравнения); + + Если ОбновлятьНаборЗаписейЦеликом(КоличествоДляЧтения, КлючиЗаписей) Тогда + + ЗаблокироватьОбластьНабораЗаписей(Данные.НаборЗаписей, Данные.ПолноеИмяРегистра); + Данные.НаборЗаписей.Прочитать(); + НовыеЗаписиНабора = Данные.НаборЗаписей.Выгрузить(); // ТаблицаЗначений + НовыеЗаписиНабора.Индексы.Добавить(Данные.ПоляСравнения); + + Для каждого Строка Из КлючиЗаписей Цикл + ЗаполнитьЗначенияСвойств(ОтборПоКлючуЗаписи, Строка); + НайденныеСтроки = НовыеЗаписиНабора.НайтиСтроки(ОтборПоКлючуЗаписи); + Если Строка.ВидИзмененияСтроки = -1 Тогда + Если НайденныеСтроки.Количество() > 0 Тогда + // Удаление старой строки. + НовыеЗаписиНабора.Удалить(НайденныеСтроки[0]); + КонецЕсли; + Иначе + // Добавление новой или обновление старой строки. + Если НайденныеСтроки.Количество() = 0 Тогда + ЗаполняемаяСтрока = НовыеЗаписиНабора.Добавить(); + Иначе + ЗаполняемаяСтрока = НайденныеСтроки[0]; + КонецЕсли; + ЗаполнитьЗначенияСвойств(ОтборНовойЗаписи, ОтборПоКлючуЗаписи); + НайденныеЗаписи = ТекущиеНовыеЗаписи.НайтиСтроки(ОтборНовойЗаписи); + Если НайденныеЗаписи.Количество() = 1 Тогда + НоваяЗапись = НайденныеЗаписи[0]; + Иначе // Ошибка в параметре НовыеЗаписи. + ИсключениеПриОшибкеПоискаЗаписи(Данные); + КонецЕсли; + ЗаполнитьЗначенияСвойств(ЗаполняемаяСтрока, НоваяЗапись); + КонецЕсли; + КонецЦикла; + // Изменение набора записей, чтобы он отличался от новых записей набора. + Если Данные.НаборЗаписей.Количество() = НовыеЗаписиНабора.Количество() Тогда + Данные.НаборЗаписей.Добавить(); + КонецЕсли; + + ТекущиеДанные = Новый Структура("НаборЗаписей, ПоляСравнения, + |ТолькоПроверка, ДополнительныеСвойства, ОбновлениеИБ"); + ЗаполнитьЗначенияСвойств(ТекущиеДанные, Данные); + ТекущиеДанные.Вставить("НовыеЗаписи", НовыеЗаписиНабора); + ТекущиеДанные.Вставить("НаборЗаписейПрочитан", Истина); + + ОбновитьНаборЗаписей(ТекущиеДанные, ЕстьИзменения); + Иначе + // Построчное обновление. + УстановитьДополнительныеСвойства(Данные.НаборДляОднойЗаписи, Данные.ДополнительныеСвойства); + Для каждого Строка Из КлючиЗаписей Цикл + Данные.НаборДляОднойЗаписи.Очистить(); + ЗаполнитьЗначенияСвойств(ОтборПоКлючуЗаписи, Строка); + Для каждого КлючИЗначение Из ОтборПоКлючуЗаписи Цикл + УстановитьОтбор( + Данные.НаборДляОднойЗаписи.Отбор[КлючИЗначение.Ключ], КлючИЗначение.Значение); + КонецЦикла; + ЗаблокироватьОбластьНабораЗаписей(Данные.НаборДляОднойЗаписи, Данные.ПолноеИмяРегистра); + Если Строка.ВидИзмененияСтроки > -1 Тогда + // Добавление новой или обновление существующей строки. + ЗаполнитьЗначенияСвойств(ОтборНовойЗаписи, ОтборПоКлючуЗаписи); + НайденныеЗаписи = ТекущиеНовыеЗаписи.НайтиСтроки(ОтборНовойЗаписи); + Если НайденныеЗаписи.Количество() = 1 Тогда + НоваяЗапись = НайденныеЗаписи[0]; + Иначе // Ошибка в параметре НовыеЗаписи. + ИсключениеПриОшибкеПоискаЗаписи(Данные); + КонецЕсли; + ЗаполнитьЗначенияСвойств(Данные.НаборДляОднойЗаписи.Добавить(), НоваяЗапись); + КонецЕсли; + ЕстьИзменения = Истина; + Если Данные.ТолькоПроверка Тогда + Возврат; + КонецЕсли; + ЗаписатьОбъектИлиНаборЗаписей(Данные, Данные.НаборДляОднойЗаписи); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьНовыеЗаписиНабораПоРазличнымНовымЗаписям. +Функция ОбновлятьНаборЗаписейЦеликом(КоличествоДляЧтения, КлючиЗаписей) + + Если КоличествоДляЧтения > 10000 Тогда + Возврат Ложь; // Слишком большой набор записей. + КонецЕсли; + + КоличествоУдаляемых = КлючиЗаписей.НайтиСтроки( + Новый Структура("ВидИзмененияСтроки", -1)).Количество(); + + КоличествоДобавляемых = КлючиЗаписей.НайтиСтроки( + Новый Структура("ВидИзмененияСтроки", 1)).Количество(); + + КоличествоДляЗаписи = КоличествоДляЧтения - КоличествоУдаляемых + + КоличествоДобавляемых; + + Если КоличествоДляЗаписи > 10000 Тогда + Возврат Ложь; // Слишком большой набор записей. + КонецЕсли; + + КоличествоИзменяемых = КлючиЗаписей.Количество() + - (КоличествоУдаляемых + КоличествоДобавляемых); + + КоличествоНеизменных = КоличествоДляЧтения + - (КоличествоУдаляемых + КоличествоИзменяемых); + + ЗатратыНаПерезаписьЦеликом = + // Операции: |Чтение|Удаление|Вставка| + КоличествоУдаляемых * ( 0.05 + 0.1 ) + + КоличествоИзменяемых * ( 0.05 + 0.1 + 1 ) + + КоличествоДобавляемых * ( 1 ) + + КоличествоНеизменных * ( 0.05 + 0.1 + 1 ); + + ЗатратыНаПерезаписьПоОднойЗаписи = + // Операции: |Удаление|Вставка| + КоличествоУдаляемых * ( 0.5 ) + + КоличествоИзменяемых * ( 0.5 + 1.2 ) + + КоличествоДобавляемых * ( 0.5 + 1.2 ); + + Возврат ЗатратыНаПерезаписьЦеликом < ЗатратыНаПерезаписьПоОднойЗаписи; + +КонецФункции + +Процедура ИсключениеПриОшибкеПоискаЗаписи(Параметры) + + Для каждого СтрокаИзменений Из Параметры.НовыеЗаписи Цикл + Если СтрокаИзменений.ВидИзмененияСтроки <> 1 + И СтрокаИзменений.ВидИзмененияСтроки <> -1 Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в процедуре %1 + |общего модуля %2. + | + |Неверное значение параметра %3 - колонка + |%4 содержит недопустимое значение ""%5"". + | + |Допустимо только 2 значения: ""1"" и ""-1"".'"), + "ОбновитьНаборыЗаписей", + "УправлениеДоступомСлужебный", + "НовыеЗаписи", + "ВидИзмененияСтроки", + Строка(СтрокаИзменений.ВидИзмененияСтроки)); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + КонецЦикла; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в процедуре %1 + |общего модуля %2. + | + |Не удалось найти требуемую в строку + |в значении параметра %3.'"), + "ОбновитьНаборыЗаписей", + "УправлениеДоступомСлужебный", + "НовыеЗаписи"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + +КонецПроцедуры + +Процедура ЗаблокироватьОбластьНабораЗаписей(НаборЗаписей, ПолноеИмяРегистра = Неопределено) + + Если НЕ ТранзакцияАктивна() Тогда + Возврат; + КонецЕсли; + + Если ПолноеИмяРегистра = Неопределено Тогда + ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(НаборЗаписей)).ПолноеИмя(); + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + Для каждого ЭлементОтбора Из НаборЗаписей.Отбор Цикл + Если ЭлементОтбора.Использование Тогда + ЭлементБлокировки.УстановитьЗначение(ЭлементОтбора.ПутьКДанным, ЭлементОтбора.Значение); + КонецЕсли; + КонецЦикла; + Блокировка.Заблокировать(); + +КонецПроцедуры + +Процедура УстановитьОтбор(ЭлементОтбора, ЗначениеОтбора) + + Попытка + ЭлементОтбора.Значение = ЗначениеОтбора; + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ВсеТипы = Новый Массив; + Для Каждого Тип Из ЭлементОтбора.ТипЗначения.Типы() Цикл + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + ВсеТипы.Добавить(Строка(Тип) + ?(ОбъектМетаданных = Неопределено, + "", " (" + ОбъектМетаданных.ПолноеИмя() + ")")); + КонецЦикла; + СвойстваОтбора = Новый Массив; + СвойстваОтбора.Добавить("Имя" + " = " + ЭлементОтбора.Имя); + СвойстваОтбора.Добавить("ПутьКДанным" + " = " + ЭлементОтбора.ПутьКДанным); + СвойстваОтбора.Добавить("ТипЗначения" + " = " + Символы.ПС + Символы.Таб + + СтрСоединить(ВсеТипы, Символы.ПС + Символы.Таб)); + МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеОтбора)); + Попытка + Если МетаданныеЗначения <> Неопределено Тогда + НавигационнаяСсылка = ПолучитьНавигационнуюСсылку(ЗначениеОтбора); + Иначе + НавигационнаяСсылка = ""; + КонецЕсли; + Исключение + НавигационнаяСсылка = ""; + КонецПопытки; + Попытка + ВнутренняяСтрока = ЗначениеВСтрокуВнутр(ЗначениеОтбора); + Исключение + ВнутренняяСтрока = ""; + КонецПопытки; + ДляАдминистратора = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось установить значение ""%1"" тип ""%2"" + | Навигационная ссылка: %3 + | Внутренняя строка: %4 + |в элемент отбора со свойствами: + |%5'"), + Строка(ЗначениеОтбора), + Строка(ТипЗнч(ЗначениеОтбора)) + ?(МетаданныеЗначения = Неопределено, + "", " (" + МетаданныеЗначения.ПолноеИмя() + ")"), + НавигационнаяСсылка, + ВнутренняяСтрока, + СтрСоединить(СвойстваОтбора, Символы.ПС)); + Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке); + Попытка + ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,, ДляАдминистратора, ИнформацияОбОшибке); + Исключение + ЗаписьЖурналаРегистрации(НСтр("ru = 'Ошибка выполнения'", ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка,,, + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); + ВызватьИсключение; + КонецПопытки; + КонецПопытки; + + ЭлементОтбора.Использование = Истина; + +КонецПроцедуры + +Функция ЗаписьНесколькимиНаборами(Данные, Отбор, ИмяПоля, ЗначенияПоля) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ЗначенияПоля", ЗначенияПоля); + Запрос.Текст = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &УсловиеОтбора + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.ИмяПоля В(&ЗначенияПоля) + | И &УсловиеОтбора + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ТекущаяТаблица.ИмяПоля КАК ИмяПоля, + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.ИмяПоля В(&ЗначенияПоля) + | И &УсловиеОтбора + | + |СГРУППИРОВАТЬ ПО + | ТекущаяТаблица.ИмяПоля"; + + УсловиеОтбора = "ИСТИНА"; + Если Данные.ФиксированныйОтбор <> Неопределено Тогда + Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл + УсловиеОтбора = УсловиеОтбора + " + | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + ОтборДобавляемых = Новый Структура; + ОтборДобавляемых.Вставить("ВидИзмененияСтроки", 1); + ОтборУдаляемых = Новый Структура; + ОтборУдаляемых.Вставить("ВидИзмененияСтроки", -1); + + Для каждого КлючИЗначение Из Отбор Цикл + УсловиеОтбора = УсловиеОтбора + " + | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + ОтборДобавляемых.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + ОтборУдаляемых.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "ИмяПоля", ИмяПоля); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Данные.ПолноеИмяРегистра); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", УсловиеОтбора); + + РезультатыЗапросов = Запрос.ВыполнитьПакет(); + + // Количество всех без отбора. + КоличествоВсех = РезультатыЗапросов[0].Выгрузить()[0].Количество; + Данные.Вставить("КоличествоДляЧтения", КоличествоВсех); + + // Количество обновляемых с отбором. + КоличествоОбновляемых = РезультатыЗапросов[1].Выгрузить()[0].Количество; + + КоличествоДобавляемых = Данные.НовыеЗаписи.НайтиСтроки(ОтборДобавляемых).Количество(); + Если КоличествоДобавляемых > КоличествоОбновляемых Тогда + КоличествоОбновляемых = КоличествоДобавляемых; + КонецЕсли; + + КоличествоУдаляемых = Данные.НовыеЗаписи.НайтиСтроки(ОтборУдаляемых).Количество(); + Если КоличествоУдаляемых > КоличествоОбновляемых Тогда + КоличествоОбновляемых = КоличествоУдаляемых; + КонецЕсли; + + // Количество для чтения по значениям отбора. + КоличествоПоЗначениям = РезультатыЗапросов[2].Выгрузить(); + КоличествоПоЗначениям.Индексы.Добавить(ИмяПоля); + Данные.Вставить("КоличествоПоЗначениям", КоличествоПоЗначениям); + + Возврат КоличествоВсех * 0.7 > КоличествоОбновляемых; + +КонецФункции + +Процедура ПрочитатьКоличествоДляЧтения(Данные) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &УсловиеОтбора"; + + УсловиеОтбора = "ИСТИНА"; + Если Данные.ФиксированныйОтбор <> Неопределено Тогда + Для каждого КлючИЗначение Из Данные.ФиксированныйОтбор Цикл + УсловиеОтбора = УсловиеОтбора + " + | И ТекущаяТаблица." + КлючИЗначение.Ключ + " = &" + КлючИЗначение.Ключ; // @query-part-1 + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ТекущаяТаблица", Данные.ПолноеИмяРегистра); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", УсловиеОтбора); + + Данные.Вставить("КоличествоДляЧтения", Запрос.Выполнить().Выгрузить()[0].Количество); + +КонецПроцедуры + +Процедура УстановитьДополнительныеСвойства(НаборЗаписей, ДополнительныеСвойства) + + Если ТипЗнч(ДополнительныеСвойства) = Тип("Структура") Тогда + Для каждого КлючИЗначение Из ДополнительныеСвойства Цикл + НаборЗаписей.ДополнительныеСвойства.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьРегистрСведений. + +Функция ЗначенияКолонкиТаблицы(Таблица, ИмяКолонки) + + НоваяТаблица = Таблица.Скопировать(, ИмяКолонки); + + НоваяТаблица.Свернуть(ИмяКолонки); + + Возврат НоваяТаблица.ВыгрузитьКолонку(ИмяКолонки); + +КонецФункции + +// Обслуживание таблиц ВидыДоступа и ЗначенияДоступа в формах редактирования. + +Процедура ДобавитьРеквизитыВспомогательныхДанныхВФорму(Форма, ИмяРеквизитаХранилищаТаблиц) + + ДобавляемыеРеквизиты = Новый Массив; + ОписаниеТиповЗначенийДоступа = Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип; + + ПутьКОбъекту = ?(ЗначениеЗаполнено(ИмяРеквизитаХранилищаТаблиц), ИмяРеквизитаХранилищаТаблиц + ".", ""); + + // Добавление реквизитов в таблицу ВидыДоступа. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Используется", Новый ОписаниеТипов("Булево"), ПутьКОбъекту + "ВидыДоступа")); + + // Добавление отдельных реквизитов. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТекущийВидДоступа", ОписаниеТиповЗначенийДоступа)); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТекущиеТипыВыбираемыхЗначений", Новый ОписаниеТипов("СписокЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТекущийТипВыбираемыхЗначений", ОписаниеТиповЗначенийДоступа)); + + Если НЕ РеквизитФормыСуществует(Форма, "ИспользоватьВнешнихПользователей") Тогда + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИспользоватьВнешнихПользователей", Новый ОписаниеТипов("Булево"))); + КонецЕсли; + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИмяРеквизитаХранилищаТаблиц", Новый ОписаниеТипов("Строка"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ЭтоПрофильГруппДоступа", Новый ОписаниеТипов("Булево"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВидДоступаПользователи", ОписаниеТиповЗначенийДоступа)); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВидДоступаВнешниеПользователи", ОписаниеТиповЗначенийДоступа)); + + // Добавление таблицы ВсеВидыДоступа. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВсеВидыДоступа", Новый ОписаниеТипов("ТаблицаЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Ссылка", ОписаниеТиповЗначенийДоступа, "ВсеВидыДоступа")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Представление", Новый ОписаниеТипов("Строка"), "ВсеВидыДоступа")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Используется", Новый ОписаниеТипов("Булево"), "ВсеВидыДоступа")); + + // Добавление таблицы ПредставленияВсеРазрешены. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ПредставленияВсеРазрешены", Новый ОписаниеТипов("ТаблицаЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Имя", Новый ОписаниеТипов("Строка"), "ПредставленияВсеРазрешены")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "Представление", Новый ОписаниеТипов("Строка"), "ПредставленияВсеРазрешены")); + + // Добавление таблицы ВсеТипыВыбираемыхЗначений. + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВсеТипыВыбираемыхЗначений", Новый ОписаниеТипов("ТаблицаЗначений"))); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ВидДоступа", ОписаниеТиповЗначенийДоступа, "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ТипЗначений", ОписаниеТиповЗначенийДоступа, "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ПредставлениеТипа", Новый ОписаниеТипов("Строка"), "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИмяТаблицы", Новый ОписаниеТипов("Строка"), "ВсеТипыВыбираемыхЗначений")); + + ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы( + "ИерархияЭлементов", Новый ОписаниеТипов("Булево"), "ВсеТипыВыбираемыхЗначений")); + + Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты); + +КонецПроцедуры + +Процедура ЗаполнитьТаблицуВсеВидыДоступаВФорме(Форма) + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ВсеВидыДоступа = Форма.ВсеВидыДоступа; + ИспользуемыеВидыДоступа = ИспользуемыеВидыДоступа(); + + Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступа.Массив Цикл + Строка = ВсеВидыДоступа.Добавить(); + Строка.Ссылка = СвойстваВидаДоступа.Ссылка; + Строка.Используется = ИспользуемыеВидыДоступа.Получить(Строка.Ссылка) <> Неопределено; + // Обеспечение уникальности представлений. + Представление = ПредставлениеВидаДоступа(СвойстваВидаДоступа); + Отбор = Новый Структура("Представление", Представление); + Пока ВсеВидыДоступа.НайтиСтроки(Отбор).Количество() > 0 Цикл + Отбор.Представление = Отбор.Представление + " "; + КонецЦикла; + Строка.Представление = Отбор.Представление; + КонецЦикла; + +КонецПроцедуры + +Процедура ЗаполнитьТаблицуПредставленияВсеРазрешеныВФорме(Форма, ЭтоПрофиль) + + ПредставленияВсеРазрешены = Форма.ПредставленияВсеРазрешены; + + Если ЭтоПрофиль Тогда + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВначалеВсеЗапрещены"; + Строка.Представление = НСтр("ru = 'Все запрещены, исключения назначаются в группах доступа'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВначалеВсеРазрешены"; + Строка.Представление = НСтр("ru = 'Все разрешены, исключения назначаются в группах доступа'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеЗапрещены"; + Строка.Представление = НСтр("ru = 'Все запрещены, исключения назначаются в профиле'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеРазрешены"; + Строка.Представление = НСтр("ru = 'Все разрешены, исключения назначаются в профиле'"); + Иначе + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеЗапрещены"; + Строка.Представление = НСтр("ru = 'Все запрещены'"); + + Строка = ПредставленияВсеРазрешены.Добавить(); + Строка.Имя = "ВсеРазрешены"; + Строка.Представление = НСтр("ru = 'Все разрешены'"); + КонецЕсли; + + СписокВыбора = Форма.Элементы.ВидыДоступаВсеРазрешеныПредставление.СписокВыбора; // СписокЗначений + + Для каждого Строка Из ПредставленияВсеРазрешены Цикл + СписокВыбора.Добавить(Строка.Представление); + КонецЦикла; + +КонецПроцедуры + +Процедура ОформитьТаблицуВидыДоступаВФорме(Форма) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма); + + // Оформление отображения неиспользуемых видов доступа. + ЭлементУсловногоОформления = Форма.УсловноеОформление.Элементы.Добавить(); + + ЭлементЦветаОформления = ЭлементУсловногоОформления.Оформление.Элементы.Найти("TextColor"); + ЭлементЦветаОформления.Значение = WebЦвета.Серый; + ЭлементЦветаОформления.Использование = Истина; + + ГруппаЭлементовОтбораДанных = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных")); + ГруппаЭлементовОтбораДанных.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИ; + ГруппаЭлементовОтбораДанных.Использование = Истина; + + ЭлементОтбораДанных = ГруппаЭлементовОтбораДанных.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); + ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ВидыДоступа.ВидДоступа"); + ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.НеРавно; + ЭлементОтбораДанных.ПравоеЗначение = Неопределено; + ЭлементОтбораДанных.Использование = Истина; + + ЭлементОтбораДанных = ГруппаЭлементовОтбораДанных.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); + ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ВидыДоступа.Используется"); + ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; + ЭлементОтбораДанных.ПравоеЗначение = Ложь; + ЭлементОтбораДанных.Использование = Истина; + + ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить(); + ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("ВидыДоступа"); + ЭлементОформляемогоПоля.Использование = Истина; + +КонецПроцедуры + +Процедура ОформитьТаблицуЗначенияДоступаВФорме(Форма) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма); + ПустыеСсылкиЗначенийДоступа = ПустыеСсылкиЗначенийДоступа(); + + // Оформление отображения пустых ссылок значений доступа. + Для Каждого Строка Из ПустыеСсылкиЗначенийДоступа Цикл + ЭлементУсловногоОформления = Форма.УсловноеОформление.Элементы.Добавить(); + + ЭлементОформленияТекст = ЭлементУсловногоОформления.Оформление.Элементы.Найти("Text"); + ЭлементОформленияТекст.Значение = Строка.Представление; + ЭлементОформленияТекст.Использование = Истина; + + ЭлементОтбораДанных = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); + ЭлементОтбораДанных.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(Параметры.ПутьКТаблицам + "ЗначенияДоступа.ЗначениеДоступа"); + ЭлементОтбораДанных.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; + ЭлементОтбораДанных.ПравоеЗначение = Строка.ПустаяСсылка; + ЭлементОтбораДанных.Использование = Истина; + + ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить(); + ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("ЗначенияДоступаЗначениеДоступа"); + ЭлементОформляемогоПоля.Использование = Истина; + КонецЦикла; + +КонецПроцедуры + +Процедура УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект = Неопределено) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект); + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ПоТипамГруппИЗначений = СвойстваВидовДоступа.ПоТипамГруппИЗначений; + + Отбор = УправлениеДоступомСлужебныйКлиентСервер.ОтборВТаблицахФормыРедактированияРазрешенныхЗначений( + Форма, ""); + + Индекс = Параметры.ЗначенияДоступа.Количество()-1; + Пока Индекс >= 0 Цикл + ЗначениеДоступа = Параметры.ЗначенияДоступа[Индекс].ЗначениеДоступа; + + СвойстваВидаДоступа = ПоТипамГруппИЗначений.Получить(ТипЗнч(ЗначениеДоступа)); // См. СвойстваВидаДоступа + Если СвойстваВидаДоступа <> Неопределено Тогда + ЗаполнитьЗначенияСвойств(Отбор, Параметры.ЗначенияДоступа[Индекс]); + Отбор.Вставить("ВидДоступа", СвойстваВидаДоступа.Ссылка); + КонецЕсли; + + Если СвойстваВидаДоступа = Неопределено + ИЛИ Параметры.ЗначенияДоступа[Индекс].ВидДоступа <> Отбор.ВидДоступа + ИЛИ Параметры.ВидыДоступа.НайтиСтроки(Отбор).Количество() = 0 Тогда + + Параметры.ЗначенияДоступа.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + +КонецПроцедуры + +Процедура УдалитьНесуществующиеВидыИЗначенияДоступа(Форма, ТекущийОбъект = Неопределено) + + Параметры = ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект); + + Индекс = Параметры.ВидыДоступа.Количество()-1; + Пока Индекс >= 0 Цикл + ВидДоступа = Параметры.ВидыДоступа[Индекс].ВидДоступа; + Если СвойстваВидаДоступа(ВидДоступа) = Неопределено Тогда + Параметры.ВидыДоступа.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + + УдалитьЛишниеЗначенияДоступа(Форма, ТекущийОбъект); + +КонецПроцедуры + +Функция ПараметрыФормыРедактированияРазрешенныхЗначений(Форма, ТекущийОбъект = Неопределено) + + Возврат УправлениеДоступомСлужебныйКлиентСервер.ПараметрыФормыРедактированияРазрешенныхЗначений( + Форма, ТекущийОбъект); + +КонецФункции + +Функция РеквизитФормыСуществует(Форма, ИмяРеквизита) + + Структура = Новый Структура(ИмяРеквизита, Null); + + ЗаполнитьЗначенияСвойств(Структура, Форма); + + Возврат Структура[ИмяРеквизита] <> Null; + +КонецФункции + +Функция ПустыеСсылкиЗначенийДоступа() Экспорт + + Таблица = Новый ТаблицаЗначений; + Таблица.Колонки.Добавить("ПустаяСсылка", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + Таблица.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка", + ,,, Новый КвалификаторыСтроки(150, ДопустимаяДлина.Переменная))); + + Для Каждого Тип Из Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип.Типы() Цикл + Типы = Новый Массив; + Типы.Добавить(Тип); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + НоваяСтрока = Таблица.Добавить(); + НоваяСтрока.ПустаяСсылка = ОписаниеТипа.ПривестиЗначение(Неопределено); + НоваяСтрока.Представление = "<" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Пустая ссылка %1'"), Строка(Тип)) + ">"; + КонецЦикла; + + Возврат Таблица; + +КонецФункции + +// Для процедуры УстановкаПараметровСеанса. + +Функция ВсеКомбинацииВидовДоступа(НеупорядоченныйМассивИмен) + + // Ограничение на максимальную длину комбинации, чтобы не допустить + // перегрузку параметров сеанса и препроцессора шаблонов ОДД. + МаксимальнаяДлинаКомбинации = 4; + + Список = Новый СписокЗначений; + Если ТипЗнч(НеупорядоченныйМассивИмен) = Тип("ФиксированныйМассив") Тогда + Список.ЗагрузитьЗначения(Новый Массив(НеупорядоченныйМассивИмен)); + Иначе + Список.ЗагрузитьЗначения(НеупорядоченныйМассивИмен); + КонецЕсли; + Список.СортироватьПоЗначению(); + МассивИмен = Список.ВыгрузитьЗначения(); + + ИтогСтроки = Новый Массив; + ИтогСтрока = Новый Массив; + + // Полный список поддерживается всегда. + Для каждого Имя Из МассивИмен Цикл + ИтогСтрока.Добавить(Имя); + КонецЦикла; + + ИтогСтроки.Добавить(ИтогСтрока); + + Если МассивИмен.Количество() < 3 Тогда + Возврат ГруппыСтрокВСтроку(ИтогСтроки); + КонецЕсли; + + ПервоеИмя = МассивИмен[0]; + МассивИмен.Удалить(0); + + ПоследнееИмя = МассивИмен[МассивИмен.Количество()-1]; + МассивИмен.Удалить(МассивИмен.Количество()-1); + + КоличествоИменВКомбинации = МассивИмен.Количество(); + + Если КоличествоИменВКомбинации > 1 Тогда + + Если (КоличествоИменВКомбинации-1) <= МаксимальнаяДлинаКомбинации Тогда + ДлинаКомбинации = КоличествоИменВКомбинации-1; + Иначе + ДлинаКомбинации = МаксимальнаяДлинаКомбинации; + КонецЕсли; + + ПозицииИменВКомбинации = Новый Массив; + Для Счетчик = 1 По ДлинаКомбинации Цикл + ПозицииИменВКомбинации.Добавить(Счетчик); + КонецЦикла; + + Пока ДлинаКомбинации > 0 Цикл + Пока Истина Цикл + // Добавление комбинации из текущих позиций. + ИтогСтрока = Новый Массив; + ИтогСтрока.Добавить(ПервоеИмя); + Для Индекс = 0 По ДлинаКомбинации-1 Цикл + ИтогСтрока.Добавить(МассивИмен[ПозицииИменВКомбинации[Индекс]-1]); + КонецЦикла; + ИтогСтрока.Добавить(ПоследнееИмя); + ИтогСтроки.Добавить(ИтогСтрока); + // Продвижение позиции в комбинации. + Индекс = ДлинаКомбинации-1; + Пока Индекс >= 0 Цикл + Если ПозицииИменВКомбинации[Индекс] < КоличествоИменВКомбинации - (ДлинаКомбинации - (Индекс+1)) Тогда + ПозицииИменВКомбинации[Индекс] = ПозицииИменВКомбинации[Индекс] + 1; + // Заполнение старших позиций начальными значениями. + Для ИндексСтаршейПозиции = Индекс+1 По ДлинаКомбинации-1 Цикл + ПозицииИменВКомбинации[ИндексСтаршейПозиции] = + ПозицииИменВКомбинации[Индекс] + ИндексСтаршейПозиции - Индекс; + КонецЦикла; + Прервать; + Иначе + Индекс = Индекс - 1; + КонецЕсли; + КонецЦикла; + Если Индекс < 0 Тогда + Прервать; + КонецЕсли; + КонецЦикла; + ДлинаКомбинации = ДлинаКомбинации - 1; + Для Индекс = 0 По ДлинаКомбинации - 1 Цикл + ПозицииИменВКомбинации[Индекс] = Индекс + 1; + КонецЦикла; + КонецЦикла; + КонецЕсли; + + ИтогСтрока = Новый Массив; + ИтогСтрока.Добавить(ПервоеИмя); + ИтогСтрока.Добавить(ПоследнееИмя); + ИтогСтроки.Добавить(ИтогСтрока); + + Возврат ГруппыСтрокВСтроку(ИтогСтроки); + +КонецФункции + +Функция ГруппыСтрокВСтроку(ГруппыСтрок) + + ИтогСтроки = Новый Массив; + + Для Каждого ИтогСтрока Из ГруппыСтрок Цикл + ИтогСтроки.Добавить(СтрСоединить(ИтогСтрока, ",")); + КонецЦикла; + + Строки = СтрСоединить( + ИтогСтроки, + ", + |,"); + + Шаблон = + "%2%1%2 + |"; + + Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, Строки, ","); + +КонецФункции + +// Для процедур ОбновитьНаборыЗначенийДоступа, ПриИзмененииНаборовЗначенийДоступа. + +// Проверяет, что наборы в табличной части отличаются от новых наборов. +Функция НаборыЗначенийДоступаТабличнойЧастиИзменены(СсылкаНаОбъект, НовыеНаборы) + + СтарыеНаборы = ОбщегоНазначения.ЗначениеРеквизитаОбъекта( + СсылкаНаОбъект, "НаборыЗначенийДоступа").Выгрузить(); + + Если СтарыеНаборы.Количество() <> НовыеНаборы.Количество() Тогда + Возврат Истина; + КонецЕсли; + + СтарыеНаборы.Колонки.Добавить("ВидДоступа", Новый ОписаниеТипов("Строка")); + УправлениеДоступом.ДобавитьНаборыЗначенийДоступа( + СтарыеНаборы, УправлениеДоступом.ТаблицаНаборыЗначенийДоступа(), Ложь, Истина); + + ПоляПоиска = "НомерНабора, ЗначениеДоступа, Уточнение, Чтение, Изменение"; + + НовыеНаборы.Индексы.Добавить(ПоляПоиска); + Отбор = Новый Структура(ПоляПоиска); + + Для каждого Строка Из СтарыеНаборы Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Если НовыеНаборы.НайтиСтроки(Отбор).Количество() <> 1 Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции РазрешенныеЗначенияДляДинамическогоСписка. +Процедура ДобавитьЗапросВПакет(ТекстПакета, ТекстЗапроса) + + Разделитель = + " + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |"; + + ТекстПакета = ТекстПакета + Разделитель + ТекстЗапроса; + +КонецПроцедуры + +// Для функции РазрешенныеЗначенияДляДинамическогоСписка. +Процедура ОбъединитьЗапросСЗапросом(ТекстЗапроса, ДобавляемыйТекстЗапроса) + + Объединитель = + " + | + |ОБЪЕДИНИТЬ ВСЕ + | + |"; // @query-part-1 + + ТекстЗапроса = ТекстЗапроса + Объединитель + ДобавляемыйТекстЗапроса; + +КонецПроцедуры + +// Обновление свойств видов доступа. + +// Для функций ПроверенныеСвойстваВидовДоступаСеанса, ПредставлениеВидовДоступа. +// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Имя - Строка +// * Представление - Строка +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// * ДополнительныеТипы - см. НоваяТаблицаДополнительныеТипыВидаДоступа +// +Функция ЗаполненныеВидыДоступаСеанса() + + // 1. Заполнение данных, указанных при внедрении. + + ВидыДоступа = Новый ТаблицаЗначений; + ВидыДоступа.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка")); + ВидыДоступа.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка")); + ВидыДоступа.Колонки.Добавить("ТипЗначений", Новый ОписаниеТипов("Тип")); + ВидыДоступа.Колонки.Добавить("ТипГруппЗначений", Новый ОписаниеТипов("Тип")); + ВидыДоступа.Колонки.Добавить("НесколькоГруппЗначений", Новый ОписаниеТипов("Булево")); + ВидыДоступа.Колонки.Добавить("ДополнительныеТипы", Новый ОписаниеТипов("ТаблицаЗначений")); + + ИнтеграцияПодсистемБСП.ПриЗаполненииВидовДоступа(ВидыДоступа); + УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа(ВидыДоступа); + + Возврат ВидыДоступа; + +КонецФункции + +// Для функции ЗаполненныеВидыДоступаСеанса и +// процедуры ДобавитьДополнительныеТипыВидаДоступа общего модуля УправлениеДоступом. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// +Функция НоваяТаблицаДополнительныеТипыВидаДоступа() Экспорт + + ДополнительныеТипы = Новый ТаблицаЗначений; + ДополнительныеТипы.Колонки.Добавить("ТипЗначений", Новый ОписаниеТипов("Тип")); + ДополнительныеТипы.Колонки.Добавить("ТипГруппЗначений", Новый ОписаниеТипов("Тип")); + ДополнительныеТипы.Колонки.Добавить("НесколькоГруппЗначений", Новый ОписаниеТипов("Булево")); + + Возврат ДополнительныеТипы; + +КонецФункции + +// Для процедур ПриЗаполненииВсехПараметровРаботыРасширений и +// ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации. +// +Процедура ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений() + + Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); + НовоеЗначение = Кэш.ХешСуммы; + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ТипыГруппИЗначенийДоступа"; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + + Если СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа + = НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа Тогда + Возврат; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + Если СтароеЗначение.ХешСуммаТиповГруппИЗначенийДоступа + <> НовоеЗначение.ХешСуммаТиповГруппИЗначенийДоступа Тогда + Если УжеИзменен Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + РегистрыСведений.ГруппыЗначенийДоступа.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + РегистрыСведений.НаборыЗначенийДоступа.ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации(); + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. +// Смотри также заполнение в функции ПроверенныеСвойстваВидовДоступаСеанса. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Массив - ФиксированныйМассив из см. СвойстваВидаДоступа +// * ПоИменам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - см. СвойстваВидаДоступа +// * ПоСсылкам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамЗначений - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамГруппИЗначений - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамЗначенийСИерархией - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ЗначенияДоступаСГруппами - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. ЗначенияДоступаСГруппами +// * БезГруппДляЗначенияДоступа - ФиксированныйМассив из Строка +// * СОднойГруппойДляЗначенияДоступа - ФиксированныйМассив из Строка +// * ТипыЗначенийДоступаСГруппами - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - СправочникСсылка +// +Функция СвойстваВидовДоступа() Экспорт + + Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса(); + + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + Если Кэш.Проверка.Дата + 3 > ТекущаяДатаСеанса Тогда + Возврат Кэш.СвойстваСеанса; + КонецЕсли; + + НовоеЗначение = Кэш.ХешСуммы; + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.СвойстваВидовДоступа"; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + + Если СтароеЗначение.ХешСумма <> НовоеЗначение.ХешСумма Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + УжеИзменен = Ложь; + СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен); + СтароеЗначение = НовыеХешСуммыСвойствВидовДоступа(СтароеЗначение); + Если СтароеЗначение.ХешСумма <> НовоеЗначение.ХешСумма Тогда + Если УжеИзменен Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Кэш.Проверка.Дата = ТекущаяДатаСеанса; + + Возврат Кэш.СвойстваСеанса; + +КонецФункции + +// Для процедуры УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса. +// Возвращает свойства видов доступа, заполняемых при внедрении в процедуре ПриЗаполненииВидовДоступа +// общего модуля УправлениеДоступомПереопределяемый и одноименных обработчиках этого события. +// +// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВидовДоступа. +// +// Параметры: +// ХешСуммы - см. НовыеХешСуммыСвойствВидовДоступа +// +// Возвращаемое значение: +// см. СвойстваВидовДоступа +// +Функция ПроверенныеСвойстваВидовДоступаСеанса(ХешСуммы) Экспорт + + ВидыДоступа = ЗаполненныеВидыДоступаСеанса(); + + // 1. Проверки: + // - тип значений доступа не указан для 2-х видов доступа + // - тип значений доступа Пользователи, ГруппыПользователей используется только для вида доступа Пользователи + // - тип значений доступа ВнешниеПользователи, ГруппыВнешнихПользователей используется только для вида доступа + // ВнешниеПользователи + // - имена видов доступа Объект, Условие, НастройкиПрав, ПравоЧтения, ПравоИзменения не указаны + // - тип групп значений не совпадает с типом значений. + // + // 2. Подготовка различных коллекций свойств видов доступа, используемых при работе программы. + + МассивСвойств = Новый Массив; // Массив из см. СвойстваВидаДоступа + ПоСсылкам = Новый Соответствие; + ПоИменам = Новый Соответствие; + ПоТипамЗначений = Новый Соответствие; + ПоТипамГруппИЗначений = Новый Соответствие; + + ЗначенияДоступаСГруппами = ЗначенияДоступаСГруппами(); + + Параметры = Новый Структура; + Параметры.Вставить("ОпределяемыеТипыЗначенийДоступа", + УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ЗначениеДоступа")); + + ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в процедуре %1 общего модуля %2.'"), + "ПриЗаполненииВидовДоступа", "УправлениеДоступомПереопределяемый") + + Символы.ПС + + Символы.ПС; + + Параметры.Вставить("ЗаголовокОшибки", ЗаголовокОшибки); + + ВсеИменаВидовДоступа = Новый Соответствие; + ВсеИменаВидовДоступа.Вставить(ВРег("Объект"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("Условие"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("НастройкиПрав"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("ПравоЧтения"), Истина); + ВсеИменаВидовДоступа.Вставить(ВРег("ПравоИзменения"), Истина); + + ВсеТипыЗначений = Новый Соответствие; + ВсеТипыГруппЗначений = Новый Соответствие; + ВсеСвойства = Новый Соответствие; + + ОписаниеВерсии = Новый Структура("СвойстваВерсии", Новый Массив); + ДобавитьЭлементВерсии(ОписаниеВерсии, "Версия", "1"); + + Для Каждого ВидДоступа Из ВидыДоступа Цикл + Если ВсеИменаВидовДоступа[ВРег(ВидДоступа.Имя)] <> Неопределено Тогда + ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Имя вида доступа ""%1"" уже определено.'"), + ВидДоступа.Имя); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + // Проверка повторения типов значений и групп. + ПроверитьТип(ВидДоступа, ВидДоступа.ТипЗначений, ВсеТипыЗначений, Параметры); + ПроверитьТип(ВидДоступа, ВидДоступа.ТипГруппЗначений, ВсеТипыГруппЗначений, Параметры, Истина); + // Проверка пересечения типов значений и групп. + ПроверитьТип(ВидДоступа, ВидДоступа.ТипЗначений, ВсеТипыГруппЗначений, Параметры, , Истина); + ПроверитьТип(ВидДоступа, ВидДоступа.ТипГруппЗначений, ВсеТипыЗначений, Параметры, Истина, Истина); + + ТаблицаДополнительныеТипы = ВидДоступа.ДополнительныеТипы; // См. НоваяТаблицаДополнительныеТипыВидаДоступа + + Для Каждого Строка Из ТаблицаДополнительныеТипы Цикл + // Проверка повторения типов значений и групп. + ПроверитьТип(ВидДоступа, Строка.ТипЗначений, ВсеТипыЗначений, Параметры); + ПроверитьТип(ВидДоступа, Строка.ТипГруппЗначений, ВсеТипыГруппЗначений, Параметры, Истина); + // Проверка пересечения типов значений и групп. + ПроверитьТип(ВидДоступа, Строка.ТипЗначений, ВсеТипыГруппЗначений, Параметры, , Истина); + ПроверитьТип(ВидДоступа, Строка.ТипГруппЗначений, ВсеТипыЗначений, Параметры, Истина, Истина); + КонецЦикла; + + ПустаяСсылкаТипаЗначений = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени( + Метаданные.НайтиПоТипу(ВидДоступа.ТипЗначений).ПолноеИмя()).ПустаяСсылка(); + + Свойства = НовыеСвойстваВидаДоступа(ВидДоступа, ПустаяСсылкаТипаЗначений); + ОписаниеВерсии.СвойстваВерсии.Добавить(""); + ДобавитьСвойстваВерсии(ОписаниеВерсии, Свойства, + "Имя, ТипЗначений, ТипГруппЗначений, НесколькоГруппЗначений"); + + ТипыВыбираемыхЗначений = Новый Массив; + ЗаполнитьЗначенияДоступаСГруппами(Свойства, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений); + ДополнительныеТипы = Новый Массив; + Для Каждого Строка Из ТаблицаДополнительныеТипы Цикл + ДополнительныйТип = ДополнительныйТипВидаДоступа(Строка); + ДополнительныеТипы.Добавить(ДополнительныйТип); + ДобавитьСвойстваВерсии(ОписаниеВерсии, Свойства, + "ТипЗначений, ТипГруппЗначений, НесколькоГруппЗначений"); + ЗаполнитьЗначенияДоступаСГруппами(Строка, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений); + КонецЦикла; + + Свойства.ТипыВыбираемыхЗначений = Новый ФиксированныйМассив(ТипыВыбираемыхЗначений); + Свойства.ДополнительныеТипы = Новый ФиксированныйМассив(ДополнительныеТипы); + ВсеСвойства.Вставить(Свойства, Новый ФиксированнаяСтруктура(Свойства)); + Свойства = ВсеСвойства.Получить(Свойства); + + МассивСвойств.Добавить(Свойства); + ПоИменам.Вставить(Свойства.Имя, Свойства); + ПоСсылкам.Вставить(ПустаяСсылкаТипаЗначений, Свойства); + ПоТипамЗначений.Вставить(Свойства.ТипЗначений, Свойства); + ПоТипамГруппИЗначений.Вставить(Свойства.ТипЗначений, Свойства); + Если Свойства.ТипГруппЗначений <> Тип("Неопределено") Тогда + ПоТипамГруппИЗначений.Вставить(Свойства.ТипГруппЗначений, Свойства); + КонецЕсли; + + Для Каждого Строка Из ВидДоступа.ДополнительныеТипы Цикл + ПоТипамЗначений.Вставить(Строка.ТипЗначений, Свойства); + ПоТипамГруппИЗначений.Вставить(Строка.ТипЗначений, Свойства); + Если Строка.ТипГруппЗначений <> Тип("Неопределено") Тогда + ПоТипамГруппИЗначений.Вставить(Строка.ТипГруппЗначений, Свойства); + КонецЕсли; + КонецЦикла; + + КонецЦикла; + + БезГруппДляЗначенияДоступа = Новый Массив; + СОднойГруппойДляЗначенияДоступа = Новый Массив; + ТипыЗначенийДоступаСГруппами = Новый Соответствие; + + ВидыДоступаСГруппами = Новый Соответствие; + + Для Каждого КлючИЗначение Из ЗначенияДоступаСГруппами.ПоТипамСсылок Цикл + ВидДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа + ИмяВидаДоступа = ВидДоступа.Имя; + ВидыДоступаСГруппами.Вставить(ИмяВидаДоступа, Истина); + + ПустаяСсылка = ПустаяСсылкаОбъектаМетаданных(КлючИЗначение.Ключ); + ТипыЗначенийДоступаСГруппами.Вставить(ТипЗнч(ПустаяСсылка), ПустаяСсылка); + + Если НЕ КлючИЗначение.Значение.НесколькоГруппЗначений + И СОднойГруппойДляЗначенияДоступа.Найти(ИмяВидаДоступа) = Неопределено Тогда + + СОднойГруппойДляЗначенияДоступа.Добавить(ИмяВидаДоступа); + КонецЕсли; + КонецЦикла; + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.Пользователи"), + Справочники.Пользователи.ПустаяСсылка()); + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ГруппыПользователей"), + Справочники.ГруппыПользователей.ПустаяСсылка()); + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ВнешниеПользователи"), + Справочники.ВнешниеПользователи.ПустаяСсылка()); + + ТипыЗначенийДоступаСГруппами.Вставить(Тип("СправочникСсылка.ГруппыВнешнихПользователей"), + Справочники.ГруппыВнешнихПользователей.ПустаяСсылка()); + + ПоТипамЗначенийСИерархией = Новый Соответствие; + Для Каждого КлючИЗначение Из ПоТипамЗначений Цикл + ТипСсылка = КлючИЗначение.Ключ; + Если ТипыЗначенийДоступаСГруппами[ТипСсылка] <> Неопределено Тогда + Продолжить; + КонецЕсли; + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипСсылка); + Если ОбъектМетаданных <> Неопределено + И (ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) + Или ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)) + И ОбъектМетаданных.Иерархический Тогда + + ТипОбъект = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных(ОбъектМетаданных); + ПоТипамЗначенийСИерархией.Вставить(ТипСсылка, КлючИЗначение.Значение); + ПоТипамЗначенийСИерархией.Вставить(ТипОбъект, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + + Для Каждого СвойстваВидаДоступа Из МассивСвойств Цикл + Если ВидыДоступаСГруппами.Получить(СвойстваВидаДоступа.Имя) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Если СвойстваВидаДоступа.Имя = "Пользователи" + ИЛИ СвойстваВидаДоступа.Имя = "ВнешниеПользователи" Тогда + Продолжить; + КонецЕсли; + БезГруппДляЗначенияДоступа.Добавить(СвойстваВидаДоступа.Имя); + КонецЦикла; + + ПроверитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ЗначенияДоступаСГруппами); + + // Окончательная фиксация данных. + + ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления = + Новый ФиксированныйМассив(ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления); + + ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления = + Новый ФиксированноеСоответствие(ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления); + + Для Каждого ОписаниеСвойства Из ЗначенияДоступаСГруппами Цикл + ТекущееСоответствие = ОписаниеСвойства.Значение; + Если ТипЗнч(ТекущееСоответствие) <> Тип("Соответствие") Тогда + Продолжить; + КонецЕсли; + Для Каждого КлючИЗначение Из ТекущееСоответствие Цикл + ТекущееСоответствие.Вставить(КлючИЗначение.Ключ, + ВсеСвойства.Получить(КлючИЗначение.Значение)); + КонецЦикла; + ЗначенияДоступаСГруппами[ОписаниеСвойства.Ключ] = + Новый ФиксированноеСоответствие(ТекущееСоответствие); + КонецЦикла; + + СвойстваВидовДоступа = Новый Структура; + СвойстваВидовДоступа.Вставить("Массив", + Новый ФиксированныйМассив(МассивСвойств)); + + СвойстваВидовДоступа.Вставить("ПоИменам", + Новый ФиксированноеСоответствие(ПоИменам)); + + СвойстваВидовДоступа.Вставить("ПоСсылкам", + Новый ФиксированноеСоответствие(ПоСсылкам)); + + СвойстваВидовДоступа.Вставить("ПоТипамЗначений", + Новый ФиксированноеСоответствие(ПоТипамЗначений)); + + СвойстваВидовДоступа.Вставить("ПоТипамЗначенийСИерархией", + Новый ФиксированноеСоответствие(ПоТипамЗначенийСИерархией)); + + СвойстваВидовДоступа.Вставить("ПоТипамГруппИЗначений", + Новый ФиксированноеСоответствие(ПоТипамГруппИЗначений)); + + СвойстваВидовДоступа.Вставить("ЗначенияДоступаСГруппами", + Новый ФиксированнаяСтруктура(ЗначенияДоступаСГруппами)); + + СвойстваВидовДоступа.Вставить("БезГруппДляЗначенияДоступа", + Новый ФиксированныйМассив(БезГруппДляЗначенияДоступа)); + + СвойстваВидовДоступа.Вставить("СОднойГруппойДляЗначенияДоступа", + Новый ФиксированныйМассив(СОднойГруппойДляЗначенияДоступа)); + + СвойстваВидовДоступа.Вставить("ТипыЗначенийДоступаСГруппами", + Новый ФиксированноеСоответствие(ТипыЗначенийДоступаСГруппами)); + + Результат = Новый ФиксированнаяСтруктура(СвойстваВидовДоступа); + + ХешСуммы.ХешСуммаТиповГруппИЗначенийДоступа = + ХешСуммаТиповГруппИЗначенийДоступа(СвойстваВидовДоступа); + + СтрокаВерсии = СтрСоединить(ОписаниеВерсии.СвойстваВерсии, Символы.ПС); + ХешСуммы.ХешСумма = ХешСуммаДанных(СтрокаВерсии); + + Возврат Результат; + +КонецФункции + +// Для функции СвойстваВидовДоступа. +// +// Возвращаемое значение: +// см. СвойстваВидаДоступа +// +Функция НовыеСвойстваВидаДоступа(ВидДоступа, ПустаяСсылкаТипаЗначений) + + Свойства = Новый Структура; + Свойства.Вставить("Имя", ВидДоступа.Имя); + Свойства.Вставить("Ссылка", ПустаяСсылкаТипаЗначений); + Свойства.Вставить("ТипЗначений", ВидДоступа.ТипЗначений); + Свойства.Вставить("ТипГруппЗначений", ВидДоступа.ТипГруппЗначений); + Свойства.Вставить("НесколькоГруппЗначений", ВидДоступа.НесколькоГруппЗначений); + Свойства.Вставить("ДополнительныеТипы"); + Свойства.Вставить("ТипыВыбираемыхЗначений"); + + Возврат Свойства; + +КонецФункции + +// Для функции СвойстваВидовДоступа. +// +// Возвращаемое значение: +// Структура: +// * ПоТипам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ПоТипамСсылок - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// * ИменаТаблицДляОбновления - ФиксированныйМассив из Строка +// * ТипыГруппЗначенийДляОбновления - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - СправочникСсылка +// * ПоТипамСсылокДляОбновления - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - см. СвойстваВидаДоступа +// +Функция ЗначенияДоступаСГруппами() + + ЗначенияДоступаСГруппами = Новый Структура; + ЗначенияДоступаСГруппами.Вставить("ПоТипам", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ПоТипамСсылок", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ИменаТаблицДляОбновления", Новый Массив); + ЗначенияДоступаСГруппами.Вставить("ТипыГруппЗначенийДляОбновления", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ПоТипамДляОбновления", Новый Соответствие); + ЗначенияДоступаСГруппами.Вставить("ПоТипамСсылокДляОбновления", Новый Соответствие); + + Возврат ЗначенияДоступаСГруппами; + +КонецФункции + +// Для функции СвойстваВидовДоступа. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ТипЗначений - Тип +// * ТипГруппЗначений - Тип +// * НесколькоГруппЗначений - Булево +// +Функция ДополнительныйТипВидаДоступа(Строка) + + Элемент = Новый Структура; + Элемент.Вставить("ТипЗначений", Строка.ТипЗначений); + Элемент.Вставить("ТипГруппЗначений", Строка.ТипГруппЗначений); + Элемент.Вставить("НесколькоГруппЗначений", Строка.НесколькоГруппЗначений); + + Возврат Новый ФиксированнаяСтруктура(Элемент); + +КонецФункции + +// Для функции СвойстваВидовДоступа. +Процедура ЗаполнитьЗначенияДоступаСГруппами(Строка, ЗначенияДоступаСГруппами, Свойства, ТипыВыбираемыхЗначений) + + Если Свойства.Имя = "Пользователи" Тогда + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.Пользователи")); + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ГруппыПользователей")); + Возврат; + КонецЕсли; + + Если Свойства.Имя = "ВнешниеПользователи" Тогда + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ВнешниеПользователи")); + ДобавитьВМассив(ТипыВыбираемыхЗначений, Тип("СправочникСсылка.ГруппыВнешнихПользователей")); + Возврат; + КонецЕсли; + + ТипСсылки = Строка.ТипЗначений; + + МетаданныеТипаЗначений = Метаданные.НайтиПоТипу(Строка.ТипЗначений); + Если ОбщегоНазначения.ЭтоПеречисление(МетаданныеТипаЗначений) Тогда + ТипОбъекта = ТипСсылки; + Иначе + ТипОбъекта = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных( + МетаданныеТипаЗначений); + КонецЕсли; + + Если Строка.ТипГруппЗначений = Тип("Неопределено") Тогда + ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, + ТипОбъекта, МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, Неопределено); + ДобавитьВМассив(ТипыВыбираемыхЗначений, Строка.ТипЗначений); + Возврат; + КонецЕсли; + + Если Строка.ТипГруппЗначений <> Тип("Неопределено") Тогда + ДобавитьВМассив(ТипыВыбираемыхЗначений, Строка.ТипГруппЗначений); + КонецЕсли; + + ЗначенияДоступаСГруппами.ПоТипам.Вставить(ТипСсылки, Свойства); + ЗначенияДоступаСГруппами.ПоТипам.Вставить(ТипОбъекта, Свойства); + ЗначенияДоступаСГруппами.ПоТипамСсылок.Вставить(ТипСсылки, Свойства); + + МетаданныеТипаГруппЗначений = Метаданные.НайтиПоТипу(Строка.ТипГруппЗначений); + + ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, + ТипОбъекта, МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, МетаданныеТипаГруппЗначений); + +КонецПроцедуры + +// Для функции СвойстваВидовДоступа и процедуры ЗаполнитьЗначенияДоступаСГруппами. +Процедура ДобавитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ТипСсылки, ТипОбъекта, + МетаданныеТипаЗначений, ЗначенияДоступаСГруппами, Свойства, МетаданныеТипаГруппЗначений) + + ПустаяСсылкаТипаЗначений = ПредопределенноеЗначение(МетаданныеТипаЗначений.ПолноеИмя() + ".ПустаяСсылка"); + + Если МетаданныеТипаГруппЗначений = Неопределено Тогда + ПустаяСсылкаТипаГруппЗначений = ПустаяСсылкаТипаЗначений; + Иначе + ПустаяСсылкаТипаГруппЗначений = ПустаяСсылкаОбъектаМетаданных(МетаданныеТипаГруппЗначений); + КонецЕсли; + + ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления.Добавить(МетаданныеТипаЗначений.ПолноеИмя()); + + ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления.Вставить(ТипСсылки, + ПустаяСсылкаТипаГруппЗначений); + + ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления.Вставить(ПустаяСсылкаТипаЗначений, + ПустаяСсылкаТипаГруппЗначений); + + ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Вставить(ТипСсылки, Свойства); + ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Вставить(ТипСсылки, Свойства); + ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Вставить(ТипОбъекта, Свойства); + +КонецПроцедуры + +// Для функции СвойстваВидовДоступа. +Процедура ПроверитьТипыПодпискиОбновитьГруппыЗначенийДоступа(ЗначенияДоступаСГруппами) + + ТекущиеТипыПодписки = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы( + "ОпределяемыйТип.ЗначениеДоступаОбъект"); + + ТребуемыеТипыПодписки = Новый Соответствие; + Для Каждого КлючИЗначение Из ЗначенияДоступаСГруппами.ПоТипамДляОбновления Цикл + Если ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ТребуемыеТипыПодписки.Вставить(КлючИЗначение.Ключ, Истина); + КонецЦикла; + + НедостающиеТипы = Новый Массив; + + Для Каждого КлючИЗначение Из ТребуемыеТипыПодписки Цикл + Если ТекущиеТипыПодписки.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + НедостающиеТипы.Добавить(КлючИЗначение.Ключ); + КонецЕсли; + КонецЦикла; + + Если НедостающиеТипы.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'По данным, полученным из процедуры %1 + |общего модуля %2, + |в определяемом типе %3 не указаны требуемые типы: + |- %4'"), + "ПриЗаполненииВидовДоступа", + "УправлениеДоступомПереопределяемый", + "ЗначениеДоступаОбъект", + СтрСоединить(НедостающиеТипы, "," + Символы.ПС + "- ")); + + ВызватьИсключение ТекстОшибки; + +КонецПроцедуры + +// Для функции СвойстваВидовДоступа. +Процедура ПроверитьТип(ВидДоступа, Тип, ВсеТипы, Параметры, ПроверкаТиповГрупп = Ложь, ПроверкаПересечения = Ложь) + + Если Тип = Тип("Неопределено") Тогда + Если ПроверкаТиповГрупп Тогда + Возврат; + КонецЕсли; + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Для вида доступа ""%1"" не указан тип значений доступа.'"), + ВидДоступа.Имя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + // Проверка, что указан тип ссылки. + Если НЕ ОбщегоНазначения.ЭтоСсылка(Тип) Тогда + Если ПроверкаТиповГрупп Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип групп значений, для вида доступа ""%2"". + |Однако это не тип ссылки.'"); + Иначе + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип значений, для вида доступа ""%2"". + |Однако это не тип ссылки.'"); + КонецЕсли; + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ОписаниеОшибки, Тип, ВидДоступа.Имя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + // Проверка повторения и пересечения типов значений и групп значений. + ДляТогоЖеВидаДоступаОшибкиНет = Ложь; + + Если ПроверкаТиповГрупп Тогда + Если ПроверкаПересечения Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип значений, для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать, как тип групп значений.'"); + Иначе + ДляТогоЖеВидаДоступаОшибкиНет = Истина; + ОписаниеОшибки = + НСтр("ru = 'Тип групп значений ""%1"" уже указан для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать.'"); + КонецЕсли; + Иначе + Если ПроверкаПересечения Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип ""%1"" указан, как тип групп значений, для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать, как тип значений.'"); + Иначе + ОписаниеОшибки = + НСтр("ru = 'Тип значений ""%1"" уже указан для вида доступа ""%2"". + |Для вида доступа ""%3"" его нельзя указать.'"); + КонецЕсли; + КонецЕсли; + + Если ВсеТипы.Получить(Тип) <> Неопределено Тогда + Если НЕ (ДляТогоЖеВидаДоступаОшибкиНет И ВидДоступа.Имя = ВсеТипы.Получить(Тип)) Тогда + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ОписаниеОшибки, Тип, ВсеТипы.Получить(Тип), ВидДоступа.Имя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ИначеЕсли НЕ ПроверкаПересечения Тогда + ВсеТипы.Вставить(Тип, ВидДоступа.Имя); + КонецЕсли; + + // Проверка состава определяемых типов. + ОписаниеОшибки = ""; + Если Параметры.ОпределяемыеТипыЗначенийДоступа.Получить(Тип) = Неопределено Тогда + Если ПроверкаТиповГрупп Тогда + ОписаниеОшибки = + НСтр("ru = 'Тип групп значений доступа ""%1"" вида доступа ""%2"" + |не указан в определяемом типе %3.'"); + Иначе + ОписаниеОшибки = + НСтр("ru = 'Тип значений доступа ""%1"" вида доступа ""%2"" + |не указан в определяемом типе %3.'"); + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда + ТекстОшибки = Параметры.ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ОписаниеОшибки, Тип, ВидДоступа.Имя, "ЗначениеДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Тип +// * Значение - Строка +// +Функция ПредставлениеВидовДоступа() Экспорт + + ВидыДоступа = ЗаполненныеВидыДоступаСеанса(); + + ПредставлениеВидовДоступа = Новый Соответствие; + + Для Каждого ВидДоступа Из ВидыДоступа Цикл + ПредставлениеВидовДоступа.Вставить(ВидДоступа.ТипЗначений, ВидДоступа.Представление); + КонецЦикла; + + Возврат Новый ФиксированноеСоответствие(ПредставлениеВидовДоступа); + +КонецФункции + +Функция ПредставлениеВидаДоступа(СвойстваВидаДоступа) Экспорт + + ПредставлениеВидовДоступа = УправлениеДоступомСлужебныйПовтИсп.ПредставлениеВидовДоступа(); + + Представление = ПредставлениеВидовДоступа.Получить(СвойстваВидаДоступа.ТипЗначений); + + Если Не ЗначениеЗаполнено(Представление) Тогда + Представление = СвойстваВидаДоступа.Имя; + КонецЕсли; + + Возврат Представление; + +КонецФункции + +// Для процедуры ЗаполнитьЗначенияДоступаСГруппами. +Процедура ДобавитьВМассив(Массив, Значение) + + Если Массив.Найти(Значение) = Неопределено Тогда + Массив.Добавить(Значение); + КонецЕсли; + +КонецПроцедуры + +// Для функций УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса, +// СвойстваВидовДоступа и процедур ОбновитьОписаниеСвойствВидовДоступа, +// ОбновитьГруппыИНаборыЗначенийДоступаПриИзмененииТиповГруппИЗначений. +// +// Параметры: +// Значение - Неопределено +// - ФиксированнаяСтруктура +// +// Возвращаемое значение: +// Структура: +// * ХешСумма - Строка +// * ХешСуммаТиповГруппИЗначенийДоступа - Строка +// +Функция НовыеХешСуммыСвойствВидовДоступа(Значение = Неопределено) Экспорт + + Результат = Новый Структура; + Результат.Вставить("ХешСумма", ""); + Результат.Вставить("ХешСуммаТиповГруппИЗначенийДоступа", ""); + + Если ТипЗнч(Значение) = Тип("ФиксированнаяСтруктура") Тогда + ЗаполнитьЗначенияСвойств(Результат, Значение); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Для процедуры ПроверенныеСвойстваВидовДоступаСеанса. +Функция ХешСуммаТиповГруппИЗначенийДоступа(СвойстваВидовДоступа) + + Данные = Новый Массив; + Данные.Добавить(ОписаниеТиповИзКлючейСоответствия(СвойстваВидовДоступа.ПоТипамЗначений)); + Данные.Добавить(ОписаниеТиповИзКлючейСоответствия(СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами)); + + ИменаТаблицДляОбновления = Новый СписокЗначений; + ИменаТаблицДляОбновления.ЗагрузитьЗначения(Новый Массив( + СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления)); + ИменаТаблицДляОбновления.СортироватьПоЗначению(); + + Данные.Добавить(ИменаТаблицДляОбновления.ВыгрузитьЗначения()); + + Данные.Добавить(Метаданные.ОпределяемыеТипы.ВладелецНаборовЗначенийДоступаОбъект.Тип); + + Возврат ХешСуммаДанных(Данные); + +КонецФункции + +// Для функции ХешСуммаТиповГруппИЗначенийДоступа. +Функция ОписаниеТиповИзКлючейСоответствия(Данные) + + Типы = Новый Массив; + Для Каждого КлючИЗначение Из Данные Цикл + Типы.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + + Возврат Новый ОписаниеТипов(Типы); + +КонецФункции + +Функция ХешСуммаДанных(Данные) Экспорт + + СтрокаДляХеширования = СтрокаДанныхДляХеширования(Данные); + + Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); + Хеширование.Добавить(СтрокаДляХеширования); + ХешСумма = Хеширование.ХешСумма; + СтрокаХешСуммы = Base64Строка(ХешСумма); + + Возврат СтрокаХешСуммы; + +КонецФункции + +Функция ГруппыДоступаИспользующиеИерархиюЗначенийДоступа(ТипЗначенияВидаДоступа) + + УстановитьПривилегированныйРежим(Истина); + + ТекстЗапроса = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Ссылка, + | ГруппыДоступа.Профиль КАК Профиль + |ПОМЕСТИТЬ ГруппыДоступа + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + | ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка + | И (ГруппыДоступа.Профиль <> &ПрофильАдминистратор) + | И (НЕ ГруппыДоступа.ПометкаУдаления) + | И (НЕ ПрофилиГруппДоступа.ПометкаУдаления) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ГДЕ + | УчастникиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка)) + | + |ИНДЕКСИРОВАТЬ ПО + | Ссылка, + | ГруппыДоступа.Профиль + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.ГруппыДоступа.ЗначенияДоступа КАК ГруппыДоступаЗначенияДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа + | ПО ГруппыДоступаЗначенияДоступа.Ссылка = ГруппыДоступа.Ссылка + |ГДЕ + | ГруппыДоступаЗначенияДоступа.ВключаяНижестоящие + | И ТИПЗНАЧЕНИЯ(ГруппыДоступаЗначенияДоступа.ЗначениеДоступа) = &ТипЗначенияВидаДоступа + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ГруппыДоступа.Ссылка + |ИЗ + | Справочник.ПрофилиГруппДоступа.ЗначенияДоступа КАК ПрофилиГруппДоступаЗначенияДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступа КАК ГруппыДоступа + | ПО ПрофилиГруппДоступаЗначенияДоступа.Ссылка = ГруппыДоступа.Профиль + |ГДЕ + | ПрофилиГруппДоступаЗначенияДоступа.ВключаяНижестоящие + | И ТИПЗНАЧЕНИЯ(ПрофилиГруппДоступаЗначенияДоступа.ЗначениеДоступа) = &ТипЗначенияВидаДоступа"; + + Запрос = Новый Запрос(ТекстЗапроса); + Запрос.УстановитьПараметр("ТипЗначенияВидаДоступа", ТипЗначенияВидаДоступа); + Запрос.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +// Возвращает таблицу значений, содержащую вид ограничений доступа по каждому праву +// объектов метаданных. +// Если записи по праву нет, значит ограничений по праву нет. +// Таблица содержит только виды доступа, заданные разработчиком, +// исходя из их применения в текстах ограничений. +// В стандартном варианте ограничения доступа для получения видов доступа объектов, +// которые ограничиваются с помощью шаблона ПоНаборамЗначений, используется текущее +// состояние регистра сведений НаборыЗначенийДоступа. Признаком такого ограничения +// является строка, в которой таблица ограничивается по виду ограничения Объект +// с той же ведущей таблицей (кроме случая, когда таблица является владельцем настроек прав). +// +// Параметры: +// ДляПроверки - Булево - вернуть текстовое описание ограничений прав, заполненное +// в переопределяемых модулях без проверки. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ДляВнешнихПользователей - Булево - если Ложь, тогда ограничение для пользователей, +// если Истина, тогда для внешних пользователей. +// Колонка присутствует только для универсального ограничения. +// * ПолноеИмя - Строка - полное имя таблицы. +// * Таблица - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы. +// * Право - Строка - "Чтение", "Изменение". +// * ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа значений вида доступа. +// Неопределено если ограничение с помощью стандартного шаблона ПоНаборамЗначений. +// Перечисление.ДополнительныеЗначенияДоступа.Неопределено для +// специальных ограничений Объект и НастройкиПрав. +// * ЭтоАвторизованныйПользователь - Булево - Истина, если вид доступа Пользователи или ВнешниеПользователи, +// но проверка только с помощью ограничения ФункцияЭтоАвторизованныйПользователь. +// * ТаблицаОбъекта - ЛюбаяСсылка - пустая ссылка объекта, который ограничивается с помощью +// стандартного шаблона ПоНаборамЗначений. +// - Неопределено - если ВидДоступа <> Неопределено. +// Колонка присутствует только для стандартного ограничения. +// +// Строка - когда ДляПроверки равно Истина, тогда ограничения прав, как они добавлены в переопределяемом модуле. +// +Функция ПостоянныеВидыОграниченийПравОбъектовМетаданных(ДляПроверки = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + + УниверсальноеОграничение = ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина); + + Если ДляПроверки Или Не УниверсальноеОграничение Тогда + ОграниченияПрав = ""; + ИнтеграцияПодсистемБСП.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(ОграниченияПрав); + УправлениеДоступомПереопределяемый.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(ОграниченияПрав); + Если ДляПроверки Тогда + Возврат ОграниченияПрав; + КонецЕсли; + КонецЕсли; + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + ВидыОграниченийПрав = Новый ТаблицаЗначений; + ВидыОграниченийПрав.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + ВидыОграниченийПрав.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(430))); + ВидыОграниченийПрав.Колонки.Добавить("Таблица", Новый ОписаниеТипов(ТипыИдентификаторов)); + ВидыОграниченийПрав.Колонки.Добавить("Право", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))); + ВидыОграниченийПрав.Колонки.Добавить("ВидДоступа", УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); + ВидыОграниченийПрав.Колонки.Добавить("ЭтоАвторизованныйПользователь", Новый ОписаниеТипов("Булево")); + ВидыОграниченийПрав.Колонки.Добавить("ТаблицаОбъекта", + Метаданные.РегистрыСведений.НаборыЗначенийДоступа.Измерения.Объект.Тип); + ВидыОграниченийПрав.Колонки.Добавить("ВедущееПраво", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))); + + ВидыДоступаПоИменам = СвойстваВидовДоступа().ПоИменам; + + Если УниверсальноеОграничение Тогда + ВсеВидыОграничений = ВсеВидыОграниченийПравДляОтчетаПраваДоступа(); + ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, + ВсеВидыОграничений.ДляПользователей, ВидыДоступаПоИменам, Истина, Ложь); + ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, + ВсеВидыОграничений.ДляВнешнихПользователей, ВидыДоступаПоИменам, Истина, Истина); + Иначе + ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, + ОграниченияПрав, ВидыДоступаПоИменам, Ложь); + КонецЕсли; + + ВидыОграниченийПрав.Индексы.Добавить("ПолноеИмя"); + ПолныеИмена = ВидыОграниченийПрав.ВыгрузитьКолонку("ПолноеИмя"); + ИдентификаторыИмен = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена); + Для Каждого Строка Из ВидыОграниченийПрав Цикл + Строка.Таблица = ИдентификаторыИмен.Получить(Строка.ПолноеИмя); + КонецЦикла; + + ВидыОграниченийПрав.Колонки.Удалить("ВедущееПраво"); + Если УниверсальноеОграничение Тогда + ВидыОграниченийПрав.Колонки.Удалить("ТаблицаОбъекта"); + Иначе + ВидыОграниченийПрав.Колонки.Удалить("ДляВнешнихПользователей"); + КонецЕсли; + + Возврат ВидыОграниченийПрав; + +КонецФункции + +// Для функции ПостоянныеВидыОграниченийПравОбъектовМетаданных. +Процедура ДобавитьВидыОграниченияПрав(ВидыОграниченийПрав, ОграниченияПрав, ВидыДоступаПоИменам, + УниверсальноеОграничение, ДляВнешнихПользователей = Неопределено) + + Для НомерСтроки = 1 По СтрЧислоСтрок(ОграниченияПрав) Цикл + ТекущаяСтрока = СокрЛП(СтрПолучитьСтроку(ОграниченияПрав, НомерСтроки)); + Если ЗначениеЗаполнено(ТекущаяСтрока) Тогда + ПояснениеОшибки = ""; + ЧастиСтроки = СтрРазделить(ТекущаяСтрока, "."); + Если Не УниверсальноеОграничение + И ЧастиСтроки.Количество() <> 4 + И ЧастиСтроки.Количество() <> 6 Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Строка должна быть в формате %1.'"), + "<ПолноеИмяТаблицы>.<ИмяПрава>.<ИмяВидаДоступа>[.<ПолноеИмяТаблицыОбъекта>]"); + ИначеЕсли УниверсальноеОграничение + И ЧастиСтроки.Количество() <> 4 + И ЧастиСтроки.Количество() <> 7 Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Строка должна быть в формате %1.'"), + "<ПолноеИмяТаблицы>.<ИмяПрава>.<ИмяВидаДоступа>[.<ПолноеИмяТаблицыОбъекта>.<ИмяВедущегоПрава>]"); + Иначе + Таблица = ЧастиСтроки[0] + "." + ЧастиСтроки[1]; + Право = ЧастиСтроки[2]; + ВидДоступа = ЧастиСтроки[3]; + Если ЧастиСтроки.Количество() = 4 Тогда + ТаблицаОбъекта = ""; + ВедущееПраво = ""; + Иначе + ТаблицаОбъекта = ЧастиСтроки[4] + "." + ЧастиСтроки[5]; + ВедущееПраво = ?(УниверсальноеОграничение, ЧастиСтроки[6], ""); + КонецЕсли; + + ОбъектМетаданныхТаблицы = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Таблица); + Если ОбъектМетаданныхТаблицы = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица ""%1"".'"), Таблица); + + ИначеЕсли Право <> "Чтение" И Право <> "Изменение" Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует право ""%1"".'"), Право); + + ИначеЕсли ВРег(ВидДоступа) = ВРег("Объект") Тогда + ОбъектМетаданныхТаблицыОбъекта = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ТаблицаОбъекта); + Если ОбъектМетаданныхТаблицыОбъекта = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица объекта ""%1"".'"), + ТаблицаОбъекта); + Иначе + Если ОбъектМетаданныхТаблицы = ОбъектМетаданныхТаблицыОбъекта Тогда + ВидДоступаСсылка = Неопределено; + ТаблицаОбъектаСсылка = ПустаяСсылкаОбъектаМетаданных(ТаблицаОбъекта); + Иначе + ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + ТаблицаОбъектаСсылка = Неопределено; + КонецЕсли; + Если УниверсальноеОграничение + И ВедущееПраво <> "Чтение" + И ВедущееПраво <> "Изменение" Тогда + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует ведущее право ""%1"".'"), ВедущееПраво); + КонецЕсли; + КонецЕсли; + + ИначеЕсли ВРег(ВидДоступа) = ВРег("НастройкиПрав") Тогда + Если ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ТаблицаОбъекта) = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица владельца настроек прав ""%1"".'"), + ТаблицаОбъекта); + Иначе + ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + ТаблицаОбъектаСсылка = Неопределено; + КонецЕсли; + + ИначеЕсли ВРег(ВидДоступа) = ВРег("ПравоЧтения") + Или ВРег(ВидДоступа) = ВРег("ПравоИзменения") + Или ВРег(ВидДоступа) = ВРег("ФункцияЭтоАвторизованныйПользователь") + Или ВРег(ВидДоступа) = ВРег("ФункцияПравоДоступаИлиРольДоступна") Тогда + + ВидДоступаСсылка = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + ТаблицаОбъектаСсылка = Неопределено; + + ИначеЕсли ВидыДоступаПоИменам.Получить(ВидДоступа) = Неопределено Тогда + Если УниверсальноеОграничение Тогда + Продолжить; + КонецЕсли; + ПояснениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует вид доступа ""%1"".'"), ВидДоступа); + Иначе + СвойстваВидаДоступа = ВидыДоступаПоИменам.Получить(ВидДоступа); // См. СвойстваВидаДоступа + ВидДоступаСсылка = СвойстваВидаДоступа.Ссылка; + ТаблицаОбъектаСсылка = Неопределено; + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(ПояснениеОшибки) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка в строке описания вида ограничений права объекта метаданных: + |""%1"".'") + + Символы.ПС + + Символы.ПС, + ТекущаяСтрока) + + ПояснениеОшибки; + + Если Не УниверсальноеОграничение Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное внедрение подсистемы %1 + |в процедуре %2 + |общего модуля %3. + | + |%4'"), + "УправлениеДоступом", + "ПриЗаполненииВидовОграниченийПравОбъектовМетаданных", + "УправлениеДоступомПереопределяемый", + ТекстОшибки); + КонецЕсли; + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + Иначе + НовоеОписание = ВидыОграниченийПрав.Добавить(); + НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; + НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); + НовоеОписание.Право = Право; + НовоеОписание.ВидДоступа = ВидДоступаСсылка; + НовоеОписание.ТаблицаОбъекта = ТаблицаОбъектаСсылка; + НовоеОписание.ВедущееПраво = ВедущееПраво; + Если ВРег(ВидДоступа) = ВРег("ФункцияЭтоАвторизованныйПользователь") Тогда + Если ДляВнешнихПользователей <> Истина Тогда + НовоеОписание = ВидыОграниченийПрав.Добавить(); + НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; + НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); + НовоеОписание.Право = Право; + НовоеОписание.ВидДоступа = Справочники.Пользователи.ПустаяСсылка(); + НовоеОписание.ЭтоАвторизованныйПользователь = Истина; + КонецЕсли; + Если ДляВнешнихПользователей <> Ложь Тогда + НовоеОписание = ВидыОграниченийПрав.Добавить(); + НовоеОписание.ДляВнешнихПользователей = ДляВнешнихПользователей; + НовоеОписание.ПолноеИмя = ОбъектМетаданныхТаблицы.ПолноеИмя(); + НовоеОписание.Право = Право; + НовоеОписание.ВидДоступа = Справочники.ВнешниеПользователи.ПустаяСсылка(); + НовоеОписание.ЭтоАвторизованныйПользователь = Истина; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ВидДоступа - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка +// * ТипГруппИЗначений - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка +// +Функция ТипыГруппИЗначенийВидовДоступа() Экспорт + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ТипыГруппИЗначенийВидовДоступа = Новый ТаблицаЗначений; + ТипыГруппИЗначенийВидовДоступа.Колонки.Добавить("ВидДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + ТипыГруппИЗначенийВидовДоступа.Колонки.Добавить("ТипГруппИЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + + Для Каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамГруппИЗначений Цикл + Строка = ТипыГруппИЗначенийВидовДоступа.Добавить(); + СвойстваВидаДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа + Строка.ВидДоступа = СвойстваВидаДоступа.Ссылка; + + Типы = Новый Массив; + Типы.Добавить(КлючИЗначение.Ключ); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + + Строка.ТипГруппИЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + КонецЦикла; + + Возврат ТипыГруппИЗначенийВидовДоступа; + +КонецФункции + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ВидДоступа - ЛюбаяСсылка +// * ТипЗначений - ЛюбаяСсылка +// +Функция ТипыЗначенийВидовДоступаИВладельцевНастроекПрав() Экспорт + + ТипыЗначенийВидовДоступаИВладельцевНастроекПрав = Новый ТаблицаЗначений; + + ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Колонки.Добавить("ВидДоступа", + УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); + + ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Колонки.Добавить("ТипЗначений", + УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав()); + + ТипыЗначенийВидовДоступа = ТипыЗначенийВидовДоступа(); + + Для Каждого Строка Из ТипыЗначенийВидовДоступа Цикл + ЗаполнитьЗначенияСвойств(ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Добавить(), Строка); + КонецЦикла; + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + ВладельцыПрав = ВозможныеПрава.ПоТипамСсылок; + + Для Каждого КлючИЗначение Из ВладельцыПрав Цикл + + Типы = Новый Массив; + Типы.Добавить(КлючИЗначение.Ключ); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + + Строка = ТипыЗначенийВидовДоступаИВладельцевНастроекПрав.Добавить(); + Строка.ВидДоступа = ОписаниеТипа.ПривестиЗначение(Неопределено); + Строка.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + КонецЦикла; + + Возврат ТипыЗначенийВидовДоступаИВладельцевНастроекПрав; + +КонецФункции + +// Для функции ТипыЗначенийВидовДоступаИВладельцевНастроекПрав. +Функция ТипыЗначенийВидовДоступа() + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ТипыЗначенийВидовДоступа = Новый ТаблицаЗначений; + ТипыЗначенийВидовДоступа.Колонки.Добавить("ВидДоступа", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + ТипыЗначенийВидовДоступа.Колонки.Добавить("ТипЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип); + + Для каждого КлючИЗначение Из СвойстваВидовДоступа.ПоТипамЗначений Цикл + Строка = ТипыЗначенийВидовДоступа.Добавить(); + СвойстваВидаДоступа = КлючИЗначение.Значение; // См. СвойстваВидаДоступа + Строка.ВидДоступа = СвойстваВидаДоступа.Ссылка; + + Типы = Новый Массив; + Типы.Добавить(КлючИЗначение.Ключ); + ОписаниеТипа = Новый ОписаниеТипов(Типы); + + Строка.ТипЗначений = ОписаниеТипа.ПривестиЗначение(Неопределено); + КонецЦикла; + + Возврат ТипыЗначенийВидовДоступа; + +КонецФункции + +// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов. +// Смотри также заполнение в функции РегистрыСведений.НастройкиПравОбъектов.ВозможныеПраваСеанса. +// +// Возвращаемое значение: +// Структура: +// * ПоТипам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип - тип ссылки или объекта из ОпределяемыйТип.ВладельцыНастроекПрав +// ** Значение - ФиксированноеСоответствие из КлючИЗначение: +// *** Ключ - Строка - имя возможного права +// *** Значение - см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава +// * ПоТипамСсылок - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип - тип ссылки из ОпределяемыйТип.ВладельцыНастроекПрав +// ** Значение - ФиксированныйМассив из см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава +// * ПоПолнымИменам - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка - владелец прав (полное имя таблицы) +// ** Значение - см. РегистрыСведений.НастройкиПравОбъектов.СвойстваВозможногоПрава +// * ТипыВладельцев - ФиксированныйМассив из ОпределяемыйТип.ВладелецНастроекПрав +// * ОтдельныеТаблицы - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы +// ** Значение - Строка - полное имя таблицы +// * ИерархическиеТаблицы - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Тип - тип ссылки или объекта из ОпределяемыйТип.ВладельцыНастроекПрав +// ** Значение - Булево - Истина. +// +Функция ВозможныеПраваДляНастройкиПравОбъектов() Экспорт + + Возврат РегистрыСведений.НастройкиПравОбъектов.ВозможныеПраваДляНастройкиПравОбъектов(); + +КонецФункции + +// Смотри УправлениеДоступомПереопределяемый.ПриЗаполненииПоставляемыхПрофилейГруппДоступа. +// Смотри также заполнение в функции Справочники.ПрофилиГруппДоступа.ПроверенныеПоставляемыеПрофилиСеанса. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ОписанияПрофилей - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - см. Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля +// * ОписанияПрофилейМассив - ФиксированныйМассив из см. Справочники.ПрофилиГруппДоступа.СвойстваПоставляемогоПрофиля +// * ПапкиПоРодителям - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - ФиксированноеСоответствие из КлючИЗначение: +// *** Ключ - Строка +// *** Значение - Булево +// * ПараметрыОбновления - ФиксированнаяСтруктура: +// ** ОбновлятьИзмененныеПрофили - Булево +// ** ЗапретитьИзменениеПрофилей - Булево +// ** ОбновлятьГруппыДоступа - Булево +// ** ОбновлятьГруппыДоступаСУстаревшимиНастройками - Булево +// +Функция ПоставляемыеПрофили() Экспорт + + Возврат Справочники.ПрофилиГруппДоступа.ПоставляемыеПрофили(); + +КонецФункции + +// Смотри заполнение в функции Справочники.ПрофилиГруппДоступа.ПодготовленныеСтандартныеРолиРасширенийСеанса. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ОбщиеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>ОбщиеПрава +// * ПолныеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>ПолныеПрава +// * БазовыеПрава - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>БазовыеПрава +// * БазовыеПраваВнешнихПользователей - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>БазовыеПраваВнешнихПользователей +// * АдминистраторСистемы - ФиксированныйМассив из Строка - имена ролей <ПрефиксРасширения>АдминистраторСистемы +// * Все - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка - имя роли расширений, из указанных выше. +// ** Значение - Строка - имя вида ролей (имя свойства структуры). +// * ДополнительныеРолиАдминистратора - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - Строка - имя ролей расширений, которые можно назначить администратору. +// ** Значение - Булево - Истина. +// +Функция СтандартныеРолиРасширений() Экспорт + + Возврат Справочники.ПрофилиГруппДоступа.СтандартныеРолиРасширений(); + +КонецФункции + +#КонецОбласти + +#Область УниверсальноеОграничение + +#Область ОбработчикиПодписокНаСобытия + +// Обработчик подписок ПроверитьДоступПередЗаписью* проверяет доступ к старой версии объекта, проверяет +// изменение полей объектов дополнительных таблиц, присоединенных в ограничениях доступа списков. +// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа +// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередЗаписью. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// +// РежимЗаписи - РежимЗаписиДокумента - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это ДокументОбъект. +// +// РежимПроведения - РежимПроведенияДокумента - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это ДокументОбъект. +// +Процедура ПроверитьДоступПередЗаписью(Источник, Отказ, РежимЗаписи = Неопределено, РежимПроведения = Неопределено) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, Ложь, Ложь); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПередЗаписьюНабораЗаписей* проверяет доступ к старой версии набора записей, +// проверяет изменение полей наборов записей дополнительных таблиц, присоединенных в ограничениях доступа списков. +// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа +// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. +// +// Параметры: +// Источник - РегистрСведенийНаборЗаписей +// - РегистрНакопленияНаборЗаписей +// - РегистрБухгалтерииНаборЗаписей +// - РегистрРасчетаНаборЗаписей +// - ПерерасчетНаборЗаписей - набор записей, передаваемый в подписку +// на событие ПередЗаписью. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// Замещение - РежимЗамещения, Булево - параметр, передаваемый в подписку на событие ПередЗаписью. +// +// ТолькоЗапись - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьФактическогоПериодаДействия - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьПерерасчетов - Булево - параметр, передаваемый в подписку на событие ПередЗаписью, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +Процедура ПроверитьДоступПередЗаписьюНабораЗаписей(Источник, Отказ, Замещение, + ТолькоЗапись = Неопределено, + ЗаписьФактическогоПериодаДействия = Неопределено, + ЗаписьПерерасчетов = Неопределено) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, Истина, Замещение); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПриЗаписи* проверяет устаревание ключа доступа +// новой версии объекта. Обновляет устаревший ключ доступа и, в этом случае, +// выполняет проверку прав Чтение и Изменение новой версии объекта. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПриЗаписи. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПриЗаписи. +// +Процедура ПроверитьДоступПриЗаписи(Источник, Отказ) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, Ложь, Ложь); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПриЗаписиНабораЗаписей* проверяет устаревание ключей доступа +// новой версии набора записей. Обновляет устаревшие ключи доступа и, в этом случае, +// выполняет проверку прав Чтение и Изменение новой версии набора записей. +// +// Параметры: +// Источник - РегистрСведенийНаборЗаписей +// - РегистрНакопленияНаборЗаписей +// - РегистрБухгалтерииНаборЗаписей +// - РегистрРасчетаНаборЗаписей +// - ПерерасчетНаборЗаписей - набор записей, передаваемый в подписку +// на событие ПриЗаписи. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПриЗаписи. +// Замещение - РежимЗамещения, Булево - параметр, передаваемый в подписку на событие ПриЗаписи. +// +// ТолькоЗапись - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьФактическогоПериодаДействия - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +// ЗаписьПерерасчетов - Булево - параметр, передаваемый в подписку на событие ПриЗаписи, +// когда Источник это РегистрРасчетаНаборЗаписей. +// +Процедура ПроверитьДоступПриЗаписиНабораЗаписей(Источник, Отказ, Замещение, + ТолькоЗапись = Неопределено, + ЗаписьФактическогоПериодаДействия = Неопределено, + ЗаписьПерерасчетов = Неопределено) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, Истина, Замещение); + +КонецПроцедуры + +// Обработчик подписок ПроверитьДоступПередУдалением* проверяет +// изменение полей объектов дополнительных таблиц, присоединенных в ограничениях доступа списков. +// Если изменения найдены, тогда регистрируется необходимость обновления ключей доступа +// для списков, у которых в ограничениях доступа присоединены дополнительные таблицы. +// +// Параметры: +// Источник - СправочникОбъект +// - ДокументОбъект +// - ПланВидовХарактеристикОбъект +// - ПланСчетовОбъект +// - ПланВидовРасчетаОбъект +// - БизнесПроцессОбъект +// - ЗадачаОбъект +// - ПланОбменаОбъект - объект данных, передаваемый в подписку на событие ПередУдалением. +// +// Отказ - Булево - параметр, передаваемый в подписку на событие ПередУдалением. +// +Процедура ПроверитьДоступПередУдалением(Источник, Отказ) Экспорт + + // ОбменДанными.Загрузка обрабатывается внутри процедуры нестандартно (с учетом проверки прав). + ПроверитьДоступПередУдалениемИсточника(Источник, Отказ); + +КонецПроцедуры + +#КонецОбласти + +#Область УниверсальноеОграничениеДоступа + +// Параметры: +// ОписаниеДанных - см. УправлениеДоступом.ИзменениеРазрешено.ОписаниеДанных +// ПравоИзменение - Булево +// ВызыватьИсключение - Булево +// ПроверитьТолькоСтаруюВерсию - Булево +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - Неопределено - проверить для текущего пользователя. +// +// Возвращаемое значение: +// Булево +// +Функция ДоступРазрешен(ОписаниеДанных, ПравоИзменение, ВызыватьИсключение = Ложь, + ПроверитьТолькоСтаруюВерсию = Ложь, Знач Пользователь = Неопределено) Экспорт + + УчитыватьПривилегированныйРежим = Истина; + ПользовательИБ = Неопределено; + + Если Пользователь <> Неопределено + И Пользователь = Пользователи.АвторизованныйПользователь() Тогда + + Пользователь = Неопределено; + УчитыватьПривилегированныйРежим = Ложь; + ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь(); + КонецЕсли; + + Если Пользователь = Неопределено + И Пользователи.ЭтоПолноправныйПользователь(,, УчитыватьПривилегированныйРежим) Тогда + Возврат Истина; + КонецЕсли; + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ОписаниеДанных)); + Если ОбъектМетаданных = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимое значение параметра %1 в %2. + |Ожидалась ссылка, объект, ключ записи или набор записей. + |Передано значение: %3 (тип %4).'"), + "ОписаниеДанных", + ?(ВызыватьИсключение, + ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", + "УправлениеДоступом.ПроверитьЧтениеРазрешено"), + ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", + "УправлениеДоступом.ЧтениеРазрешено")), + Строка(ОписаниеДанных), + Строка(ТипЗнч(ОписаниеДанных))); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ПроизводительныйВариант = УправлениеДоступом.ПроизводительныйВариант(); + + Если Пользователь <> Неопределено Тогда + ОбщегоНазначенияКлиентСервер.ПроверитьПараметр( + ?(ВызыватьИсключение, + ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", + "УправлениеДоступом.ПроверитьЧтениеРазрешено"), + ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", + "УправлениеДоступом.ЧтениеРазрешено")), + "Пользователь", + Пользователь, + Новый ОписаниеТипов("СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи")); + + Если Не ПроизводительныйВариант Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимое значение параметра %1 в %2. + |В стандартном варианте ограничения доступа поддерживается только %3. + |Передано значение: %4 (тип %5).'"), + "Пользователь", + ?(ВызыватьИсключение, + ?(ПравоИзменение, "УправлениеДоступом.ПроверитьИзменениеРазрешено", + "УправлениеДоступом.ПроверитьЧтениеРазрешено"), + ?(ПравоИзменение, "УправлениеДоступом.ИзменениеРазрешено", + "УправлениеДоступом.ЧтениеРазрешено")), + "Неопределено", + Строка(Пользователь), + Строка(ТипЗнч(Пользователь))); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ВызыватьИсключение Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Вызов исключения поддерживается только для текущего пользователя. + |В %1 + |- либо недопустимое значение параметра %2 + |передано значение: %3 (тип %4), + |- либо недопустимое значение параметра %5 + |передано значение: %6 (тип %7).'"), + "УправлениеДоступом.ДоступРазрешен", + "ВызыватьИсключение", + Строка(ВызыватьИсключение), + Строка(ТипЗнч(ВызыватьИсключение)), + "Пользователь", + Строка(Пользователь), + Строка(ТипЗнч(Пользователь))); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Пользователи.ЭтоПолноправныйПользователь(Пользователь,, УчитыватьПривилегированныйРежим) Тогда + Возврат Истина; + КонецЕсли; + + ИдентификаторПользователяИБ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователь, + "ИдентификаторПользователяИБ"); + + Если ТипЗнч(ИдентификаторПользователяИБ) <> Тип("УникальныйИдентификатор") Тогда + Возврат Ложь; + КонецЕсли; + + ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору( + ИдентификаторПользователяИБ); + + Если ПользовательИБ = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + ЛюбойОбъект = ОписаниеДанных; // СправочникОбъект + + Если Не ПравоИзменение Тогда + ИмяПраваДоступа = "Чтение"; + + ИначеЕсли ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ОбъектМетаданных) + И Не ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ЛюбойОбъект)) + И ЛюбойОбъект.ЭтоНовый() Тогда + + ИмяПраваДоступа = "Добавление"; + Иначе + ИмяПраваДоступа = "Изменение"; + КонецЕсли; + + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + СписокПолей = УправлениеДоступомСлужебныйПовтИсп.СписокВсехПолейОграниченияДоступа(ПолноеИмя); + + Если ВызыватьИсключение Тогда + ВыполнитьПроверкуПравДоступа(ИмяПраваДоступа, ОбъектМетаданных); + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей); + + ИначеЕсли ПользовательИБ = Неопределено Тогда + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей); + + ИначеЕсли Пользователь = Неопределено Тогда + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей, ПользовательИБ); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + Иначе + ПараметрыДоступа = ПараметрыДоступа(ИмяПраваДоступа, ОбъектМетаданных, СписокПолей, ПользовательИБ); + КонецЕсли; + Если Не ПараметрыДоступа.Доступность Тогда + Возврат Ложь; + ИначеЕсли Не ПараметрыДоступа.ОграничениеУсловием Тогда + Возврат Истина; + КонецЕсли; + + Если УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа(Пользователь) Тогда + Возврат Истина; + КонецЕсли; + + Если Не ПроизводительныйВариант Тогда + Возврат ЧтениеДоступно(ПолноеИмя, ОбъектМетаданных, ОписаниеДанных, ВызыватьИсключение); + КонецЕсли; + + Если ЗначениеЗаполнено(Пользователь) Тогда + ДляВнешнихПользователей = ТипЗнч(Пользователь) = Тип("СправочникСсылка.ВнешниеПользователи"); + Иначе + ДляВнешнихПользователей = Неопределено; + КонецЕсли; + Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + + ИдентификаторТранзакции = Новый УникальныйИдентификатор; + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, ДляВнешнихПользователей); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(); + + Если ПараметрыОграничения.ОграничениеОтключено + Или Не ПравоИзменение + И ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда + + Возврат Истина; + КонецЕсли; + + СтараяВерсия = Истина; + ПравоИзменения = Ложь; + ЭтоНовый = Ложь; + + Если ПараметрыОграничения.ДоступЗапрещен Тогда + ДоступРазрешен = Ложь; + Иначе + Запрос = Новый Запрос; + УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос, Пользователь); + + Запрос.Текст = ?(ПравоИзменение, ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение, + ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение); + + Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда + СсылкаНаОбъект = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеДанных)), + ОписаниеДанных, ОписаниеДанных.Ссылка); + Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект); + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); + КонецЕсли; + Если ОписаниеДанных = СсылкаНаОбъект Или ЗначениеЗаполнено(СсылкаНаОбъект) Тогда + ДоступРазрешен = Не Запрос.Выполнить().Пустой(); + Иначе + ДоступРазрешен = Истина; + КонецЕсли; + + Если Не ДоступРазрешен Тогда + ДанныеДляПредставления = СсылкаНаОбъект; + + ИначеЕсли ОписаниеДанных <> СсылкаНаОбъект И Не ПроверитьТолькоСтаруюВерсию Тогда + СтараяВерсия = Ложь; + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + ПоляЧерезТочку = СтрРазделить(ПараметрыОграничения.ПолеВладельца.Имя, ".", Ложь); + ПолеОбъекта = ПоляЧерезТочку[0]; + ЗначениеПоляОбъекта = ОписаниеДанных[ПолеОбъекта]; + Если ПоляЧерезТочку.Количество() = 1 Тогда + ПараметрИзПамяти = "&Владелец"; + Иначе + ОбъектМетаданныхПоТипу = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеПоляОбъекта)); + Если ОбъектМетаданныхПоТипу = Неопределено Тогда + ПараметрИзПамяти = "&Владелец"; + ЗначениеПоляОбъекта = Null; + Иначе + ПоляЧерезТочку.Удалить(0); + ПараметрИзПамяти = "ВЫРАЗИТЬ(&Владелец КАК " + ОбъектМетаданныхПоТипу.ПолноеИмя() + + ")." + СтрСоединить(ПоляЧерезТочку, "."); // @query-part-1 + КонецЕсли; + КонецЕсли; + Запрос.Текст = СтрЗаменить(Запрос.Текст, + ПараметрыОграничения.ПолеОбъектаВладельцаВЗапросеПроверкиПрав, ПараметрИзПамяти); + Запрос.УстановитьПараметр("Владелец", ЗначениеПоляОбъекта); + Иначе + МодельОбъектовВПамяти = МодельОбъектовВПамяти(ОписаниеДанных, ПараметрыОграничения); + ПараметрыОбновления = Новый Структура(ПараметрыОграничения); + ПараметрыОбновления.Вставить("МодельОбъектовВПамяти", МодельОбъектовВПамяти); + ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); + ПараметрыОбновления.Вставить("ИдентификаторСписка", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); + ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(МодельОбъектовВПамяти.ЭлементыДанных, ПараметрыОбновления); + Запрос.УстановитьПараметр("КлючиДоступаКОбъектам", МодельОбъектовВПамяти.КлючиДоступаКОбъектам); + Запрос.УстановитьПараметр("Объект", МодельОбъектовВПамяти.ЭлементыДанных[0].ТекущаяСсылка); + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК Объект, + | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, + | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей + |ПОМЕСТИТЬ РегистрСведений_КлючиДоступаКОбъектам + |ИЗ + | &КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам"; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "РегистрСведений.КлючиДоступаКОбъектам", + "РегистрСведений_КлючиДоступаКОбъектам"); + Запрос.Текст = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + КонецЕсли; + ПроверкаДобавления = Ложь; + ТекстЗапросаИзменения = Запрос.Текст; + ЭтоНовый = ОписаниеДанных.ЭтоНовый(); + УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления); + ДоступРазрешен = Не Запрос.Выполнить().Пустой(); + Если Не ДоступРазрешен И ПроверкаДобавления Тогда + Запрос.Текст = ТекстЗапросаИзменения; + ПравоИзменения = Не Запрос.Выполнить().Пустой(); + КонецЕсли; + ДанныеДляПредставления = ОписаниеДанных; + КонецЕсли; + Иначе + НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); + ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей); + + Замещение = Неопределено; + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос, Замещение); + ТекстЗапроса = Запрос.Текст; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборПоИзмерениям", ОтборПоИзмерениям); + ДоступРазрешен = Запрос.Выполнить().Пустой(); + + Если ДоступРазрешен + И ТипЗнч(ОписаниеДанных) = ТипЗнч(НаборЗаписей) + И Не ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) + И Не ПроверитьТолькоСтаруюВерсию Тогда + + СтараяВерсия = Ложь; + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + ПолеВладельца = ПараметрыОграничения.ПолеВладельца.Имя; + Комбинации = ОписаниеДанных.Выгрузить(, ПолеВладельца); // ТаблицаЗначений + Комбинации.Свернуть(ПолеВладельца); + Запрос.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", Комбинации); + ТекстЗапросаПодготовкиКомбинаций = "ВЫБРАТЬ ТекущаяТаблица." + ПолеВладельца + " + |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей + |ИЗ &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"; // @query-part-1, @query-part-2 + Иначе + ТекстЗапросаПодготовкиКомбинаций = "ВЫБРАТЬ ТекущаяТаблица." + + СтрСоединить(ПараметрыОграничения.ОпорныеПоля.Используемые, ", + | ТекущаяТаблица.") + " + |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей + |ИЗ &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"; // @query-part-1, @query-part-2, @query-part-3 + ОписаниеДанных.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", + ИдентификаторТранзакции); + ОбновитьКлючиДоступаКНаборуЗаписей(ОписаниеДанных, Ложь, Ложь, + ИдентификаторТранзакции, ПараметрыОграничения, "", Запрос); + ОписаниеДанных.ДополнительныеСвойства.Удалить("УправлениеДоступомИдентификаторТранзакции"); + КонецЕсли; + Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", "ИСТИНА"); + ПолноеИмяРегистра = Метаданные.НайтиПоТипу(ТипЗнч(ОписаниеДанных)).ПолноеИмя(); + Запрос.Текст = ТекстЗапросаПодготовкиКомбинаций + ОбщегоНазначения.РазделительПакетаЗапросов() + + СтрЗаменить(Запрос.Текст, ПолноеИмяРегистра + " КАК ТекущаяТаблица", + "КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица"); // @query-part-1 @query-part-2 + + ДоступРазрешен = Запрос.Выполнить().Пустой(); + КонецЕсли; + ДанныеДляПредставления = НаборЗаписей; + КонецЕсли; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Если ДоступРазрешен Или Не ВызыватьИсключение Тогда + Возврат ДоступРазрешен; + КонецЕсли; + + Если ПравоИзменение Тогда + ПравоЧтения = ДоступРазрешен(ОписаниеДанных, Ложь); + Иначе + ПравоЧтения = Ложь; + КонецЕсли; + + СообщитьОбОшибкеДоступа(ДанныеДляПредставления, СтараяВерсия, ПравоЧтения, ПравоИзменения, ЭтоНовый); + + Возврат Ложь; + +КонецФункции + +// Для функции ДоступРазрешен. +Функция ЧтениеДоступно(ПолноеИмя, ОбъектМетаданных, ОписаниеДанных, ВызыватьИсключение) + + Запрос = Новый Запрос; + + Если ЭтоСсылочныйТипТаблицы(ПолноеИмя) Тогда + СсылкаНаОбъект = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ОписаниеДанных)), + ОписаниеДанных, ОписаниеДанных.Ссылка); + + Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект); + ТекстЗапроса = + "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Ссылка = &Ссылка"; + Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя); + Если Не Запрос.Выполнить().Пустой() Тогда + Возврат Истина; + КонецЕсли; + ДанныеДляПредставления = СсылкаНаОбъект; + Иначе + НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); + ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей); + + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос); + ТекстЗапроса = + "ВЫБРАТЬ РАЗРЕШЕННЫЕ + | КОЛИЧЕСТВО(1) КАК КоличествоДанных + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", ОтборПоИзмерениям); + Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ПолноеИмя); + + УстановитьПривилегированныйРежим(Истина); + Выборка = Запрос.Выполнить().Выбрать(); + УстановитьПривилегированныйРежим(Ложь); + ВсегоДанных = ?(Выборка.Следующий(), Выборка.КоличествоДанных, 0); + + Выборка = Запрос.Выполнить().Выбрать(); + ДоступноДанных = ?(Выборка.Следующий(), Выборка.КоличествоДанных, 0); + + Если ВсегоДанных = ДоступноДанных Тогда + Возврат Истина; + КонецЕсли; + ДанныеДляПредставления = НаборЗаписей; + КонецЕсли; + + Если Не ВызыватьИсключение Тогда + Возврат Ложь; + КонецЕсли; + + СообщитьОбОшибкеДоступа(ДанныеДляПредставления, Истина, Ложь, Ложь, Ложь); + + Возврат Ложь; + +КонецФункции + +// См. УправлениеДоступом.ПраваДоступаКДанным +Функция ПраваДоступаКДанным(ОписаниеДанных, ДляВнешнихПользователей, СоставПользователей) Экспорт + + Если ТипЗнч(ДляВнешнихПользователей) <> Тип("Булево") Тогда + Результат1 = ПраваДоступаКДанным(ОписаниеДанных, Ложь, СоставПользователей); + Результат2 = ПраваДоступаКДанным(ОписаниеДанных, Истина, СоставПользователей); + Для Каждого СтрокаТЗ Из Результат2 Цикл + ЗаполнитьЗначенияСвойств(Результат1.Добавить(), СтрокаТЗ); + КонецЦикла; + Возврат Результат1; + КонецЕсли; + + Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда + ТекстОшибки = НСтр("ru = 'Недостаточно прав доступа.'"); + ДляАдминистратора = НСтр("ru = 'Нужны полные права или привилегированный режим.'"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа,, ДляАдминистратора); + КонецЕсли; + + Если Не УправлениеДоступом.ПроизводительныйВариант() Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Функция %1 не поддерживается в стандартном варианте ограничения доступа.'"), + "УправлениеДоступом.ПраваДоступаКДанным"); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда + ЭлементДанных = ?(ОписаниеДанных.Количество() > 0, ОписаниеДанных[0], + "<" + НСтр("ru = 'Пустой массив'") + ">"); + Иначе + ЭлементДанных = ОписаниеДанных; + КонецЕсли; + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(ЭлементДанных)); + Если ОбъектМетаданных = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимое значение параметра %1 в %2. + |Ожидалась ссылка, ключ записи, набор записей или непустой массив ссылок одного типа. + |Передано значение: %3 (тип %4).'"), + "ОписаниеДанных", + "УправлениеДоступом.ПраваДоступаКДанным", + Строка(ЭлементДанных), + Строка(ТипЗнч(ОписаниеДанных))); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, + Новый УникальныйИдентификатор, ДляВнешнихПользователей); + + Если ДляВнешнихПользователей + И Не Константы.ИспользоватьВнешнихПользователей.Получить() Тогда + + Возврат ПодготовленныйРезультат(ПараметрыОграничения); + КонецЕсли; + + Запрос = Новый Запрос; + ДобавитьЗапросПроверяемыхПользователей(Запрос, ДляВнешнихПользователей, СоставПользователей); + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + Запрос.УстановитьПараметр("ИдентификаторОбъектаМетаданных", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных)); + + Если ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ОграничениеОтключено Тогда + + ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, + ?(ПараметрыОграничения.ДоступЗапрещен, "ТолькоПраваБезОграничения", "ПраваСОграничением"), + ?(СоставПользователей = Неопределено, "", "ПроверяемыеПользователи"), + "ПользователиСПравамиНаТаблицу"); + + ТекстЗапросаПравСДанными = Неопределено; + ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, ТекстЗапросаПравСДанными); + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаПравСДанными; + + Возврат ПодготовленныйРезультат(ПараметрыОграничения, Запрос); + КонецЕсли; + + ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, + ?(ПараметрыОграничения.ОграничениеЧтенияОтключено, "ОграничениеЧтенияОтключено", "ТолькоПраваБезОграничения"), + ?(СоставПользователей = Неопределено, "", "ПроверяемыеПользователи"), + "ПользователиСПравамиБезОграниченияНаТаблицу"); + + ТекстЗапросаПравСДанными = ""; + ОтборПоИзмерениям = ""; + ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, + ТекстЗапросаПравСДанными, ОтборПоИзмерениям); + + ТекстЗапроса = ПараметрыОграничения.ТекстЗапросаПравПользователей; + + Если СоставПользователей <> Неопределено Тогда + ОтборПользователей = СтрШаблон( + "ВЫРАЗИТЬ(НаборыПользователей.Пользователь КАК %1) В + | (ВЫБРАТЬ + | ПроверяемыеПользователи.ПользовательСПравом + | ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи)", + ?(ДляВнешнихПользователей, "Справочник.ВнешниеПользователи", "Справочник.Пользователи")); + Иначе + ОтборПользователей = "ИСТИНА"; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПользователей1", + ТекстСОтступом(ОтборПользователей, " ")); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПользователей2", ТекстСОтступом( + СтрЗаменить(ОтборПользователей, "НаборыПользователей.Пользователь", "СоставыГруппПользователей.Пользователь"), + " ")); + + Если Не ПараметрыОграничения.ЭтоСсылочныйТип + И Не ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", + ТекстСОтступом(ОтборПоИзмерениям, " ")); + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + + Запрос.УстановитьПараметр("РазрешенныйПустойНаборГруппДоступа", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); + КонецЕсли; + + ДобавитьЗапросПользователейИзПравНаЭлементыДанных(Запрос, ПараметрыОграничения, СоставПользователей); + + ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, + "ПраваСОграничением", + "ПользователиИзПравНаЭлементыДанных", + "ПользователиСПравамиСОграничениемНаТаблицу"); + + ДобавитьИтоговыйЗапросПравПользователей(Запрос, ПараметрыОграничения, ТекстЗапросаПравСДанными, ОтборПоИзмерениям); + + Возврат ПодготовленныйРезультат(ПараметрыОграничения, Запрос); + +КонецФункции + +// Для функций ДоступРазрешен, ЧтениеРазрешено, ПраваДоступаКДанным. +Функция ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмяРегистра, НовыйПустойНаборЗаписей, + ПраваДоступаКДанным = Ложь) + + Если ТипЗнч(ОписаниеДанных) <> ТипЗнч(НовыйПустойНаборЗаписей) Тогда + // КлючЗаписи. + ОтборЗаписей = Новый Массив; + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + ОтборЗаписей.Добавить(Новый Структура("Имя, Значение, Использование", + ОписаниеПоля.Имя, ОписаниеДанных[ОписаниеПоля.Имя], Истина)); + КонецЦикла; + Возврат ОтборЗаписей; + КонецЕсли; + + Если Не ПраваДоступаКДанным Тогда + Возврат ОписаниеДанных; + КонецЕсли; + + ЕстьОтбор = Ложь; + Для Каждого ЭлементОтбора Из ОписаниеДанных.Отбор Цикл + Если ЭлементОтбора.Использование Тогда + ЕстьОтбор = Истина; + КонецЕсли; + КонецЦикла; + + Возврат ?(ЕстьОтбор, ОписаниеДанных.Отбор, Неопределено); + +КонецФункции + +// Для функции ПраваДоступаКДанным. +Функция ПодготовленныйРезультат(ПараметрыОграничения, Запрос = Неопределено); + + ПолноеИмя = ПараметрыОграничения.Список; + + Если Запрос = Неопределено Тогда + ТипПользователь = Новый ОписаниеТипов("СправочникСсылка.Пользователи, СправочникСсылка.ВнешниеПользователи"); + Результат = Новый ТаблицаЗначений; + Результат.Колонки.Добавить("ПользовательСПравом", ТипПользователь); + Результат.Колонки.Добавить("ПравоИзменение", Новый ОписаниеТипов("Булево")); + Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда + ТипСсылки = ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); + Результат.Колонки.Добавить("Ссылка", + Новый ОписаниеТипов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки))); + Иначе + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + Результат.Колонки.Добавить(ОписаниеПоля.Имя, ОписаниеПоля.Тип); + КонецЦикла; + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) КАК ПользовательСПравом, + | ЛОЖЬ КАК ПравоИзменение, + | НЕОПРЕДЕЛЕНО КАК Ссылка + |ГДЕ + | ЛОЖЬ + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка), + | ЛОЖЬ, + | НЕОПРЕДЕЛЕНО КАК Ссылка + |ГДЕ + | ЛОЖЬ"; + Если Не ПараметрыОграничения.ЭтоСсылочныйТип Тогда + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); + ИзмеренияДляВыбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + ИзмеренияДляВыбора.Добавить("НЕОПРЕДЕЛЕНО"); // @query-part-1 + КонецЦикла; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "НЕОПРЕДЕЛЕНО КАК Ссылка", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); // @query-part-1 + КонецЕсли; + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.ТекстОбъединитьВсе() + ТекстЗапроса; + Результат = Запрос.Выполнить().Выгрузить(); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Процедура ДобавитьЗапросПроверяемыхПользователей(Запрос, ДляВнешнихПользователей, СоставПользователей) + + Если СоставПользователей = Неопределено Тогда + Возврат; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПроверяемыеПользователи.Пользователь КАК ПользовательСПравом + |ПОМЕСТИТЬ ПроверяемыеПользователи + |ИЗ + | &ПроверяемыеПользователи КАК ПроверяемыеПользователи + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь"; + + ПроверяемыеПользователи = Новый ТаблицаЗначений; + ТипПользователя = ?(ДляВнешнихПользователей, Тип("СправочникСсылка.ВнешниеПользователи"), + Тип("СправочникСсылка.Пользователи")); + ПроверяемыеПользователи.Колонки.Добавить("Пользователь", Новый ОписаниеТипов( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипПользователя))); + + Для Каждого Пользователь Из СоставПользователей Цикл + Если ТипЗнч(Пользователь) = ТипПользователя И ЗначениеЗаполнено(Пользователь) Тогда + ПроверяемыеПользователи.Добавить().Пользователь = Пользователь; + КонецЕсли; + КонецЦикла; + + Запрос.УстановитьПараметр("ПроверяемыеПользователи", ПроверяемыеПользователи); + Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(Запрос.Текст), + ОбщегоНазначения.РазделительПакетаЗапросов(), "") + ТекстЗапроса; + +КонецПроцедуры + +Процедура ДобавитьЗапросПравПользователейНаТаблицу(Запрос, ПараметрыОграничения, ВариантПрав, + ИмяВременнойТаблицыПроверяемыхПользователей = "", ИмяВременнойТаблицыРезультата = "") + + Если ИмяВременнойТаблицыПроверяемыхПользователей = "" Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | СписокПользователей.Ссылка КАК ПользовательСПравом, + | МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение) КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Ссылка = ТаблицыГруппДоступа.ГруппаДоступа) + | И (ТаблицыГруппДоступа.Таблица = &ИдентификаторОбъектаМетаданных) + | И (&ОтборПрав) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = ГруппыДоступаПользователи.Пользователь) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей + | ПО (СписокПользователей.Ссылка = СоставыГруппПользователей.Пользователь) + | И (СписокПользователей.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (НЕ СписокПользователей.ПометкаУдаления) + | И (НЕ СписокПользователей.Недействителен) + | И (НЕ СписокПользователей.Служебный) + | + |СГРУППИРОВАТЬ ПО + | СписокПользователей.Ссылка"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПроверяемыеПользователи.ПользовательСПравом КАК ПользовательСПравом, + | МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение) КАК ПравоИзменение + |ИЗ + | ПроверяемыеПользователи КАК ПроверяемыеПользователи + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей + | ПО (СписокПользователей.Ссылка = ПроверяемыеПользователи.ПользовательСПравом) + | И (СписокПользователей.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (НЕ СписокПользователей.ПометкаУдаления) + | И (НЕ СписокПользователей.Недействителен) + | И (НЕ СписокПользователей.Служебный) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.Пользователь = СписокПользователей.Ссылка) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи + | ПО (ГруппыДоступаПользователи.Пользователь = СоставыГруппПользователей.ГруппаПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ПО (ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступаПользователи.Ссылка) + | И (ТаблицыГруппДоступа.Таблица = &ИдентификаторОбъектаМетаданных) + | И (&ОтборПрав) + | + |СГРУППИРОВАТЬ ПО + | ПроверяемыеПользователи.ПользовательСПравом"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПроверяемыеПользователи КАК", + ИмяВременнойТаблицыПроверяемыхПользователей + " КАК"); // @query-part-1, @query-part-2 + КонецЕсли; + + Если ИмяВременнойТаблицыРезультата <> "" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КАК ПравоИзменение", + "КАК ПравоИзменение + |ПОМЕСТИТЬ " + ИмяВременнойТаблицыРезультата); // @query-part-1, @query-part-2 + КонецЕсли; + + Если ПараметрыОграничения.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СписокПользователей.Недействителен", "ЛОЖЬ"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СписокПользователей.Служебный", "ЛОЖЬ"); + КонецЕсли; + + Если ВариантПрав = "ПраваСОграничением" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", "ИСТИНА"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменение)", + "МАКСИМУМ(ТаблицыГруппДоступа.ПравоИзменениеБезОграничения)"); // @query-part-1, @query-part-2 + + Если ВариантПрав = "ОграничениеЧтенияОтключено" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", "ИСТИНА"); + Иначе // ТолькоПраваБезОграничения + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПрав", + "ТаблицыГруппДоступа.ПравоЧтениеБезОграничения"); + КонецЕсли; + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(Запрос.Текст), + ОбщегоНазначения.РазделительПакетаЗапросов(), "") + ТекстЗапроса; + +КонецПроцедуры + +Процедура ДобавитьЗапросПроверяемыхОбъектов(Запрос, ОписаниеДанных, ПараметрыОграничения, + ТекстЗапросаПравСДанными = Неопределено, ОтборПоИзмерениям = Неопределено) + + ТекущаяТаблица = Новый ТаблицаЗначений; + ПолноеИмя = ПараметрыОграничения.Список; + + Если ПараметрыОграничения.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ТекущаяТаблица + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица"; + + ТипСсылки = ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); + ТекущаяТаблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки))); + + Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда + Для Счетчик = 1 По ОписаниеДанных.Количество() Цикл + ТекущаяТаблица.Добавить(); + КонецЦикла; + ТекущаяТаблица.ЗагрузитьКолонку(ОписаниеДанных, "Ссылка"); + Иначе + ТекущаяТаблица.Добавить().Ссылка = ОписаниеДанных; + КонецЕсли; + Запрос.УстановитьПараметр("ТекущаяТаблица", ТекущаяТаблица); + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + + Если ТекстЗапросаПравСДанными = Неопределено Тогда + ТекстЗапросаПравСДанными = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ПользователиСПравамиНаТаблицу КАК ПраваПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица + | ПО ИСТИНА"; + КонецЕсли; + + Возврат; + + КонецЕсли; + + НаборЗаписей = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя).СоздатьНаборЗаписей(); + ОтборЗаписей = ОтборЗаписейИзОписанияДанных(ОписаниеДанных, ПолноеИмя, НаборЗаписей, Истина); + + ОтборПоИзмерениям = ?(ОтборЗаписей = Неопределено, "ИСТИНА", + ОтборПоИзмерениямНабораЗаписей(ОтборЗаписей, Запрос)); + + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмя); + + Если ЗначениеЗаполнено(ОписаниеДанных) И ОтборЗаписей = Неопределено Тогда + ИзмеренияДляВыбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %1", ОписаниеПоля.Имя)); // @query-part-1 + КонецЦикла; + ТекстЗапросаКлючейЗаписей = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.Поле1 КАК Поле1 + |ПОМЕСТИТЬ КлючиЗаписейРегистра + |ИЗ + | &КлючиЗаписейРегистра КАК ТекущаяТаблица"; + ТекстЗапросаКлючейЗаписей = СтрЗаменить(ТекстЗапросаКлючейЗаписей, + "ТекущаяТаблица.Поле1 КАК Поле1", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); // @query-part-1 + Запрос.УстановитьПараметр("КлючиЗаписейРегистра", + ОписаниеДанных.Выгрузить(, ОписаниеКлючаЗаписи.СписокПолей)); + + ОтборПоИзмерениям = + "ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | КлючиЗаписейРегистра КАК КлючиЗаписейРегистра + | ГДЕ + | КлючиЗаписейРегистра.Поле1 = ТекущаяТаблица.Поле1)"; // @query-part-1 + УсловияОтбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + УсловияОтбора.Добавить(СтрШаблон("КлючиЗаписейРегистра.%1 = ТекущаяТаблица.%1", ОписаниеПоля.Имя)); + КонецЦикла; + ОтборПоИзмерениям = СтрЗаменить(ОтборПоИзмерениям, + "КлючиЗаписейРегистра.Поле1 = ТекущаяТаблица.Поле1", + СтрСоединить(УсловияОтбора, " + | И ")); // @query-part-1, @query-part-2 + КонецЕсли; + + Если ТекстЗапросаПравСДанными = Неопределено Тогда + ТекстЗапросаПравСДанными = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ПользователиСПравамиНаТаблицу КАК ПраваПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаРегистра КАК ТекущаяТаблица + | ПО (&ОтборПоИзмерениям)"; + + ИначеЕсли ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + ОпорноеПолеВладельца = СтрРазделить(ПараметрыОграничения.ПолеВладельца.Имя, ".").Получить(0); + ТекстЗапросаВладельца = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.ОпорноеПолеВладельца КАК Ссылка + |ПОМЕСТИТЬ ТекущаяТаблица + |ИЗ + | &ТаблицаРегистра КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям"; + ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "ОпорноеПолеВладельца", ОпорноеПолеВладельца); + ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "&ТаблицаРегистра", ПолноеИмя); + ТекстЗапросаВладельца = СтрЗаменить(ТекстЗапросаВладельца, "&ОтборПоИзмерениям", ОтборПоИзмерениям); + + ТекстЗапросаПравСДанными = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | ПраваПользователей.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ПраваПользователейНаЗаписиРегистраПоВладельцу КАК ПраваПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТаблицаРегистра КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.ОпорноеПолеВладельца = ПраваПользователей.Ссылка) + | И (&ОтборПоИзмерениям)"; + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, + "ОпорноеПолеВладельца", ОпорноеПолеВладельца); + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаПравСДанными) Тогда + ИзмеренияДляВыбора = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + УточненноеИмя = УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ОписаниеПоля.Имя); + ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %2", ОписаниеПоля.Имя, УточненноеИмя)); // @query-part-1 + КонецЦикла; + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, "&ТаблицаРегистра", ПолноеИмя); + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, "&ОтборПоИзмерениям", + ТекстСОтступом(ОтборПоИзмерениям, " ")); + ТекстЗапросаПравСДанными = СтрЗаменить(ТекстЗапросаПравСДанными, + "ТекущаяТаблица.Поле1 КАК Поле1", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); // @query-part-1 + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаКлючейЗаписей) Тогда + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаКлючейЗаписей; + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаВладельца) Тогда + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаВладельца; + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьЗапросПользователейИзПравНаЭлементыДанных(Запрос, ПараметрыОграничения, СоставПользователей) + + Если СоставПользователей = Неопределено Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ВсеПользователиИзПрав.ПользовательСПравом КАК ПользовательСПравом + |ПОМЕСТИТЬ ПользователиИзПравНаЭлементыДанных + |ИЗ + | (ВЫБРАТЬ + | ВЫРАЗИТЬ(ПользователиСПравами.ПользовательСПравом КАК Справочник.Пользователи) КАК ПользовательСПравом + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ГДЕ + | ТИПЗНАЧЕНИЯ(ПользователиСПравами.ПользовательСПравом) = ТИП(Справочник.Пользователи) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СписокПользователей.Ссылка + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК СписокПользователей + | ПО (ПользователиСПравами.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ВсеПользователиИзПрав"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ВсеПользователиИзПрав.ПользовательСПравом КАК ПользовательСПравом + |ПОМЕСТИТЬ ПользователиИзПравНаЭлементыДанных + |ИЗ + | (ВЫБРАТЬ + | ВЫРАЗИТЬ(ПользователиСПравами.ПользовательСПравом КАК Справочник.Пользователи) КАК ПользовательСПравом + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ГДЕ + | ТИПЗНАЧЕНИЯ(ПользователиСПравами.ПользовательСПравом) = ТИП(Справочник.Пользователи) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ПроверяемыеПользователи.ПользовательСПравом + | ИЗ + | ПользователиСПравамиНаЭлементыДанных КАК ПользователиСПравами + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПроверяемыеПользователи КАК ПроверяемыеПользователи + | ПО (ПользователиСПравами.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ВсеПользователиИзПрав"; + КонецЕсли; + + Если ПараметрыОграничения.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + +КонецПроцедуры + +Процедура ДобавитьИтоговыйЗапросПравПользователей(Запрос, ПараметрыОграничения, + ТекстЗапросаПравСДанными, ОтборПоИзмерениям) + + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | МАКСИМУМ(ПраваПользователей.ПравоИзменение) КАК ПравоИзменение, + | ПраваПользователей.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ПраваНаТаблицу.ПользовательСПравом КАК ПользовательСПравом, + | ПраваНаТаблицу.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + | ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиБезОграниченияНаТаблицу КАК ПраваНаТаблицу + | ПО (&ОтборПоИзмерениям) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ПраваНаТаблицу.ПользовательСПравом, + | ПраваНаТаблицу.ПравоИзменение + | И ТекущаяТаблица.ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + | ИЗ + | ПользователиСПравамиСОграничениемНаТаблицу КАК ПраваНаТаблицу + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиНаЭлементыДанных КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.ПользовательСПравом = ПраваНаТаблицу.ПользовательСПравом) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | ПраваНаТаблицу.ПользовательСПравом, + | ПраваНаТаблицу.ПравоИзменение + | И ТекущаяТаблица.ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + | ИЗ + | ПользователиСПравамиСОграничениемНаТаблицу КАК ПраваНаТаблицу + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПользователиСПравамиНаЭлементыДанных КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.ПользовательСПравом = &РазрешенныйПустойНаборГруппДоступа)) КАК ПраваПользователей + | + |СГРУППИРОВАТЬ ПО + | ПраваПользователей.Ссылка, + | ПраваПользователей.ПользовательСПравом"; + + Если Не ПараметрыОграничения.ЭтоСсылочныйТип + И ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка КАК Ссылка", + "ПраваПользователей.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПраваПользователейНаЗаписиРегистраПоВладельцу"); // @query-part-1, @query-part-2 + + ТекстЗапроса = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаПравСДанными; + + ИначеЕсли Не ПараметрыОграничения.ЭтоСсылочныйТип Тогда + + УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, ПараметрыОграничения.Список); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекущаяТаблица КАК ТекущаяТаблица", + ПараметрыОграничения.Список + " КАК ТекущаяТаблица"); // @query-part-1, @query-part-2 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", + ТекстСОтступом(ОтборПоИзмерениям, " ")); + КонецЕсли; + + Если ПараметрыОграничения.ЭтоСсылочныйТип + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоИзмерениям", "ИСТИНА"); + КонецЕсли; + + Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + +КонецПроцедуры + +// Требуется, как начальная максимальная дата при планировании начального обновления доступа. +// +// Возвращаемое значение: +// Дата +// +Функция МаксимальнаяДата() Экспорт + + Возврат '39991231235959'; + +КонецФункции + +// Требуется, как начальная максимальная дата при планировании продолжения обновления доступа. +Функция МаксимальнаяДатаПриПродолжении() + + Возврат '39990101000000'; + +КонецФункции + +// Для функции НастройкиВнедрения. +Функция ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Возврат Свойства.ЯзыкАнглийский + "." + СоставИмени[1]; + +КонецФункции + +// Для процедуры ДобавитьТипыТребуемыеВОпределяемомТипе. +Функция ИмяТипаСсылки(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Если Не Свойства.ЭтоСсылочныйТип Тогда + Возврат ""; + КонецЕсли; + + Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда + ИмяТипа = Свойства.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS + Иначе + ИмяТипа = Свойства.ЯзыкАнглийский + "Ref." + СоставИмени[1]; + КонецЕсли; + + Возврат ИмяТипа; + +КонецФункции + +// Для функции НастройкиВнедрения. +Функция ИмяТипаСсылкиXML(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Если Свойства.ЭтоСсылочныйТип Тогда + Возврат Свойства.ЯзыкАнглийский + "Ref." + СоставИмени[1]; + КонецЕсли; + + Возврат ""; + +КонецФункции + +// Для функции ДобавитьТипыТребуемыеВОпределяемомТипе. +Функция ИмяТипаОбъектаИлиНабораЗаписей(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ИмяТипа = ""; + + Если Свойства.ЭтоСсылочныйТип Тогда + Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда + ИмяТипа = Свойства.ЯзыкРусский + "Объект." + СоставИмени[1]; // @Non-NLS + Иначе + ИмяТипа = Свойства.ЯзыкАнглийский + "Object." + СоставИмени[1]; + КонецЕсли; + КонецЕсли; + + Если СтрНачинаетсяС(Свойства.ИмяКоллекции, "Регистры") Тогда + Если ВРег(Свойства.ЯзыкРусский) = ВРег(СоставИмени[0]) Тогда + ИмяТипа = Свойства.ЯзыкРусский + "НаборЗаписей." + СоставИмени[1]; // @Non-NLS + Иначе + ИмяТипа = Свойства.ЯзыкАнглийский + "RecordSet." + СоставИмени[1]; + КонецЕсли; + КонецЕсли; + + Возврат ИмяТипа; + +КонецФункции + +// Для функции НастройкиВнедрения. +Функция ИмяТипаОбъектаИлиНабораЗаписейXML(ПолноеИмя, ТипыТаблицПоИменам) + + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Свойства = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + Если Свойства.ЭтоСсылочныйТип Тогда + Возврат Свойства.ЯзыкАнглийский + "Object." + СоставИмени[1]; + КонецЕсли; + + Если СтрНачинаетсяС(Свойства.ИмяКоллекции, "Регистры") Тогда + Возврат Свойства.ЯзыкАнглийский + "RecordSet." + СоставИмени[1]; + КонецЕсли; + + Возврат ""; + +КонецФункции + +// Для функции НастройкиВнедрения. +Процедура ДобавитьОбъектКВладельцам(ИмяТипаОбъектаXML, ВладельцыЗначенийКлючейДоступа) + + Если СтрНачинаетсяС(ИмяТипаОбъектаXML, "DocumentObject.") Тогда + ВладельцыЗначенийКлючейДоступа.Документы.Добавить(ИмяТипаОбъектаXML); + + ИначеЕсли СтрНачинаетсяС(ИмяТипаОбъектаXML, "CalculationRegisterRecordSet.") Тогда + ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета.Добавить(ИмяТипаОбъектаXML); + + ИначеЕсли СтрНайти(ИмяТипаОбъектаXML, "RecordSet.") > 0 Тогда + ВладельцыЗначенийКлючейДоступа.НаборыЗаписей.Добавить(ИмяТипаОбъектаXML); + + ИначеЕсли СтрНайти(ИмяТипаОбъектаXML, "Object.") > 0 Тогда + ВладельцыЗначенийКлючейДоступа.Объекты.Добавить(ИмяТипаОбъектаXML); + КонецЕсли; + +КонецПроцедуры + +// Для функции НастройкиВнедрения. +Процедура ДобавитьОграниченияВРолях(ПолноеИмяXML, ПолноеИмя, ОграниченияВРолях, СвойстваОграничений, Контекст) + + Свойства = СвойстваОграничений.Получить(ПолноеИмя); + Если Свойства <> Неопределено И Свойства.ДоступЗапрещен Тогда + Возврат; + КонецЕсли; + + ОграничениеВРоли = Новый Структура("ШаблонДляОбъекта, Параметры", Истина, Новый Массив); + ОграниченияВРолях.Вставить(ПолноеИмяXML, ОграничениеВРоли); + + Если Свойства = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Свойства.ПолеВладельца <> Неопределено Тогда + ПолеВладельца = Свойства.ПолеВладельца; // См. НовоеПолеВладельца + ОграничениеВРоли.Параметры.Добавить(ПолеВладельца.Имя); + Возврат; + КонецЕсли; + + Если Свойства.ОпорныеПоля = Неопределено + Или Не ЗначениеЗаполнено(Свойства.ОпорныеПоля) Тогда + Возврат; + КонецЕсли; + + ОграничениеВРоли.ШаблонДляОбъекта = Ложь; + + Если ЗначениеЗаполнено(Свойства.ИмяОтдельногоРегистраКлючей) Тогда + ПервыйПараметр = Свойства.ИмяОтдельногоРегистраКлючей; + + ДобавитьТипыИзмерения(Свойства.ИмяОтдельногоРегистраКлючей, + Свойства.ОпорныеПоля, ПолноеИмя, Контекст); + Иначе + ПервыйПараметр = + УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных(ПолноеИмя); + + ДобавитьТипыИзмерения("КлючиДоступаКРегистрам", + Свойства.ОпорныеПоля, ПолноеИмя, Контекст); + + Контекст.ПредопределенныеИдентификаторы.Вставить(ПервыйПараметр, ПолноеИмя); + КонецЕсли; + + ОграничениеВРоли.Параметры.Добавить(ПервыйПараметр); + + Для Каждого ОпорноеПоле Из Свойства.ОпорныеПоля.Все Цикл + ОграничениеВРоли.Параметры.Добавить(ОпорноеПоле); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьОграниченияВРолях. +Процедура ДобавитьТипыИзмерения(ИмяРегистраКлючей, ОпорныеПоля, ИмяИсходногоРегистра, Контекст) + + Если ОпорныеПоля.Все.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ТипыИзмерений = ТипыИзмеренийРегистраКлючей(Контекст.ТипыИзмеренийРегистровКлючей, ИмяРегистраКлючей); + ТипыТаблицПоИменам = Контекст.ТипыТаблицПоИменам; + + ИменаТипов = ТипыИзмерений.ИменаТипов; + ПоляРегистровПоТипам = ТипыИзмерений.ПоляРегистровПоТипам; + + ПоляРегистра = Новый Массив; + ТипыИзмерений.ПоляРегистров.Вставить(ИмяИсходногоРегистра, ПоляРегистра); + + Для Каждого ИмяПоля Из ОпорныеПоля.Все Цикл + ХранилищеТиповПоля = ОпорныеПоля.ТипыВсех[ОпорныеПоля.Все.Найти(ИмяПоля)]; // ХранилищеЗначения + ТипыПоля = ХранилищеТиповПоля.Получить(); + ПоляРегистра.Добавить(Новый Структура("Поле, Тип", ИмяПоля, ТипыПоля)); + Для Каждого Тип Из ТипыПоля.Типы() Цикл + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + Если ОбъектМетаданных = Неопределено Тогда + СинтаксисЯзыка = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка(); + ИмяТипа = СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(Тип)).ЯзыкАнглийский; + Иначе + ИмяТипа = ИмяТипаСсылкиXML(Метаданные.НайтиПоТипу(Тип).ПолноеИмя(), ТипыТаблицПоИменам); + КонецЕсли; + Если ИменаТипов.Найти(ИмяТипа) = Неопределено Тогда + ИменаТипов.Добавить(ИмяТипа); + КонецЕсли; + ПоляРегистровПоТипу = ПоляРегистровПоТипам.Получить(ИмяТипа); + Если ПоляРегистровПоТипу = Неопределено Тогда + ПоляРегистровПоТипу = Новый Массив; + ПоляРегистровПоТипам.Вставить(ИмяТипа, ПоляРегистровПоТипу); + КонецЕсли; + ПолноеИмяПоля = ИмяИсходногоРегистра + "." + ИмяПоля; + Если ПоляРегистровПоТипу.Найти(ПолноеИмяПоля) = Неопределено Тогда + ПоляРегистровПоТипу.Добавить(ПолноеИмяПоля); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для функции НастройкиВнедрения и процедуры ДобавитьТипыИзмерения. +Функция ТипыИзмеренийРегистраКлючей(ТипыИзмеренийРегистровКлючей, ИмяРегистраКлючей) + + ТипыИзмерений = ТипыИзмеренийРегистровКлючей.Получить(ИмяРегистраКлючей); + Если ТипыИзмерений = Неопределено Тогда + ТипыИзмерений = Новый Структура; + ТипыИзмерений.Вставить("ИменаТипов", Новый Массив); + ТипыИзмерений.Вставить("ПоляРегистров", Новый Соответствие); + ТипыИзмерений.Вставить("ПоляРегистровПоТипам", Новый Соответствие); + ТипыИзмеренийРегистровКлючей.Вставить(ИмяРегистраКлючей, ТипыИзмерений); + ТипыИзмерений.ИменаТипов.Добавить("EnumRef.ДополнительныеЗначенияДоступа"); + КонецЕсли; + + Возврат ТипыИзмерений; + +КонецФункции + +// Для функции ОграничиватьДоступНаУровнеЗаписейУниверсально. +Функция КонстантаПервоеОбновлениеДоступаЗавершилось() + + Возврат Не ВариантВстроенногоЯзыкаРусский() + Или Константы.ПервоеОбновлениеДоступаЗавершилось.Получить(); + +КонецФункции + +#КонецОбласти + +#Область ПроверкаДоступаПриИзменении + +// Для процедур ПроверитьДоступПередЗаписьюИсточника и др. +Процедура ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ() + + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); + Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); + Блокировка.Добавить("Справочник.КлючиДоступа"); + Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ТаблицыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ГруппыЗначенийДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗначенияГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ЗначенияГруппДоступаПоУмолчанию"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НастройкиПравОбъектов"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НаследованиеНастроекПравОбъектов"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + Блокировка.Заблокировать(); + +КонецПроцедуры + +// Для процедур ПроверитьДоступПередЗаписьюИсточника и др. +Процедура ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ() + + Если ЭтоСеансФоновогоОбновленияДоступа() Тогда + Возврат; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Константа.КоличествоПотоковОбновленияДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + Блокировка.Заблокировать(); + +КонецПроцедуры + +// Для обработчиков подписок на событие ПередЗаписью. +Процедура ПроверитьДоступПередЗаписьюИсточника(Источник, Отказ, ЭтоНаборЗаписей, Замещение) + + Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + Возврат; + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Если Не ЭтоНаборЗаписей И Источник.ЭтоНовый() Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + Иначе + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + КонецЕсли; + + ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь() + Или УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа() + Или Не УправлениеДоступом.ПроизводительныйВариант(); + + Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", + Новый УникальныйИдентификатор); + + ЕстьСтараяВерсия = Не ЭтоНаборЗаписей И Не Источник.ЭтоНовый() + Или ЭтоНаборЗаписей + И Замещение <> Ложь + И Не ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение); + + Если ЕстьСтараяВерсия Тогда + ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, ЭтоНаборЗаписей, Замещение); + ПроверитьДоступКИсточнику(Источник, Истина, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь); + + ИначеЕсли Не ЭтоНаборЗаписей Тогда + УстановитьРазрешенныйКлючДоступаДляНовогоОбъекта(Источник, ЭтоПолноправныйПользователь); + КонецЕсли; + + Если ЭтоНаборЗаписей Тогда + ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью(Источник, Замещение, ЭтоПолноправныйПользователь); + КонецЕсли; + +КонецПроцедуры + +// Для обработчиков подписок на событие ПриЗаписи. +Процедура ПроверитьДоступПриЗаписиИсточника(Источник, Отказ, ЭтоНаборЗаписей, Замещение) + + Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + Возврат; + КонецЕсли; + + ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь() + Или УправлениеДоступомСлужебныйПовтИсп.ЭтоПользовательБезОграниченияДоступа() + Или Не УправлениеДоступом.ПроизводительныйВариант(); + + // Проверка доступа к новой версии. + ПроверитьДоступКИсточнику(Источник, Ложь, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь); + + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, ЭтоНаборЗаписей, Ложь); + +КонецПроцедуры + +// Для обработчиков подписок на событие ПередУдалением. +Процедура ПроверитьДоступПередУдалениемИсточника(Источник, Отказ) + + Если ПропуститьПроверкуДоступа(Отказ, Источник) Тогда + Возврат; + КонецЕсли; + + Источник.ДополнительныеСвойства.Вставить("УправлениеДоступомИдентификаторТранзакции", + Новый УникальныйИдентификатор); + + ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, Ложь, Ложь); + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, Ложь, Истина); + +КонецПроцедуры + + +// Для процедур ПроверитьДоступПередЗаписьюИсточника, ПроверитьДоступПриЗаписиИсточника. +Функция ПропуститьПроверкуДоступа(Отказ, Источник) + + Если СтандартныеПодсистемыСервер.ЭтоИдентификаторОбъектаМетаданных(Источник) Тогда + Возврат Истина; + КонецЕсли; + + Если УправлениеДоступомСлужебныйПовтИсп.РазделенныеДанныеНедоступны() Тогда + Возврат Истина; + КонецЕсли; + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Ложь) Тогда + Возврат Истина; + КонецЕсли; + + ОтключениеОбновления = ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа; // См. НовоеОтключениеОбновленияКлючейДоступа + Если ОтключениеОбновления.Полное Тогда + Возврат Истина; + КонецЕсли; + + Если ОтключениеОбновления.Стандартное Тогда + Кэш = УправлениеДоступомСлужебныйПовтИсп.КэшИзмененныхСписковПриОтключенномОбновленииКлючейДоступа(); + ТипИсточника = ТипЗнч(Источник); + Если Кэш.Получить(ТипИсточника) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + ОтключениеОбновления = Новый Структура(ОтключениеОбновления); + ИзмененныеСписки = ОтключениеОбновления.ИзмененныеСписки.Получить(); + ИзмененныеСписки.Вставить(ТипИсточника, Истина); + ОтключениеОбновления.ИзмененныеСписки = Новый ХранилищеЗначения(ИзмененныеСписки); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + ПараметрыСеанса.ОтключениеОбновленияКлючейДоступа = Новый ФиксированнаяСтруктура(ОтключениеОбновления); + УстановитьПривилегированныйРежим(Истина); + УстановитьОтключениеБезопасногоРежима(Истина); + + Кэш.Вставить(ТипИсточника, Истина); + Возврат Истина; + КонецЕсли; + + Если Отказ Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ПроверитьДоступПередЗаписьюИсточника. +Процедура ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа(Источник, ЭтоНаборЗаписей, Замещение) + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмя, + Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоЗначениямПолей = Неопределено Тогда + + Источник.ДополнительныеСвойства.Вставить( + "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи"); + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + + Если ЭтоНаборЗаписей Тогда + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(Источник, Запрос, Замещение); + Запрос.Текст = СтрЗаменить(СвойстваСпискаКакВедущего.ПоЗначениямПолей.ТекстЗапроса, + "&ОтборПоИзмерениям", ОтборПоИзмерениям); + Иначе + Запрос.Текст = СвойстваСпискаКакВедущего.ПоЗначениямПолей.ТекстЗапроса; + Запрос.УстановитьПараметр("СсылкаНаОбъект", Источник.Ссылка); + КонецЕсли; + + Источник.ДополнительныеСвойства.Вставить( + "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи", + Запрос.ВыполнитьПакет()); + +КонецПроцедуры + +// Для процедур ЗапомнитьДанныеВлияющиеНаЗависимыеКлючиДоступа, ОбновитьКлючиДоступаКНаборуЗаписей и +// функций ДоступРазрешен, ЧтениеДоступно. +// +Функция ОтборПоИзмерениямНабораЗаписей(НаборЗаписей, Запрос, Замещение = Неопределено, ЗапросНовыхКомбинаций = Неопределено) + + Параметры = ОбщегоНазначения.НовыеПараметрыОтбораЗаписейНабораИзБазыДанных(); + Параметры.ПрефиксИменПолейВПараметрах = "ЗначениеПоля"; + + ОтборЗаписей = ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение,, Параметры); + + Для Каждого КлючИЗначение Из ОтборЗаписей.ПараметрыЗапроса Цикл + Если Запрос <> Неопределено Тогда + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + Если ЗапросНовыхКомбинаций <> Неопределено Тогда + ЗапросНовыхКомбинаций.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + + Возврат ОтборЗаписей.УсловиеЗапроса; + +КонецФункции + +// Для процедуры ПроверитьДоступПередЗаписьюИсточника. +Процедура УстановитьРазрешенныйКлючДоступаДляНовогоОбъекта(Источник, ЭтоПолноправныйПользователь) + + Если ЭтоПолноправныйПользователь Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + СсылкаНового = ПользователиСлужебный.СсылкаОбъекта(Источник); + РазрешенныйКлючДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа(); + + НаборЗаписей = РегистрыСведений.КлючиДоступаКОбъектам.СоздатьНаборЗаписей(); + НаборЗаписей.Отбор.Объект.Установить(СсылкаНового); + + Запись = НаборЗаписей.Добавить(); + Запись.Объект = СсылкаНового; + Запись.КлючДоступаПользователей = РазрешенныйКлючДоступа; + Запись.КлючДоступаВнешнихПользователей = РазрешенныйКлючДоступа; + + НаборЗаписей.Записать(); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедур ПроверитьДоступПередЗаписьюИсточника, ПроверитьДоступПриЗаписиИсточника. +Процедура ПроверитьДоступКИсточнику(Источник, ПередЗаписью, ЭтоНаборЗаписей, Замещение, ЭтоПолноправныйПользователь) + + Если ПередЗаписью И ЭтоПолноправныйПользователь Тогда + Возврат; + КонецЕсли; + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + ИдентификаторТранзакции = Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции; + ВсеПараметрыОграничения = ПараметрыОграниченияПриПроверкеДоступа(Источник, ПолноеИмя, ИдентификаторТранзакции); + + Если Пользователи.ЭтоСеансВнешнегоПользователя() Тогда + ПараметрыОграничения = ВсеПараметрыОграничения.ДляВнешнихПользователей; + ПараметрыОграниченияДополнительные = ВсеПараметрыОграничения.ДляПользователей + Иначе + ПараметрыОграничения = ВсеПараметрыОграничения.ДляПользователей; + ПараметрыОграниченияДополнительные = ВсеПараметрыОграничения.ДляВнешнихПользователей + КонецЕсли; + + Если ПараметрыОграничения.ДоступЗапрещен И Не ЭтоПолноправныйПользователь Тогда + Если ПараметрыОграничения.ДляВнешнихПользователей Тогда + ШаблонОшибки = + НСтр("ru = 'Внешним пользователям запрещен доступ к данным списка + |""%1"".'"); + Иначе + ШаблонОшибки = + НСтр("ru = 'Пользователям запрещен доступ к данным списка + |""%1"".'"); + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + Источник.Метаданные().Представление()); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ЭтоНаборЗаписей Тогда + ПроверитьДоступКНаборуЗаписей(Источник, ПередЗаписью, Замещение, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные); + Иначе + ПроверитьДоступКОбъекту(Источник, ПередЗаписью, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКИсточнику. +// +// Возвращаемое значение: +// см. РассчитанныеПараметрыОграничения +// +Функция ПараметрыОграниченияПриПроверкеДоступа(Источник, ПолноеИмя, ИдентификаторТранзакции) + + Возврат ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Null); + +КонецФункции + +// Для процедуры ПроверитьДоступКИсточнику. +Процедура ПроверитьДоступКОбъекту(Источник, ПередЗаписью, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные) + + ЭтоНовый = Не Источник.ДополнительныеСвойства.Свойство( + "УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи"); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Не ПередЗаписью Тогда + КлючДоступаОбновлен = Ложь; + + ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, + ПараметрыОграничения, КлючДоступаОбновлен); + + ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, + ПараметрыОграниченияДополнительные); + + Если Не КлючДоступаОбновлен Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + Если ПараметрыОграничения.ОграничениеОтключено Или ЭтоПолноправныйПользователь Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение; + + ПроверкаДобавления = Ложь; + Если Не ПередЗаписью Тогда + УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления); + КонецЕсли; + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(); + + Запрос.УстановитьПараметр("Объект", Источник.Ссылка); + УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос); + + Если ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОграничения.ИдентификаторТаблицыНастроекПрав); + КонецЕсли; + + Если Не РезультатЗапросаПроверкиДоступа(Запрос, Источник).Пустой() Тогда + Возврат; // Доступ разрешен. + КонецЕсли; + + Если ПроверкаДобавления Тогда + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение; + ПравоИзменения = Не Запрос.Выполнить().Пустой(); + Иначе + ПравоИзменения = Ложь; + КонецЕсли; + + Если ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда + ПравоЧтения = Истина; + Иначе + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение; + ПравоЧтения = Не Запрос.Выполнить().Пустой(); + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Данные = ?(ПередЗаписью, Источник.Ссылка, Источник); + СообщитьОбОшибкеДоступа(Данные, ПередЗаписью, ПравоЧтения, ПравоИзменения, ЭтоНовый); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКОбъекту и функции ДоступРазрешен. +Процедура УточнитьПравоДобавление(Запрос, ЭтоНовый, ПараметрыОграничения, ПроверкаДобавления) + + ПроверкаДобавления = ЭтоНовый И Не ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу; + Если Не ПроверкаДобавления Тогда + Возврат; + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "РазрешенныеКлючиДоступа.ПравоИзменение", "РазрешенныеКлючиДоступа.ПравоДобавление"); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКОбъекту. +Процедура ОбновитьКлючДоступаОбъектаПриЗаписи(Источник, ЭтоНовый, ИдентификаторТранзакции, + ПараметрыОграничения, КлючДоступаОбновлен = Ложь) + + Если ПараметрыОграничения.ДоступЗапрещен + Или (ПараметрыОграничения.ОграничениеОтключено + И Не ПараметрыОграничения.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей) Тогда + Возврат; + КонецЕсли; + + Если Не ЭтоНовый И Не КлючДоступаИсточникаУстарел(Источник.Ссылка, ПараметрыОграничения, Источник) Тогда + Возврат; + КонецЕсли; + + ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(Источник.Ссылка, + ПараметрыОграничения, ИдентификаторТранзакции,,, Источник); + + КлючДоступаОбновлен = Истина; + +КонецПроцедуры + +// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. +Функция РезультатЗапросаПроверкиДоступа(Запрос, Источник) + + Возврат Запрос.Выполнить(); + +КонецФункции + +// Для процедуры ПроверитьДоступКИсточнику. +Процедура ПроверитьДоступКНаборуЗаписей(Источник, ПередЗаписью, Замещение, ЭтоПолноправныйПользователь, + ИдентификаторТранзакции, ПараметрыОграничения, ПараметрыОграниченияДополнительные) + + Если ПередЗаписью + И (Замещение = Ложь + Или ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение)) + Или Не ПередЗаписью + И (Источник.Количество() = 0 + Или ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение)) Тогда + + Возврат; + КонецЕсли; + + ОтборПоИзмерениям = ""; + Запрос = ?(ПараметрыОграничения.ОграничениеОтключено Или ЭтоПолноправныйПользователь, + Неопределено, Новый Запрос); + + ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, + ИдентификаторТранзакции, ПараметрыОграничения, ОтборПоИзмерениям, Запрос); + + ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, + ИдентификаторТранзакции, ПараметрыОграниченияДополнительные, "", Неопределено); + + Если Запрос = Неопределено Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Запрос.Текст = СтрЗаменить(ПараметрыОграничения.ТекстЗапросаПроверкиПравЧтениеИзменение, + "&ОтборПоИзмерениям", ОтборПоИзмерениям); + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(); + УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос); + + Если РезультатЗапросаПроверкиДоступа(Запрос, Источник).Пустой() Тогда + Возврат; // Доступ разрешен. + КонецЕсли; + + Если ПараметрыОграничения.ОграничениеЧтенияОтключено Тогда + ПравоЧтения = Истина; + Иначе + Запрос.Текст = СтрЗаменить(ПараметрыОграничения.ТекстЗапросаПроверкиПраваЧтение, + "&ОтборПоИзмерениям", ОтборПоИзмерениям); + ПравоЧтения = Запрос.Выполнить().Пустой(); + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + СообщитьОбОшибкеДоступа(Источник, ПередЗаписью, ПравоЧтения, Ложь, Ложь); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступКНаборуЗаписей и для функции ДоступРазрешен. +Процедура ОбновитьКлючиДоступаКНаборуЗаписей(Источник, ПередЗаписью, Замещение, + ИдентификаторТранзакции, ПараметрыОграничения, ОтборПоИзмерениям, Запрос) + + Если ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу + И Запрос = Неопределено Тогда + + Возврат; + КонецЕсли; + + Если Не ПередЗаписью Тогда + ЗапросНовыхКомбинаций = Новый Запрос; + КонецЕсли; + + Если Замещение <> Ложь + И Не ОбщегоНазначения.ЭтоДобавлениеНабораЗаписей(Замещение) Тогда + + ОтборПоИзмерениям = ОтборПоИзмерениямНабораЗаписей(Источник, Запрос, Замещение, ЗапросНовыхКомбинаций); + Иначе + КомбинацииЗначенийОпорныхПолей = КомбинацииЗначенийОпорныхПолей(Источник, + ОтборПоИзмерениям, ПараметрыОграничения); + + Если Запрос <> Неопределено Тогда + Запрос.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", КомбинацииЗначенийОпорныхПолей); + КонецЕсли; + ЗапросНовыхКомбинаций.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", КомбинацииЗначенийОпорныхПолей); + КонецЕсли; + + Если ПередЗаписью Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступПередЗаписьюИсточника. +Процедура ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью(Источник, Замещение, ЭтоПолноправныйПользователь) + + Если ЭтоПолноправныйПользователь + Или Источник.Количество() = 0 + Или ОбщегоНазначения.ЭтоУдалениеНабораЗаписей(Замещение) Тогда + Возврат; + КонецЕсли; + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + ИдентификаторТранзакции = Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции; + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + + ЗапросНовыхКомбинаций = Новый Запрос; + ОтборПоИзмерениям = ""; + + ЗапросНовыхКомбинаций.УстановитьПараметр("КомбинацииЗначенийОпорныхПолей", + КомбинацииЗначенийОпорныхПолей(Источник, ОтборПоИзмерениям, ПараметрыОграничения)); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедур ПроверитьДоступКНаборуЗаписей, +// ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью. +// +Функция КомбинацииЗначенийОпорныхПолей(Источник, ОтборПоИзмерениям, ПараметрыОграничения) + + Поля = СтрСоединить(ПараметрыОграничения.ОпорныеПоля.Используемые, ","); + Поля = УправлениеДоступомСлужебныйПовтИсп.ПоляВРегистреСимволовМетаданных(ПараметрыОграничения.Список, Поля); + КомбинацииЗначенийОпорныхПолей = Источник.Выгрузить(, Поля); + КомбинацииЗначенийОпорныхПолей.Свернуть(Поля); + + ПоляОтбора = ""; + Для Каждого Поле Из ПараметрыОграничения.ОпорныеПоля.Используемые Цикл + ПоляОтбора = ПоляОтбора + ?(ПоляОтбора = "", "", ", ") + "ТекущаяТаблица." + Поле; + КонецЦикла; + ОтборПоИзмерениям = "(" + ПоляОтбора + ") В (&КомбинацииЗначенийОпорныхПолей)"; // @query-part-2 + + Возврат КомбинацииЗначенийОпорныхПолей; + +КонецФункции + +// Для процедур ПроверитьДоступКНаборуЗаписей, +// ЗаписатьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолейПередЗаписью. +// +Процедура ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения) + + ЭлементыДанных = ЭлементыДанныхНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения); + + Если ЭлементыДанных.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(ЭлементыДанных, ПараметрыОграничения, + Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции,,, Источник); + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаНовыхКомбинацийЗначенийОпорныхПолей. +Функция ЭлементыДанныхНовыхКомбинацийЗначенийОпорныхПолей(ЗапросНовыхКомбинаций, + ОтборПоИзмерениям, Источник, ПараметрыОграничения) + + Если ЗапросНовыхКомбинаций.Параметры.Свойство("КомбинацииЗначенийОпорныхПолей") Тогда + ЗапросНовыхКомбинаций.Текст = + ПараметрыОграничения.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей; + Иначе + ЗапросНовыхКомбинаций.Текст = СтрЗаменить( + ПараметрыОграничения.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей, + "&ОтборПоИзмерениям", + ОтборПоИзмерениям); + КонецЕсли; + + РезультатЗапросаНовыхКомбинаций = ЗапросНовыхКомбинаций.Выполнить(); + Если РезультатЗапросаНовыхКомбинаций.Пустой() Тогда + Возврат Новый Массив; + КонецЕсли; + + ЭлементыДанных = РезультатЗапросаНовыхКомбинаций.Выгрузить(); + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов("Число")); + Индекс = 0; + + Если ПараметрыОграничения.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей Тогда + ВсеЭлементыДанных = ЭлементыДанных; + ЭлементыДанных = ВсеЭлементыДанных.Скопировать(Новый Массив); + Для Каждого ЭлементДанных Из ВсеЭлементыДанных Цикл + Если НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОграничения) Тогда + Продолжить; + КонецЕсли; + ЭлементДанных.ТекущаяСсылка = Индекс; + Индекс = Индекс + 1; + ЗаполнитьЗначенияСвойств(ЭлементыДанных.Добавить(), ЭлементДанных); + КонецЦикла; + Иначе + Для Каждого ЭлементДанных Из ЭлементыДанных Цикл + ЭлементДанных.ТекущаяСсылка = Индекс; + Индекс = Индекс + 1; + КонецЦикла; + КонецЕсли; + + Возврат ЭлементыДанных; + +КонецФункции + +// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. +Процедура СообщитьОбОшибкеДоступа(Данные, СтараяВерсия, ЕстьПравоЧтения, ЕстьПравоИзменения, ЭтоНовый) + + Если СтараяВерсия Тогда + Если ЕстьПравоЧтения Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для изменения данных: + |%1'"), ПредставлениеДанных(Данные)); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для чтения данных: + |%1'"), ПредставлениеДанных(Данные)); + КонецЕсли; + Иначе + Если ЕстьПравоЧтения И ЕстьПравоИзменения Тогда + Если ЭтоНовый Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (нет права добавления): + |%1'"), ПредставлениеДанных(Данные)); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (нет права добавления для сделанных изменений): + |%1'"), ПредставлениеДанных(Данные)); + КонецЕсли; + ИначеЕсли ЕстьПравоЧтения Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (невозможно будет изменить): + |%1'"), ПредставлениеДанных(Данные)); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недостаточно прав для добавления данных (невозможно будет прочитать): + |%1.'"), ПредставлениеДанных(Данные)); + КонецЕсли; + КонецЕсли; + + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.НарушениеПравДоступа); + +КонецПроцедуры + +// Для процедуры СообщитьОбОшибкеДоступа. +Функция ПредставлениеДанных(Данные) + + Если ТипЗнч(Данные) = Тип("Строка") Тогда + Возврат СокрЛП(Данные); + КонецЕсли; + + Если ТипЗнч(Данные) = Тип("Структура") Тогда + ЭтоРегистр = Истина; + Если ТипЗнч(Данные.Регистр) = Тип("Строка") Тогда + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Данные.Регистр); + Иначе + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Данные.Регистр)); + КонецЕсли; + Иначе + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Данные)); + ЭтоРегистр = ОбщегоНазначения.ЭтоРегистр(ОбъектМетаданных); + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + Возврат ""; + КонецЕсли; + + Если ЭтоРегистр Тогда + ПредставлениеДанных = ОбъектМетаданных.Представление(); + + КоличествоПолей = 0; + Для каждого ЭлементОтбора Из Данные.Отбор Цикл + Если ЭлементОтбора.Использование Тогда + КоличествоПолей = КоличествоПолей + 1; + КонецЕсли; + КонецЦикла; + + Если КоличествоПолей = 1 Тогда + ПредставлениеДанных = ПредставлениеДанных + + " " + НСтр("ru = 'с полем'") + " " + Строка(Данные.Отбор); + + ИначеЕсли КоличествоПолей > 1 Тогда + ПредставлениеДанных = ПредставлениеДанных + + " " + НСтр("ru = 'с полями'") + " " + Строка(Данные.Отбор); + КонецЕсли; + Иначе + ПредставлениеДанных = Строка(Данные); + ПредставлениеМетаданных = ОбщегоНазначения.ПредставлениеОбъекта(ОбъектМетаданных); + + Если Не СтрЗаканчиваетсяНа(ПредставлениеДанных, "(" + ПредставлениеМетаданных + ")") + И Не СтрНачинаетсяС(ПредставлениеДанных, ПредставлениеМетаданных) Тогда + + ПредставлениеДанных = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 (%2)", + ПредставлениеДанных, ПредставлениеМетаданных); + КонецЕсли; + КонецЕсли; + + Возврат ПредставлениеДанных; + +КонецФункции + +// Для процедуры ПроверитьДоступКОбъекту и формы ОбновлениеДоступаРучноеУправление. +// +// Возвращаемое значение: +// Булево +// +Функция КлючДоступаИсточникаУстарел(СсылкаНаОбъект, ПараметрыОграничения, Источник = Неопределено) Экспорт + + Если ПараметрыОграничения.БезЗаписиКлючейДоступа Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Ссылка", СсылкаНаОбъект); + + Если Не ЗначениеЗаполнено(ПараметрыОграничения.СоставПолей) Тогда + Запрос.УстановитьПараметр("Список", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); + КонецЕсли; + + Запрос.Текст = ПараметрыОграничения.ТекстЗапросаПроверкиКлючаДоступаОбъекта; + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Запрос.Выполнить().Пустой() Тогда + Возврат Ложь; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Возврат Истина; + +КонецФункции + +// Для процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей и формы ОбновлениеДоступаРучноеУправление. +Процедура ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи(ОписаниеЭлементовДанных, ПараметрыОграничения, + ИдентификаторТранзакции, ОбновитьПраваНаКлючи = Ложь, ЕстьИзмененияПрав = Ложь, Источник = Неопределено) Экспорт + + Если ПараметрыОграничения.БезЗаписиКлючейДоступа Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ОписаниеЭлементовДанных) = Тип("ТаблицаЗначений") Тогда + ЭлементыДанных = ОписаниеЭлементовДанных; + Иначе + ЭлементыДанных = Новый ТаблицаЗначений; + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка"); + ЭлементыДанных.Добавить().ТекущаяСсылка = ОписаниеЭлементовДанных; + КонецЕсли; + + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПараметрыОграничения.Список, + ИдентификаторТранзакции); + ИмяСвойстваВидаПользователей = ?(ПараметрыОграничения.ДляВнешнихПользователей, + "ДляВнешнихПользователей", "ДляПользователей"); + + ПараметрыОбновления = Новый Структура(ПараметрыОграничения); + ПараметрыОбновления.Вставить("ЕстьИзмененияПрав", ЕстьИзмененияПрав); + ПараметрыОбновления.Вставить("ОбновитьПраваНаКлючи", ОбновитьПраваНаКлючи); + ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); + ПараметрыОбновления.Вставить("ИдентификаторСписка", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПараметрыОграничения.Список)); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей] = Неопределено Тогда + + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", Новый Массив); + Иначе + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", + СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей]); + КонецЕсли; + + ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ЭлементыДанных, ПараметрыОбновления); + + ЕстьИзмененияПрав = ПараметрыОбновления.ЕстьИзмененияПрав; + +КонецПроцедуры + +// Для регистра сведений ГруппыЗначенийДоступа. +Процедура ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами(ЗначенияСИзменениямиПоТипам) Экспорт + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + Возврат; + КонецЕсли; + + ИдентификаторТранзакции = Новый УникальныйИдентификатор; + + СпискиДляОбновления = Новый Соответствие; + Для Каждого ОписаниеЗначений Из ЗначенияСИзменениямиПоТипам Цикл + ПолноеИмяВедущего = Метаданные.НайтиПоТипу(ОписаниеЗначений.Ключ).ПолноеИмя(); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмяВедущего, ИдентификаторТранзакции); + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоЗначениямСГруппами = Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, + СвойстваСпискаКакВедущего.ПоЗначениямСГруппами, "ДляПользователей"); + + ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, + СвойстваСпискаКакВедущего.ПоЗначениямСГруппами, "ДляВнешнихПользователей"); + КонецЦикла; + + ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, + ИдентификаторТранзакции, + "ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами", + ?(ЗначенияСИзменениямиПоТипам.Количество() <> 1 Или ОписаниеЗначений.Значение = Истина, + Неопределено, Новый Структура("ПоЗначениямСГруппами", ОписаниеЗначений.Значение))); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами. +Процедура ДобавитьСпискиДляОбновленияДляВидаПользователей(СпискиДляОбновления, ПоЗначениямСГруппами, ИмяВидаПользователей) + + ПолныеИмена = ПоЗначениямСГруппами[ИмяВидаПользователей]; + Если ПолныеИмена = Неопределено Тогда + Возврат; + КонецЕсли; + + Для Каждого ПолноеИмя Из ПолныеИмена Цикл + СписокДляОбновления = СпискиДляОбновления.Получить(ПолноеИмя); + Если СписокДляОбновления = Неопределено Тогда + СписокДляОбновления = Новый Структура("ДляПользователей, ДляВнешнихПользователей", Ложь, Ложь); + СпискиДляОбновления.Вставить(ПолноеИмя, СписокДляОбновления); + КонецЕсли; + СписокДляОбновления[ИмяВидаПользователей] = Истина; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа, ЗаписатьКлючиДоступаОбъектов, +// ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами. +// +Процедура ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, ИдентификаторТранзакции, + Описание, ВедущийОбъект = Неопределено, ЭтоПродолжениеОбновления = Ложь) + + Если ТипЗнч(СпискиДляОбновления) = Тип("Соответствие") + И СпискиДляОбновления.Количество() = 0 + Или ТипЗнч(СпискиДляОбновления) = Тип("Структура") + И СпискиДляОбновления.ИменаСписков.Количество() = 0 Тогда + + Возврат; + КонецЕсли; + + Списки = Новый Массив; + СпискиДляПользователей = Новый Массив; + СпискиДляВнешнихПользователей = Новый Массив; + + Если ТипЗнч(СпискиДляОбновления) = Тип("Соответствие") Тогда + Для Каждого ОписаниеСписка Из СпискиДляОбновления Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + Свойства = ОписаниеСписка.Значение; + + Если Свойства.ДляПользователей Тогда + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Ложь); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + Свойства.ДляПользователей = Ложь; + КонецЕсли; + КонецЕсли; + + Если Свойства.ДляВнешнихПользователей Тогда + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Истина); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + Свойства.ДляВнешнихПользователей = Ложь; + КонецЕсли; + КонецЕсли; + + Если Свойства.ДляПользователей И Свойства.ДляВнешнихПользователей Тогда + Списки.Добавить(ПолноеИмя); + + ИначеЕсли Свойства.ДляПользователей Тогда + СпискиДляПользователей.Добавить(ПолноеИмя); + + ИначеЕсли Свойства.ДляВнешнихПользователей Тогда + СпискиДляВнешнихПользователей.Добавить(ПолноеИмя); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого ПолноеИмя Из СпискиДляОбновления.ИменаСписков Цикл + ПараметрыОграничения = ПараметрыОграничения(ПолноеИмя, + ИдентификаторТранзакции, СпискиДляОбновления.ДляВнешнихПользователей); + + Если ПараметрыОграничения.ОграничениеОтключено + Или ПараметрыОграничения.ДоступЗапрещен + Или ПараметрыОграничения.ИспользуетсяОграничениеПоВладельцу Тогда + + Продолжить; + КонецЕсли; + + Если СпискиДляОбновления.ДляВнешнихПользователей Тогда + СпискиДляВнешнихПользователей.Добавить(ПолноеИмя); + Иначе + СпискиДляПользователей.Добавить(ПолноеИмя); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если Описание = "ЗаполнитьКэшПараметровОграниченияДоступа" Тогда + Возврат; + КонецЕсли; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.Описание = Описание; + ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; + ПараметрыПланирования.ЭтоПродолжениеОбновления = ЭтоПродолжениеОбновления; + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); + + ПараметрыПланирования.ДляПользователей = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ПроверитьДоступПриЗаписиИсточника, ПроверитьДоступПередУдалениемИсточника. +Процедура ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа(Источник, ЭтоНаборЗаписей, Удаление) + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ПолноеИмя = Источник.Метаданные().ПолноеИмя(); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(ПолноеИмя, + Источник.ДополнительныеСвойства.УправлениеДоступомИдентификаторТранзакции); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоЗначениямПолей = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Источник.ДополнительныеСвойства.Свойство("УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи") Тогда + РезультатыЗапроса = Источник.ДополнительныеСвойства.УправлениеДоступомЗначенияПолейДляПроверкиИзмененияПриЗаписи; + Иначе + РезультатыЗапроса = Неопределено; + КонецЕсли; + + ИзмененияПоЗначениямПолей = Новый Структура; + ИзмененияПоЗначениямПолей.Вставить("Описание", ?(ЭтоНаборЗаписей, Источник.Отбор, Источник.Ссылка)); + ИзмененияПоЗначениямПолей.Вставить("ИзмененнаяТаблица", ПолноеИмя); + ИзмененияПоЗначениямПолей.Вставить("СоставИзменений"); + + ВедущийОбъект = ОписаниеВедущегоОбъекта(); + ВедущийОбъект.Вставить("ПоЗначениямПолей", ИзмененияПоЗначениямПолей); + + ПоЗначениямПолей = СвойстваСпискаКакВедущего.ПоЗначениямПолей; + ПоляШапки = ПоЗначениямПолей.ПоляШапки; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.Описание = "ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа"; + ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; + + Если ЭтоНаборЗаписей Тогда + Если ЗначениеЗаполнено(ПоляШапки.ВсеПоля) Тогда + РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[0]); + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + Источник, ПоляШапки.НаборыПолей, ПараметрыПланирования); + КонецЕсли; + Иначе + Если ЗначениеЗаполнено(ПоляШапки.ВсеПоля) Тогда + РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[0]); + НовыеЗначения = Новый ТаблицаЗначений; + Для Каждого ИмяПоля Из ПоляШапки.ВсеПоля Цикл + НовыеЗначения.Колонки.Добавить(ИмяПоля, ПоляШапки.ТипыВсехПолей.Получить(ИмяПоля).Получить()); + КонецЦикла; + Если Не Удаление Тогда + ЗаполнитьЗначенияСвойств(НовыеЗначения.Добавить(), Источник); + КонецЕсли; + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + НовыеЗначения, ПоляШапки.НаборыПолей, ПараметрыПланирования); + Индекс = 1; + Иначе + Индекс = 0; + КонецЕсли; + Для Каждого ОписаниеТабличнойЧасти Из ПоЗначениямПолей.ТабличныеЧасти Цикл + РезультатЗапроса = ?(РезультатыЗапроса = Неопределено, Неопределено, РезультатыЗапроса[Индекс]); + ИзмененияПоЗначениямПолей.ИзмененнаяТаблица = ПолноеИмя + "." + ОписаниеТабличнойЧасти.Имя; + НовыеЗначения = НовыеЗначенияТабличнойЧасти(Источник, ОписаниеТабличнойЧасти, Удаление); + // @skip-check query-in-loop - В вызываемом варианте ветка с запросом не используется + ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + НовыеЗначения, ОписаниеТабличнойЧасти.НаборыПолей, ПараметрыПланирования); + Индекс = Индекс + 1; + КонецЦикла; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ПоЗначениямПолей - Структура: +// ** Описание - ЛюбаяСсылка +// - Отбор +// ** ИзмененнаяТаблица - Строка - полное имя списка +// ** СоставИзменений - см. СоставИзмененийТаблицы +// * ПоКлючамДоступа - СправочникСсылка.КлючиДоступа +// * ПоЗначениямСГруппами - ОпределяемыйТип.ЗначениеДоступа - только значения доступа с группами. +// * ПоДаннымКэшаРасчетаПрав - Строка - наименование данных для кэша расчета прав. +// +Функция ОписаниеВедущегоОбъекта() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа. +Функция НовыеЗначенияТабличнойЧасти(Источник, ОписаниеТабличнойЧасти, Удаление) + + Поля = Новый Массив(ОписаниеТабличнойЧасти.ВсеПоля); + + ИмяПоляСсылка = "Ссылка"; // @Non-NLS + Индекс = Поля.Найти(ИмяПоляСсылка); + Если Индекс <> Неопределено Тогда + Поля.Удалить(Индекс); + Иначе + ИмяПоляСсылка = "Ref"; + Индекс = Поля.Найти(ИмяПоляСсылка); + Если Индекс <> Неопределено Тогда + Поля.Удалить(Индекс); + КонецЕсли; + КонецЕсли; + + НовыеЗначения = Источник[ОписаниеТабличнойЧасти.Имя].Выгрузить( + ?(Удаление, Новый Массив, Неопределено), СтрСоединить(Поля, ", ")); // ТаблицаЗначений + + Если Индекс <> Неопределено Тогда + Типы = Новый Массив; + Типы.Добавить(ТипЗнч(Источник.Ссылка)); + НовыеЗначения.Колонки.Добавить(ИмяПоляСсылка, Новый ОписаниеТипов(Типы)); + НовыеЗначения.ЗаполнитьЗначения(Источник.Ссылка, ИмяПоляСсылка); + КонецЕсли; + + Возврат НовыеЗначения; + +КонецФункции + +// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступа. +Процедура ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей(РезультатЗапроса, + Источник, НаборыПолейПоВидамПользователей, ПараметрыПланирования) + + ВидыПользователей = Новый Массив; + ВидыПользователей.Добавить("ДляПользователей"); + ВидыПользователей.Добавить("ДляВнешнихПользователей"); + + Для Каждого ВидПользователей Из ВидыПользователей Цикл + НаборыПолей = НаборыПолейПоВидамПользователей[ВидПользователей]; + Если НаборыПолей = Неопределено Тогда + Продолжить; + КонецЕсли; + Если ВидПользователей = "ДляПользователей" Тогда + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ПараметрыПланирования.ДляПользователей = Истина; + Иначе + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ПараметрыПланирования.ДляПользователей = Ложь; + КонецЕсли; + Для Каждого ОписаниеНабораПолей Из НаборыПолей Цикл + СоставИзменений = СоставИзмененийТаблицы(РезультатЗапроса, Источник, ОписаниеНабораПолей.Ключ); + Если СоставИзменений = Null Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеЗависимыхТаблиц Из ОписаниеНабораПолей.Значение Цикл + Если ОписаниеЗависимыхТаблиц.Ключ = ОписаниеНабораПолей.Ключ + Или СоставИзменений = Неопределено Тогда + ТекущийСоставИзменений = СоставИзменений; + Иначе + ТекущийСоставИзменений = СоставИзменений.Скопировать(, ОписаниеЗависимыхТаблиц.Ключ); + ТекущийСоставИзменений.Свернуть(ОписаниеЗависимыхТаблиц.Ключ); + КонецЕсли; + ПараметрыПланирования.ВедущийОбъект.ПоЗначениямПолей.СоставИзменений = ТекущийСоставИзменений; + // @skip-check query-in-loop - В вызываемом варианте ветка с запросом не используется + ЗапланироватьОбновлениеДоступа(ОписаниеЗависимыхТаблиц.Значение, ПараметрыПланирования); + КонецЦикла; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеЗависимыхУстаревшихКлючейДоступаПоЗначениямПолей. +// +// Возвращаемое значение: +// ТаблицаЗначений +// +Функция СоставИзмененийТаблицы(РезультатЗапроса, Источник, Поля) + + МаксимумКомбинаций = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); + Если РезультатЗапроса = Неопределено Тогда + СтарыеКомбинации = Новый ТаблицаЗначений; + Иначе + СтарыеКомбинации = РезультатЗапроса.Выгрузить(); + Если СтрРазделить(Поля, ",").Количество() < СтарыеКомбинации.Колонки.Количество() Тогда + СтарыеКомбинации.Свернуть(Поля); + КонецЕсли; + КонецЕсли; + + Если СтарыеКомбинации.Количество() >= МаксимумКомбинаций Тогда + Возврат Неопределено; + КонецЕсли; + + Если ТипЗнч(Источник) = Тип("ТаблицаЗначений") Тогда + НовыеКомбинации = Источник.Скопировать(, Поля); + Иначе + НовыеКомбинации = Источник.Выгрузить(, Поля); + КонецЕсли; + НовыеКомбинации.Свернуть(Поля); + + Если НовыеКомбинации.Количество() >= МаксимумКомбинаций Тогда + Возврат Неопределено; + КонецЕсли; + + СоставИзменений = НовыеКомбинации.Скопировать(Новый Массив); + + НовыеКомбинации.Колонки.Добавить("ВидИзменения", Новый ОписаниеТипов("Число")); + НовыеКомбинации.ЗаполнитьЗначения(1, "ВидИзменения"); + Для Каждого Строка Из СтарыеКомбинации Цикл + НоваяСтрока = НовыеКомбинации.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); + НоваяСтрока.ВидИзменения = -1; + КонецЦикла; + НовыеКомбинации.Свернуть(Поля, "ВидИзменения"); + + Для Каждого Строка Из НовыеКомбинации Цикл + Если Строка.ВидИзменения <> 0 Тогда + ЗаполнитьЗначенияСвойств(СоставИзменений.Добавить(), Строка); + КонецЕсли; + КонецЦикла; + + Возврат ?(СоставИзменений.Количество() > 0, СоставИзменений, Null); + +КонецФункции + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений. +Процедура ПроверитьОбъектыНастроекДоступа() + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + УстановитьРазделяемуюБлокировку("Справочник.ГруппыВнешнихПользователей"); + УстановитьРазделяемуюБлокировку("Справочник.ВнешниеПользователи"); + УстановитьРазделяемуюБлокировку("Справочник.ГруппыПользователей"); + УстановитьРазделяемуюБлокировку("Справочник.Пользователи"); + УстановитьРазделяемуюБлокировку("Справочник.ПрофилиГруппДоступа"); + УстановитьРазделяемуюБлокировку("Справочник.ГруппыДоступа"); + +КонецПроцедуры + +// Для процедуры ПроверитьОбъектыНастроекДоступа. +Процедура УстановитьРазделяемуюБлокировку(ИмяТаблицы) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ИмяТаблицы); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// См. УправлениеДоступом.УстановитьБлокировкуПередЗаписьюВФайловойИБ +Процедура УстановитьБлокировкуПередЗаписьюВФайловойИБ(ПередЗаписьюНовогоОбъекта = Ложь, + ПередЗаписьюНастройкиДоступа = Ложь) Экспорт + + Если ПередЗаписьюНастройкиДоступа Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(,, Истина); + ИначеЕсли ПередЗаписьюНовогоОбъекта Тогда + ПредварительнаяБлокировкаПередЗаписьюНовогоВФайловойИБ(); + Иначе + ПредварительнаяБлокировкаПередЗаписьюСуществующегоВФайловойИБ(); + КонецЕсли; + +КонецПроцедуры + +Процедура ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(ЭтоОшибкаБлокировки = Ложь, + ОбновлениеПараметров = Ложь, ЭтоЗаписьОбъектаНастроекДоступа = Ложь) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Константа.КоличествоПотоковОбновленияДоступа"); + Если Не ЭтоСеансФоновогоОбновленияДоступа() Тогда + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + + Если ЭтоЗаписьОбъектаНастроекДоступа Тогда + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); + Если Не ОбновлениеПараметров Тогда + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаПользователей"); + Попытка + Блокировка.Заблокировать(); + Исключение + ЭтоОшибкаБлокировки = Истина; + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для вызова и модуля менеджера справочника ГруппыДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа(ГруппыДоступа, + ТипыИзмененныхУчастников, ПриЗагрузке = Ложь) Экспорт + + Если Не ТипыИзмененныхУчастников.Пользователи + И Не ТипыИзмененныхУчастников.ВнешниеПользователи Тогда + Возврат; + КонецЕсли; + + Описание = ?(ПриЗагрузке, + "ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступаПриЗагрузке", + "ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа"); + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "УчастникиГруппДоступа"); + + Запрос = Новый Запрос; + + Если ГруппыДоступа = Неопределено Тогда + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа"; + Иначе + Запрос.УстановитьПараметр("ГруппыДоступа", ГруппыДоступа); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + |ГДЕ + | ТаблицыГруппДоступа.ГруппаДоступа В(&ГруппыДоступа)"; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Таблицы = Запрос.Выполнить().Выгрузить(); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, Описание, + ТипыИзмененныхУчастников.Пользователи, ТипыИзмененныхУчастников.ВнешниеПользователи, Истина); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедуры ПослеОбновленияСоставовГруппПользователей и +// модуля менеджера справочника ГруппыДоступа. +// +Процедура ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа(ИзмененныеУчастники, + ПриЗагрузке = Ложь, ПослеУстановкиПользователяИБ = Ложь) + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Описание = ?(ПослеУстановкиПользователяИБ, + "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступаПослеУстановкиПользователяИБ", + ?(ПриЗагрузке, + "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступаПриЗагрузке", + "ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа")); + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "СоставыГруппПользователей"); + + Если ИзмененныеУчастники = Неопределено Тогда + ДляПользователей = Истина; + ДляВнешнихПользователей = Истина; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа"; + Иначе + ДляПользователей = Ложь; + ДляВнешнихПользователей = Ложь; + + Для Каждого Участник Из ИзмененныеУчастники Цикл + Если ТипЗнч(Участник) = Тип("СправочникСсылка.Пользователи") + Или ТипЗнч(Участник) = Тип("СправочникСсылка.ГруппыПользователей") Тогда + + ДляПользователей = Истина; + + ИначеЕсли ТипЗнч(Участник) = Тип("СправочникСсылка.ВнешниеПользователи") + Или ТипЗнч(Участник) = Тип("СправочникСсылка.ГруппыВнешнихПользователей") Тогда + + ДляВнешнихПользователей = Истина; + КонецЕсли; + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИзмененныеУчастники", ИзмененныеУчастники); + Если ПослеУстановкиПользователяИБ Тогда + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ПО ТаблицыГруппДоступа.ГруппаДоступа = УчастникиГруппДоступа.Ссылка + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.Пользователь В (&ИзмененныеУчастники)) + | И (СоставыГруппПользователей.ГруппаПользователей = УчастникиГруппДоступа.Пользователь)"; + Иначе + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ПО ТаблицыГруппДоступа.ГруппаДоступа = УчастникиГруппДоступа.Ссылка + | И (УчастникиГруппДоступа.Пользователь В (&ИзмененныеУчастники))"; + КонецЕсли; + КонецЕсли; + + Таблицы = Запрос.Выполнить().Выгрузить(); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, + Описание, ДляПользователей, ДляВнешнихПользователей, Истина); + + ЗапланироватьОбновлениеНаборовГруппДоступа(Описание, ДляПользователей, ДляВнешнихПользователей); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для вызова из модуля менеджера регистра ТаблицыГруппДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа(Таблицы) Экспорт + + Описание = "ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа"; + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ТаблицыГруппДоступа"); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(Таблицы, Описание, Истина, Истина); + +КонецПроцедуры + +// Для вызова из модуля объекта и модуля менеджера справочника ПрофилиГруппДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРолейПрофиля(Описание, ИзмененныеРоли) Экспорт + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "РолиПрофилейГруппДоступа"); + + Если ИзмененныеРоли = Неопределено + Или ИзмененныеРоли.Количество() > 0 Тогда + + ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли); + КонецЕсли; + +КонецПроцедуры + +// Для вызова из модуля объекта и модуля менеджера справочника ГруппыДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииПрофиляГруппыДоступа(Описание, ИзмененныеРоли, ПрофильИзменен) Экспорт + + Если ПрофильИзменен Тогда + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ГруппыДоступаПрофилей"); + КонецЕсли; + + Если ИзмененныеРоли = Неопределено + Или ИзмененныеРоли.Количество() > 0 Тогда + + ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииРолейПрофиля и +// ЗапланироватьОбновлениеДоступаПриИзмененииПрофиляГруппыДоступа. +// +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРолей(Описание, ИзмененныеРоли) + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + Если Не ЗначениеЗаполнено(ДействующиеПараметры.ВедущиеРоли) Тогда + Возврат; + КонецЕсли; + + Если ИзмененныеРоли <> Неопределено Тогда + МетаданныеРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИзмененныеРоли, Ложь); + ИменаРолей = Новый Соответствие; + Для Каждого КлючИЗначение Из МетаданныеРолей Цикл + Если ТипЗнч(КлючИЗначение.Значение) = Тип("ОбъектМетаданных") Тогда + ИменаРолей.Вставить(КлючИЗначение.Значение.Имя, Истина); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + СпискиДляПользователей = Новый Массив; + СпискиДляВнешнихПользователей = Новый Массив; + ДобавленныеСпискиДляПользователей = Новый Соответствие; + ДобавленныеСпискиДляВнешнихПользователей = Новый Соответствие; + + Для Каждого ОписаниеВедущейРоли Из ДействующиеПараметры.ВедущиеРоли Цикл + Если ИзмененныеРоли <> Неопределено + И ИменаРолей.Получить(ОписаниеВедущейРоли.Ключ) = Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавитьСпискиВедущейРолиДляОбновленияПрав(СпискиДляПользователей, + ОписаниеВедущейРоли.Значение.ДляПользователей, ДобавленныеСпискиДляПользователей); + ДобавитьСпискиВедущейРолиДляОбновленияПрав(СпискиДляВнешнихПользователей, + ОписаниеВедущейРоли.Значение.ДляВнешнихПользователей, ДобавленныеСпискиДляВнешнихПользователей); + КонецЦикла; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.КлючиДоступаКДанным = Ложь; + ПараметрыПланирования.Описание = Описание; + + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); + + ПараметрыПланирования.ДляПользователей = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеДоступаПриИзмененииРолей. +Процедура ДобавитьСпискиВедущейРолиДляОбновленияПрав(Списки, СпискиВедущейРоли, ДобавленныеСписки) + + Если Не ЗначениеЗаполнено(СпискиВедущейРоли) Тогда + Возврат; + КонецЕсли; + + Для Каждого ОписаниеСписка Из СпискиВедущейРоли Цикл + Если ДобавленныеСписки.Получить(ОписаниеСписка.Ключ) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавленныеСписки.Вставить(ОписаниеСписка.Ключ, Истина); + Списки.Добавить(ОписаниеСписка.Ключ); + КонецЦикла; + +КонецПроцедуры + +// Для вызова из модуля менеджера регистра ЗначенияГруппДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений(ГруппыДоступаИТипыЗначений) Экспорт + + Описание = "ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений"; + + ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, "ЗначенияГруппДоступа"); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ГруппыДоступаИТипыЗначений", ГруппыДоступаИТипыЗначений); + Запрос.Текст = + "ВЫБРАТЬ + | ГруппыДоступаИТипыЗначений.ГруппаДоступа КАК ГруппаДоступа, + | ГруппыДоступаИТипыЗначений.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ПОМЕСТИТЬ ГруппыДоступаИТипыЗначений + |ИЗ + | &ГруппыДоступаИТипыЗначений КАК ГруппыДоступаИТипыЗначений + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТаблицыГруппДоступа.Таблица КАК Таблица, + | ТИПЗНАЧЕНИЯ(ГруппыДоступаИТипыЗначений.ТипЗначенийДоступа) КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГруппыДоступаИТипыЗначений КАК ГруппыДоступаИТипыЗначений + | ПО ТаблицыГруппДоступа.ГруппаДоступа = ГруппыДоступаИТипыЗначений.ГруппаДоступа + |ИТОГИ ПО + | Таблица"; + + ТаблицыИТипыЗначенийДоступа = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + + ЗапланироватьОбновлениеПользователейКлючейДоступа(ТаблицыИТипыЗначенийДоступа.Строки, + Описание, Истина, Истина); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеДоступа, ЗапланироватьОбновлениеПараметровОграниченияДоступа. +Функция СлужебныйИдентификатор(ПолноеИмя) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПолноеИмя", ПолноеИмя); + Запрос.Текст = + "ВЫБРАТЬ + | ИдентификаторыОбъектовМетаданных.Ссылка КАК Ссылка + |ИЗ + | Справочник.ИдентификаторыОбъектовМетаданных КАК ИдентификаторыОбъектовМетаданных + |ГДЕ + | ИдентификаторыОбъектовМетаданных.ПолноеИмя = &ПолноеИмя + | + |УПОРЯДОЧИТЬ ПО + | ИдентификаторыОбъектовМетаданных.ПометкаУдаления"; + + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + Возврат Выборка.Ссылка; + КонецЕсли; + + Возврат Null; + +КонецФункции + +// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений. +// +Процедура ЗапланироватьОбновлениеПользователейКлючейДоступа(ОписаниеСписков, Описание, ДляПользователей, + ДляВнешнихПользователей, ПриИзмененииУчастниковГруппыДоступа = Ложь, ВедущийОбъект = Неопределено) + + Если ОписаниеСписков.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Контекст = Новый Структура; + Контекст.Вставить("ПриИзмененииУчастниковГруппыДоступа", ПриИзмененииУчастниковГруппыДоступа); + Контекст.Вставить("ИдентификаторТранзакции", Новый УникальныйИдентификатор); + Контекст.Вставить("Список", Неопределено); + Контекст.Вставить("ПолноеИмя", Неопределено); + Контекст.Вставить("ТипыЗначенийДоступа", Неопределено); + + Если ТипЗнч(ОписаниеСписков) = Тип("ФиксированныйМассив") Тогда + ИдентификаторыСписковПоПолнымИменам = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ОписаниеСписков); + Иначе + ПолныеИмена = ОписаниеСписков.ВыгрузитьКолонку("Таблица"); + ОбъектыМетаданныхСписков = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ПолныеИмена, Ложь); + КонецЕсли; + + Списки = Новый Массив; + СпискиДляПользователей = Новый Массив; + СпискиДляВнешнихПользователей = Новый Массив; + + Для Каждого ОписаниеСписка Из ОписаниеСписков Цикл + Если ИдентификаторыСписковПоПолнымИменам <> Неопределено Тогда + Контекст.ПолноеИмя = ОписаниеСписка; + Контекст.Список = ИдентификаторыСписковПоПолнымИменам.Получить(Контекст.ПолноеИмя); + Иначе + ОбъектМетаданных = ОбъектыМетаданныхСписков.Получить(ОписаниеСписка.Таблица); + Контекст.ПолноеИмя = ?(ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных"), ОбъектМетаданных.ПолноеИмя(), ""); + Контекст.Список = ОписаниеСписка.Таблица; + Если ТипЗнч(ОписаниеСписка) = Тип("СтрокаДереваЗначений") Тогда + Контекст.ТипыЗначенийДоступа = ОписаниеСписка.Строки; + КонецЕсли; + КонецЕсли; + Если Не ЗначениеЗаполнено(Контекст.ПолноеИмя) Тогда + Продолжить; + КонецЕсли; + ЗапланироватьДляПользователей = ДляПользователей + И ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, Ложь); + + ЗапланироватьДляВнешнихПользователей = ДляВнешнихПользователей + И ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, Истина); + + Если ЗапланироватьДляПользователей И ЗапланироватьДляВнешнихПользователей Тогда + Списки.Добавить(Контекст.ПолноеИмя); + + ИначеЕсли ЗапланироватьДляПользователей Тогда + СпискиДляПользователей.Добавить(Контекст.ПолноеИмя); + + ИначеЕсли ЗапланироватьДляВнешнихПользователей Тогда + СпискиДляВнешнихПользователей.Добавить(Контекст.ПолноеИмя); + КонецЕсли; + КонецЦикла; + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.КлючиДоступаКДанным = Ложь; + ПараметрыПланирования.ВедущийОбъект = ВедущийОбъект; + ПараметрыПланирования.Описание = Описание; + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ЗапланироватьОбновлениеДоступа(СпискиДляПользователей, ПараметрыПланирования); + + ПараметрыПланирования.ДляПользователей = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Истина; + ЗапланироватьОбновлениеДоступа(СпискиДляВнешнихПользователей, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ЗапланироватьОбновлениеПользователейКлючейДоступа. +Функция ТребуетсяОбновлениеПользователейКлючейДоступа(Контекст, ДляВнешнихПользователей) + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Контекст.ИдентификаторТранзакции, Неопределено, Ложь); + Если ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + + Если Не Контекст.ПриИзмененииУчастниковГруппыДоступа + И ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(Контекст.ПолноеИмя) <> Неопределено + И ДополнительныйКонтекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(Контекст.ПолноеИмя) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + + СвойстваОграничения = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Контекст.ПолноеИмя); + + Если ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(Контекст.ПолноеИмя) <> Неопределено + Или СвойстваОграничения = Неопределено + Или СвойстваОграничения.ДоступЗапрещен + Или СвойстваОграничения.ПолеВладельца <> Неопределено + И Не СвойстваОграничения.ПолеВладельца.Отключено + Или Контекст.ПриИзмененииУчастниковГруппыДоступа + И Не СвойстваОграничения.РассчитыватьПраваПользователей Тогда + + Возврат Ложь; + КонецЕсли; + + Если СвойстваОграничения <> Неопределено + И Контекст.ТипыЗначенийДоступа <> Неопределено + И Не Контекст.ПриИзмененииУчастниковГруппыДоступа Тогда + + СредиИзмененныхТиповЗначенийДоступаНетИспользуемых = Истина; + ИспользуемыеТипыЗначенийДоступа = СвойстваОграничения.ИспользуемыеТипыЗначенийДоступа.Получить(); // Массив из Тип + Для Каждого Строка Из Контекст.ТипыЗначенийДоступа Цикл + Если ИспользуемыеТипыЗначенийДоступа.Найти(Строка.ТипЗначенийДоступа) <> Неопределено Тогда + СредиИзмененныхТиповЗначенийДоступаНетИспользуемых = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если СредиИзмененныхТиповЗначенийДоступаНетИспользуемых Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для процедуры ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа и +// модулей менеджера и объекта справочника ГруппыДоступа. +// +Процедура ЗапланироватьОбновлениеНаборовГруппДоступа(Описание, ДляПользователей = Истина, ДляВнешнихПользователей = Истина) Экспорт + + Если Не ДляПользователей И Не ДляВнешнихПользователей Тогда + Возврат; + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + + Список = "Справочник.НаборыГруппДоступа"; + КлючУникальности = Новый УникальныйИдентификатор; + ИдентификаторСписка = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Список); + ТекущаяДата = ТекущаяДатаСеанса(); + МаксимальнаяДата = МаксимальнаяДата(); + + // Обновление только по изменениям (не полное). + ПараметрыЗадания = Новый Структура; + УстановитьВидКлючаДанных(ПараметрыЗадания, "НовыеНаборыИзОдногоПользователя"); + ХранилищеПараметровЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); + + Если ДляПользователей Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальности; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Ложь; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = 3; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДата; + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючУникальности = КлючУникальности; + НоваяЗапись.Список = ИдентификаторСписка; + НоваяЗапись.ДляВнешнихПользователей = Истина; + НоваяЗапись.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата; + НоваяЗапись.ПараметрыЗадания = ХранилищеПараметровЗадания; + НоваяЗапись.РазмерЗадания = 3; + НоваяЗапись.ДатаИзмененияЗаписиРегистра = ТекущаяДата; + КонецЕсли; + + НаборЗаписей.Записать(Ложь); + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = Ложь; + ПараметрыПланирования.ДляПользователей = ДляПользователей; + ПараметрыПланирования.ДляВнешнихПользователей = ДляВнешнихПользователей; + ПараметрыПланирования.Описание = Описание; + + СпискиПоИдентификаторам = Новый Соответствие; + СпискиПоИдентификаторам.Вставить(ИдентификаторСписка, Список); + + ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования); + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + +КонецПроцедуры + +// Для процедур ЗапланироватьОбновлениеДоступаПриИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриКосвенномИзмененииУчастниковГруппыДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииТаблицГруппДоступа, +// ЗапланироватьОбновлениеДоступаПриИзмененииРазрешенныхЗначений. +// +Процедура ЗапланироватьОбновлениеКэшаРасчетаПрав(Описание, ИмяИзмененныхДанных) + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.КлючиДоступаКДанным = Ложь; + ПараметрыПланирования.ДляВнешнихПользователей = Ложь; + ПараметрыПланирования.Описание = Описание; + ПараметрыПланирования.ВедущийОбъект = Новый Структура("ПоДаннымКэшаРасчетаПрав", ИмяИзмененныхДанных); + ЗапланироватьОбновлениеДоступа(СписокДляПланированияОбновленияКэшаРасчетаПрав(), ПараметрыПланирования); + +КонецПроцедуры + +// Для процедур ПодготовитьПланОбновления, ЗапланироватьОбновлениеКэшаРасчетаПрав +// и функции ВерсияДанныхДляКэшаРасчетаПрав. +// +Функция СписокДляПланированияОбновленияКэшаРасчетаПрав() + + Возврат "РегистрСведений.ПараметрыРаботыВерсийРасширений"; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ТаблицыГруппДоступа - Строка +// - Неопределено +// * ЗначенияГруппДоступа - Строка +// - Неопределено +// * УчастникиГруппДоступа - Строка +// - Неопределено +// * СоставыГруппПользователей - Строка +// - Неопределено +// * РолиПрофилейГруппДоступа - Строка +// - Неопределено +// * ГруппыДоступаПрофилей - Строка +// - Неопределено +// +Функция НоваяВерсияДанныхДляКэшаРасчетаПрав(Версия = Неопределено) Экспорт + + НоваяВерсияДанных = Новый Структура; + НоваяВерсияДанных.Вставить("ТаблицыГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("ЗначенияГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("УчастникиГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("СоставыГруппПользователей", Версия); + НоваяВерсияДанных.Вставить("РолиПрофилейГруппДоступа", Версия); + НоваяВерсияДанных.Вставить("ГруппыДоступаПрофилей", Версия); + + Возврат НоваяВерсияДанных; + +КонецФункции + +// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. +Функция ИмяПараметраВерсииДанныхДляКэшаРасчетаПрав() + + Возврат "СтандартныеПодсистемы.УправлениеДоступом.ВерсияДанныхДляКэшаРасчетаПрав"; + +КонецФункции + +#КонецОбласти + +#Область ОбновлениеДоступа + +// Для процедуры ЗапуститьОбновлениеДоступа. +Функция ЕстьЗапланированныеТочечныеЗадания() + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("СписокДляПланированияОбновленияКэшаРасчетаПрав", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных(СписокДляПланированияОбновленияКэшаРасчетаПрав(), Ложь)); + + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + |ГДЕ + | ОбновлениеКлючейДоступаКДанным.ТочечноеЗадание + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей + |ГДЕ + | ОбновлениеКлючейДоступаПользователей.ТочечноеЗадание + | И ОбновлениеКлючейДоступаПользователей.Список <> &СписокДляПланированияОбновленияКэшаРасчетаПрав"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Запускает фоновое задание обновления доступа вместо регламентного задания. +// +// Параметры: +// ЭтоЗапускВручную - Булево - если передать Ложь, то наименование будет начинаться с "Автозапуск", +// в противном случае, наименование будет начинаться с "Запуск вручную", +// блокировка обновления доступа будет снята, если была установлена, +// выполнение будет продолжаться до полного завершения. +// ЭтоПерезапуск - Булево - если передать Истина, тогда текущий сеанс фонового задания не будет +// считаться незавершенным исполнителем. +// ДляУскорения - Булево - если передать Истина, тогда признак передается в процедуру обновления доступа, +// чтобы прекратить обновление, когда точечных заданий нет и функция +// ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий возвращает Истина. +// +// Возвращаемое значение: +// - Неопределено - обновление доступа не требуется или запрещено. +// - Структура: +// * УжеВыполняется - Булево - если обновление уже выполняется. +// +// * ИдентификаторФоновогоЗадания - Неопределено - если обновление не выполняется или +// выполняется не в фоновом задании. +// - УникальныйИдентификатор - идентификатор фонового задания. +// +// * СвойстваСеанса - Неопределено - если запуска не было или фоновое задание только добавлено в очередь. +// - Структура - со свойствами сеанса, если обновление уже выполняется: +// ** ИмяКомпьютера - Строка - одноименное свойства объекта СеансИнформационнойБазы. +// ** НомерСеанса - Число - одноименное свойства объекта СеансИнформационнойБазы. +// ** НачалоСеанса - Строка - одноименное свойства объекта СеансИнформационнойБазы. +// +// * ТекстПредупреждения - Неопределено - если запуска не было или запущено новое фоновое задание. +// - Строка - описание, что обновление доступа уже запущено. +// +Функция ЗапуститьОбновлениеДоступаНаУровнеЗаписей(ЭтоЗапускВручную = Ложь, ЭтоПерезапуск = Ложь, ДляУскорения = Ложь) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Если Не ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно запустить обновление доступа на уровне записей, так как + |константа %1 выключена.'"), + "ОграничиватьДоступНаУровнеЗаписейУниверсально"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ТранзакцияАктивна() Тогда + ТекстОшибки = + НСтр("ru = 'Невозможно запустить обновление доступа на уровне записей в открытой транзакции.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Не ЭтоЗапускВручную И Не ЗапланированоОбновлениеДоступа() Тогда + Возврат Неопределено; + КонецЕсли; + + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(); + Если Не ЭтоЗапускВручную И ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Возврат Неопределено; + КонецЕсли; + + ИдентификаторИсключаемогоЗадания = Неопределено; + Если ЭтоПерезапуск Тогда + ТекущееФоновоеЗадание = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание(); + Если ТекущееФоновоеЗадание <> Неопределено Тогда + ИдентификаторИсключаемогоЗадания = ТекущееФоновоеЗадание.УникальныйИдентификатор; + КонецЕсли; + КонецЕсли; + Результат = Новый Структура("УжеВыполняется, ТекстПредупреждения, ИдентификаторФоновогоЗадания, СвойстваСеанса", Истина, ""); + Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторИсключаемогоЗадания); + + Если Исполнитель = Неопределено Тогда + Результат.УжеВыполняется = Ложь; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Попытка + // В файловой ИБ перезапуск фонового задания с расширениями базы данных + // выполняется с той же версией динамического поколения конфигурации. + СтандартныеПодсистемыСервер.ПроверитьДинамическоеОбновлениеВерсииПрограммы(); + Исключение + Результат.ТекстПредупреждения = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); + Возврат Результат; + КонецПопытки; + КонецЕсли; + Если ЭтоЗапускВручную Тогда + УстановитьЗапретОбновленияДоступа(Ложь); + ПараметрыЗадания = Новый Массив; + ПараметрыЗадания.Добавить(Истина); + ИначеЕсли ЭтоПерезапуск Или ДляУскорения Тогда + ДополнительныеПараметры = НовыеДополнительныеПараметрыОбновленияДоступа(); + ДополнительныеПараметры.ЭтоПерезапуск = ЭтоПерезапуск; + ДополнительныеПараметры.ДляУскорения = ДляУскорения; + ПараметрыЗадания = Новый Массив; + ПараметрыЗадания.Добавить(Ложь); + ПараметрыЗадания.Добавить(Ложь); + ПараметрыЗадания.Добавить(ДополнительныеПараметры); + Иначе + ПараметрыЗадания = Неопределено; + КонецЕсли; + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + НаименованиеЗадания = + ?(ЭтоЗапускВручную, + НСтр("ru = 'Запуск вручную'", ОбщегоНазначения.КодОсновногоЯзыка()), + НСтр("ru = 'Автозапуск'", ОбщегоНазначения.КодОсновногоЯзыка())) + + ": " + Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.Синоним + " (" + + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'из сеанса %1 от %2'", ОбщегоНазначения.КодОсновногоЯзыка()), + Формат(ТекущийСеанс.НомерСеанса, "ЧГ="), + Формат(ТекущийСеанс.НачалоСеанса, "ДЛФ=DT")) + ")"; + + ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных( + ИмяМетодаЗаданияОбновленияДоступа(), ПараметрыЗадания,, НаименованиеЗадания); + + Результат.ИдентификаторФоновогоЗадания = ФоновоеЗадание.УникальныйИдентификатор; + + ИначеЕсли ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") + И Исполнитель.УникальныйИдентификатор <> ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания Тогда + + Результат.ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже запущено %1 в %2'"), + Формат(Исполнитель.Начало, "ДЛФ=D"), + Формат(Исполнитель.Начало, "ДЛФ=T")); + Иначе + СвойстваСеанса = Новый Структура("ИмяКомпьютера, НомерСеанса, НачалоСеанса"); + Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") Тогда + ЗаполнитьЗначенияСвойств(СвойстваСеанса, ПоследнееОбновлениеДоступа); + Иначе + ЗаполнитьЗначенияСвойств(СвойстваСеанса, Исполнитель); + КонецЕсли; + Результат.СвойстваСеанса = СвойстваСеанса; + Результат.ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обновление доступа уже выполняется + |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), + СвойстваСеанса.ИмяКомпьютера, + СвойстваСеанса.НомерСеанса, + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=D"), + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=T")); + КонецЕсли; + + Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") Тогда + Результат.ИдентификаторФоновогоЗадания = Исполнитель.УникальныйИдентификатор; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Отменить обновление доступа, которое выполняется в фоновом задании. +Процедура ОтменитьОбновлениеДоступаНаУровнеЗаписей() Экспорт + + Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа()); + + Если ТипЗнч(Исполнитель) = Тип("СеансИнформационнойБазы") Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно отменить полное обновление доступа + |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), + Исполнитель.ИмяКомпьютера, + Исполнитель.НомерСеанса, + Формат(Исполнитель.НачалоСеанса, "ДЛФ=D"), + Формат(Исполнитель.НачалоСеанса, "ДЛФ=T")); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Выполняется = ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание"); + + ЗавершитьПотокиОбновленияДоступа(Истина); + УстановитьЗапретОбновленияДоступа(Истина, Выполняется); + + Если Выполняется Тогда + Исполнитель = Исполнитель.ОжидатьЗавершенияВыполнения(СекундОжиданияЗавершенияФоновогоЗадания()); + Если Исполнитель.Состояние = СостояниеФоновогоЗадания.Активно Тогда + Исполнитель.Отменить(); + КонецЕсли; + КонецЕсли; + + Отбор = Новый Структура; + Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно); + Отбор.Вставить("ИмяМетода", ИмяМетодаЗаданияОбновленияДоступа()); + ОсновныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); + + Для Каждого ОсновноеЗадание Из ОсновныеЗадания Цикл + ОсновноеЗадание = ОсновноеЗадание.ОжидатьЗавершенияВыполнения(1); + Если ОсновноеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + ОсновноеЗадание.Отменить(); + КонецЕсли; + КонецЦикла; + + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(); + +КонецПроцедуры + +// Для процедуры УстановитьОбновлениеДоступа. +Процедура ВключитьРегламентноеЗаданиеОбновленияДоступа() Экспорт + + ИзменитьРегламентноеЗаданиеОбновленияДоступа(Истина); + +КонецПроцедуры + +// Для процедуры УстановитьОбновлениеДоступа. +Процедура ОтключитьРегламентноеЗаданиеОбновленияДоступа() Экспорт + + ИзменитьРегламентноеЗаданиеОбновленияДоступа(Ложь); + +КонецПроцедуры + +// Для процедуры УстановитьОбновлениеДоступа. +Процедура ИзменитьРегламентноеЗаданиеОбновленияДоступа(ВключитьЗадание) + + Отбор = Новый Структура("Метаданные", Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); + + ТребуетсяИзменить = Ложь; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ТребуетсяИзменить = Истина; + Иначе + УстановитьПривилегированныйРежим(Истина); + Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); + Для Каждого Задание Из Задания Цикл + Если ВключитьЗадание <> Задание.Использование Тогда + ТребуетсяИзменить = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + УстановитьПривилегированныйРежим(Ложь); + КонецЕсли; + + Если Не ТребуетсяИзменить Тогда + Возврат; + КонецЕсли; + + ЭтоОшибкаБлокировки = Ложь; + НомерПопыткиБлокировки = 0; + Пока Истина Цикл + НомерПопыткиБлокировки = НомерПопыткиБлокировки + 1; + НачатьТранзакцию(); + Попытка + ЭтоОшибкаБлокировки = Истина; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + РегламентныеЗаданияСервер.ЗаблокироватьРегламентноеЗадание(Новый УникальныйИдентификатор); + КонецЕсли; + ЭтоОшибкаБлокировки = Ложь; + УстановитьПривилегированныйРежим(Истина); + Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор); + Для Каждого Задание Из Задания Цикл + Если ВключитьЗадание = Задание.Использование Тогда + Продолжить; + КонецЕсли; + РегламентныеЗаданияСервер.ИзменитьЗадание(Задание, + Новый Структура("Использование", ВключитьЗадание)); + КонецЦикла; + УстановитьПривилегированныйРежим(Ложь); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + Если ЭтоОшибкаБлокировки + И НомерПопыткиБлокировки <= 3 + И Не ТранзакцияАктивна() Тогда + Продолжить; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + Прервать; + КонецЦикла; + +КонецПроцедуры + +// Включает или отключает запрет обновления доступа при запуске +// с помощью регламентного задания или при программном запуске. +// +// При вызове процедуры ОбновлениеДоступаНаУровнеЗаписей +// с признаком ОбновитьВсе запрет игнорируется. +// +// При вызове процедуры ЗапуститьОбновлениеДоступаНаУровнеЗаписей +// с признаком ЭтоЗапускВручную запрет снимается автоматически. +// +Процедура УстановитьЗапретОбновленияДоступа(Использование, ОтменитьОбновление = Ложь) Экспорт + + БлокировкаДанных = Новый БлокировкаДанных; + БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); + + ЕстьВнешняяТранзакция = ТранзакцияАктивна(); + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + Записать = Ложь; + Если ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено <> Использование Тогда + ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено = Использование; + Записать = Истина; + КонецЕсли; + + Если ОтменитьОбновление + И ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере > ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере + И ( Не ПоследнееОбновлениеДоступа.ОбновлениеОтменено + Или ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения <> "") Тогда + + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Истина; + ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ""; + ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = '00010101'; + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере = ТекущаяДатаНаСервере(); + ПоследнееОбновлениеДоступа.ПоследнееВыполнениеСекунд = + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере + + СекундОжиданияЗавершенияФоновогоЗадания() + 1; + Записать = Истина; + КонецЕсли; + + Если Записать Тогда + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедур ОтменитьОбновлениеДоступаНаУровнеЗаписей, УстановитьЗапретОбновленияДоступа. +Функция СекундОжиданияЗавершенияФоновогоЗадания() + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Возврат 3; + Иначе + Возврат 15; + КонецЕсли; + +КонецФункции + +// Обработчик регламентного задания ОбновлениеДоступаНаУровнеЗаписей. +Процедура ОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе = Ложь, ВызыватьИсключениеВместоРегистрацииОшибки = Ложь, + ДополнительныеПараметры = Неопределено) Экспорт + + // Регламентное задание должно запускаться сразу, как только было запланировано обновление доступа. + // После обработки первой порции по всем таблицам (2 мин на все) можно сделать + // небольшую паузу вместо непрерывного выполнения до конца. + // В данном случае пауза - это перезапуск через 15 секунд. + // В отличие от обычных регламентных заданий это задание самоотключаемое, + // то есть после отработки запланированного обновления, задание выключает само себя и + // запуски полностью прекращаются до того, как будет запланировано новое обновление доступа. + + ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания( + Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей); + + ВыполнитьОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе, ВызыватьИсключениеВместоРегистрацииОшибки, + 0, , ДополнительныеПараметры); + +КонецПроцедуры + +// Только для внутреннего использования. +// +// Возвращаемое значение: +// Структура: +// * ДляУскорения - Булево +// * ЭтоПерезапуск - Булево +// +Функция НовыеДополнительныеПараметрыОбновленияДоступа() + + Результат = Новый Структура; + Результат.Вставить("ДляУскорения", Ложь); + Результат.Вставить("ЭтоПерезапуск", Ложь); + + Возврат Результат; + +КонецФункции + +// Выполняет обновление доступа, если запланировано. +Процедура ВыполнитьОбновлениеДоступаНаУровнеЗаписей(ОбновитьВсе, ВызыватьИсключениеВместоРегистрацииОшибки, + СекундНеБолее, ПослеОбновлениеИБ = Ложь, ДополнительныеПараметры = Неопределено) + + Если ОбновитьВсе Тогда + СекундНеБолее = 0; + КонецЕсли; + + НовыеДополнительныеПараметры = НовыеДополнительныеПараметрыОбновленияДоступа(); + Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда + ЗаполнитьЗначенияСвойств(НовыеДополнительныеПараметры, ДополнительныеПараметры); + КонецЕсли; + ДополнительныеПараметры = НовыеДополнительныеПараметры; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + УстановитьЭтоСеансФоновогоОбновленияДоступа(); + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + ОписаниеОсновногоСеанса = ОписаниеОсновногоСеанса(); + ОписаниеОсновногоСеанса.Вставить("НомерСеанса", ТекущийСеанс.НомерСеанса); + ОписаниеОсновногоСеанса.Вставить("НачалоСеанса", ТекущийСеанс.НачалоСеанса); + + Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда + Если ОбновитьВсе Тогда + ИдентификаторФоновогоЗадания = ИдентификаторПроизвольногоСеанса(); + Иначе + ТекстОшибки = НСтр("ru = 'Обновление доступа может выполняться порциями только в фоновом задании.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ИдентификаторОсновногоСеанса = Строка(Новый УникальныйИдентификатор); + Иначе + ТекущееФоновоеЗадание = ТекущийСеанс.ПолучитьФоновоеЗадание(); + Если ТекущееФоновоеЗадание = Неопределено Тогда + ТекстОшибки = НСтр("ru = 'Не удалось получить фоновое задание текущего сеанса.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ИдентификаторФоновогоЗадания = ТекущееФоновоеЗадание.УникальныйИдентификатор; + ОписаниеОсновногоСеанса.ФоновоеЗадание = ТекущееФоновоеЗадание; + ОписаниеОсновногоСеанса.ИдентификаторФоновогоЗадания = ИдентификаторФоновогоЗадания; + ИдентификаторОсновногоСеанса = Строка(ИдентификаторФоновогоЗадания); + КонецЕсли; + ОписаниеОсновногоСеанса.Вставить("Идентификатор", ИдентификаторОсновногоСеанса + + " (" + НСтр("ru = 'Идентификатор основного сеанса'") + ")"); + + БлокировкаДанных = Новый БлокировкаДанных; + БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); + + ЕстьВнешняяТранзакция = ТранзакцияАктивна(); + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + Если ОбновитьВсе Или Не ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Исполнитель = ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторФоновогоЗадания); + + Если Исполнитель = Неопределено Тогда + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Ложь; + ПоследнееОбновлениеДоступа.ДляУскорения = ДополнительныеПараметры.ДляУскорения; + ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере = ТекущаяДатаНаСервере(); + ПоследнееОбновлениеДоступа.НомерСеанса = ТекущийСеанс.НомерСеанса; + ПоследнееОбновлениеДоступа.НачалоСеанса = ТекущийСеанс.НачалоСеанса; + ПоследнееОбновлениеДоступа.ИмяКомпьютера = ТекущийСеанс.ИмяКомпьютера; + ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = ИдентификаторФоновогоЗадания; + + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + КонецЕсли; + + Если ПоследнееОбновлениеДоступа.ДляУскорения И Не ДополнительныеПараметры.ДляУскорения Тогда + ПоследнееОбновлениеДоступа.ДляУскорения = Ложь; + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если Не ОбновитьВсе И ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено Тогда + Если ТекущееФоновоеЗадание.РегламентноеЗадание <> Неопределено Тогда + УстановитьОбновлениеДоступа(Ложь); + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обновление доступа запрещено. + |Чтобы разрешить нужно нажать ""Разрешить"" в форме ""Обновление доступа на уровне записей"". + |Форму можно открыть из панели ""Настройки пользователей и прав"" или перейти по навигационной ссылке: + |%1'"), + "e1cib/app/РегистрСведений.ОбновлениеКлючейДоступаКДанным.Форма.ОбновлениеДоступаНаУровнеЗаписей"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Исполнитель <> Неопределено Тогда + Если Не ОбновитьВсе Или ПослеОбновлениеИБ Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание") + И Исполнитель.УникальныйИдентификатор <> ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже запущено %1 в %2'"), + Формат(Исполнитель.Начало, "ДЛФ=D"), + Формат(Исполнитель.Начало, "ДЛФ=T")); + Иначе + СвойстваСеанса = ?(ТипЗнч(Исполнитель) = Тип("ФоновоеЗадание"), + ПоследнееОбновлениеДоступа, Исполнитель); + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось начать обновление доступа, так как оно уже выполняется + |(компьютер: %1, сеанс: %2, начат: %3 в %4)'"), + СвойстваСеанса.ИмяКомпьютера, + СвойстваСеанса.НомерСеанса, + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=D"), + Формат(СвойстваСеанса.НачалоСеанса, "ДЛФ=T")); + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Ложь; + ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ""; + ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор(); + + ПерезапускВозможен = ТекущееФоновоеЗадание <> Неопределено + И Не ОбновитьВсе + И Не ВызыватьИсключениеВместоРегистрацииОшибки + И СекундНеБолее = 0 + И Не ПослеОбновлениеИБ; + + ТекстВсехОшибок = ""; + ДатаПолногоЗавершения = ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения; + + ПараметрыВыполнения = Новый Структура; + ПараметрыВыполнения.Вставить("СекундНеБолее", СекундНеБолее); + ПараметрыВыполнения.Вставить("ТекстОшибкиПланирования", ""); + ПараметрыВыполнения.Вставить("ТекстОшибкиЗавершения", ""); + ПараметрыВыполнения.Вставить("ОписаниеОсновногоСеанса", ОписаниеОсновногоСеанса); + Попытка + Если ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда + ВыполнитьОбновлениеДоступа(ОбновитьВсе, ПараметрыВыполнения, ПоследнееОбновлениеДоступа); + Если Не ПерезапускВозможен Тогда + СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(ТекстВсехОшибок); + КонецЕсли; + Иначе + УстановитьОбновлениеДоступа(Ложь); + КонецЕсли; + Исключение + Если ТранзакцияАктивна() Тогда + ВызватьИсключение; + КонецЕсли; + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстВсехОшибок = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + Если ПерезапускВозможен + И СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + ТекстВсехОшибок = ""; + КонецЕсли; + КонецПопытки; + + Попытка + ЗавершитьПотокиОбновленияДоступа(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось завершить потоки обновления доступа по причине: + |%1'"), + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке))); + КонецПопытки; + + Попытка + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(2); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось отменить фоновые задания потоков обновления доступа по причине: + |%1'"), + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке))); + КонецПопытки; + + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, ПараметрыВыполнения.ТекстОшибкиПланирования); + ДобавитьТекстОшибкиЗавершения(ТекстВсехОшибок, ПараметрыВыполнения.ТекстОшибкиЗавершения); + + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере = ТекущаяДатаНаСервере(); + Если ЗначениеЗаполнено(ТекстВсехОшибок) Тогда + ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = '00010101'; + КонецЕсли; + Если Не ЗначениеЗаполнено(ДатаПолногоЗавершения) + Или ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения <> ДатаПолногоЗавершения Тогда + + ПоследнееОбновлениеДоступа.ТекстОшибкиЗавершения = ТекстВсехОшибок; + ПоследнееОбновлениеДоступа.ПоследнееВыполнениеСекунд = + ПоследнееОбновлениеДоступа.ДатаЗавершенияНаСервере - ПоследнееОбновлениеДоступа.ДатаЗапускаНаСервере; + КонецЕсли; + + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ТекущееПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + ПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено = + ТекущееПоследнееОбновлениеДоступа.ОбновлениеДоступаЗапрещено; + + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ПерезапускВозможен И СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + ЗапуститьОбновлениеДоступаНаУровнеЗаписей(, Истина, ПоследнееОбновлениеДоступа.ДляУскорения); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ТекстВсехОшибок) Тогда + Возврат; + КонецЕсли; + + ТекстВсехОшибок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось выполнить обновление доступа по причине: + |%1'"), ТекстВсехОшибок); + + Если ВызыватьИсключениеВместоРегистрацииОшибки Тогда + ВызватьИсключение ТекстВсехОшибок; + Иначе + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстВсехОшибок, + Новый Структура("ОписаниеОсновногоСеанса", ОписаниеОсновногоСеанса)); + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ИдентификаторФоновогоЗадания - УникальныйИдентификатор +// * ФоновоеЗадание - ФоновоеЗадание +// * НомерСеанса - Число +// * НачалоСеанса - Дата +// * Идентификатор - Строка - представление сеанса +// +Функция ОписаниеОсновногоСеанса() + + Возврат Новый Структура("ИдентификаторФоновогоЗадания, ФоновоеЗадание"); + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей. +Функция ЗапланированоОбновлениеДоступа() + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей и +// процедур ОбновлениеДоступаНаУровнеЗаписей, ОтменитьОбновлениеДоступаНаУровнеЗаписей и +// формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Возвращаемое значение: +// Структура: +// * ДатаЗапускаНаСервере - Дата +// * ДатаЗавершенияНаСервере - Дата +// * ОбновлениеОтменено - Булево +// * ПоследнееВыполнениеСекунд - Число +// * ДатаПолногоЗавершения - Дата +// * ТекстОшибкиЗавершения - Строка +// * НомерСеанса - Число +// * ИмяКомпьютера - Строка +// * ОбновлениеДоступаЗапрещено - Булево +// * БалансировкаНагрузкиНаДиск - Булево +// * ИдентификаторФоновогоЗадания - УникальныйИдентификатор +// * ПоследнееПланированиеОбработкиУстаревшихЭлементов - Дата +// +Функция ПоследнееОбновлениеДоступа(ТекущееЗначение = Неопределено) Экспорт + + Если ТекущееЗначение = Неопределено Тогда + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ПоследнееОбновлениеДоступа.Значение КАК Значение + |ИЗ + | Константа.ПоследнееОбновлениеДоступа КАК ПоследнееОбновлениеДоступа"; + + Выборка = Запрос.Выполнить().Выбрать(); + ТекущееЗначение = ?(Выборка.Следующий(), Выборка.Значение, Неопределено); + КонецЕсли; + + Свойства = Новый Структура; + Свойства.Вставить("ДатаЗапускаНаСервере", '00010101'); + Свойства.Вставить("ДатаЗавершенияНаСервере", '00010101'); + Свойства.Вставить("ОбновлениеОтменено", Ложь); + Свойства.Вставить("ПоследнееВыполнениеСекунд", 0); + Свойства.Вставить("ДатаПолногоЗавершения", '00010101'); + Свойства.Вставить("ТекстОшибкиЗавершения", ""); + Свойства.Вставить("НомерСеанса", 0); + Свойства.Вставить("НачалоСеанса", '00010101'); + Свойства.Вставить("ИмяКомпьютера", ""); + Свойства.Вставить("ОбновлениеДоступаЗапрещено", Ложь); + Свойства.Вставить("БалансировкаНагрузкиНаДиск", Истина); + Свойства.Вставить("ИдентификаторДоступа"); + Свойства.Вставить("ИдентификаторФоновогоЗадания", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + Свойства.Вставить("ПоследнееПланированиеОбработкиУстаревшихЭлементов", '00010101'); + Свойства.Вставить("ДляУскорения", Ложь); + + Если ТипЗнч(ТекущееЗначение) <> Тип("ХранилищеЗначения") Тогда + Возврат Свойства; + КонецЕсли; + + ТекущиеСвойства = ТекущееЗначение.Получить(); + + Если ТипЗнч(ТекущиеСвойства) <> Тип("Структура") Тогда + Возврат Свойства; + КонецЕсли; + + ЗаполнитьЗначенияСвойств(Свойства, ТекущиеСвойства); + + Возврат Свойства; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаНаУровнеЗаписей, +// УстановитьЗапретОбновленияДоступа и УстановитьБалансировкуНагрузкиНаДиск. +// +Процедура УстановитьПоследнееОбновлениеДоступа(Свойства, ЕстьВнешняяТранзакция) + + Если Не ЗначениеЗаполнено(Свойства.ИдентификаторДоступа) И Не ЕстьВнешняяТранзакция Тогда + Свойства.ИдентификаторДоступа = Новый УникальныйИдентификатор; + КонецЕсли; + + МенеджерЗначения = СлужебныйМенеджерЗначения(Константы.ПоследнееОбновлениеДоступа); + МенеджерЗначения.Значение = Новый ХранилищеЗначения(Свойства); + МенеджерЗначения.Записать(); + +КонецПроцедуры + +// Для константы ОграничиватьДоступНаУровнеЗаписейУниверсально. +Процедура ОчиститьПоследнееОбновлениеДоступа() Экспорт + + Свойства = ПоследнееОбновлениеДоступа(Null); + ЗаполнитьЗначенияСвойств(Свойства, ПоследнееОбновлениеДоступа(), + "ИдентификаторДоступа, ОбновлениеДоступаЗапрещено, БалансировкаНагрузкиНаДиск"); + + МенеджерЗначения = СлужебныйМенеджерЗначения(Константы.ПоследнееОбновлениеДоступа); + МенеджерЗначения.Значение = Новый ХранилищеЗначения(Свойства); + МенеджерЗначения.Записать(); + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаНаУровнеЗаписей и +// процедур ОбновлениеДоступаНаУровнеЗаписей, ОтменитьОбновлениеДоступаНаУровнеЗаписей и +// формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Параметры: +// ПоследнееОбновлениеДоступа - см. ПоследнееОбновлениеДоступа +// ИдентификаторИсключаемогоЗадания - УникальныйИдентификатор +// - Неопределено +// +// Возвращаемое значение: +// - ФоновоеЗадание +// - СеансИнформационнойБазы +// - Неопределено +// +Функция ИсполнительОбновленияДоступа(ПоследнееОбновлениеДоступа, ИдентификаторИсключаемогоЗадания = Неопределено) Экспорт + + Если ЗначениеЗаполнено(ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания) Тогда + Если ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания = ИдентификаторПроизвольногоСеанса() Тогда + Сеансы = ПолучитьСеансыИнформационнойБазы(); + Для Каждого Сеанс Из Сеансы Цикл + Если Сеанс.НомерСеанса = ПоследнееОбновлениеДоступа.НомерСеанса + И Сеанс.НачалоСеанса = ПоследнееОбновлениеДоступа.НачалоСеанса Тогда + Возврат Сеанс; + КонецЕсли; + КонецЦикла; + Иначе + ИсполняющееФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору( + ПоследнееОбновлениеДоступа.ИдентификаторФоновогоЗадания); + + Если ИсполняющееФоновоеЗадание <> Неопределено + И ИсполняющееФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + + Возврат ИсполняющееФоновоеЗадание; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Отбор = Новый Структура("Состояние, ИмяМетода", СостояниеФоновогоЗадания.Активно, + ИмяМетодаЗаданияОбновленияДоступа()); + + НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); + Для Каждого НайденноеЗадание Из НайденныеЗадания Цикл + Если НайденноеЗадание.УникальныйИдентификатор <> ИдентификаторИсключаемогоЗадания Тогда + Возврат НайденноеЗадание; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ОбновлениеДоступаНаУровнеЗаписей, ИсполнительОбновленияДоступа. +Функция ИдентификаторПроизвольногоСеанса() + + Возврат Новый УникальныйИдентификатор("ba4730f7-0493-402d-b5d3-8052c80fb125"); + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступа, ДобавитьЗаданияОбновленияДоступа и +// ОбновитьСоставИспользуемыхВерсийПараметровШаблонов. +// +// Параметры: +// Контекст - см. НовыйКонтекстОбновленияДоступа +// ПриЗапуске - Булево +// +Процедура ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст, ПриЗапуске = Ложь) + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + НачалоПроверки = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + РегистрыСведений.ИспользуемыеВидыДоступа.ОбновитьДанныеРегистра(, Истина); + + ДатаОбновленияВерсииРасширений = Справочники.ВерсииРасширений.ПоследняяВерсияРасширений().ДатаОбновления; + + ДатаОбновленияВсехПараметровРаботыПрограммы = + РегистрыСведений.ПараметрыРаботыПрограммы.ДатаОбновленияВсехПараметровРаботыПрограммы(); + + ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений = + РегистрыСведений.ПараметрыРаботыВерсийРасширений.ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений(); + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + ДатаСозданияПараметровОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа.ДатаСоздания; + + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; + ДатаПроверкиПараметровОграниченияДоступа = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + Если ТипЗнч(ДатаПроверкиПараметровОграниченияДоступа) <> Тип("Дата") Тогда + ДатаПроверкиПараметровОграниченияДоступа = '00010101'; + КонецЕсли; + + Если ДатаПроверкиПараметровОграниченияДоступа > ДатаСозданияПараметровОграниченияДоступа Тогда + ДатаАктуальностиПараметровОграниченияДоступа = ДатаПроверкиПараметровОграниченияДоступа; + Иначе + ДатаАктуальностиПараметровОграниченияДоступа = ДатаСозданияПараметровОграниченияДоступа; + КонецЕсли; + + Если ДатаАктуальностиПараметровОграниченияДоступа > ТекущаяДатаСеанса() Тогда + ДатаАктуальностиПараметровОграниченияДоступа = '00010101'; + КонецЕсли; + + ИспользованиеВидовДоступаИзменено = ИспользованиеВидовДоступаИзменено(ДействующиеПараметры); + + ВерсияТекстовОграниченияДоступаИзменена = Ложь; + ТекущаяВерсияТекстов = Неопределено; + Если ПриЗапуске Тогда + ТекущаяВерсияТекстов = РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(); + Если ДействующиеПараметры.ВерсияТекстовОграниченияДоступа <> ТекущаяВерсияТекстов Тогда + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; + ПоследняяВерсияТекстов = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + ВерсияТекстовОграниченияДоступаИзменена = ПоследняяВерсияТекстов <> ТекущаяВерсияТекстов; + КонецЕсли; + КонецЕсли; + + Если ДатаОбновленияВерсииРасширений > ДатаАктуальностиПараметровОграниченияДоступа + Или ДатаОбновленияВсехПараметровРаботыПрограммы > ДатаАктуальностиПараметровОграниченияДоступа + Или ДатаПоследнегоЗаполненияВсехПараметровРаботыРасширений > ДатаАктуальностиПараметровОграниченияДоступа + Или ИспользованиеВидовДоступаИзменено + Или ВерсияТекстовОграниченияДоступаИзменена + Или ПриЗапуске + И ЗапланированоОбновлениеПараметровОграниченияДоступа(ДатаАктуальностиПараметровОграниченияДоступа) Тогда + + Если Показатели <> Неопределено Тогда + НачалоОбновления = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + // Предварительное кэширование в файловой ИБ вне транзакции для предотвращения конфликтов блокировок. + ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом"); // СтандартныеПодсистемыПовтИсп.ИменаПодсистем + УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписей(); + УправлениеДоступомСлужебныйПовтИсп.КонстантаОграничиватьДоступНаУровнеЗаписейУниверсально(); + УправлениеДоступомСлужебныйПовтИсп.ПрофильАдминистратор(); + УправлениеДоступомСлужебныйПовтИсп.ГруппаДоступаАдминистраторы(); + СвойстваВидовДоступа(); + ВозможныеПраваДляНастройкиПравОбъектов(); + КонецЕсли; + + Если ИспользованиеВидовДоступаИзменено Тогда + Попытка + РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); + Исключение + РегистрыСведений.ИспользуемыеВидыДоступа.ПриИзмененииИспользованияВидовДоступа(); + КонецПопытки; + КонецЕсли; + Попытка + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); + Исключение + ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений(); + КонецПопытки; + Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия > 100000000000000 Тогда + Попытка + УменьшитьНомераВерсийПараметровОграниченияДоступа(); + Исключение + УменьшитьНомераВерсийПараметровОграниченияДоступа(); + КонецПопытки; + КонецЕсли; + НоваяДатаПроверкиПараметровОграниченияДоступа = ТекущаяДатаСеанса(); + Попытка + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Истина); + Исключение + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Истина); + КонецПопытки; + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; + ПоследняяДата = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + ПоследняяДата = ?(ТипЗнч(ПоследняяДата) = Тип("Дата"), ПоследняяДата, '00010101'); + Если ПоследняяДата < НоваяДатаПроверкиПараметровОграниченияДоступа Тогда + Попытка + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + НоваяДатаПроверкиПараметровОграниченияДоступа, Истина); + Исключение + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + НоваяДатаПроверкиПараметровОграниченияДоступа, Истина); + КонецПопытки; + КонецЕсли; + Если ТекущаяВерсияТекстов = Неопределено Тогда + ТекущаяВерсияТекстов = РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(); + КонецЕсли; + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; + ПоследняяВерсияТекстов = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + Если ПоследняяВерсияТекстов <> ТекущаяВерсияТекстов Тогда + Попытка + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + ТекущаяВерсияТекстов, Истина); + Исключение + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, + ТекущаяВерсияТекстов, Истина); + КонецПопытки; + КонецЕсли; + Если Показатели <> Неопределено Тогда + Показатели.ВремяОбновленияПараметровОграничения = Показатели.ВремяОбновленияПараметровОграничения + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОбновления); + КонецЕсли; + КонецЕсли; + + // Удаление устаревших параметров ограничения доступа. + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТекущаяВерсия", ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия); + Запрос.УстановитьПараметр("ДатаУстаревания", ТекущаяДатаСеанса() - 2 * 24 * 60 *60); + Запрос.Текст = + "ВЫБРАТЬ + | ПараметрыОграниченияДоступа.Версия КАК Версия, + | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания + |ИЗ + | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа + |ГДЕ + | ПараметрыОграниченияДоступа.Версия < &ТекущаяВерсия + | И ПараметрыОграниченияДоступа.ДатаСоздания <= &ДатаУстаревания + | + |УПОРЯДОЧИТЬ ПО + | Версия УБЫВ, + | ДатаСоздания УБЫВ"; + + // АПК:1328-выкл. См. 648.1.1. Допустимо чтение без предварительной + // управляемой разделяемой блокировки, так как используется только + // для очистки и какой сеанс очистит первым не важно. + // Если установить разделяемую блокировку, то позже будет повышение + // до исключительной, что ведет к взаимоблокировке и недопустимо. + // Если установить исключительную блокировку на таблицу, то + // это вызовет избыточное замедление запуска сеансов при установке + // параметров сеанса из параметров ограничения, что недопустимо. + РезультатЗапроса = Запрос.Выполнить(); + // АПК:1328-вкл. + + Если Не РезультатЗапроса.Пустой() Тогда + НаборЗаписей = РегистрыСведений.ПараметрыОграниченияДоступа.СоздатьНаборЗаписей(); + Выборка = РезультатЗапроса.Выбрать(); + Пока Выборка.Следующий() Цикл + НаборЗаписей.Отбор.Версия.Установить(Выборка.Версия); + Попытка + НаборЗаписей.Записать(); + Исключение + НаборЗаписей.Записать(); + КонецПопытки; + КонецЦикла; + КонецЕсли; + + УстановитьПривилегированныйРежим(Ложь); + УстановитьОтключениеБезопасногоРежима(Ложь); + + Если Показатели <> Неопределено Тогда + Показатели.ВремяПроверкиИОбновленияПараметровОграничения = Показатели.ВремяПроверкиИОбновленияПараметровОграничения + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоПроверки); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. +Функция ЗапланированоОбновлениеПараметровОграниченияДоступа(ДатаАктуальности) + + Идентификатор = СлужебныйИдентификатор("РегистрСведений.ПараметрыОграниченияДоступа"); + Если Идентификатор = Null Тогда + Возврат Ложь; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Список", Идентификатор); + Запрос.УстановитьПараметр("ДатаАктуальности", ДатаАктуальности); + Запрос.Текст = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Список = &Список + | И ТекущаяТаблица.ДатаИзмененияЗаписиРегистра >= &ДатаАктуальности + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ИСТИНА + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Список = &Список + | И ТекущаяТаблица.ДатаИзмененияЗаписиРегистра >= &ДатаАктуальности"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. +Процедура УменьшитьНомераВерсийПараметровОграниченияДоступа() + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + НаборЗаписей = РегистрыСведений.ПараметрыОграниченияДоступа.СоздатьНаборЗаписей(); + НаборЗаписей.Прочитать(); + Выгрузка = НаборЗаписей.Выгрузить(); + Выгрузка.Сортировать("Версия"); + ТекущаяВерсия = 1; + Для Каждого Строка Из Выгрузка Цикл + Строка.Версия = ТекущаяВерсия; + ТекущаяВерсия = ТекущаяВерсия + 1; + КонецЦикла; + НаборЗаписей.Загрузить(Выгрузка); + НаборЗаписей.Записать(); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа. +Функция ИспользованиеВидовДоступаИзменено(ДействующиеПараметры) + + Если ДействующиеПараметры.ВнешниеПользователиВключены + <> Константы.ИспользоватьВнешнихПользователей.Получить() + Или ДействующиеПараметры.ОграничениеДоступаВключено + <> Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() Тогда + Возврат Истина; + КонецЕсли; + + СвойстваВидовДоступа = СвойстваВидовДоступа(); + ТекущиеИспользуемыеТипыЗначений = ИспользуемыеТипыЗначений(СвойстваВидовДоступа,,, Истина); + + ИспользуемыеТипыЗначений = ДействующиеПараметры.ИспользуемыеТипыЗначений.Получить(); + + Если ТипЗнч(ИспользуемыеТипыЗначений) <> Тип("Структура") + Или Не ИспользуемыеТипыЗначений.Свойство("ХешСумма") + Или ИспользуемыеТипыЗначений.ХешСумма <> ТекущиеИспользуемыеТипыЗначений.ХешСумма Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступа, +// ОтменитьОбновлениеДоступаНаУровнеЗаписей, ЗавершитьОбновлениеДоступа. +// +Процедура ЗавершитьПотокиОбновленияДоступа(ОтменитьОбновление = Ложь) + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + + Если ОтменитьОбновление Тогда + НаборЗаписей.Добавить().ИдентификаторПотока = ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей(); + Иначе + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ОбновлениеКлючейДоступаТекущиеЗадания"; + + Если Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + НаборЗаписей.Записать(); + +КонецПроцедуры + +// Для процедур ОбработатьВыполненныеЗадания, ЗавершитьПотокиОбновленияДоступа. +Функция ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей() + + Возврат Новый УникальныйИдентификатор("06cc4b5f-a2f9-4622-bef0-df4870ab5dd5"); + +КонецФункции + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступа, +// ОтменитьОбновлениеДоступаНаУровнеЗаписей, ЗавершитьОбновлениеДоступа. +// +Процедура ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(СекундОжидания = 5) + + Отбор = Новый Структура; + Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно); + Отбор.Вставить("ИмяМетода", ИмяМетодаПотокаОбновленияДоступа()); + + ФоновыеЗаданияПотоков = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); + Если ФоновыеЗаданияПотоков.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ФоновыеЗаданияПотоков = ФоновыеЗадания.ОжидатьЗавершенияВыполнения(ФоновыеЗаданияПотоков, СекундОжидания); + Для Каждого ФоновоеЗаданиеПотока Из ФоновыеЗаданияПотоков Цикл + Если ФоновоеЗаданиеПотока.Состояние = СостояниеФоновогоЗадания.Активно Тогда + ФоновоеЗаданиеПотока.Отменить(); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Обновляет ключи доступа к данным на основе записей в регистре сведений +// ОбновлениеКлючейДоступаКДанным и ключи доступа пользователей на основе записей +// регистра сведений ОбновлениеКлючейДоступаПользователей. +// +// Обновляется порция данных для каждой таблицы, начиная с самых свежих данных. +// Процедура должна вызываться повторно, пока обработка не будет завершена, +// при этом регламентное задание выключается. +// +// Процедура предназначена для работы в единственном экземпляре, то есть без параллельной +// работы (вызов из процедуры регламентного задания ОбновлениеДоступаНаУровнеЗаписей). +// Параллельность обеспечивает сама процедура путем запуска до двух фоновых заданий +// на каждый список, но не более значения константы КоличествоПотоковОбновленияДоступа. +// +Процедура ВыполнитьОбновлениеДоступа(ОбновитьВсе, ПараметрыВыполнения, ПоследнееОбновлениеДоступа) + + Контекст = НовыйКонтекстОбновленияДоступа(); + Контекст.Вставить("Показатели", ПоказателиОбновленияОсновногоСеанса()); + Контекст.Вставить("ОписаниеОсновногоСеанса", ПараметрыВыполнения.ОписаниеОсновногоСеанса); + Контекст.Вставить("ТекущееФоновоеЗадание", ПараметрыВыполнения.ОписаниеОсновногоСеанса.ФоновоеЗадание); + Контекст.Вставить("Задания", ТаблицаЗаданийОбновления()); + Контекст.Вставить("ЗаданияДляЗапуска", Новый Массив); + Контекст.Вставить("ЗанятыеПотоки", Новый Соответствие); + Контекст.Вставить("СвободныеПотоки", Новый Массив); + Контекст.Вставить("ГраницаОбновленияЗаданий", '00010101'); + Контекст.Вставить("ОбщиеПараметрыОбновления", ОписаниеОбщихПараметровОбновления()); + Контекст.Вставить("ОбновлениеВЭтомСеансе", Ложь); + Контекст.Вставить("КоличествоПотоков", 0); + Контекст.Вставить("ДатаПолногоЗавершения", ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения); + Контекст.Вставить("ТекстОшибкиЗавершения", ""); + Контекст.Вставить("ЕстьОтложенныеЗадания", Ложь); + Контекст.Вставить("ЕстьЗапущенноеЗадание", Истина); + Контекст.Вставить("ОбработкаЗавершена", Ложь); + Контекст.Вставить("ОбновлениеОтменено", Ложь); + Контекст.Вставить("ТребуетсяПерезапускСеанса",Ложь); + Контекст.Вставить("МаксимумПорцийИзИсходной", 0); + Контекст.Вставить("МаксимумМиллисекундОбработкиПорции", 0); + Контекст.Вставить("КоличествоДополнительныхПорций", 0); + Контекст.Вставить("ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных", Ложь); + Контекст.Вставить("МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных", 0); + Контекст.Вставить("ИдентификаторыОтключенныхОбъектовМетаданных", Новый Соответствие); + Контекст.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.НаборыГруппДоступа")); + ПараметрыВыполнения.ОписаниеОсновногоСеанса.Удалить("ФоновоеЗадание"); + + ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст, Истина); + ЗапланироватьОбработкуУстаревшихЭлементов(ПараметрыВыполнения.ТекстОшибкиПланирования, + ПоследнееОбновлениеДоступа.ПоследнееПланированиеОбработкиУстаревшихЭлементов); + + Запрос = Новый Запрос; + Запрос.Текст = ТекстЗапросаЗаданий(); + Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДата()); + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ЗавершитьПотокиОбновленияДоступа(); + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(1); + + Задания = Контекст.Задания; + ЗанятыеПотоки = Контекст.ЗанятыеПотоки; + + Если ПараметрыВыполнения.СекундНеБолее > 0 Тогда + ОкончаниеВыполнения = ТекущаяДатаСеанса() + ПараметрыВыполнения.СекундНеБолее; + Иначе + ОкончаниеВыполнения = ТекущаяДатаСеанса() + + МаксимальноеКоличествоМинутВыполненияФоновогоЗаданияОбновленияДоступа() * 60; + КонецЕсли; + + ЗаполнитьКоличествоПотоков(Контекст); + ДобавитьПоказателиОбновленияУправляющегоПотока(Контекст); + ПовторныйЗапуск = Ложь; + + Пока Истина Цикл + Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск + Или ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + Прервать; + КонецЕсли; + Контекст.ОбработкаЗавершена = Истина; + + ЗаполнитьКоличествоПотоков(Контекст); + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + + Если Контекст.ОбновлениеОтменено Или Контекст.ТребуетсяПерезапускСеанса Тогда + Контекст.ОбработкаЗавершена = Ложь; + Прервать; + КонецЕсли; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + ДобавитьЗаданияОбновленияДоступа(РезультатыЗапроса, Контекст); + + Если Контекст.ТребуетсяПерезапускСеанса Тогда + Контекст.ОбработкаЗавершена = Ложь; + Прервать; + ИначеЕсли Контекст.ОбработкаЗавершена Тогда + ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст); + Если Не Контекст.ОбработкаЗавершена Тогда + Продолжить; + КонецЕсли; + Прервать; + КонецЕсли; + Контекст.ДатаПолногоЗавершения = '00010101'; + + ОкончаниеТекущегоЗапуска = ТекущаяДатаСеанса() + 5; + Контекст.Вставить("ПервыйПроход", Истина); + + Пока Истина Цикл + + Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск + Или ТекущаяДатаСеанса() > ОкончаниеТекущегоЗапуска + Или ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) + Или Задания.Количество() = 0 + Или Контекст.ОбновлениеОтменено + Или Контекст.ТребуетсяПерезапускСеанса Тогда + Прервать; + КонецЕсли; + + ПрерватьПроход = Ложь; + МоментПрерыванияПрохода = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + ЗаполнитьОбщиеПараметрыОбновления(Контекст); + Контекст.ЕстьЗапущенноеЗадание = Ложь; + ЗаданияДляЗапуска = Контекст.ЗаданияДляЗапуска; + + Для Каждого Задание Из ЗаданияДляЗапуска Цикл + + Пока ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Цикл + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + + Если Контекст.ОбновлениеОтменено Или Контекст.ТребуетсяПерезапускСеанса Тогда + ПрерватьПроход = Истина; + Прервать; + КонецЕсли; + + Если ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Тогда + Если Не ОбновитьВсе И ТекущаяДатаСеанса() > ОкончаниеВыполнения И ПовторныйЗапуск + Или ТекущаяДатаСеанса() > ОкончаниеТекущегоЗапуска Тогда + ПрерватьПроход = Истина; + Прервать; + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + ПодождатьОсвобожденияПотока(Контекст, Истина); + Если Не Контекст.ПервыйПроход + И ТекущаяУниверсальнаяДатаВМиллисекундах() > МоментПрерыванияПрохода Тогда + ПрерватьПроход = Истина; + Прервать; + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если ПрерватьПроход Тогда + Прервать; + КонецЕсли; + Если ЗанятыеПотоки.Количество() < Контекст.КоличествоПотоков Тогда + // @skip-check query-in-loop - Порционная обработка данных + ЗапуститьОбновлениеДоступаСписка(Задание, Контекст); + ПовторныйЗапуск = Истина; + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) + Или Контекст.ОбновлениеОтменено + Или Контекст.ТребуетсяПерезапускСеанса Тогда + Прервать; + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Не Контекст.ЕстьЗапущенноеЗадание + И (ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков + Или Не Контекст.ЕстьОтложенныеЗадания) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ПодождатьОсвобожденияПотока(Контекст, Истина); + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + Контекст.ПервыйПроход = Ложь; + КонецЦикла; + + Если Не ОбновитьВсе + И ПоследнееОбновлениеДоступа.ДляУскорения + И ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(Ложь) + И Задания.Найти(Истина, "ЕстьТочечноеЗадание") = Неопределено Тогда + + Если ПоследнееОбновлениеДоступа().ДляУскорения Тогда + Прервать; + Иначе + ПоследнееОбновлениеДоступа.ДляУскорения = Ложь; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если Не Контекст.ОбработкаЗавершена + И Не ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) + И Не Контекст.ОбновлениеОтменено + И Не Контекст.ТребуетсяПерезапускСеанса Тогда + + ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст); + КонецЕсли; + + ЗавершитьОбновлениеДоступа(Контекст); + + ПараметрыВыполнения.ТекстОшибкиЗавершения = Контекст.ТекстОшибкиЗавершения; + ПоследнееОбновлениеДоступа.ОбновлениеОтменено = Контекст.ОбновлениеОтменено; + ПоследнееОбновлениеДоступа.ДатаПолногоЗавершения = Контекст.ДатаПолногоЗавершения; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ОписаниеОсновногоСеанса - см. ОписаниеОсновногоСеанса +// * ТекущееФоновоеЗадание - ФоновоеЗадание +// * Задания - см. ТаблицаЗаданийОбновления +// * ЗаданияДляЗапуска - Массив из СтрокаТаблицыЗначений: см. ТаблицаЗаданийОбновления +// * ЗанятыеПотоки - Соответствие из КлючИЗначение: +// ** Ключ - УникальныйИдентификатор +// ** Значение - см. НовыйПоток +// * СвободныеПотоки - Массив из см. НовыйПоток +// * ГраницаОбновленияЗаданий - Дата +// * ОбщиеПараметрыОбновления - см. ОписаниеОбщихПараметровОбновления +// * ОбновлениеВЭтомСеансе - Булево +// * КоличествоПотоков - Число +// * ДатаПолногоЗавершения - Дата +// * ТекстОшибкиЗавершения - Строка +// * ЕстьОтложенныеЗадания - Булево +// * ЕстьЗапущенноеЗадание - Булево +// * ОбработкаЗавершена - Булево +// * ОбновлениеОтменено - Булево +// * ТребуетсяПерезапускСеанса - Булево +// * МаксимумПорцийИзИсходной - Число +// * КоличествоДополнительныхПорций - Число +// * ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных - Булево +// * МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных - Число +// * ИдентификаторыОтключенныхОбъектовМетаданных - Соответствие +// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// +Функция НовыйКонтекстОбновленияДоступа() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗапланироватьОбработкуУстаревшихЭлементов(ТекстОшибкиПланирования, + ПоследнееПланированиеОбработкиУстаревшихЭлементов) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПустойИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | ГДЕ ОбновлениеКлючейДоступаКДанным.РазмерЗадания = 2 + | И КлючУникальности <> &ПустойИдентификатор"; + + Если Не Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПоследнееПланированиеОбработкиУстаревшихЭлементов) Тогда + ПоследнееПланированиеОбработкиУстаревшихЭлементов = ТекущаяДатаСеанса(); + КонецЕсли; + Попытка + ГраницаОжидания = ТекущаяДатаСеанса() - КоличествоЧасовМеждуПланированиемОбработкиУстаревшихЭлементов() * 60 * 60; + Если ПоследнееПланированиеОбработкиУстаревшихЭлементов < ГраницаОжидания Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ПараметрыПланирования.Описание = "ОбновлениеДоступаНаУровнеЗаписей"; + ЗапланироватьОбновлениеДоступа(, ПараметрыПланирования); + ПоследнееПланированиеОбработкиУстаревшихЭлементов = ТекущаяДатаСеанса(); + КонецЕсли; + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибкиПланирования = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось запланировать обработку устаревших элементов ограничения доступа по причине: + |%1'"), + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ЗапуститьОбновлениеДоступаСписка. +Функция МаксимумМиллисекундПолученияПорций(Контекст) + + Если Не ЗначениеЗаполнено(Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных) Тогда + Результат = 3000; + + ИначеЕсли Не Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных Тогда + Результат = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000 - 1000; + Иначе + Результат = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000 / 2; + КонецЕсли; + + Если Результат < 1000 Тогда + Результат = 1000; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Для процедуры ЗаполнитьКоличествоПотоков и формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Возвращаемое значение: +// Булево +// +Функция ДоступнаБалансировкаНагрузкиНаДиск() Экспорт + + Возврат МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных() > 0 + И УправлениеДоступомСлужебныйПовтИсп.ДоступнаБалансировкаНагрузкиНаДиск(); + +КонецФункции + +// Для процедуры ЗаполнитьКоличествоПотоков и формы ОбновлениеДоступаНаУровнеЗаписей. +// +// Возвращаемое значение: +// Булево +// +Функция БалансировкаНагрузкиНаДиск() Экспорт + + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + Возврат ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск; + +КонецФункции + +// Для формы ОбновлениеДоступаНаУровнеЗаписей. +Процедура УстановитьБалансировкуНагрузкиНаДиск(Использование) Экспорт + + БлокировкаДанных = Новый БлокировкаДанных; + БлокировкаДанных.Добавить("Константа.ПоследнееОбновлениеДоступа"); + + ЕстьВнешняяТранзакция = ТранзакцияАктивна(); + НачатьТранзакцию(); + Попытка + БлокировкаДанных.Заблокировать(); + ЗначениеКонстанты = Константы.ПоследнееОбновлениеДоступа.Получить(); + ПоследнееОбновлениеДоступа = ПоследнееОбновлениеДоступа(ЗначениеКонстанты); + + Если ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск <> Использование Тогда + ПоследнееОбновлениеДоступа.БалансировкаНагрузкиНаДиск = Использование; + УстановитьПоследнееОбновлениеДоступа(ПоследнееОбновлениеДоступа, ЕстьВнешняяТранзакция); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +// Возвращаемое значение: +// ТаблицаЗначений: +// * ЕстьТочечноеЗадание - Булево +// * ЕстьНачальноеОбновлениеТочечногоЗадания - Дата +// * ДатаПоследнегоЗапускаТочечногоЗадания - Дата +// * ДатаДобавленияТочечногоЗадания - Дата +// * УровеньЗависимости - Число +// * ЗависимыеСписки - Массив +// - Строка +// * ЕстьНачальноеОбновление - Булево +// * ЕстьПерезапуск - Булево +// * ДатаПоследнегоЗапускаОбщегоЗадания - Дата +// * ЕстьДатаПоследнегоОбновленногоЭлемента - Булево +// * ДатаПоследнегоОбновленногоЭлемента - Дата +// * ДатаДобавленияОбщегоЗадания - Дата +// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ДляВнешнихПользователей - Булево +// * ЭтоОбновлениеПрав - Булево +// * Запускать - Булево +// * ЗанятыеПотоки - Соответствие из КлючИЗначение: +// ** Ключ - УникальныйИдентификатор +// ** Значение - см. НовыйПоток +// * НаборПорций - Массив из см. ПорцияИзНабора +// * КоличествоПорцийДляОбработки - Число +// * ИндексСледующейПорцииДляОбработки - Число +// * Пропустить - Булево +// * Удалить - Булево +// * ПорядокВидаКлючаДанных - Число +// * ЭтоОбработкаУстаревшихЭлементов - Булево +// * ОбновитьУровеньЗависимости - Булево +// +Функция ТаблицаЗаданийОбновления() + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + Задания = Новый ТаблицаЗначений; + Задания.Колонки.Добавить("ЕстьТочечноеЗадание", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЕстьНачальноеОбновлениеТочечногоЗадания",Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ДатаПоследнегоЗапускаТочечногоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ДатаДобавленияТочечногоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("УровеньЗависимости", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("ЗависимыеСписки", Новый ОписаниеТипов("Массив,Строка")); + Задания.Колонки.Добавить("ЕстьНачальноеОбновление", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЕстьПерезапуск", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ДатаПоследнегоЗапускаОбщегоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ЕстьДатаПоследнегоОбновленногоЭлемента", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ДатаПоследнегоОбновленногоЭлемента", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ДатаДобавленияОбщегоЗадания", Новый ОписаниеТипов("Дата")); + Задания.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); + Задания.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЭтоОбновлениеПрав", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("Запускать", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЗанятыеПотоки", Новый ОписаниеТипов("Соответствие")); + Задания.Колонки.Добавить("НаборПорций", Новый ОписаниеТипов("Массив")); + Задания.Колонки.Добавить("КоличествоПорцийДляОбработки", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("ИндексСледующейПорцииДляОбработки", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("Пропустить", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("Удалить", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ПорядокВидаКлючаДанных", Новый ОписаниеТипов("Число")); + Задания.Колонки.Добавить("ЭтоОбработкаУстаревшихЭлементов", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("РазрешенаОбработкаУстаревшихЭлементов", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ОбновитьУровеньЗависимости", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("БылаОшибка", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ТекстОшибки", Новый ОписаниеТипов("Строка")); + Задания.Колонки.Добавить("ДлительноеЗаданиеПолученияПорцийДо", Новый ОписаниеТипов("Дата")); + + Задания.Индексы.Добавить( + "ЕстьТочечноеЗадание, + |ЕстьНачальноеОбновлениеТочечногоЗадания, + |ДатаПоследнегоЗапускаТочечногоЗадания, + |ДатаДобавленияТочечногоЗадания, + |ЕстьНачальноеОбновление, + |ДатаПоследнегоЗапускаОбщегоЗадания, + |ЕстьДатаПоследнегоОбновленногоЭлемента, + |ДатаПоследнегоОбновленногоЭлемента, + |ДатаДобавленияОбщегоЗадания"); + + Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав, ЭтоОбработкаУстаревшихЭлементов"); + Задания.Индексы.Добавить("Удалить, ЭтоОбработкаУстаревшихЭлементов"); + Задания.Индексы.Добавить("УровеньЗависимости"); + + Возврат Задания; + +КонецФункции + +// Для процедуры ДобавитьЗаданияОбновленияДоступа. +Функция ТаблицаКлючейЗаданий() + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + Задания = Новый ТаблицаЗначений; + Задания.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); + Задания.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + Задания.Колонки.Добавить("ЭтоОбновлениеПрав", Новый ОписаниеТипов("Булево")); + + Задания.Индексы.Добавить("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + + Возврат Задания; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +// +// Возвращаемое значение: +// Структура: +// * ИдентификаторПотока - УникальныйИдентификатор +// * ФоновоеЗадание - ФоновоеЗадание +// * Задание - СтрокаТаблицыЗначений из см. ТаблицаЗаданийОбновления +// * ОтменитьЗадание - Булево +// * МоментЗапускаЗадания - Число +// * ПорцияИзНабора - см. ПорцияИзНабора +// * ПолучитьПорции - Число +// * ДатаОсвобождения - Дата +// +Функция НовыйПоток() + + Поток = Новый Структура; + Поток.Вставить("ИдентификаторПотока"); + Поток.Вставить("ФоновоеЗадание"); + Поток.Вставить("Задание"); + Поток.Вставить("ОтменитьЗадание", Ложь); + Поток.Вставить("МоментЗапускаЗадания", 0); + Поток.Вставить("ПорцияИзНабора"); + Поток.Вставить("ПолучитьПорции", 0); + Поток.Вставить("ДатаОсвобождения", '00010101'); + + Возврат Поток; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +// +// Возвращаемое значение: +// Структура: +// * ЭтоОбновлениеПрав - Булево +// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ДляВнешнихПользователей - Булево +// * ЭтоОбработкаУстаревшихЭлементов - Булево +// * РазрешенаОбработкаУстаревшихЭлементов - Булево +// * ДатаНачала - Дата +// * ДатаОкончания - Дата +// * НачальноеОбновление - Булево +// * ОбработкаЗавершена - Булево +// * МаксимумМиллисекундОбработки - Число +// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// * Кэш - см. НовыйКэшКонтекста +// * МаксимумПорцийИзИсходной - Число +// +Функция ОписаниеОбщихПараметровОбновления(Контекст = Неопределено) + + ОбщиеПараметрыОбновления = Новый Структура; + ОбщиеПараметрыОбновления.Вставить("ЭтоОбновлениеПрав", Ложь); + ОбщиеПараметрыОбновления.Вставить("ИдентификаторСписка", Неопределено); + ОбщиеПараметрыОбновления.Вставить("ДляВнешнихПользователей", Ложь); + ОбщиеПараметрыОбновления.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); + ОбщиеПараметрыОбновления.Вставить("РазрешенаОбработкаУстаревшихЭлементов", Ложь); + ОбщиеПараметрыОбновления.Вставить("ДатаНачала", '00010101'); + ОбщиеПараметрыОбновления.Вставить("ДатаОкончания", '00010101'); + ОбщиеПараметрыОбновления.Вставить("НачальноеОбновление", Ложь); + ОбщиеПараметрыОбновления.Вставить("ОбработкаЗавершена", Истина); + ОбщиеПараметрыОбновления.Вставить("МаксимумМиллисекундОбработки", 1000); + + Если Контекст = Неопределено Тогда + ОбщиеПараметрыОбновления.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", + ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.НаборыГруппДоступа")); + Иначе + ОбщиеПараметрыОбновления.Вставить("ИдентификаторСправочникаНаборыГруппДоступа", + Контекст.ИдентификаторСправочникаНаборыГруппДоступа); + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + ОбщиеПараметрыОбновления.Вставить("Кэш", Контекст.Кэш); + КонецЕсли; + ОбщиеПараметрыОбновления.Вставить("МаксимумПорцийИзИсходной", Контекст.МаксимумПорцийИзИсходной); + КонецЕсли; + + Возврат ОбщиеПараметрыОбновления; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Функция ТекстЗапросаЗаданий() + + Возврат + "ВЫБРАТЬ + | ЛОЖЬ КАК ЭтоОбновлениеПрав, + | Списки.Список КАК ИдентификаторСписка, + | Списки.ДляВнешнихПользователей КАК ДляВнешнихПользователей, + | МАКСИМУМ(Списки.ТочечноеЗадание) КАК ЕстьТочечноеЗадание, + | МАКСИМУМ(Списки.ТочечноеЗадание + | И Списки.ДатаПоследнегоОбновленногоЭлемента = &МаксимальнаяДата) КАК ЕстьНачальноеОбновлениеТочечногоЗадания, + | МАКСИМУМ(ВЫБОР + | КОГДА Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) КАК ДатаДобавленияТочечногоЗадания, + | МАКСИМУМ(Списки.РазмерЗадания = 2) КАК ЕстьОбработкаУстаревших, + | МАКСИМУМ(Списки.РазмерЗадания = 3) КАК ЕстьПолноеОбновление, + | МАКСИМУМ(Списки.РазмерЗадания = 3 + | И Списки.ДатаПоследнегоОбновленногоЭлемента = &МаксимальнаяДата) КАК ЕстьНачальноеОбновление, + | МАКСИМУМ(НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор) КАК ЕстьПерезапуск, + | МАКСИМУМ(ВЫБОР + | КОГДА НЕ Списки.ТочечноеЗадание + | ИЛИ Списки.КлючУникальности = &ПустойИдентификатор + | ТОГДА Списки.ДатаПоследнегоОбновленногоЭлемента + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) КАК ДатаПоследнегоОбновленногоЭлемента, + | МАКСИМУМ(ВЫБОР + | КОГДА НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) КАК ДатаДобавленияОбщегоЗадания + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК Списки + | + |СГРУППИРОВАТЬ ПО + | Списки.Список, + | Списки.ДляВнешнихПользователей + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ИСТИНА, + | Списки.Список, + | Списки.ДляВнешнихПользователей, + | МАКСИМУМ(Списки.ТочечноеЗадание), + | ЛОЖЬ, + | МАКСИМУМ(ВЫБОР + | КОГДА Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ), + | МАКСИМУМ(Списки.РазмерЗадания = 2), + | МАКСИМУМ(Списки.РазмерЗадания = 3), + | ЛОЖЬ, + | МАКСИМУМ(НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор), + | ДАТАВРЕМЯ(1, 1, 1), + | МАКСИМУМ(ВЫБОР + | КОГДА НЕ Списки.ТочечноеЗадание + | И Списки.КлючУникальности <> &ПустойИдентификатор + | ТОГДА Списки.ДатаИзмененияЗаписиРегистра + | ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ) + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК Списки + | + |СГРУППИРОВАТЬ ПО + | Списки.Список, + | Списки.ДляВнешнихПользователей"; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗаполнитьКоличествоПотоков(Контекст) + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Возврат; + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + КоличествоПотоков = 1; + Контекст.МаксимумПорцийИзИсходной = 5; + Иначе + КоличествоПотоков = Константы.КоличествоПотоковОбновленияДоступа.Получить(); + Контекст.МаксимумПорцийИзИсходной = 5 + (КоличествоПотоков - 1) * 2; + КонецЕсли; + + Если КоличествоПотоков < 1 Тогда + КоличествоПотоков = 1; + КонецЕсли; + + Если Контекст.КоличествоПотоков = 0 Тогда + Контекст.ОбновлениеВЭтомСеансе = КоличествоПотоков = 1; + КонецЕсли; + + Контекст.КоличествоПотоков = КоличествоПотоков; + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Возврат; + КонецЕсли; + + Если ДоступнаБалансировкаНагрузкиНаДиск() И БалансировкаНагрузкиНаДиск() Тогда + Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных = + МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных(); + Иначе + Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных = 0; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ДобавитьЗаданияОбновленияДоступа(РезультатыЗапроса, Контекст) + + Если Контекст.Свойство("Кэш") Тогда + Кэш = Контекст.Кэш; // см. НовыйКэшКонтекста + Иначе + Кэш = НовыйКэшКонтекста(); + Контекст.Вставить("Кэш", Кэш); + Контекст.Вставить("ИдентификаторыПоПолнымИменам", Новый Соответствие); + Контекст.Вставить("ВерсияПараметровОграничения"); + Контекст.Вставить("ХешСуммаПараметровОграничения"); + КонецЕсли; + Если Не Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда + Кэш.Вставить("ОбъектыМетаданныхПоИдентификаторам", Новый Соответствие); + КонецЕсли; + + Попытка + ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст); + Исключение + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + Возврат; + КонецЕсли; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + Задания = Контекст.Задания; + ИдентификаторыСписков = Новый Массив; + + Если Контекст.ВерсияПараметровОграничения <> ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия + Или Контекст.ХешСуммаПараметровОграничения <> ПараметрыСеанса.ПараметрыОграниченияДоступа.ХешСумма Тогда + + Задания.ЗаполнитьЗначения(-1, "УровеньЗависимости"); + Задания.ЗаполнитьЗначения(Неопределено, "ЗависимыеСписки"); + Контекст.Вставить("ИдентификаторыПоПолнымИменам", Новый Соответствие); + Контекст.Вставить("ВедущиеСпискиПоЗависимым", ТаблицаКлючейЗаданий()); + Контекст.ВедущиеСпискиПоЗависимым.Колонки.Добавить("ВедущиеСписки"); + + ТекущиеИдентификаторыСписка = Задания.Скопировать(, "ИдентификаторСписка"); + ТекущиеИдентификаторыСписка.Свернуть("ИдентификаторСписка"); + ИдентификаторыСписков = ТекущиеИдентификаторыСписка.ВыгрузитьКолонку("ИдентификаторСписка"); + + Контекст.ВерсияПараметровОграничения = ПараметрыСеанса.ПараметрыОграниченияДоступа.Версия; + Контекст.ХешСуммаПараметровОграничения = ПараметрыСеанса.ПараметрыОграниченияДоступа.ХешСумма; + КонецЕсли; + + Задания.ЗаполнитьЗначения(Истина, "Удалить"); + Отбор = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + + Выгрузка = РезультатыЗапроса[0].Выгрузить(); + + Для Каждого Строка Из Выгрузка Цикл + Если Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Получить(Строка.ИдентификаторСписка) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Строки = Задания.НайтиСтроки(Отбор); + Если Строки.Количество() = 0 Тогда + Задание = Задания.Добавить(); + Задание.УровеньЗависимости = -1; // Не заполнен. + Если Строка.ИдентификаторСписка <> Неопределено + И Кэш.ОбъектыМетаданныхПоИдентификаторам.Получить(Строка.ИдентификаторСписка) = Неопределено Тогда + ИдентификаторыСписков.Добавить(Строка.ИдентификаторСписка); + КонецЕсли; + Если Строка.ЕстьОбработкаУстаревших И Не Строка.ЕстьТочечноеЗадание И Не Строка.ЕстьПолноеОбновление Тогда + Задание.ПорядокВидаКлючаДанных = ПорядокВидаКлючаДанных("УстаревшиеЭлементы"); + КонецЕсли; + Иначе + Задание = Строки[0]; + КонецЕсли; + ЗаполнитьЗначенияСвойств(Задание, Строка); + Задание.Удалить = Ложь; + ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание, Ложь); + Если Строка.ЕстьПолноеОбновление Тогда + Задание.ЭтоОбработкаУстаревшихЭлементов = Ложь; + КонецЕсли; + Задание.ЕстьДатаПоследнегоОбновленногоЭлемента + = ЗначениеЗаполнено(Задание.ДатаПоследнегоОбновленногоЭлемента); + + Если Задание.ЕстьПерезапуск Тогда + ОтменитьЗадание(Задание); + КонецЕсли; + КонецЦикла; + + Если ИдентификаторыСписков.Количество() > 0 Тогда + ОбъектыМетаданныхПоИдентификаторам = + ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИдентификаторыСписков, Ложь); + Для Каждого КлючИЗначение Из ОбъектыМетаданныхПоИдентификаторам Цикл + Кэш.ОбъектыМетаданныхПоИдентификаторам.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + Если ТипЗнч(КлючИЗначение.Значение) = Тип("ОбъектМетаданных") Тогда + Контекст.ИдентификаторыПоПолнымИменам.Вставить(КлючИЗначение.Значение.ПолноеИмя(), КлючИЗначение.Ключ); + ИначеЕсли КлючИЗначение.Значение = Неопределено Тогда + Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Вставить(КлючИЗначение.Ключ, Истина); + Строки = Задания.НайтиСтроки(Новый Структура("ИдентификаторСписка", КлючИЗначение.Ключ)); + Для Каждого Строка Из Строки Цикл + Задания.Удалить(Строка); + КонецЦикла; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если Задания.Количество() > 0 Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + + ЗаполнитьУровниЗависимостиЗаданий(Контекст, ДействующиеПараметры.ВедущиеСписки); + +КонецПроцедуры + +// Для функции ДобавитьЗаданияОбновленияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ОбъектыМетаданныхПоИдентификаторам - Соответствие +// +Функция НовыйКэшКонтекста() + + Возврат Новый Структура; + +КонецФункции + +// Для процедур ДобавитьЗаданияОбновленияДоступа, ОбновитьСвойстваЗадания и +// функции ЗапуститьОбновлениеДоступаСписка. +// +Процедура ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание, ТребуетсяОбновитьУровеньЗависимостиПриИзменении = Истина) + + ЭтоОбработкаУстаревшихЭлементов = Не Задание.ЕстьТочечноеЗадание + И Задание.ПорядокВидаКлючаДанных >= ПорядокВидаКлючаДанных("УстаревшиеЭлементы") + И Задание.ПорядокВидаКлючаДанных < ПорядокВидаКлючаДанных("НетДанных"); + + Если Задание.ЭтоОбработкаУстаревшихЭлементов <> ЭтоОбработкаУстаревшихЭлементов Тогда + Задание.ЭтоОбработкаУстаревшихЭлементов = ЭтоОбработкаУстаревшихЭлементов; + Задание.ОбновитьУровеньЗависимости = ТребуетсяОбновитьУровеньЗависимостиПриИзменении; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОбщиеПараметрыОбновления. +Функция ЭтоОбновлениеСоставаНаборовГруппДоступа(Задание, Контекст) + + Возврат Задание.ИдентификаторСписка = Контекст.ИдентификаторСправочникаНаборыГруппДоступа + И Задание.ПорядокВидаКлючаДанных <= ПорядокВидаКлючаДанных("НаборыГруппРазрешенныеПользователям"); + +КонецФункции + +// Для процедуры ДобавитьЗаданияОбновленияДоступа. +Процедура ЗаполнитьУровниЗависимостиЗаданий(Контекст, СвойстваВедущихСписков) + + Задания = Контекст.Задания; + ОбъектыМетаданныхПоИдентификаторам = Контекст.Кэш.ОбъектыМетаданныхПоИдентификаторам; + ИдентификаторыПоПолнымИменам = Контекст.ИдентификаторыПоПолнымИменам; + + ЗаданияДляЗаполнения = Задания.НайтиСтроки(Новый Структура("УровеньЗависимости", -1)); + ВедущиеСпискиПоЗависимым = Контекст.ВедущиеСпискиПоЗависимым; + ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + + Для Каждого Задание Из ЗаданияДляЗаполнения Цикл + УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, ВедущиеСпискиПоЗависимым); + + ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(Задание.ИдентификаторСписка); + Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда + Продолжить; + КонецЕсли; + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + СвойстваВедущегоСписка = СвойстваВедущихСписков.Получить(ПолноеИмя); + Если СвойстваВедущегоСписка = Неопределено + Или СвойстваВедущегоСписка.ПоКлючамДоступа = Неопределено Тогда + Продолжить; + КонецЕсли; + Если Задание.ДляВнешнихПользователей Тогда + ЗависимыеСписки = СвойстваВедущегоСписка.ПоКлючамДоступа.ДляВнешнихПользователей; + Иначе + ЗависимыеСписки = СвойстваВедущегоСписка.ПоКлючамДоступа.ДляПользователей; + КонецЕсли; + Если ЗависимыеСписки = Неопределено Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(ОтборЗадания, Задание); + Для Каждого ЗависимыйСписок Из ЗависимыеСписки Цикл + ИдентификаторЗависимого = ИдентификаторыПоПолнымИменам.Получить(ЗависимыйСписок); + Если Задание.ЗависимыеСписки = Неопределено Тогда + Задание.ЗависимыеСписки = Новый Массив; + КонецЕсли; + ЗаданиеЗависимыеСписки = Задание.ЗависимыеСписки; + ЗаданиеЗависимыеСписки.Добавить(ИдентификаторЗависимого); + ОтборЗадания.ИдентификаторСписка = ИдентификаторЗависимого; + Найденные = ВедущиеСпискиПоЗависимым.НайтиСтроки(ОтборЗадания); + Если Найденные.Количество() = 0 Тогда + ВедущиеСписки = Новый Соответствие; + НоваяСтрока = ВедущиеСпискиПоЗависимым.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ОтборЗадания); + НоваяСтрока.ВедущиеСписки = ВедущиеСписки; + Иначе + ВедущиеСписки = Найденные[0].ВедущиеСписки; + КонецЕсли; + ВедущиеСписки.Вставить(Задание.ИдентификаторСписка, Истина); + ЗависимыеЗадания = Задания.НайтиСтроки(ОтборЗадания); + Если ЗависимыеЗадания.Количество() > 0 Тогда + УстановитьУровеньЗависимостиПоВедущим(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗаполнитьУровниЗависимостиЗаданий, ОбновитьУровеньЗависимости. +Процедура УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, ВедущиеСпискиПоЗависимым) + + Задание.УровеньЗависимости = 0; + Если Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Возврат; + КонецЕсли; + + ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав", + Задание.ИдентификаторСписка, Задание.ДляВнешнихПользователей, Задание.ЭтоОбновлениеПрав); + + Найденные = ВедущиеСпискиПоЗависимым.НайтиСтроки(ОтборЗадания); + Если Найденные.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ОтборЗадания.Вставить("ЭтоОбработкаУстаревшихЭлементов", Ложь); + + Для Каждого ОписаниеВедущегоСписка Из Найденные[0].ВедущиеСписки Цикл + ОтборЗадания.ИдентификаторСписка = ОписаниеВедущегоСписка.Ключ; + ВедущиеЗадания = Задания.НайтиСтроки(ОтборЗадания); + Если ВедущиеЗадания.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + Если Задание.УровеньЗависимости < ВедущиеЗадания[0].УровеньЗависимости + 1 Тогда + Задание.УровеньЗависимости = ВедущиеЗадания[0].УровеньЗависимости + 1; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОбщиеПараметрыОбновления. +Процедура ОбновитьУровеньЗависимости(СвойстваЗадания, Задания, ВедущиеСпискиПоЗависимым) + + Если Не ЗначениеЗаполнено(СвойстваЗадания.ЗависимыеСписки) Тогда + Возврат; + КонецЕсли; + ОтборЗадания = Новый Структура("ИдентификаторСписка, ДляВнешнихПользователей, ЭтоОбновлениеПрав"); + ЗаполнитьЗначенияСвойств(ОтборЗадания, СвойстваЗадания); + + Для Каждого ЗависимыйСписок Из СвойстваЗадания.ЗависимыеСписки Цикл + ОтборЗадания.ИдентификаторСписка = ЗависимыйСписок; + ЗависимыеЗадания = Задания.НайтиСтроки(ОтборЗадания); + Если ЗависимыеЗадания.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + УстановитьУровеньЗависимостиПоВедущим(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); + ОбновитьУровеньЗависимости(ЗависимыеЗадания[0], Задания, ВедущиеСпискиПоЗависимым); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗаполнитьОбщиеПараметрыОбновления(Контекст) + + Задания = Контекст.Задания; + Задания.Сортировать( + "ЕстьТочечноеЗадание Убыв, + |ЕстьНачальноеОбновлениеТочечногоЗадания Убыв, + |ДатаПоследнегоЗапускаТочечногоЗадания Возр, + |ДатаДобавленияТочечногоЗадания Убыв, + |ЕстьНачальноеОбновление Убыв, + |ДатаПоследнегоЗапускаОбщегоЗадания Возр, + |ЕстьДатаПоследнегоОбновленногоЭлемента Возр, + |ДатаПоследнегоОбновленногоЭлемента Убыв, + |ДатаДобавленияОбщегоЗадания Убыв"); + + ЗаданияДляУдаления = Задания.НайтиСтроки(Новый Структура("Удалить", Истина)); + Для Каждого Задание Из ЗаданияДляУдаления Цикл + Если Не Задание.Удалить Или Задание.ЗанятыеПотоки.Количество() > 0 Тогда + Продолжить; + КонецЕсли; + СвойстваЗадания = Новый Структура("ИдентификаторСписка, + |ДляВнешнихПользователей, ЭтоОбновлениеПрав, ЗависимыеСписки"); + ЗаполнитьЗначенияСвойств(СвойстваЗадания, Задание); + Задания.Удалить(Задание); + ОбновитьУровеньЗависимости(СвойстваЗадания, Задания, Контекст.ВедущиеСпискиПоЗависимым); + КонецЦикла; + ЗаданияДляОбновленияУровня = Задания.НайтиСтроки(Новый Структура("ОбновитьУровеньЗависимости", Истина)); + Для Каждого Задание Из ЗаданияДляОбновленияУровня Цикл + УстановитьУровеньЗависимостиПоВедущим(Задание, Задания, Контекст.ВедущиеСпискиПоЗависимым); + ОбновитьУровеньЗависимости(Задание, Задания, Контекст.ВедущиеСпискиПоЗависимым); + Задание.ОбновитьУровеньЗависимости = Ложь; + КонецЦикла; + + ОтборУровней = Новый Структура("Удалить, ЭтоОбработкаУстаревшихЭлементов", Ложь, Ложь); + Уровни = Задания.Скопировать(ОтборУровней, "УровеньЗависимости"); + Уровни.Свернуть("УровеньЗависимости"); + Уровни.Сортировать("УровеньЗависимости"); + НаименьшийУровеньЗависимости = ?(Уровни.Количество() > 0, Уровни[0].УровеньЗависимости, 0); + ЭтоОбработкаУстаревшихЭлементов = Уровни.Количество() = 0; + ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания = '00010101'; + Если Уровни.Количество() > 1 Или Не ЭтоОбработкаУстаревшихЭлементов Тогда + Для Каждого Задание Из Задания Цикл + Если Задание.Удалить + Или Задание.ЕстьТочечноеЗадание Тогда + Продолжить; + КонецЕсли; + Если Задание.УровеньЗависимости > НаименьшийУровеньЗависимости + И ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания < Задание.ДатаПоследнегоЗапускаОбщегоЗадания Тогда + ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания = Задание.ДатаПоследнегоЗапускаОбщегоЗадания; + КонецЕсли; + КонецЦикла; + КонецЕсли; + ЗапускаемоеЗависимоеОбщееЗадание = + ?(ДатаПоследнегоЗапускаЗависимогоОбщегоЗадания > ТекущаяДатаСеанса() - 10, Null, Неопределено); + + ОбщиеПараметрыОбновления = Контекст.ОбщиеПараметрыОбновления; + ОбщиеПараметрыОбновления.ЭтоОбработкаУстаревшихЭлементов = ЭтоОбработкаУстаревшихЭлементов; + ОбщиеПараметрыОбновления.НачальноеОбновление = Ложь; + ПоследняяДата = '00010101'; + ЗаданиеСправочникаНаборыГруппДоступа = Неопределено; + ГраницаОжиданияДляЗависимыхЗаданий = ТекущаяДатаСеанса() - 3; + МаксимальнаяДатаПриПродолжении = МаксимальнаяДатаПриПродолжении(); + ЕстьСписокБезПериода = Ложь; + + Для Каждого Задание Из Задания Цикл + Если Задание.Удалить Тогда + Продолжить; + КонецЕсли; + Если ЭтоОбновлениеСоставаНаборовГруппДоступа(Задание, Контекст) Тогда + ЗаданиеСправочникаНаборыГруппДоступа = Задание; + КонецЕсли; + Если Задание.БылаОшибка Тогда + Задание.Пропустить = Истина; + Продолжить; + КонецЕсли; + Задание.Пропустить = Ложь; + + Если Задание.ЕстьНачальноеОбновление Тогда + ОбщиеПараметрыОбновления.НачальноеОбновление = Истина; + + ИначеЕсли Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Задание.Пропустить = Не ЭтоОбработкаУстаревшихЭлементов + И ЭтоДлительноеЗаданиеПолученияПорций(Задание); + Продолжить; + + ИначеЕсли Не Задание.ЕстьПерезапуск Тогда + + Если Задание.УровеньЗависимости > НаименьшийУровеньЗависимости Тогда + Если Задание.ЕстьТочечноеЗадание Тогда + Если Задание.ДатаПоследнегоЗапускаТочечногоЗадания > ГраницаОжиданияДляЗависимыхЗаданий Тогда + Задание.Пропустить = Истина; + Продолжить; + КонецЕсли; + ИначеЕсли ЗапускаемоеЗависимоеОбщееЗадание <> Неопределено Тогда + Задание.Пропустить = Истина; + Продолжить; + Иначе + ЗапускаемоеЗависимоеОбщееЗадание = Задание; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если Задание.ЭтоОбновлениеПрав Тогда + Продолжить; + КонецЕсли; + Если Задание.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДатаПриПродолжении Тогда + ЕстьСписокБезПериода = Истина; + ИначеЕсли Задание.ДатаПоследнегоОбновленногоЭлемента > ПоследняяДата Тогда + ПоследняяДата = Задание.ДатаПоследнегоОбновленногоЭлемента; + КонецЕсли; + КонецЦикла; + + Если ОбщиеПараметрыОбновления.НачальноеОбновление Тогда + // Начало обновления. + ОбщиеПараметрыОбновления.ДатаНачала = НачалоДня(ТекущаяДатаСеанса()) - 7 * (60 * 60 * 24); // 7 Дней. + Иначе + // Продолжение обновления. + МаксимальныйПериод = МаксимальныйПериодПолученияПорцийЗапросом(); + + Если МаксимальныйПериод = "Неделя" Тогда + ДатаНачала = НачалоНедели(ПоследняяДата); + + ИначеЕсли МаксимальныйПериод = "Месяц" Тогда + ДатаНачала = НачалоМесяца(ПоследняяДата); + Иначе + ЭтотГод = Год(ТекущаяДатаСеанса()) - Год(ПоследняяДата) = 0; + СмещениеМесяца = Месяц(ТекущаяДатаСеанса()) - Месяц(ПоследняяДата); + + Если ЭтотГод И СмещениеМесяца = 0 Тогда + ДатаНачала = НачалоМесяца(ПоследняяДата); + + ИначеЕсли ЭтотГод И СмещениеМесяца < 3 Или МаксимальныйПериод = "Квартал" Тогда + ДатаНачала = НачалоКвартала(ПоследняяДата); + Иначе + ДатаНачала = НачалоГода(ПоследняяДата); + КонецЕсли; + КонецЕсли; + + ОбщиеПараметрыОбновления.ДатаНачала = ДатаНачала; + КонецЕсли; + ОбщиеПараметрыОбновления.ДатаОкончания = ПоследняяДата; + + ЗаданияДляЗапуска = Новый Массив; + Контекст.ЗаданияДляЗапуска = ЗаданияДляЗапуска; + Контекст.ЕстьОтложенныеЗадания = Ложь; + ЗаданийДляЗапускаСУчетомПорций = 0; + СпискиСОбработкойНеТолькоУстаревшихЭлементов = Новый Соответствие; + + Для Каждого Задание Из Задания Цикл + Задание.Запускать = Ложь; + Задание.РазрешенаОбработкаУстаревшихЭлементов = Ложь; + + Если Задание.Удалить Или Задание.Пропустить Тогда + Продолжить; + + ИначеЕсли Задание.ЕстьПерезапуск + Или Задание.ЕстьНачальноеОбновление + Или Задание.ЕстьТочечноеЗадание Тогда + + Задание.Запускать = Истина; + + ИначеЕсли Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Задание.Запускать = ЭтоОбработкаУстаревшихЭлементов; + Задание.РазрешенаОбработкаУстаревшихЭлементов = Истина; + + ИначеЕсли Задание = ЗаданиеСправочникаНаборыГруппДоступа + Или Задание.ЭтоОбновлениеПрав + Или Задание.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДатаПриПродолжении Тогда // Список без периода. + + Задание.Запускать = Истина; + Иначе + Запускать = Не ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + Задание.ДатаПоследнегоОбновленногоЭлемента); + Задание.Пропустить = Не Запускать; // Нет смысла запускать, так как в исполняющем потоке будет возврат. + Задание.Запускать = Запускать И Не ЕстьСписокБезПериода; + КонецЕсли; + + Если Задание.Запускать Тогда + ЗаданияДляЗапуска.Добавить(Задание); + ЗаданийДляЗапускаСУчетомПорций = ЗаданийДляЗапускаСУчетомПорций + ?(Не Задание.ЕстьПерезапуск + И ЗначениеЗаполнено(Задание.НаборПорций), Задание.НаборПорций.Количество(), 1); + ИначеЕсли Не Задание.Пропустить Тогда + Контекст.ЕстьОтложенныеЗадания = Истина; + КонецЕсли; + Если Не Задание.РазрешенаОбработкаУстаревшихЭлементов Тогда + СпискиСОбработкойНеТолькоУстаревшихЭлементов.Вставить(Задание.ИдентификаторСписка, Истина); + КонецЕсли; + КонецЦикла; + + Если ЗаданийДляЗапускаСУчетомПорций >= Контекст.КоличествоПотоков + Или Не ЗагружатьСвободныеПотокиСледующимиЗаданиямиПриДлительныхЗапросах() Тогда + Контекст.ЕстьОтложенныеЗадания = Ложь; + КонецЕсли; + + Если Не Контекст.ЕстьЗапущенноеЗадание + И Контекст.ЕстьОтложенныеЗадания + И Контекст.ЗанятыеПотоки.Количество() < Контекст.КоличествоПотоков Тогда + + Контекст.ЕстьОтложенныеЗадания = Ложь; + КоличествоСвободныхПотоков = Контекст.КоличествоПотоков - Контекст.ЗанятыеПотоки.Количество(); + КоличествоДополнительныхЗаданий = 0; + + Для ДобавитьОбработкуУстаревшихЭлементов = 0 По 1 Цикл + Для Каждого Задание Из Задания Цикл + Если Задание.Удалить + Или Задание.Запускать + Или Задание.Пропустить + Или Задание.ЭтоОбработкаУстаревшихЭлементов + И (СпискиСОбработкойНеТолькоУстаревшихЭлементов.Получить(Задание.ИдентификаторСписка) <> Неопределено + Или ДобавитьОбработкуУстаревшихЭлементов = 0 + И Не ЭтоОбработкаУстаревшихЭлементов) Тогда + Продолжить; + КонецЕсли; + Если КоличествоДополнительныхЗаданий >= КоличествоСвободныхПотоков Тогда + Контекст.ЕстьОтложенныеЗадания = Истина; + Прервать; + КонецЕсли; + Задание.Запускать = Истина; + ЗаданияДляЗапуска.Добавить(Задание); + КоличествоДополнительныхЗаданий = КоличествоДополнительныхЗаданий + 1; + КонецЦикла; + Если КоличествоДополнительныхЗаданий >= КоличествоСвободныхПотоков Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + КоличествоОсновныхЗаданий = ЗаданияДляЗапуска.Количество(); + Если КоличествоОсновныхЗаданий > 0 Тогда + Контекст.КоличествоДополнительныхПорций = Цел(Контекст.КоличествоПотоков / КоличествоОсновныхЗаданий); + Иначе + Контекст.КоличествоДополнительныхПорций = 0; + КонецЕсли; + + КоличествоЗаданий = Задания.Количество(); + Если КоличествоЗаданий = 0 Тогда + ДостаточностьПотоков = 0; + ИначеЕсли Контекст.КоличествоПотоков > КоличествоЗаданий Тогда + ДостаточностьПотоков = 1; + Иначе + ДостаточностьПотоков = Контекст.КоличествоПотоков / КоличествоЗаданий; + КонецЕсли; + НагруженностьОтПотоков = Контекст.КоличествоПотоков * 0.025; + Если НагруженностьОтПотоков > 1 Тогда + НагруженностьОтПотоков = 1; + КонецЕсли; + Контекст.МаксимумМиллисекундОбработкиПорции = + Цел(МинимальноеКоличествоСекундОбработкиПорцииВОтдельномПотоке() * 1000 + * (1 + НагруженностьОтПотоков) * (1 + ДостаточностьПотоков)); + + Если КоличествоОсновныхЗаданий = 0 + И КоличествоЗаданий > 0 + И Не ЗначениеЗаполнено(Контекст.ЗанятыеПотоки) Тогда + + ОбработатьЗаданияСОшибками(Контекст); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ДобавитьЗаданияОбновленияДоступа, ЗапуститьОбновлениеДоступаСписка, +// ВыполнитьОбновлениеДоступаСписка. +// +Функция ПериодОбновленияДоПериодаДанных(ДатаНачала, ДатаПоследнегоОбновленногоЭлемента) + + // ДатаНачала - например, 01.01.2012, а дата окончания 31.12.2012, + // при этом ДатаПоследнегоОбновленногоЭлемента, например, 03.01.2013. + // В таком случае данные для обновления старее, чем период обновления. + Возврат ЗначениеЗаполнено(ДатаПоследнегоОбновленногоЭлемента) + И ДатаНачала > ДатаПоследнегоОбновленногоЭлемента; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ОбработатьЗаданияСОшибками(Контекст) + + Отбор = Новый Структура("БылаОшибка", Истина); + ЗаданияСОшибками = Контекст.Задания.НайтиСтроки(Отбор); + Если Не ЗначениеЗаполнено(ЗаданияСОшибками) Тогда + Возврат; + КонецЕсли; + Контекст.ОбработкаЗавершена = Ложь; + + ТекстыОшибок = Новый Массив; + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + ТекстыОшибок.Добавить(Контекст.ТекстОшибкиЗавершения); + КонецЕсли; + + Для Каждого Задание Из ЗаданияСОшибками Цикл + Контекст.ОбработкаЗавершена = Ложь; + ТекстыОшибок.Добавить(Задание.ТекстОшибки); + КонецЦикла; + Контекст.ТекстОшибкиЗавершения = СтрСоединить(ТекстыОшибок, Символы.ПС + Символы.ПС); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ОбновитьСоставИспользуемыхВерсийПараметровШаблонов(Контекст) + + Если Не Контекст.ОбработкаЗавершена + И ПараметрыСеанса.ПараметрыОграниченияДоступа.ДатаСоздания > ТекущаяДатаСеанса() - 5 * 60 Тогда + + Возврат; + КонецЕсли; + + Попытка + ПроверитьОбновитьДействующиеПараметрыОграниченияДоступа(Контекст); + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + Исключение + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + Возврат; + КонецЕсли; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст; + + Если ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст.ДляПользователей) + И ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст.ДляВнешнихПользователей) Тогда + + Возврат; + КонецЕсли; + + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); + ОбщийКонтекст.Вставить("СпискиСУстаревшимиВариантамиДоступа", Новый Массив); + + Попытка + ДействующиеПараметрыОграниченияДоступа(Неопределено, ОбщийКонтекст, Истина); + Исключение + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса() Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + Возврат; + КонецЕсли; + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + + Если ЗначениеЗаполнено(ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа) Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ЗавершитьОбновлениеДоступа(Контекст) + + Если Не Контекст.ОбновлениеОтменено И Не Контекст.ТребуетсяПерезапускСеанса Тогда + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + ГраницаОжидания = ТекущаяДатаСеанса() + 3; + Иначе + ГраницаОжидания = ТекущаяДатаСеанса() + 15; + КонецЕсли; + Пока Контекст.ЗанятыеПотоки.Количество() > 0 Цикл + // @skip-check query-in-loop - Порционная обработка данных + ПодождатьОсвобожденияПотока(Контекст); + // @skip-check query-in-loop - Порционная обработка данных + ОбработатьВыполненныеЗадания(Контекст); + Если ТекущаяДатаСеанса() > ГраницаОжидания Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ЗавершитьПотокиОбновленияДоступа(); + ОтменитьФоновыеЗаданияПотоковОбновленияДоступа(); + + Попытка + Если Контекст.ОбработкаЗавершена Тогда + Контекст.Вставить("ОшибкаОжиданияБлокировкиДанных", Ложь); + Попытка + ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий(Контекст); + Исключение + Если Не Контекст.ОшибкаОжиданияБлокировкиДанных Тогда + ВызватьИсключение; + КонецЕсли; + КонецПопытки; + Если Не Константы.ПервоеОбновлениеДоступаЗавершилось.Получить() Тогда + Константы.ПервоеОбновлениеДоступаЗавершилось.Установить(Истина); + КонецЕсли; + КонецЕсли; + Исключение + ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст); + ВызватьИсключение; + КонецПопытки; + + ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст); + +КонецПроцедуры + +// Для процедуры ОбновитьСоставИспользуемыхВерсийПараметровШаблонов. +Функция ИспользуетсяОдинВариантДоступа(ДополнительныйКонтекст) + + ИспользуетсяНесколькоВариантов = Ложь; + + Для Каждого КлючИЗначение Из ДополнительныйКонтекст.ОсновныеВариантыДоступа Цикл + Если КлючИЗначение.Значение.Количество() > 1 Тогда + ИспользуетсяНесколькоВариантов = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Не ИспользуетсяНесколькоВариантов; + +КонецФункции + +// Для процедуры ЗавершитьОбновлениеДоступа. +Процедура ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий(Контекст) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("НедоступныеСпискиДляОбновленияКлючейДоступаКДанным", Новый Массив); + Запрос.УстановитьПараметр("НедоступныеСпискиДляОбновленияКлючейДоступаПользователей", Новый Массив); + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаКДанным.Список КАК Список + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + |ГДЕ + | НЕ ОбновлениеКлючейДоступаКДанным.Список В (&НедоступныеСпискиДляОбновленияКлючейДоступаКДанным) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаПользователей.Список КАК Список + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей + |ГДЕ + | НЕ ОбновлениеКлючейДоступаПользователей.Список В (&НедоступныеСпискиДляОбновленияКлючейДоступаПользователей)"; + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Если Не РезультатыЗапроса[0].Пустой() Тогда + УстановитьНедоступныеСписки(РезультатыЗапроса[0], + Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным); + КонецЕсли; + + Если Не РезультатыЗапроса[1].Пустой() Тогда + УстановитьНедоступныеСписки(РезультатыЗапроса[1], + Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным); + КонецЕсли; + + Если Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаКДанным.Количество() > 0 + Или Запрос.Параметры.НедоступныеСпискиДляОбновленияКлючейДоступаПользователей.Количество() > 0 Тогда + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + КонецЕсли; + + Если РезультатыЗапроса[0].Пустой() + И РезультатыЗапроса[1].Пустой() Тогда + + Блокировка = Новый БлокировкаДанных; + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаПользователей"); + НачатьТранзакцию(); + Попытка + Контекст.ОшибкаОжиданияБлокировкиДанных = Истина; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + РегламентныеЗаданияСервер.ЗаблокироватьРегламентноеЗадание(Новый УникальныйИдентификатор); + КонецЕсли; + Блокировка.Заблокировать(); + Контекст.ОшибкаОжиданияБлокировкиДанных = Ложь; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Если РезультатыЗапроса[0].Пустой() + И РезультатыЗапроса[1].Пустой() Тогда + + Если ЗначениеЗаполнено(Контекст.ДатаПолногоЗавершения) Тогда + ГраницаОтключения = ТекущаяДатаСеанса() + - КоличествоСекундПередОтключениемРегламентногоЗаданияПослеПолногоЗавершенияОбновления(); + Если Контекст.ДатаПолногоЗавершения < ГраницаОтключения Тогда + УстановитьОбновлениеДоступа(Ложь); + КонецЕсли; + Иначе + Контекст.ДатаПолногоЗавершения = ТекущаяДатаСеанса(); + КонецЕсли; + Иначе + Контекст.ОбработкаЗавершена = Ложь; + Контекст.ДатаПолногоЗавершения = '00010101'; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + Контекст.ОбработкаЗавершена = Ложь; + ВызватьИсключение; + КонецПопытки; + Иначе + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОтключитьРегламентноеЗаданиеЕслиНетНовыхЗаданий. +// +// Параметры: +// РезультатЗапроса - РезультатЗапроса +// НедоступныеСписки - Массив +// +Процедура УстановитьНедоступныеСписки(РезультатЗапроса, НедоступныеСписки) + + ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( + РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Список"), Ложь); + + Для Каждого КлючИЗначение Из ОбъектыМетаданныхПоИдентификаторам Цикл + Если КлючИЗначение.Значение = Неопределено Тогда + НедоступныеСписки.Добавить(КлючИЗначение.Ключ); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Функция ЗапуститьОбновлениеДоступаСписка(Задание, Контекст) + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + Показатели.НачалоВыдачиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + ОбработатьВыполненныеЗадания(Контекст, Задание.ЗанятыеПотоки); + + Если ЗначениеЗаполнено(Контекст.ТекстОшибкиЗавершения) Тогда + Возврат Ложь; + КонецЕсли; + + Если Задание.ЗанятыеПотоки.Количество() > 0 И Контекст.ПервыйПроход Тогда + Возврат Истина; // Уже запущено. + КонецЕсли; + + Если ОбщееЗаданиеВыполняется(Задание) + И Не ЗапускатьОбновлениеПолученныхПорцийПриПолученииНовыхПорций() Тогда + Возврат Истина; + КонецЕсли; + + ОбщиеПараметрыОбновления = ОписаниеОбщихПараметровОбновления(Контекст); + ЗаполнитьЗначенияСвойств(ОбщиеПараметрыОбновления, Контекст.ОбщиеПараметрыОбновления); + ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав = Задание.ЭтоОбновлениеПрав; + ОбщиеПараметрыОбновления.ИдентификаторСписка = Задание.ИдентификаторСписка; + ОбщиеПараметрыОбновления.ДляВнешнихПользователей = Задание.ДляВнешнихПользователей; + ОбщиеПараметрыОбновления.РазрешенаОбработкаУстаревшихЭлементов = Задание.РазрешенаОбработкаУстаревшихЭлементов; + + НаборПорций = Задание.НаборПорций; + ПоследнийИндекс = НаборПорций.Количество() - 1; + + ИндексСледующейПорцииДляОбработки = Задание.ИндексСледующейПорцииДляОбработки; + ПорцияДляОбработки = Неопределено; + Для Индекс = ИндексСледующейПорцииДляОбработки По ПоследнийИндекс Цикл + ПорцияЭлементов = НаборПорций.Получить(Индекс); + Если Не ПорцияЭлементов.Обработана И Не ПорцияЭлементов.Обрабатывается Тогда + ПорцияДляОбработки = ПорцияЭлементов; + Задание.ИндексСледующейПорцииДляОбработки = Индекс; + ИндексСледующейПорцииДляОбработки = Индекс + 1; + Прервать; + КонецЕсли; + КонецЦикла; + + Если ПорцияДляОбработки = Неопределено Тогда + Задание.ИндексСледующейПорцииДляОбработки = ПоследнийИндекс + 1; + ПредыдущаяПорция = Неопределено; + + ИначеЕсли Индекс > 0 Тогда + ПредыдущаяПорция = НаборПорций.Получить(Индекс - 1); + Иначе + ПредыдущаяПорция = Неопределено; + КонецЕсли; + + Если Не Задание.ЕстьТочечноеЗадание И ПорцияДляОбработки <> Неопределено Тогда + Если ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + ?(ПредыдущаяПорция = Неопределено, Задание.ДатаПоследнегоОбновленногоЭлемента, + ПредыдущаяПорция.ДатаПоследнегоЭлементаПорции)) Тогда + Возврат Истина; + КонецЕсли; + ОбщиеПараметрыОбновления.Вставить("ПорцияИзНабора", ПорцияДляОбработки); + ПорцияДляОбработки.Обрабатывается = Истина; + Задание.ИндексСледующейПорцииДляОбработки = ИндексСледующейПорцииДляОбработки; + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки = Контекст.МаксимумМиллисекундОбработкиПорции; + Иначе + ПоследняяПорция = ?(ПоследнийИндекс > -1, НаборПорций[ПоследнийИндекс], Неопределено); + + Если ПоследняяПорция <> Неопределено + И (ПоследняяПорция.ПоследнийЭлементПорции.ВидКлючаДанных + <> ПоследняяПорция.НовыйПоследнийЭлементПорции.ВидКлючаДанных + Или ПоследняяПорция.НовыйПоследнийЭлементПорции.КлючДанных = Null + Или Не ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав + И ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + ПоследняяПорция.ДатаПоследнегоЭлементаПорции)) Тогда + + ПолучитьПорции = 0; + Иначе + КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки; + ПолучитьПорции = (Контекст.КоличествоДополнительныхПорций + 2) * 2; + Если Задание.ЕстьТочечноеЗадание Тогда + ПолучитьПорции = ПолучитьПорции - КоличествоПорцийДляОбработки; + Если ПолучитьПорции - КоличествоПорцийДляОбработки < Цел(ПолучитьПорции / 3) Тогда + ПолучитьПорции = Цел(ПолучитьПорции / 3); + Иначе + ПолучитьПорции = ПолучитьПорции - КоличествоПорцийДляОбработки; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если Не Задание.ЕстьТочечноеЗадание И ПолучитьПорции = 0 Тогда + Возврат Истина; + КонецЕсли; + + ОбщиеПараметрыОбновления.Вставить("ПолучитьПорции", ПолучитьПорции); + Если ПоследняяПорция <> Неопределено Тогда + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийЭлементПорции", + ПоследняяПорция.НовыйПоследнийЭлементПорции); + КонецЕсли; + Если ПолучитьПорции > 0 Тогда + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки = МаксимумМиллисекундПолученияПорций(Контекст); + КонецЕсли; + КонецЕсли; + + Если Не ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") И ОбщееЗаданиеВыполняется(Задание) Тогда + Возврат Истина; + КонецЕсли; + + Если Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных + И Не Задание.ЭтоОбновлениеПрав + И ОбщиеПараметрыОбновления.Свойство("ПолучитьПорции") + И ОбщиеПараметрыОбновления.ПолучитьПорции > 0 Тогда + + Если Задание.ЕстьТочечноеЗадание Тогда + ОбщиеПараметрыОбновления.ПолучитьПорции = 0; + ИначеЕсли ЭтоДлительноеЗаданиеПолученияПорций(Задание) Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Если Задание.ЕстьТочечноеЗадание Тогда + Задание.ЕстьТочечноеЗадание = Ложь; + ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание); + Задание.ДатаПоследнегоЗапускаТочечногоЗадания = ТекущаяДатаСеанса(); + Иначе + Задание.ДатаПоследнегоЗапускаОбщегоЗадания = ТекущаяДатаСеанса(); + КонецЕсли; + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст); + ОбработатьРезультатЗадания(Контекст, ОбщиеПараметрыОбновления, Задание); + Иначе + Для Каждого СвободныйПоток Из Контекст.СвободныеПотоки Цикл + Прервать; + КонецЦикла; + Если СвободныйПоток = Неопределено Тогда + Если Контекст.ЗанятыеПотоки.Количество() >= Контекст.КоличествоПотоков Тогда + Возврат Истина; + КонецЕсли; + СвободныйПоток = НовыйПоток(); + Параметры = Новый Массив; + Параметры.Добавить(Контекст.ОписаниеОсновногоСеанса); + СвободныйПоток.ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяМетодаПотокаОбновленияДоступа(), Параметры,, + НСтр("ru = 'Управление доступом: Поток обновления доступа на уровне записей'", + ОбщегоНазначения.КодОсновногоЯзыка())); + СвободныйПоток.ИдентификаторПотока = СвободныйПоток.ФоновоеЗадание.УникальныйИдентификатор; + Контекст.СвободныеПотоки.Добавить(СвободныйПоток); + КонецЕсли; + + ИдентификаторПотока = СвободныйПоток.ИдентификаторПотока; + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока); + ЗаписьНабора = НаборЗаписей.Добавить(); + ЗаписьНабора.ИдентификаторПотока = ИдентификаторПотока; + ЗаписьНабора.ЭтоЗапуск = Истина; + ЗаписьНабора.Параметры = Новый ХранилищеЗначения(ОбщиеПараметрыОбновления); + ЗаписьНабора.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + + НаборЗаписей.Записать(); + + СвободныйПоток.Задание = Задание; + СвободныйПоток.МоментЗапускаЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + СвободныйПоток.ПорцияИзНабора = ?(ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора"), + ОбщиеПараметрыОбновления.ПорцияИзНабора, Неопределено); + СвободныйПоток.ПолучитьПорции = ?(ОбщиеПараметрыОбновления.Свойство("ПолучитьПорции"), + ОбщиеПараметрыОбновления.ПолучитьПорции, 0); + Задание.ЗанятыеПотоки.Вставить(ИдентификаторПотока, СвободныйПоток); + Контекст.ЗанятыеПотоки.Вставить(ИдентификаторПотока, СвободныйПоток); + Контекст.СвободныеПотоки.Удалить(0); + Если Показатели <> Неопределено Тогда + СнятьПоказателиВыдачиЗаданий(Показатели); + КонецЕсли; + Контекст.ЕстьЗапущенноеЗадание = Истина; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ОбработатьРезультатЗадания. +Функция ОбщееЗаданиеВыполняется(Задание) + + Для Каждого ОписаниеЗанятогоПотока Из Задание.ЗанятыеПотоки Цикл + Если ОписаниеЗанятогоПотока.Значение.ПорцияИзНабора = Неопределено Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ОтменитьФоновыеЗаданияПотоковОбновленияДоступа. +Функция ИмяМетодаПотокаОбновленияДоступа() + + Возврат "УправлениеДоступомСлужебный.ВыполнитьОбновлениеДоступаСпискаВФоне"; + +КонецФункции + +// Для процедур УстановитьОбновлениеДоступа, ЗапуститьОбновлениеДоступаНаУровнеЗаписей, +// ОтменитьОбновлениеДоступаНаУровнеЗаписей и функции ИсполнительОбновленияДоступа. +// +Функция ИмяМетодаЗаданияОбновленияДоступа() + + Возврат Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.ИмяМетода; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа, ЗавершитьОбновлениеДоступа. +Процедура ПодождатьОсвобожденияПотока(Контекст, ЖдатьЗавершенияЗадания = Ложь) + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Возврат; + КонецЕсли; + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + НачалоОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Выполнять = Истина; + + Если ЖдатьЗавершенияЗадания Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторыПотоков", ИдентификаторыПотоков(Контекст.ЗанятыеПотоки)); + Запрос.УстановитьПараметр("КоличествоПотоков", Контекст.КоличествоПотоков); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | ТекущиеЗадания.ИдентификаторПотока В(&ИдентификаторыПотоков) + | + |СГРУППИРОВАТЬ ПО + | ТекущиеЗадания.ИдентификаторПотока + | + |ИМЕЮЩИЕ + | (МИНИМУМ(ТекущиеЗадания.ЭтоЗапуск) = ЛОЖЬ + | ИЛИ КОЛИЧЕСТВО(ТекущиеЗадания.ЭтоЗапуск) < &КоличествоПотоков)"; + Если Не Запрос.Выполнить().Пустой() Тогда + Выполнять = Ложь; + КонецЕсли; + ГраницаОжидания = ТекущаяДатаСеанса() + 5; + КонецЕсли; + + Пока Выполнять Цикл + Если Контекст.ТекущееФоновоеЗадание <> Неопределено Тогда + ФоновоеЗадание = Контекст.ТекущееФоновоеЗадание; + Иначе + ФоновоеЗадание = Неопределено; + Для Каждого ОписаниеПотока Из Контекст.ЗанятыеПотоки Цикл + Поток = ОписаниеПотока.Значение; + ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); + Если Поток.ФоновоеЗадание <> Неопределено + И Поток.ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + + ФоновоеЗадание = Поток.ФоновоеЗадание; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ФоновоеЗадание = Неопределено Тогда + Прервать; + КонецЕсли; + ФоновоеЗадание.ОжидатьЗавершенияВыполнения(0.025); + Если Не ЖдатьЗавершенияЗадания + Или ТекущаяДатаСеанса() > ГраницаОжидания + Или Контекст.ЗанятыеПотоки.Количество() = 0 Тогда + Прервать; + КонецЕсли; + // @skip-check query-in-loop - Порционная обработка данных + Если Не Запрос.Выполнить().Пустой() Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + Если Показатели <> Неопределено Тогда + Показатели.ВремяОжиданийСвободногоПотока = Показатели.ВремяОжиданийСвободногоПотока + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОжидания); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПодождатьОсвобожденияПотока, ОбработатьВыполненныеЗадания. +Функция ИдентификаторыПотоков(ЗанятыеПотоки) + + ИдентификаторыПотоков = Новый Массив; + + Для Каждого ОписаниеПотока Из ЗанятыеПотоки Цикл + ИдентификаторыПотоков.Добавить(ОписаниеПотока.Ключ); + КонецЦикла; + + Возврат ИдентификаторыПотоков; + +КонецФункции + +// Для процедур ПодождатьОсвобожденияПотока, УдалитьОстановленныеПотоки. +Процедура ОбновитьСвойстваФоновогоЗадания(Поток, Контекст) + + ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Поток.ИдентификаторПотока); + + Если ФоновоеЗадание = Неопределено Тогда + Если РегистрироватьПоказателиОбновленияДоступа() Тогда + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( + НСтр("ru = 'Не удалось найти запущенное фоновое задание.'"), Поток.Задание, Истина), Контекст); + КонецЕсли; + Контекст.ОбработкаЗавершена = Ложь; + Возврат; + КонецЕсли; + Поток.ФоновоеЗадание = ФоновоеЗадание; + +КонецПроцедуры + +// Для процедуры ОбработатьВыполненныеЗадания. +Процедура ОтменитьФоновоеЗаданиеПотока(Поток, Контекст) + + ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); + ФоновоеЗадание = Поток.ФоновоеЗадание; + + Если ФоновоеЗадание = Неопределено + Или ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Активно Тогда + + Возврат; + КонецЕсли; + + Попытка + ФоновоеЗадание.Отменить(); + Исключение + ПредставлениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось отменить фоновое задание потока по причине: + |%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( + ПредставлениеОшибки, Поток.Задание, Истина), Контекст); + КонецПопытки; + + Контекст.ОбработкаЗавершена = Ложь; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа, ОбработатьРезультатЗадания. +Процедура ОбработатьВыполненныеЗадания(Контекст, ЗанятыеПотоки = Неопределено) + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Если ОбновлениеДоступаОтменено() Тогда + Контекст.ОбновлениеОтменено = Истина; + КонецЕсли; + Возврат; + КонецЕсли; + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + НачалоОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Если ЗанятыеПотоки = Неопределено Тогда + ЗанятыеПотоки = Контекст.ЗанятыеПотоки; + КонецЕсли; + ОписаниеПотоков = Новый Соответствие(Новый ФиксированноеСоответствие(ЗанятыеПотоки)); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторОтмены", ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей()); + Запрос.УстановитьПараметр("ИдентификаторыПотоков", ИдентификаторыПотоков(ОписаниеПотоков)); + Запрос.УстановитьПараметр("ГраницаОжиданияВыполнения", ТекущаяДатаСеанса() + - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()); + + Запрос.Текст = + "ВЫБРАТЬ + | ТекущиеЗадания.ИдентификаторПотока КАК ИдентификаторПотока, + | ТекущиеЗадания.Результат КАК Результат, + | ТекущиеЗадания.ЭтоЗапуск + | И &ГраницаОжиданияВыполнения > ТекущиеЗадания.ДатаИзмененияЗаписиРегистра + | ИЛИ ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторОтмены КАК ПревышеноВремяВыполнения, + | ТекущиеЗадания.ДатаИзмененияЗаписиРегистра КАК ДатаИзмененияЗаписиРегистра + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | (НЕ ТекущиеЗадания.ЭтоЗапуск + | И ТекущиеЗадания.ИдентификаторПотока В (&ИдентификаторыПотоков) + | ИЛИ ТекущиеЗадания.ЭтоЗапуск + | И &ГраницаОжиданияВыполнения > ТекущиеЗадания.ДатаИзмененияЗаписиРегистра + | ИЛИ ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторОтмены)"; + + ОписаниеРезультатов = Новый Соответствие; + Выборка = Запрос.Выполнить().Выбрать(); + + Пока Выборка.Следующий() Цикл + Если Выборка.ПревышеноВремяВыполнения = Истина Тогда + Если Выборка.ИдентификаторПотока = ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей() Тогда + Контекст.ОбновлениеОтменено = Истина; + Возврат; + КонецЕсли; + Поток = Контекст.ЗанятыеПотоки.Получить(Выборка.ИдентификаторПотока); + Если Поток = Неопределено Тогда + Для Каждого СвободныйПоток Из Контекст.СвободныеПотоки Цикл + Если СвободныйПоток.ИдентификаторПотока = Выборка.ИдентификаторПотока Тогда + Поток = СвободныйПоток; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если Поток = Неопределено Тогда + Продолжить; + КонецЕсли; + Если Поток.Задание.ИдентификаторСписка = Контекст.ИдентификаторСправочникаНаборыГруппДоступа + И Выборка.ДатаИзмененияЗаписиРегистра > (Запрос.Параметры.ГраницаОжиданияВыполнения + - МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()) Тогда + Продолжить; + КонецЕсли; + + ПредставлениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Превышено время выполнения задания в потоке (%1 сек). + |Рекомендуется реиндексация и обновление статистик таблиц базы данных. + |В некоторых случаях, достаточно запустить обновление доступа еще раз. + |См. также режим ""Медленный диск"" в панели настройки количества потоков.'"), + МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке()); + + Поток.Задание.БылаОшибка = Истина; + Поток.Задание.ТекстОшибки = ТекстОшибкиОбновленияСКонтекстом(ПредставлениеОшибки, Поток.Задание); + + ОтменитьФоновоеЗаданиеПотока(Поток, Контекст); + УдалитьПоток(Поток, Контекст); + ОписаниеПотоков.Удалить(Поток.ИдентификаторПотока); + + Если Показатели <> Неопределено Тогда + Показатели.КоличествоПотоковСПревышениемВремениВыполнения = + Показатели.КоличествоПотоковСПревышениемВремениВыполнения + 1; + КонецЕсли; + + ИначеЕсли ТипЗнч(Выборка.Результат) = Тип("ХранилищеЗначения") Тогда + ОписаниеРезультата = Новый Структура; + ОписаниеРезультата.Вставить("ДатаЗавершения", Выборка.ДатаИзмененияЗаписиРегистра); + ОписаниеРезультата.Вставить("Результат", Выборка.Результат.Получить()); + ОписаниеРезультатов.Вставить(Выборка.ИдентификаторПотока, ОписаниеРезультата); + КонецЕсли; + КонецЦикла; + + ЗадержкаЗапроса = Контекст.МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных * 1000; + Для Каждого ОписаниеПотока Из ОписаниеПотоков Цикл + Поток = ОписаниеПотока.Значение; + ОписаниеРезультата = ОписаниеРезультатов.Получить(Поток.ИдентификаторПотока); + ОбработатьРезультатВыполненногоЗадания(Поток, ОписаниеРезультата, Контекст, ЗадержкаЗапроса); + КонецЦикла; + + КоличествоПотоков = Контекст.ЗанятыеПотоки.Количество() + Контекст.СвободныеПотоки.Количество(); + Если КоличествоПотоков > Контекст.КоличествоПотоков Тогда + Индекс = Контекст.СвободныеПотоки.Количество() - 1; + Пока Индекс >= 0 Цикл + СвободныйПоток = Контекст.СвободныеПотоки.Получить(Индекс); + УдалитьПоток(СвободныйПоток, Контекст); + Индекс = Индекс - 1; + КоличествоПотоков = КоличествоПотоков - 1; + Если КоличествоПотоков <= Контекст.КоличествоПотоков Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Ложь; + Если ЗадержкаЗапроса > 0 Тогда + ЭтоОбработкаУстаревшихЭлементов = Контекст.ОбщиеПараметрыОбновления.ЭтоОбработкаУстаревшихЭлементов; + ТекущиеЗанятыеПотоки = Новый Соответствие(Новый ФиксированноеСоответствие(Контекст.ЗанятыеПотоки)); + ТекущийМомент = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ДлительныеПотоки = Новый СписокЗначений; + ЕстьДлительноеЗаданиеПолученияПорций = Ложь; + Для Каждого ОписаниеПотока Из ТекущиеЗанятыеПотоки Цикл + Поток = ОписаниеПотока.Значение; // см. НовыйПоток + Если Поток.ПорцияИзНабора <> Неопределено + Или Поток.Задание.ЭтоОбновлениеПрав + Или Поток.ПолучитьПорции = 0 Тогда + Продолжить; + КонецЕсли; + Если ЭтоДлительноеЗаданиеПолученияПорций(Поток.Задание) Тогда + ЕстьДлительноеЗаданиеПолученияПорций = Истина; + КонецЕсли; + Если ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса / 2 Тогда + Продолжить; + КонецЕсли; + ДлительныеПотоки.Добавить(Поток, Формат(Поток.МоментЗапускаЗадания, "ЧЦ=23; ЧВН=")); + Если ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда + Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Истина; + КонецЕсли; + КонецЦикла; + Если Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных Тогда + ДлительныеПотоки.СортироватьПоПредставлению(); + Поток = ДлительныеПотоки.Получить(0).Значение; // см. НовыйПоток + Граница1 = ТекущаяДатаСеанса() + ЗадержкаЗапроса + 5; + Граница2 = ТекущаяДатаСеанса() + ЗадержкаЗапроса * 10; + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница1; + ДлительныеПотоки.Удалить(0); + Для Каждого ОписаниеПотока Из ДлительныеПотоки Цикл + Поток = ОписаниеПотока.Значение; // см. НовыйПоток + Если Не ЭтоОбработкаУстаревшихЭлементов И Поток.Задание.ЭтоОбработкаУстаревшихЭлементов Тогда + Граница2 = Граница2 + ЗадержкаЗапроса * 2; + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница2; + ИначеЕсли ТекущийМомент - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда + Продолжить; + Иначе + Граница1 = Граница1 + 10; + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = Граница1; + КонецЕсли; + ОтменитьФоновоеЗаданиеПотока(Поток, Контекст); + УдалитьПоток(Поток, Контекст); + Контекст.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); + КонецЦикла; + КонецЕсли; + Если ЕстьДлительноеЗаданиеПолученияПорций Тогда + Контекст.ЕстьДлительноеЗаданиеПолученияПорцийЭлементовДанных = Истина; + КонецЕсли; + КонецЕсли; + + Если ТекущаяДатаСеанса() > Контекст.ГраницаОбновленияЗаданий Тогда + Контекст.ГраницаОбновленияЗаданий = ТекущаяДатаСеанса() + 2; + УдалитьОстановленныеПотоки(Контекст, Контекст.ЗанятыеПотоки); + УдалитьОстановленныеПотоки(Контекст, Контекст.СвободныеПотоки); + УдалитьНеиспользуемыеСвободныеПотоки(Контекст); + КонецЕсли; + + Если Показатели <> Неопределено Тогда + Показатели.ВремяОбработкиРезультатовЗаданий = Показатели.ВремяОбработкиРезультатовЗаданий + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОбработки); + КонецЕсли; + +КонецПроцедуры + +// Параметры: +// Задание - СтрокаТаблицыЗначений из см. ТаблицаЗаданийОбновления +// +// Возвращаемое значение: +// Булево +// +Функция ЭтоДлительноеЗаданиеПолученияПорций(Задание) + + Возврат Задание.ДлительноеЗаданиеПолученияПорцийДо > ТекущаяДатаСеанса(); + +КонецФункции + +// Для процедур ОбработатьВыполненныеЗадания, ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора. +Функция ОбновлениеДоступаОтменено() + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторПотока", ИдентификаторОтменыОбновленияДоступаНаУровнеЗаписей()); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторПотока"; + + Возврат Не Запрос.Выполнить().Пустой(); + +КонецФункции + +// Для процедуры ОбработатьВыполненныеЗадания. +Процедура ОбработатьРезультатВыполненногоЗадания(Поток, ОписаниеРезультата, Контекст, ЗадержкаЗапроса) + + Если Не Поток.ОтменитьЗадание + И Не Поток.Задание.Удалить Тогда + + Если ОписаниеРезультата = Неопределено Тогда + Возврат; + ИначеЕсли ТипЗнч(ОписаниеРезультата.Результат) <> Тип("Структура") Тогда + Контекст.ОбработкаЗавершена = Ложь; + Иначе + Результат = ОписаниеРезультата.Результат; + Если Результат.Свойство("ПорцияИзНабора") Тогда + Результат.ПорцияИзНабора = Поток.ПорцияИзНабора; + КонецЕсли; + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + Показатели.НачалоОбработкиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + Если ЗадержкаЗапроса > 0 + И ЭтоДлительноеЗаданиеПолученияПорций(Поток.Задание) + И Результат.Свойство("НаборПорций") + И ТекущаяУниверсальнаяДатаВМиллисекундах() - Поток.МоментЗапускаЗадания < ЗадержкаЗапроса Тогда + Поток.Задание.ДлительноеЗаданиеПолученияПорцийДо = '00010101'; + КонецЕсли; + ОбработатьРезультатЗадания(Контекст, Результат, Поток.Задание); + Если Показатели <> Неопределено Тогда + СнятьПоказателиОбработкиРезультатаЗадания(Показатели); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если ОписаниеРезультата = Неопределено Тогда + ДатаЗавершения = Неопределено; + Иначе + ДатаЗавершения = ОписаниеРезультата.ДатаЗавершения; + КонецЕсли; + + ОсвободитьПоток(Поток, Контекст, ДатаЗавершения); + +КонецПроцедуры + +// Для процедур ОбработатьРезультатВыполненногоЗадания, УдалитьПоток. +Процедура ОсвободитьПоток(Поток, Контекст, ДатаЗавершения = Неопределено) + + ПозицияВставки = 0; + Если ДатаЗавершения = Неопределено Тогда + Поток.ДатаОсвобождения = ТекущаяДатаСеанса(); + Иначе + Поток.ДатаОсвобождения = ДатаЗавершения; + Количество = Контекст.СвободныеПотоки.Количество(); + Пока ПозицияВставки < Количество Цикл + ТекущийПоток = Контекст.СвободныеПотоки.Получить(ПозицияВставки); + Если ТекущийПоток.ДатаОсвобождения <= ДатаЗавершения Тогда + Прервать; + КонецЕсли; + ПозицияВставки = ПозицияВставки + 1; + КонецЦикла; + КонецЕсли; + + Контекст.СвободныеПотоки.Вставить(ПозицияВставки, Поток); + Контекст.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); + Поток.Задание.ЗанятыеПотоки.Удалить(Поток.ИдентификаторПотока); + Если Поток.ПорцияИзНабора <> Неопределено Тогда + СнятьПризнакОбрабатываетсяДляПорции(Поток, Поток.Задание); + Поток.ПорцияИзНабора = Неопределено; + КонецЕсли; + Поток.МоментЗапускаЗадания = 0; + Поток.ПолучитьПорции = 0; + Поток.Задание = Неопределено; + Поток.ОтменитьЗадание = Ложь; + +КонецПроцедуры + +// Для процедур ЗапуститьОбновлениеДоступаСписка, ОбработатьРезультатВыполненногоЗадания, ОсвободитьПоток. +Процедура СнятьПризнакОбрабатываетсяДляПорции(ПотокИлиРезультат, Задание) + + ПорцияИзНабора = Неопределено; + + Если Не ПотокИлиРезультат.Свойство("ПорцияИзНабора", ПорцияИзНабора) + Или ПорцияИзНабора = Неопределено + Или Не ПорцияИзНабора.Обрабатывается Тогда + Возврат; + КонецЕсли; + + Если Не ПорцияИзНабора.Обработана Тогда + ИндексПорции = Задание.НаборПорций.Найти(ПорцияИзНабора); + + Если ИндексПорции = Неопределено Тогда + Задание.ИндексСледующейПорцииДляОбработки = 0; + + ИначеЕсли Задание.ИндексСледующейПорцииДляОбработки > ИндексПорции Тогда + Задание.ИндексСледующейПорцииДляОбработки = ИндексПорции; + КонецЕсли; + КонецЕсли; + + ПорцияИзНабора.Обрабатывается = Ложь; + +КонецПроцедуры + +// Для процедуры ОбработатьРезультатВыполненногоЗадания, ЗавершитьОбновлениеДоступа. +Процедура УдалитьПоток(Поток, Контекст) + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + НаборЗаписей.Отбор.ИдентификаторПотока.Установить(Поток.ИдентификаторПотока); + НаборЗаписей.Записать(); + + Если Контекст.ЗанятыеПотоки.Получить(Поток.ИдентификаторПотока) <> Неопределено Тогда + ОсвободитьПоток(Поток, Контекст); + КонецЕсли; + + Индекс = Контекст.СвободныеПотоки.Найти(Поток); + Если Индекс <> Неопределено Тогда + Контекст.СвободныеПотоки.Удалить(Индекс); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбработатьРезультатВыполненногоЗадания, ЗавершитьОбновлениеДоступа. +Процедура УдалитьОстановленныеПотоки(Контекст, ОписаниеПотоков) + + Если ТипЗнч(ОписаниеПотоков) = Тип("Соответствие") Тогда + ИсходноеОписаниеПотоков = Новый ФиксированноеСоответствие(ОписаниеПотоков); + Иначе + ИсходноеОписаниеПотоков = Новый ФиксированныйМассив(ОписаниеПотоков); + КонецЕсли; + + Для Каждого ОписаниеПотока Из ИсходноеОписаниеПотоков Цикл + Если ТипЗнч(ОписаниеПотока) = Тип("КлючИЗначение") Тогда + Поток = ОписаниеПотока.Значение; + Иначе + Поток = ОписаниеПотока; + КонецЕсли; + ОбновитьСвойстваФоновогоЗадания(Поток, Контекст); + ФоновоеЗадание = Поток.ФоновоеЗадание; + + Если ФоновоеЗадание <> Неопределено + И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + Продолжить; + КонецЕсли; + Контекст.ОбработкаЗавершена = Ложь; + + УдалитьПоток(Поток, Контекст); + + Если ФоновоеЗадание <> Неопределено + И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда + + ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибкиОбновленияСКонтекстом( + ФоновоеЗадание.ИнформацияОбОшибке, Поток.Задание, Истина), Контекст); + + Если Контекст.Показатели <> Неопределено Тогда + Контекст.Показатели.КоличествоПотоковСНештатнымЗавершением = + Контекст.Показатели.КоличествоПотоковСНештатнымЗавершением + 1; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбработатьВыполненныеЗадания. +Процедура УдалитьНеиспользуемыеСвободныеПотоки(Контекст) + + Количество = Контекст.СвободныеПотоки.Количество(); + Если Количество = 0 Тогда + Возврат; + КонецЕсли; + + СвободныеПотоки = Контекст.СвободныеПотоки; + Индекс = Количество - 1; + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + + Пока Индекс >= 0 Цикл + Поток = СвободныеПотоки.Получить(Индекс); + Если ТекущаяДатаСеанса > Поток.ДатаОсвобождения + 15 Тогда + УдалитьПоток(Поток, Контекст); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ДобавитьЗаданияОбновленияДоступа и ОбработатьРезультатЗадания. +Процедура ОтменитьЗадание(Задание) + + Задание.НаборПорций = Новый Массив; + Задание.КоличествоПорцийДляОбработки = 0; + Задание.ИндексСледующейПорцииДляОбработки = 0; + + Для Каждого ОписаниеПотока Из Задание.ЗанятыеПотоки Цикл + ОписаниеПотока.Значение.ОтменитьЗадание = Истина; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗапуститьОбновлениеДоступаСписка, ОбработатьРезультатВыполненногоЗадания. +Процедура ОбработатьРезультатЗадания(Контекст, Результат, Задание) + + Если Результат.Свойство("НетЗаданий") Или Результат.Свойство("ПерезапускОбновления") Тогда + Если Результат.Свойство("ПерезапускОбновления") Тогда + Задание.ЕстьПерезапуск = Истина; + Если Результат.Свойство("ПерезапускОбновленияСНачала") Тогда + Задание.ЕстьНачальноеОбновление = Истина; + КонецЕсли; + КонецЕсли; + ОтменитьЗадание(Задание); + Если Результат.Свойство("НетЗаданий") Тогда + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + ОбновитьСвойстваЗадания(Задание, Новый Структура("КлючДанных", Null)); + Если Результат.НетЗаданий = "ОбъектМетаданныхОтключен" Тогда + Контекст.ИдентификаторыОтключенныхОбъектовМетаданных.Вставить(Задание.ИдентификаторСписка, Истина); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если Результат.Свойство("ТребуетсяПерезапускСеанса") Тогда + Контекст.ТребуетсяПерезапускСеанса = Истина; + Контекст.ОбработкаЗавершена = Ложь; + СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(Результат.ТребуетсяПерезапускСеанса); + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + Возврат; + КонецЕсли; + + Если Результат.Свойство("ТекстОшибкиЗавершения") Тогда + Если Не Результат.ОбработкаЗавершена Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + Если ЗначениеЗаполнено(Результат.ТекстОшибкиЗавершения) Тогда + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + ДобавитьТекстОшибкиЗавершения(Контекст.ТекстОшибкиЗавершения, Результат.ТекстОшибкиЗавершения); + Возврат; + КонецЕсли; + КонецЕсли; + + Если Результат.Свойство("НетЗаданий") Тогда + Возврат; + КонецЕсли; + + Если Результат.Свойство("НачальноеОбновлениеЗавершено") Тогда + Задание.ЕстьНачальноеОбновление = Ложь; + Задание.ЕстьПерезапуск = Ложь; + КонецЕсли; + + Если Результат.Свойство("ПорцияИзНабора") Тогда + ИсходнаяПорцияИзНабора = Результат.ПорцияИзНабора; + Если Результат.Свойство("НаборПорций") Тогда + Индекс = Задание.НаборПорций.Найти(ИсходнаяПорцияИзНабора); + Если Задание.ИндексСледующейПорцииДляОбработки > Индекс Тогда + Задание.ИндексСледующейПорцииДляОбработки = Индекс + 1; + КонецЕсли; + Для Каждого НоваяПорцияИзИсходной Из Результат.НаборПорций Цикл + Индекс = Индекс + 1; + Задание.НаборПорций.Вставить(Индекс, НоваяПорцияИзИсходной); + КонецЦикла; + Задание.КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки + + Результат.НаборПорций.Количество(); + ИсходнаяПорцияИзНабора.ПоследнийЭлементПорции = Результат.НовыйПоследнийОбновленныйЭлемент; + ИсходнаяПорцияИзНабора.НовыйПоследнийЭлементПорции = Результат.НовыйПоследнийОбновленныйЭлемент; + КонецЕсли; + ИсходнаяПорцияИзНабора.Обработана = Истина; + СнятьПризнакОбрабатываетсяДляПорции(Результат, Задание); + + ИначеЕсли Результат.Свойство("НаборПорций") Тогда + Для Каждого НоваяПорция Из Результат.НаборПорций Цикл + Задание.НаборПорций.Добавить(НоваяПорция); + КонецЦикла; + Задание.КоличествоПорцийДляОбработки = Задание.КоличествоПорцийДляОбработки + + Результат.НаборПорций.Количество(); + + ИначеЕсли Результат.Свойство("НовыйПоследнийОбновленныйЭлемент") Тогда + ОбновитьСвойстваЗадания(Задание, Результат.НовыйПоследнийОбновленныйЭлемент); + КонецЕсли; + + Если Результат.Свойство("ПорцияИзНабора") И ОбщееЗаданиеВыполняется(Задание) Тогда + Возврат; + КонецЕсли; + + Зафиксировать = Ложь; + Пока Задание.НаборПорций.Количество() > 0 Цикл + ПорцияИзНабора = Задание.НаборПорций[0]; + Если Не ПорцияИзНабора.Обработана Тогда + Прервать; + КонецЕсли; + Зафиксировать = Истина; + НовыйПоследнийОбновленныйЭлемент = ПорцияИзНабора.НовыйПоследнийЭлементПорции; + Задание.НаборПорций.Удалить(0); + Если Задание.ИндексСледующейПорцииДляОбработки > 0 Тогда + Задание.ИндексСледующейПорцииДляОбработки = Задание.ИндексСледующейПорцииДляОбработки - 1; + КонецЕсли; + КонецЦикла; + + Если Зафиксировать Тогда + ЗаписатьПоследнийОбновленныйЭлемент(Результат, НовыйПоследнийОбновленныйЭлемент); + ОбновитьСвойстваЗадания(Задание, НовыйПоследнийОбновленныйЭлемент); + Если Не Результат.ОбработкаЗавершена Тогда + Контекст.ОбработкаЗавершена = Ложь; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбработатьРезультатЗадания. +Процедура ОбновитьСвойстваЗадания(Задание, НовыйПоследнийОбновленныйЭлемент) + + Если НовыйПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда + Задание.Удалить = Истина; + Иначе + Если НовыйПоследнийОбновленныйЭлемент.Свойство("Дата") Тогда + Задание.ДатаПоследнегоОбновленногоЭлемента = НовыйПоследнийОбновленныйЭлемент.Дата; + Иначе + Задание.ДатаПоследнегоОбновленногоЭлемента = '00010101'; + КонецЕсли; + Задание.ЕстьДатаПоследнегоОбновленногоЭлемента + = ЗначениеЗаполнено(Задание.ДатаПоследнегоОбновленногоЭлемента); + + Задание.ПорядокВидаКлючаДанных = НовыйПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных; + ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов(Задание); + КонецЕсли; + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка. +Процедура ВыполнитьОбновлениеДоступаСпискаВФоне(ОписаниеРодительскогоСеанса) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + Контекст = Новый Структура; + Контекст.Вставить("Показатели", ПоказателиОбновленияИсполняющегоПотока()); + Контекст.Вставить("ОписаниеРодительскогоСеанса", ОписаниеРодительскогоСеанса); + + Если Не ИсполняющийПотокЗапущен(Контекст) Тогда + Возврат; + КонецЕсли; + Кэш = Новый Структура; + УстановитьЭтоСеансФоновогоОбновленияДоступа(); + + Пока Истина Цикл + Запрос = Контекст.Запрос; // Запрос + Выборка = Запрос.Выполнить().Выбрать(); + Если Не Выборка.Следующий() Тогда + Прервать; + КонецЕсли; + Если ТипЗнч(Выборка.Параметры) <> Тип("ХранилищеЗначения") Тогда + Если ПродолжитьОжиданиеНовогоЗадания(Контекст) Тогда + Продолжить; + Иначе + Прервать; + КонецЕсли; + КонецЕсли; + Результат = ОписаниеОбщихПараметровОбновления(); + Результат.Вставить("ОбработкаЗавершена", Ложь); + Результат.Вставить("ТекстОшибкиЗавершения", ""); + Попытка + ОбщиеПараметрыОбновления = Выборка.Параметры.Получить(); // см. ОписаниеОбщихПараметровОбновления + ЗаполнитьЗначенияСвойств(Результат, ОбщиеПараметрыОбновления); + ОбщиеПараметрыОбновления.Вставить("Кэш", Кэш); + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания = + Цел(0.025 * Результат.МаксимумМиллисекундОбработки) / 1000; + + ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст); + Результат.ОбработкаЗавершена = ОбщиеПараметрыОбновления.ОбработкаЗавершена; + + ВозвращаемыеСвойства = "НетЗаданий, ПерезапускОбновления, ПерезапускОбновленияСНачала, + |НаборПорций, НовыйПоследнийОбновленныйЭлемент, НачальноеОбновлениеЗавершено, + |ТекстОшибкиЗавершения, ТребуетсяПерезапускСеанса"; + Для Каждого КлючИЗначение Из Новый Структура(ВозвращаемыеСвойства) Цикл + Если ОбщиеПараметрыОбновления.Свойство(КлючИЗначение.Ключ) Тогда + Результат.Вставить(КлючИЗначение.Ключ, ОбщиеПараметрыОбновления[КлючИЗначение.Ключ]); + КонецЕсли; + КонецЦикла; + Если ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") Тогда + Результат.Вставить("ПорцияИзНабора"); + КонецЕсли; + Исключение + ДобавитьТекстОшибкиЗавершения(Результат.ТекстОшибкиЗавершения, ТекстОшибкиОбновленияСКонтекстом( + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()), Результат)); + КонецПопытки; + ЗаписатьРезультатОбновленияДоступаСпискаВФоне(Результат, Выборка.Параметры, Контекст); + КонецЦикла; + + ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока(Контекст); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Функция ИсполняющийПотокЗапущен(Контекст) + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + Контекст.Вставить("ТекущийСеанс", ТекущийСеанс); + + Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда + ТекстОшибки = НСтр("ru = 'Порция обновления доступа может обрабатываться только в фоновом задании.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Контекст.Вставить("ТекущееФоновоеЗадание", ТекущийСеанс.ПолучитьФоновоеЗадание()); + ИдентификаторПотока = Контекст.ТекущееФоновоеЗадание.УникальныйИдентификатор; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторПотока", ИдентификаторПотока); + Запрос.Текст = + "ВЫБРАТЬ + | ВЫБОР + | КОГДА ТекущиеЗадания.ЭтоЗапуск + | ТОГДА ТекущиеЗадания.Параметры + | ИНАЧЕ НЕОПРЕДЕЛЕНО + | КОНЕЦ КАК Параметры + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания КАК ТекущиеЗадания + |ГДЕ + | ТекущиеЗадания.ИдентификаторПотока = &ИдентификаторПотока"; + Контекст.Вставить("Запрос", Запрос); + + Блокировка = Новый("БлокировкаДанных"); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ОбновлениеКлючейДоступаТекущиеЗадания"); + ЭлементБлокировки.УстановитьЗначение("ИдентификаторПотока", ИдентификаторПотока); + Контекст.Вставить("Блокировка", Блокировка); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаТекущиеЗадания); + НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока); + Контекст.Вставить("НаборЗаписей", НаборЗаписей); + + ЗаписьНабора = НаборЗаписей.Добавить(); + ЗаписьНабора.ИдентификаторПотока = ИдентификаторПотока; + ЗаписьНабора.ЭтоЗапуск = Ложь; + Контекст.Вставить("ЗаписьНабора", ЗаписьНабора); + + // Ожидание признака запуска. + ГраницаОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + Пока Истина Цикл + Если Не Запрос.Выполнить().Пустой() Тогда + Прервать; + КонецЕсли; + Если ТекущаяУниверсальнаяДатаВМиллисекундах() > ГраницаОжидания Тогда + Возврат Ложь; + КонецЕсли; + Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения(0.025); + КонецЦикла; + + Контекст.Вставить("ГраницаПроверкиРодительскогоСеанса", ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000); + Контекст.Вставить("КоличествоСекундОжиданияДоПоискаНовогоЗадания", 0.025); + + Возврат Истина; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Функция ПродолжитьОжиданиеНовогоЗадания(Контекст) + + Если ТекущаяУниверсальнаяДатаВМиллисекундах() > Контекст.ГраницаПроверкиРодительскогоСеанса Тогда + Если ОбновлениеДоступаОтменено() Тогда + Возврат Ложь; + КонецЕсли; + Контекст.ГраницаПроверкиРодительскогоСеанса = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + Если Не СеансСуществует(Контекст.ОписаниеРодительскогоСеанса) Тогда + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Показатели = Контекст.Показатели; + Если Показатели <> Неопределено Тогда + Показатели.КоличествоОжиданийНовыхЗаданий = Показатели.КоличествоОжиданийНовыхЗаданий + 1; + КонецЕсли; + + НачалоОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + + Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения( + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания); + + Если Показатели <> Неопределено Тогда + Показатели.ВремяОжиданияНовыхЗаданий = Показатели.ВремяОжиданияНовыхЗаданий + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - НачалоОжидания); + КонецЕсли; + Если Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания < 1 Тогда + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания = + Контекст.КоличествоСекундОжиданияДоПоискаНовогоЗадания + 0.010; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для функции ПродолжитьОжиданиеНовогоЗадания. +Функция СеансСуществует(ОписаниеСеанса) + + Если ЗначениеЗаполнено(ОписаниеСеанса.ИдентификаторФоновогоЗадания) Тогда + ФоновоеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору( + ОписаниеСеанса.ИдентификаторФоновогоЗадания); + + Возврат ФоновоеЗадание <> Неопределено + И ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно; + КонецЕсли; + + ОсновнойСеансНайден = Ложь; + Сеансы = ПолучитьСеансыИнформационнойБазы(); + + Для Каждого Сеанс Из Сеансы Цикл + + Если Сеанс.НачалоСеанса = ОписаниеСеанса.НачалоСеанса + И Сеанс.НомерСеанса = ОписаниеСеанса.НомерСеанса Тогда + + ОсновнойСеансНайден = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат ОсновнойСеансНайден; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура ЗаписатьРезультатОбновленияДоступаСпискаВФоне(Результат, ИсходныеПараметры, Контекст) + + НачатьТранзакцию(); + Попытка + Контекст.Блокировка.Заблокировать(); + Запрос = Контекст.Запрос; // Запрос - + Выборка = Запрос.Выполнить().Выбрать(); + + Если Выборка.Следующий() + И XMLСтрока(Выборка.Параметры) = XMLСтрока(ИсходныеПараметры) Тогда + + Контекст.ЗаписьНабора.Параметры = ИсходныеПараметры; + Контекст.ЗаписьНабора.Результат = Новый ХранилищеЗначения(Результат); + Контекст.ЗаписьНабора.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + НаборЗаписей = Контекст.НаборЗаписей; // РегистрСведенийНаборЗаписей - + НаборЗаписей.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступа. +Функция ПоказателиОбновленияОсновногоСеанса() + + Если Не РегистрироватьПоказателиОбновленияДоступа() + Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда + Возврат Неопределено; + КонецЕсли; + + Показатели = Новый Структура; + Показатели.Вставить("ВремяПроверкиИОбновленияПараметровОграничения", 0); + Показатели.Вставить("ВремяОбновленияПараметровОграничения", 0); + + // Переменные. + Показатели.Вставить("НачалоРаботыВМиллисекундах", ТекущаяУниверсальнаяДатаВМиллисекундах()); + Показатели.Вставить("НачалоВыдачиЗадания"); + + Возврат Показатели; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступа. +Процедура ДобавитьПоказателиОбновленияУправляющегоПотока(Контекст) + + Показатели = Контекст.Показатели; + Если Показатели = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + ДобавитьПоказателиВыполненияЗаданий(Показатели); + Иначе + Показатели.Вставить("ВремяОжиданийСвободногоПотока", 0); + + Показатели.Вставить("КоличествоВыданныхЗаданий", 0); + Показатели.Вставить("ВремяВыдачиЗаданий", 0); + Показатели.Вставить("МинимальноеВремяВыдачиЗадания", 0); + Показатели.Вставить("МаксимальноеВремяВыдачиЗадания", 0); + + Показатели.Вставить("ВремяОбработкиРезультатовЗаданий", 0); + Показатели.Вставить("МинимальноеВремяОбработкиРезультатаЗадания", 0); + Показатели.Вставить("МаксимальноеВремяОбработкиРезультатаЗадания", 0); + + Показатели.Вставить("КоличествоПотоковСПревышениемВремениВыполнения", 0); + Показатели.Вставить("КоличествоПотоковСНештатнымЗавершением", 0); + + // Переменные. + Показатели.Вставить("НачалоОбработкиЗадания", 0); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Функция ПоказателиОбновленияИсполняющегоПотока() + + Если Не РегистрироватьПоказателиОбновленияДоступа() + Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда + Возврат Неопределено; + КонецЕсли; + + Показатели = Новый Структура; + + Показатели.Вставить("НачалоРаботыВМиллисекундах", ТекущаяУниверсальнаяДатаВМиллисекундах()); + Показатели.Вставить("КоличествоОжиданийНовыхЗаданий", 0); + Показатели.Вставить("ВремяОжиданияНовыхЗаданий", 0); + + ДобавитьПоказателиВыполненияЗаданий(Показатели); + + Возврат Показатели; + +КонецФункции + +// Для функций ПоказателиОбновленияУправляющегоПотока, ПоказателиОбновленияИсполняющегоПотока. +Процедура ДобавитьПоказателиВыполненияЗаданий(Показатели) + + // Переменные. + Показатели.Вставить("ЗаданиеСПолучениемПорций", Истина); + Показатели.Вставить("НачалоПервойПопыткиВыполненияЗадания", 0); + Показатели.Вставить("НачалоВыполненияЗадания", 0); + + // Общие показатели. + Показатели.Вставить("КоличествоЗаданийСПовторамиИзЗаОшибок", 0); + Показатели.Вставить("ВремяВыполненияЗаданийСПовторамиИзЗаОшибок", 0); + Показатели.Вставить("КоличествоПовторовЗаданийИзЗаОшибок", 0); + Показатели.Вставить("МаксимальноеКоличествоПовторовЗаданияПриОшибке", 0); + Показатели.Вставить("ТекстОшибокПриПопыткахПовтора", ""); + + // Получение порций или сразу обработка маленькой порции. + Показатели.Вставить("КоличествоВыполненныхЗаданийСПолучениемПорций", 0); + Показатели.Вставить("ВремяВыполненияЗаданийСПолучениемПорций", 0); + Показатели.Вставить("МинимальноеВремяВыполненияЗаданийСПолучениемПорций", 0); + Показатели.Вставить("МаксимальноеВремяВыполненияЗаданийСПолучениемПорций", 0); + + // Только обработки порции. + Показатели.Вставить("КоличествоВыполненныхЗаданийБезПолученияПорций", 0); + Показатели.Вставить("ВремяВыполненияЗаданийБезПолученияПорций", 0); + Показатели.Вставить("МинимальноеВремяВыполненияЗаданийБезПолученияПорций", 0); + Показатели.Вставить("МаксимальноеВремяВыполненияЗаданийБезПолученияПорций", 0); + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка. +Процедура СнятьПоказателиВыдачиЗаданий(Показатели) + + ВремяВыдачиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоВыдачиЗадания; + + Показатели.КоличествоВыданныхЗаданий = Показатели.КоличествоВыданныхЗаданий + 1; + Показатели.ВремяВыдачиЗаданий = Показатели.ВремяВыдачиЗаданий + ВремяВыдачиЗадания; + + Если Показатели.МинимальноеВремяВыдачиЗадания = 0 Тогда + Показатели.МинимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; + КонецЕсли; + Если ВремяВыдачиЗадания < Показатели.МинимальноеВремяВыдачиЗадания Тогда + Показатели.МинимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; + КонецЕсли; + + Если ВремяВыдачиЗадания > Показатели.МаксимальноеВремяВыдачиЗадания Тогда + Показатели.МаксимальноеВремяВыдачиЗадания = ВремяВыдачиЗадания; + КонецЕсли; + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка. +Процедура СнятьПоказателиОбработкиРезультатаЗадания(Показатели) + + ВремяОбработкиЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоОбработкиЗадания; + + Показатели.ВремяОбработкиРезультатовЗаданий = + Показатели.ВремяОбработкиРезультатовЗаданий + ВремяОбработкиЗадания; + + Если Показатели.МинимальноеВремяОбработкиРезультатаЗадания = 0 Тогда + Показатели.МинимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; + КонецЕсли; + Если ВремяОбработкиЗадания < Показатели.МинимальноеВремяОбработкиРезультатаЗадания Тогда + Показатели.МинимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; + КонецЕсли; + + Если ВремяОбработкиЗадания > Показатели.МаксимальноеВремяОбработкиРезультатаЗадания Тогда + Показатели.МаксимальноеВремяОбработкиРезультатаЗадания = ВремяОбработкиЗадания; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура СнятьПоказателиВыполненияЗадания(Показатели) + + ВремяВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоВыполненияЗадания; + + Если Показатели.ЗаданиеСПолучениемПорций Тогда + Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций = + Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций + 1; + + Показатели.ВремяВыполненияЗаданийСПолучениемПорций = + Показатели.ВремяВыполненияЗаданийСПолучениемПорций + ВремяВыполненияЗадания; + + Если Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = 0 Тогда + Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; + КонецЕсли; + Если ВремяВыполненияЗадания < Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций Тогда + Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; + КонецЕсли; + + Если ВремяВыполненияЗадания > Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций Тогда + Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций = ВремяВыполненияЗадания; + КонецЕсли; + Иначе + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций = + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций + 1; + + Показатели.ВремяВыполненияЗаданийБезПолученияПорций = + Показатели.ВремяВыполненияЗаданийБезПолученияПорций + ВремяВыполненияЗадания; + + Если Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = 0 Тогда + Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; + КонецЕсли; + Если ВремяВыполненияЗадания < Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций Тогда + Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; + КонецЕсли; + + Если ВремяВыполненияЗадания > Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций Тогда + Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций = ВремяВыполненияЗадания; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура СнятьПоказателиОшибокВыполненияЗадания(Показатели, ТекстОшибок, КоличествоОшибок); + + Если КоличествоОшибок = 0 Тогда + Возврат; + КонецЕсли; + + Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок = Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок + 1; + + Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок = Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок + + (ТекущаяУниверсальнаяДатаВМиллисекундах() - Показатели.НачалоПервойПопыткиВыполненияЗадания); + + Показатели.КоличествоПовторовЗаданийИзЗаОшибок = + Показатели.КоличествоПовторовЗаданийИзЗаОшибок + КоличествоОшибок; + + Если КоличествоОшибок > Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке Тогда + Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке = КоличествоОшибок; + КонецЕсли; + + ДобавитьТекстОшибкиЗавершения(Показатели.ТекстОшибокПриПопыткахПовтора, ТекстОшибок); + +КонецПроцедуры + +// Для процедур ЗарегистрироватьПоказателиОбновленияОсновногоПотока, +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока, +// ДобавитьЗначенияПоказателейРаботыСеанса, +// ДобавитьЗначенияПоказателейВыполненияЗаданий. +// +Функция ФорматСекунд(ЧислоСекунд) + + Если ЧислоСекунд = 0 Тогда + Возврат СтрЗаменить(Формат(1.111), "1", "0"); + КонецЕсли; + + Возврат Формат(ЧислоСекунд, "ЧДЦ=3; ЧГ="); + +КонецФункции + +// Для процедур ЗарегистрироватьПоказателиОбновленияОсновногоПотока, +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока, +// ДобавитьЗначенияПоказателейВыполненияЗаданий. +// +Функция ФорматКоличества(ЧислоКоличества) + + Возврат Формат(ЧислоКоличества, "ЧН=0; ЧГ="); + +КонецФункции + +// Для процедуры ЗавершитьОбновлениеДоступа. +Процедура ЗарегистрироватьПоказателиОбновленияОсновногоПотока(Контекст) + + Показатели = Контекст.Показатели; + Если Показатели = Неопределено Тогда + Возврат; + КонецЕсли; + + ОписаниеСеанса = Контекст.ОписаниеОсновногоСеанса; // См. ОписаниеОсновногоСеанса + + Если Контекст.ОбновлениеВЭтомСеансе Тогда + Комментарий = НСтр("ru = 'Завершен сеанс обновления доступа.'"); + ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса); + ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели); + Иначе + ВремяОжиданийСвободногоПотока = Показатели.ВремяОжиданийСвободногоПотока / 1000; + + ВремяВыдачиЗаданий = Показатели.ВремяВыдачиЗаданий / 1000; + МинимальноеВремяВыдачиЗадания = Показатели.МинимальноеВремяВыдачиЗадания / 1000; + МаксимальноеВремяВыдачиЗадания = Показатели.МаксимальноеВремяВыдачиЗадания / 1000; + + ВремяОбработкиРезультатовЗаданий = Показатели.ВремяОбработкиРезультатовЗаданий / 1000; + МинимальноеВремяОбработкиРезультатаЗадания = Показатели.МинимальноеВремяОбработкиРезультатаЗадания / 1000; + МаксимальноеВремяОбработкиРезультатаЗадания = Показатели.МаксимальноеВремяОбработкиРезультатаЗадания / 1000; + + Комментарий = НСтр("ru = 'Завершен сеанс управляющего потока обновления доступа.'"); + ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса); + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Время ожиданий свободного потока: %1 сек + | + |Количество выданных заданий: %2 + |Время выдачи заданий: %3 сек + |Минимальное время выдачи заданий: %4 сек + |Максимальное время выдачи заданий: %5 сек'"), + ФорматСекунд(ВремяОжиданийСвободногоПотока), + ФорматКоличества(Показатели.КоличествоВыданныхЗаданий), + ФорматСекунд(ВремяВыдачиЗаданий), + ФорматСекунд(МинимальноеВремяВыдачиЗадания), + ФорматСекунд(МаксимальноеВремяВыдачиЗадания)); + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Время обработки результатов заданий: %1 сек + |Минимальное время обработки результатов заданий: %2 сек + |Максимальное время обработки результатов заданий: %3 сек + | + |Количество потоков с превышением времени выполнения: %4 + |Количество потоков с нештатным завершением: %5'"), + ФорматСекунд(ВремяОбработкиРезультатовЗаданий), + ФорматСекунд(МинимальноеВремяОбработкиРезультатаЗадания), + ФорматСекунд(МаксимальноеВремяОбработкиРезультатаЗадания), + ФорматКоличества(Показатели.КоличествоПотоковСПревышениемВремениВыполнения), + ФорматКоличества(Показатели.КоличествоПотоковСНештатнымЗавершением)); + КонецЕсли; + Данные = ОписаниеСеанса.Идентификатор; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Показатели.Обновление доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, , Данные, Комментарий); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока(Контекст) + + Показатели = Контекст.Показатели; + Если Показатели = Неопределено Тогда + Возврат; + КонецЕсли; + + ВремяОжиданияНовыхЗаданий = Показатели.ВремяОжиданияНовыхЗаданий / 1000; + + Комментарий = НСтр("ru = 'Завершен сеанс исполняющего потока обновления доступа.'"); + ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, Контекст.ТекущийСеанс, Истина); + + ОписаниеСеанса = Контекст.ОписаниеРодительскогоСеанса; // См. ОписаниеОсновногоСеанса + + Комментарий = Комментарий + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Номер сеанса управляющего потока: %1 + |Начало сеанса управляющего потока: %2 + | + |Количество ожиданий новых заданий: %3 + |Время ожидания новых заданий: %4 сек'"), + ОписаниеСеанса.НомерСеанса, + ОписаниеСеанса.НачалоСеанса, + ФорматКоличества(Показатели.КоличествоОжиданийНовыхЗаданий), + ФорматСекунд(ВремяОжиданияНовыхЗаданий)); + + ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели); + Данные = ОписаниеСеанса.Идентификатор; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Показатели.Обновление доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, , Данные, Комментарий); + +КонецПроцедуры + +// Для процедур ЗарегистрироватьПоказателиОбновленияУправляющегоПотока и +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока. +// +Процедура ДобавитьЗначенияПоказателейРаботыСеанса(Комментарий, Показатели, ОписаниеСеанса, ЭтоИсполняющийПоток = Ложь) + + ВремяРаботы = (ТекущаяУниверсальнаяДатаВМиллисекундах() + - Показатели.НачалоРаботыВМиллисекундах) / 1000; + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Номер сеанса: %1 + |Начало сеанса: %2 + |Время работы: %3 сек'"), + ОписаниеСеанса.НомерСеанса, + ОписаниеСеанса.НачалоСеанса, + ФорматСекунд(ВремяРаботы)); + + Если ЭтоИсполняющийПоток Тогда + Возврат; + КонецЕсли; + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Время проверки и обновления параметров ограничения: %1 сек + |Время обновления параметров ограничения: %2 сек'"), + ФорматСекунд(Показатели.ВремяПроверкиИОбновленияПараметровОграничения / 1000), + ФорматСекунд(Показатели.ВремяОбновленияПараметровОграничения / 1000)); + +КонецПроцедуры + +// Для процедур ЗарегистрироватьПоказателиОбновленияУправляющегоПотока и +// ЗарегистрироватьПоказателиОбновленияИсполняющегоПотока. +// +Процедура ДобавитьЗначенияПоказателейВыполненияЗаданий(Комментарий, Показатели) + + ВремяВыполненияЗаданийСПолучениемПорций = Показатели.ВремяВыполненияЗаданийСПолучениемПорций / 1000; + МаксимальноеВремяВыполненияЗаданийСПолучениемПорций = Показатели.МаксимальноеВремяВыполненияЗаданийСПолучениемПорций / 1000; + МинимальноеВремяВыполненияЗаданийСПолучениемПорций = Показатели.МинимальноеВремяВыполненияЗаданийСПолучениемПорций / 1000; + + ВремяВыполненияЗаданийБезПолученияПорций = Показатели.ВремяВыполненияЗаданийБезПолученияПорций / 1000; + МаксимальноеВремяВыполненияЗаданийБезПолученияПорций = Показатели.МаксимальноеВремяВыполненияЗаданийБезПолученияПорций / 1000; + МинимальноеВремяВыполненияЗаданийБезПолученияПорций = Показатели.МинимальноеВремяВыполненияЗаданийБезПолученияПорций / 1000; + + КоличествоВыполненныхЗаданий = Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций + + Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций; + + ВремяВыполненияЗаданий = ВремяВыполненияЗаданийСПолучениемПорций + ВремяВыполненияЗаданийБезПолученияПорций; + ВремяВыполненияЗаданийСПовторамиИзЗаОшибок = Показатели.ВремяВыполненияЗаданийСПовторамиИзЗаОшибок / 1000; + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Количество выполненных заданий: %1 + |Время выполнения заданий: %2 сек + | + |Количество заданий с повторами из-за ошибок: %3 + |Время выполнения заданий с повторами из-за ошибок: %4 сек + |Количество повторов заданий из-за ошибок: %5 + |Максимум повторов отдельного задания из-за ошибок: %6'"), + ФорматКоличества(КоличествоВыполненныхЗаданий), + ФорматСекунд(ВремяВыполненияЗаданий), + ФорматКоличества(Показатели.КоличествоЗаданийСПовторамиИзЗаОшибок), + ФорматСекунд(ВремяВыполненияЗаданийСПовторамиИзЗаОшибок), + ФорматКоличества(Показатели.КоличествоПовторовЗаданийИзЗаОшибок), + ФорматКоличества(Показатели.МаксимальноеКоличествоПовторовЗаданияПриОшибке)); + + Комментарий = Комментарий + Символы.ПС + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Задания получения порций и/или обработки маленькой порции: + |- количество выполненных заданий: %1 + |- время выполнения заданий: %2 сек + |- минимальное время выполнения задания: %3 сек + |- максимальное время выполнения задания: %4 сек + | + |Задания обработки порций: + |- количество выполненных заданий: %5 + |- время выполнения заданий: %6 сек + |- минимальное время выполнения задания: %7 сек + |- максимальное время выполнения задания: %8 сек'"), + ФорматКоличества(Показатели.КоличествоВыполненныхЗаданийСПолучениемПорций), + ФорматСекунд(ВремяВыполненияЗаданийСПолучениемПорций), + ФорматСекунд(МинимальноеВремяВыполненияЗаданийСПолучениемПорций), + ФорматСекунд(МаксимальноеВремяВыполненияЗаданийСПолучениемПорций), + ФорматКоличества(Показатели.КоличествоВыполненныхЗаданийБезПолученияПорций), + ФорматСекунд(ВремяВыполненияЗаданийБезПолученияПорций), + ФорматСекунд(МинимальноеВремяВыполненияЗаданийБезПолученияПорций), + ФорматСекунд(МаксимальноеВремяВыполненияЗаданийБезПолученияПорций)); + + Если ЗначениеЗаполнено(Показатели.ТекстОшибокПриПопыткахПовтора) Тогда + Комментарий = Комментарий + Символы.ПС + Символы.ПС + + НСтр("ru = 'Тексты ошибок при попытках повторного выполнения:'") + + Символы.ПС + Символы.ПС + Показатели.ТекстОшибокПриПопыткахПовтора; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ОбработатьРезультатЗадания, ЗарегистрироватьОшибкуОбновленияДоступа. +Процедура ДобавитьТекстОшибкиЗавершения(ТекстОшибкиЗавершения, ТекстОшибки) + + Если Не ЗначениеЗаполнено(ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстОшибкиЗавершения) Тогда + Если СтрНайти(ТекстОшибкиЗавершения, ТекстОшибки) > 0 Тогда + Возврат; + КонецЕсли; + ТекстОшибкиЗавершения = ТекстОшибкиЗавершения + Символы.ПС + Символы.ПС; + КонецЕсли; + + ТекстОшибкиЗавершения = ТекстОшибкиЗавершения + ТекстОшибки; + +КонецПроцедуры + +// Для процедур ОбновитьСвойстваФоновогоЗадания, ОтменитьФоновоеЗаданиеПотока, ОбработатьВыполненныеЗадания, +// УдалитьОстановленныеПотоки, ВыполнитьОбновлениеДоступаСпискаВФоне. +// +Функция ТекстОшибкиОбновленияСКонтекстом(ИнформацияОбОшибке, ОбщиеПараметрыОбновления, УстранимаяОшибка = Ложь) + + Если ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда + ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + Иначе + ПредставлениеОшибки = Строка(ИнформацияОбОшибке); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда + Возврат ""; + КонецЕсли; + + Если ОбщиеПараметрыОбновления = Неопределено Тогда + ТекстОшибки = ПредставлениеОшибки; + + ИначеЕсли Не ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав Тогда + + Если ОбщиеПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа к элементам данных списка + |""%1"" (для внешних пользователей) + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа к элементам данных списка + |""%1"" (для пользователей) + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + КонецЕсли; + + Иначе // ОбновлениеКлючейДоступаПользователей. + + Если ОбщиеПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа внешних пользователей списка + |""%1"" + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить ключи доступа пользователей списка + |""%1"" + |по причине: + |%2'"), + Строка(ОбщиеПараметрыОбновления.ИдентификаторСписка), + ПредставлениеОшибки); + КонецЕсли; + КонецЕсли; + + Если УстранимаяОшибка Тогда + ТекстОшибки = НСтр("ru = 'Возникла устранимая ошибка (обновление продолжается автоматически).'") + + Символы.ПС + ТекстОшибки; + КонецЕсли; + + Возврат ТекстОшибки; + +КонецФункции + +// Для процедур ОбновлениеДоступаНаУровнеЗаписей, ЗавершитьФоновыеЗадания, +// ОбработатьРезультатВыполненногоЗадания, ОбновитьСвойстваФоновогоЗадания, +// ВыполнитьОбновлениеДоступаСпискаВФоне. +// +Процедура ЗарегистрироватьОшибкуОбновленияДоступа(ТекстОшибки, Контекст) + + Если Контекст.Свойство("ОписаниеРодительскогоСеанса") Тогда + ОписаниеСеанса = Контекст.ОписаниеРодительскогоСеанса; // См. ОписаниеОсновногоСеанса + Иначе + ОписаниеСеанса = Контекст.ОписаниеОсновногоСеанса; // См. ОписаниеОсновногоСеанса + КонецЕсли; + + Данные = ОписаниеСеанса.Идентификатор; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Обновление доступа на уровне записей'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Ошибка, , Данные, ТекстОшибки); + +КонецПроцедуры + +// Для функции ЗапуститьОбновлениеДоступаСписка и процедуры ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора(ОбщиеПараметрыОбновления, Контекст) + + Показатели = Контекст.Показатели; + + Если Показатели <> Неопределено Тогда + Показатели.НачалоПервойПопыткиВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + ПопыткаВыполнения = 1; + ОшибкиПопытокВыполнения = Новый Массив; + Пока Истина Цикл + ТекстОшибкиТекущейПопытки = ""; + Если Показатели <> Неопределено Тогда + Показатели.ЗаданиеСПолучениемПорций = Не ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора"); + Показатели.НачалоВыполненияЗадания = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + Попытка + ВыполнитьОбновлениеДоступаСписка(ОбщиеПараметрыОбновления); + Исключение + Если ТранзакцияАктивна() Тогда + ВызватьИсключение; + КонецЕсли; + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибкиТекущейПопытки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Если Показатели <> Неопределено И Не ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда + СнятьПоказателиВыполненияЗадания(Показатели); + КонецЕсли; + ТекстОшибкиТребуетсяПерезапуск = ""; + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(ТекстОшибкиТребуетсяПерезапуск) Тогда + ОбщиеПараметрыОбновления.Вставить("ТребуетсяПерезапускСеанса", ТекстОшибкиТребуетсяПерезапуск); + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + ТекстОшибкиТекущейПопытки = ""; + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда + ВремяОшибкиТекущейПопытки = Формат(ТекущаяДатаСеанса(), "ДЛФ=DT"); + ОшибкиПопытокВыполнения.Добавить(ВремяОшибкиТекущейПопытки + " " + ТекстОшибкиТекущейПопытки); + ПопыткаВыполнения = ПопыткаВыполнения + 1; + Если ПопыткаВыполнения < 9 И Не ЗначениеЗаполнено(ТекстОшибкиТребуетсяПерезапуск) Тогда + Для Счетчик = 1 По ПопыткаВыполнения Цикл + // @skip-check query-in-loop - Порционная обработка данных + Если ОбновлениеДоступаОтменено() Тогда + Прервать; + КонецЕсли; + Если Контекст.ТекущееФоновоеЗадание <> Неопределено Тогда + Контекст.ТекущееФоновоеЗадание.ОжидатьЗавершенияВыполнения(1); + Иначе + ГраницаОжидания = ТекущаяУниверсальнаяДатаВМиллисекундах() + 1000; + Пока ГраницаОжидания > ТекущаяУниверсальнаяДатаВМиллисекундах() Цикл + Продолжить; + КонецЦикла; + КонецЕсли; + КонецЦикла; + // @skip-check query-in-loop - Порционная обработка данных + Если Не ОбновлениеДоступаОтменено() Тогда + Продолжить; + КонецЕсли; + КонецЕсли; + КонецЕсли; + ТекстОшибки = СтрСоединить(ОшибкиПопытокВыполнения, Символы.ПС + "---" + Символы.ПС); + ТекстОшибки = ТекстОшибкиОбновленияСКонтекстом(ТекстОшибки, ОбщиеПараметрыОбновления); + + Если ЗначениеЗаполнено(ТекстОшибкиТекущейПопытки) Тогда + ОбщиеПараметрыОбновления.Вставить("ТекстОшибкиЗавершения", ""); + ДобавитьТекстОшибкиЗавершения(ОбщиеПараметрыОбновления.ТекстОшибкиЗавершения, ТекстОшибки); + КонецЕсли; + Если Показатели <> Неопределено Тогда + СнятьПоказателиОшибокВыполненияЗадания(Показатели, ТекстОшибки, ОшибкиПопытокВыполнения.Количество()); + КонецЕсли; + Прервать; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСпискаСПопыткамиПовтора. +Процедура ВыполнитьОбновлениеДоступаСписка(ОбщиеПараметрыОбновления) + + Если Не ОбщиеПараметрыОбновления.Свойство("Кэш") Тогда + ОбщиеПараметрыОбновления.Вставить("Кэш", Новый Структура); + КонецЕсли; + + Если ОбщиеПараметрыОбновления.ИдентификаторСписка = Неопределено Тогда + ОбъектМетаданных = Null; + ИначеЕсли ОбщиеПараметрыОбновления.Свойство("Кэш") + И ОбщиеПараметрыОбновления.Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда + + ОбъектМетаданных = ОбщиеПараметрыОбновления.Кэш.ОбъектыМетаданныхПоИдентификаторам.Получить( + ОбщиеПараметрыОбновления.ИдентификаторСписка); + Иначе + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору( + ОбщиеПараметрыОбновления.ИдентификаторСписка, Ложь); + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + // Если расширение конфигурации отключено, тогда обновление невозможно, + // но нельзя очищать регистрацию к обновлению. + ОбщиеПараметрыОбновления.Вставить("НетЗаданий", "ОбъектМетаданныхОтключен"); + Возврат; + КонецЕсли; + + ЭтоОбновлениеПрав = ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав; + + Если Не ОбщиеПараметрыОбновления.ДляВнешнихПользователей + И ОбщиеПараметрыОбновления.ИдентификаторСписка + = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка() Тогда + УдалитьОбъектыНедопустимыхТиповВРегистреКлючиДоступаКОбъектам(); + КонецЕсли; + + ПараметрыОбновления = ПараметрыОбновления(ОбщиеПараметрыОбновления, ОбъектМетаданных); + + // Обработка ранее подготовленной порции для обработки. + Если ОбщиеПараметрыОбновления.Свойство("ПорцияИзНабора") Тогда + ПорцияИзНабора = ОбщиеПараметрыОбновления.ПорцияИзНабора; // См. ПорцияИзНабора + ЭлементыПорции = ПорцияИзНабора.Элементы.Получить(); + ПараметрыОбновления.Вставить("ПоследнийОбновленныйЭлемент", + ПорцияИзНабора.ПоследнийЭлементПорции); + + ОбновитьПорциюЭлементов(ЭлементыПорции, ПараметрыОбновления); + + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); + + Если ЭлементыПорции <> Неопределено Тогда + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + ВыбраныВсеЭлементы = ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; + ОбщиеПараметрыОбновления.Вставить("НаборПорций", НаборПорцийЭлементов( + ПараметрыОбновления, ЭлементыПорции, ВыбраныВсеЭлементы)); + КонецЕсли; + Возврат; + КонецЕсли; + + // Подготовка плана обработки элементов данных. + ПодготовкаЗавершена = Ложь; + ПараметрыОбновления.Вставить("ПерезапускОбновления", Ложь); + + Пока Не ПодготовкаЗавершена Цикл + ПодготовкаЗавершена = Истина; + ПараметрыОбновления.Вставить("ЕстьЗадания", Истина); + ПараметрыОбновления.Вставить("ТочечноеЗадание", Неопределено); + ПараметрыОбновления.Вставить("ПоследнийОбновленныйЭлемент", НачальныйЭлемент(ПараметрыОбновления)); + // @skip-check query-in-loop - Порционная обработка данных + ПодготовитьПланОбновления(ПараметрыОбновления, ПодготовкаЗавершена); + КонецЦикла; + + Если Не ПараметрыОбновления.ЕстьЗадания Тогда + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + Если Не ПараметрыОбновления.ЭтоОбновлениеПрав + И ПараметрыОбновления.БезОбновленияКлючейДоступаКОбъектам Тогда + + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Null; + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ТочечноеЗадание <> Неопределено Тогда + ВыбраныВсеЭлементы = Ложь; + Элементы = ЭлементыТочечногоЗаданияДляОбновления(ПараметрыОбновления, + КоличествоЭлементовВЗапросе(ЭтоОбновлениеПрав), ВыбраныВсеЭлементы); + + Если Элементы <> Неопределено Тогда + МаксимумМиллисекунд = МинимальноеКоличествоСекундВыполненияТочечногоЗадания() * 1000; + Если ПараметрыОбновления.ГраницаВремениОбработки - ТекущаяУниверсальнаяДатаВМиллисекундах() < МаксимумМиллисекунд Тогда + ПараметрыОбновления.ГраницаВремениОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах() + МаксимумМиллисекунд; + КонецЕсли; + ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления, Истина); + КонецЕсли; + Если Элементы <> Неопределено Или Не ВыбраныВсеЭлементы Тогда + ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении(ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + + УточнитьПоследнийОбновленныйЭлемент(ПараметрыОбновления); + + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Null; + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ТочечноеЗадание <> Неопределено Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Вставить("ОчиститьТочечноеЗадание"); + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Удалить("ОчиститьТочечноеЗадание"); + КонецЕсли; + + Если ПараметрыОбновления.ПерезапускОбновления Тогда + ОбщиеПараметрыОбновления.Вставить("ПерезапускОбновления"); + Если ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") Тогда + ОбщиеПараметрыОбновления.Удалить("НовыйПоследнийЭлементПорции"); + КонецЕсли; + КонецЕсли; + + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) + И Не ОбщиеПараметрыОбновления.РазрешенаОбработкаУстаревшихЭлементов Тогда + + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + ОбщиеПараметрыОбновления.Вставить("НачальноеОбновлениеЗавершено"); + Возврат; + КонецЕсли; + + Если ОбщиеПараметрыОбновления.ПолучитьПорции > 0 + И ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") Тогда + + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); + ЗаполнитьЗначенияСвойств(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + ОбщиеПараметрыОбновления.НовыйПоследнийЭлементПорции); + КонецЕсли; + + Если Не ЭтоОбновлениеПрав + И ПериодОбновленияДоПериодаДанных(ОбщиеПараметрыОбновления.ДатаНачала, + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата) Тогда + + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.ПоследнийОбновленныйЭлемент); + + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + Возврат; + КонецЕсли; + + // Однопоточное обновление некоторых наборов групп доступа. + Если Не ЭтоОбновлениеПрав + И ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + И ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных = Неопределено Тогда + + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + УстранитьДублиНаборовИзОдногоПользователяВСправочнике(ПараметрыОбновления); + + ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + ЗаполнитьПустыеХешиНаборовГрупп(ПараметрыОбновления); + + ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + ОбновитьПраваНаРазрешенныйКлючДоступа(); + КонецЕсли; + ОчиститьПраваПустогоНабораГруппДоступа(ПараметрыОбновления); + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ОчиститьПраваНесуществующихНаборовГруппДоступа(ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + + // Запрос элементов для обработки. + ВыбраныВсеЭлементы = Ложь; + + Если ОбщиеПараметрыОбновления.ПолучитьПорции > 0 Тогда + КоличествоВПорции = КоличествоЭлементовВПорции(ПараметрыОбновления); + КоличествоВЗапросе = КоличествоВПорции * ОбщиеПараметрыОбновления.ПолучитьПорции; + Элементы = ЭлементыДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы); + + Если ОбщиеПараметрыОбновления.Свойство("НовыйПоследнийЭлементПорции") + Или Элементы <> Неопределено + И Элементы.Количество() > КоличествоВПорции * 2 + Или КоличествоВЗапросе = Null Тогда + + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + ОбщиеПараметрыОбновления.Вставить("НаборПорций", НаборПорцийЭлементов( + ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы, КоличествоВПорции)); + Если КоличествоВЗапросе = Null Тогда + ОбщиеПараметрыОбновления.НаборПорций[0].Обработана = Истина; + КонецЕсли; + Возврат; + КонецЕсли; + Иначе + Возврат; + КонецЕсли; + + // Обработка элементов данных. + ПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + НачальныйЭлемент(ПараметрыОбновления, , Истина)); + + ОбщиеПараметрыОбновления.Вставить("НачальноеОбновлениеЗавершено"); + + Если Элементы <> Неопределено Тогда + ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления); + КонецЕсли; + + // Уточнение нового последнего элемента. + Если Элементы = Неопределено И ВыбраныВсеЭлементы Тогда + УстановитьПустойПоследнийЭлемент(ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент, + ПараметрыОбновления); + КонецЕсли; + + // Запись нового последнего элемента. + ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, + ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); + + Если ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда + ОбщиеПараметрыОбновления.Вставить("НетЗаданий"); + Возврат; + КонецЕсли; + + ОбщиеПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПараметрыОбновления.НовыйПоследнийОбновленныйЭлемент); + + // Подготовка оставшихся элементов к продолжению обновления. + Если Элементы <> Неопределено Тогда + ОбщиеПараметрыОбновления.Вставить("НаборПорций", + НаборПорцийЭлементов(ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы)); + КонецЕсли; + +КонецПроцедуры + +Функция ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + + Если ПараметрыОбновления.Свойство("Список") Тогда + Возврат ПараметрыОбновления.Список = "Справочник.НаборыГруппДоступа"; + КонецЕсли; + + Возврат ПараметрыОбновления.ИдентификаторСписка + = ПараметрыОбновления.ИдентификаторСправочникаНаборыГруппДоступа; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +// +// Возвращаемое значение: +// Структура: +// * ЭтоОбновлениеПрав - Булево +// * ИдентификаторСписка - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ДляВнешнихПользователей - Булево +// * Кэш - см. НовыйКэшКонтекста +// * ДатаНачала - Дата +// * ДатаОкончания - Дата +// * МаксимумПорцийИзИсходной - Число +// * ИдентификаторСправочникаНаборыГруппДоступа - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// * ГраницаВремениОбработки - Дата +// +// Свойства, если ЭтоСправочникНаборыГруппДоступа. +// * СписокСДатой - Булево +// * СписокСПериодом - Булево +// * ЭтоСсылочныйТип - Булево +// * ПустойНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа +// +// Свойства, если не ЭтоСправочникНаборыГруппДоступа. +// * ИдентификаторТранзакции - УникальныйИдентификатор +// * ЗависимыеСпискиПоКлючамДоступа - Массив из Строка - полные имена списков +// +// Свойства добавляемые в процессе работы. +// * ЕстьИзмененияПрав - Булево +// * ОбновитьПраваНаКлючи - Булево +// * ПоследнийОбновленныйЭлемент - см. НачальныйЭлемент +// * НовыйПоследнийОбновленныйЭлемент - см. НачальныйЭлемент +// * ПерезапускОбновления - Булево +// * ЕстьЗадания - Булево +// * ТочечноеЗадание - см. ПодготовленноеТочечноеЗадание +// * НаборПорций - Массив из см. ПорцияИзНабора +// * ТипПользователя - Тип +// * ТипГруппыПользователей - Тип +// * ТипГруппыДоступа - Тип +// * ПустаяГруппаДоступа - СправочникСсылка.ГруппыДоступа +// * ПраваГруппДоступаСписка - см. НовыеПраваГруппДоступаСписка +// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей +// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа +// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа +// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа +// * ЗначенияГруппДоступа - см. НовыеЗначенияГруппДоступа +// * РолиПрофилейГруппДоступа - см. НовыеРолиПрофилейГруппДоступа +// * ГруппыДоступаПрофилей - см. НовыеГруппыДоступаПрофилей +// * ПраваНаСпискиВедущихКлючейДоступа - см. НовыеПраваНаСпискиВедущихКлючейДоступа +// * ПраваНаВедущиеКлючиДоступа - см. НовыеПраваНаВедущиеКлючиДоступа +// * ПраваНаВедущиеСписки - см. НовыеПраваНаВедущиеСписки +// * ПраваПоВладельцамНастроекПрав - см. НовыеПраваПоВладельцамНастроекПрав +// * МодельОбъектовВПамяти - см. МодельОбъектовВПамяти +// +// Копия свойств из ПараметрыОграниченияПоСтруктуреОграничения. +// * Список - Строка +// * ДляВнешнихПользователей - Булево +// * Версия - Строка +// * ВедущиеСписки - см. НовыеВедущиеСписки +// * ДоступЗапрещен - Булево +// * ОграничениеОтключено - Булево +// * ОграничениеЧтенияОтключено - Булево +// * ПолеВладельца - см. НовоеПолеВладельца +// * ТребуетсяОграничениеПоВладельцу - Булево +// * ИспользуетсяОграничениеПоВладельцу - Булево +// * РассчитыватьПраваПользователей - Булево +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа +// * ЧтениеРазрешеноДляВсехПользователей - Булево +// * ИзменениеРазрешеноДляВсехПользователей - Булево +// * ЕстьВедущиеКлючиДоступа - Булево +// * ЕстьВедущиеСпискиПоПравам - Булево +// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ИдентификаторТаблицыНастроекПрав - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// * ЕстьВладельцыНастроекПрав - Булево +// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип +// * ВсеВидыОграниченийПрав - Соответствие +// * ПоляТаблицОбъекта - Массив из см. НовыеПоляТаблицыОбъекта +// * ИмяОтдельногоРегистраКлючей - Строка +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ВариантДоступа - Число +// * СоставПолей - Число +// * ЕстьОграничениеЧтения - Булево +// * ЕстьОграничениеИзменения - Булево +// * ЕстьОграничениеПоПользователям - Булево +// * СтруктураРасчетаПраваЧтение - см. СтруктураРасчетаПрава +// * СтруктураРасчетаПраваИзменение - см. СтруктураРасчетаПрава +// * Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +// Свойства, добавляемые в процедуре ДобавитьТекстыЗапросовВПараметрыОграничения. +// * ТекстЗапросаПроверкиПравЧтениеИзменение - Строка +// * ТекстЗапросаПроверкиПраваЧтение - Строка +// * ПолеОбъектаВладельцаВЗапросеПроверкиПрав - Строка +// * ТекстЗапросаУстаревшихЭлементовДанных - Строка +// * ТекстЗапросаПроверкиУстаревшихЭлементовДанных - Строка +// * ТекстЗапросаНекорректныхЭлементовДанных - Строка +// * ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра - Строка +// * ТаблицыКлюча - Массив из Строка +// * РеквизитыТаблицКлюча - см. НовыеРеквизитыТаблицКлюча +// * ТекстЗапросаДиапазонаЭлементовДанных - Строка +// * ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами - Строка +// * ТекстЗапросаПроверкиКлючаДоступаОбъекта - Строка +// * ТекстЗапросаЭлементовДанныхБезКлючейДоступа - Строка +// * ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей - Строка +// * ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей - Строка +// * ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам - Соответствие из КлючИЗначение: +// ** Ключ - Строка +// ** Значение - Соответствие из КлючИЗначение: +// *** Ключ - Строка +// *** Значение - Соответствие +// - Структура: +// *** ТипСсылки - ХранилищеЗначения +// *** КлючиЗапросовПоТипам - Соответствие +// *** ТекстыЗапросовПоКлючам - Соответствие +// *** ТекстЗапросаПараметров - Строка +// - Строка +// * ТекстЗапросаТекущихКлючейДоступаРегистра - Строка +// * ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа - Строка +// * ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа - Строка +// * ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения - Строка +// * ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения - Строка +// * ТекстЗапросаСуществованияКлючейДляСравнения - Строка +// * ТекстЗапросаКлючейДоступаДляОбновленияПрав - Строка +// * ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав - Строка +// * ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав - Строка +// * ТекстЗапросаУстаревшихКлючейДоступа - Строка +// +Функция ПараметрыОбновления(ОбщиеПараметрыОбновления, ОбъектМетаданных) + + ПараметрыОбновления = Новый Структура("ЭтоОбновлениеПрав, + |ИдентификаторСписка, ДляВнешнихПользователей, Кэш, + |ДатаНачала, ДатаОкончания, МаксимумПорцийИзИсходной, + |ЭтоФоновоеОбновлениеДоступа, ИдентификаторСправочникаНаборыГруппДоступа"); + + ЗаполнитьЗначенияСвойств(ПараметрыОбновления, ОбщиеПараметрыОбновления); + + Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда + ПараметрыОбновления.Вставить("Список", ОбъектМетаданных.ПолноеИмя()); + КонецЕсли; + + ПараметрыОбновления.Вставить("ГраницаВремениОбработки", + ТекущаяУниверсальнаяДатаВМиллисекундах() + + ОбщиеПараметрыОбновления.МаксимумМиллисекундОбработки); + + ДобавитьПараметрыОграничения(ПараметрыОбновления); + + Возврат ПараметрыОбновления; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Процедура ДобавитьПараметрыОграничения(ПараметрыОбновления) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + ПараметрыОбновления.Вставить("СписокСДатой", Ложь); + ПараметрыОбновления.Вставить("СписокСПериодом", Ложь); + ПараметрыОбновления.Вставить("ЭтоСсылочныйТип", Истина); + ПараметрыОбновления.Вставить("ПустойНаборГруппДоступа", Справочники.НаборыГруппДоступа.ПустаяСсылка()); + ПараметрыОбновления.Вставить("БезОбновленияКлючейДоступаКОбъектам", Ложь); + Возврат; + КонецЕсли; + + ИдентификаторТранзакции = Новый УникальныйИдентификатор; + Список = ?(ПараметрыОбновления.Свойство("Список"), ПараметрыОбновления.Список, ""); + СвойстваСпискаКакВедущего = СвойстваСпискаКакВедущего(Список, ИдентификаторТранзакции); + ПараметрыОграничения = ПараметрыОграничения(Список, + ИдентификаторТранзакции, ПараметрыОбновления.ДляВнешнихПользователей); + + ПараметрыОграничения = Новый Структура(ПараметрыОграничения); + Для Каждого КлючИЗначение Из ПараметрыОбновления Цикл + ПараметрыОграничения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + ПараметрыОбновления = ПараметрыОграничения; + ПараметрыОбновления.Вставить("ИдентификаторТранзакции", ИдентификаторТранзакции); + + ИмяСвойстваВидаПользователей = ?(ПараметрыОбновления.ДляВнешнихПользователей, + "ДляВнешнихПользователей", "ДляПользователей"); + + Если СвойстваСпискаКакВедущего = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа = Неопределено + Или СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей] = Неопределено Тогда + + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", Новый Массив); + Иначе + ПараметрыОбновления.Вставить("ЗависимыеСпискиПоКлючамДоступа", + СвойстваСпискаКакВедущего.ПоКлючамДоступа[ИмяСвойстваВидаПользователей]); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ПодготовитьПланОбновления. +// +// Возвращаемое значение: +// Структура: +// * КлючДанных - ЛюбаяСсылка +// - Null +// - Структура +// * ОбработатьУстаревшиеЭлементы - Булево +// * ОбработатьНаборыГруппСУстаревшимиПравами - Булево +// * Дата - Дата +// +Функция НачальныйЭлемент(ПараметрыОбновления, ВидКлючаДанных = Неопределено, + СохранитьВидКлючаДанных = Ложь, ПерезапускОбновленияСНачала = Ложь) + + НачальныйЭлемент = Новый Структура; + НачальныйЭлемент.Вставить("КлючДанных"); + НачальныйЭлемент.Вставить("ОбработатьУстаревшиеЭлементы", Ложь); + НачальныйЭлемент.Вставить("ОбработатьНаборыГруппСУстаревшимиПравами", Ложь); + СохранитьСвойства = Ложь; + + Если ВидКлючаДанных = Неопределено Тогда + Если СохранитьВидКлючаДанных Тогда + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + СохранитьСвойства = Истина; + + ИначеЕсли ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя"; + + ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ВидКлючаДанных = "ЭлементыСУстаревшимиПравами"; + Иначе + ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами"; + КонецЕсли; + ИначеЕсли ВидКлючаДанных <> "НетДанных" + И ПараметрыОбновления.Свойство("ПоследнийОбновленныйЭлемент") Тогда + СохранитьСвойства = Истина; + КонецЕсли; + Если СохранитьСвойства Тогда + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы Тогда + НачальныйЭлемент.ОбработатьУстаревшиеЭлементы = Истина; + КонецЕсли; + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами Тогда + НачальныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + КонецЕсли; + УстановитьВидКлючаДанных(НачальныйЭлемент, ВидКлючаДанных); + + Если Не ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + НачальныйЭлемент.Вставить("Дата", ?(ПерезапускОбновленияСНачала, + МаксимальнаяДата(), МаксимальнаяДатаПриПродолжении())); + КонецЕсли; + + Возврат НачальныйЭлемент; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Процедура ПодготовитьПланОбновления(ПараметрыОбновления, ПодготовкаЗавершена) + + ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; + ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + ЭтоОбновлениеПрав = ПараметрыОбновления.ЭтоОбновлениеПрав; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Список", ИдентификаторСписка); + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); + + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | КлючиУникальности.КлючУникальности КАК КлючУникальности, + | КлючиУникальности.ПараметрыЗадания КАК ПараметрыЗадания, + | КлючиУникальности.ДатаПоследнегоОбновленногоЭлемента КАК ДатаПоследнегоОбновленногоЭлемента + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК КлючиУникальности + |ГДЕ + | КлючиУникальности.Список = &Список + | И КлючиУникальности.ДляВнешнихПользователей = &ДляВнешнихПользователей + | + |УПОРЯДОЧИТЬ ПО + | КлючиУникальности.Список, + | КлючиУникальности.ДляВнешнихПользователей, + | КлючиУникальности.КлючУникальности"; + + Если ЭтоОбновлениеПрав Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "РегистрСведений.ОбновлениеКлючейДоступаКДанным", + "РегистрСведений.ОбновлениеКлючейДоступаПользователей"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, ", + | КлючиУникальности.ДатаПоследнегоОбновленногоЭлемента КАК ДатаПоследнегоОбновленногоЭлемента", + ""); // @query-part-1 + КонецЕсли; + + РезультатЗапроса = Запрос.Выполнить(); + + Если РезультатЗапроса.Пустой() Тогда + ПараметрыОбновления.ЕстьЗадания = Ложь; + Возврат; + КонецЕсли; + + Выгрузка = РезультатЗапроса.Выгрузить(); + + Если Выгрузка.Количество() = 1000 Тогда + ПодготовкаЗавершена = Ложь; + КонецЕсли; + + Если ЭтоОбновлениеПрав Тогда + ПланОбновления = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаПользователей); + Иначе + ПланОбновления = СлужебныйНаборЗаписей(РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + КонецЕсли; + ПланОбновления.Отбор.Список.Установить(ИдентификаторСписка); + ПланОбновления.Отбор.ДляВнешнихПользователей.Установить(ДляВнешнихПользователей); + + Если ПараметрыОбновления.Список = СписокДляПланированияОбновленияКэшаРасчетаПрав() Тогда + ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка); + ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка); + ПараметрыОбновления.ЕстьЗадания = Ложь; + Возврат; + КонецЕсли; + + ПерезапускОбновления = Ложь; + ПерезапускОбновленияСНачала = Ложь; + СохраняемыеПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ПараметрыОбновления); + + Если Не ЗначениеЗаполнено(Выгрузка[0].КлючУникальности) Тогда + ТекущийИтог = Выгрузка[0]; + ПараметрыЗадания = ТекущийИтог.ПараметрыЗадания.Получить(); + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") Тогда + СохраняемыеПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, + ПараметрыОбновления, ПараметрыЗадания, ПерезапускОбновления); + Иначе + ПерезапускОбновления = Истина; + КонецЕсли; + Если Не ПерезапускОбновления И Не ЭтоОбновлениеПрав Тогда + СохраненнаяДата = ТекущийИтог.ДатаПоследнегоОбновленногоЭлемента; + Если ТипЗнч(СохраненнаяДата) = Тип("Дата") Тогда + СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент.Дата = СохраненнаяДата; + Иначе + ПерезапускОбновления = Истина; + КонецЕсли; + КонецЕсли; + Выгрузка.Удалить(0); + Если Не ПерезапускОбновления Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = + СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент; + КонецЕсли; + КонецЕсли; + + Если Не ПерезапускОбновления + И ТекущийИтог <> Неопределено + И Выгрузка.Количество() = 0 Тогда + + ПараметрыОбновления.ТочечноеЗадание = ПодготовленноеТочечноеЗадание( + ЭтоОбновлениеПрав, СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); + Если Не ПерезапускОбновления Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + ПустойИдентификатор = ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор(); + ПолноеИмяРегистра = ?(ЭтоОбновлениеПрав, "РегистрСведений.ОбновлениеКлючейДоступаПользователей", + "РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); + ЭлементБлокировки.УстановитьЗначение("КлючУникальности", ПустойИдентификатор); + + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); + ЭлементБлокировки.ИсточникДанных = Выгрузка; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючУникальности", "КлючУникальности"); + + МаксимальнаяДата = МаксимальнаяДата(); + СвойстваКлючаДанных = НачальныйЭлемент(ПараметрыОбновления, "НетДанных"); + ВидКлючаДанныхУстановлен = Истина; + Для Каждого Строка Из Выгрузка Цикл + ПараметрыЗадания = Строка.ПараметрыЗадания.Получить(); + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") И ПараметрыЗадания.Свойство("ТочечноеЗадание") Тогда + ДобавитьВедущийОбъектКТочечномуЗаданию(ПараметрыЗадания.ТочечноеЗадание, + СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); + Иначе + ПерезапускОбновления = Истина; + Если Не ЭтоОбновлениеПрав И Строка.ДатаПоследнегоОбновленногоЭлемента = МаксимальнаяДата Тогда + ПерезапускОбновленияСНачала = Истина; + КонецЕсли; + Если ЕстьСвойстваКлючаДанных(ПараметрыЗадания) Тогда + Если СвойстваКлючаДанных.ПорядокВидаКлючаДанных > ПараметрыЗадания.ПорядокВидаКлючаДанных Тогда + СвойстваКлючаДанных.ПорядокВидаКлючаДанных = ПараметрыЗадания.ПорядокВидаКлючаДанных; + СвойстваКлючаДанных.ВидКлючаДанных = ПараметрыЗадания.ВидКлючаДанных; + КонецЕсли; + Если ЭтоОбработкаУстаревшихЭлементов(Новый Структура("ПоследнийОбновленныйЭлемент", ПараметрыЗадания)) Тогда + СвойстваКлючаДанных.ОбработатьУстаревшиеЭлементы = Истина; + КонецЕсли; + Если ПараметрыЗадания.Свойство("ОбработатьНаборыГруппСУстаревшимиПравами") + И ПараметрыЗадания.ОбработатьНаборыГруппСУстаревшимиПравами = Истина Тогда + СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + Иначе + ВидКлючаДанныхУстановлен = Ложь; + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + Если ЭтоОбновлениеПрав Или ПерезапускОбновленияСНачала Тогда + Прервать; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + ПараметрыОбновления.ТочечноеЗадание = ПодготовленноеТочечноеЗадание( + ЭтоОбновлениеПрав, СохраняемыеПараметрыЗадания.ТочечноеЗадание, ПерезапускОбновления); + + Если ПерезапускОбновления Тогда + ПараметрыОбновления.ПерезапускОбновления = Истина; + Если ПерезапускОбновленияСНачала Тогда + ПараметрыОбновления.Вставить("ПерезапускОбновленияСНачала"); + КонецЕсли; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = + НачальныйЭлемент(ПараметрыОбновления, , , ПерезапускОбновленияСНачала); + КонецЕсли; + + ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; + Если ВидКлючаДанныхУстановлен Тогда + Если ТекущийИтог = Неопределено Тогда + УстановитьВидКлючаДанных(ПоследнийОбновленныйЭлемент, СвойстваКлючаДанных.ВидКлючаДанных); + + ИначеЕсли ПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных > СвойстваКлючаДанных.ПорядокВидаКлючаДанных Тогда + ПоследнийОбновленныйЭлемент.ПорядокВидаКлючаДанных = СвойстваКлючаДанных.ПорядокВидаКлючаДанных; + ПоследнийОбновленныйЭлемент.ВидКлючаДанных = СвойстваКлючаДанных.ВидКлючаДанных; + КонецЕсли; + КонецЕсли; + Если СвойстваКлючаДанных.ОбработатьУстаревшиеЭлементы Тогда + ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы = Истина; + КонецЕсли; + Если СвойстваКлючаДанных.ОбработатьНаборыГруппСУстаревшимиПравами Тогда + ПоследнийОбновленныйЭлемент.ОбработатьНаборыГруппСУстаревшимиПравами = Истина; + КонецЕсли; + СохраняемыеПараметрыЗадания.ПоследнийОбновленныйЭлемент = ПоследнийОбновленныйЭлемент; + + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда + РазмерЗадания = 1; + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(Новый Структура("ПоследнийОбновленныйЭлемент", + ПоследнийОбновленныйЭлемент)) Тогда + РазмерЗадания = 2; + Иначе + РазмерЗадания = 3; + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "ВЫБРАТЬ ПЕРВЫЕ 1000", "ВЫБРАТЬ ПЕРВЫЕ 1"); // @query-part-1, @query-part-2 + ЗаданияУдалены = Ложь; + + ПланОбновления.Отбор.КлючУникальности.Установить(ПустойИдентификатор); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + РезультатЗапроса = Запрос.Выполнить(); + Если РезультатЗапроса.Пустой() Тогда + ЗаданияУдалены = Истина; + Иначе + Запись = ПланОбновления.Добавить(); + Запись.Список = ИдентификаторСписка; + Запись.ДляВнешнихПользователей = ДляВнешнихПользователей; + Запись.ТочечноеЗадание = ПараметрыОбновления.ТочечноеЗадание <> Неопределено; + Запись.ПараметрыЗадания = Новый ХранилищеЗначения(СохраняемыеПараметрыЗадания); + Запись.РазмерЗадания = РазмерЗадания; + Если Не ЭтоОбновлениеПрав Тогда + Запись.ДатаПоследнегоОбновленногоЭлемента = + ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата; + КонецЕсли; + Запись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + ПланОбновления.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЗаданияУдалены Тогда + ПараметрыОбновления.ЕстьЗадания = Ложь; + ПараметрыОбновления.ТочечноеЗадание = Неопределено; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); + Возврат; + КонецЕсли; + + ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка) + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Процедура ОчиститьЗагруженныеЗаписи(ПланОбновления, Выгрузка) + + Если Не ЗначениеЗаполнено(Выгрузка) Тогда + Возврат; + КонецЕсли; + + ПланОбновления.Очистить(); + + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено; + + Если ПакетныйРежим Тогда + Выгрузка.Колонки.Добавить("Список"); + Выгрузка.Колонки.Добавить("ДляВнешнихПользователей"); + Выгрузка.ЗаполнитьЗначения(ПланОбновления.Отбор.Список.Значение, "Список"); + Выгрузка.ЗаполнитьЗначения(ПланОбновления.Отбор.ДляВнешнихПользователей.Значение, "ДляВнешнихПользователей"); + ПланОбновления.Загрузить(Выгрузка); + ПланОбновления.Отбор.Список.Использование = Ложь; + ПланОбновления.Отбор.ДляВнешнихПользователей.Использование = Ложь; + ПланОбновления.Отбор.КлючУникальности.Использование = Ложь; + ПланОбновления.Записать(РежимУдаления); + Иначе + Для Каждого Строка Из Выгрузка Цикл + ПланОбновления.Отбор.КлючУникальности.Установить(Строка.КлючУникальности); + ПланОбновления.Записать(); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Процедура ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка, НоваяВерсияДанныхДляКэша = Неопределено) + + ВерсияДанныхДляКэша = НоваяВерсияДанныхДляКэшаРасчетаПрав(); + + Для Каждого Строка Из Выгрузка Цикл + ПараметрыЗадания = Строка.ПараметрыЗадания.Получить(); + Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") + Или Не ПараметрыЗадания.Свойство("ТочечноеЗадание") + Или ТипЗнч(ПараметрыЗадания.ТочечноеЗадание) <> Тип("Структура") + Или Не ПараметрыЗадания.ТочечноеЗадание.Свойство("ПоДаннымКэшаРасчетаПрав") Тогда + Продолжить; + КонецЕсли; + ИмяИзмененныхДанных = ПараметрыЗадания.ТочечноеЗадание.ПоДаннымКэшаРасчетаПрав; + ОбработатьЗаданиеОбновленияКэшаРасчетаПрав(ВерсияДанныхДляКэша, + ИмяИзмененныхДанных, Строка.КлючУникальности); + КонецЦикла; + + ИмяПараметра = ИмяПараметраВерсииДанныхДляКэшаРасчетаПрав(); + + Если НоваяВерсияДанныхДляКэша = Неопределено Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений"); + ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка()); + ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ТекущееЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + НовоеЗначение = НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша); + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина); + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + Иначе + ТекущееЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина); + НоваяВерсияДанныхДляКэша = НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша, Ложь); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. +Процедура ОбработатьЗаданиеОбновленияКэшаРасчетаПрав(ВерсияДанныхДляКэша, ИмяИзмененныхДанных, КлючУникальности) + + Если ТипЗнч(ИмяИзмененныхДанных) <> Тип("Строка") + Или Не ВерсияДанныхДляКэша.Свойство(ИмяИзмененныхДанных) Тогда + + Для Каждого КлючИЗначение Из ВерсияДанныхДляКэша Цикл + ВерсияДанныхДляКэша[КлючИЗначение.Ключ] = Строка(Новый УникальныйИдентификатор); + КонецЦикла; + Возврат; + КонецЕсли; + + Если ТипЗнч(ВерсияДанныхДляКэша[ИмяИзмененныхДанных]) = Тип("Строка") Тогда + Возврат; + КонецЕсли; + + Если ВерсияДанныхДляКэша[ИмяИзмененныхДанных] = Неопределено Тогда + ВерсияДанныхДляКэша[ИмяИзмененныхДанных] = Новый ХешированиеДанных(ХешФункция.SHA256); + КонецЕсли; + + ХешированиеДанных = ВерсияДанныхДляКэша[ИмяИзмененныхДанных]; // ХешированиеДанных + ХешированиеДанных.Добавить(Строка(КлючУникальности)); + +КонецПроцедуры + +// Для процедуры ОбработатьПланОбновленияКэшаРасчетаПрав. +Функция НоваяВерсияДанныхДляКэша(ТекущееЗначение, ВерсияДанныхДляКэша, ДляЗаписи = Истина) + + НовоеЗначение = НоваяВерсияДанныхДляКэшаРасчетаПрав(); + + Если ТипЗнч(ТекущееЗначение) = Тип("Структура") Тогда + ЗаполнитьЗначенияСвойств(НовоеЗначение, ТекущееЗначение); + КонецЕсли; + + Для Каждого КлючИЗначение Из ВерсияДанныхДляКэша Цикл + Если КлючИЗначение.Значение = Неопределено Тогда + Продолжить; + КонецЕсли; + Если ТипЗнч(КлючИЗначение.Значение) = Тип("ХешированиеДанных") Тогда + НовоеЗначение[КлючИЗначение.Ключ] = Base64Строка(КлючИЗначение.Значение.ХешСумма); + Иначе + НовоеЗначение[КлючИЗначение.Ключ] = КлючИЗначение.Значение; + КонецЕсли; + КонецЦикла; + + Для Каждого КлючИЗначение Из НовоеЗначение Цикл + Если КлючИЗначение.Значение <> Неопределено Тогда + Продолжить; + КонецЕсли; + НовоеЗначение[КлючИЗначение.Ключ] = ?(ДляЗаписи, + Строка(Новый УникальныйИдентификатор), "00000000-0000-0000-0000-000000000000"); + КонецЦикла; + + Возврат НовоеЗначение; + +КонецФункции + +// Для функции КэшРасчетаПравДляВидаПользователей. +Функция ВерсияДанныхДляКэшаРасчетаПрав() + + ИдентификаторСпискаПланирования = ОбщегоНазначения.ИдентификаторОбъектаМетаданных( + СписокДляПланированияОбновленияКэшаРасчетаПрав()); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Список", ИдентификаторСпискаПланирования); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | КлючиУникальности.КлючУникальности КАК КлючУникальности, + | КлючиУникальности.ПараметрыЗадания КАК ПараметрыЗадания + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК КлючиУникальности + |ГДЕ + | КлючиУникальности.Список = &Список + | И КлючиУникальности.ДляВнешнихПользователей = ЛОЖЬ + | + |УПОРЯДОЧИТЬ ПО + | КлючиУникальности.Список, + | КлючиУникальности.ДляВнешнихПользователей, + | КлючиУникальности.КлючУникальности"; + + Если ТранзакцияАктивна() И ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + + Выгрузка = Запрос.Выполнить().Выгрузить(); + + ВерсияДанныхДляКэша = Новый Структура; + ОбработатьПланОбновленияКэшаРасчетаПрав(Выгрузка, ВерсияДанныхДляКэша); + + Возврат ВерсияДанныхДляКэша; + +КонецФункции + +// Для процедуры ПодготовитьПланОбновления, ЗаписатьПоследнийОбновленныйЭлемент. +// +// Возвращаемое значение: +// Структура: +// * ПоследнийОбновленныйЭлемент - см. НачальныйЭлемент +// * ТочечноеЗадание - Структура: +// ** ПоКлючамДоступа - Соответствие +// ** ПоЗначениямПолей - Соответствие +// ** ПоЗначениямСГруппами - Соответствие +// +Функция СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ПараметрыОбновления, ПараметрыЗадания = Неопределено, + ПерезапускОбновления = Ложь, ОчиститьТочечноеЗадание = Ложь) + + ТочечноеЗадание = Новый Структура; + ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый Соответствие); + Если Не ЭтоОбновлениеПрав Тогда + ТочечноеЗадание.Вставить("ПоЗначениямПолей", Новый Соответствие); + ТочечноеЗадание.Вставить("ПоЗначениямСГруппами", Новый Соответствие); + КонецЕсли; + + СохраняемыеПараметры = Новый Структура; + СохраняемыеПараметры.Вставить("ТочечноеЗадание", ТочечноеЗадание); + СохраняемыеПараметры.Вставить("ПоследнийОбновленныйЭлемент", НачальныйЭлемент(ПараметрыОбновления)); + + Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") Тогда + Возврат СохраняемыеПараметры; + КонецЕсли; + + Если ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") Тогда + Порядок = ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных); + Если Порядок <> Неопределено Тогда + ЗаполнитьЗначенияСвойств(СохраняемыеПараметры.ПоследнийОбновленныйЭлемент, + ПараметрыЗадания.ПоследнийОбновленныйЭлемент); + КонецЕсли; + КонецЕсли; + + Если ОчиститьТочечноеЗадание Или Не ПараметрыЗадания.Свойство("ТочечноеЗадание") Тогда + Возврат СохраняемыеПараметры; + КонецЕсли; + + ТекущееТочечноеЗадание = ПараметрыЗадания.ТочечноеЗадание; + Если ТипЗнч(ТекущееТочечноеЗадание) <> Тип("Структура") Тогда + ПерезапускОбновления = Истина; + Возврат СохраняемыеПараметры; + КонецЕсли; + + Для Каждого ВариантЗадания Из ТочечноеЗадание Цикл + Если Не ТекущееТочечноеЗадание.Свойство(ВариантЗадания.Ключ) + Или ТипЗнч(ТекущееТочечноеЗадание[ВариантЗадания.Ключ]) <> Тип("Соответствие") Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + ТочечноеЗадание[ВариантЗадания.Ключ] = ТекущееТочечноеЗадание[ВариантЗадания.Ключ]; + КонецЦикла; + + Возврат СохраняемыеПараметры; + +КонецФункции + +// Для процедуры ПодготовитьПланОбновления. +Процедура ДобавитьВедущийОбъектКТочечномуЗаданию(ТочечноеЗадание, СохраняемоеТочечноеЗадание, + ПерезапускОбновления) + + Если ТипЗнч(ТочечноеЗадание) <> Тип("Структура") Тогда + ПерезапускОбновления = Истина; + Возврат; + КонецЕсли; + МаксимальноеКоличество = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); + + Для Каждого ВариантЗадания Из ТочечноеЗадание Цикл + Если Не СохраняемоеТочечноеЗадание.Свойство(ВариантЗадания.Ключ) Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + Если ВариантЗадания.Ключ <> "ПоЗначениямПолей" Тогда + Ссылки = ?(ТипЗнч(ВариантЗадания.Значение) = Тип("Массив"), ВариантЗадания.Значение, + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ВариантЗадания.Значение)); + СохраняемыеСсылки = СохраняемоеТочечноеЗадание[ВариантЗадания.Ключ]; + Для Каждого Ссылка Из Ссылки Цикл + СохраняемыеСсылки.Вставить(Ссылка, Истина); + Если СохраняемыеСсылки.Количество() >= МаксимальноеКоличество Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + КонецЦикла; + Иначе + Свойства = ВариантЗадания.Значение; + СохраняемыеТаблицы = СохраняемоеТочечноеЗадание[ВариантЗадания.Ключ]; + + Если Не Свойства.Свойство("ИзмененнаяТаблица") + Или Не Свойства.Свойство("СоставИзменений") + Или ТипЗнч(Свойства.СоставИзменений) <> Тип("ТаблицаЗначений") + Или ТипЗнч(СохраняемыеТаблицы) <> Тип("Соответствие") Тогда + + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + СохраняемаяТаблица = СохраняемыеТаблицы.Получить(Свойства.ИзмененнаяТаблица); + СоставИзменений = Свойства.СоставИзменений; + Если СохраняемаяТаблица = Неопределено Тогда + СохраняемыеТаблицы.Вставить(Свойства.ИзмененнаяТаблица, СоставИзменений); + + ИначеЕсли ТипЗнч(СохраняемаяТаблица) <> Тип("ТаблицаЗначений") + Или СоставИзменений.Колонки.Количество() <> СохраняемаяТаблица.Колонки.Количество() Тогда + + ПерезапускОбновления = Истина; + Продолжить; + Иначе + ИменаКолонок = Новый Массив; + Для Каждого Колонка Из СохраняемаяТаблица.Колонки Цикл + Если СоставИзменений.Колонки.Найти(Колонка.Имя) = Неопределено Тогда + ИменаКолонок = Неопределено; + Прервать; + КонецЕсли; + ИменаКолонок.Добавить(Колонка.Имя); + КонецЦикла; + Если ИменаКолонок = Неопределено Тогда + ПерезапускОбновления = Истина; + Продолжить; + КонецЕсли; + СписокИменКолонок = СтрСоединить(ИменаКолонок, ","); + Отбор = Новый Структура(СписокИменКолонок); + Если СохраняемаяТаблица.Индексы.Количество() = 0 Тогда + СохраняемаяТаблица.Индексы.Добавить(СписокИменКолонок); + КонецЕсли; + Для Каждого Строка Из СоставИзменений Цикл + ЗаполнитьЗначенияСвойств(Отбор, Строка); + Если СохраняемаяТаблица.НайтиСтроки(Отбор).Количество() = 0 Тогда + Если СохраняемаяТаблица.Количество() >= МаксимальноеКоличество Тогда + ПерезапускОбновления = Истина; + Прервать; + КонецЕсли; + ЗаполнитьЗначенияСвойств(СохраняемаяТаблица.Добавить(), Строка); + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Функция ЕстьСвойстваКлючаДанных(ПараметрыЗадания) + + Если ТипЗнч(ПараметрыЗадания) <> Тип("Структура") + Или Не ПараметрыЗадания.Свойство("ВидКлючаДанных") + Или Не ПараметрыЗадания.Свойство("ПорядокВидаКлючаДанных") Тогда + Возврат Ложь; + КонецЕсли; + + Порядок = ПорядокВидаКлючаДанных(ПараметрыЗадания.ВидКлючаДанных); + + Возврат Порядок <> Неопределено И Порядок = ПараметрыЗадания.ПорядокВидаКлючаДанных; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ОбновитьПорциюЭлементов, +// УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных, ОбновитьНаборыГруппДоступа и +// функций ЭлементыДляОбновления, ПоследнийЭлемент, КлючДанных, НаборыГруппДоступаДляОбновления. +// +Функция ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) + + Порядок = ПорядокВидаКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных); + + Возврат Порядок >= ПорядокВидаКлючаДанных("УстаревшиеЭлементы") + И Порядок < ПорядокВидаКлючаДанных("НетДанных"); + +КонецФункции + +// Для функций СохраняемыеПараметрыЗадания, ЕстьСвойстваКлючаДанных и +// процедур ОбновитьСвойствоЭтоОбработкаУстаревшихЭлементов, УстановитьВидКлючаДанных. +// +Функция ПорядокВидаКлючаДанных(ВидКлючаДанных) + + ВидыКлючейДанных = Новый Соответствие; + ВидыКлючейДанных.Вставить("ЭлементыСУстаревшимиКлючами", 0); + ВидыКлючейДанных.Вставить("ЭлементыБезКлючейПоЗначениямПолей", 1); + ВидыКлючейДанных.Вставить("ЭлементыБезКлючейПоПериоду", 1); + + ВидыКлючейДанных.Вставить("ЭлементыСУстаревшимиПравами", 0); + + ВидыКлючейДанных.Вставить("НовыеНаборыИзОдногоПользователя", 0); + ВидыКлючейДанных.Вставить("НаборыГруппДоступаНазначенныеПользователям", 1); + ВидыКлючейДанных.Вставить("НаборыГруппПользователейНазначенныеПользователям", 2); + ВидыКлючейДанных.Вставить("НовыеНаборыГруппСУстаревшимиПравами", 3); + ВидыКлючейДанных.Вставить("НаборыГруппРазрешенныеПользователям", 4); + ВидыКлючейДанных.Вставить("НаборыГруппСУстаревшимиПравами", 5); + + ВидыКлючейДанных.Вставить("УстаревшиеЭлементы", 10); + ВидыКлючейДанных.Вставить("НекорректныеЭлементы", 11); + ВидыКлючейДанных.Вставить("НекорректныеЭлементыОбщегоРегистра", 12); + + ВидыКлючейДанных.Вставить("НетДанных", 99); + + Возврат ВидыКлючейДанных.Получить(ВидКлючаДанных); + +КонецФункции + +// Для процедур ЗапланироватьОбновлениеДоступа, ЗапланироватьОбновлениеНаборовГруппДоступа, +// УточнитьПустойПоследнийЭлемент и функции НачальныйЭлемент. +// +Процедура УстановитьВидКлючаДанных(Элемент, ВидКлючаДанных) + + Порядок = ПорядокВидаКлючаДанных(ВидКлючаДанных); + Если Порядок = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректный имя вида порядка ключа данных ""%1""'"), ВидКлючаДанных); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Элемент.Вставить("ВидКлючаДанных", ВидКлючаДанных); + Элемент.Вставить("ПорядокВидаКлючаДанных", Порядок); + +КонецПроцедуры + +// Для процедуры ПодготовитьПланОбновления. +Функция ПодготовленноеТочечноеЗадание(ЭтоОбновлениеПрав, СохраняемоеТочечноеЗадание, ПерезапускОбновления) + + ТочечноеЗадание = Новый Структура; + Если ЭтоОбновлениеПрав Тогда + ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый Массив); + Иначе + ТочечноеЗадание.Вставить("ПоЗначениямПолей", Новый Соответствие); + ТочечноеЗадание.Вставить("ПоКлючамДоступа", Новый ТаблицаЗначений); + ТочечноеЗадание.Вставить("ПоЗначениямСГруппами", Новый ТаблицаЗначений); + КонецЕсли; + + ЭтоПустоеЗадание = Истина; + МаксимальноеКоличество = МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных(); + ТипыВедущихОбъектов = УправлениеДоступомСлужебныйПовтИсп.ТиповСсылокВедущихОбъектов(); + + Для Каждого ВариантЗадания Из СохраняемоеТочечноеЗадание Цикл + Если ВариантЗадания.Ключ = "ПоЗначениямПолей" Тогда + Если ЗначениеЗаполнено(ВариантЗадания.Значение) Тогда + ЭтоПустоеЗадание = Ложь; + ТочечноеЗадание.ПоЗначениямПолей = ВариантЗадания.Значение; + КонецЕсли; + Продолжить; + КонецЕсли; + + УдаляемыеСсылки = Новый Массив; + ОписаниеСсылок = ВариантЗадания.Значение; + Если ЭтоОбновлениеПрав Тогда + Ссылки = ТочечноеЗадание[ВариантЗадания.Ключ]; + Иначе + Ссылки = Новый Массив; + Типы = Новый Соответствие; + Таблица = ТочечноеЗадание[ВариантЗадания.Ключ]; // ТаблицаЗначений + КонецЕсли; + Для Каждого ОписаниеСсылки Из ОписаниеСсылок Цикл + Ссылка = ОписаниеСсылки.Ключ; + Тип = ТипЗнч(Ссылка); + Если ТипыВедущихОбъектов.Получить(Тип) = Неопределено Тогда + ПерезапускОбновления = Истина; + УдаляемыеСсылки.Добавить(Ссылка); + Продолжить; + КонецЕсли; + Ссылки.Добавить(Ссылка); + Если Не ЭтоОбновлениеПрав Тогда + Типы.Вставить(Тип, Истина); + Таблица.Добавить(); + КонецЕсли; + Если Ссылки.Количество() >= МаксимальноеКоличество Тогда + ПерезапускОбновления = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Ссылка Из УдаляемыеСсылки Цикл + ОписаниеСсылок.Удалить(Ссылка); + КонецЦикла; + Если Ссылки.Количество() > 0 Тогда + ЭтоПустоеЗадание = Ложь; + Иначе + Продолжить; + КонецЕсли; + Если Не ЭтоОбновлениеПрав Тогда + ТипыКолонки = Новый Массив; + Для Каждого КлючИЗначение Из Типы Цикл + ТипыКолонки.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + Таблица.Колонки.Добавить("Ссылка", Новый ОписаниеТипов(ТипыКолонки)); + Таблица.ЗагрузитьКолонку(Ссылки, "Ссылка"); + КонецЕсли; + КонецЦикла; + + Если ЭтоПустоеЗадание Тогда + Возврат Неопределено; + КонецЕсли; + + Возврат ТочечноеЗадание; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Функция КоличествоЭлементовВПорции(ПараметрыОбновления) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + Возврат 25; + ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Возврат КоличествоКлючейДоступаВПорции(); + Иначе + Возврат КоличествоЭлементовДанныхВПорции(); + КонецЕсли; + +КонецФункции + +// Для процедура ВыполнитьОбновлениеДоступаСписка. +Функция КоличествоЭлементовВЗапросе(ЭтоОбновлениеПрав) + + Если ЭтоОбновлениеПрав Тогда + Возврат КоличествоКлючейДоступаВЗапросе(); + Иначе + Возврат КоличествоЭлементовДанныхВЗапросе(); + КонецЕсли; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОбновитьПорциюЭлементов(Элементы, ПараметрыОбновления, ЭтоТочечноеЗадание = Ложь) + + ПараметрыОбновления.Вставить("КоличествоОбработанныхЭлементов", 0); + + Если ЭтоТочечноеЗадание Тогда + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ОбновитьПраваПорцииКлючейДоступаСписка(Элементы, ПараметрыОбновления); + Иначе + ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(Элементы, ПараметрыОбновления); + КонецЕсли; + + ИначеЕсли ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ОбработатьУстаревшиеКлючиДоступаСписка(Элементы, ПараметрыОбновления); + Иначе + ОбновитьПраваПорцииКлючейДоступаСписка(Элементы, ПараметрыОбновления); + КонецЕсли; + + ИначеЕсли ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + ОбновитьНаборыГруппДоступа(Элементы, ПараметрыОбновления); + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + УдалитьУстаревшиеЭлементыДанныхСписка(Элементы, ПараметрыОбновления); + Иначе + ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(Элементы, ПараметрыОбновления); + КонецЕсли; + + Если Не ЭтоТочечноеЗадание И Элементы.Количество() > 0 Тогда + ПараметрыОбновления.Вставить("НовыйПоследнийОбновленныйЭлемент", + ПоследнийЭлемент(Элементы, ПараметрыОбновления, Истина)); + КонецЕсли; + + Если Элементы.Количество() = ПараметрыОбновления.КоличествоОбработанныхЭлементов Тогда + Элементы = Неопределено; + Иначе + Для Счетчик = 1 По ПараметрыОбновления.КоличествоОбработанныхЭлементов Цикл + Элементы.Удалить(0); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьНаборыГруппДоступа, УдалитьУстаревшиеЭлементыДанныхСписка, +// ЗаписатьКлючиДоступаОбъектов, ЗаписатьКлючиДоступаРегистров, +// ОбновитьПраваПорцииКлючейДоступаСписка, УдалитьПорциюКлючейДоступаСписка, +// УдалитьТекущуюПорциюКлючейДоступаСписка. +// +Функция ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанныхНаШаге = 1) + + Если Не ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") + Или Не ПараметрыОбновления.Свойство("ГраницаВремениОбработки") Тогда + Возврат Ложь; + КонецЕсли; + + ПараметрыОбновления.КоличествоОбработанныхЭлементов = + ПараметрыОбновления.КоличествоОбработанныхЭлементов + КоличествоОбработанныхНаШаге; + + Если ТекущаяУниверсальнаяДатаВМиллисекундах() > ПараметрыОбновления.ГраницаВремениОбработки Тогда + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ПроверитьЗавершитьОбновлениеПоПорциям. +Процедура ЗаписатьПоследнийОбновленныйЭлемент(ОбщиеПараметрыОбновления, ПоследнийОбновленныйЭлемент) + + ЭтоОбновлениеПрав = ОбщиеПараметрыОбновления.ЭтоОбновлениеПрав; + ДляВнешнихПользователей = ОбщиеПараметрыОбновления.ДляВнешнихПользователей; + ИдентификаторСписка = ОбщиеПараметрыОбновления.ИдентификаторСписка; + + МенеджерРегистра = ?(ЭтоОбновлениеПрав, РегистрыСведений.ОбновлениеКлючейДоступаПользователей, + РегистрыСведений.ОбновлениеКлючейДоступаКДанным); + + ПланОбновления = СлужебныйНаборЗаписей(МенеджерРегистра); + ПланОбновления.Отбор.Список.Установить(ИдентификаторСписка); + ПланОбновления.Отбор.ДляВнешнихПользователей.Установить(ДляВнешнихПользователей); + ПланОбновления.Отбор.КлючУникальности.Установить( + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ПолноеИмяРегистра = ?(ЭтоОбновлениеПрав, "РегистрСведений.ОбновлениеКлючейДоступаПользователей", + "РегистрСведений.ОбновлениеКлючейДоступаКДанным"); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистра); + ЭлементБлокировки.УстановитьЗначение("Список", ИдентификаторСписка); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", ДляВнешнихПользователей); + ЭлементБлокировки.УстановитьЗначение("КлючУникальности", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + ПланОбновления.Прочитать(); + Если ПланОбновления.Количество() > 0 Тогда + Если ПоследнийОбновленныйЭлемент.КлючДанных = Null Тогда + ПланОбновления.Очистить(); + Иначе + Запись = ПланОбновления[0]; + Если ПоследнийОбновленныйЭлемент.Свойство("ОчиститьТочечноеЗадание") Тогда + Запись.ТочечноеЗадание = Ложь; + КонецЕсли; + + ТекущиеПараметрыЗадания = Запись.ПараметрыЗадания.Получить(); + ПараметрыЗадания = СохраняемыеПараметрыЗадания(ЭтоОбновлениеПрав, ОбщиеПараметрыОбновления, + ТекущиеПараметрыЗадания, , ПоследнийОбновленныйЭлемент.Свойство("ОчиститьТочечноеЗадание")); + + ЗаполнитьЗначенияСвойств(ПараметрыЗадания.ПоследнийОбновленныйЭлемент, ПоследнийОбновленныйЭлемент); + + Если Не ЭтоОбновлениеПрав И ПоследнийОбновленныйЭлемент.Свойство("Дата") Тогда + Запись.ДатаПоследнегоОбновленногоЭлемента = ПоследнийОбновленныйЭлемент.Дата; + КонецЕсли; + + Запись.ПараметрыЗадания = Новый ХранилищеЗначения(ПараметрыЗадания); + Запись.РазмерЗадания = ?(ЭтоОбработкаУстаревшихЭлементов( + Новый Структура("ПоследнийОбновленныйЭлемент", ПоследнийОбновленныйЭлемент)), 2, 3); + + Запись.ДатаИзмененияЗаписиРегистра = ТекущаяДатаСеанса(); + ОбщиеПараметрыОбновления.ОбработкаЗавершена = Ложь; + КонецЕсли; + ПланОбновления.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Функция ЭлементыДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ВыбраныВсеЭлементы = Истина; + Возврат Неопределено; + КонецЕсли; + Элементы = НаборыГруппДоступаДляОбновления(ПараметрыОбновления, КоличествоВЗапросе); + Иначе + Запрос = Новый Запрос; + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + + ПоследнийКлючДоступа = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных; + Если ТипЗнч(ПоследнийКлючДоступа) <> Тип("СправочникСсылка.КлючиДоступа") Тогда + ПоследнийКлючДоступа = Неопределено; + КонецЕсли; + Запрос.УстановитьПараметр("ПоследнийКлючДоступа", ПоследнийКлючДоступа); + + Если ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда + // Для режима ЭтоОчисткаВыбранныхКлючей в процедуре ОбработатьУстаревшиеКлючиДоступаСписка. + // Переключение на шаг УстаревшиеЭлементы выполняется в процедуре УточнитьПоследнийОбновленныйЭлемент. + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей Тогда + // Для режима ЭтоОчисткаВыбранныхКлючей в процедуре ОбработатьУстаревшиеКлючиДоступаСписка. + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.СоставПолей > 0 + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + Иначе + Запрос.УстановитьПараметр("ДатаУстаревания", ДатаУстаревания()); + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаУстаревшихКлючейДоступа; + КонецЕсли; + Иначе + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаКлючейДоступаДляОбновленияПрав; + КонецЕсли; + Иначе + УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных(Запрос, ПараметрыОбновления); + КонецЕсли; + + Если Запрос.Текст = ПризнакПустогоЗапроса() Тогда + ВыбраныВсеЭлементы = Истина; + Возврат Неопределено; + + ИначеЕсли Запрос.Текст = ПризнакИтерационногоЗапроса() Тогда + Возврат ИтерационнаяВыборкаЭлементовДляОбновления(Запрос, + ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы, Неопределено); + Иначе + КоличествоВЗапросе = ?(КоличествоВЗапросе < 1000, 1000, ?(КоличествоВЗапросе > 10000, 10000, КоличествоВЗапросе)); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + Элементы = Запрос.Выполнить().Выгрузить(); + КонецЕсли; + КонецЕсли; + + Если Элементы.Количество() = 0 Тогда + ВыбраныВсеЭлементы = Истина; + Возврат Неопределено; + КонецЕсли; + + ВыбраныВсеЭлементы = Элементы.Количество() < КоличествоВЗапросе; + + Возврат Элементы; + +КонецФункции + +// Для функции ЭлементыДляОбновления и процедур +// УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных, +// УстановитьОбработкуУстаревшихДанных, +// ДобавитьТекстЗапросаУстаревшихЭлементовДанных. +// +Функция ПризнакПустогоЗапроса() + Возврат "НетЭлементов"; +КонецФункции + +// Для функции ЭлементыДляОбновления и +// процедуры УстановитьПустойПоследнийЭлемент. +// +Функция ПризнакИтерационногоЗапроса() + Возврат "*"; +КонецФункции + +// Для функции ЭлементыДляОбновления. +Функция ИтерационнаяВыборкаЭлементовДляОбновления(Запрос, ПараметрыОбновления, КоличествоВЗапросе, + ВыбраныВсеЭлементы, КоличествоЗапрошенныхЭлементов) + + КоличествоЭлементов = 500; // Начальное количество элементов данных в диапазоне. + ТекстЗапросаДиапазона = ПараметрыОбновления.ТекстЗапросаДиапазонаЭлементовДанных; + ТекстЗапросаЭлементовДанных = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами; + + // Подготовка запроса получения первой границы диапазона. + Если ПараметрыОбновления.СписокСДатой Тогда + Запрос.УстановитьПараметр("ДатаОкончанияДиапазона", Запрос.Параметры.ДатаОкончания); + ТекстЗапросаДиапазона = СтрЗаменить(ТекстЗапросаДиапазона, + "ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона", "ИСТИНА"); // @query-part-1 + ТекстЗапросаЭлементовДанных = СтрЗаменить(ТекстЗапросаЭлементовДанных, + "ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона", "ИСТИНА"); // @query-part-1 + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Запрос.УстановитьПараметр("СсылкаНачалаДиапазона", Запрос.Параметры.ПоследняяОбработаннаяСсылка); + Иначе + Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл + НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); + ИмяПоля = СтрШаблон("Поле%1НачалаДиапазона", НомерПоля); + Если КлючИЗначение.Значение = Неопределено Тогда + ТекстЗапросаДиапазона = СтрЗаменить(ТекстЗапросаДиапазона, + " > &" + ИмяПоля, " >= &" + ИмяПоля); + ТекстЗапросаЭлементовДанных = СтрЗаменить(ТекстЗапросаЭлементовДанных, + " > &" + ИмяПоля, " >= &" + ИмяПоля); + КонецЕсли; + Запрос.УстановитьПараметр(ИмяПоля, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + + Элементы = Неопределено; + + Пока Истина Цикл + // Получение очередной границы диапазона. + Запрос.Текст = СтрЗаменить(ТекстЗапросаДиапазона, "993", Формат(КоличествоЭлементов, "ЧГ=")); + ТекущийТекстЗапросаДиапазона = Запрос.Текст; + Выгрузка = Запрос.Выполнить().Выгрузить(); + Если Не ЗначениеЗаполнено(Выгрузка) Тогда + ВыбраныВсеЭлементы = Истина; + Прервать; + КонецЕсли; + Если КоличествоЗапрошенныхЭлементов <> Неопределено Тогда + КоличествоЗапрошенныхЭлементов.Добавить(КоличествоЭлементов); + КонецЕсли; + Для Каждого Колонка Из Выгрузка.Колонки Цикл + Запрос.УстановитьПараметр(Колонка.Имя, Выгрузка[0][Колонка.Имя]); + КонецЦикла; + + // Получение элементов с устаревшими ключами из диапазона. + Запрос.Текст = СтрЗаменить(ТекстЗапросаЭлементовДанных, "993", Формат(КоличествоЭлементов, "ЧГ=")); + + МоментНачала = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ТекущиеЭлементы = Запрос.Выполнить().Выгрузить(); + ВремяЗапроса = ТекущаяУниверсальнаяДатаВМиллисекундах() - МоментНачала; + + // Перерасчет количества элементов в диапазоне. + Если ВремяЗапроса < 1000 Тогда + КоличествоЭлементов = КоличествоЭлементов * Цел((1050 - ВремяЗапроса) / 50); + ИначеЕсли ВремяЗапроса > 2000 Тогда + КоличествоЭлементов = КоличествоЭлементов / 2; + КонецЕсли; + КоличествоЭлементов = (1 + Цел((КоличествоЭлементов - 1) / 500)) * 500; + Если КоличествоЭлементов > 10000 Тогда + КоличествоЭлементов = 10000; + КонецЕсли; + Если КоличествоЭлементов < 500 Тогда + КоличествоЭлементов = 500; + КонецЕсли; + + // Проверка неизменности текущего диапазона. + Запрос.Текст = ТекущийТекстЗапросаДиапазона; + Выгрузка = Запрос.Выполнить().Выгрузить(); + ДиапазонИзменился = Ложь; + Для Каждого Колонка Из Выгрузка.Колонки Цикл + Если Запрос.Параметры[Колонка.Имя] <> Выгрузка[0][Колонка.Имя] Тогда + ДиапазонИзменился = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Если ДиапазонИзменился Тогда + Запрос.Текст = СтрЗаменить(ТекстЗапросаЭлементовДанных, "ПЕРВЫЕ 993", ""); + ТекущиеЭлементы = Запрос.Выполнить().Выгрузить(); + КонецЕсли; + + ПоследнийТекущийЭлемент = Неопределено; + Если ЗначениеЗаполнено(ТекущиеЭлементы) Тогда + Если Элементы = Неопределено Тогда + Элементы = ТекущиеЭлементы; + Иначе + Для Каждого ТекущийЭлемент Из ТекущиеЭлементы Цикл + ЗаполнитьЗначенияСвойств(Элементы.Добавить(), ТекущийЭлемент); + КонецЦикла; + КонецЕсли; + ПоследнийТекущийЭлемент = ТекущиеЭлементы[ТекущиеЭлементы.Количество() - 1]; + КонецЕсли; + + Если Элементы <> Неопределено + И Элементы.Количество() >= КоличествоВЗапросе + Или ТекущаяУниверсальнаяДатаВМиллисекундах() > ПараметрыОбновления.ГраницаВремениОбработки + И (ЗначениеЗаполнено(Элементы) + Или Не ПараметрыОбновления.СписокСДатой + Или Запрос.Параметры.ДатаОкончания > Запрос.Параметры.ДатаНачалаДиапазона) Тогда + + Прервать; + КонецЕсли; + + // Подготовка запроса следующей границы диапазона. + ТекстЗапросаДиапазона = ПараметрыОбновления.ТекстЗапросаДиапазонаЭлементовДанных; + ТекстЗапросаЭлементовДанных = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами; + + Если ПараметрыОбновления.СписокСДатой Тогда + Запрос.УстановитьПараметр("ДатаОкончанияДиапазона", Запрос.Параметры.ДатаНачалаДиапазона); + Запрос.УстановитьПараметр("СсылкаДатыОкончанияДиапазона", Запрос.Параметры.СсылкаДатыНачалаДиапазона); + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Запрос.УстановитьПараметр("СсылкаНачалаДиапазона", Запрос.Параметры.СсылкаОкончанияДиапазона); + Иначе + Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл + НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); + ИмяПоляНачала = СтрШаблон("Поле%1НачалаДиапазона", НомерПоля); + ИмяПоляОкончания = СтрШаблон("Поле%1ОкончанияДиапазона", НомерПоля); + ЗначениеПоляОкончания = Запрос.Параметры[ИмяПоляОкончания]; + Запрос.УстановитьПараметр(ИмяПоляНачала, ЗначениеПоляОкончания); + КонецЦикла; + КонецЕсли; + КонецЦикла; + + Если ВыбраныВсеЭлементы Или ЗначениеЗаполнено(Элементы) Тогда + Возврат Элементы; + КонецЕсли; + + КоличествоВЗапросе = Null; + + // Подготовка обработанного элемента для продвижения указателя. + Элементы = ТекущиеЭлементы; + Элемент = Элементы.Добавить(); + + Если ПараметрыОбновления.СписокСДатой Тогда + Элемент.Дата = Запрос.Параметры.ДатаНачалаДиапазона; + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Элемент.ТекущаяСсылка = Запрос.Параметры.СсылкаОкончанияДиапазона; + Иначе + Для Каждого КлючИЗначение Из Запрос.Параметры.УстановленныйКлючДанных Цикл + НомерПоля = Число(СтрЗаменить(КлючИЗначение.Ключ, "Поле", "")); + ИмяПоляОкончания = СтрШаблон("Поле%1ОкончанияДиапазона", НомерПоля); + Элемент[КлючИЗначение.Ключ] = Запрос.Параметры[ИмяПоляОкончания]; + КонецЦикла; + КонецЕсли; + + Возврат Элементы; + +КонецФункции + +// Для процедур выполнения запросов. +Процедура УстановитьУточнениеПланаЗапроса(ТекстЗапроса, УникальныйПлан = Ложь) + + Если УправлениеДоступомСлужебныйПовтИсп.ТребуетсяУточнениеПланаЗапроса() Тогда + Если УникальныйПлан Тогда + ТекущаяДатаСеанса = ТекущаяДатаСеанса(); + ВсегоМинут = Цел((ТекущаяДатаСеанса - '00010101') / 60); + ОстатокМинут = ВсегоМинут - Цел(ВсегоМинут / 2048) * 2048; + УточнениеПланаЗапроса = УправлениеДоступомСлужебныйПовтИсп.УточнениеПланаЗапроса(ОстатокМинут, 11); + Иначе + ТочноеВремя = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ВсегоДесятыхСекунд = Цел(ТочноеВремя / 100); + ОстатокДесятыхСекунд = ВсегоДесятыхСекунд - Цел(ВсегоДесятыхСекунд / 1048576) * 1048576; + УточнениеПланаЗапроса = УправлениеДоступомСлужебныйПовтИсп.УточнениеПланаЗапроса(ОстатокДесятыхСекунд, 20); + КонецЕсли; + Иначе + УточнениеПланаЗапроса = "ИСТИНА"; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УточнениеПланаЗапроса", УточнениеПланаЗапроса); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Функция ЭлементыТочечногоЗаданияДляОбновления(ПараметрыОбновления, КоличествоВЗапросе, ВыбраныВсеЭлементы) + + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + Или ПараметрыОбновления.БезЗаписиКлючейДоступа + Или ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей Тогда + + Возврат Неопределено; + КонецЕсли; + + Запрос = Новый Запрос; + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав; + Если Не ЗначениеЗаполнено(Запрос.Текст) Тогда + Возврат Неопределено; + КонецЕсли; + Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + Запрос.УстановитьПараметр("ВедущиеКлючиДоступа", ПараметрыОбновления.ТочечноеЗадание.ПоКлючамДоступа); + Иначе + Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда + Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + ОписаниеЗапросов = ПараметрыОбновления.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам; + ЗапросыПакета = Новый Массив; + ЗапросыДанных = Новый Массив; + Если ЗначениеЗаполнено(ПараметрыОбновления.ТочечноеЗадание.ПоЗначениямПолей) Тогда + ОписаниеЗапросовПоЗначениямПолей = ОписаниеЗапросов.Получить("ПоЗначениямПолей"); + Если ОписаниеЗапросовПоЗначениямПолей = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + Для Каждого ОписаниеИзменений Из ПараметрыОбновления.ТочечноеЗадание.ПоЗначениямПолей Цикл + ОписаниеЗапроса = ОписаниеЗапросовПоЗначениямПолей.Получить(ОписаниеИзменений.Ключ); + Если ОписаниеЗапроса = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + СоставИзменений = ОписаниеИзменений.Значение; // ТаблицаЗначений + Если ОписаниеЗапроса.ТипыПолей.Количество() <> СоставИзменений.Колонки.Количество() Тогда + Возврат Неопределено; + КонецЕсли; + Для Каждого Колонка Из СоставИзменений.Колонки Цикл + ТипыПоля = ОписаниеЗапроса.ТипыПолей.Получить(Колонка.Имя); + Если ТипЗнч(ТипыПоля) <> Тип("ХранилищеЗначения") Тогда + Возврат Неопределено; + КонецЕсли; + ТипКолонки = Новый ОписаниеТипов(Колонка.ТипЗначения,, "Null"); + Если ТипыПоля.Получить() <> ТипКолонки + Или СтрокаДанныхДляХеширования(Колонка.ТипЗначения) + <> СтрокаДанныхДляХеширования(Новый ОписаниеТипов(Колонка.ТипЗначения.Типы())) Тогда + Возврат Неопределено; + КонецЕсли; + КонецЦикла; + ИмяВременнойТаблицыИПараметра = СтрЗаменить(ОписаниеИзменений.Ключ, ".", "_"); + Запрос.УстановитьПараметр(ИмяВременнойТаблицыИПараметра, СоставИзменений); + ЗапросыПакета.Добавить(ОписаниеЗапроса.ТекстЗапросаПараметров); + Для Каждого ТекстЗапросаДанных Из ОписаниеЗапроса.ТекстыЗапросовДанных Цикл + ЗапросыДанных.Добавить(ТекстЗапросаДанных); + КонецЦикла; + КонецЦикла; + КонецЕсли; + Если Не ДобавитьЗапросыТочечногоЗадания("ПоКлючамДоступа", + Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) + Или Не ДобавитьЗапросыТочечногоЗадания("ПоЗначениямСГруппами", + Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) + Или ЗапросыДанных.Количество() = 0 Тогда + Возврат Неопределено; + КонецЕсли; + Если ЗапросыДанных.Количество() = 1 Тогда + ЗапросыПакета.Добавить(СтрЗаменить(ЗапросыДанных[0], + " + |ИЗ + | ", + " + |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам + |ИЗ + | ")); // @query-part-1, @query-part-2 + Иначе + ТекстыЗапросов = СтрСоединить(ЗапросыДанных, + " + | + |ОБЪЕДИНИТЬ ВСЕ + | + |"); // @query-part-1 + ЗапросыПакета.Добавить(СтрЗаменить(ОписаниеЗапросов.Получить("ТекстЗапросаОберткиВыбораДанных"), + "#ЗапросыВыбораДанных", "(" + ТекстСОтступом(ТекстыЗапросов, " ") + ")")); + КонецЕсли; + ЗапросыПакета.Добавить(ОписаниеЗапросов.Получить("ТекстЗапросаТочечнойПроверки")); + Запрос.Текст = СтрСоединить(ЗапросыПакета, ОбщегоНазначения.РазделительПакетаЗапросов()); + КонецЕсли; + + КоличествоВЗапросе = ?(КоличествоВЗапросе < 1000, 1000, ?(КоличествоВЗапросе > 4000, 4000, КоличествоВЗапросе)); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Элементы = Запрос.Выполнить().Выгрузить(); + КоличествоВыбранных = Элементы.Количество(); + Иначе + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + КоличествоВыбранных = РезультатыЗапроса[ЗапросыПакета.Количество() - 2].Выгрузить()[0].Количество; + Элементы = РезультатыЗапроса[ЗапросыПакета.Количество() - 1].Выгрузить(); + КонецЕсли; + + ВыбраныВсеЭлементы = КоличествоВыбранных < КоличествоВЗапросе; + + Если Элементы.Количество() = 0 Тогда + Возврат Неопределено; + КонецЕсли; + + Возврат Элементы; + +КонецФункции + +// Для функции ЭлементыТочечногоЗаданияДляОбновления. +Функция ДобавитьЗапросыТочечногоЗадания(ВидЗадания, Запрос, ЗапросыПакета, ЗапросыДанных, ПараметрыОбновления) + + Данные = ТаблицаТочечногоЗадания(); + Данные = ПараметрыОбновления.ТочечноеЗадание[ВидЗадания]; // см. ТаблицаТочечногоЗадания + Если Не ЗначениеЗаполнено(Данные) Тогда + Возврат Истина; + КонецЕсли; + + ОписаниеЗапросов = + ПараметрыОбновления.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам.Получить(ВидЗадания); + + Если ОписаниеЗапросов = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ТипКолонки = Данные.Колонки.Ссылка.ТипЗначения; + НедостающиеТипы = Новый ОписаниеТипов(ТипКолонки, , ОписаниеЗапросов.ТипСсылки.Получить().Типы()); + Если НедостающиеТипы.Типы().Количество() > 0 Тогда + Возврат Ложь; + КонецЕсли; + + Запрос.УстановитьПараметр(ВидЗадания, Данные); + ЗапросыПакета.Добавить(ОписаниеЗапросов.ТекстЗапросаПараметров); + + КлючиЗапросов = Новый Соответствие; + Для Каждого Тип Из ТипКолонки.Типы() Цикл + ТекущиеКлючи = ОписаниеЗапросов.КлючиЗапросовПоТипам.Получить(Тип); + Если ТекущиеКлючи = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + Для Каждого Ключ Из ТекущиеКлючи Цикл + КлючиЗапросов.Вставить(Ключ, Истина); + КонецЦикла; + КонецЦикла; + + Для Каждого КлючИЗначение Из КлючиЗапросов Цикл + ТекстЗапроса = ОписаниеЗапросов.ТекстыЗапросовПоКлючам.Получить(КлючИЗначение.Ключ); + Если ТекстЗапроса = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + ЗапросыДанных.Добавить(ТекстЗапроса); + КонецЦикла; + + Возврат Истина; + +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Ссылка - ЛюбаяСсылка +// +Функция ТаблицаТочечногоЗадания() + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении(ПараметрыОбновления) + + ПараметрыОбновления.ПерезапускОбновления = Истина; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = НачальныйЭлемент(ПараметрыОбновления); + + // Регистрация косвенного планирования обновления доступа. + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(Ложь); + ПараметрыПланирования.РазрешенныеКлючиДоступа = ПараметрыОбновления.ЭтоОбновлениеПрав; + ПараметрыПланирования.ДляПользователей = Не ПараметрыОбновления.ДляВнешнихПользователей; + ПараметрыПланирования.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + ПараметрыПланирования.Описание = "ПерезапуститьОбновлениеПриНезавершенномТочечномОбновлении"; + + СпискиПоИдентификаторам = Новый Соответствие; + СпискиПоИдентификаторам.Вставить(ПараметрыОбновления.ИдентификаторСписка, ПараметрыОбновления.Список); + + ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Функция НаборПорцийЭлементов(ПараметрыОбновления, Элементы, ВыбраныВсеЭлементы, РазмерПорции = Неопределено) + + НаборПорций = Новый Массив; + + Если Элементы = Неопределено Тогда + ПорцияИзНабора = ПорцияИзНабора(); + ПорцияИзНабора.Вставить("Обработана", Истина); + ПорцияИзНабора.Вставить("Обрабатывается", Ложь); + ПорцияИзНабора.Вставить("Элементы", Новый ХранилищеЗначения(Новый ТаблицаЗначений)); + ПорцияИзНабора.Вставить("ДатаПоследнегоЭлементаПорции", '00010101'); + ПорцияИзНабора.Вставить("ПоследнийЭлементПорции", НачальныйЭлемент(ПараметрыОбновления,, Истина)); + ПорцияИзНабора.Вставить("НовыйПоследнийЭлементПорции"); + НаборПорций.Добавить(ПорцияИзНабора); + ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; + Если ПорцияИзНабора.ПоследнийЭлементПорции.Свойство("Дата") Тогда + ПорцияИзНабора.ПоследнийЭлементПорции.Дата = '00010101'; + КонецЕсли; + УстановитьПустойПоследнийЭлемент(ПорцияИзНабора.НовыйПоследнийЭлементПорции, + ПараметрыОбновления, '00010101'); + Возврат НаборПорций; + КонецЕсли; + + Если РазмерПорции = Неопределено Тогда + РазмерПорции = ПараметрыОбновления.КоличествоОбработанныхЭлементов; + МаксимумНовыхПорций = ПараметрыОбновления.МаксимумПорцийИзИсходной; + Если Элементы.Количество() / РазмерПорции > МаксимумНовыхПорций Тогда + РазмерПорции = Элементы.Количество() / МаксимумНовыхПорций; + Если РазмерПорции <> Цел(РазмерПорции) Тогда + РазмерПорции = Цел(РазмерПорции) + 1; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ПараметрыОбновления.Вставить("НаборПорций", НаборПорций); + Индекс = 0; + Для Каждого Элемент Из Элементы Цикл + Если Индекс / РазмерПорции = Цел(Индекс / РазмерПорции) Тогда + ПорцияИзНабора = Новый Массив; + НаборПорций.Добавить(ПорцияИзНабора); + КонецЕсли; + ПорцияИзНабора.Добавить(Элемент); + Индекс = Индекс + 1; + КонецЦикла; + + Для Индекс = 0 По НаборПорций.Количество() - 1 Цикл + ЭлементыПорции = Элементы.Скопировать(НаборПорций[Индекс]); + ПорцияИзНабора = ПорцияИзНабора(); + ПорцияИзНабора.Вставить("Обработана", Ложь); + ПорцияИзНабора.Вставить("Обрабатывается", Ложь); + НаборПорций[Индекс] = ПорцияИзНабора; + ПорцияИзНабора.Вставить("Элементы", Новый ХранилищеЗначения(ЭлементыПорции)); + ПорцияИзНабора.Вставить("ПоследнийЭлементПорции", + ПоследнийЭлемент(ЭлементыПорции, ПараметрыОбновления)); + ПорцияИзНабора.Вставить("ДатаПоследнегоЭлементаПорции", + ?(ПорцияИзНабора.ПоследнийЭлементПорции.Свойство("Дата"), + ПорцияИзНабора.ПоследнийЭлементПорции.Дата, '00010101')); + ПорцияИзНабора.Вставить("НовыйПоследнийЭлементПорции", + ПоследнийЭлемент(ЭлементыПорции, ПараметрыОбновления)); + КонецЦикла; + + Если ВыбраныВсеЭлементы Тогда + ПорцияИзНабора.ПоследнийЭлементПорции.КлючДанных = Null; + УстановитьПустойПоследнийЭлемент(ПорцияИзНабора.НовыйПоследнийЭлементПорции, + ПараметрыОбновления, '00010101'); + КонецЕсли; + + Возврат НаборПорций; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Обработана - Булево +// * Обрабатывается - Булево +// * Элементы - ХранилищеЗначения +// * ДатаПоследнегоЭлементаПорции - Дата +// * ПоследнийЭлементПорции - см. НачальныйЭлемент +// * НовыйПоследнийЭлементПорции - см. НачальныйЭлемент +// +Функция ПорцияИзНабора() + + Возврат Новый Структура; + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаСписка, ОбновитьПорциюЭлементов, НаборПорцийЭлементов. +Функция ПоследнийЭлемент(Элементы, ПараметрыОбновления, ПоследнийОбработанный = Ложь) + + НомерПоследнего = ?(ПоследнийОбработанный, + ПараметрыОбновления.КоличествоОбработанныхЭлементов, Элементы.Количество()); + + ПоследнийЭлемент = Элементы[НомерПоследнего - 1]; + + ЭлементДанных = НачальныйЭлемент(ПараметрыОбновления, , Истина); + + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + ЭлементДанных.КлючДанных = ПоследнийЭлемент.Ссылка; + Возврат ЭлементДанных; + КонецЕсли; + + Если ПараметрыОбновления.СписокСДатой + И Не ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + + ЭлементДанных.Дата = ПоследнийЭлемент.Дата; + + ИначеЕсли ПараметрыОбновления.ЭтоСсылочныйТип Тогда + ЭлементДанных.КлючДанных = ПоследнийЭлемент.ТекущаяСсылка; + Иначе + ЭлементДанных.КлючДанных = КлючДанных(ПараметрыОбновления); + ЗаполнитьЗначенияСвойств(ЭлементДанных.КлючДанных, ПоследнийЭлемент); + + Если ПараметрыОбновления.СписокСПериодом + И ЭлементДанных.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + + ЭлементДанных.Дата = ПоследнийЭлемент.Период; + КонецЕсли; + КонецЕсли; + + Возврат ЭлементДанных; + +КонецФункции + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура УточнитьПоследнийОбновленныйЭлемент(ПараметрыОбновления) + + Если ПараметрыОбновления.Список = "Справочник.НаборыГруппДоступа" + Или ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НетДанных" Тогда + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда + Если Не ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы Тогда + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = + НачальныйЭлемент(ПараметрыОбновления, "НетДанных"); + + ИначеЕсли Не ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + УстановитьОбработкуУстаревшихДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + ПараметрыОбновления, "НетДанных"); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ВыполнитьОбновлениеДоступаСписка, НаборПорцийЭлементов. +Процедура УстановитьПустойПоследнийЭлемент(Элемент, ПараметрыОбновления, ДатаЭлемента = '00010101') + + ДатаЭлемента = '00010101'; + Элемент = НачальныйЭлемент(ПараметрыОбновления, , Истина); + Элемент.КлючДанных = Null; + + // Уточнение нового последнего элемента. + Если ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Возврат; + КонецЕсли; + НовыйВидКлючаДанных = ""; + Если Элемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + НовыйВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + НовыйВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + НовыйВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + НовыйВидКлючаДанных = "НаборыГруппРазрешенныеПользователям"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" + И Элемент.ОбработатьНаборыГруппСУстаревшимиПравами Тогда + + НовыйВидКлючаДанных = "НаборыГруппСУстаревшимиПравами"; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" + Или Элемент.ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Если ЗначениеЗаполнено(НовыйВидКлючаДанных) Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, НовыйВидКлючаДанных); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ЭтоОбновлениеПрав Тогда + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиПравами" Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "НекорректныеЭлементыОбщегоРегистра" Тогда + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда + Если ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных <> ПризнакПустогоЗапроса() Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементы"); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "НекорректныеЭлементы" Тогда + Если Не ПараметрыОбновления.ЭтоСсылочныйТип + И ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + + Элемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементыОбщегоРегистра"); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.СписокСДатой Тогда + УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента); + Если Элемент.КлючДанных = Null Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если ПараметрыОбновления.ЭтоСсылочныйТип + Или ПараметрыОбновления.БезЗаписиКлючейДоступа Тогда + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента); + Если Элемент.КлючДанных = Null Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + Возврат; + КонецЕсли; + + Если Не ПараметрыОбновления.СписокСПериодом Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, "ЭлементыБезКлючейПоЗначениямПолей"); + Возврат; + КонецЕсли; + + Элемент = НачальныйЭлемент(ПараметрыОбновления, "ЭлементыБезКлючейПоПериоду"); + ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = Элемент; + УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента, МаксимальнаяДата()); + ПараметрыОбновления.ПоследнийОбновленныйЭлемент = ПоследнийОбновленныйЭлемент; + + Если Элемент.КлючДанных = Null Тогда + УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления); + КонецЕсли; + +КонецПроцедуры + +// Для процедур УточнитьПоследнийОбновленныйЭлемент, УстановитьПустойПоследнийЭлемент. +Процедура УстановитьОбработкуУстаревшихДанных(Элемент, ПараметрыОбновления, ВидКлючаДанныхЗавершения = Неопределено) + + НовыйЭлемент = Неопределено; + Если Элемент.ОбработатьУстаревшиеЭлементы Тогда + + Если ПараметрыОбновления.ЭтоОбновлениеПрав + Или ЭтоСправочникНаборыГруппДоступа(ПараметрыОбновления) + Или ПараметрыОбновления.ТекстЗапросаУстаревшихЭлементовДанных <> ПризнакПустогоЗапроса() Тогда + + НовыйЭлемент = НачальныйЭлемент(ПараметрыОбновления, "УстаревшиеЭлементы"); + + ИначеЕсли ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных <> ПризнакПустогоЗапроса() Тогда + НовыйЭлемент = НачальныйЭлемент(ПараметрыОбновления, "НекорректныеЭлементы"); + КонецЕсли; + КонецЕсли; + + Если НовыйЭлемент <> Неопределено Тогда + Элемент = НовыйЭлемент; + + ИначеЕсли ВидКлючаДанныхЗавершения <> Неопределено Тогда + Элемент = НачальныйЭлемент(ПараметрыОбновления, ВидКлючаДанныхЗавершения); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры УточнитьПустойПоследнийЭлемент. +Процедура УстановитьЭлементСледующегоПериода(ПараметрыОбновления, Элемент, ДатаЭлемента, + ДатаНачалаТекущегоПериода = Неопределено) + + Если ДатаНачалаТекущегоПериода = Неопределено Тогда + ДатаНачалаТекущегоПериода = ПараметрыОбновления.ДатаНачала; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДатаНачала", ДатаНачалаТекущегоПериода); + + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаДатыСледующегоЭлементаДанных; + + РезультатЗапроса = Запрос.Выполнить(); + + Если РезультатЗапроса.Пустой() Тогда + Элемент.КлючДанных = Null; + Возврат; + КонецЕсли; + + Элемент = ПоследнийЭлемент(РезультатЗапроса.Выгрузить(), ПараметрыОбновления); + ДатаЭлемента = ?(Элемент.Свойство("Дата"), Элемент.Дата, '00010101'); + +КонецПроцедуры + +// Для функции ЭлементыДляОбновления. +Процедура УстановитьТекстЗапросаИПараметрыПоследнегоОбновленногоЭлементаДанных(Запрос, ПараметрыОбновления) + + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + Если ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаУстаревшихЭлементовДанных; + ИначеЕсли ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных = "НекорректныеЭлементы" Тогда + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанных; + Иначе + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра; + КонецЕсли; + Иначе + // ТекстЗапросаДиапазонаЭлементовДанных, ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами. + Запрос.Текст = ПризнакИтерационногоЗапроса(); + Если Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда + Запрос.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + Если ПараметрыОбновления.СписокСДатой Тогда + Запрос.УстановитьПараметр("ДатаНачала", ПараметрыОбновления.ДатаНачала); + Запрос.УстановитьПараметр("ДатаОкончания", ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата); + Возврат; + КонецЕсли; + КонецЕсли; + + КлючДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.КлючДанных; + + Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда + УстановленныйКлючДанных = ?(ОбщегоНазначения.ЭтоСсылка(ТипЗнч(КлючДанных)), КлючДанных, Неопределено); + Запрос.УстановитьПараметр("ПоследняяОбработаннаяСсылка", УстановленныйКлючДанных); + Возврат; + КонецЕсли; + + Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); + УстановленныйКлючДанных = КлючДанных(ПараметрыОбновления, КлючДанных); + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + + ЭлементыБезКлючей = ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" + Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей"; + + Если ЭлементыБезКлючей И ПараметрыОбновления.СписокСПериодом Тогда + Если ВидКлючаДанных <> "ЭлементыБезКлючейПоПериоду" Тогда + УстановитьВидКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + "ЭлементыБезКлючейПоПериоду"); + КонецЕсли; + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхБезКлючейДоступа; + Запрос.УстановитьПараметр("ДатаНачала", ПараметрыОбновления.ДатаНачала); + Запрос.УстановитьПараметр("ДатаОкончания", ПараметрыОбновления.ПоследнийОбновленныйЭлемент.Дата); + + ИначеЕсли ЭлементыБезКлючей Тогда + Если ВидКлючаДанных <> "ЭлементыБезКлючейПоЗначениямПолей" Тогда + УстановитьВидКлючаДанных(ПараметрыОбновления.ПоследнийОбновленныйЭлемент, + "ЭлементыБезКлючейПоЗначениямПолей"); + КонецЕсли; + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЭлементовДанныхБезКлючейДоступа; + КонецЕсли; + + Если Запрос.Текст = ПризнакИтерационногоЗапроса() Тогда + Запрос.УстановитьПараметр("УстановленныйКлючДанных", УстановленныйКлючДанных); + Возврат; + КонецЕсли; + + Для Каждого КлючИЗначение Из УстановленныйКлючДанных Цикл + Если КлючИЗначение.Значение = Неопределено Тогда + ИмяПоля = КлючИЗначение.Ключ; + Запрос.Текст = СтрЗаменить(Запрос.Текст, " > &" + ИмяПоля, " >= &" + ИмяПоля); + КонецЕсли; + Запрос.УстановитьПараметр(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для процедур ПоследнийЭлемент, УстановитьПараметрыПоследнегоОбновленногоЭлемента и +// функции ТекстЗапросаКоличестваОставшихсяЭлементовРегистра. +// +// Возвращаемое значение: +// Структура: +// * Поле1 - ЛюбаяСсылка +// * Поле2 - ЛюбаяСсылка +// * Поле3 - ЛюбаяСсылка +// * Поле4 - ЛюбаяСсылка +// * Поле5 - ЛюбаяСсылка +// +Функция КлючДанных(ПараметрыОбновления, ИсходныйКлючДанных = Неопределено) + + КоличествоПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); + + Если КоличествоПолей = 0 + Или ПараметрыОбновления.ИспользуетсяОграничениеПоВладельцу + Или ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + + КоличествоПолей = ПараметрыОбновления.ОпорныеПоля.МаксимальноеКоличество; + КонецЕсли; + ПолеВариантДоступа = ?(ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления), 1, 0); + + Если ТипЗнч(ИсходныйКлючДанных) = Тип("Структура") + И ИсходныйКлючДанных.Количество() = КоличествоПолей + ПолеВариантДоступа Тогда + + ЗначенияПолей = ИсходныйКлючДанных; + Иначе + ЗначенияПолей = Новый Структура; + КонецЕсли; + + НовыеЗначенияПолей = Новый Структура; + Если ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ИмяПоля = "ВариантДоступа"; + Если ЗначенияПолей.Свойство(ИмяПоля) Тогда + НовыеЗначенияПолей.Вставить(ИмяПоля, ЗначенияПолей[ИмяПоля]); + Иначе + НовыеЗначенияПолей.Вставить(ИмяПоля, Неопределено); + КонецЕсли; + КонецЕсли; + + Для Номер = 1 По КоличествоПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", Номер); + Если ЗначенияПолей.Свойство(ИмяПоля) Тогда + НовыеЗначенияПолей.Вставить(ИмяПоля, ЗначенияПолей[ИмяПоля]); + Иначе + НовыеЗначенияПолей.Вставить(ИмяПоля, Неопределено); + КонецЕсли; + КонецЦикла; + + Возврат НовыеЗначенияПолей; + +КонецФункции + +// Для процедуры ЭлементыДляОбновления. +Функция НаборыГруппДоступаДляОбновления(ПараметрыОбновления, КоличествоВЗапросе) + + ПоследнийОбновленныйЭлемент = ПараметрыОбновления.ПоследнийОбновленныйЭлемент; + ВидКлючаДанных = ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ПоследняяОбработаннаяСсылка", ПоследнийОбновленныйЭлемент.КлючДанных); + + Если ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК ТекущаяСсылка, + | ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) КАК ЭтоНаборГруппДоступа + |ИЗ + | Справочник.НаборыГруппДоступа КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТекущийСписок.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) + | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | СоставыГруппПользователей.Пользователь КАК ТекущаяСсылка, + | СоставыГруппПользователей.Пользователь.Наименование КАК Наименование, + | СоставыГруппПользователей.Используется + | И ЕСТЬNULL(ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ, &ПустойУникальныйИдентификатор) <> &ПустойУникальныйИдентификатор КАК Используется, + | НаборыГруппДоступа.НеИспользуетсяС КАК НеИспользуетсяС + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ПО (НаборыГруппДоступа.Пользователь = СоставыГруппПользователей.Пользователь) + | И (НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей) + | И (НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) + | И (НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов + | ГДЕ + | ГруппыНаборов.Ссылка = НаборыГруппДоступа.Ссылка)) + |ГДЕ + | ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.Пользователи) + | И ВЫБОР + | КОГДА СоставыГруппПользователей.Используется + | И ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор + | ТОГДА НаборыГруппДоступа.Пользователь ЕСТЬ NULL + | ИЛИ НаборыГруппДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(1, 1, 1) + | ИНАЧЕ НаборыГруппДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | КОНЕЦ + | И СоставыГруппПользователей.Пользователь > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | СоставыГруппПользователей.Пользователь"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + ИначеЕсли ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + Возврат НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа( + ПараметрыОбновления, КоличествоВЗапросе); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + Возврат НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей( + ПараметрыОбновления, КоличествоВЗапросе); + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК ТекущаяСсылка, + | ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) КАК ЭтоНаборГруппДоступа + |ИЗ + | Справочник.НаборыГруппДоступа КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТекущийСписок.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.НовыйНаборГруппДоступа = ТекущийСписок.Ссылка) + | ИЛИ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.НовыйНаборГруппПользователей = ТекущийСписок.Ссылка)) + | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ИначеЕсли ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | Справочник.НаборыГруппДоступа КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТекущийСписок.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И (ТекущийСписок.НовыйНаборГруппДоступа <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.Ссылка = ТекущийСписок.НовыйНаборГруппДоступа + | И НаборыГруппДоступа.НовыйНаборГруппДоступа = ТекущийСписок.НовыйНаборГруппДоступа) + | ИЛИ ТекущийСписок.НовыйНаборГруппПользователей <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.Ссылка = ТекущийСписок.НовыйНаборГруппПользователей + | И НаборыГруппДоступа.НовыйНаборГруппПользователей = ТекущийСписок.НовыйНаборГруппПользователей)) + | И ТекущийСписок.Ссылка > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + Возврат УстаревшиеНаборыГруппДоступаВСправочнике(ПараметрыОбновления, КоличествоВЗапросе); + КонецЕсли; + + КоличествоВЗапросе = ?(КоличествоВЗапросе < 25, 25, ?(КоличествоВЗапросе > 10000, 10000, КоличествоВЗапросе)); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "995", Формат(КоличествоВЗапросе, "ЧГ=")); + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + ЭлементыДанных = Запрос.Выполнить().Выгрузить(); + + Возврат ЭлементыДанных; + +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбновитьНаборыГруппДоступа(ЭлементыДанных, ПараметрыОбновления) + + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + + Если ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления); + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + ОбновитьНаборыИзОдногоПользователяВСправочнике(ЭлементыДанных, ПараметрыОбновления); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления, Истина); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления, Ложь); + + ИначеЕсли ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления, Истина); + + ИначеЕсли ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда + ОбновитьНаборыГруппРазрешенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления); + + ИначеЕсли ЭтоОбработкаУстаревшихЭлементов(ПараметрыОбновления) Тогда + ОбработатьУстаревшиеНаборыВСправочнике(ЭлементыДанных, ПараметрыОбновления); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОчиститьПраваПустогоНабораГруппДоступа(ПараметрыОбновления) + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборовГруппДоступа + |ГДЕ + | КлючиДоступаНаборовГруппДоступа.НаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей + |ГДЕ + | КлючиДоступаПользователей.Пользователь = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей + |ГДЕ + | КлючиДоступаВнешнихПользователей.ВнешнийПользователь = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка)"; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Если Не РезультатыЗапроса[0].Пустой() Тогда + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + НаборЗаписей.Отбор.НаборГруппДоступа.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); + НаборЗаписей.Записать(); + КонецЕсли; + + Если Не РезультатыЗапроса[1].Пустой() Тогда + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); + НаборЗаписей.Отбор.Пользователь.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); + НаборЗаписей.Записать(); + КонецЕсли; + + Если Не РезультатыЗапроса[2].Пустой() Тогда + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); + НаборЗаписей.Отбор.ВнешнийПользователь.Установить(Справочники.НаборыГруппДоступа.ПустаяСсылка()); + НаборЗаписей.Записать(); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыГруппСУстаревшимиПравами(ЭлементыДанных, ПараметрыОбновления, ЭтоНовыеНаборы = Ложь) + + Если ЭтоНовыеНаборы Тогда + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + КонецЕсли; + + Для Каждого ЭлементДанных Из ЭлементыДанных Цикл + Если ЭлементДанных.ЭтоНаборГруппДоступа Тогда + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, + "КлючиДоступаНаборовГруппДоступа", "ГруппыДоступа", "НаборГруппДоступа"); + + ИначеЕсли Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, + "КлючиДоступаПользователей", "ГруппыПользователей", "Пользователь"); + Иначе + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, ЭлементДанных.ТекущаяСсылка, + "КлючиДоступаВнешнихПользователей", "ГруппыВнешнихПользователей", "ВнешнийПользователь"); + КонецЕсли; + + Если ЭтоНовыеНаборы Тогда + ЭлементБлокировки.УстановитьЗначение("Ссылка", ЭлементДанных.ТекущаяСсылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, ЭлементДанных.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + ИмяРеквизита = ?(ЭлементДанных.ЭтоНаборГруппДоступа, + "НовыйНаборГруппДоступа", "НовыйНаборГруппПользователей"); + Если ЗначениеЗаполнено(Объект[ИмяРеквизита]) Тогда + Объект[ИмяРеквизита] = ПараметрыОбновления.ПустойНаборГруппДоступа; + Объект.Записать(); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппСУстаревшимиПравами. +Процедура ОбновитьКлючиДоступаНаборовГрупп(ПараметрыОбновления, НаборГруппДоступа, ИмяРегистраПрав, + ИмяСправочникаГрупп, ИмяПоляНабораГрупп) + + Если НаборГруппДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа() Тогда + ТекстЗапросаВыбораПорцииДляБлокировки = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки, + | ВсеСтроки.КлючДоступа КАК КлючДоступа + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ГДЕ + | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И &УточнениеПланаЗапроса + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки, + | КлючДоступа"; + + ТекстЗапросаВыбораПорцииДляОбновления = + "ВЫБРАТЬ ПЕРВЫЕ 100 + | ВсеСтроки.КлючДоступа КАК КлючДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ГДЕ + | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И КлючиДоступаГруппДоступа.КлючДоступа В(&КлючиДоступа) + | И &УточнениеПланаЗапроса + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа + | И СтарыеДанные.КлючДоступа В(&КлючиДоступа)) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + Иначе + ТекстЗапросаВыбораПорцииДляБлокировки = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки, + | ВсеСтроки.КлючДоступа КАК КлючДоступа + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) + | И (ГруппыВходящиеВНаборы.Ссылка = &НаборГруппДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | КлючиДоступаГруппДоступа.КлючДоступа + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки, + | КлючДоступа"; + + ТекстЗапросаВыбораПорцииДляОбновления = + "ВЫБРАТЬ ПЕРВЫЕ 100 + | ВсеСтроки.КлючДоступа КАК КлючДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | КлючиДоступаГруппДоступа.КлючДоступа КАК КлючДоступа, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) + | И (ГруппыВходящиеВНаборы.Ссылка = &НаборГруппДоступа) + | И (КлючиДоступаГруппДоступа.КлючДоступа В (&КлючиДоступа)) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | КлючиДоступаГруппДоступа.КлючДоступа + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.КлючДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | &УсловиеОтбораПравГрупп + | И СтарыеДанные.НаборГруппДоступа = &НаборГруппДоступа + | И СтарыеДанные.КлючДоступа В(&КлючиДоступа)) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.КлючДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + КонецЕсли; + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "ТИП(Справочник.ГруппыДоступа)", "ТИП(Справочник." + ИмяСправочникаГрупп + ")"); // @query-part-1, @query-part-2 + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "ТИП(Справочник.ГруппыДоступа)", "ТИП(Справочник." + ИмяСправочникаГрупп + ")"); // @query-part-1, @query-part-2 + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "СтарыеДанные.НаборГруппДоступа", "СтарыеДанные." + ИмяПоляНабораГрупп); + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "СтарыеДанные.НаборГруппДоступа", "СтарыеДанные." + ИмяПоляНабораГрупп); + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "РегистрСведений.КлючиДоступаНаборовГруппДоступа", "РегистрСведений." + ИмяРегистраПрав); + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "РегистрСведений.КлючиДоступаНаборовГруппДоступа", "РегистрСведений." + ИмяРегистраПрав); + + ТекстЗапросаВыбораПорцииДляБлокировки = СтрЗаменить(ТекстЗапросаВыбораПорцииДляБлокировки, + "&УсловиеОтбораПравГрупп", ?(ИмяСправочникаГрупп = "ГруппыДоступа", "ИСТИНА", "СтарыеДанные.ЭтоПраваНабораГрупп")); + + ТекстЗапросаВыбораПорцииДляОбновления = СтрЗаменить(ТекстЗапросаВыбораПорцииДляОбновления, + "&УсловиеОтбораПравГрупп", ?(ИмяСправочникаГрупп = "ГруппыДоступа", "ИСТИНА", "СтарыеДанные.ЭтоПраваНабораГрупп")); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + Пока Истина Цикл + Запрос = Новый Запрос; + Запрос.Текст = ТекстЗапросаВыбораПорцииДляБлокировки; + УстановитьУточнениеПланаЗапроса(Запрос.Текст, Истина); + Запрос.УстановитьПараметр("НаборГруппДоступа", НаборГруппДоступа); + + Выгрузка = Запрос.Выполнить().Выгрузить(); + Если Выгрузка.Количество() = 0 Тогда + Прервать; + КонецЕсли; + + КлючиДоступа = Выгрузка.Скопировать(Новый Массив, "КлючДоступа"); + ПорцииКлючейДоступа = Новый Массив; + Для Каждого Строка Из Выгрузка Цикл + Если КлючиДоступа.Количество() > 100 Тогда + ПорцииКлючейДоступа.Добавить(КлючиДоступа); + КлючиДоступа = Выгрузка.Скопировать(Новый Массив, "КлючДоступа"); + КонецЕсли; + КлючиДоступа.Добавить().КлючДоступа = Строка.КлючДоступа; + КонецЦикла; + ПорцииКлючейДоступа.Добавить(КлючиДоступа); + + Для Каждого КлючиДоступа Из ПорцииКлючейДоступа Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраПрав); + ЭлементБлокировки.УстановитьЗначение(ИмяПоляНабораГрупп, НаборГруппДоступа); + ЭлементБлокировки.ИсточникДанных = КлючиДоступа; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючДоступа", "КлючДоступа"); + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = ТекстЗапросаВыбораПорцииДляОбновления; + УстановитьУточнениеПланаЗапроса(Запрос.Текст, Истина); + Запрос.УстановитьПараметр("НаборГруппДоступа", НаборГруппДоступа); + Запрос.УстановитьПараметр("КлючиДоступа", КлючиДоступа.ВыгрузитьКолонку("КлючДоступа")); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраПрав]); + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляНабораГрупп]; // ЭлементОтбора + ЭлементОтбора.Установить(НаборГруппДоступа); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + // @skip-check query-in-loop - Порционная обработка данных + Выборка = Запрос.Выполнить().Выбрать(); + + УдалениеЗавершено = Ложь; + Пока Выборка.Следующий() Цикл + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.КлючДоступа.Установить(Выборка.КлючДоступа); + КонецЕсли; + Если Не УдалениеЗавершено И Выборка.ВидИзмененияСтроки = 1 Тогда + УдалениеЗавершено = Истина; + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись[ИмяПоляНабораГрупп] = НаборГруппДоступа; + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + Если УдалениеЗавершено Тогда + ЗаполнитьЗначенияСвойств(ОднаЗапись, Выборка); + КонецЕсли; + НаборЗаписей.Записать(); + Иначе + Запись = НаборЗаписей.Добавить(); + Запись[ИмяПоляНабораГрупп] = НаборГруппДоступа; + ЗаполнитьЗначенияСвойств(Запись, Выборка); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(?(УдалениеЗавершено, РежимСлияния, РежимУдаления)); + КонецЕсли; + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура УстранитьДублиНаборовИзОдногоПользователяВСправочнике(ПараметрыОбновления) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.Пользователь КАК Пользователь, + | НаборыГруппДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И НаборыГруппДоступа.Пользователь В + | (ВЫБРАТЬ + | ВЫРАЗИТЬ(НаборыГруппДоступа.Пользователь КАК Справочник.Пользователи) КАК Пользователь + | ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + | ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | СГРУППИРОВАТЬ ПО + | НаборыГруппДоступа.Пользователь + | ИМЕЮЩИЕ + | КОЛИЧЕСТВО(НаборыГруппДоступа.Пользователь) > 1)"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + Если Выборка.Ссылка.УникальныйИдентификатор() = Выборка.Пользователь.УникальныйИдентификатор() Тогда + Продолжить; + КонецЕсли; + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Выборка.Ссылка); + Если Объект <> Неопределено Тогда + Объект.ТипЭлементовНабора = Неопределено; + Объект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыИзОдногоПользователяВСправочнике(ЭлементыДанных, ПараметрыОбновления) + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ТипЭлементовНабора = Справочники.ВнешниеПользователи.ПустаяСсылка(); + ПредставлениеЭлемента = НСтр("ru = 'Внешний пользователь'", ОбщегоНазначения.КодОсновногоЯзыка()); + Иначе + ТипЭлементовНабора = Справочники.Пользователи.ПустаяСсылка(); + ПредставлениеЭлемента = НСтр("ru = 'Пользователь'", ОбщегоНазначения.КодОсновногоЯзыка()); + КонецЕсли; + + Для Каждого Строка Из ЭлементыДанных Цикл + СсылкаНабора = Справочники.НаборыГруппДоступа.ПолучитьСсылку(Строка.ТекущаяСсылка.УникальныйИдентификатор()); + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНабора); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + Объект = СлужебныйЭлемент(Неопределено, СсылкаНабора); + Если Объект = Неопределено Тогда + Объект = СлужебныйЭлемент(Справочники.НаборыГруппДоступа); + Объект.УстановитьСсылкуНового(СсылкаНабора); + Иначе + Объект.Группы.Очистить(); + КонецЕсли; + Если Строка.Используется Тогда + Объект.НеИспользуетсяС = '00010101'; + ИначеЕсли Не ЗначениеЗаполнено(Строка.НеИспользуетсяС) Тогда + Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); + КонецЕсли; + Объект.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + Объект.ТипЭлементовНабора = ТипЭлементовНабора; + Объект.Пользователь = Строка.ТекущаяСсылка; + ОписаниеОбъекта = Строка; // СправочникОбъект.Пользователи + Объект.Наименование = Строка(ОписаниеОбъекта.Наименование) + " (" + ПредставлениеЭлемента + ")"; + Объект.Записать(); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ЗаполнитьПустыеХешиНаборовГрупп(ПараметрыОбновления) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("РазрешенныйПустойНабор", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора В (ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка), ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ПустаяСсылка)) + | И НаборыГруппДоступа.Хеш = 0 + | И НаборыГруппДоступа.Ссылка <> &РазрешенныйПустойНабор"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка); + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Выборка.Ссылка); + Если Объект <> Неопределено Тогда + ЗаполнитьХешНабораГрупп(Объект); + Объект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Для функции НаборыГруппДоступаДляОбновления. +Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа(ПараметрыОбновления, + КоличествоВЗапросе) + + Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстЗапросаГрупп = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Группа + |ПОМЕСТИТЬ АктивныеГруппы + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль <> &ПрофильАдминистратор + | И НЕ ГруппыДоступа.ПометкаУдаления + | И НЕ ГруппыДоступа.Профиль.ПометкаУдаления + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа + | ГДЕ + | ПользователиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка) + | И ВЫБОР + | КОГДА ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение + | ГДЕ + | Назначение.Ссылка = ГруппыДоступа.Профиль + | И ТИПЗНАЧЕНИЯ(Назначение.ТипПользователей) = ТИП(Справочник.Пользователи)) + | ТОГДА ИСТИНА + | КОГДА НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение + | ГДЕ + | Назначение.Ссылка = ГруппыДоступа.Профиль) + | ТОГДА ИСТИНА + | ИНАЧЕ ЛОЖЬ + | КОНЕЦ + | + |ИНДЕКСИРОВАТЬ ПО + | ГруппыДоступа.Ссылка"; + Иначе + ТекстЗапросаГрупп = + "ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК Группа + |ПОМЕСТИТЬ АктивныеГруппы + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + |ГДЕ + | ГруппыДоступа.Профиль <> &ПрофильАдминистратор + | И НЕ ГруппыДоступа.ПометкаУдаления + | И НЕ ГруппыДоступа.Профиль.ПометкаУдаления + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа + | ГДЕ + | ПользователиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка) + | И ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | Справочник.ПрофилиГруппДоступа.Назначение КАК Назначение + | ГДЕ + | Назначение.Ссылка = ГруппыДоступа.Профиль + | И Назначение.ТипПользователей <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(Назначение.ТипПользователей) <> ТИП(Справочник.Пользователи)) + | + |ИНДЕКСИРОВАТЬ ПО + | ГруппыДоступа.Ссылка"; + КонецЕсли; + + ТекстЗапросаНовыхНаборовГрупп = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | СоставыГруппПользователей.Пользователь КАК Пользователь, + | ПользователиГруппДоступа.Ссылка КАК Группа + |ПОМЕСТИТЬ НовыеНаборыГрупп + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппДоступа + | ПО СоставыГруппПользователей.ГруппаПользователей = ПользователиГруппДоступа.Пользователь + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА) + | И (СоставыГруппПользователей.Используется) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы + | ПО (ПользователиГруппДоступа.Ссылка = АктивныеГруппы.Группа) + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь, + | Группа"; + + ЭлементыДанных = НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, + ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, "НаборГруппДоступа", "ГруппыДоступа"); + + КоличествоВЗапросе = ЭлементыДанных.Количество() + 1; + Возврат ЭлементыДанных; + +КонецФункции + +// Для функции НаборыГруппДоступаДляОбновления. +Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей(ПараметрыОбновления, + КоличествоВЗапросе) + + ТекстЗапросаГрупп = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | СоставыГруппПользователей.ГруппаПользователей КАК Группа + |ПОМЕСТИТЬ АктивныеГруппы + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + |ГДЕ + | СоставыГруппПользователей.Используется + | И ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей) + | + |ИНДЕКСИРОВАТЬ ПО + | СоставыГруппПользователей.ГруппаПользователей"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ТекстЗапросаГрупп = СтрЗаменить(ТекстЗапросаГрупп, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ТекстЗапросаНовыхНаборовГрупп = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | СоставыГруппПользователей.Пользователь КАК Пользователь, + | СоставыГруппПользователей.ГруппаПользователей КАК Группа + |ПОМЕСТИТЬ НовыеНаборыГрупп + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы + | ПО СоставыГруппПользователей.ГруппаПользователей = АктивныеГруппы.Группа + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА) + | И (СоставыГруппПользователей.Используется) + | + |ИНДЕКСИРОВАТЬ ПО + | Пользователь, + | Группа"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ИмяСправочникаГрупп = "ГруппыВнешнихПользователей"; + Иначе + ИмяСправочникаГрупп = "ГруппыПользователей"; + КонецЕсли; + + ЭлементыДанных = НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, + ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, "НаборГруппПользователей", ИмяСправочникаГрупп); + + КоличествоВЗапросе = ЭлементыДанных.Количество() + 1; + Возврат ЭлементыДанных; + +КонецФункции + +// Для функций НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппДоступа, +// НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГруппПользователей. +// +Функция НаборыИзОдногоПользователяДляОбновленияНазначенныхНаборовГрупп(ПараметрыОбновления, + ТекстЗапросаГрупп, ТекстЗапросаНовыхНаборовГрупп, ИмяПоляНабора, ИмяСправочникаГрупп) + + ЧастиЗапроса = Новый Массив; + ЧастиЗапроса.Добавить(ТекстЗапросаГрупп); + ЧастиЗапроса.Добавить(ТекстЗапросаНовыхНаборовГрупп); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | НовыеНаборыГрупп.Пользователь КАК Пользователь, + | НовыеНаборыГрупп.Группа КАК Группа + |ИЗ + | НовыеНаборыГрупп КАК НовыеНаборыГрупп + | + |УПОРЯДОЧИТЬ ПО + | Пользователь, + | Группа + |ИТОГИ ПО + | Пользователь + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НаборыГрупп.Ссылка КАК ТекущаяСсылка, + | НаборыГрупп.Пользователь КАК Пользователь, + | ВЫБОР + | КОГДА НаборыГрупп.НовыйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | ТОГДА НаборыГрупп.РазрешенныйНаборГруппДоступа + | ИНАЧЕ НаборыГрупп.НовыйНаборГруппДоступа + | КОНЕЦ КАК ТекущийНаборГрупп + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГрупп + |ГДЕ + | НаборыГрупп.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГрупп.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И НаборыГрупп.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И НЕ(НаборыГрупп.РазрешенныйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НаборыГрупп.НовыйНаборГруппДоступа = ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка) + | И НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | НовыеНаборыГрупп КАК НовыеНаборыГрупп + | ГДЕ + | НовыеНаборыГрупп.Пользователь = НаборыГрупп.Пользователь)) + | И &УточнениеПланаЗапроса + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НаборыГрупп.Ссылка КАК Ссылка + |ПОМЕСТИТЬ НаборыСАктивнымиГруппами + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГрупп + |ГДЕ + | НаборыГрупп.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГрупп.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов + | ЛЕВОЕ СОЕДИНЕНИЕ АктивныеГруппы КАК АктивныеГруппы + | ПО + | ГруппыНаборов.Группа = АктивныеГруппы.Группа + | ГДЕ + | ГруппыНаборов.Ссылка = НаборыГрупп.Ссылка + | И АктивныеГруппы.Группа ЕСТЬ NULL) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НаборыГрупп.Ссылка КАК НаборГрупп, + | ГруппыНаборов.Группа КАК Группа + |ИЗ + | НаборыСАктивнымиГруппами КАК НаборыГрупп + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыНаборов + | ПО (ГруппыНаборов.Ссылка = НаборыГрупп.Ссылка) + | + |УПОРЯДОЧИТЬ ПО + | НаборГрупп, + | Группа + |ИТОГИ ПО + | НаборГрупп + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаборыГруппДоступа.НовыйНаборГруппДоступа КАК НовыйНабор + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.НовыйНаборГруппДоступа <> ЗНАЧЕНИЕ(Справочник.НаборыГруппДоступа.ПустаяСсылка)"; + + ЧастиЗапроса.Добавить(ТекстЗапроса); + Запрос.Текст = СтрСоединить(ЧастиЗапроса, ОбщегоНазначения.РазделительПакетаЗапросов()); + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.Пользователи).Служебный <> ИСТИНА", "ИСТИНА"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка)", + "ЗНАЧЕНИЕ(Справочник." + ИмяСправочникаГрупп + ".ПустаяСсылка)"); // @query-part-1, @query-part-2 + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "НовыйНаборГруппДоступа", "Новый" + ИмяПоляНабора); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "РазрешенныйНаборГруппДоступа", "Разрешенный" + ИмяПоляНабора); + + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + НовыеНаборы = РезультатыЗапроса[6].Выгрузить(); + РезультатыЗапроса[6] = Неопределено; + НовыеНаборы.Индексы.Добавить("НовыйНабор"); + + СуществующиеНаборыГрупп = Новый Соответствие; + Выгрузка = РезультатыЗапроса[5].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + РезультатыЗапроса[5] = Неопределено; + Для Каждого СтрокаДЗ Из Выгрузка.Строки Цикл + ГруппыНабора = СтрокаДЗ.Строки.ВыгрузитьКолонку("Группа"); + СуществующиеНаборыГрупп.Вставить(СтрокаДанныхДляХеширования(ГруппыНабора), + Новый Структура("НаборГрупп, НаборГруппНовый", СтрокаДЗ.НаборГрупп, + НовыеНаборы.Найти(СтрокаДЗ.НаборГрупп, "НовыйНабор") <> Неопределено)); + КонецЦикла; + Выгрузка.Строки.Очистить(); + НовыеНаборы.Очистить(); + + НовыеНаборыГрупп = Новый Соответствие; + Выгрузка = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + РезультатыЗапроса[2] = Неопределено; + Для Каждого СтрокаДЗ Из Выгрузка.Строки Цикл + ГруппыНабора = СтрокаДЗ.Строки.ВыгрузитьКолонку("Группа"); + СуществующийНаборГрупп = СуществующиеНаборыГрупп.Получить(СтрокаДанныхДляХеширования(ГруппыНабора)); + Свойства = Новый Структура("НаборГрупп, НаборГруппНовый, ГруппыНабора, ИдентификаторГрупп"); + Если СуществующийНаборГрупп = Неопределено Тогда + Свойства.ГруппыНабора = ГруппыНабора; + Свойства.ИдентификаторГрупп = Новый УникальныйИдентификатор; + Иначе + Свойства.НаборГрупп = СуществующийНаборГрупп.НаборГрупп; + Свойства.НаборГруппНовый = СуществующийНаборГрупп.НаборГруппНовый; + КонецЕсли; + НовыеНаборыГрупп.Вставить(СтрокаДЗ.Пользователь, Свойства); + КонецЦикла; + Выгрузка.Строки.Очистить(); + СуществующиеНаборыГрупп.Очистить(); + + Выборка = РезультатыЗапроса[3].Выбрать(); + РезультатыЗапроса.Очистить(); + + ЭлементыДанных = Новый ТаблицаЗначений; + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка"); + ЭлементыДанных.Колонки.Добавить("НаборГрупп"); + ЭлементыДанных.Колонки.Добавить("НаборГруппНовый", Новый ОписаниеТипов("Булево")); + ЭлементыДанных.Колонки.Добавить("ГруппыНабора"); + ЭлементыДанных.Колонки.Добавить("ИдентификаторГрупп"); + ПустойНабор = ПредопределенноеЗначение("Справочник.НаборыГруппДоступа.ПустаяСсылка"); + + Пока Выборка.Следующий() Цикл + НовыйНаборГрупп = НовыеНаборыГрупп.Получить(Выборка.Пользователь); + Если НовыйНаборГрупп <> Неопределено + И НовыйНаборГрупп.НаборГрупп = Выборка.ТекущийНаборГрупп Тогда + Продолжить; + КонецЕсли; + СтрокаТЗ = ЭлементыДанных.Добавить(); + СтрокаТЗ.ТекущаяСсылка = Выборка.ТекущаяСсылка; + Если НовыйНаборГрупп = Неопределено Тогда + СтрокаТЗ.НаборГрупп = ПустойНабор; + Продолжить; + ИначеЕсли НовыйНаборГрупп.НаборГрупп <> Неопределено Тогда + СтрокаТЗ.НаборГрупп = НовыйНаборГрупп.НаборГрупп; + СтрокаТЗ.НаборГруппНовый = НовыйНаборГрупп.НаборГруппНовый; + Продолжить; + КонецЕсли; + СтрокаТЗ.ГруппыНабора = НовыйНаборГрупп.ГруппыНабора; + СтрокаТЗ.ИдентификаторГрупп = НовыйНаборГрупп.ИдентификаторГрупп; + КонецЦикла; + + Возврат ЭлементыДанных; + +КонецФункции + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыГруппНазначенныеПользователямВСправочнике(ЭлементыДанных, + ПараметрыОбновления, ЭтоОбновлениеНазначенныхНаборовГруппДоступа) + + ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + + Если ЭтоОбновлениеНазначенныхНаборовГруппДоступа Тогда + ИмяПоляНабора = "НаборГруппДоступа"; + ТипЭлементовНабора = Справочники.ГруппыДоступа.ПустаяСсылка(); + ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()); + + Иначе + ИмяПоляНабора = "НаборГруппПользователей"; + Если Не ДляВнешнихПользователей Тогда + ТипЭлементовНабора = Справочники.ГруппыПользователей.ПустаяСсылка(); + ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы пользователей'", + ОбщегоНазначения.КодОсновногоЯзыка()); + Иначе + ТипЭлементовНабора = Справочники.ГруппыВнешнихПользователей.ПустаяСсылка(); + ПредставлениеЭлементовГрупп = НСтр("ru = 'Группы внешних пользователей'", + ОбщегоНазначения.КодОсновногоЯзыка()); + КонецЕсли; + КонецЕсли; + + НовыеНаборыГрупп = Новый Соответствие; + + Для Каждого Строка Из ЭлементыДанных Цикл + Если Строка.НаборГрупп = Неопределено Тогда + ОписаниеНабораГрупп = НовыеНаборыГрупп.Получить(Строка.ИдентификаторГрупп); + Если ОписаниеНабораГрупп = Неопределено Тогда + ОписаниеНабораГрупп = Новый Структура("НаборГрупп, НаборГруппНовый",, Ложь); + // @skip-check query-in-loop - Порционная обработка данных + ОписаниеНабораГрупп.НаборГрупп = НовыйНаборГрупп(Строка.ГруппыНабора, + ПараметрыОбновления.ДляВнешнихПользователей, + ТипЭлементовНабора, + ИмяПоляНабора, + ПредставлениеЭлементовГрупп, + ОписаниеНабораГрупп.НаборГруппНовый); + НовыеНаборыГрупп.Вставить(Строка.ИдентификаторГрупп, ОписаниеНабораГрупп); + КонецЕсли; + Строка.НаборГрупп = ОписаниеНабораГрупп.НаборГрупп; + Строка.НаборГруппНовый = ОписаниеНабораГрупп.НаборГруппНовый; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Строка.НаборГруппНовый Тогда + Объект["Новый" + ИмяПоляНабора] = Строка.НаборГрупп; + Иначе + Объект["Разрешенный" + ИмяПоляНабора] = Строка.НаборГрупп; + Объект["Новый" + ИмяПоляНабора] = ПараметрыОбновления.ПустойНаборГруппДоступа; + КонецЕсли; + Объект.Записать(); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьНаборыГруппНазначенныеПользователямВСправочнике. +Функция НовыйНаборГрупп(ГруппыНабора, ДляВнешнихПользователей, ТипЭлементовНабора, + ИмяПоляНабора, ПредставлениеЭлементовГрупп, НаборГруппНовый) + + НоваяСсылка = Справочники.НаборыГруппДоступа.ПолучитьСсылку(); + Объект = СлужебныйЭлемент(Справочники.НаборыГруппДоступа); + Объект.УстановитьСсылкуНового(НоваяСсылка); + Объект.ДляВнешнихПользователей = ДляВнешнихПользователей; + Объект.ТипЭлементовНабора = ТипЭлементовНабора; + Объект.Наименование = Строка(НоваяСсылка.УникальныйИдентификатор()) + " (" + ПредставлениеЭлементовГрупп + ")"; + + Для Каждого ГруппаНабора Из ГруппыНабора Цикл + Объект.Группы.Добавить().Группа = ГруппаНабора; + КонецЦикла; + + ЗаполнитьХешНабораГрупп(Объект); + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("ТипЭлементовНабора", Объект.ТипЭлементовНабора); + ЭлементБлокировки.УстановитьЗначение("Хеш", Объект.Хеш); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Если НаборГруппСуществует(Объект) Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); + Запрос.УстановитьПараметр("СуществующийНабор", Объект.Ссылка); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.НаборыГруппДоступа КАК ВсеНаборы + |ГДЕ + | ВсеНаборы.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ВсеНаборы.НовыйНаборГруппДоступа = &СуществующийНабор"; + Запрос.Текст = СтрЗаменить(Запрос.Текст, "НовыйНаборГруппДоступа", "Новый" + ИмяПоляНабора); + + Если Не Запрос.Выполнить().Пустой() Тогда + НаборГруппНовый = Истина; + КонецЕсли; + Иначе + Объект["Новый" + ИмяПоляНабора] = НоваяСсылка; + Объект.Записать(); + НаборГруппНовый = Истина; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Возврат Объект.Ссылка; + +КонецФункции + +// Для функции НовыйНаборГрупп и процедуры ЗаполнитьПустыеХешиНаборовГрупп. +Процедура ЗаполнитьХешНабораГрупп(Объект) + + Объект.Группы.Сортировать("Группа", Новый СравнениеЗначений); + + ДанныеДляХеша = Объект.Группы.ВыгрузитьКолонку("Группа"); + СтрокаДляХеша = СтрокаДанныхДляХеширования(ДанныеДляХеша); + Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); + Хеширование.Добавить(СтрокаДляХеша); + Объект.Хеш = Хеширование.ХешСумма; + +КонецПроцедуры + +// Для функции НовыйНаборГрупп. +Функция НаборГруппСуществует(Объект) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ТипЭлементовНабора", Объект.ТипЭлементовНабора); + Запрос.УстановитьПараметр("Хеш", Объект.Хеш); + Запрос.Текст = + "ВЫБРАТЬ + | СуществующиеНаборы.Ссылка КАК СсылкаНабора, + | СуществующиеНаборы.Группы.( + | Группы.Группа КАК Группа + | ) КАК ГруппыНабора + |ИЗ + | Справочник.НаборыГруппДоступа КАК СуществующиеНаборы + |ГДЕ + | СуществующиеНаборы.ТипЭлементовНабора = &ТипЭлементовНабора + | И СуществующиеНаборы.Хеш = &Хеш + | + |УПОРЯДОЧИТЬ ПО + | Ссылка"; + + ГруппыОбъекта = Объект.Группы.Выгрузить(, "Группа"); + ГруппыОбъекта.Индексы.Добавить("Группа"); + + Выгрузка = Запрос.Выполнить().Выгрузить(); + Для Каждого Строка Из Выгрузка Цикл + Если ГруппыОбъекта.Количество() <> Строка.ГруппыНабора.Количество() Тогда + Продолжить; + КонецЕсли; + ГруппыСовпадают = Истина; + Для Каждого Подстрока Из Строка.ГруппыНабора Цикл + Если ГруппыОбъекта.Найти(Подстрока.Группа, "Группа") = Неопределено Тогда + ГруппыСовпадают = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если ГруппыСовпадают Тогда + Объект = Новый Структура("Ссылка", Строка.СсылкаНабора); + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ОбновитьНаборыГруппДоступа. +Процедура ОбновитьНаборыГруппРазрешенныеПользователямВСправочнике(ЭлементыДанных, ПараметрыОбновления) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + + Для Каждого Строка Из ЭлементыДанных Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + Если ЗначениеЗаполнено(Объект.НовыйНаборГруппДоступа) Тогда + Объект.РазрешенныйНаборГруппДоступа = Объект.НовыйНаборГруппДоступа; + Объект.НовыйНаборГруппДоступа = ПараметрыОбновления.ПустойНаборГруппДоступа; + КонецЕсли; + Если ЗначениеЗаполнено(Объект.НовыйНаборГруппПользователей) Тогда + Объект.РазрешенныйНаборГруппПользователей = Объект.НовыйНаборГруппПользователей; + Объект.НовыйНаборГруппПользователей = ПараметрыОбновления.ПустойНаборГруппДоступа; + КонецЕсли; + Если Объект.Модифицированность() Тогда + Объект.Записать(); + КонецЕсли; + КонецЕсли; + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОчиститьПраваНесуществующихНаборовГруппДоступа(ПараметрыОбновления) + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаНаборов.НаборГруппДоступа КАК Набор + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.НаборГруппДоступа.Ссылка ЕСТЬ NULL + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаНаборов.Пользователь КАК Набор + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.Пользователь.Ссылка ЕСТЬ NULL + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаНаборов.ВнешнийПользователь КАК Набор + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.ВнешнийПользователь.Ссылка ЕСТЬ NULL"; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Выборка = РезультатыЗапроса[0].Выбрать(); + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Выборка.Набор, + "КлючиДоступаНаборовГруппДоступа", "НаборГруппДоступа"); + КонецЦикла; + + Выборка = РезультатыЗапроса[1].Выбрать(); + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Выборка.Набор, + "КлючиДоступаПользователей", "Пользователь"); + КонецЦикла; + + Выборка = РезультатыЗапроса[2].Выбрать(); + Пока Выборка.Следующий() Цикл + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Выборка.Набор, + "КлючиДоступаВнешнихПользователей", "ВнешнийПользователь"); + КонецЦикла; + +КонецПроцедуры + +// Для функции НаборыГруппДоступаДляОбновления. +Функция УстаревшиеНаборыГруппДоступаВСправочнике(ПараметрыОбновления, КоличествоВЗапросе) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ПараметрыОбновления.ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ДатаУстаревания", ДатаУстаревания()); + Запрос.УстановитьПараметр("РазрешенныйПустойНабор", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.Ссылка КАК ТекущаяСсылка, + | НаборыГруппДоступа.ТипЭлементовНабора КАК ТипЭлементовНабора, + | ЛОЖЬ КАК Используется, + | ИСТИНА КАК Удалить + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ТипЭлементовНабора = НЕОПРЕДЕЛЕНО + | И &УточнениеПланаЗапроса + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | НаборыГруппДоступа.Ссылка, + | НаборыГруппДоступа.ТипЭлементовНабора, + | ЛОЖЬ, + | ИСТИНА + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И НаборыГруппДоступа.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И (ВЫРАЗИТЬ(НаборыГруппДоступа.Пользователь КАК Справочник.Пользователи).Ссылка ЕСТЬ NULL + | ИЛИ НаборыГруппДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(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) + | ИЛИ НаборыГруппПользователей.НеИспользуетсяС < &ДатаУстаревания + | КОНЕЦ"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + + ЭлементыДанных = Запрос.Выполнить().Выгрузить(); + + КоличествоВЗапросе = ЭлементыДанных.Количество(); + Возврат ЭлементыДанных; + +КонецФункции + +// Для функций УстаревшиеНаборыГруппДоступаВСправочнике, ЭлементыДляОбновления. +Функция ДатаУстаревания() + + Возврат ТекущаяДатаСеанса() - КоличествоЧасовУстареванияНеиспользуемыхЭлементов() * 60 * 60; + +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбработатьУстаревшиеНаборыВСправочнике(ЭлементыДанных, ПараметрыОбновления) + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + + Для Каждого Строка Из ЭлементыДанных Цикл + ЭлементБлокировки.УстановитьЗначение("Ссылка", Строка.ТекущаяСсылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + Если Строка.Используется Тогда + Объект.НеИспользуетсяС = '00010101'; + ИначеЕсли Не Строка.Удалить Тогда + Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); + Иначе + Объект.ТипЭлементовНабора = Неопределено; + Объект.Хеш = 0; + Объект.Группы.Очистить(); + КонецЕсли; + Объект.Записать(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если Не Строка.Используется И Строка.Удалить Тогда + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаНаборовГруппДоступа", "НаборГруппДоступа"); + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаПользователей", "Пользователь"); + // @skip-check query-in-loop - Порционная обработка данных + УдалитьЗаписиРегистраДляНабора(Строка.ТекущаяСсылка, "КлючиДоступаВнешнихПользователей", "ВнешнийПользователь"); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Строка.ТекущаяСсылка); + Если Объект <> Неопределено Тогда + Объект.Удалить(); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры УдалитьУстаревшиеНаборыВСправочнике, ОчиститьПраваНесуществующихНаборовГруппДоступа. +Процедура УдалитьЗаписиРегистраДляНабора(Набор, ИмяРегистраСведений, ИмяПоляНабора) + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Набор", Набор); + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1000 + | КлючиДоступаНаборов.КлючДоступа КАК КлючДоступа + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборов + |ГДЕ + | КлючиДоступаНаборов.НаборГруппДоступа = &Набор"; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "КлючиДоступаНаборовГруппДоступа", ИмяРегистраСведений); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "НаборГруппДоступа", ИмяПоляНабора); + + ПолноеИмяРегистраСведений = "РегистрСведений." + ИмяРегистраСведений; + + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено; + + Пока Истина Цикл + Выгрузка = Запрос.Выполнить().Выгрузить(); + Если Выгрузка.Количество() = 0 Тогда + Прервать; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить(ПолноеИмяРегистраСведений); + ЭлементБлокировки.УстановитьЗначение(ИмяПоляНабора, Набор); + ЭлементБлокировки.ИсточникДанных = Выгрузка; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("КлючДоступа", "КлючДоступа"); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраСведений]); + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляНабора]; // ЭлементОтбора + ЭлементОтбора.Установить(Набор); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Для Каждого Строка Из Выгрузка Цикл + Если ПакетныйРежим Тогда + СтараяЗапись = НаборЗаписей.Добавить(); + СтараяЗапись[ИмяПоляНабора] = Набор; + СтараяЗапись.КлючДоступа = Строка.КлючДоступа; + Иначе + НаборЗаписей.Отбор.КлючДоступа.Установить(Строка.КлючДоступа); + НаборЗаписей.Записать(); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура ОбновитьПраваНаРазрешенныйКлючДоступа(ЕстьИзменения = Ложь) + + ОбновитьГруппыДоступаРазрешенногоКлючаДоступа( , ЕстьИзменения); + +КонецПроцедуры + +// Для процедуры ОбновитьПраваНаРазрешенныйКлючДоступа. +Процедура ОбновитьГруппыДоступаРазрешенногоКлючаДоступа(ГруппыДоступа = Неопределено, ЕстьИзменения = Ложь) Экспорт + + УстановитьПривилегированныйРежим(Истина); + РазрешенныйКлючДоступа = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйКлючДоступа(); + РазрешенныйПустойНабор = УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа(); + + Блокировка = Новый БлокировкаДанных; + + // Обновление групп доступа в регистре КлючиДоступаГруппДоступа. + ЗапросГрупп = Новый Запрос; + ЗапросГрупп.УстановитьПараметр("КлючДоступа", РазрешенныйКлючДоступа); + ЗапросГрупп.УстановитьПараметр("ПрофильАдминистратор", УправлениеДоступом.ПрофильАдминистратор()); + ЗапросГрупп.Текст = ТекстЗапросаВыбораРазличийГруппДоступаРазрешенногоКлюча(); + УстановитьУсловиеОтбораВЗапросе(ЗапросГрупп, ГруппыДоступа, "ГруппыДоступа", + "&УсловиеОтбораГруппДоступа1:ГруппыДоступа.Ссылка + |&УсловиеОтбораГруппДоступа2:СтарыеДанные.ГруппаДоступа"); // @query-part-2 + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + ЭлементБлокировкиГрупп = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировкиГрупп.УстановитьЗначение("КлючДоступа", РазрешенныйКлючДоступа); + НаборЗаписейГрупп = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписейГрупп.Отбор.КлючДоступа.Установить(РазрешенныйКлючДоступа); + КонецЕсли; + + // Обновление наборов групп доступа в регистре КлючиДоступаНаборовГруппДоступа. + ЗапросПравДляГруппДоступа = Новый Запрос; + ЗапросПравДляГруппДоступа.УстановитьПараметр("КлючДоступа", РазрешенныйКлючДоступа); + ЗапросПравДляГруппДоступа.УстановитьПараметр("РазрешенныйПустойНабор", РазрешенныйПустойНабор); + ЗапросПравДляГруппДоступа.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа(); + + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", РазрешенныйКлючДоступа); + ПраваДляГруппДоступа = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + Если Не ПакетныйРежим Тогда + ПраваДляГруппДоступа.Отбор.КлючДоступа.Установить(РазрешенныйКлючДоступа); + КонецЕсли; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + + РезультатЗапросаГрупп = ЗапросГрупп.Выполнить(); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаГрупп, + НаборЗаписейГрупп, "ГруппаДоступа", РазрешенныйКлючДоступа, ЕстьИзменения); + + РезультатЗапросаПравДляГруппДоступа = ЗапросПравДляГруппДоступа.Выполнить(); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаПравДляГруппДоступа, + ПраваДляГруппДоступа, "НаборГруппДоступа", РазрешенныйКлючДоступа, ЕстьИзменения); + + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ОбновитьГруппыРазрешенногоКлючаДоступа. +Функция ТекстЗапросаВыбораРазличийГруппДоступаРазрешенногоКлюча() + + ТекстЗапроса = + "ВЫБРАТЬ + | ВсеСтроки.ГруппаДоступа КАК ГруппаДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыДоступа.Ссылка КАК ГруппаДоступа, + | ИСТИНА КАК ПравоИзменение, + | ИСТИНА КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа + | ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка + | И (ГруппыДоступа.Профиль <> &ПрофильАдминистратор) + | И (НЕ ГруппыДоступа.ПометкаУдаления) + | И (НЕ ПрофилиГруппДоступа.ПометкаУдаления) + | И (&УсловиеОтбораГруппДоступа1) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + | ИЗ + | Справочник.ГруппыДоступа.Пользователи КАК УчастникиГруппДоступа + | ГДЕ + | УчастникиГруппДоступа.Ссылка = ГруппыДоступа.Ссылка)) + | И (&УточнениеПланаЗапроса) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.ГруппаДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.КлючДоступа = &КлючДоступа + | И &УсловиеОтбораГруппДоступа2) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.ГруппаДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура УдалитьУстаревшиеЭлементыДанныхСписка(ЭлементыДанных, ПараметрыОбновления) + + Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда + УдалитьУстаревшиеЭлементыДанныхСсылочногоТипа(ЭлементыДанных, ПараметрыОбновления) + Иначе + УдалитьУстаревшиеЭлементыДанныхРегистров(ЭлементыДанных, ПараметрыОбновления) + КонецЕсли; + +КонецПроцедуры + +// Для процедуры УдалитьУстаревшиеЭлементыДанныхСписка. +Процедура УдалитьУстаревшиеЭлементыДанныхСсылочногоТипа(ЭлементыДанных, ПараметрыОбновления) + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + Если ПакетныйРежим Тогда + РазмерПорции = 1000; // Удаление N элементов данных по 1000 за раз. + Иначе + РазмерПорции = 100; // Удаление N элементов данных по 100 за раз. + КонецЕсли; + ПорцияЭлементовДанных = Неопределено; + КоличествоЭлементов = ЭлементыДанных.Количество(); + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + НаборЗаписейДляУдаления = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + + Индекс = 0; + Пока Индекс < КоличествоЭлементов Цикл + Если ПорцияЭлементовДанных = Неопределено Тогда + ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); + ПорцияДляОбновления = ПорцияЭлементовДанных.Скопировать(); + ПорцияДляПроверки = ПорцияЭлементовДанных.Скопировать(); + КонецЕсли; + ЭлементДанных = ЭлементыДанных[Индекс]; + ЗаполнитьЗначенияСвойств(ПорцияЭлементовДанных.Добавить(), ЭлементДанных); + Если ЭлементДанных.Обновить Тогда + ЗаполнитьЗначенияСвойств(ПорцияДляОбновления.Добавить(), ЭлементДанных); + ИначеЕсли Не ЭлементДанных.Удалить Тогда // Не Обновить И Не Удалить. + ЗаполнитьЗначенияСвойств(ПорцияДляПроверки.Добавить(), ЭлементДанных); + КонецЕсли; + + Индекс = Индекс + 1; + Если ПорцияЭлементовДанных.Количество() < РазмерПорции И Индекс < КоличествоЭлементов Тогда + Продолжить; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); + ЭлементБлокировки.ИсточникДанных = ПорцияЭлементовДанных; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Объект", "ТекущаяСсылка"); + + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + ЗапросДляОбновления = Новый Запрос; + ЗапросДляОбновления.Текст = ПараметрыОбновления.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных; + ЗапросДляОбновления.УстановитьПараметр("ЭлементыДанных", ПорцияДляОбновления); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "ТекущаяСсылка"); + ЗапросДляПроверки = Новый Запрос; + ЗапросДляПроверки.Текст = ПараметрыОбновления.ТекстЗапросаПроверкиУстаревшихЭлементовДанных; + ЗапросДляПроверки.УстановитьПараметр("ЭлементыДанных", ПорцияДляПроверки); + УстановитьУточнениеПланаЗапроса(ЗапросДляПроверки.Текст); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляОбновления = ЗапросДляОбновления.Выполнить().Выгрузить(); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляУдаления = ЗапросДляПроверки.Выполнить().Выгрузить(); + КонецЕсли; + Для Каждого Строка Из ПорцияЭлементовДанных Цикл + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.Объект.Установить(Строка.ТекущаяСсылка); + КонецЕсли; + Если Строка.Обновить Тогда + Если Не ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + КонецЕсли; + НайденнаяСтрока = ДанныеДляОбновления.Найти(Строка.ТекущаяСсылка, "Объект"); + Если НайденнаяСтрока <> Неопределено Тогда + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + НайденнаяСтрока.КлючДоступаПользователей = Неопределено; + Иначе + НайденнаяСтрока.КлючДоступаВнешнихПользователей = Неопределено; + КонецЕсли; + Если ЗначениеЗаполнено(НайденнаяСтрока.КлючДоступаВнешнихПользователей) + Или ЗначениеЗаполнено(НайденнаяСтрока.КлючДоступаПользователей) Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НайденнаяСтрока); + ИначеЕсли ПакетныйРежим Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), НайденнаяСтрока); + КонецЕсли; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + КонецЕсли; + КонецЕсли; + ИначеЕсли Строка.Удалить + Или ЗначениеЗаполнено(ПорцияДляПроверки) + И ДанныеДляУдаления.Найти(Строка.ТекущаяСсылка, "ТекущаяСсылка") <> Неопределено Тогда + + Если ПакетныйРежим Тогда + НаборЗаписейДляУдаления.Добавить().Объект = Строка.ТекущаяСсылка; + Иначе + НаборЗаписей.Очистить(); + НаборЗаписей.Записать(); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим Тогда + Если ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + Если ЗначениеЗаполнено(НаборЗаписейДляУдаления) Тогда + НаборЗаписейДляУдаления.Записать(РежимУдаления); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + Если ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + НаборЗаписейДляУдаления.Очистить(); + КонецЕсли; + КоличествоОбработанных = ПорцияЭлементовДанных.Количество(); + ПорцияЭлементовДанных = Неопределено; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры УдалитьУстаревшиеЭлементыДанныхСписка. +Процедура УдалитьУстаревшиеЭлементыДанныхРегистров(ЭлементыДанных, ПараметрыОбновления) + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + Если ПакетныйРежим Тогда + РазмерПорции = 1000; // Удаление N элементов данных по 1000 за раз. + Иначе + РазмерПорции = 100; // Удаление N элементов данных по 100 за раз. + КонецЕсли; + + Если ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) + И ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных <> "НекорректныеЭлементыОбщегоРегистра" Тогда + + ИмяРегистра = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; + Иначе + ИмяРегистра = "КлючиДоступаКРегистрам"; + КонецЕсли; + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистра]); + НаборЗаписейДляУдаления = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистра]); + + ИзмеренияСпискаДляБлокировки = Новый Массив; + ОпорныеПоля = ПараметрыОбновления.ОпорныеПоля; + Если ОпорныеПоля = Неопределено Тогда + КоличествоИспользуемыхОпорныхПолей = 0; + МаксимальноеКоличествоОпорныхПолей = + УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистра); + Иначе + КоличествоИспользуемыхОпорныхПолей = ОпорныеПоля.Используемые.Количество(); + МаксимальноеКоличествоОпорныхПолей = ОпорныеПоля.МаксимальноеКоличество; + ОписаниеПолейБлокировки = УправлениеДоступомСлужебныйПовтИсп.ОписаниеПолейБлокировкиРегистра( + ПараметрыОбновления.Список); + ПоляБлокировкиСписка = СтрРазделить(ОписаниеПолейБлокировки.СписокПолей, ","); + БлокироватьСписокПоРегистратору = Ложь; + Номер = 1; + Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл + ИндексПоля = ПоляБлокировкиСписка.Найти(ИмяОпорногоПоля); + Если ИндексПоля <> Неопределено Тогда + ОписаниеПоля = ОписаниеПолейБлокировки.ОписаниеПолей.Получить(ИндексПоля); + ИзмерениеСписка = Новый Структура; + ИзмерениеСписка.Вставить("ИмяОпорногоПоля", ОписаниеПоля.Имя); + ИзмерениеСписка.Вставить("Тип", ОписаниеПоля.Тип); + ИзмерениеСписка.Вставить("ИмяПоля", СтрШаблон("Поле%1", Номер)); + ИзмеренияСпискаДляБлокировки.Добавить(ИзмерениеСписка); + Если ОписаниеПоля.Имя = "Регистратор" + И ОписаниеПолейБлокировки.БлокироватьПоРегистратору Тогда + БлокироватьСписокПоРегистратору = Истина; + КонецЕсли; + КонецЕсли; + Номер = Номер + 1; + КонецЦикла; + КонецЕсли; + ИменаИзмерений = Новый Массив; + Если ИмяРегистра = "КлючиДоступаКРегистрам" Тогда + ИменаИзмерений.Добавить("Регистр"); + КонецЕсли; + ИменаИзмерений.Добавить("ВариантДоступа"); + Для Номер = 1 По КоличествоИспользуемыхОпорныхПолей Цикл + ИменаИзмерений.Добавить(СтрШаблон("Поле%1", Номер)); + КонецЦикла; + + ОтборДанных = Новый Структура; + ТочныйОтборДанных = Новый Структура; + Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл + ОтборДанных.Вставить(ИмяИзмерения); + ТочныйОтборДанных.Вставить(ИмяИзмерения); + КонецЦикла; + Для Счетчик = Номер По МаксимальноеКоличествоОпорныхПолей Цикл + ТочныйОтборДанных.Вставить(СтрШаблон("Поле%1", Счетчик), + Перечисления.ДополнительныеЗначенияДоступа.Null); + КонецЦикла; + + ПорцияЭлементовДанных = Неопределено; + КоличествоЭлементов = ЭлементыДанных.Количество(); + + Индекс = 0; + Пока Индекс < КоличествоЭлементов Цикл + Если ПорцияЭлементовДанных = Неопределено Тогда + ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); + ПорцияДляОбновления = ПорцияЭлементовДанных.Скопировать(); + ПорцияДляПроверки = ПорцияЭлементовДанных.Скопировать(); + КонецЕсли; + ЭлементДанных = ЭлементыДанных[Индекс]; + ЗаполнитьЗначенияСвойств(ПорцияЭлементовДанных.Добавить(), ЭлементДанных); + Если ЭлементДанных.Обновить Тогда + ЗаполнитьЗначенияСвойств(ПорцияДляОбновления.Добавить(), ЭлементДанных); + ИначеЕсли Не ЭлементДанных.Удалить Тогда // Не Обновить И Не Удалить. + Для Каждого ИзмерениеСписка Из ИзмеренияСпискаДляБлокировки Цикл + Если Не ИзмерениеСписка.Тип.СодержитТип(ТипЗнч(ЭлементДанных[ИзмерениеСписка.ИмяПоля])) Тогда + ЭлементДанных.Удалить = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + Если Не ЭлементДанных.Удалить Тогда + ЗаполнитьЗначенияСвойств(ПорцияДляПроверки.Добавить(), ЭлементДанных); + КонецЕсли; + КонецЕсли; + + Индекс = Индекс + 1; + Если ПорцияЭлементовДанных.Количество() < РазмерПорции И Индекс < КоличествоЭлементов Тогда + Продолжить; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистра); + ЭлементБлокировки.ИсточникДанных = ПорцияЭлементовДанных; + Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл + ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ИмяИзмерения, ИмяИзмерения); + КонецЦикла; + + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + ЗапросДляОбновления = Новый Запрос; + ЗапросДляОбновления.Текст = ПараметрыОбновления.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных; + ЗапросДляОбновления.УстановитьПараметр("ЭлементыДанных", ПорцияДляОбновления); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + Если БлокироватьСписокПоРегистратору Тогда + ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список + ".НаборЗаписей"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; + ЭлементБлокировки.ИспользоватьИзИсточникаДанных( + ИзмеренияСпискаДляБлокировки[0].ИмяОпорногоПоля, + ИзмеренияСпискаДляБлокировки[0].ИмяПоля); + Иначе + ЭлементБлокировки = Блокировка.Добавить(ПараметрыОбновления.Список); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + Если ЗначениеЗаполнено(ИзмеренияСпискаДляБлокировки) Тогда + ЭлементБлокировки.ИсточникДанных = ПорцияДляПроверки; + Для Каждого ИзмерениеСписка Из ИзмеренияСпискаДляБлокировки Цикл + ЭлементБлокировки.ИспользоватьИзИсточникаДанных(ИзмерениеСписка.ИмяОпорногоПоля, + ИзмерениеСписка.ИмяПоля); + КонецЦикла; + КонецЕсли; + КонецЕсли; + ЗапросДляПроверки = Новый Запрос; + ЗапросДляПроверки.Текст = ПараметрыОбновления.ТекстЗапросаПроверкиУстаревшихЭлементовДанных; + ЗапросДляПроверки.УстановитьПараметр("КлючиДоступаКРегистрам", ПорцияДляПроверки); + УстановитьУточнениеПланаЗапроса(ЗапросДляПроверки.Текст); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Если ЗначениеЗаполнено(ПорцияДляОбновления) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляОбновления = ЗапросДляОбновления.Выполнить().Выгрузить(); + КонецЕсли; + Если ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДанныеДляУдаления = ЗапросДляПроверки.Выполнить().Выгрузить(); + КонецЕсли; + Для Каждого Строка Из ПорцияЭлементовДанных Цикл + Если Не ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл + ЭлементОтбора = НаборЗаписей.Отбор[ИмяИзмерения]; // ЭлементОтбора + Если Строка[ИмяИзмерения] = Неопределено Тогда + ЭлементОтбора.Значение = Неопределено; + ЭлементОтбора.Использование = Истина; + Иначе + ЭлементОтбора.Установить(Строка[ИмяИзмерения]); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если Строка.Обновить Тогда + ЗаполнитьЗначенияСвойств(ОтборДанных, Строка); + НайденныеСтроки = ДанныеДляОбновления.НайтиСтроки(ОтборДанных); + Если Не ЗначениеЗаполнено(НайденныеСтроки) Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(ТочныйОтборДанных, ОтборДанных); + ТочноНайденныеСтроки = ДанныеДляОбновления.НайтиСтроки(ТочныйОтборДанных); + Если ТочноНайденныеСтроки.Количество() > 0 Тогда + НайденнаяСтрока = ТочноНайденныеСтроки.Получить(0); + Если Не ПакетныйРежим Тогда + Если НайденныеСтроки.Количество() = 1 Тогда + Продолжить; + КонецЕсли; + ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), НайденнаяСтрока); + КонецЕсли; + Иначе + НайденнаяСтрока = Неопределено; + НоваяЗапись = НаборЗаписей.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяЗапись, НайденныеСтроки[0]); + ЗаполнитьЗначенияСвойств(НоваяЗапись, ТочныйОтборДанных); + КонецЕсли; + Если ПакетныйРежим Тогда + Для Каждого УдаляемаяСтрока Из НайденныеСтроки Цикл + Если УдаляемаяСтрока <> НайденнаяСтрока Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), УдаляемаяСтрока); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ИначеЕсли Не Строка.Удалить И ЗначениеЗаполнено(ПорцияДляПроверки) Тогда + ЗаполнитьЗначенияСвойств(ОтборДанных, Строка); + Если ДанныеДляУдаления.НайтиСтроки(ОтборДанных).Количество() = 0 Тогда + Продолжить; + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + ИначеЕсли Не Строка.Обновить Тогда + ЗаполнитьЗначенияСвойств(НаборЗаписейДляУдаления.Добавить(), Строка); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим Тогда + Если ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + Если ЗначениеЗаполнено(НаборЗаписейДляУдаления) Тогда + НаборЗаписейДляУдаления.Записать(РежимУдаления); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + Если ПакетныйРежим Тогда + НаборЗаписей.Очистить(); + НаборЗаписейДляУдаления.Очистить(); + КонецЕсли; + КоличествоОбработанных = ПорцияЭлементовДанных.Количество(); + ПорцияЭлементовДанных = Неопределено; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ВыполнитьОбновлениеДоступаСписка. +Процедура УдалитьОбъектыНедопустимыхТиповВРегистреКлючиДоступаКОбъектам() + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) КАК ТипСсылки + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным"; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + ДопустимыеТипы = УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповСсылокДопустимыхОбъектов(); + Выборка = Запрос.Выполнить().Выбрать(); + + Запрос.Текст = + "ВЫБРАТЬ + | КлючиДоступаКДанным.Объект КАК Объект + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКДанным + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКДанным.Объект) = &Тип"; + + Пока Выборка.Следующий() Цикл + Если Выборка.ТипСсылки = Тип("Неопределено") Тогда + НаборЗаписей.Отбор.Объект.Установить(Неопределено); + НаборЗаписей.Записать(); + Продолжить; + ИначеЕсли ДопустимыеТипы.СодержитТип(Выборка.ТипСсылки) Тогда + Продолжить; + КонецЕсли; + Запрос.УстановитьПараметр("Тип", Выборка.ТипСсылки); + // @skip-check query-in-loop - Порционная обработка данных + Объекты = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Объект"); + Для Каждого Объект Из Объекты Цикл + НаборЗаписей.Отбор.Объект.Установить(Объект); + НаборЗаписей.Записать(); + КонецЦикла; + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = НЕОПРЕДЕЛЕНО"; + + Если Запрос.Выполнить().Пустой() Тогда + Возврат; + КонецЕсли; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКРегистрам); + НаборЗаписей.Отбор.Регистр.Установить(Неопределено); + НаборЗаписей.Записать(); + +КонецПроцедуры + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами(ЭлементыДанных, ПараметрыОбновления) + + РазмерПорции = 100; // Загрузка N элементов данных по 100 за раз. + + Если ПараметрыОбновления.ЭтоСсылочныйТип Тогда + ЭтоОбработкаСуществующихКомбинаций = Ложь; + ЭтоОбработкаНовыхКомбинаций = Ложь; + Иначе + ВидКлючаДанных = ПараметрыОбновления.ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + ЭтоОбработкаСуществующихКомбинаций = ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами"; + ЭтоОбработкаНовыхКомбинаций = ПараметрыОбновления.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей + И ( ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" + Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей"); + КонецЕсли; + + Индекс = 0; + Пока Индекс < ЭлементыДанных.Количество() Цикл + + ПорцияЭлементовДанных = ЭлементыДанных.Скопировать(Новый Массив); + Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда + ПорцияЭлементовДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов("Число")); + ПорцияУдаляемыхЭлементовДанных = Новый Массив; + КонецЕсли; + КоличествоПропущенных = 0; + + Пока Индекс < ЭлементыДанных.Количество() + И ПорцияЭлементовДанных.Количество() < РазмерПорции + И (ПараметрыОбновления.ЭтоСсылочныйТип + Или ПорцияУдаляемыхЭлементовДанных.Количество() < РазмерПорции) Цикл + + ЭлементДанных = ЭлементыДанных[Индекс]; + + Если ЭтоОбработкаСуществующихКомбинаций + И НекорректнаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) Тогда + + Если ПорцияЭлементовДанных.Количество() > 0 Тогда + Прервать; + КонецЕсли; + ПорцияУдаляемыхЭлементовДанных.Добавить(ЭлементДанных); + + ИначеЕсли ЭтоОбработкаСуществующихКомбинаций + И ПорцияУдаляемыхЭлементовДанных.Количество() > 0 Тогда + Прервать; + + ИначеЕсли ЭтоОбработкаНовыхКомбинаций + И НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) Тогда + + КоличествоПропущенных = КоличествоПропущенных + 1; + Иначе + НоваяСтрока = ПорцияЭлементовДанных.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭлементДанных); + Если Не ПараметрыОбновления.ЭтоСсылочныйТип Тогда + НоваяСтрока.ТекущаяСсылка = ПорцияЭлементовДанных.Индекс(НоваяСтрока) + 1; + КонецЕсли; + КонецЕсли; + Индекс = Индекс + 1; + КонецЦикла; + + Если ЭтоОбработкаСуществующихКомбинаций + И ПорцияУдаляемыхЭлементовДанных.Количество() > 0 Тогда + + УдалитьНекорректныеКомбинацииЗначенийОпорныхПолей(ПорцияУдаляемыхЭлементовДанных, ПараметрыОбновления); + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, ПорцияУдаляемыхЭлементовДанных.Количество()) Тогда + Прервать; + КонецЕсли; + КонецЕсли; + + Если ПорцияЭлементовДанных.Количество() > 0 Тогда + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ПорцияЭлементовДанных, ПараметрыОбновления); + КонецЕсли; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоПропущенных) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. +Функция НекорректнаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) + + Номер = 1; + Для Каждого ХранилищеТиповПоля Из ПараметрыОбновления.ОпорныеПоля.ТипыИспользуемых Цикл + ТипыПоля = ХранилищеТиповПоля.Получить(); + ИмяПоля = СтрШаблон("Поле%1", Номер); + + Если Не ТипыПоля.СодержитТип(ТипЗнч(ЭлементДанных[ИмяПоля])) + И ЭлементДанных[ИмяПоля] <> Неопределено Тогда + + Возврат Истина; + КонецЕсли; + + Номер = Номер + 1; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. +Функция НедопустимаяКомбинацияЗначенийОпорныхПолей(ЭлементДанных, ПараметрыОбновления) + + ТипыПолей = УправлениеДоступомСлужебныйПовтИсп.ТипыОпорныхПолейРегистра( + ПараметрыОбновления.ИмяОтдельногоРегистраКлючей); + + Для Номер = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл + ИмяПоля = СтрШаблон("Поле%1", Номер); + + Если Не ТипыПолей[ИмяПоля].СодержитТип(ТипЗнч(ЭлементДанных[ИмяПоля])) + И ЭлементДанных[ИмяПоля] <> Неопределено Тогда + + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции ДоступРазрешен. +Функция МодельОбъектовВПамяти(ОписаниеДанных, ПараметрыОграничения) + + Если ТипЗнч(ОписаниеДанных) = Тип("Массив") Тогда + Объекты = ОписаниеДанных; + Иначе + Объекты = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ОписаниеДанных); + КонецЕсли; + Объект = Объекты[0]; // СправочникОбъект + + ЭлементыДанных = Новый ТаблицаЗначений; + ЭлементыДанных.Колонки.Добавить("ТекущаяСсылка", Новый ОписаниеТипов( + ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипЗнч(Объект.Ссылка)))); + + Модель = Новый Структура; + Модель.Вставить("ЭлементыДанных", ЭлементыДанных); + Модель.Вставить("Таблицы", Новый Соответствие); + Модель.Вставить("КлючиДоступаКОбъектам", + РегистрыСведений.КлючиДоступаКОбъектам.СоздатьНаборЗаписей().Выгрузить()); + + ПоляТаблицОбъекта = ПараметрыОграничения.ПоляТаблицОбъекта; + + Для Каждого Объект Из Объекты Цикл + Объект = Объект; // СправочникОбъект + ТекущаяСсылка = ПользователиСлужебный.СсылкаОбъекта(ОписаниеДанных); + ЭлементыДанных.Добавить().ТекущаяСсылка = ТекущаяСсылка; + Для Каждого ОписаниеТаблицы Из ПоляТаблицОбъекта Цикл + ОписаниеТаблицы = ОписаниеТаблицы; // см. НовыеПоляТаблицыОбъекта + Таблица = Модель.Таблицы.Получить(ОписаниеТаблицы.ПолноеИмяТаблицы); // ТаблицаЗначений + СписокПолей = ОписаниеТаблицы.СписокПолей; + Если Таблица = Неопределено Тогда + Таблица = ОписаниеТаблицы.ТаблицаСПолями.Получить(); + Модель.Таблицы.Вставить(ОписаниеТаблицы.ПолноеИмяТаблицы, Таблица); + КонецЕсли; + Если ЗначениеЗаполнено(ОписаниеТаблицы.ТабличнаяЧасть) Тогда + Выгрузка = Объект[ОписаниеТаблицы.ТабличнаяЧасть].Выгрузить(, СписокПолей); // ТаблицаЗначений + Выгрузка.Свернуть(СписокПолей); + Для Каждого Строка Из Выгрузка Цикл + НоваяСтрока = Таблица.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка, СписокПолей); + НоваяСтрока.Ссылка = ТекущаяСсылка; + КонецЦикла; + Иначе + НоваяСтрока = Таблица.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Объект, СписокПолей); + НоваяСтрока.Ссылка = ТекущаяСсылка; + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Возврат Модель; + +КонецФункции + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами, ОбновитьКлючиДоступаЭлементовДанныхПриЗаписи. +Процедура ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка(ПорцияЭлементовДанных, ПараметрыОбновления) + + ЭтоСсылочныйТип = ПараметрыОбновления.ЭтоСсылочныйТип; + ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; + + Контекст = Новый Структура; + Контекст.Вставить("ПорцияЭлементовДанных", ПорцияЭлементовДанных); + + ЗапросЗначенийЭлементовДанных = Новый Запрос; + Если ЭтоСсылочныйТип Тогда + Контекст.Вставить("СсылкиНаОбъекты", ПорцияЭлементовДанных.ВыгрузитьКолонку("ТекущаяСсылка")); + КонецЕсли; + Если ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда + Если ЭтоСсылочныйТип Тогда + ЗапросЗначенийЭлементовДанных.УстановитьПараметр("СсылкиНаОбъекты", Контекст.СсылкиНаОбъекты); + ИндексТаблицы = 0; + КонецЕсли; + Если ПараметрыОбновления.Свойство("МодельОбъектовВПамяти") Тогда + ЗапросЗначенийЭлементовДанных.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа; + Для Каждого Таблица Из ПараметрыОбновления.МодельОбъектовВПамяти.Таблицы Цикл + ЗапросЗначенийЭлементовДанных.УстановитьПараметр(Таблица.Ключ, Таблица.Значение); + КонецЦикла; + ИндексТаблицы = ПараметрыОбновления.МодельОбъектовВПамяти.Таблицы.Количество(); + Иначе + ЗапросЗначенийЭлементовДанных.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа; + Если Не ЭтоСсылочныйТип Тогда + ЗапросЗначенийЭлементовДанных.УстановитьПараметр("ИдентификаторРегистра", ИдентификаторСписка); + ЗапросЗначенийЭлементовДанных.УстановитьПараметр("ЗначенияОпорныхПолей", ПорцияЭлементовДанных); + ИндексТаблицы = 1; + КонецЕсли; + КонецЕсли; + УстановитьУточнениеПланаЗапроса(ЗапросЗначенийЭлементовДанных.Текст); + РезультатыЗапросаЗначенийЭлементов = ЗапросЗначенийЭлементовДанных.ВыполнитьПакет(); + Иначе + РезультатыЗапросаЗначенийЭлементов = Новый Массив; + КонецЕсли; + + ДанныеСтроковыхКлючейДоступа = Новый Соответствие; + ТаблицыКлюча = ПараметрыОбновления.ТаблицыКлюча; + + ЗначенияСтрокТаблиц = Новый Соответствие; + КлючиЗначенийСтрокОбъектов = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийЭлементов, + ИндексТаблицы, ТаблицыКлюча, ЗначенияСтрокТаблиц); + + ТребуемыеКлючиДоступа = Новый Массив; + ХешиТребуемыхКлючейДоступа = Новый Массив; + ОписаниеКлючейДоступаОбъектов = Новый Массив; + Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл + ОписаниеКлючейЗначений = КлючиЗначенийСтрокОбъектов.Получить(ЭлементДанных.ТекущаяСсылка); + СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); + Свойства = ДанныеСтроковыхКлючейДоступа.Получить(СтрокаДляХеша); + Если Свойства = Неопределено Тогда + Свойства = Новый Структура("ЗначенияТаблиц, СтрокаДляХеша, Хеш, КлючДоступа, ЗначенияКолонокТаблиц"); + ДанныеСтроковыхКлючейДоступа.Вставить(СтрокаДляХеша, Свойства); + ЗначенияТаблиц = Новый Массив; + Для Каждого ИмяТаблицы Из ТаблицыКлюча Цикл + КлючЗначений = ОписаниеКлючейЗначений.КлючиЗначений[ТаблицыКлюча.Найти(ИмяТаблицы)]; + ЗначенияСтрок = ЗначенияСтрокТаблиц.Получить(ИмяТаблицы).Получить(КлючЗначений); + Если ЗначенияСтрок = Неопределено Тогда + ЗначенияСтрок = Новый Массив; + КонецЕсли; + ЗначенияТаблиц.Добавить(Новый Структура("ИмяТаблицы, Таблица", ИмяТаблицы, ЗначенияСтрок)); + КонецЦикла; + Свойства.ЗначенияТаблиц = ЗначенияТаблиц; + Свойства.СтрокаДляХеша = СтрокаДляХеша; + Свойства.ЗначенияКолонокТаблиц = ОписаниеКлючейЗначений.ЗначенияКолонокТаблиц; + Хеширование = Новый ХешированиеДанных(ХешФункция.CRC32); + Хеширование.Добавить(СтрокаДляХеша); + Свойства.Хеш = Хеширование.ХешСумма; + ТребуемыеКлючиДоступа.Добавить(Свойства); + ХешиТребуемыхКлючейДоступа.Добавить(Свойства.Хеш); + КонецЕсли; + ОписаниеКлючейДоступаОбъектов.Добавить( + Новый Структура("ТекущаяСсылка, СвойстваКлюча", ЭлементДанных.ТекущаяСсылка, Свойства)); + КонецЦикла; + Контекст.Вставить("ОписаниеКлючейДоступаОбъектов", ОписаниеКлючейДоступаОбъектов); + + // Получение данных существующих ключей доступа по хешам требуемых ключей доступа. + ЗапросЗначенийКлючей = Новый Запрос; + ЗапросЗначенийКлючей.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения; + ЗапросЗначенийКлючей.УстановитьПараметр("Хеши", ХешиТребуемыхКлючейДоступа); + ЗапросЗначенийКлючей.УстановитьПараметр("Список", ИдентификаторСписка); + УстановитьУточнениеПланаЗапроса(ЗапросЗначенийКлючей.Текст); + РезультатыЗапросаЗначенийКлючей = ЗапросЗначенийКлючей.ВыполнитьПакет(); + + КлючиЗначенийСтрокКлючей = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийКлючей, + ?(Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) + Или СтрНачинаетсяС(ТаблицыКлюча[0], "Шапка"), 0, 1), + ТаблицыКлюча); + Выборка = РезультатыЗапросаЗначенийКлючей[0].Выбрать(); + + Пока Выборка.Следующий() Цикл + ОписаниеКлючейЗначений = КлючиЗначенийСтрокКлючей.Получить(Выборка.ТекущаяСсылка); + СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); + Свойства = ДанныеСтроковыхКлючейДоступа.Получить(СтрокаДляХеша); + Если Свойства <> Неопределено И Свойства.КлючДоступа = Неопределено Тогда + Свойства.КлючДоступа = Выборка.ТекущаяСсылка; + КонецЕсли; + КонецЦикла; + + // Создание недостающих ключей доступа. + ОписаниеНовыхКлючей = Новый Массив; + Для Каждого ОписаниеКлюча Из ТребуемыеКлючиДоступа Цикл + Если ОписаниеКлюча.КлючДоступа <> Неопределено Тогда + Продолжить; + КонецЕсли; + ОписаниеНовыхКлючей.Добавить(ОписаниеКлюча); + КонецЦикла; + Если ОписаниеНовыхКлючей.Количество() > 0 Тогда + ОбновитьПраваНаКлючиДоступа(ОписаниеНовыхКлючей, ПараметрыОбновления, Истина, Контекст); + Для Каждого ОписаниеКлюча Из ОписаниеНовыхКлючей Цикл + КлючДоступаОбъект = ОписаниеКлюча.КлючДоступаОбъект; // СправочникОбъект.КлючиДоступа + Если ЗначениеЗаполнено(КлючДоступаОбъект.Ссылка) Тогда + ОписаниеКлюча.КлючДоступа = КлючДоступаОбъект.Ссылка; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + // Обновление ключей доступа элементов данных. + Если ЭтоСсылочныйТип Тогда + Если ПараметрыОбновления.Свойство("МодельОбъектовВПамяти") Тогда + ИмяПоляКлюча = ?(ПараметрыОбновления.ДляВнешнихПользователей, + "КлючДоступаВнешнихПользователей", "КлючДоступаПользователей"); + КлючиДоступаКОбъектам = ПараметрыОбновления.МодельОбъектовВПамяти.КлючиДоступаКОбъектам; // РегистрСведенийНаборЗаписей + Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл + НоваяСтрока = КлючиДоступаКОбъектам.Добавить(); + НоваяСтрока.Объект = ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка; + НоваяСтрока[ИмяПоляКлюча] = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + КонецЦикла; + Иначе + ЗаписатьКлючиДоступаОбъектов(ПараметрыОбновления, Контекст); + КонецЕсли; + Иначе + ЗаписатьКлючиДоступаРегистров(ПараметрыОбновления, Контекст); + КонецЕсли; + + // Принудительное обновление прав вручную. + Если ПараметрыОбновления.Свойство("ОбновитьПраваНаКлючи") + И ПараметрыОбновления.ОбновитьПраваНаКлючи Тогда + + СуществующиеКлючиДоступа = Новый Массив; + Для Каждого ОписаниеКлюча Из ТребуемыеКлючиДоступа Цикл + Если ОписаниеНовыхКлючей.Найти(ОписаниеКлюча) <> Неопределено Тогда + Продолжить; + КонецЕсли; + СуществующиеКлючиДоступа.Добавить(ОписаниеКлюча.КлючДоступа); + КонецЦикла; + Если СуществующиеКлючиДоступа.Количество() > 0 Тогда + ОбновитьПраваНаКлючиДоступа(СуществующиеКлючиДоступа, ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка. +Процедура ОбновитьПраваНаКлючиДоступа(ОписаниеКлючей, ПараметрыОбновления, ЭтоНовыеКлючи = Ложь, Контекст = Неопределено) + + Если ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") Тогда + КоличествоОбработанных = ПараметрыОбновления.КоличествоОбработанныхЭлементов; + ПараметрыОбновления.КоличествоОбработанныхЭлементов = 0; + КонецЕсли; + + Если ЭтоНовыеКлючи Тогда + КлючиДоступа = Новый ТаблицаЗначений; + КлючиДоступа.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); + + ЗапросЗначенийКлючей = Новый Запрос; + ЗапросЗначенийКлючей.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения; + ЗапросЗначенийКлючей.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + УстановитьУточнениеПланаЗапроса(ЗапросЗначенийКлючей.Текст); + + ЗапросСуществованияКлючей = Новый Запрос; + ЗапросСуществованияКлючей.Текст = ПараметрыОбновления.ТекстЗапросаСуществованияКлючейДляСравнения; + ЗапросСуществованияКлючей.УстановитьПараметр("Список", ПараметрыОбновления.ИдентификаторСписка); + УстановитьУточнениеПланаЗапроса(ЗапросСуществованияКлючей.Текст); + + ОписаниеНовыхКлючей = Новый Структура; + ОписаниеНовыхКлючей.Вставить("ОписаниеКлючей", ОписаниеКлючей); + ОписаниеНовыхКлючей.Вставить("КлючиДоступа", КлючиДоступа); + ОписаниеНовыхКлючей.Вставить("ЗначенияТаблиц", Новый Структура); + ОписаниеНовыхКлючей.Вставить("ОписанияКлючейПоСсылке", Новый Соответствие); + ОписаниеНовыхКлючей.Вставить("ЗапросЗначенийКлючей", ЗапросЗначенийКлючей); + ОписаниеНовыхКлючей.Вставить("ЗапросСуществованияКлючей", ЗапросСуществованияКлючей); + + ДопустимыеТипыЗначений = УправлениеДоступомСлужебныйПовтИсп.ДопустимыеТипыЗначенийКлючейДоступа(); + ЗначенияТаблиц = ОписаниеНовыхКлючей.ЗначенияТаблиц; + + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + ТаблицаЗначений = ЗначенияТаблицыКлюча(); + ТаблицаЗначений.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); + ПоляТаблицы = ПараметрыОбновления.РеквизитыТаблицКлюча.Получить(ТаблицаКлюча); + Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") И ТаблицаКлюча <> "Шапка0" Тогда + ТаблицаЗначений.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число")); + КонецЕсли; + Для Каждого Поле Из ПоляТаблицы Цикл + ТаблицаЗначений.Колонки.Добавить(Поле, ДопустимыеТипыЗначений); + КонецЦикла; + ЗначенияТаблиц.Вставить(ТаблицаКлюча, ТаблицаЗначений); + КонецЦикла; + + Для Каждого ОписаниеКлюча Из ОписаниеКлючей Цикл + ПроверитьТипЗначенийКлючаДоступа(ОписаниеКлюча, ДопустимыеТипыЗначений, ПараметрыОбновления); + ПодготовитьНовыйКлючДоступа(ОписаниеКлюча, ОписаниеНовыхКлючей, ПараметрыОбновления); + КонецЦикла; + ОписаниеКлючейДоступа = ОписаниеНовыхКлючей; + Иначе + ОписаниеКлючейДоступа = Новый ТаблицаЗначений; + ОписаниеКлючейДоступа.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("СправочникСсылка.КлючиДоступа")); + Для Каждого КлючДоступаСсылка Из ОписаниеКлючей Цикл + ОписаниеКлючейДоступа.Добавить().Ссылка = КлючДоступаСсылка; + КонецЦикла; + КонецЕсли; + + ОбновитьПраваПорцииКлючейДоступаСписка(ОписаниеКлючейДоступа, ПараметрыОбновления, ЭтоНовыеКлючи); + + Если ПараметрыОбновления.Свойство("КоличествоОбработанныхЭлементов") Тогда + ПараметрыОбновления.КоличествоОбработанныхЭлементов = КоличествоОбработанных; + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Ссылка - СправочникСсылка.КлючиДоступа +// * НомерСтроки - Число - номер строки табличной части +// +Функция ЗначенияТаблицыКлюча() + + Возврат Новый ТаблицаЗначений; + +КонецФункции + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанныхСписка. +Функция СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча) + + Если ОписаниеКлючейЗначений = Неопределено Тогда + ОписаниеКлючейЗначений = Новый Структура( + "КлючиЗначений, ИменаТаблиц, ЗначенияКолонокТаблиц", + Новый Массив, Новый Массив, Новый Массив); + КонецЕсли; + + КлючиЗначений = ОписаниеКлючейЗначений.КлючиЗначений; + ИменаТаблиц = ОписаниеКлючейЗначений.ИменаТаблиц; + + Если ИменаТаблиц.Количество() <> ТаблицыКлюча.Количество() Тогда + // В ключе доступа используются табличные части и некоторые пустые. + Для Индекс = 0 По ТаблицыКлюча.Количество() - 1 Цикл + + Если Индекс >= ИменаТаблиц.Количество() + Или ИменаТаблиц[Индекс] <> ТаблицыКлюча[Индекс] Тогда + + ИменаТаблиц.Вставить(Индекс, ТаблицыКлюча[Индекс]); + КлючиЗначений.Вставить(Индекс, "6ab8db6a-4878-483a-b9d5-ef905ff1537e"); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат СтрСоединить(КлючиЗначений); + +КонецФункции + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ЗаписатьКлючиДоступаОбъектов(ПараметрыОбновления, Контекст) + + ЗаписыватьТолькоИзмененные = ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных(); + + Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей + Или ЗаписыватьТолькоИзмененные Тогда + + ЗапросТекущихКлючей = Новый Запрос; + ЗапросТекущихКлючей.Текст = + "ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК Объект, + | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, + | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | КлючиДоступаКОбъектам.Объект В (&СсылкиНаОбъекты)"; + ЗапросТекущихКлючей.УстановитьПараметр("СсылкиНаОбъекты", Контекст.СсылкиНаОбъекты); + КонецЕсли; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ИмяРеквизитаСохраняемогоКлюча = "КлючДоступаПользователей"; + ИмяРеквизитаОбновляемогоКлюча = "КлючДоступаВнешнихПользователей"; + Иначе + ИмяРеквизитаСохраняемогоКлюча = "КлючДоступаВнешнихПользователей"; + ИмяРеквизитаОбновляемогоКлюча = "КлючДоступаПользователей"; + КонецЕсли; + + ОбъектТип = Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект.Тип; + Если Не ОбъектТип.СодержитТип(ТипЗнч(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка)) Тогда + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно обновить ключ доступа объекта ""%1"" типа ""%2"", + |так как тип ""%3"" не указан в определяемом типе ""%4"".'"), + Строка(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка), + Строка(ТипЗнч(Контекст.ОписаниеКлючейДоступаОбъектов[0].ТекущаяСсылка)), + ИмяТипаСсылки(ПараметрыОбновления.Список, ТипыТаблицПоИменам), + "ВладелецЗначенийКлючейДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если ЗаписыватьТолькоИзмененные Тогда + ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); + ТекущиеКлючиДоБлокировки = ЗапросТекущихКлючей.Выполнить().Выгрузить(); + ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); + КонецЕсли; + + КоличествоОбработанных = 0; + ОписаниеКлючейДоступаОбъектов = Новый Массив; + + Блокировка = Новый БлокировкаДанных; + Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл + КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + Если КлючДоступа = Неопределено Тогда + Прервать; + КонецЕсли; + Если ЗаписыватьТолькоИзмененные Тогда + Строка = ТекущиеКлючиДоБлокировки.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "Объект"); + Если Строка <> Неопределено И Строка[ИмяРеквизитаОбновляемогоКлюча] = КлючДоступа Тогда + КоличествоОбработанных = КоличествоОбработанных + 1; + Продолжить; + КонецЕсли; + КонецЕсли; + ОписаниеКлючейДоступаОбъектов.Добавить(ОписаниеКлючаДоступаОбъекта); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаКОбъектам"); + ЭлементБлокировки.УстановитьЗначение("Объект", ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); + КонецЦикла; + + Если ОписаниеКлючейДоступаОбъектов.Количество() = 0 Тогда + ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных); + Возврат; + КонецЕсли; + + СпискиДляОбновления = Новый Структура("ИменаСписков, ДляВнешнихПользователей", + ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа, + ПараметрыОбновления.ДляВнешнихПользователей); + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, + ПараметрыОбновления.ИдентификаторТранзакции, "ЗаполнитьКэшПараметровОграниченияДоступа"); + КонецЕсли; + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + ПакетныйРежим = РежимСлияния <> Неопределено; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаКОбъектам); + Если Не ПакетныйРежим Тогда + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + + НачатьТранзакцию(); + Попытка + ПередБлокировкойДанных(ПараметрыОбновления); + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + Блокировка.Заблокировать(); + ПослеБлокировкиДанных(ПараметрыОбновления); + + Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей Тогда + ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); + ТекущиеКлючи = ЗапросТекущихКлючей.Выполнить().Выгрузить(); + ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); + КонецЕсли; + + ПередЗаписьюСтрок(ПараметрыОбновления); + СсылкиНаОбъекты = Новый Массив; + Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл + СсылкиНаОбъекты.Добавить(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.Объект.Установить(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка); + Иначе + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + Запись.Объект = ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка; + Запись[ИмяРеквизитаОбновляемогоКлюча] = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + + Если ПараметрыОбновления.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей Тогда + Строка = ТекущиеКлючи.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "Объект"); + Если Строка <> Неопределено Тогда + Запись[ИмяРеквизитаСохраняемогоКлюча] = Строка[ИмяРеквизитаСохраняемогоКлюча]; + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + ПослеЗаписиСтрок(ПараметрыОбновления, ОписаниеКлючейДоступаОбъектов.Количество()); + + ПередПланированиемОбновления(ПараметрыОбновления); + ЗапланироватьОбновлениеУстаревшихКлючейДоступа(СпискиДляОбновления, + ПараметрыОбновления.ИдентификаторТранзакции, + "ЗаписатьКлючиДоступаОбъектов", + ?(СсылкиНаОбъекты.Количество() > 25, Неопределено, + Новый Структура("ПоКлючамДоступа", СсылкиНаОбъекты)), + ПараметрыОбновления.Свойство("ЭтоФоновоеОбновлениеДоступа")); + ПослеПланированияОбновления(ПараметрыОбновления); + + // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, + // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), + // а в режиме анализа производительности последствия учитываются и не являются критичными. + ПередФиксациейТранзакции(ПараметрыОбновления); + ЗафиксироватьТранзакцию(); + ПослеФиксацииТранзакции(ПараметрыОбновления); + // АПК:330-вкл. + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + КоличествоОбработанных = КоличествоОбработанных + ОписаниеКлючейДоступаОбъектов.Количество(); + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Возврат; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ЗаписатьКлючиДоступаРегистров(ПараметрыОбновления, Контекст) + + ПорцияЭлементовДанных = Контекст.ПорцияЭлементовДанных; + + ЗаписыватьТолькоИзмененные = ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных(); + Если ЗаписыватьТолькоИзмененные Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ИдентификаторРегистра", ПараметрыОбновления.ИдентификаторСписка); + ТекстЗапроса = ПараметрыОбновления.ТекстЗапросаТекущихКлючейДоступаРегистра; + ТекстыПакета = Новый Массив; + НомерСтроки = 1; + Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл + ТекущийНомер = "_" + Формат(НомерСтроки, "ЧГ="); + ТекстыПакета.Добавить(СтрЗаменить(ТекстЗапроса, "_%1", ТекущийНомер)); + Для НомерПоля = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); + Запрос.УстановитьПараметр(ИмяПоля + ТекущийНомер, ЭлементДанных[ИмяПоля]); + КонецЦикла; + НомерСтроки = НомерСтроки + 1; + КонецЦикла; + Запрос.Текст = СтрСоединить(ТекстыПакета, ОбщегоНазначения.РазделительПакетаЗапросов()); + ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления); + Если ТекстыПакета.Количество() > 1 Тогда + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Иначе + РезультатыЗапроса = Новый Массив; + РезультатыЗапроса.Добавить(Запрос.Выполнить()); + КонецЕсли; + ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; + Иначе + ИмяРегистраКлючей = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; + КонецЕсли; + + КоличествоОбработанных = 0; + ОписаниеКлючейДоступаОбъектов = Новый Массив; + + ИндексРезультата = -1; + Блокировка = Новый БлокировкаДанных; + Для Каждого ОписаниеКлючаДоступаОбъекта Из Контекст.ОписаниеКлючейДоступаОбъектов Цикл + ИндексРезультата = ИндексРезультата + 1; + КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + Если КлючДоступа = Неопределено Тогда + Прервать; + КонецЕсли; + Если ЗаписыватьТолькоИзмененные Тогда + РезультатЗапроса = РезультатыЗапроса[ИндексРезультата]; + Если Не РезультатЗапроса.Пустой() Тогда + Выгрузка = РезультатЗапроса.Выгрузить(); + Если Выгрузка.Количество() = 1 И Выгрузка[0].КлючДоступа = КлючДоступа Тогда + КоличествоОбработанных = КоличествоОбработанных + 1; + Продолжить; + КонецЕсли; + КонецЕсли; + КонецЕсли; + ОписаниеКлючейДоступаОбъектов.Добавить(ОписаниеКлючаДоступаОбъекта); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраКлючей); + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ЭлементБлокировки.УстановитьЗначение("Регистр", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + ЭлементБлокировки.УстановитьЗначение("ВариантДоступа", ПараметрыОбновления.ВариантДоступа); + ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); + Для НомерПоля = 1 По ПараметрыОбновления.ОпорныеПоля.Используемые.Количество() Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементБлокировки.УстановитьЗначение(ИмяПоля, ЭлементДанных[ИмяПоля]); + КонецЦикла; + КонецЦикла; + + Если ОписаниеКлючейДоступаОбъектов.Количество() = 0 Тогда + ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных); + Возврат; + КонецЕсли; + + ПустыеЗначенияОпорныхПолей = УправлениеДоступомСлужебныйПовтИсп.ПустыеЗначенияОпорныхПолей( + ПараметрыОбновления.ОпорныеПоля.МаксимальноеКоличество); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + ПакетныйРежим = РежимСлияния <> Неопределено; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраКлючей]); + Если Не ПакетныйРежим Тогда + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + + Если Не ПакетныйРежим Тогда + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + НаборЗаписей.Отбор.Регистр.Установить(ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + НаборЗаписей.Отбор.ВариантДоступа.Установить(ПараметрыОбновления.ВариантДоступа); + КонецЕсли; + КоличествоИспользуемыхПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); + + НачатьТранзакцию(); + Попытка + ПередБлокировкойДанных(ПараметрыОбновления); + Блокировка.Заблокировать(); + ПослеБлокировкиДанных(ПараметрыОбновления); + + ПередЗаписьюСтрок(ПараметрыОбновления); + Для Каждого ОписаниеКлючаДоступаОбъекта Из ОписаниеКлючейДоступаОбъектов Цикл + Если ПакетныйРежим Тогда + Запись = НаборЗаписей.Добавить(); + КонецЕсли; + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + Запись.Регистр = ПараметрыОбновления.ИдентификаторСписка; + КонецЕсли; + Запись.ВариантДоступа = ПараметрыОбновления.ВариантДоступа; + + ЭлементДанных = ПорцияЭлементовДанных.Найти(ОписаниеКлючаДоступаОбъекта.ТекущаяСсылка, "ТекущаяСсылка"); + ЗаполнитьЗначенияСвойств(Запись, ПустыеЗначенияОпорныхПолей); + Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоля]; // ЭлементОтбора + Если ЭлементДанных[ИмяПоля] = Неопределено Тогда + ЭлементОтбора.Значение = Неопределено; + ЭлементОтбора.Использование = Истина; + Иначе + ЭлементОтбора.Установить(ЭлементДанных[ИмяПоля]); + КонецЕсли; + КонецЕсли; + Запись[ИмяПоля] = ЭлементДанных[ИмяПоля]; + КонецЦикла; + + Запись.КлючДоступа = ОписаниеКлючаДоступаОбъекта.СвойстваКлюча.КлючДоступа; + Если Не ПакетныйРежим Тогда + НаборЗаписей.Записать(); + КонецЕсли; + КонецЦикла; + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + ПослеЗаписиСтрок(ПараметрыОбновления, ОписаниеКлючейДоступаОбъектов.Количество()); + + // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, + // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), + // а в режиме анализа производительности последствия учитываются и не являются критичными. + ПередФиксациейТранзакции(ПараметрыОбновления); + ЗафиксироватьТранзакцию(); + ПослеФиксацииТранзакции(ПараметрыОбновления); + // АПК:330-вкл. + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + КоличествоОбработанных = КоличествоОбработанных + ОписаниеКлючейДоступаОбъектов.Количество(); + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, КоличествоОбработанных) Тогда + Возврат; + КонецЕсли; + +КонецПроцедуры + +// Для функции ОбновитьЭлементыДанныхСпискаСУстаревшимиКлючами. +Процедура УдалитьНекорректныеКомбинацииЗначенийОпорныхПолей(ПорцияЭлементовДанных, ПараметрыОбновления) + + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; + Иначе + ИмяРегистраКлючей = ПараметрыОбновления.ИмяОтдельногоРегистраКлючей; + КонецЕсли; + НаборИзОднойЗаписи = СлужебныйНаборЗаписей(РегистрыСведений[ИмяРегистраКлючей]); + КоличествоИспользуемыхПолей = ПараметрыОбновления.ОпорныеПоля.Используемые.Количество(); + + Блокировка = Новый БлокировкаДанных; + Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений." + ИмяРегистраКлючей); + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + ЭлементБлокировки.УстановитьЗначение("Регистр", ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + ЭлементБлокировки.УстановитьЗначение("ВариантДоступа", ПараметрыОбновления.ВариантДоступа); + Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементБлокировки.УстановитьЗначение(ИмяПоля, ЭлементДанных[ИмяПоля]); + КонецЦикла; + КонецЦикла; + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Для Каждого ЭлементДанных Из ПорцияЭлементовДанных Цикл + Если Не ЗначениеЗаполнено(ПараметрыОбновления.ИмяОтдельногоРегистраКлючей) Тогда + НаборИзОднойЗаписи.Отбор.Регистр.Установить(ПараметрыОбновления.ИдентификаторСписка); + КонецЕсли; + НаборИзОднойЗаписи.Отбор.ВариантДоступа.Установить(ПараметрыОбновления.ВариантДоступа); + Для НомерПоля = 1 По КоличествоИспользуемыхПолей Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ЭлементОтбора = НаборИзОднойЗаписи.Отбор[ИмяПоля]; // ЭлементОтбора + Если ЭлементДанных[ИмяПоля] = Неопределено Тогда + ЭлементОтбора.Значение = Неопределено; + ЭлементОтбора.Использование = Истина; + Иначе + ЭлементОтбора.Установить(ЭлементДанных[ИмяПоля]); + КонецЕсли; + КонецЦикла; + НаборИзОднойЗаписи.Записать(); + КонецЦикла; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Функция КлючиЗначенийСтрокОбъектов(РезультатыЗапроса, Индекс, ТаблицыКлюча, ЗначенияСтрокТаблиц = Неопределено) + + КлючиЗначенийСтрокОбъектов = Новый Соответствие; + + Если ЗначенияСтрокТаблиц = Неопределено Тогда + ЗначенияСтрокТаблиц = Новый Соответствие; + КонецЕсли; + + Для Каждого ИмяТаблицыКлючаДоступа Из ТаблицыКлюча Цикл + ЗначенияСтрокТаблицы = ЗначенияСтрокТаблиц.Получить(ИмяТаблицыКлючаДоступа); + Если ЗначенияСтрокТаблицы = Неопределено Тогда + ЗначенияСтрокТаблицы = Новый Соответствие; + ЗначенияСтрокТаблиц.Вставить(ИмяТаблицыКлючаДоступа, ЗначенияСтрокТаблицы); + КонецЕсли; + Дерево = РезультатыЗапроса[Индекс].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Индекс = Индекс + 1; + Для Каждого Строка Из Дерево.Строки Цикл + ЗначенияКолонокТаблицы = Новый Массив; + Для Каждого Колонка Из Дерево.Колонки Цикл + Если СтрНачинаетсяС(Колонка.Имя, "Значение") Тогда + ЗначенияКолонокТаблицы.Добавить(Строка.Строки.ВыгрузитьКолонку(Колонка.Имя)); + КонецЕсли; + КонецЦикла; + КлючЗначенийСтрок = СтрокаДанныхДляХеширования(ЗначенияКолонокТаблицы); + Если ЗначенияСтрокТаблицы.Получить(КлючЗначенийСтрок) = Неопределено Тогда + ЗначенияСтрокТаблицы.Вставить(КлючЗначенийСтрок, Строка.Строки); + КонецЕсли; + ОписаниеКлючейЗначений = КлючиЗначенийСтрокОбъектов.Получить(Строка.ТекущаяСсылка); + Если ОписаниеКлючейЗначений = Неопределено Тогда + ОписаниеКлючейЗначений = Новый Структура( + "КлючиЗначений, ИменаТаблиц, ЗначенияКолонокТаблиц", + Новый Массив, Новый Массив, Новый Массив); + КлючиЗначенийСтрокОбъектов.Вставить(Строка.ТекущаяСсылка, ОписаниеКлючейЗначений); + КонецЕсли; + ОписаниеКлючейЗначений.ИменаТаблиц.Добавить(ИмяТаблицыКлючаДоступа); + ОписаниеКлючейЗначений.КлючиЗначений.Добавить(КлючЗначенийСтрок); + ОписаниеКлючейЗначений.ЗначенияКолонокТаблиц.Добавить(ЗначенияКолонокТаблицы); + КонецЦикла; + КонецЦикла; + + Возврат КлючиЗначенийСтрокОбъектов; + +КонецФункции + +// Для функции КлючиЗначенийСтрокОбъектов и др. +Функция СтрокаДанныхДляХеширования(Данные) + + // Возвращает строку данных для последующего хеширования, например, + // строковое описание ссылок, сохраняемых в базе данных, с учетом типов + // по внутренним идентификаторам, что обеспечивает неизменность хеш-суммы + // при изменении имен таблиц и имен реквизитов, то есть обеспечивает + // соответствие хеш-суммы данных самим данным, сохраняемым в базе данных. + // + // Это позволяет избежать избыточного массового пересоздания ключей доступа с последующим + // перерасчетом пользователей и групп доступа для пересозданных ключей доступа. + + Возврат ЗначениеВСтрокуВнутр(Данные); + +КонецФункции + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ПроверитьТипЗначенийКлючаДоступа(ОписаниеКлюча, ДопустимыеТипыЗначений, ПараметрыОбновления) + + ЗначенияКолонокТаблиц = ОписаниеКлюча.ЗначенияКолонокТаблиц; + + Для Каждого ЗначенияКолонокТаблицы Из ЗначенияКолонокТаблиц Цикл + Для Каждого ЗначенияКолонкиТаблицы Из ЗначенияКолонокТаблицы Цикл + Для Каждого Значение Из ЗначенияКолонкиТаблицы Цикл + Если Не ДопустимыеТипыЗначений.СодержитТип(ТипЗнч(Значение)) Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Невозможно сохранить значение ""%1"" типа ""%2"" + |при обновлении ключей доступа списка ""%3"", + |так как этот тип не указан в определяемом типе %4.'"), + Строка(Значение), + Строка(ТипЗнч(Значение)), + ПараметрыОбновления.Список, + "ЗначениеДоступа"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЦикла; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьКлючиДоступаПорцииЭлементовДанных. +Процедура ПодготовитьНовыйКлючДоступа(ОписаниеКлюча, ОписаниеНовыхКлючей, ПараметрыОбновления) + + НоваяСсылка = Справочники.КлючиДоступа.ПолучитьСсылку(); + НовыйКлюч = СлужебныйЭлемент(Справочники.КлючиДоступа); // СправочникОбъект.КлючиДоступа + + НовыйКлюч.УстановитьСсылкуНового(НоваяСсылка); + НовыйКлюч.Наименование = Строка(НоваяСсылка.УникальныйИдентификатор()); + НовыйКлюч.Список = ПараметрыОбновления.ИдентификаторСписка; + НовыйКлюч.СоставПолей = ПараметрыОбновления.СоставПолей; + НовыйКлюч.ДляВнешнихПользователей = ПараметрыОбновления.ДляВнешнихПользователей; + НовыйКлюч.Хеш = ОписаниеКлюча.Хеш; + + ВсеЗначенияТаблиц = ОписаниеНовыхКлючей.ЗначенияТаблиц; + + Для Каждого ЗначенияТаблицы Из ОписаниеКлюча.ЗначенияТаблиц Цикл + ВсеЗначенияТаблицы = ВсеЗначенияТаблиц[ЗначенияТаблицы.ИмяТаблицы]; // См. ЗначенияТаблицыКлюча + + Если СтрНачинаетсяС(ЗначенияТаблицы.ИмяТаблицы, "Шапка") Тогда + НоваяСтрока = ВсеЗначенияТаблицы.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, ЗначенияТаблицы.Таблица[0]); + НоваяСтрока.Ссылка = НоваяСсылка; + + Если СтрЗаканчиваетсяНа(ЗначенияТаблицы.ИмяТаблицы, "0") Тогда + ЗаполнитьЗначенияСвойств(НовыйКлюч, ЗначенияТаблицы.Таблица[0],, "Родитель"); + Иначе + НомерСтроки = Число(Прав(ЗначенияТаблицы.ИмяТаблицы, 1)); + НовыйКлюч.Шапка.Добавить(); + ЗаполнитьЗначенияСвойств(НовыйКлюч.Шапка[НомерСтроки - 1], ЗначенияТаблицы.Таблица[0]); + НоваяСтрока.НомерСтроки = НомерСтроки; + КонецЕсли; + Иначе + Для Каждого Строка Из ЗначенияТаблицы.Таблица Цикл + ТабличнаяЧастьКлюча = НовыйКлюч[ЗначенияТаблицы.ИмяТаблицы]; // ТабличнаяЧасть + ЗаполнитьЗначенияСвойств(ТабличнаяЧастьКлюча.Добавить(), Строка); + НоваяСтрока = ВсеЗначенияТаблицы.Добавить(); + ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); + НоваяСтрока.Ссылка = НоваяСсылка; + КонецЦикла; + КонецЕсли; + КонецЦикла; + + ОписаниеКлюча.Вставить("КлючДоступаОбъект", НовыйКлюч); + ОписаниеНовыхКлючей.КлючиДоступа.Добавить().Ссылка = НоваяСсылка; + ОписаниеНовыхКлючей.ОписанияКлючейПоСсылке.Вставить(НоваяСсылка, ОписаниеКлюча); + +КонецПроцедуры + +// Для процедур ОбновитьПорциюЭлементов, ОбновитьПраваНаКлючиДоступа. +Процедура ОбновитьПраваПорцииКлючейДоступаСписка(ОписаниеКлючейДоступа, ПараметрыОбновления, ЭтоНовыеКлючи = Ложь) + + Если Не ПараметрыОбновления.Свойство("Кэш") Тогда + ПараметрыОбновления.Вставить("Кэш", Новый Структура); + КонецЕсли; + КлючиДоступа = ?(ЭтоНовыеКлючи, ОписаниеКлючейДоступа.КлючиДоступа, ОписаниеКлючейДоступа); + + Если ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) Тогда + Запрос = Новый Запрос; + Запрос.Текст = ПараметрыОбновления.ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав; + НомерТаблицы = 0; + + Если ЭтоНовыеКлючи Тогда + ТекстыЗапроса = Новый Массив; + РеквизитыТаблицКлюча = ПараметрыОбновления.РеквизитыТаблицКлюча; + Шаблон = + "ВЫБРАТЬ + | &Поля + |ПОМЕСТИТЬ Таблица + |ИЗ + | &Таблица КАК Таблица"; + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + ПолеНомерСтроки = ""; + Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") Тогда + Если СтрЗаканчиваетсяНа(ТаблицаКлюча, "0") Тогда + ИмяВременнойТаблицы = "СправочникКлючиДоступа"; + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "@Справочник.КлючиДоступа ", ИмяВременнойТаблицы + " "); + Иначе + ИмяВременнойТаблицы = "СправочникКлючиДоступа" + ТаблицаКлюча; + ПолеНомерСтроки = "НомерСтроки, "; // @query-part-1 + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "@Справочник.КлючиДоступа.Шапка КАК " + ТаблицаКлюча, + ИмяВременнойТаблицы + " КАК " + ТаблицаКлюча); // @query-part-1, @query-part-2 + КонецЕсли; + Иначе + ИмяВременнойТаблицы = "СправочникКлючиДоступа" + ТаблицаКлюча; + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "@Справочник.КлючиДоступа." + ТаблицаКлюча, ИмяВременнойТаблицы); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(Шаблон, "Таблица", ИмяВременнойТаблицы); + РеквизитыТаблицы = РеквизитыТаблицКлюча.Получить(ТаблицаКлюча); + Поля = "Ссылка, " + ПолеНомерСтроки + СтрСоединить(РеквизитыТаблицы, ", "); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Поля", Поля); + ТекстыЗапроса.Добавить(ТекстЗапроса); + Запрос.УстановитьПараметр(ИмяВременнойТаблицы, ОписаниеКлючейДоступа.ЗначенияТаблиц[ТаблицаКлюча]); + НомерТаблицы = НомерТаблицы + 1; + КонецЦикла; + ТекстыЗапроса.Добавить(Запрос.Текст); + Запрос.Текст = СтрСоединить(ТекстыЗапроса, ОбщегоНазначения.РазделительПакетаЗапросов()); + Иначе + Запрос.Текст = СтрЗаменить(Запрос.Текст, "@Справочник.КлючиДоступа", "Справочник.КлючиДоступа"); + КонецЕсли; + Запрос.УстановитьПараметр("КлючиДоступа", КлючиДоступа); + + Запрос.УстановитьПараметр("ИдентификаторТаблицыНастроекПрав", + ПараметрыОбновления.ИдентификаторТаблицыНастроекПрав); + + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + УстановитьУточнениеПланаЗапроса(Запрос.Текст); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Иначе + РезультатыЗапроса = Новый Массив; + КонецЕсли; + + ПараметрыОбновления.Вставить("ТипПользователя", ?(ПараметрыОбновления.ДляВнешнихПользователей, + Тип("СправочникСсылка.ВнешниеПользователи"), Тип("СправочникСсылка.Пользователи"))); + + ПараметрыОбновления.Вставить("ТипГруппыПользователей", ?(ПараметрыОбновления.ДляВнешнихПользователей, + Тип("СправочникСсылка.ГруппыВнешнихПользователей"), Тип("СправочникСсылка.ГруппыПользователей"))); + + ПараметрыОбновления.Вставить("ТипГруппыДоступа", Тип("СправочникСсылка.ГруппыДоступа")); + ПараметрыОбновления.Вставить("ПустаяГруппаДоступа", Справочники.ГруппыДоступа.ПустаяСсылка()); + + ЗначенияТаблицКлючей = НовыеЗначенияТаблицКлючей(); + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + НомерТаблицы = НомерТаблицы + 1; + ЗначенияТаблицКлючей.Вставить(ТаблицаКлюча, + РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам)); + КонецЦикла; + ЗаполнитьПраваНаВедущиеКлючиДоступаИВедущиеСписки(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления); + ЗаполнитьПраваПоВладельцамНастроекПрав(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления); + + КэшРасчетаПрав = КэшРасчетаПравДляВидаПользователей(ПараметрыОбновления.ДляВнешнихПользователей); + Если Не ПараметрыОбновления.Кэш.Свойство("ПраваРолейФункцииПравоДоступа") + Или КэшРасчетаПрав.РолиПрофилейГруппДоступа = Неопределено Тогда + ПараметрыОбновления.Кэш.Вставить("ПраваРолейФункцииПравоДоступа", Новый Соответствие); + ПараметрыОбновления.Кэш.Вставить("ОбъектыМетаданныхФункцииПравоДоступа", Новый Соответствие); + ПараметрыОбновления.Кэш.Вставить("ПраваПрофилейФункцииПравоДоступа", Новый Соответствие); + КонецЕсли; + + ЗаполнитьПраваГруппДоступаСписка(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьЗначенияГруппДоступаДляРасчетаПрав(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьПользователейГруппПользователей(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьУчастниковГруппДоступаСписка(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьГруппыПользователейКакЗначенияДоступа(ПараметрыОбновления, КэшРасчетаПрав); + ЗаполнитьРолиИГруппыДоступаПрофилей(ПараметрыОбновления, КэшРасчетаПрав); + + ЗначенияПервойТаблицы = ?(ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей), + ЗначенияТаблицКлючей.Получить(ПараметрыОбновления.ТаблицыКлюча[0]), + Новый Структура("Строки", КлючиДоступа)); + ИндексПоследнегоКлюча = ЗначенияПервойТаблицы.Строки.Количество() - 1; + + Для ИндексКлюча = 0 По ИндексПоследнегоКлюча Цикл + ЗначенияТаблицКлюча = НовыеЗначенияТаблицКлюча(); + Для Каждого ТаблицаКлюча Из ПараметрыОбновления.ТаблицыКлюча Цикл + ЗначенияТаблицы = ЗначенияТаблицКлючей.Получить(ТаблицаКлюча).Строки[ИндексКлюча].Строки; + Если СтрНачинаетсяС(ТаблицаКлюча, "Шапка") Тогда + ЗначенияТаблицы = ЗначенияТаблицы[0]; + КонецЕсли; + ЗначенияТаблицКлюча.Вставить(ТаблицаКлюча, ЗначенияТаблицы); + КонецЦикла; + СтрокаЗначений = ЗначенияПервойТаблицы.Строки[ИндексКлюча]; // СправочникОбъект.КлючиДоступа + КлючДоступа = СтрокаЗначений.Ссылка; + + ПраваНаКлюч = ПраваНаКлючДоступаСписка(ЗначенияТаблицКлюча, ПараметрыОбновления); + // @skip-check query-in-loop - Порционная обработка данных + ОбновитьПраваНаКлючДоступаСписка(КлючДоступа, ПраваНаКлюч, + ?(ЭтоНовыеКлючи, ОписаниеКлючейДоступа, Неопределено), ПараметрыОбновления); + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура из КлючИЗначение: +// * Ключ - Строка - имя таблицы ключа +// * Значение - ДеревоЗначений +// +Функция НовыеЗначенияТаблицКлючей() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// Структура из КлючИЗначение: +// * Ключ - Строка - имя таблицы ключа +// * Значение - см. НовыеЗначенияТаблицыКлюча +// +Функция НовыеЗначенияТаблицКлюча() + Возврат Новый Структура; +КонецФункции + +// Возвращаемое значение: +// - КоллекцияСтрокДереваЗначений +// - ТаблицаЗначений +// - СтрокаДереваЗначений +// +Функция НовыеЗначенияТаблицыКлюча() + Возврат Новый ТаблицаЗначений; +КонецФункции + +// Для процедуры ОбновитьПорциюЭлементов. +Процедура ОбработатьУстаревшиеКлючиДоступаСписка(ЭлементыДанных, ПараметрыОбновления) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + |ГДЕ + | КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК КлючиДоступаНаборовГруппДоступа + |ГДЕ + | КлючиДоступаНаборовГруппДоступа.КлючДоступа = &КлючДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей + |ГДЕ + | КлючиДоступаПользователей.КлючДоступа = &КлючДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК Поле1 + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей + |ГДЕ + | КлючиДоступаВнешнихПользователей.КлючДоступа = &КлючДоступа"; + + ЭтоОчисткаВыбранныхКлючей = ПараметрыОбновления.БезЗаписиКлючейДоступа + Или ПараметрыОбновления.СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей; + + Если Не ЭтоОчисткаВыбранныхКлючей Тогда + ЗапросИспользованияКлюча = Новый Запрос; + ЗапросИспользованияКлюча.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Ссылка = &Ссылка + | И КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1)"; + КонецЕсли; + + НаборЗаписейГруппДоступаКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); + НаборЗаписейНаборовГруппДоступаКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + НаборЗаписейПользователейКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); + НаборЗаписейВнешнихПользователейКлюча = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); + + Для Каждого Строка Из ЭлементыДанных Цикл + СтрокаЗначений = Строка; // СправочникОбъект.КлючиДоступа + Ссылка = СтрокаЗначений.Ссылка; + Если Не ЭтоОчисткаВыбранныхКлючей И Строка.Используется Тогда + ЗапросИспользованияКлюча.УстановитьПараметр("Ссылка", Ссылка); + // @skip-check query-in-loop - Порционная обработка данных + Если Не ЗапросИспользованияКлюча.Выполнить().Пустой() Тогда + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + Продолжить; + КонецЕсли; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + Если Не ЭтоОчисткаВыбранныхКлючей Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); + ЭлементБлокировки.УстановитьЗначение("Список", Строка.Список); + ЭлементБлокировки.УстановитьЗначение("Хеш", Строка.Хеш); + ЭлементБлокировки.УстановитьЗначение("СоставПолей", Строка.СоставПолей); + ЭлементБлокировки.УстановитьЗначение("ДляВнешнихПользователей", + ПараметрыОбновления.ДляВнешнихПользователей); + КонецЕсли; + ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); + ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", Ссылка); + + НачатьТранзакцию(); + Попытка + Блокировка.Заблокировать(); + Объект = СлужебныйЭлемент(Неопределено, Ссылка); + УдалитьКлюч = Ложь; + Если ЭтоОчисткаВыбранныхКлючей Или Объект = Неопределено Тогда + УдалитьКлюч = Истина; + ИначеЕсли Строка.Используется Тогда + Объект.НеИспользуетсяС = '00010101'; + ИначеЕсли Не Строка.Удалить Тогда + Объект.НеИспользуетсяС = ТекущаяДатаСеанса(); + ИначеЕсли ЗначениеЗаполнено(Объект.НеИспользуетсяС) Тогда + УдалитьКлюч = Истина; + КонецЕсли; + Если УдалитьКлюч Тогда + Запрос.УстановитьПараметр("КлючДоступа", Ссылка); + // @skip-check query-in-loop - Порционная обработка данных + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Если Не РезультатыЗапроса[0].Пустой() Тогда + НаборЗаписейГруппДоступаКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейГруппДоступаКлюча.Записать(); + КонецЕсли; + Если Не РезультатыЗапроса[1].Пустой() Тогда + НаборЗаписейНаборовГруппДоступаКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейНаборовГруппДоступаКлюча.Записать(); + КонецЕсли; + Если Не РезультатыЗапроса[2].Пустой() Тогда + НаборЗаписейПользователейКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейПользователейКлюча.Записать(); + КонецЕсли; + Если Не РезультатыЗапроса[3].Пустой() Тогда + НаборЗаписейВнешнихПользователейКлюча.Отбор.КлючДоступа.Установить(Ссылка); + НаборЗаписейВнешнихПользователейКлюча.Записать(); + КонецЕсли; + КонецЕсли; + Если Объект <> Неопределено Тогда + Если УдалитьКлюч Тогда + Объект.Удалить(); + ИначеЕсли Объект.Модифицированность() Тогда + Объект.Записать(); + КонецЕсли; + КонецЕсли; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ТребуетсяПрерватьОбработкуЭлементов(ПараметрыОбновления, 1) Тогда + Прервать; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +// +// Возвращаемое значение: +// Структура: +// * ПраваГруппДоступаСписков - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор списка +// ** Значение - см. ПраваГруппДоступаСписка +// +// * ЗначенияГруппДоступа - см. НовыеЗначенияГруппДоступа +// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа +// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей +// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа +// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа +// * РолиПрофилейГруппДоступа - см. НовыеРолиПрофилейГруппДоступа +// * ГруппыДоступаПрофилей - см. НовыеГруппыДоступаПрофилей +// +Функция КэшРасчетаПравДляВидаПользователей(ДляВнешнихПользователей) Экспорт + + КлючДанныхПовторногоИспользования = Строка(ПараметрыСеанса.КлючДанныхПовторногоИспользования); + Кэш = УправлениеДоступомСлужебныйПовтИсп.КэшРасчетаПрав(КлючДанныхПовторногоИспользования); + + ВерсияДанных = ВерсияДанныхДляКэшаРасчетаПрав(); + + Если Кэш.ВерсияДанных.ТаблицыГруппДоступа <> ВерсияДанных.ТаблицыГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "ПраваГруппДоступаСписков", Истина); + Кэш.ВерсияДанных.ТаблицыГруппДоступа = ВерсияДанных.ТаблицыГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.ЗначенияГруппДоступа <> ВерсияДанных.ЗначенияГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "ЗначенияГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыПользователейКакЗначенияДоступа"); + Кэш.ВерсияДанных.ЗначенияГруппДоступа = ВерсияДанных.ЗначенияГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.УчастникиГруппДоступа <> ВерсияДанных.УчастникиГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "УчастникиГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГрупповыеПользователиГруппДоступа"); + Кэш.ВерсияДанных.УчастникиГруппДоступа = ВерсияДанных.УчастникиГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.СоставыГруппПользователей <> ВерсияДанных.СоставыГруппПользователей Тогда + СброситьКэшРасчетаПрав(Кэш, "ПользователиГруппПользователей"); + СброситьКэшРасчетаПрав(Кэш, "УчастникиГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГрупповыеПользователиГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыПользователейКакЗначенияДоступа"); + Кэш.ВерсияДанных.СоставыГруппПользователей = ВерсияДанных.СоставыГруппПользователей; + КонецЕсли; + + Если Кэш.ВерсияДанных.РолиПрофилейГруппДоступа <> ВерсияДанных.РолиПрофилейГруппДоступа Тогда + СброситьКэшРасчетаПрав(Кэш, "РолиПрофилейГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыДоступаПрофилей"); + Кэш.ВерсияДанных.РолиПрофилейГруппДоступа = ВерсияДанных.РолиПрофилейГруппДоступа; + КонецЕсли; + + Если Кэш.ВерсияДанных.ГруппыДоступаПрофилей <> ВерсияДанных.ГруппыДоступаПрофилей Тогда + СброситьКэшРасчетаПрав(Кэш, "РолиПрофилейГруппДоступа"); + СброситьКэшРасчетаПрав(Кэш, "ГруппыДоступаПрофилей"); + Кэш.ВерсияДанных.ГруппыДоступаПрофилей = ВерсияДанных.ГруппыДоступаПрофилей; + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + Возврат Кэш.ДляВнешнихПользователей; + Иначе + Возврат Кэш.ДляПользователей; + КонецЕсли; + +КонецФункции + +// Для функции КэшРасчетаПравДляВидаПользователей. +Процедура СброситьКэшРасчетаПрав(Кэш, Свойство, НовоеСоответствие = Ложь) + + Кэш.ДляПользователей[Свойство] = ?(НовоеСоответствие, Новый Соответствие, Неопределено); + Кэш.ДляВнешнихПользователей[Свойство] = ?(НовоеСоответствие, Новый Соответствие, Неопределено); + +КонецПроцедуры + +// Для процедур ЗаполнитьПраваГруппДоступаСписка и +// ЗаполнитьУчастниковГруппДоступаСписка. +// +Функция ТекстЗапросаНазначенияПрофилей() + + Возврат + "ВЫБРАТЬ + | Профили.Ссылка КАК Профиль, + | МАКСИМУМ(ВЫБОР + | КОГДА НазначениеПрофилей.ТипПользователей ЕСТЬ NULL + | ТОГДА ИСТИНА + | ИНАЧЕ ТИПЗНАЧЕНИЯ(НазначениеПрофилей.ТипПользователей) = ТИП(Справочник.Пользователи) + | КОНЕЦ) КАК ДляПользователей, + | МАКСИМУМ(ВЫБОР + | КОГДА НазначениеПрофилей.ТипПользователей ЕСТЬ NULL + | ТОГДА ЛОЖЬ + | ИНАЧЕ НазначениеПрофилей.ТипПользователей <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(НазначениеПрофилей.ТипПользователей) <> ТИП(Справочник.Пользователи) + | КОНЕЦ) КАК ДляВнешнихПользователей + |ПОМЕСТИТЬ НазначениеПрофилей + |ИЗ + | Справочник.ПрофилиГруппДоступа КАК Профили + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Назначение КАК НазначениеПрофилей + | ПО (НазначениеПрофилей.Ссылка = Профили.Ссылка) + | + |СГРУППИРОВАТЬ ПО + | Профили.Ссылка"; + +КонецФункции + +// Параметры: +// Права - ТаблицаЗначений +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа +// * ПравоИзменение - Булево +// * ПравоДобавление - Булево +// * ПравоЧтениеБезОграничения - Булево +// * ПравоИзменениеБезОграничения - Булево +// * ПравоДобавлениеБезОграничения - Булево +// +Функция НовыеПраваГруппДоступаСписка(Права) + Возврат Права; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПраваГруппДоступаСписка(ПараметрыОбновления, Кэш) + + ИдентификаторСписка = ПараметрыОбновления.ИдентификаторСписка; + ПраваГруппДоступаСписка = Кэш.ПраваГруппДоступаСписков.Получить(ИдентификаторСписка); + Если ПраваГруппДоступаСписка <> Неопределено Тогда + ПараметрыОбновления.Вставить("ПраваГруппДоступаСписка", ПраваГруппДоступаСписка); + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("Таблица", ИдентификаторСписка); + Запрос.Текст = + "ВЫБРАТЬ + | ТаблицыГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | ТаблицыГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | ТаблицыГруппДоступа.ПравоДобавление КАК ПравоДобавление, + | ТаблицыГруппДоступа.ПравоЧтениеБезОграничения КАК ПравоЧтениеБезОграничения, + | ТаблицыГруппДоступа.ПравоИзменениеБезОграничения КАК ПравоИзменениеБезОграничения, + | ТаблицыГруппДоступа.ПравоДобавлениеБезОграничения КАК ПравоДобавлениеБезОграничения + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ТаблицыГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа + | ПО (ТаблицыГруппДоступа.Таблица = &Таблица) + | И (ГруппыДоступа.Ссылка = ТаблицыГруппДоступа.ГруппаДоступа) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НазначениеПрофилей КАК НазначениеПрофилей + | ПО (НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль) + | И (НазначениеПрофилей.ДляПользователей)"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); + КонецЕсли; + + Запрос.Текст = ТекстЗапросаНазначенияПрофилей() + + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + + ПраваГруппДоступаСписка = НовыеПраваГруппДоступаСписка(Запрос.Выполнить().Выгрузить()); + Кэш.ПраваГруппДоступаСписков.Вставить(ИдентификаторСписка, ПраваГруппДоступаСписка); + ПараметрыОбновления.Вставить("ПраваГруппДоступаСписка", ПраваГруппДоступаСписка); + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// ** Значение - Булево - Истина +// +Функция НовыеПользователиГруппПользователей() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПользователейГруппПользователей(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("ПользователиГруппПользователей", НовыеПользователиГруппПользователей()); + + Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Возврат; + КонецЕсли; + + Если Кэш.ПользователиГруппПользователей <> Неопределено Тогда + ПараметрыОбновления.ПользователиГруппПользователей = Кэш.ПользователиГруппПользователей; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, + | СоставыГруппПользователей.Пользователь КАК Пользователь + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи + | ПО (Пользователи.Ссылка = СоставыГруппПользователей.Пользователь) + | И (Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)) + | И (СоставыГруппПользователей.Используется) + |ИТОГИ ПО + | ГруппаПользователей"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + ПользователиГруппПользователей = ПараметрыОбновления.ПользователиГруппПользователей; + + РезультатЗапроса = Запрос.Выполнить(); + ЗаполнитьПользователейГрупп(ПользователиГруппПользователей, РезультатЗапроса); + + Кэш.ПользователиГруппПользователей = ПользователиГруппПользователей; + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// ** Значение - Булево - Истина +// +Функция НовыеГруппыПользователейКакЗначенияДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьГруппыПользователейКакЗначенияДоступа(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("ГруппыПользователейКакЗначенияДоступа", + НовыеГруппыПользователейКакЗначенияДоступа()); + + Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Возврат; + КонецЕсли; + + Если Кэш.ГруппыПользователейКакЗначенияДоступа <> Неопределено Тогда + ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа = Кэш.ГруппыПользователейКакЗначенияДоступа; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | СоставыГруппПользователей.ГруппаПользователей КАК ГруппаПользователей, + | СоставыГруппПользователей.Пользователь КАК Пользователь + |ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияГруппДоступа КАК ЗначенияГруппДоступа + | ПО СоставыГруппПользователей.ГруппаПользователей = ЗначенияГруппДоступа.ЗначениеДоступа + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)) + | И (ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыПользователей)) + |ИТОГИ ПО + | ГруппаПользователей"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + ГруппыПользователейКакЗначенияДоступа = ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа; + + РезультатЗапроса = Запрос.Выполнить(); + ЗаполнитьПользователейГрупп(ГруппыПользователейКакЗначенияДоступа, РезультатЗапроса); + + Кэш.ГруппыПользователейКакЗначенияДоступа = ГруппыПользователейКакЗначенияДоступа; + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыДоступа +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ВнешниеПользователи +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - Истина +// +Функция НовыеУчастникиГруппДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыДоступа +// * Значение - Соответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// ** Значение - Булево - Истина +// +Функция НовыеГрупповыеПользователиГруппДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьУчастниковГруппДоступаСписка(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("УчастникиГруппДоступа", НовыеУчастникиГруппДоступа()); + ПараметрыОбновления.Вставить("ГрупповыеПользователиГруппДоступа", НовыеГрупповыеПользователиГруппДоступа()); + + Если Не ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Возврат; + КонецЕсли; + + Если Кэш.УчастникиГруппДоступа <> Неопределено Тогда + ПараметрыОбновления.УчастникиГруппДоступа = Кэш.УчастникиГруппДоступа; + ПараметрыОбновления.ГрупповыеПользователиГруппДоступа = Кэш.ГрупповыеПользователиГруппДоступа; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ПользователиГруппыДоступа.Ссылка КАК ГруппаДоступа, + | ПользователиГруппыДоступа.Пользователь КАК Участник + |ИЗ + | Справочник.ГруппыДоступа КАК ГруппыДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НазначениеПрофилей КАК НазначениеПрофилей + | ПО (НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль) + | И (НазначениеПрофилей.ДляПользователей) + | И (НЕ ГруппыДоступа.ПометкаУдаления) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК ПользователиГруппыДоступа + | ПО (ПользователиГруппыДоступа.Ссылка = ГруппыДоступа.Ссылка) + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи + | ПО + | СоставыГруппПользователей.ГруппаПользователей = ПользователиГруппыДоступа.Пользователь + | И СоставыГруппПользователей.Используется + | И Пользователи.Ссылка = СоставыГруппПользователей.Пользователь + | И Пользователи.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор)) + |ИТОГИ ПО + | ГруппаДоступа"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "Справочник.ГруппыПользователей", "Справочник.ГруппыВнешнихПользователей"); + КонецЕсли; + + Запрос.Текст = ТекстЗапросаНазначенияПрофилей() + + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + УчастникиГруппДоступа = ПараметрыОбновления.УчастникиГруппДоступа; + ГрупповыеПользователиГруппДоступа = ПараметрыОбновления.ГрупповыеПользователиГруппДоступа; + ТипГруппыПользователей = ПараметрыОбновления.ТипГруппыПользователей; + ПользователиГруппПользователей = ПараметрыОбновления.ПользователиГруппПользователей; + + Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + + Для Каждого Строка Из Дерево.Строки Цикл + УчастникиГруппыДоступа = Новый Соответствие; + ГрупповыеПользователиГруппыДоступа = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + УчастникиГруппыДоступа.Вставить(Подстрока.Участник, Истина); + Если ТипЗнч(Подстрока.Участник) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(Подстрока.Участник); + Если ПользователиГруппы <> Неопределено Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + ГрупповыеПользователиГруппыДоступа.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если УчастникиГруппыДоступа.Количество() > 0 Тогда + УчастникиГруппДоступа.Вставить(Строка.ГруппаДоступа, УчастникиГруппыДоступа); + КонецЕсли; + Если ГрупповыеПользователиГруппыДоступа.Количество() > 0 Тогда + ГрупповыеПользователиГруппДоступа.Вставить(Строка.ГруппаДоступа, ГрупповыеПользователиГруппыДоступа); + КонецЕсли; + КонецЦикла; + + Кэш.УчастникиГруппДоступа = УчастникиГруппДоступа; + Кэш.ГрупповыеПользователиГруппДоступа = ГрупповыеПользователиГруппДоступа; + +КонецПроцедуры + +// Для процедур ЗаполнитьПользователейГруппПользователей и +// ЗаполнитьГруппыПользователейКакЗначенияДоступа. +// +Процедура ЗаполнитьПользователейГрупп(ПользователиГруппПользователей, РезультатЗапроса) + + Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ПользователиГруппыПользователей = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПользователиГруппыПользователей.Вставить(Подстрока.Пользователь, Истина); + КонецЦикла; + ПользователиГруппПользователей.Вставить(Строка.ГруппаПользователей, ПользователиГруппыПользователей); + КонецЦикла; + +КонецПроцедуры + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Тип - тип значений доступа +// * Значение - Структура: +// ** ВсеРазрешены - Булево +// ** Значения - Соответствие из КлючИЗначение: +// *** Ключ - ОпределяемыйТип.ЗначениеДоступа +// *** Значение - Булево - Истина +// +Функция НовыеЗначенияГруппыДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ГруппыДоступа +// * Значение - см. НовыеЗначенияГруппыДоступа +// +Функция НовыеЗначенияГруппДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьЗначенияГруппДоступаДляРасчетаПрав(ПараметрыОбновления, Кэш) + + Если Кэш.ЗначенияГруппДоступа <> Неопределено Тогда + ПараметрыОбновления.Вставить("ЗначенияГруппДоступа", Кэш.ЗначенияГруппДоступа); + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ЗначенияГруппДоступаПоУмолчанию.ГруппаДоступа КАК ГруппаДоступа, + | ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступаПоУмолчанию.ТипЗначенийДоступа) КАК ТипЗначенийДоступа, + | ЗначенияГруппДоступаПоУмолчанию.ВсеРазрешены КАК ВсеРазрешены + |ИЗ + | РегистрСведений.ЗначенияГруппДоступаПоУмолчанию КАК ЗначенияГруппДоступаПоУмолчанию + |ГДЕ + | НЕ ЗначенияГруппДоступаПоУмолчанию.БезНастройки + |ИТОГИ ПО + | ГруппаДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ЗначенияГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | ТИПЗНАЧЕНИЯ(ЗначенияГруппДоступа.ЗначениеДоступа) КАК ТипЗначенийДоступа, + | ЗначенияГруппДоступа.ЗначениеДоступа КАК ЗначениеДоступа + |ИЗ + | РегистрСведений.ЗначенияГруппДоступа КАК ЗначенияГруппДоступа + |ИТОГИ ПО + | ГруппаДоступа, + | ТипЗначенийДоступа"; + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + ЗначенияГруппДоступа = НовыеЗначенияГруппДоступа(); + + Дерево = РезультатыЗапроса[0].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ЗначенияГруппыДоступа = НовыеЗначенияГруппыДоступа(); + Для Каждого Подстрока Из Строка.Строки Цикл + ЗначенияОдногоТипа = Новый Структура; + ЗначенияОдногоТипа.Вставить("ВсеРазрешены", Подстрока.ВсеРазрешены); + ЗначенияОдногоТипа.Вставить("Значения", Новый Соответствие); + ЗначенияГруппыДоступа.Вставить(Подстрока.ТипЗначенийДоступа, ЗначенияОдногоТипа); + КонецЦикла; + ЗначенияГруппДоступа.Вставить(Строка.ГруппаДоступа, ЗначенияГруппыДоступа); + КонецЦикла; + + Дерево = РезультатыЗапроса[1].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ЗначенияГруппыДоступа = ЗначенияГруппДоступа.Получить(Строка.ГруппаДоступа); + Если ЗначенияГруппыДоступа = Неопределено Тогда + Продолжить; + КонецЕсли; + Для Каждого Подстрока Из Строка.Строки Цикл + ЗначенияОдногоТипа = ЗначенияГруппыДоступа.Получить(Подстрока.ТипЗначенийДоступа); + Если ЗначенияОдногоТипа = Неопределено Тогда + Продолжить; + КонецЕсли; + Значения = ЗначенияОдногоТипа.Значения; + Для Каждого ОписаниеЗначения Из Подстрока.Строки Цикл + Значения.Вставить(ОписаниеЗначения.ЗначениеДоступа, Истина); + КонецЦикла; + КонецЦикла; + КонецЦикла; + + ПараметрыОбновления.Вставить("ЗначенияГруппДоступа", ЗначенияГруппДоступа); + Кэш.ЗначенияГруппДоступа = ЗначенияГруппДоступа; + +КонецПроцедуры + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Профиль - СправочникСсылка.ПрофилиГруппДоступа +// * Роль - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// * ИмяРоли - Строка +// * ИмяРолиВерхнийРегистр - Строка +// +Функция НовыеРолиПрофилейГруппДоступа() + Возврат Новый ТаблицаЗначений; +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Профиль - СправочникСсылка.ПрофилиГруппДоступа +// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа +// +Функция НовыеГруппыДоступаПрофилей() + Возврат Новый ТаблицаЗначений; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьРолиИГруппыДоступаПрофилей(ПараметрыОбновления, Кэш) + + ПараметрыОбновления.Вставить("РолиПрофилейГруппДоступа", НовыеРолиПрофилейГруппДоступа()); + ПараметрыОбновления.Вставить("ГруппыДоступаПрофилей", НовыеГруппыДоступаПрофилей()); + + Если Не ПараметрыОбновления.ЕстьФункцияПравоДоступаИлиРольДоступна Тогда + Возврат; + КонецЕсли; + + Если Кэш.РолиПрофилейГруппДоступа <> Неопределено Тогда + ПараметрыОбновления.РолиПрофилейГруппДоступа = Кэш.РолиПрофилейГруппДоступа; + ПараметрыОбновления.ГруппыДоступаПрофилей = Кэш.ГруппыДоступаПрофилей; + Возврат; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | РолиПрофилей.Роль КАК Роль + |ИЗ + | НазначениеПрофилей КАК НазначениеПрофилей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей + | ПО (РолиПрофилей.Ссылка = НазначениеПрофилей.Профиль) + | И (НазначениеПрофилей.ДляПользователей) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | РолиПрофилей.Ссылка КАК Профиль, + | РолиПрофилей.Роль КАК Роль + |ИЗ + | НазначениеПрофилей КАК НазначениеПрофилей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей + | ПО (РолиПрофилей.Ссылка = НазначениеПрофилей.Профиль) + | И (НазначениеПрофилей.ДляПользователей) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НазначениеПрофилей.Профиль КАК Профиль, + | ГруппыДоступа.Ссылка КАК ГруппаДоступа + |ИЗ + | НазначениеПрофилей КАК НазначениеПрофилей + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа + | ПО НазначениеПрофилей.Профиль = ГруппыДоступа.Профиль + | И (НазначениеПрофилей.ДляПользователей)"; + + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "НазначениеПрофилей.ДляПользователей", "НазначениеПрофилей.ДляВнешнихПользователей"); + КонецЕсли; + + Запрос.Текст = ТекстЗапросаНазначенияПрофилей() + + ОбщегоНазначения.РазделительПакетаЗапросов() + Запрос.Текст; + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + Роли = РезультатыЗапроса[1].Выгрузить().ВыгрузитьКолонку("Роль"); + ОбъектыМетаданныхРолей = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(Роли, Ложь); + + РолиПрофилейГруппДоступа = РезультатыЗапроса[2].Выгрузить(); + ТипИмениРоли = Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.Имя.Тип; + РолиПрофилейГруппДоступа.Колонки.Добавить("ИмяРоли", ТипИмениРоли); + РолиПрофилейГруппДоступа.Колонки.Добавить("ИмяРолиВерхнийРегистр", ТипИмениРоли); + РолиПрофилейГруппДоступа.Индексы.Добавить("Роль"); + Отбор = Новый Структура("Роль"); + ТребуетсяПроверитьАктуальностьМетаданных = Ложь; + + Для Каждого ОписаниеРоли Из ОбъектыМетаданныхРолей Цикл + Если ТипЗнч(ОписаниеРоли.Значение) <> Тип("ОбъектМетаданных") Тогда + ТребуетсяПроверитьАктуальностьМетаданных = Истина; + Продолжить; + КонецЕсли; + ИмяРоли = ОписаниеРоли.Значение.Имя; + ИмяРолиВерхнийРегистр = ВРег(ИмяРоли); + Отбор.Роль = ОписаниеРоли.Ключ; + Строки = РолиПрофилейГруппДоступа.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + Строка.ИмяРоли = ИмяРоли; + Строка.ИмяРолиВерхнийРегистр = ИмяРолиВерхнийРегистр; + КонецЦикла; + КонецЦикла; + Если ТребуетсяПроверитьАктуальностьМетаданных Тогда + ПроверитьАктуальностьМетаданных(); + КонецЕсли; + РолиПрофилейГруппДоступа.Индексы.Добавить("Профиль,ИмяРолиВерхнийРегистр"); + + ГруппыДоступаПрофилей = РезультатыЗапроса[3].Выгрузить(); + ГруппыДоступаПрофилей.Индексы.Добавить("ГруппаДоступа"); + + ПараметрыОбновления.РолиПрофилейГруппДоступа = РолиПрофилейГруппДоступа; + ПараметрыОбновления.ГруппыДоступаПрофилей = ГруппыДоступаПрофилей; + Кэш.РолиПрофилейГруппДоступа = РолиПрофилейГруппДоступа; + Кэш.ГруппыДоступаПрофилей = ГруппыДоступаПрофилей; + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.КлючиДоступа +// * Значение - ФиксированнаяСтруктура: +// ** ОграничениеЧтенияОтключено - Булево +// ** ОграничениеОтключено - Булево +// ** ПоГруппамДоступа - ФиксированноеСоответствие из КлючИЗначение: +// *** Ключ - СправочникСсылка.ГруппыДоступа +// *** Значение - Булево - право изменение +// +Функция НовыеПраваНаСпискиВедущихКлючейДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.КлючиДоступа +// * Значение - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ГруппыДоступа +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - право изменение +// +Функция НовыеПраваНаВедущиеКлючиДоступа() + Возврат Новый Соответствие; +КонецФункции + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор списка +// - Тип - тип значений списка +// * Значение - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.ГруппыДоступа +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - право изменение +// +Функция НовыеПраваНаВедущиеСписки() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПраваНаВедущиеКлючиДоступаИВедущиеСписки(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления) + + ПраваНаСпискиВедущихКлючейДоступа = НовыеПраваНаСпискиВедущихКлючейДоступа(); + ПраваНаВедущиеКлючиДоступа = НовыеПраваНаВедущиеКлючиДоступа(); + Если ПараметрыОбновления.ЕстьВедущиеКлючиДоступа Тогда + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ПараметрыОбновления.ИдентификаторТранзакции, Неопределено, Ложь); + Если ПараметрыОбновления.ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + НомерТаблицы = НомерТаблицы + 1; + ПраваНаСписки = Новый Соответствие; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + ИдентификаторыСписков = Дерево.Строки.ВыгрузитьКолонку("Список"); + Если ПараметрыОбновления.Кэш.Свойство("ОбъектыМетаданныхПоИдентификаторам") Тогда + ОбъектыМетаданныхПоИдентификаторам = ПараметрыОбновления.Кэш.ОбъектыМетаданныхПоИдентификаторам; + НенайденныеИдентификаторыСписков = Новый Массив; + Для Каждого ИдентификаторСписка Из ИдентификаторыСписков Цикл + Если ОбъектыМетаданныхПоИдентификаторам.Получить(ИдентификаторСписка) = Неопределено Тогда + НенайденныеИдентификаторыСписков.Добавить(ИдентификаторСписка); + КонецЕсли; + КонецЦикла; + Результат = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( + НенайденныеИдентификаторыСписков, Ложь); + Для Каждого КлючИЗначение Из Результат Цикл + ОбъектыМетаданныхПоИдентификаторам.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Иначе + ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам( + ИдентификаторыСписков, Ложь); + КонецЕсли; + Для Каждого Строка Из Дерево.Строки Цикл + ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(Строка.Список); + Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда + Продолжить; + КонецЕсли; + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ПоГруппамДоступа = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПоГруппамДоступа.Вставить(Подстрока.ГруппаДоступа, Подстрока.ПравоИзменение); + КонецЦикла; + ПраваНаСписок = Новый Структура; + ПраваНаСписок.Вставить("ОграничениеЧтенияОтключено", + ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения.Получить(ПолноеИмя) <> Неопределено); + ПраваНаСписок.Вставить("ОграничениеОтключено", + ДополнительныйКонтекст.СпискиСОтключеннымОграничением.Получить(ПолноеИмя) <> Неопределено); + ПраваНаСписок.Вставить("ПоГруппамДоступа", Новый ФиксированноеСоответствие(ПоГруппамДоступа)); + ПраваНаСписки.Вставить(Строка.Список, Новый ФиксированнаяСтруктура(ПраваНаСписок)); + КонецЦикла; + НомерТаблицы = НомерТаблицы + 1; + Таблица = РезультатыЗапроса[НомерТаблицы].Выгрузить(); + Для Каждого Строка Из Таблица Цикл + ПраваНаСпискиВедущихКлючейДоступа.Вставить(Строка.КлючДоступа, + ПраваНаСписки.Получить(Строка.Список)); + КонецЦикла; + НомерТаблицы = НомерТаблицы + 1; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ПраваНаВедущийКлюч = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПраваНаВедущийКлюч.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); + КонецЦикла; + ПраваНаВедущиеКлючиДоступа.Вставить(Строка.КлючДоступа, + Новый ФиксированноеСоответствие(ПраваНаВедущийКлюч)); + КонецЦикла; + КонецЕсли; + ПараметрыОбновления.Вставить("ПраваНаСпискиВедущихКлючейДоступа", + Новый ФиксированноеСоответствие(ПраваНаСпискиВедущихКлючейДоступа)); + ПараметрыОбновления.Вставить("ПраваНаВедущиеКлючиДоступа", + Новый ФиксированноеСоответствие(ПраваНаВедущиеКлючиДоступа)); + + ПраваНаВедущиеСписки = НовыеПраваНаВедущиеСписки(); + Если ПараметрыОбновления.ЕстьВедущиеСпискиПоПравам Тогда + НомерТаблицы = НомерТаблицы + 1; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + ДобавитьПраваПоТипам = Дерево.Колонки.Найти("ТипЗначения") <> Неопределено; + Для Каждого Строка Из Дерево.Строки Цикл + ПраваНаВедущийСписок = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПраваНаВедущийСписок.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); + Если ДобавитьПраваПоТипам Тогда + ТипЗначенияСписка = Подстрока.ТипЗначения; + КонецЕсли; + КонецЦикла; + ПраваНаВедущиеСписки.Вставить(Строка.Список, + Новый ФиксированноеСоответствие(ПраваНаВедущийСписок)); + Если ДобавитьПраваПоТипам Тогда + ПраваНаВедущиеСписки.Вставить(ТипЗначенияСписка, + Новый ФиксированноеСоответствие(ПраваНаВедущийСписок)); + КонецЕсли; + КонецЦикла; + КонецЕсли; + ПараметрыОбновления.Вставить("ПраваНаВедущиеСписки", + Новый ФиксированноеСоответствие(ПраваНаВедущиеСписки)); + +КонецПроцедуры + +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - ОпределяемыйТип.ВладелецНастроекПрав +// * Значение - ФиксированноеСоответствие из КлючИЗначение: +// ** Ключ - СправочникСсылка.Пользователи +// - СправочникСсылка.ГруппыПользователей +// - СправочникСсылка.ВнешниеПользователи +// - СправочникСсылка.ГруппыВнешнихПользователей +// ** Значение - Булево - право изменение +// +Функция НовыеПраваПоВладельцамНастроекПрав() + Возврат Новый Соответствие; +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ЗаполнитьПраваПоВладельцамНастроекПрав(РезультатыЗапроса, НомерТаблицы, ПараметрыОбновления) + + ПраваПоВладельцамНастроекПрав = НовыеПраваПоВладельцамНастроекПрав(); + Если ПараметрыОбновления.ЕстьВладельцыНастроекПрав Тогда + НомерТаблицы = НомерТаблицы + 5; + Дерево = РезультатыЗапроса[НомерТаблицы].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого Строка Из Дерево.Строки Цикл + ПраваПоВладельцуНастроекПрав = Новый Соответствие; + Для Каждого Подстрока Из Строка.Строки Цикл + ПраваПоВладельцуНастроекПрав.Вставить(Подстрока.ВладелецПрав, Подстрока.ПравоИзменение); + КонецЦикла; + ПраваПоВладельцамНастроекПрав.Вставить(Строка.ВладелецНастроекПрав, + Новый ФиксированноеСоответствие(ПраваПоВладельцуНастроекПрав)); + КонецЦикла; + КонецЕсли; + ПараметрыОбновления.Вставить("ПраваПоВладельцамНастроекПрав", + Новый ФиксированноеСоответствие(ПраваПоВладельцамНастроекПрав)); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ЗначенияТаблицКлюча - см. НовыеЗначенияТаблицКлюча +// * БезЗаписиПраваЧтение - Булево +// * РеквизитыТаблицКлюча - см. НовыеРеквизитыТаблицКлюча +// * УчастникиГруппДоступа - см. НовыеУчастникиГруппДоступа +// * ГрупповыеПользователиГруппДоступа - см. НовыеГрупповыеПользователиГруппДоступа +// * ГруппыПользователейКакЗначенияДоступа - см. НовыеГруппыПользователейКакЗначенияДоступа +// * ПользователиГруппПользователей - см. НовыеПользователиГруппПользователей +// * ПраваНаСпискиВедущихКлючейДоступа - см. НовыеПраваНаСпискиВедущихКлючейДоступа +// * ПраваНаВедущиеКлючиДоступа - см. НовыеПраваНаВедущиеКлючиДоступа +// * ПраваНаВедущиеСписки - см. НовыеПраваНаВедущиеСписки +// * ПраваПоВладельцамНастроекПрав - см. НовыеПраваПоВладельцамНастроекПрав +// * ТипГруппыДоступа - Тип +// * ПустаяГруппаДоступа - СправочникСсылка.ГруппыДоступа +// * ТипПользователя - Тип +// * ТипГруппыПользователей - Тип +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ПраваРолейФункцииПравоДоступа - Соответствие +// * ОбъектыМетаданныхФункцииПравоДоступа - Соответствие +// * ПраваПрофилейФункцииПравоДоступа - Соответствие +// * РолиПрофилейГруппДоступа - см. РолиПрофилейГруппДоступа +// * ГруппыДоступаПрофилей - см. ГруппыДоступаПрофилей +// * ГруппаДоступа - СправочникСсылка.ГруппыДоступа - текущее значение +// * ЗначенияГруппыДоступа - см. НовыеЗначенияГруппыДоступа +// * ОписанияТребуемыхТаблицКлюча - Массив из Структура: +// ** РеквизитыТаблиц - Соответствие из КлючИЗначение: +// *** Ключ - Строка - имя таблицы ключа +// *** Значение - Массив из Строка - имя реквизита таблицы ключа +// ** ЗначенияТаблиц - см. ТекущиеЗначенияТаблицКлюча +// ** ИндексыСтрокТаблиц - Соответствие +// * ТекущиеСтрокиТаблицКлюча - см. НовыеЗначенияТаблицКлюча +// +Функция НовыйКонтекстРасчетаПрав() + Возврат Новый Структура; +КонецФункции + +// Для процедуры ОбновитьПраваНаКлючиДоступаСписка. +Функция ПраваНаКлючДоступаСписка(ЗначенияТаблицКлюча, ПараметрыОбновления) + + ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); + + Если ПараметрыОбновления.ОграничениеОтключено Тогда + Если Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа Тогда + Возврат ПраваНаКлюч; + ИначеЕсли ПараметрыОбновления.ИзменениеРазрешеноДляВсехПользователей Тогда + ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); + Возврат ПраваНаКлюч; + КонецЕсли; + КонецЕсли; + + БезЗаписиПраваЧтение = ПараметрыОбновления.ОграничениеЧтенияОтключено + И Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа; + + Контекст = НовыйКонтекстРасчетаПрав(); + Контекст.Вставить("ЗначенияТаблицКлюча", ЗначенияТаблицКлюча); + Контекст.Вставить("БезЗаписиПраваЧтение", БезЗаписиПраваЧтение); + Контекст.Вставить("РеквизитыТаблицКлюча", ПараметрыОбновления.РеквизитыТаблицКлюча); + Контекст.Вставить("УчастникиГруппДоступа", ПараметрыОбновления.УчастникиГруппДоступа); + Контекст.Вставить("ГрупповыеПользователиГруппДоступа", ПараметрыОбновления.ГрупповыеПользователиГруппДоступа); + Контекст.Вставить("ГруппыПользователейКакЗначенияДоступа", ПараметрыОбновления.ГруппыПользователейКакЗначенияДоступа); + Контекст.Вставить("ПользователиГруппПользователей", ПараметрыОбновления.ПользователиГруппПользователей); + Контекст.Вставить("ПраваНаСпискиВедущихКлючейДоступа", ПараметрыОбновления.ПраваНаСпискиВедущихКлючейДоступа); + Контекст.Вставить("ПраваНаВедущиеКлючиДоступа", ПараметрыОбновления.ПраваНаВедущиеКлючиДоступа); + Контекст.Вставить("ПраваНаВедущиеСписки", ПараметрыОбновления.ПраваНаВедущиеСписки); + Контекст.Вставить("ПраваПоВладельцамНастроекПрав", ПараметрыОбновления.ПраваПоВладельцамНастроекПрав); + Контекст.Вставить("РассчитыватьПраваПользователей", ПараметрыОбновления.РассчитыватьПраваПользователей); + Контекст.Вставить("ТипГруппыДоступа", ПараметрыОбновления.ТипГруппыДоступа); + Контекст.Вставить("ПустаяГруппаДоступа", ПараметрыОбновления.ПустаяГруппаДоступа); + Контекст.Вставить("ТипПользователя", ПараметрыОбновления.ТипПользователя); + Контекст.Вставить("ТипГруппыПользователей", ПараметрыОбновления.ТипГруппыПользователей); + Контекст.Вставить("ТипыВладельцевНастроекПрав", ПараметрыОбновления.ТипыВладельцевНастроекПрав); + Контекст.Вставить("ПраваРолейФункцииПравоДоступа", ПараметрыОбновления.Кэш.ПраваРолейФункцииПравоДоступа); + Контекст.Вставить("ОбъектыМетаданныхФункцииПравоДоступа", ПараметрыОбновления.Кэш.ОбъектыМетаданныхФункцииПравоДоступа); + Контекст.Вставить("ПраваПрофилейФункцииПравоДоступа", ПараметрыОбновления.Кэш.ПраваПрофилейФункцииПравоДоступа); + Контекст.Вставить("РолиПрофилейГруппДоступа", ПараметрыОбновления.РолиПрофилейГруппДоступа); + Контекст.Вставить("ГруппыДоступаПрофилей", ПараметрыОбновления.ГруппыДоступаПрофилей); + + ЧтениеРазрешеноДляВсехГруппДоступа = Истина; + ИзменениеРазрешеноДляВсехГруппДоступа = Истина; + ДобавлениеРазрешеноДляВсехГруппДоступа = Истина; + + Для Каждого ОписаниеПрав Из ПараметрыОбновления.ПраваГруппДоступаСписка Цикл + ГруппаДоступа = ОписаниеПрав.ГруппаДоступа; + ПраваГруппыДоступа = ОписаниеПрав; // СтрокаТаблицыЗначений + + Контекст.Вставить("ГруппаДоступа", ГруппаДоступа); + Контекст.Вставить("ЗначенияГруппыДоступа", + ПараметрыОбновления.ЗначенияГруппДоступа.Получить(ГруппаДоступа)); + + Если БезЗаписиПраваЧтение + Или ПраваГруппыДоступа.ПравоЧтениеБезОграничения Тогда + + ПравоЧтение = "Истина"; + Иначе + ПравоЧтение = РассчитанноеУсловиеДляСтрок(Контекст, + ПараметрыОбновления.СтруктураРасчетаПраваЧтение); + КонецЕсли; + + Если ПравоЧтение <> "Истина" Тогда + ЧтениеРазрешеноДляВсехГруппДоступа = Ложь; + ИзменениеРазрешеноДляВсехГруппДоступа = Ложь; + ДобавлениеРазрешеноДляВсехГруппДоступа = Ложь; + КонецЕсли; + + Если ПравоЧтение = "Ложь" + Или ТипЗнч(ПравоЧтение) = Тип("Соответствие") + И ПравоЧтение.Количество() = 0 Тогда + + Продолжить; + КонецЕсли; + + Если ПраваГруппыДоступа.ПравоИзменениеБезОграничения + И ПраваГруппыДоступа.ПравоДобавлениеБезОграничения Тогда + + ПравоИзменение = "Истина"; + + ИначеЕсли Не ПраваГруппыДоступа.ПравоИзменение Тогда + ПравоИзменение = "Ложь"; + + ИначеЕсли ПараметрыОбновления.ЕстьОграничениеИзменения Тогда + ПравоИзменение = РассчитанноеУсловиеДляСтрок(Контекст, + ПараметрыОбновления.СтруктураРасчетаПраваИзменение); + + ИначеЕсли БезЗаписиПраваЧтение + Или ПраваГруппыДоступа.ПравоЧтениеБезОграничения Тогда + + ПравоИзменение = РассчитанноеУсловиеДляСтрок(Контекст, + ПараметрыОбновления.СтруктураРасчетаПраваЧтение); + Иначе + ПравоИзменение = "Истина"; + КонецЕсли; + + ПравоДобавление = ?(ПраваГруппыДоступа.ПравоДобавление, ПравоИзменение, "Ложь"); + + Если ПраваГруппыДоступа.ПравоИзменениеБезОграничения Тогда + ПравоИзменение = "Истина"; + КонецЕсли; + + Если ПравоИзменение <> "Истина" Тогда + ИзменениеРазрешеноДляВсехГруппДоступа = Ложь; + КонецЕсли; + Если ПравоДобавление <> "Истина" Тогда + ДобавлениеРазрешеноДляВсехГруппДоступа = Ложь; + КонецЕсли; + + Если Контекст.РассчитыватьПраваПользователей Тогда + ДобавитьПраваПользователейНаКлючДоступа(ПраваНаКлюч, + ПравоЧтение, ПравоИзменение, ПравоДобавление, Контекст); + + ИначеЕсли Не БезЗаписиПраваЧтение Или ПравоИзменение = "Истина" Или ПравоДобавление = "Истина" Тогда + ПраваНаКлюч.ДляГрупп.Вставить(ГруппаДоступа, Новый Структура("ПравоИзменение, ПравоДобавление", + ПравоИзменение = "Истина", ПравоДобавление = "Истина")); + КонецЕсли; + КонецЦикла; + + Если Не ЧтениеРазрешеноДляВсехГруппДоступа + Или ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа + И Не ПараметрыОбновления.ЧтениеРазрешеноДляВсехПользователей Тогда + + Возврат ПраваНаКлюч; + КонецЕсли; + + Если ДобавлениеРазрешеноДляВсехГруппДоступа + И ( Не ПараметрыОбновления.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа + Или ПараметрыОбновления.ИзменениеРазрешеноДляВсехПользователей) Тогда + + ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); + ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); + + Иначе // ЧтениеРазрешеноДляВсехГруппДоступа. + ТекущиеПраваНаКлюч = ПраваНаКлюч; + ПраваНаКлюч = Новый Структура("ДляГрупп, ДляПользователей", Новый Соответствие, Новый Соответствие); + Если Не БезЗаписиПраваЧтение Или ИзменениеРазрешеноДляВсехГруппДоступа Тогда + ПраваНаКлюч.ДляГрупп.Вставить(ПараметрыОбновления.ПустаяГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", ИзменениеРазрешеноДляВсехГруппДоступа, Ложь)); + КонецЕсли; + ИмяПрава = ?(ИзменениеРазрешеноДляВсехГруппДоступа, "ПравоДобавление", "ПравоИзменение"); + Для Каждого КлючИЗначение Из ТекущиеПраваНаКлюч.ДляГрупп Цикл + Если КлючИЗначение.Значение[ИмяПрава] Тогда + ПраваНаКлюч.ДляГрупп.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + Для Каждого КлючИЗначение Из ТекущиеПраваНаКлюч.ДляПользователей Цикл + Если КлючИЗначение.Значение[ИмяПрава] Тогда + ПраваНаКлюч.ДляПользователей.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат ПраваНаКлюч; + +КонецФункции + +// Для процедуры ПраваНаКлючДоступаСписка. +Процедура ДобавитьПраваПользователейНаКлючДоступа(ПраваНаКлюч, ПравоЧтение, ПравоИзменение, ПравоДобавление, Контекст) + + Если ТипЗнч(ПравоИзменение) = Тип("Соответствие") И ПравоИзменение.Количество() = 0 Тогда + ПравоИзменение = "Ложь"; + ПравоДобавление = "Ложь"; + + ИначеЕсли ТипЗнч(ПравоДобавление) = Тип("Соответствие") И ПравоДобавление.Количество() = 0 Тогда + ПравоДобавление = "Ложь"; + КонецЕсли; + + Права = НовыеПрава(ПравоИзменение = "Истина", ПравоДобавление = "Истина"); + + Если ТипЗнч(ПравоЧтение) <> Тип("Соответствие") Тогда + Если Не Контекст.БезЗаписиПраваЧтение Или Права.ПравоИзменение Или Права.ПравоДобавление Тогда + ПраваНаКлюч.ДляГрупп.Вставить(Контекст.ГруппаДоступа, + Новый Структура("ПравоИзменение, ПравоДобавление", + Права.ПравоИзменение, Права.ПравоДобавление)); + КонецЕсли; + Иначе + ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлюч.ДляПользователей, + ПравоЧтение, Права.ПравоИзменение, Права.ПравоДобавление, Контекст.БезЗаписиПраваЧтение); + КонецЕсли; + + Если ТипЗнч(ПравоИзменение) <> Тип("Соответствие") + И ТипЗнч(ПравоДобавление) <> Тип("Соответствие") Тогда + Возврат; + КонецЕсли; + + Право = ?(ТипЗнч(ПравоИзменение) = Тип("Соответствие"), ПравоИзменение, ПравоДобавление); + ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлюч.ДляПользователей, + Право, Истина, ПравоДобавление <> "Ложь", Контекст.БезЗаписиПраваЧтение); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ПравоИзменение - Булево +// * ПравоДобавление - Булево +// +Функция НовыеПрава(ПравоИзменение, ПравоДобавление) + + Возврат Новый Структура("ПравоИзменение, ПравоДобавление", ПравоИзменение, ПравоДобавление); + +КонецФункции + +// Для процедуры ДобавитьПраваПользователейНаКлючДоступа. +Процедура ДобавитьПользователямПраваНаКлючДоступа(ПраваНаКлючДляПользователей, + СоставПользователей, ПравоИзменение, ПравоДобавление, БезЗаписиПраваЧтение) + + Если ПравоИзменение И ПравоДобавление Тогда + Для Каждого КлючИЗначение Из СоставПользователей Цикл + ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, + Новый Структура("ПравоИзменение, ПравоДобавление", Истина, Истина)); + КонецЦикла; + + ИначеЕсли Не ПравоИзменение И Не ПравоДобавление Тогда + Если Не БезЗаписиПраваЧтение Тогда + Для Каждого КлючИЗначение Из СоставПользователей Цикл + Права = ПраваНаКлючДляПользователей.Получить(КлючИЗначение.Ключ); + Если Права = Неопределено Тогда + Права = Новый Структура("ПравоИзменение, ПравоДобавление", Ложь, Ложь); + ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, Права); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Иначе + Для Каждого КлючИЗначение Из СоставПользователей Цикл + Права = ПраваНаКлючДляПользователей.Получить(КлючИЗначение.Ключ); // См. НовыеПрава + Если Права = Неопределено Тогда + Права = Новый Структура("ПравоИзменение, ПравоДобавление", + ПравоИзменение, ПравоДобавление); + Иначе + Права.ПравоИзменение = Права.ПравоИзменение Или ПравоИзменение; + Права.ПравоДобавление = Права.ПравоДобавление Или ПравоДобавление; + КонецЕсли; + ПраваНаКлючДляПользователей.Вставить(КлючИЗначение.Ключ, Права); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для функций ПраваНаКлючДоступаСписка и РассчитанноеУсловие. +Функция РассчитанноеУсловиеДляСтрок(Контекст, Условие, УзелРеквизитов = Неопределено, ДляЛюбойИзСтрок = Истина, КорневойУзел = Истина) + + Если УзелРеквизитов = Неопределено Тогда + Контекст.Вставить("ОписанияТребуемыхТаблицКлюча", Новый Массив); + Если Условие.Узел = "ДляВсехСтрок" Или Условие.Узел = "ДляОднойИзСтрок" Тогда + Возврат РассчитанноеУсловие(Контекст, Условие, КорневойУзел); + КонецЕсли; + УзелРеквизитов = Условие; + КонецЕсли; + + Если Не ЗначениеЗаполнено(УзелРеквизитов.ТребуемыеРеквизитыТабличныхЧастейКлюча) Тогда + Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", Контекст.ЗначенияТаблицКлюча); + Возврат РассчитанноеУсловие(Контекст, Условие, КорневойУзел); + КонецЕсли; + РеквизитыТаблиц = УзелРеквизитов.ТребуемыеРеквизитыТабличныхЧастейКлюча; + ЗначенияТаблиц = ТекущиеЗначенияТаблицКлюча(Контекст, РеквизитыТаблиц); + ИндексыСтрокТаблиц = Новый Соответствие; + + Контекст.ОписанияТребуемыхТаблицКлюча.Добавить( + Новый Структура("РеквизитыТаблиц, ЗначенияТаблиц, ИндексыСтрокТаблиц", + РеквизитыТаблиц, ЗначенияТаблиц, ИндексыСтрокТаблиц)); + + ТекущиеСтрокиТаблицКлюча = ?(Контекст.Свойство("ТекущиеСтрокиТаблицКлюча"), + Контекст.ТекущиеСтрокиТаблицКлюча, Неопределено); + + Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", Новый Структура); + Для Каждого ОписаниеЗначений Из Контекст.ЗначенияТаблицКлюча Цикл + Если СтрНачинаетсяС(ОписаниеЗначений.Ключ, "Шапка") Тогда + Контекст.ТекущиеСтрокиТаблицКлюча.Вставить(ОписаниеЗначений.Ключ, ОписаниеЗначений.Значение); + КонецЕсли; + КонецЦикла; + + Результат = "Неопределено"; + + Пока Истина Цикл + ИндексИзменен = Ложь; + Для Каждого ОписаниеТаблицы Из РеквизитыТаблиц Цикл + ИмяТаблицыКлюча = ОписаниеТаблицы.Ключ; + ИндексСтроки = ИндексыСтрокТаблиц.Получить(ИмяТаблицыКлюча); + ЗначенияТаблицы = ЗначенияТаблиц[ИмяТаблицыКлюча]; + Если ИндексСтроки = Неопределено Тогда + ИндексСтроки = 0; + Иначе + Если ИндексСтроки >= ЗначенияТаблицы.Количество() - 1 Тогда + Продолжить; + КонецЕсли; + ИндексСтроки = ИндексСтроки + 1; + КонецЕсли; + ИндексИзменен = Истина; + ИндексыСтрокТаблиц.Вставить(ИмяТаблицыКлюча, ИндексСтроки); + Контекст.ТекущиеСтрокиТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицы[ИндексСтроки]); + КонецЦикла; + Если Не ИндексИзменен Тогда + Прервать; + КонецЕсли; + ТекущийРезультат = РассчитанноеУсловие(Контекст, Условие); + Если ТипЗнч(ТекущийРезультат) <> Тип("Соответствие") Тогда + Если ДляЛюбойИзСтрок Тогда + Если ТекущийРезультат = "Истина" Тогда + Результат = "Истина"; + Прервать; + ИначеЕсли ТекущийРезультат = "Ложь" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Ложь"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + КонецЕсли; + Иначе + Если ТекущийРезультат = "Ложь" Тогда + Результат = "Ложь"; + Прервать; + ИначеЕсли ТекущийРезультат = "Истина" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + КонецЕсли; + КонецЕсли; + Иначе + Если Не ДляЛюбойИзСтрок И ТекущийРезультат.Количество() = 0 Тогда + Результат = "Ложь"; + Прервать; + КонецЕсли; + Если ТипЗнч(Результат) = Тип("Строка") Тогда + Результат = ТекущийРезультат; + Иначе + ДобавитьТекущийРезультат(Результат, ТекущийРезультат, ДляЛюбойИзСтрок, Контекст); + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + ИначеЕсли КорневойУзел И Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + + Контекст.ОписанияТребуемыхТаблицКлюча.Удалить( + Контекст.ОписанияТребуемыхТаблицКлюча.Количество() - 1); + + Контекст.Вставить("ТекущиеСтрокиТаблицКлюча", ТекущиеСтрокиТаблицКлюча); + + Возврат Результат; + +КонецФункции + +// Для функции РассчитанноеУсловиеДляСтрок. +Процедура ДобавитьТекущийРезультат(Результат, ТекущийРезультат, ДляЛюбойИзСтрок, Контекст) + + Если ДляЛюбойИзСтрок Тогда + Для Каждого КлючИЗначение Из ТекущийРезультат Цикл + Результат.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Иначе + Если Результат.Количество() > ТекущийРезультат.Количество() Тогда + МеньшийРезультат = ТекущийРезультат; + БольшийРезультат = Результат; + Иначе + МеньшийРезультат = Результат; + БольшийРезультат = ТекущийРезультат; + КонецЕсли; + Результат = Новый Соответствие; + ТипГруппыПользователей = Неопределено; + + Для Каждого КлючИЗначение Из МеньшийРезультат Цикл + Участник = КлючИЗначение.Ключ; + Если БольшийРезультат.Получить(Участник) <> Неопределено Тогда + Результат.Вставить(Участник, Истина); + Иначе + Если ТипГруппыПользователей = Неопределено Тогда + ТипГруппыПользователей = Контекст.ТипГруппыПользователей; + ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; + БольшийРезультатПользователиГрупп = ПользователиГрупп(БольшийРезультат, Контекст); + КонецЕсли; + Если ТипЗнч(Участник) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(Участник); + Если ПользователиГруппы = Неопределено Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если БольшийРезультатПользователиГрупп.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + ИначеЕсли БольшийРезультатПользователиГрупп.Получить(Участник) <> Неопределено Тогда + Результат.Вставить(Участник, Истина); + КонецЕсли; + КонецЕсли; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьТекущийРезультат и УстановитьОбратныйРезультат. +Функция ПользователиГрупп(ПользователиИГруппы, Контекст) + + ПользователиГрупп = Новый Соответствие; + + ТипГруппыПользователей = Контекст.ТипГруппыПользователей; + ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; + + Для Каждого КлючИЗначение Из ПользователиИГруппы Цикл + Если ТипЗнч(КлючИЗначение.Ключ) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(КлючИЗначение.Ключ); + Если ПользователиГруппы <> Неопределено Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + ПользователиГрупп.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Возврат ПользователиГрупп; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Процедура УстановитьОбратныйРезультат(Результат, Контекст) + + СписокИсключений = Результат; + Результат = Новый Соответствие; + + УчастникиТекущейГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если УчастникиТекущейГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + + ПользователиГруппПользователей = Контекст.ПользователиГруппПользователей; + ТипГруппыПользователей = Контекст.ТипГруппыПользователей; + ТипПользователя = Контекст.ТипПользователя; + + ПользователиИсключаемыхГрупп = ПользователиГрупп(СписокИсключений, Контекст); + + Для Каждого КлючИЗначение Из УчастникиТекущейГруппыДоступа Цикл + Участник = КлючИЗначение.Ключ; + Если СписокИсключений.Получить(Участник) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Если ТипЗнч(Участник) = ТипПользователя Тогда + Если СписокИсключений.Получить(Участник) = Неопределено + И ПользователиИсключаемыхГрупп.Получить(Участник) = Неопределено Тогда + + Результат.Вставить(Участник, Истина); + КонецЕсли; + ИначеЕсли ТипЗнч(Участник) = ТипГруппыПользователей Тогда + ПользователиГруппы = ПользователиГруппПользователей.Получить(Участник); + Если ПользователиГруппы = Неопределено Тогда + Продолжить; + КонецЕсли; + ВсяГруппаБезИсключений = Истина; + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если СписокИсключений.Получить(ОписаниеПользователя.Ключ) <> Неопределено + Или ПользователиИсключаемыхГрупп.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + + ВсяГруппаБезИсключений = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если ВсяГруппаБезИсключений Тогда + Результат.Вставить(Участник, Истина); + Иначе + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если СписокИсключений.Получить(ОписаниеПользователя.Ключ) = Неопределено + И ПользователиИсключаемыхГрупп.Получить(ОписаниеПользователя.Ключ) = Неопределено Тогда + + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для функции РассчитанноеУсловиеДляСтрок. +// +// Возвращаемое значение: +// Структура из КлючИЗначение: +// * Ключ - Строка - имя таблицы ключа +// * Значение - см. ЗначенияТаблицыКлюча +// +Функция ТекущиеЗначенияТаблицКлюча(Контекст, ТребуемыеРеквизитыТабличныхЧастейКлюча) + + ТекущиеЗначенияТаблицКлюча = Новый Структура; + Для Каждого ОписаниеТаблицы Из ТребуемыеРеквизитыТабличныхЧастейКлюча Цикл + ИмяТаблицыКлюча = ОписаниеТаблицы.Ключ; + Реквизиты = ОписаниеТаблицы.Значение; + ЗначенияТаблицыКлюча = Контекст.ЗначенияТаблицКлюча[ИмяТаблицыКлюча]; + Отбор = Новый Структура; + Для Каждого ТекущееОписание Из Контекст.ОписанияТребуемыхТаблицКлюча Цикл + РеквизитыТаблицы = ТекущееОписание.РеквизитыТаблиц.Получить(ИмяТаблицыКлюча); + ЗначенияТаблицы = ТекущееОписание.ЗначенияТаблиц[ИмяТаблицыКлюча]; + ИндексСтрокиТаблицы = ТекущееОписание.ИндексыСтрокТаблиц.Получить(ИмяТаблицыКлюча); + СтрокаТаблицы = ЗначенияТаблицы[ИндексСтрокиТаблицы]; + Для Каждого ИмяРеквизита Из РеквизитыТаблицы Цикл + Отбор.Вставить(ИмяРеквизита, СтрокаТаблицы[ИмяРеквизита]); + КонецЦикла; + КонецЦикла; + ВсегоРеквизитовТаблицы = Контекст.РеквизитыТаблицКлюча.Получить(ИмяТаблицыКлюча).Количество(); + Если ВсегоРеквизитовТаблицы = Реквизиты.Количество() И Не ЗначениеЗаполнено(Отбор) Тогда + ТекущиеЗначенияТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицыКлюча); + Продолжить; + КонецЕсли; + Строки = ЗначенияТаблицыКлюча; + Если ЗначениеЗаполнено(Отбор) Тогда + Строки = Строки.НайтиСтроки(Отбор); + КонецЕсли; + ЗначенияТаблицы = НовыеЗначенияТаблицыКлюча(); + Для Каждого ИмяРеквизита Из Реквизиты Цикл + ЗначенияТаблицы.Колонки.Добавить(ИмяРеквизита); + КонецЦикла; + Для Каждого Строка Из Строки Цикл + ЗаполнитьЗначенияСвойств(ЗначенияТаблицы.Добавить(), Строка); + КонецЦикла; + Если Реквизиты.Количество() < ВсегоРеквизитовТаблицы Тогда + РеквизитыСтрокой = СтрСоединить(Реквизиты, ", "); + ЗначенияТаблицы.Свернуть(РеквизитыСтрокой); + КонецЕсли; + ТекущиеЗначенияТаблицКлюча.Вставить(ИмяТаблицыКлюча, ЗначенияТаблицы); + КонецЦикла; + + Возврат ТекущиеЗначенияТаблицКлюча; + +КонецФункции + +// Для функции РассчитанноеУсловиеДляСтрок. +Функция РассчитанноеУсловие(Контекст, Условие, КорневойУзел = Ложь) + + // Проверяемые типы уже учтены. + + Если Условие.Узел = "Поле" Тогда + Значение = Контекст.ТекущиеСтрокиТаблицКлюча[Условие.Таблица][Условие.Реквизит]; + Результат = ?(Значение = Перечисления.ДополнительныеЗначенияДоступа.Истина + Или Значение = Null И Условие.Свойство("ПроверкаЕстьNull"), "Истина", "Ложь"); + + ИначеЕсли Условие.Узел = "Константа" Тогда + Результат = ?(Условие.Значение = Истина, "Истина", + ?(Условие.Значение = "Пусто", "Пусто", "Ложь")); + + ИначеЕсли Условие.Узел = "И" Тогда + + Результат = "Неопределено"; + Для Каждого Аргумент Из Условие.Аргументы Цикл + ТекущийРезультат = РассчитанноеУсловие(Контекст, Аргумент); + Если ТекущийРезультат = "Ложь" Тогда + Результат = "Ложь"; + Прервать; + КонецЕсли; + Если ТекущийРезультат = "Истина" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + ИначеЕсли ТипЗнч(ТекущийРезультат) = Тип("Соответствие") Тогда + Если ТекущийРезультат.Количество() = 0 Тогда + Результат = "Ложь"; + Прервать; + КонецЕсли; + Если ТипЗнч(Результат) = Тип("Строка") Тогда + Результат = ТекущийРезультат; + Иначе + ДобавитьТекущийРезультат(Результат, ТекущийРезультат, Ложь, Контекст); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + КонецЕсли; + + ИначеЕсли Условие.Узел = "Или" Тогда + + Результат = "Неопределено"; + Для Каждого Аргумент Из Условие.Аргументы Цикл + ТекущийРезультат = РассчитанноеУсловие(Контекст, Аргумент); + Если ТекущийРезультат = "Истина" Тогда + Результат = "Истина"; + Прервать; + КонецЕсли; + Если ТекущийРезультат = "Ложь" Тогда + Если Результат = "Неопределено" Или Результат = "Пусто" Тогда + Результат = "Ложь"; + КонецЕсли; + ИначеЕсли ТекущийРезультат = "Пусто" Тогда + Если Результат = "Неопределено" Тогда + Результат = "Пусто"; + КонецЕсли; + ИначеЕсли ТипЗнч(ТекущийРезультат) = Тип("Соответствие") Тогда + Если ТекущийРезультат.Количество() = 0 Тогда + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + КонецЕсли; + ИначеЕсли ТипЗнч(Результат) = Тип("Строка") Тогда + Результат = ТекущийРезультат; + Иначе + ДобавитьТекущийРезультат(Результат, ТекущийРезультат, Истина, Контекст); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Если Результат = "Неопределено" Тогда + Результат = "Ложь"; + КонецЕсли; + + ИначеЕсли Условие.Узел = "Не" Тогда + Результат = РассчитанноеУсловие(Контекст, Условие.Аргумент); + Если Результат = "Истина" Тогда + Результат = "Ложь"; + ИначеЕсли Результат = "Ложь" Тогда + Результат = "Истина"; + ИначеЕсли ТипЗнч(Результат) = Тип("Соответствие") Тогда + Если Результат.Количество() = 0 Тогда + Результат = "Истина"; + Иначе + УстановитьОбратныйРезультат(Результат, Контекст); + КонецЕсли; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + Результат = РассчитанноеУсловиеДляСтрок(Контекст, + Условие.Аргумент, Условие, Условие.Узел = "ДляОднойИзСтрок", Ложь); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + Результат = Неопределено; + Для Каждого Когда Из Условие.Когда Цикл + Если РассчитанноеУсловие(Контекст, Когда.Условие) = "Истина" Тогда + Результат = РассчитанноеУсловие(Контекст, Когда.Значение); + Прервать; + КонецЕсли; + КонецЦикла; + Если Результат = Неопределено Тогда + Результат = РассчитанноеУсловие(Контекст, Условие.Иначе); + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + Значение = Контекст.ТекущиеСтрокиТаблицКлюча[Условие.Поле.Таблица][Условие.Поле.Реквизит]; + Если Значение = Null Тогда + Значение = Перечисления.ДополнительныеЗначенияДоступа.Null; + ИначеЕсли Значение = Неопределено Тогда + Значение = Перечисления.ДополнительныеЗначенияДоступа.Неопределено; + КонецЕсли; + ОтключеноКакЛожь = Условие.УточненияСравнения.Получить("Отключено") = "Ложь"; + + Если Значение = Перечисления.ДополнительныеЗначенияДоступа.ТипРазрешенный Тогда + Если ОтключеноКакЛожь Тогда + ТекущийРезультат = "Пусто"; + Иначе + ТекущийРезультат = "Истина"; + КонецЕсли; + + ИначеЕсли Значение = Перечисления.ДополнительныеЗначенияДоступа.ТипЗапрещенный Тогда + Если ОтключеноКакЛожь Тогда + ТекущийРезультат = "Пусто"; + Иначе + ТекущийРезультат = "Ложь"; + КонецЕсли; + Иначе + ТекущийРезультат = Неопределено; + Для Каждого УточнениеСравнения Из Условие.УточненияСравнения Цикл + Если УточнениеСравнения.Ключ = "Null" + Или УточнениеСравнения.Ключ = "Неопределено" Тогда + Если Значение = Перечисления.ДополнительныеЗначенияДоступа[УточнениеСравнения.Ключ] Тогда + ТекущийРезультат = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + ИначеЕсли УточнениеСравнения.Ключ = "ПустаяСсылка" Тогда + Если Значение = Перечисления.ДополнительныеЗначенияДоступа.ПустаяСсылкаЛюбогоТипа + Или Значение.Пустая() Тогда + ТекущийРезультат = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + ИначеЕсли УточнениеСравнения.Ключ = ТипЗнч(Значение) Тогда + ТекущийРезультат = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если ТекущийРезультат <> Неопределено Тогда + Результат = ТекущийРезультат; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" Тогда + Если Значение = Перечисления.ДополнительныеЗначенияДоступа.Null + Или Значение = Перечисления.ДополнительныеЗначенияДоступа.Неопределено Тогда + Если ОтключеноКакЛожь Тогда + Результат = "Пусто"; + Иначе + Результат = "Ложь"; + КонецЕсли; + Иначе + Если Контекст.ЗначенияГруппыДоступа = Неопределено Тогда + ЗначенияОдногоТипа = Неопределено; + Иначе + ТипЗначения = ТипЗнч(Значение); + ЗначенияОдногоТипа = Контекст.ЗначенияГруппыДоступа.Получить(ТипЗначения); + КонецЕсли; + Если ЗначенияОдногоТипа = Неопределено Тогда + Если ОтключеноКакЛожь Тогда + Результат = "Пусто"; + Иначе + Результат = "Истина"; + КонецЕсли; + Иначе + ЗначениеУказано = ЗначенияОдногоТипа.Значения.Получить(Значение) <> Неопределено; + Если Не ЗначениеУказано И ТипЗначения = Контекст.ТипПользователя Тогда + ЗначениеУказано = ЗначениеУказаноВГруппеПользователей(Значение, Контекст); + КонецЕсли; + Результат = "Ложь"; + Если ЗначениеУказано И Не ЗначенияОдногоТипа.ВсеРазрешены + Или Не ЗначениеУказано И ЗначенияОдногоТипа.ВсеРазрешены Тогда + Результат = "Истина"; + + ИначеЕсли ТипЗначения = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(Результат, Значение, Контекст); + + ИначеЕсли ТипЗначения = Контекст.ТипГруппыПользователей Тогда + ЗаполнитьРезультатДляГруппыПользователей(Результат, Значение, Контекст); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" Тогда + Если ТипЗнч(Значение) = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(Результат, Значение, Контекст); + Иначе + Результат = "Ложь"; + КонецЕсли; + + ИначеЕсли ТипЗнч(Значение) = Тип("СправочникСсылка.КлючиДоступа") Тогда + ПраваНаСписок = Контекст.ПраваНаСпискиВедущихКлючейДоступа.Получить(Значение); + Если ПраваНаСписок = Неопределено Тогда + Результат = "Ложь"; + Иначе + ПравоИзменение = ПраваНаСписок.ПоГруппамДоступа.Получить(Контекст.ГруппаДоступа); + Если Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение = Неопределено + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение <> Истина Тогда + Результат = "Ложь"; + + ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" И ПраваНаСписок.ОграничениеЧтенияОтключено + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПраваНаСписок.ОграничениеОтключено Тогда + + Результат = "Истина"; + Иначе + ПраваНаВедущийКлючДоступа = Контекст.ПраваНаВедущиеКлючиДоступа.Получить(Значение); + Если ПраваНаВедущийКлючДоступа = Неопределено Тогда + Результат = "Ложь"; + + ИначеЕсли Контекст.РассчитыватьПраваПользователей Тогда + Если Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда + + Результат = "Ложь"; + ПроверятьПравоИзменение = Условие.Узел <> "ЧтениеОбъектаРазрешено"; + ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ПустаяГруппаДоступа); + Если ПравоИзменение <> Неопределено + И (Не ПроверятьПравоИзменение Или ПравоИзменение) Тогда + Результат = "Истина"; + Иначе + ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ГруппаДоступа); + Если ПравоИзменение <> Неопределено + И (Не ПроверятьПравоИзменение Или ПравоИзменение) Тогда + Результат = "Истина"; + КонецЕсли; + КонецЕсли; + Если Результат <> "Истина" Тогда + Результат = Новый Соответствие; + Для Каждого КлючИЗначение Из ПраваНаВедущийКлючДоступа Цикл + Если ПроверятьПравоИзменение И Не КлючИЗначение.Значение Тогда + Продолжить; + КонецЕсли; + ЗначениеКлюча = КлючИЗначение.Ключ; + ТипКлюча = ТипЗнч(ЗначениеКлюча); + Если ТипКлюча = Контекст.ТипГруппыДоступа Тогда + Продолжить; + КонецЕсли; + ТекущийРезультат = "Ложь"; + Если ТипКлюча = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(ТекущийРезультат, ЗначениеКлюча, Контекст); + ИначеЕсли ТипКлюча = Контекст.ТипГруппыПользователей Тогда + ЗаполнитьРезультатДляГруппыПользователей(ТекущийРезультат, ЗначениеКлюча, Контекст); + КонецЕсли; + Если ТекущийРезультат = "Ложь" Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеУчастника Из ТекущийРезультат Цикл + Результат.Вставить(ОписаниеУчастника.Ключ, Истина); + КонецЦикла; + КонецЦикла; + Если Результат.Количество() = 0 Тогда + Результат = "Ложь"; + КонецЕсли; + КонецЕсли; + Иначе + Результат = "Ложь"; + КонецЕсли; + Иначе + ПравоИзменение = ПраваНаВедущийКлючДоступа.Получить(Контекст.ГруппаДоступа); + Если Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение <> Неопределено + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение = Истина Тогда + Результат = "Истина"; + Иначе + Результат = "Ложь"; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ИначеЕсли Контекст.ТипыВладельцевНастроекПрав.Получить(ТипЗнч(Значение)) <> Неопределено Тогда + ПраваПоВладельцуНастроекПрав = Контекст.ПраваПоВладельцамНастроекПрав.Получить(Значение); + Если ПраваПоВладельцуНастроекПрав = Неопределено Тогда + Результат = "Ложь"; + + ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда + + ПроверятьПравоИзменение = Условие.Узел <> "ЧтениеОбъектаРазрешено"; + Результат = Новый Соответствие; + Для Каждого КлючИЗначение Из ПраваПоВладельцуНастроекПрав Цикл + Если ПроверятьПравоИзменение И Не КлючИЗначение.Значение Тогда + Продолжить; + КонецЕсли; + ЗначениеКлюча = КлючИЗначение.Ключ; + ТипКлюча = ТипЗнч(ЗначениеКлюча); + ТекущийРезультат = "Ложь"; + Если ТипКлюча = Контекст.ТипПользователя Тогда + ЗаполнитьРезультатДляПользователя(ТекущийРезультат, ЗначениеКлюча, Контекст); + ИначеЕсли ТипКлюча = Контекст.ТипГруппыПользователей Тогда + ЗаполнитьРезультатДляГруппыПользователей(ТекущийРезультат, ЗначениеКлюча, Контекст); + КонецЕсли; + Если ТекущийРезультат = "Ложь" Тогда + Продолжить; + КонецЕсли; + Для Каждого ОписаниеУчастника Из ТекущийРезультат Цикл + Результат.Вставить(ОписаниеУчастника.Ключ, Истина); + КонецЦикла; + КонецЦикла; + Если Результат.Количество() = 0 Тогда + Результат = "Ложь"; + КонецЕсли; + Иначе + Результат = "Ложь"; + КонецЕсли; + + Иначе // Проверка прав на список. + ПраваНаВедущийСписок = Контекст.ПраваНаВедущиеСписки.Получить(Значение); + Если ПраваНаВедущийСписок = Неопределено Тогда + ПраваНаВедущийСписок = Контекст.ПраваНаВедущиеСписки.Получить(ТипЗнч(Значение)); + КонецЕсли; + Если ПраваНаВедущийСписок = Неопределено Тогда + Результат = "Ложь"; + Иначе + ПравоИзменение = ПраваНаВедущийСписок.Получить(Контекст.ГруппаДоступа); + Если Условие.Узел = "ЧтениеСпискаРазрешено" И ПравоИзменение <> Неопределено + Или Условие.Узел = "ЧтениеОбъектаРазрешено" И ПравоИзменение <> Неопределено + Или Условие.Узел = "ИзменениеСпискаРазрешено" И ПравоИзменение = Истина + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ПравоИзменение = Истина Тогда + + Результат = "Истина"; + Иначе + Результат = "Ложь"; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ПравоДоступа" Тогда + Результат = ?(ЕстьПравоДоступаВРоляхПрофиляГруппыДоступа(Условие, Контекст), "Истина", "Ложь"); + + ИначеЕсли Условие.Узел = "РольДоступна" Тогда + Результат = ?(ЕстьРольВПрофилеГруппыДоступа(Условие, Контекст), "Истина", "Ложь"); + + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При вычислении прав на ключ доступа узел не поддерживается ""%1"".'"), + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если КорневойУзел И Результат = "Пусто" Тогда + Результат = "Истина"; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Функция ЗначениеУказаноВГруппеПользователей(Пользователь, Контекст) + + УказанныеГруппыПользователей = Контекст.ЗначенияГруппыДоступа.Получить(Контекст.ТипГруппыПользователей); + Если УказанныеГруппыПользователей = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого УказаннаяГруппаПользователей Из УказанныеГруппыПользователей.Значения Цикл + ПользователиГруппы = Контекст.ГруппыПользователейКакЗначенияДоступа.Получить(УказаннаяГруппаПользователей.Ключ); + Если ПользователиГруппы = Неопределено Тогда + Продолжить; + КонецЕсли; + Если ПользователиГруппы.Получить(Пользователь) <> Неопределено Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Процедура ЗаполнитьРезультатДляПользователя(Результат, Пользователь, Контекст) + + Результат = "Ложь"; + + УчастникиГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если УчастникиГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + Если УчастникиГруппыДоступа.Получить(Пользователь) <> Неопределено Тогда + Результат = Новый Соответствие; + Результат.Вставить(Пользователь, Истина); + Возврат; + КонецЕсли; + + ГрупповыеПользователиГруппыДоступа = Контекст.ГрупповыеПользователиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если ГрупповыеПользователиГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ГрупповыеПользователиГруппыДоступа.Получить(Пользователь) <> Неопределено Тогда + Результат = Новый Соответствие; + Результат.Вставить(Пользователь, Истина); + КонецЕсли; + +КонецПроцедуры + +// Для функции РассчитанноеУсловие. +Процедура ЗаполнитьРезультатДляГруппыПользователей(Результат, ГруппаПользователей, Контекст) + + Результат = "Ложь"; + + УчастникиГруппыДоступа = Контекст.УчастникиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если УчастникиГруппыДоступа = Неопределено Тогда + Возврат; + КонецЕсли; + + Если УчастникиГруппыДоступа.Получить(ГруппаПользователей) <> Неопределено Тогда + Результат = Новый Соответствие; + Результат.Вставить(ГруппаПользователей, Истина); + Возврат; + КонецЕсли; + + ПользователиГруппы = Контекст.ПользователиГруппПользователей.Получить(ГруппаПользователей); + Если ПользователиГруппы = Неопределено Тогда + Возврат; + КонецЕсли; + + ГрупповыеПользователиГруппыДоступа = Контекст.ГрупповыеПользователиГруппДоступа.Получить(Контекст.ГруппаДоступа); + Если ГрупповыеПользователиГруппыДоступа = Неопределено Тогда + ГрупповыеПользователиГруппыДоступа = Новый Соответствие; + КонецЕсли; + + Результат = Новый Соответствие; + + Если УчастникиГруппыДоступа.Количество() > ПользователиГруппы.Количество() Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если УчастникиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + Продолжить; + КонецЕсли; + Если ГрупповыеПользователиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого ОписаниеУчастника Из УчастникиГруппыДоступа Цикл + Если ПользователиГруппы.Получить(ОписаниеУчастника.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеУчастника.Ключ, Истина); + КонецЕсли; + КонецЦикла; + Если ГрупповыеПользователиГруппыДоступа.Количество() > ПользователиГруппы.Количество() Тогда + Для Каждого ОписаниеПользователя Из ПользователиГруппы Цикл + Если ГрупповыеПользователиГруппыДоступа.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + Иначе + Для Каждого ОписаниеПользователя Из ГрупповыеПользователиГруппыДоступа Цикл + Если ПользователиГруппы.Получить(ОписаниеПользователя.Ключ) <> Неопределено Тогда + Результат.Вставить(ОписаниеПользователя.Ключ, Истина); + КонецЕсли; + КонецЦикла; + КонецЕсли; + КонецЕсли; + + Если Результат.Количество() = 0 Тогда + Результат = "Ложь"; + КонецЕсли; + +КонецПроцедуры + +// Для функции РассчитанноеУсловие. +Функция ЕстьПравоДоступаВРоляхПрофиляГруппыДоступа(Условие, Контекст) + + ПолноеИмя = Условие.ПолноеИмяОбъектаМетаданных; + Описание = Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Получить(ПолноеИмя); + Если Описание = Неопределено Тогда + Описание = Новый Структура("ОбъектМетаданных, ИмяСтандартногоРеквизита"); + Описание.ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава( + ПолноеИмя, Описание.ИмяСтандартногоРеквизита); + Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Вставить(ПолноеИмя, Описание); + КонецЕсли; + + СтрокаТаблицы = Контекст.ГруппыДоступаПрофилей.Найти(Контекст.ГруппаДоступа, "ГруппаДоступа"); + Если СтрокаТаблицы = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ПраваПрофиля = Контекст.ПраваПрофилейФункцииПравоДоступа.Получить(СтрокаТаблицы.Профиль); + Если ПраваПрофиля = Неопределено Тогда + ПраваПрофиля = Новый Соответствие; + Контекст.ПраваПрофилейФункцииПравоДоступа.Вставить(СтрокаТаблицы.Профиль, ПраваПрофиля); + КонецЕсли; + + КлючПраваВРоляхПрофиля = ПолноеИмя + "/" + Условие.ИмяПрава; + ЕстьПравоВРоляхПрофиля = ПраваПрофиля.Получить(КлючПраваВРоляхПрофиля); + Если ТипЗнч(ЕстьПравоВРоляхПрофиля) = Тип("Булево") Тогда + Возврат ЕстьПравоВРоляхПрофиля; + КонецЕсли; + + Отбор = Новый Структура("Профиль", СтрокаТаблицы.Профиль); + РолиПрофиля = Контекст.РолиПрофилейГруппДоступа.НайтиСтроки(Отбор); + + ЕстьПравоВРоли = Ложь; + Для Каждого ОписаниеРоли Из РолиПрофиля Цикл + КлючПраваРоли = ОписаниеРоли.ИмяРоли + "/" + ПолноеИмя + "/" + Условие.ИмяПрава; + ЕстьПравоВРоли = Контекст.ПраваРолейФункцииПравоДоступа.Получить(КлючПраваРоли); + Если ЕстьПравоВРоли = Неопределено Тогда + Если ЗначениеЗаполнено(ОписаниеРоли.ИмяРоли) Тогда + ПолноеИмяРоли = "Роль." + ОписаниеРоли.ИмяРоли; + Роль = Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Получить(ПолноеИмяРоли); + Если Роль = Неопределено Тогда + Роль = Метаданные.Роли[ОписаниеРоли.ИмяРоли]; + Контекст.ОбъектыМетаданныхФункцииПравоДоступа.Вставить(ПолноеИмяРоли, Роль); + КонецЕсли; + ЕстьПравоВРоли = ПравоДоступа(Условие.ИмяПрава, Описание.ОбъектМетаданных, Роль, + Описание.ИмяСтандартногоРеквизита); + Иначе + ЕстьПравоВРоли = Ложь; + КонецЕсли; + Контекст.ПраваРолейФункцииПравоДоступа.Вставить(КлючПраваРоли, ЕстьПравоВРоли); + КонецЕсли; + Если ЕстьПравоВРоли Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + ПраваПрофиля.Вставить(КлючПраваВРоляхПрофиля, ЕстьПравоВРоли); + + Возврат ЕстьПравоВРоли; + +КонецФункции + +// Для функции РассчитанноеУсловие. +Функция ЕстьРольВПрофилеГруппыДоступа(Условие, Контекст) + + СтрокаТаблицы = Контекст.ГруппыДоступаПрофилей.Найти(Контекст.ГруппаДоступа, "ГруппаДоступа"); + Если СтрокаТаблицы = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Отбор = Новый Структура("Профиль,ИмяРолиВерхнийРегистр", СтрокаТаблицы.Профиль, ВРег(Условие.ИмяРоли)); + + Возврат Контекст.РолиПрофилейГруппДоступа.НайтиСтроки(Отбор).Количество() > 0; + +КонецФункции + +// Для процедуры ОбновитьПраваПорцииКлючейДоступаСписка. +Процедура ОбновитьПраваНаКлючДоступаСписка(КлючДоступа, ПраваНаКлюч, ОписаниеНовыхКлючей, ПараметрыОбновления) + + Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + ПраваНаКлючДляПользователей = Новый Соответствие; + ТипПользователя = ПараметрыОбновления.ТипПользователя; + Для Каждого КлючИЗначение Из ПраваНаКлюч.ДляПользователей Цикл + Если ТипЗнч(КлючИЗначение.Ключ) = ТипПользователя Тогда + Набор = Справочники.НаборыГруппДоступа.ПолучитьСсылку(КлючИЗначение.Ключ.УникальныйИдентификатор()); + ПраваНаКлючДляПользователей.Вставить(Набор, КлючИЗначение.Значение); + Иначе + ПраваНаКлюч.ДляГрупп.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Блокировка = Новый БлокировкаДанных; + + ЗапросГрупп = Новый Запрос; + ЗапросГрупп.УстановитьПараметр("КлючДоступа", КлючДоступа); + ЗапросГрупп.Текст = + "ВЫБРАТЬ + | КлючиДоступаГруппДоступа.ГруппаДоступа КАК ГруппаДоступа, + | КлючиДоступаГруппДоступа.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление КАК ПравоДобавление + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + |ГДЕ + | КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа + | И &УточнениеПланаЗапроса"; + УстановитьУточнениеПланаЗапроса(ЗапросГрупп.Текст); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + ЭлементБлокировкиГрупп = Блокировка.Добавить("РегистрСведений.КлючиДоступаГруппДоступа"); + ЭлементБлокировкиГрупп.УстановитьЗначение("КлючДоступа", КлючДоступа); + НаборЗаписейГрупп = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаГруппДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписейГрупп.Отбор.КлючДоступа.Установить(КлючДоступа); + КонецЕсли; + + ЗапросНаборовГруппДоступа = Новый Запрос; + ЗапросНаборовГруппДоступа.УстановитьПараметр("КлючДоступа", КлючДоступа); + ЗапросНаборовГруппДоступа.УстановитьПараметр("РазрешенныйПустойНабор", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + ЗапросНаборовГруппДоступа.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа(); + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаНаборовГруппДоступа"); + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", КлючДоступа); + НаборЗаписейНаборовГруппДоступа = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаНаборовГруппДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписейНаборовГруппДоступа.Отбор.КлючДоступа.Установить(КлючДоступа); + КонецЕсли; + + Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("КлючДоступа", КлючДоступа); + + Если Не ПараметрыОбновления.ДляВнешнихПользователей Тогда + Запрос.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляПользователей(); + ИмяПоляВладельцаПрав = "Пользователь"; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаПользователей"); + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаПользователей); + Иначе + Запрос.Текст = ТекстЗапросаВыбораРазличийПроизводныхПравДляВнешнихПользователей(); + ИмяПоляВладельцаПрав = "ВнешнийПользователь"; + ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.КлючиДоступаВнешнихПользователей"); + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.КлючиДоступаВнешнихПользователей); + КонецЕсли; + ЭлементБлокировки.УстановитьЗначение("КлючДоступа", КлючДоступа); + Если Не ПакетныйРежим Тогда + НаборЗаписей.Отбор.КлючДоступа.Установить(КлючДоступа); + КонецЕсли; + КонецЕсли; + + Если ОписаниеНовыхКлючей <> Неопределено Тогда + ОписаниеНовогоКлюча = ОписаниеНовыхКлючей.ОписанияКлючейПоСсылке.Получить(КлючДоступа); + КлючДоступаОбъект = ОписаниеНовогоКлюча.КлючДоступаОбъект; // СправочникОбъект.КлючиДоступа + ЭлементБлокировкиКлюча = Блокировка.Добавить("Справочник.КлючиДоступа"); + ЭлементБлокировкиКлюча.УстановитьЗначение("Хеш", КлючДоступаОбъект.Хеш); + ЭлементБлокировкиКлюча.УстановитьЗначение("Список", КлючДоступаОбъект.Список); + ЭлементБлокировкиКлюча.УстановитьЗначение("ДляВнешнихПользователей", КлючДоступаОбъект.ДляВнешнихПользователей); + ЭлементБлокировкиКлюча.УстановитьЗначение("СоставПолей", КлючДоступаОбъект.СоставПолей); + КонецЕсли; + + ОбновлениеВручную = ПараметрыОбновления.Свойство("ОбновитьПраваНаКлючи") + И ПараметрыОбновления.ОбновитьПраваНаКлючи; + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Если ОписаниеНовыхКлючей <> Неопределено Тогда + ЭлементБлокировки = Блокировка.Добавить("Справочник.КлючиДоступа"); + КонецЕсли; + ЭлементБлокировки = Блокировка.Добавить("Справочник.НаборыГруппДоступа"); + ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый; + КонецЕсли; + + НачатьТранзакцию(); + Попытка + ПередБлокировкойДанных(ПараметрыОбновления); + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(); + КонецЕсли; + Блокировка.Заблокировать(); + ПослеБлокировкиДанных(ПараметрыОбновления); + + ЕстьИзмененияПрав = Ложь; + + Если ОписаниеНовыхКлючей = Неопределено + Или Не НовыйКлючДоступаУжеСуществует(ОписаниеНовыхКлючей, ОписаниеНовогоКлюча, ПараметрыОбновления) Тогда + + Если ОписаниеНовыхКлючей <> Неопределено Тогда + ПередЗаписьюНовогоКлюча(ПараметрыОбновления); + КлючДоступаОбъект.Записать(); + ПослеЗаписиНовогоКлюча(ПараметрыОбновления); + КонецЕсли; + + ПередЗапросомПравГруппДоступа(ПараметрыОбновления); + РезультатЗапросаГрупп = ЗапросГрупп.Выполнить(); + ПослеЗапросаПравГруппДоступа(ПараметрыОбновления); + + ЕстьИзменения = Новый Структура("ПраваГруппДоступа, ПраваГруппПользователей", Ложь, Ложь); + ОбновитьИсходныеПраваГруппНаКлючДоступа(РезультатЗапросаГрупп, НаборЗаписейГрупп, "ГруппаДоступа", + КлючДоступа, ПраваНаКлюч.ДляГрупп, ПараметрыОбновления, ЕстьИзменения); + + ЕстьИзмененияПрав = ЕстьИзменения.ПраваГруппДоступа Или ЕстьИзменения.ПраваГруппПользователей; + + Если ЕстьИзменения.ПраваГруппДоступа Или ОбновлениеВручную Тогда + ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления); + РезультатЗапросаНаборовГруппДоступа = ЗапросНаборовГруппДоступа.Выполнить(); + ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапросаНаборовГруппДоступа, + НаборЗаписейНаборовГруппДоступа, "НаборГруппДоступа", КлючДоступа, , ПараметрыОбновления); + КонецЕсли; + + Если ПараметрыОбновления.РассчитыватьПраваПользователей Тогда + ЗапросыПакета = СтрРазделить(Запрос.Текст, ";", Ложь); + Если ЕстьИзменения.ПраваГруппПользователей Или ОбновлениеВручную Тогда + Запрос.Текст = ЗапросыПакета[1]; + ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления); + РезультатЗапроса = Запрос.Выполнить(); + ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления); + ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапроса, + НаборЗаписей, ИмяПоляВладельцаПрав, КлючДоступа, , ПараметрыОбновления); + НаборЗаписей.Очистить(); + КонецЕсли; + Запрос.Текст = ЗапросыПакета[0]; + ПередЗапросомПравПользователей(ПараметрыОбновления); + РезультатЗапросаПользователей = Запрос.Выполнить(); + ПослеЗапросаПравПользователей(ПараметрыОбновления); + ОбновитьИсходныеПраваПользователейНаКлючДоступа(РезультатЗапросаПользователей, НаборЗаписей, + ИмяПоляВладельцаПрав, КлючДоступа, ПраваНаКлючДляПользователей, ЕстьИзмененияПрав, ПараметрыОбновления); + КонецЕсли; + + Если ОписаниеНовыхКлючей = Неопределено + И ЕстьИзмененияПрав + И ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа.Количество() > 0 Тогда + + ПередПланированиемОбновления(ПараметрыОбновления); + ЗапланироватьОбновлениеПользователейКлючейДоступа(ПараметрыОбновления.ЗависимыеСпискиПоКлючамДоступа, + "ОбновитьПраваНаКлючДоступаСписка", + Не ПараметрыОбновления.ДляВнешнихПользователей, + ПараметрыОбновления.ДляВнешнихПользователей, , + Новый Структура("ПоКлючамДоступа", КлючДоступа)); + ПослеПланированияОбновления(ПараметрыОбновления); + КонецЕсли; + КонецЕсли; + + // АПК:330-выкл - №783.1.3 Допустимо указать вызов после ЗафиксироватьТранзакцию, + // так как это вызов пустой процедуры в штатном режиме (то есть исключение невозможно), + // а в режиме анализа производительности последствия учитываются и не являются критичными. + ПередФиксациейТранзакции(ПараметрыОбновления); + ЗафиксироватьТранзакцию(); + ПослеФиксацииТранзакции(ПараметрыОбновления); + // АПК:330-вкл. + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + Если ЕстьИзмененияПрав И ПараметрыОбновления.Свойство("ЕстьИзмененияПрав") Тогда + ПараметрыОбновления.ЕстьИзмененияПрав = Истина; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьПраваНаКлючДоступаСписка, ОбновитьГруппыДоступаРазрешенногоКлючаДоступа. +Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляГруппДоступа() + + ТекстЗапроса = + "ВЫБРАТЬ + | ВсеСтроки.НаборГруппДоступа КАК НаборГруппДоступа, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыВходящиеВНаборы.Ссылка КАК НаборГруппДоступа, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыДоступа)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа)) + | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | ГруппыВходящиеВНаборы.Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | &РазрешенныйПустойНабор, + | КлючиДоступаГруппДоступа.ПравоИзменение, + | КлючиДоступаГруппДоступа.ПравоДобавление, + | 1 + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ГДЕ + | КлючиДоступаГруппДоступа.ГруппаДоступа = ЗНАЧЕНИЕ(Справочник.ГруппыДоступа.ПустаяСсылка) + | И КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.НаборГруппДоступа, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.НаборГруппДоступа, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедур ОбновитьПраваНаКлючДоступаСписка. +Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляПользователей() + + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступаПользователей.Пользователь КАК Пользователь, + | КлючиДоступаПользователей.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаПользователей.ПравоДобавление КАК ПравоДобавление, + | КлючиДоступаПользователей.ЭтоПраваНабораГрупп КАК ЭтоПраваНабораГрупп + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК КлючиДоступаПользователей + |ГДЕ + | КлючиДоступаПользователей.КлючДоступа = &КлючДоступа + | И НЕ КлючиДоступаПользователей.ЭтоПраваНабораГрупп + | И &УточнениеПланаЗапроса + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ВсеСтроки.Пользователь КАК Пользователь, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыВходящиеВНаборы.Ссылка КАК Пользователь, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыПользователей)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыПользователей)) + | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | ГруппыВходящиеВНаборы.Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.Пользователь, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.ЭтоПраваНабораГрупп + | И СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.Пользователь, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедур ОбновитьПраваНаКлючДоступаСписка. +Функция ТекстЗапросаВыбораРазличийПроизводныхПравДляВнешнихПользователей() + + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступаВнешнихПользователей.ВнешнийПользователь КАК ВнешнийПользователь, + | КлючиДоступаВнешнихПользователей.ПравоИзменение КАК ПравоИзменение, + | КлючиДоступаВнешнихПользователей.ПравоДобавление КАК ПравоДобавление, + | КлючиДоступаВнешнихПользователей.ЭтоПраваНабораГрупп КАК ЭтоПраваНабораГрупп + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК КлючиДоступаВнешнихПользователей + |ГДЕ + | КлючиДоступаВнешнихПользователей.КлючДоступа = &КлючДоступа + | И НЕ КлючиДоступаВнешнихПользователей.ЭтоПраваНабораГрупп + | И &УточнениеПланаЗапроса + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ВсеСтроки.ВнешнийПользователь КАК ВнешнийПользователь, + | ВсеСтроки.ПравоИзменение КАК ПравоИзменение, + | ВсеСтроки.ПравоДобавление КАК ПравоДобавление, + | ИСТИНА КАК ЭтоПраваНабораГрупп, + | СУММА(ВсеСтроки.ВидИзмененияСтроки) КАК ВидИзмененияСтроки + |ИЗ + | (ВЫБРАТЬ + | ГруппыВходящиеВНаборы.Ссылка КАК ВнешнийПользователь, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоИзменение) КАК ПравоИзменение, + | МАКСИМУМ(КлючиДоступаГруппДоступа.ПравоДобавление) КАК ПравоДобавление, + | 1 КАК ВидИзмененияСтроки + | ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК КлючиДоступаГруппДоступа + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа.Группы КАК ГруппыВходящиеВНаборы + | ПО (ГруппыВходящиеВНаборы.Группа = КлючиДоступаГруппДоступа.ГруппаДоступа) + | И (ТИПЗНАЧЕНИЯ(ГруппыВходящиеВНаборы.Группа) = ТИП(Справочник.ГруппыВнешнихПользователей)) + | И (ТИПЗНАЧЕНИЯ(КлючиДоступаГруппДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыВнешнихПользователей)) + | И (КлючиДоступаГруппДоступа.КлючДоступа = &КлючДоступа) + | И (&УточнениеПланаЗапроса) + | + | СГРУППИРОВАТЬ ПО + | ГруппыВходящиеВНаборы.Ссылка + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | СтарыеДанные.ВнешнийПользователь, + | СтарыеДанные.ПравоИзменение, + | СтарыеДанные.ПравоДобавление, + | -1 + | ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК СтарыеДанные + | ГДЕ + | СтарыеДанные.ЭтоПраваНабораГрупп + | И СтарыеДанные.КлючДоступа = &КлючДоступа) КАК ВсеСтроки + | + |СГРУППИРОВАТЬ ПО + | ВсеСтроки.ВнешнийПользователь, + | ВсеСтроки.ПравоИзменение, + | ВсеСтроки.ПравоДобавление + | + |ИМЕЮЩИЕ + | СУММА(ВсеСтроки.ВидИзмененияСтроки) <> 0 + | + |УПОРЯДОЧИТЬ ПО + | ВидИзмененияСтроки"; + + УстановитьУточнениеПланаЗапроса(ТекстЗапроса); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Функция НовыйКлючДоступаУжеСуществует(ОписаниеНовыхКлючей, ОписаниеНовогоКлюча, ПараметрыОбновления) + + ЗапросСуществованияКлючей = ОписаниеНовыхКлючей.ЗапросСуществованияКлючей; + ЗапросСуществованияКлючей.УстановитьПараметр("Хеш", ОписаниеНовогоКлюча.КлючДоступаОбъект.Хеш); + + Если ЗапросСуществованияКлючей.Выполнить().Пустой() Тогда + Возврат Ложь; + КонецЕсли; + + ЗапросЗначенийКлючей = ОписаниеНовыхКлючей.ЗапросЗначенийКлючей; + ЗапросЗначенийКлючей.УстановитьПараметр("Хеши", ОписаниеНовогоКлюча.КлючДоступаОбъект.Хеш); + + РезультатыЗапросаЗначенийКлючей = ЗапросЗначенийКлючей.ВыполнитьПакет(); + + ТаблицыКлюча = ПараметрыОбновления.ТаблицыКлюча; + КлючиЗначенийСтрокКлючей = КлючиЗначенийСтрокОбъектов(РезультатыЗапросаЗначенийКлючей, + ?(Не ЗначениеЗаполнено(ПараметрыОбновления.СоставПолей) + Или СтрНачинаетсяС(ТаблицыКлюча[0], "Шапка"), 0, 1), + ТаблицыКлюча); + + Выборка = РезультатыЗапросаЗначенийКлючей[0].Выбрать(); + + Пока Выборка.Следующий() Цикл + Ссылка = Выборка.ТекущаяСсылка; // СправочникСсылка.КлючиДоступа + ОписаниеКлючейЗначений = КлючиЗначенийСтрокКлючей.Получить(Ссылка); + СтрокаДляХеша = СтрокаДляХешаКлючаДоступа(ОписаниеКлючейЗначений, ТаблицыКлюча); + Если ОписаниеНовогоКлюча.СтрокаДляХеша = СтрокаДляХеша Тогда + ОписаниеНовогоКлюча.КлючДоступаОбъект = Новый Структура("Ссылка", Ссылка); + НеИспользуетсяС = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "НеИспользуетсяС"); + Если ЗначениеЗаполнено(НеИспользуетсяС) Тогда + Объект = СлужебныйЭлемент(Неопределено, Ссылка); + Объект.НеИспользуетсяС = '00010101'; + Объект.Записать(); + КонецЕсли; + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Процедура ОбновитьИсходныеПраваГруппНаКлючДоступа(РезультатЗапроса, НаборЗаписей, ИмяПоляВладельцаПрав, + КлючДоступа, ПраваНаКлюч, ПараметрыОбновления, ЕстьИзменения) + + Выборка = РезультатЗапроса.Выбрать(); + ТипГруппыДоступа = ПараметрыОбновления.ТипГруппыДоступа; + ЕстьИзмененияПравГруппДоступа = Ложь; + ЕстьИзмененияПравГруппПользователей = Ложь; + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + КоличествоЗаписанных = 0; + ПередЗаписьюСтрок(ПараметрыОбновления); + + Пока Выборка.Следующий() Цикл + ВладелецПрав = Выборка[ИмяПоляВладельцаПрав]; + Права = ПраваНаКлюч.Получить(ВладелецПрав); // См. НовыеПрава + Если Права = Неопределено Тогда + Если ПакетныйРежим Тогда + СтараяЗапись = НаборЗаписей.Добавить(); + СтараяЗапись.КлючДоступа = КлючДоступа; + СтараяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + НаборЗаписей.Записать(); + КонецЕсли; + Если ТипЗнч(ВладелецПрав) = ТипГруппыДоступа Тогда + ЕстьИзмененияПравГруппДоступа = Истина; + Иначе + ЕстьИзмененияПравГруппПользователей = Истина; + КонецЕсли; + ИначеЕсли Выборка.ПравоИзменение = Права.ПравоИзменение + И Выборка.ПравоДобавление = Права.ПравоДобавление Тогда + ПраваНаКлюч.Вставить(ВладелецПрав, Null); + КонецЕсли; + КонецЦикла; + + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись.КлючДоступа = КлючДоступа; + + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + + Для Каждого ОписаниеПрав Из ПраваНаКлюч Цикл + Права = ОписаниеПрав.Значение; // См. НовыеПрава + Если Права = Null Тогда + Продолжить; + КонецЕсли; + ВладелецПрав = ОписаниеПрав.Ключ; + Если ПакетныйРежим Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючДоступа = КлючДоступа; + НоваяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + НоваяЗапись.ПравоИзменение = Права.ПравоИзменение; + НоваяЗапись.ПравоДобавление = Права.ПравоДобавление; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + ОднаЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + ОднаЗапись.ПравоИзменение = Права.ПравоИзменение; + ОднаЗапись.ПравоДобавление = Права.ПравоДобавление; + НаборЗаписей.Записать(); + КонецЕсли; + Если ТипЗнч(ВладелецПрав) = ТипГруппыДоступа Тогда + ЕстьИзмененияПравГруппДоступа = Истина; + Иначе + ЕстьИзмененияПравГруппПользователей = Истина; + КонецЕсли; + КоличествоЗаписанных = КоличествоЗаписанных + 1; + КонецЦикла; + + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + + ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); + + ЕстьИзменения.ПраваГруппДоступа = ЕстьИзмененияПравГруппДоступа; + ЕстьИзменения.ПраваГруппПользователей = ЕстьИзмененияПравГруппПользователей; + +КонецПроцедуры + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Процедура ОбновитьИсходныеПраваПользователейНаКлючДоступа(РезультатЗапроса, НаборЗаписей, + ИмяПоляВладельцаПрав, КлючДоступа, ПраваНаКлюч, ЕстьИзмененияПрав, ПараметрыОбновления) + + Выборка = РезультатЗапроса.Выбрать(); + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + КоличествоЗаписанных = 0; + ПередЗаписьюСтрок(ПараметрыОбновления); + + Пока Выборка.Следующий() Цикл + ВладелецПрав = Выборка[ИмяПоляВладельцаПрав]; + Права = ПраваНаКлюч.Получить(ВладелецПрав); // См. НовыеПрава + Если Права = Неопределено Тогда + Если ПакетныйРежим Тогда + СтараяЗапись = НаборЗаписей.Добавить(); + СтараяЗапись.КлючДоступа = КлючДоступа; + СтараяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + НаборЗаписей.Записать(); + КонецЕсли; + ЕстьИзмененияПрав = Истина; + ИначеЕсли Выборка.ПравоИзменение = Права.ПравоИзменение + И Выборка.ПравоДобавление = Права.ПравоДобавление + И Выборка.ЭтоПраваНабораГрупп = Ложь Тогда + ПраваНаКлюч.Вставить(ВладелецПрав, Null); + КонецЕсли; + КонецЦикла; + + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись.КлючДоступа = КлючДоступа; + + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + + Для Каждого ОписаниеПрав Из ПраваНаКлюч Цикл + Права = ОписаниеПрав.Значение; // См. НовыеПрава + Если Права = Null Тогда + Продолжить; + КонецЕсли; + ВладелецПрав = ОписаниеПрав.Ключ; + Если ПакетныйРежим Тогда + НоваяЗапись = НаборЗаписей.Добавить(); + НоваяЗапись.КлючДоступа = КлючДоступа; + НоваяЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + НоваяЗапись.ПравоИзменение = Права.ПравоИзменение; + НоваяЗапись.ПравоДобавление = Права.ПравоДобавление; + НоваяЗапись.ЭтоПраваНабораГрупп = Ложь; + Иначе + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(ВладелецПрав); + ОднаЗапись[ИмяПоляВладельцаПрав] = ВладелецПрав; + ОднаЗапись.ПравоИзменение = Права.ПравоИзменение; + ОднаЗапись.ПравоДобавление = Права.ПравоДобавление; + ОднаЗапись.ЭтоПраваНабораГрупп = Ложь; + НаборЗаписей.Записать(); + КонецЕсли; + ЕстьИзмененияПрав = Истина; + КоличествоЗаписанных = КоличествоЗаписанных + 1; + КонецЦикла; + + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимСлияния); + КонецЕсли; + + ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); + +КонецПроцедуры + +// Для процедуры ОбновитьПраваНаКлючДоступаСписка. +Процедура ОбновитьПроизводныеПраваНаКлючДоступа(РезультатЗапроса, НаборЗаписей, ИмяПоляВладельцаПрав, + КлючДоступа, ЕстьИзменения = Ложь, ПараметрыОбновления = Неопределено) + + Выборка = РезультатЗапроса.Выбрать(); + УдалениеЗавершено = Ложь; + + РежимСлияния = ОбщегоНазначения.РежимСлиянияНабораЗаписей(); + РежимУдаления = ОбщегоНазначения.РежимУдаленияНабораЗаписей(); + ПакетныйРежим = РежимУдаления <> Неопределено И РежимСлияния <> Неопределено; + + КоличествоЗаписанных = 0; + ПередЗаписьюСтрок(ПараметрыОбновления); + + Пока Выборка.Следующий() Цикл + Если Не ПакетныйРежим Тогда + ЭлементОтбора = НаборЗаписей.Отбор[ИмяПоляВладельцаПрав]; // ЭлементОтбора + ЭлементОтбора.Установить(Выборка[ИмяПоляВладельцаПрав]); + КонецЕсли; + Если Не УдалениеЗавершено И Выборка.ВидИзмененияСтроки = 1 Тогда + УдалениеЗавершено = Истина; + Если Не ПакетныйРежим Тогда + ОднаЗапись = НаборЗаписей.Добавить(); + ОднаЗапись.КлючДоступа = КлючДоступа; + ИначеЕсли ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(РежимУдаления); + НаборЗаписей.Очистить(); + КонецЕсли; + КонецЕсли; + Если Не ПакетныйРежим Тогда + Если УдалениеЗавершено Тогда + ЗаполнитьЗначенияСвойств(ОднаЗапись, Выборка); + КонецЕсли; + НаборЗаписей.Записать(); + Иначе + Запись = НаборЗаписей.Добавить(); + Запись.КлючДоступа = КлючДоступа; + ЗаполнитьЗначенияСвойств(Запись, Выборка); + КонецЕсли; + ЕстьИзменения = Истина; + КоличествоЗаписанных = КоличествоЗаписанных + 1; + КонецЦикла; + + Если ПакетныйРежим И ЗначениеЗаполнено(НаборЗаписей) Тогда + НаборЗаписей.Записать(?(УдалениеЗавершено, РежимСлияния, РежимУдаления)); + КонецЕсли; + + ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных); + +КонецПроцедуры + +// Создает служебный элемент справочника, который не участвует в подписках на события. +Функция СлужебныйЭлемент(МенеджерСправочника, Ссылка = Неопределено) + + Если Ссылка = Неопределено Тогда + ЭлементСправочника = МенеджерСправочника.СоздатьЭлемент(); + Иначе + ЭлементСправочника = Ссылка.ПолучитьОбъект(); + Если ЭлементСправочника = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + КонецЕсли; + + ЭлементСправочника.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); + ЭлементСправочника.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); + ЭлементСправочника.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; + ЭлементСправочника.ОбменДанными.Загрузка = Истина; + + Возврат ЭлементСправочника; + +КонецФункции + +// Создает набор записей служебного регистра, который не участвует в подписках на события. +Функция СлужебныйНаборЗаписей(МенеджерРегистра) + + НаборЗаписей = МенеджерРегистра.СоздатьНаборЗаписей(); + НаборЗаписей.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); + НаборЗаписей.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); + НаборЗаписей.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; + НаборЗаписей.ОбменДанными.Загрузка = Истина; + + Возврат НаборЗаписей; + +КонецФункции + +// Создает менеджер значения служебной константы, которая не участвует в подписках на события. +Функция СлужебныйМенеджерЗначения(МенеджерКонстанты) + + МенеджерЗначения = МенеджерКонстанты.СоздатьМенеджерЗначения(); + МенеджерЗначения.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); + МенеджерЗначения.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); + МенеджерЗначения.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; + МенеджерЗначения.ОбменДанными.Загрузка = Истина; + + Возврат МенеджерЗначения; + +КонецФункции + +// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступа. +Процедура ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале(Списки, ПараметрыПланирования) + + КомментарийДляЖурнала = НСтр("ru = 'Источник'", ОбщегоНазначения.КодОсновногоЯзыка()) + + ": " + ПараметрыПланирования.Описание + Символы.ПС; + + Если Списки.Количество() > 1 Тогда + КомментарийДляЖурнала = КомментарийДляЖурнала + + НСтр("ru = 'Списки'", ОбщегоНазначения.КодОсновногоЯзыка()) + ":" + + Символы.ПС + Символы.Таб + СтрСоединить(Списки, Символы.ПС + Символы.Таб); + Иначе + КомментарийДляЖурнала = КомментарийДляЖурнала + + НСтр("ru = 'Список'", ОбщегоНазначения.КодОсновногоЯзыка()); + + КомментарийДляЖурнала = КомментарийДляЖурнала + " = " + Списки[0]; + КонецЕсли; + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоТочечноеЗадание" + + " = " + ?(ПараметрыПланирования.Свойство("ЭтоТочечноеЗадание"), "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "КлючиДоступаКДанным" + + " = " + ?(ПараметрыПланирования.КлючиДоступаКДанным, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "РазрешенныеКлючиДоступа" + + " = " + ?(ПараметрыПланирования.РазрешенныеКлючиДоступа, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ДляПользователей" + + " = " + ?(ПараметрыПланирования.ДляПользователей, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ДляВнешнихПользователей" + + " = " + ?(ПараметрыПланирования.ДляВнешнихПользователей, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоПродолжениеОбновления" + + " = " + ?(ПараметрыПланирования.ЭтоПродолжениеОбновления, "Да", "Нет"); + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + "ЭтоОбработкаУстаревшихЭлементов" + + " = " + ?(ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов, "Да", "Нет"); + + ВедущийОбъект = Неопределено; + ОписаниеВедущегоОбъекта = ПараметрыПланирования.ВедущийОбъект; // См. ОписаниеВедущегоОбъекта + + Если ТипЗнч(ОписаниеВедущегоОбъекта) = Тип("Структура") Тогда + Если ОписаниеВедущегоОбъекта.Свойство("ПоЗначениямПолей") Тогда + Указатели = ОписаниеВедущегоОбъекта.ПоЗначениямПолей.Описание; + ВедущийОбъект = "ПоЗначениямПолей"; + ИначеЕсли ОписаниеВедущегоОбъекта.Свойство("ПоКлючамДоступа") Тогда + Указатели = ОписаниеВедущегоОбъекта.ПоКлючамДоступа; + ВедущийОбъект = "ПоКлючамДоступа"; + ИначеЕсли ОписаниеВедущегоОбъекта.Свойство("ПоЗначениямСГруппами") Тогда + Указатели = ОписаниеВедущегоОбъекта.ПоЗначениямСГруппами; + ВедущийОбъект = "ПоЗначениямСГруппами"; + КонецЕсли; + Если ВедущийОбъект <> Неопределено Тогда + Если ТипЗнч(Указатели) = Тип("Массив") И Указатели.Количество() > 1 Тогда + ВедущийОбъект = ВедущийОбъект + ":"; + Для Каждого Указатель Из Указатели Цикл + ВедущийОбъект = ВедущийОбъект + Символы.ПС + """" + Строка(Указатель) + """ " + + ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования); + КонецЦикла; + Иначе + Указатель = ?(ТипЗнч(Указатели) = Тип("Массив"), Указатели[0], Указатели); + ВедущийОбъект = ВедущийОбъект + ": """ + Строка(Указатель) + """ " + + ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования); + КонецЕсли; + КонецЕсли; + Если ОписаниеВедущегоОбъекта.Свойство("ПоДаннымКэшаРасчетаПрав") Тогда + ВедущийОбъект = "ПоДаннымКэшаРасчетаПрав" + ": """ + + ОписаниеВедущегоОбъекта.ПоДаннымКэшаРасчетаПрав; + КонецЕсли; + КонецЕсли; + + Попытка + ВызватьИсключение НСтр("ru = 'Стек вызовов'"); + Исключение + СтекВызовов = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()); + КонецПопытки; + + КомментарийДляЖурнала = КомментарийДляЖурнала + Символы.ПС + Символы.ПС + СтекВызовов; + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Показатели.Планирование обновления доступа'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, , + ВедущийОбъект, + КомментарийДляЖурнала, + ?(ТранзакцияАктивна(), РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная, Неопределено)); + +КонецПроцедуры + +// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале. +Функция ОписаниеУказателяВедущегоОбъекта(Указатель, ПараметрыПланирования) + + Если ПараметрыПланирования.Свойство("ТиповСсылокВедущихОбъектов") Тогда + ТипыСсылок = ПараметрыПланирования.ТиповСсылокВедущихОбъектов; + Иначе + ТипыСсылок = УправлениеДоступомСлужебныйПовтИсп.ТиповСсылокВедущихОбъектов(); + ПараметрыПланирования.Вставить("ТиповСсылокВедущихОбъектов", ТипыСсылок); + КонецЕсли; + + Если ТипыСсылок.Получить(ТипЗнч(Указатель)) <> Неопределено Тогда + Возврат ПолучитьНавигационнуюСсылку(Указатель); + КонецЕсли; + + Описание = ""; + Для Каждого ЭлементОтбора Из Указатель Цикл + Если Не ЭлементОтбора.Использование Тогда + Продолжить; + КонецЕсли; + Если ТипыСсылок.Получить(ТипЗнч(ЭлементОтбора.Значение)) <> Неопределено Тогда + ОписаниеЗначения = ПолучитьНавигационнуюСсылку(ЭлементОтбора.Значение); + ИначеЕсли ТипЗнч(ЭлементОтбора.Значение) = Тип("Неопределено") Тогда + ОписаниеЗначения = НСтр("ru = 'Неопределено'"); + Иначе + ОписаниеЗначения = Формат(ЭлементОтбора.Значение, "ЧН=0; ДП='01.01.0001 00:00:00'"); + КонецЕсли; + Описание = Описание + ?(Описание = "", "", ", ") + + ЭлементОтбора.Имя + " = " + ОписаниеЗначения; + КонецЦикла; + + Возврат Описание; + +КонецФункции + +// Для вызова из мест планирования обновления доступа. +Процедура ЗарегистрироватьПланированиеОбновленияДоступа(СпискиПоИдентификаторам, ПараметрыПланирования, ВсеСписки = Ложь) + + Если Не РегистрироватьПоказателиПланированияОбновленияДоступа() + Или Не ПользователиСлужебный.ВключенаЗаписьИнформацииВЖурнал() Тогда + Возврат; + КонецЕсли; + + Если ПараметрыПланирования = Неопределено Тогда + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + КонецЕсли; + + Списки = Новый Массив; + + Если Не ВсеСписки Тогда + Если ПараметрыПланирования.ИдентификаторыВсехСписков <> Неопределено Тогда + ВсеПолныеИменаПоИдентификаторам = Новый Соответствие; + Для Каждого КлючИЗначение Из ПараметрыПланирования.ИдентификаторыВсехСписков Цикл + ВсеПолныеИменаПоИдентификаторам.Вставить(КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЦикла; + КонецЕсли; + Для Каждого ОписаниеСписка Из СпискиПоИдентификаторам Цикл + Если ЗначениеЗаполнено(ОписаниеСписка.Значение) Тогда + Списки.Добавить(ОписаниеСписка.Значение); + Иначе + Списки.Добавить(ПолноеИмяСписка(ОписаниеСписка.Ключ, ВсеПолныеИменаПоИдентификаторам)); + КонецЕсли; + КонецЦикла; + Иначе + Списки.Добавить("Все"); + КонецЕсли; + + ЗарегистрироватьПланированиеОбновленияДоступаВЖурнале(Списки, ПараметрыПланирования); + +КонецПроцедуры + +// Для процедуры ЗарегистрироватьПланированиеОбновленияДоступа. +Функция ПолноеИмяСписка(ОписаниеСписка, ВсеПолныеИменаПоИдентификаторам) + + Если ТипЗнч(ОписаниеСписка) = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") + Или ТипЗнч(ОписаниеСписка) = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда + + Если ВсеПолныеИменаПоИдентификаторам = Неопределено Тогда + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(ОписаниеСписка, Ложь); + Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда + Возврат ОбъектМетаданных.ПолноеИмя(); + КонецЕсли; + Иначе + ПолноеИмя = ВсеПолныеИменаПоИдентификаторам.Получить(ОписаниеСписка); + КонецЕсли; + + Если ПолноеИмя <> Неопределено Тогда + Возврат ПолноеИмя; + Иначе + Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ОписаниеСписка, "ПолноеИмя"); + КонецЕсли; + Иначе + Возврат Строка(ОписаниеСписка); + КонецЕсли; + +КонецФункции + +// Для процедуры УправлениеДоступом.ОтключитьОбновлениеКлючейДоступа. +// +// Параметры: +// Списки - Массив +// ДобавленныеСписки - Соответствие +// НедоступныеСписки - Массив - возвращаемое значение. +// +Процедура ДобавитьЗависимыеСписки(Списки, ДобавленныеСписки, НедоступныеСписки) Экспорт + + ИсходныеСписки = Новый ФиксированныйМассив(Списки); + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + + НенайденныеСписки = Новый Массив; + + Для Каждого ИсходныйСписок Из ИсходныеСписки Цикл + Свойства = ДействующиеПараметры.ВедущиеСписки.Получить(ИсходныйСписок); + Если Свойства = Неопределено Тогда + Продолжить; + КонецЕсли; + Для Каждого КлючИЗначение Из Свойства.ЗависимыеСписки Цикл + Если ДобавленныеСписки.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(КлючИЗначение.Ключ); + Если ОбъектМетаданных = Неопределено Тогда + НенайденныеСписки.Добавить(КлючИЗначение.Ключ); + Иначе + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + Списки.Добавить(ПолноеИмя); + ДобавленныеСписки.Вставить(ПолноеИмя, Истина); + КонецЕсли; + ДобавленныеСписки.Вставить(КлючИЗначение.Ключ, Истина); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Если НенайденныеСписки.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + НедоступныеСписки = ВсеИдентификаторыСПодобнымиПолнымиИменами(НенайденныеСписки); + +КонецПроцедуры + +Функция ОписаниеОграниченийДанных() Экспорт + + ОбщийКонтекст = Новый Структура; + ОбщийКонтекст.Вставить("СпискиСОграничением", УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением()); + + Результат = Новый Соответствие; + + Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); + Результат.Вставить(ПолноеИмя, ОписаниеОграничения); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +#Область ПараметрыДляПереопределенияЧерезРасширениеКонфигурации + +Функция КоличествоЧасовУстареванияНеиспользуемыхЭлементов() + + Возврат 47; + +КонецФункции + +Функция КоличествоЧасовМеждуПланированиемОбработкиУстаревшихЭлементов() + + Возврат 48; + +КонецФункции + +Функция МаксимальноеКоличествоМинутВыполненияФоновогоЗаданияОбновленияДоступа() + + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Возврат 2; + Иначе + Возврат 15; + КонецЕсли; + +КонецФункции + +Функция МаксимальноеКоличествоСекундОжиданияВыполненияОдногоЗаданияВПотоке() Экспорт + + Возврат 900; // 15 минут (например, избыточно длительный запрос SQL). + +КонецФункции + +Функция МинимальноеКоличествоСекундОбработкиПорцииВОтдельномПотоке() + + Возврат 1; + +КонецФункции + +Функция МинимальноеКоличествоСекундВыполненияТочечногоЗадания() + + Возврат 15; + +КонецФункции + +Функция ЗагружатьСвободныеПотокиСледующимиЗаданиямиПриДлительныхЗапросах() + + Возврат Истина; + +КонецФункции + +Функция МаксимальныйПериодПолученияПорцийЗапросом() + + Возврат "Год"; // Год, Квартал, Месяц, Неделя. + +КонецФункции + +Функция ЗапускатьОбновлениеПолученныхПорцийПриПолученииНовыхПорций() + + Возврат Ложь; + +КонецФункции + +Функция МаксимальноеКоличествоСекундБыстрогоПолученияПорцийЭлементовДанных() + + Возврат 15; // 0 - отключить балансировку нагрузки на диск. + +КонецФункции + +Функция КоличествоЭлементовДанныхВЗапросе() + + Возврат 1000; + +КонецФункции + +Функция КоличествоЭлементовДанныхВПорции() + + Возврат 1000; + +КонецФункции + +Функция КоличествоКлючейДоступаВЗапросе() + + Возврат 1000; + +КонецФункции + +Функция КоличествоКлючейДоступаВПорции() + + Возврат 200; + +КонецФункции + +Функция ЗаписыватьТолькоИзмененныеКлючиДоступаЭлементовДанных() + + Возврат Ложь; + +КонецФункции + +Функция МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных() + + Возврат 100; + +КонецФункции + +Функция КоличествоСекундПередОтключениемРегламентногоЗаданияПослеПолногоЗавершенияОбновления() + + Возврат 15; + +КонецФункции + +Функция ЗапускатьОбновлениеДоступаДляУскоренияТолькоТочечныхЗаданий(ПроверкаПриЗапуске) + + Результат = Ложь; + + Если ОбщегоНазначения.РазделениеВключено() Тогда + Результат = Истина; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Функция РегистрироватьПоказателиОбновленияДоступа() + + Возврат Истина; + +КонецФункции + +Функция РегистрироватьПоказателиПланированияОбновленияДоступа() + + Возврат Ложь; + +КонецФункции + +Функция РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() + + Возврат Ложь; + +КонецФункции + +#КонецОбласти + +#Область ТочкиПодключенияДляАнализаПроизводительностиЧерезРасширениеКонфигурации + +Процедура ПередБлокировкойДанных(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеБлокировкиДанных(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомТекущихКлючейДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаТекущихКлючейДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗаписьюСтрок(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗаписиСтрок(ПараметрыОбновления, КоличествоЗаписанных) + Возврат; +КонецПроцедуры + +Процедура ПередФиксациейТранзакции(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеФиксацииТранзакции(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередПланированиемОбновления(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеПланированияОбновления(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗаписьюНовогоКлюча(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗаписиНовогоКлюча(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомПравГруппДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаПравГруппДоступа(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомИзмененийПроизводныхПрав(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаИзмененийПроизводныхПрав(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередЗапросомПравПользователей(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПослеЗапросаПравПользователей(ПараметрыОбновления) + Возврат; +КонецПроцедуры + +Процедура ПередИзменениемПараметровСеансаДляШаблонов(НовыеЗначения, ЭтоУстановка) + Возврат; +КонецПроцедуры + +Процедура ПриОшибкеПроверкиАктуальностиМетаданных(ТекстОшибки) + Возврат; +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область ПараметрыОграниченияДоступа + +#Область ПараметрыОграниченияДоступаОбщаяЧасть + +// Основная функция, возвращающая параметры, необходимые для регистрации +// необходимости обновления ключей доступа к элементам данных. +// +// Параметры: +// ПолноеИмя - Строка - полное имя списка +// ИдентификаторТранзакции - УникальныйИдентификатор +// ПовторныйВызов - Булево - только при вызове из самой же функции +// +// Возвращаемое значение: +// Структура: +// * ЗависимыеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка. +// ** Значение - Булево - Истина. +// * ПоЗначениямПолей - см. ВедущийСписокПоЗначениямПолей +// * ПоКлючамДоступа - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// * ПоЗначениямСГруппами - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// +Функция СвойстваСпискаКакВедущего(ПолноеИмя, ИдентификаторТранзакции = Неопределено, ПовторныйВызов = Ложь) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, Неопределено, ПовторныйВызов); + ХранимыеСвойстваСпискаКакВедущего = ДействующиеПараметры.ВедущиеСписки.Получить(ПолноеИмя); + + Если ХранимыеСвойстваСпискаКакВедущего = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Кэш = КэшПараметровОграничения(); + + СвойстваСпискаКакВедущего = Кэш.ВедущиеСпискиПроверенные.Получить(ПолноеИмя); + Если СвойстваСпискаКакВедущего <> Неопределено Тогда + Возврат СвойстваСпискаКакВедущего; + КонецЕсли; + + СвойстваСпискаКакВедущего = Новый Структура(ХранимыеСвойстваСпискаКакВедущего); + Отказ = Ложь; + ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка(ПолноеИмя, + СвойстваСпискаКакВедущего, Отказ); + + Если Не Отказ Тогда + Кэш.ВедущиеСпискиПроверенные.Вставить(ПолноеИмя, + Новый ФиксированнаяСтруктура(СвойстваСпискаКакВедущего)); + + Возврат СвойстваСпискаКакВедущего; + КонецЕсли; + + Если ПовторныйВызов Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось подготовить свойства списка ""%1"" как ведущего, + |из-за некорректного состояния параметров ограничения доступа.'"), + ПолноеИмя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Возврат СвойстваСпискаКакВедущего(ПолноеИмя, ИдентификаторТранзакции, Истина); + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ВедущиеСпискиПроверенные - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. УправлениеДоступомСлужебный.СвойстваСпискаКакВедущего +// * ОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. УправлениеДоступомСлужебный.РассчитанныеПараметрыОграничения +// * ИдентификаторыТранзакции - Соответствие из КлючИЗначение: +// ** Ключ - УникальныйИдентификатор - произвольный УИД. +// ** Значение - Булево - значение Истина. +// * ВидыОграниченийПравДляПользователей - Неопределено +// - Строка +// * ВидыОграниченийПравДляВнешнихПользователей - Неопределено +// - Строка +// +Функция НовыйКэшПараметровОграничения() Экспорт + + Хранилище = Новый Структура; + Хранилище.Вставить("ВедущиеСпискиПроверенные", Новый Соответствие); + Хранилище.Вставить("ОграниченияСписков", Новый Соответствие); + Хранилище.Вставить("ИдентификаторыТранзакции", Новый Соответствие); + Хранилище.Вставить("ВидыОграниченийПравДляПользователей", Неопределено); + Хранилище.Вставить("ВидыОграниченийПравДляВнешнихПользователей", Неопределено); + + Возврат Хранилище; + +КонецФункции + +// Для функции СвойстваСпискаКакВедущего и процедур ЗаполнитьПараметрыОграничения, +// ОбновитьИдентификаторыТранзакции, УстановитьВерсиюПараметров. +// +Функция КэшПараметровОграничения() + + КлючДанныхПовторногоИспользования = Строка(ПараметрыСеанса.КлючДанныхПовторногоИспользования); + + Возврат УправлениеДоступомСлужебныйПовтИсп.КэшПараметровОграничения(КлючДанныхПовторногоИспользования); + +КонецФункции + +Процедура СброситьКэшПараметровОграничения() + + Кэш = КэшПараметровОграничения(); + НовыйКэш = НовыйКэшПараметровОграничения(); + + Для Каждого КлючИЗначение Из НовыйКэш Цикл + Кэш.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для функции СвойстваСпискаКакВедущего. +Процедура ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка(ПолноеИмя, Свойства, Отказ) + + Свойства.Удалить("ЗависимыеСписки"); + Если Свойства.ПоЗначениямПолей = Неопределено Тогда + Возврат; + КонецЕсли; + + ПоЗначениямПолей = Новый Структура(Свойства.ПоЗначениямПолей); // См. ВедущийСписокПоЗначениямПолей + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); + + Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда + Если ЗначениеЗаполнено(ПоЗначениямПолей.ПоляШапки.ВсеПоля) Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | (ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина) КАК ЗначениеИстина + | ЛЕВОЕ СОЕДИНЕНИЕ ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица + | ПО (ТекущаяТаблица.Ссылка = &СсылкаНаОбъект)"; + ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, + ПолноеИмя, ПоЗначениямПолей.ПоляШапки.ВсеПоля, ОбъектМетаданных, Отказ); + Иначе + ТекстЗапроса = ""; + КонецЕсли; + + Для Каждого ТабличнаяЧасть Из ПоЗначениямПолей.ТабличныеЧасти Цикл + Коллекции = Новый Структура("СтандартныеТабличныеЧасти, ТабличныеЧасти"); + ТабличнаяЧастьИмя = ТабличнаяЧасть.Имя; + ЗаполнитьЗначенияСвойств(Коллекции, ОбъектМетаданных); + МетаданныеТаблицы = Неопределено; + Если ТипЗнч(Коллекции.ТабличныеЧасти) = Тип("КоллекцияОбъектовМетаданных") Тогда + МетаданныеТаблицы = ОбъектМетаданных.ТабличныеЧасти.Найти(ТабличнаяЧастьИмя); + КонецЕсли; + Если МетаданныеТаблицы = Неопределено + И ТипЗнч(Коллекции.СтандартныеТабличныеЧасти) = Тип("ОписанияСтандартныхТабличныхЧастей") Тогда + Для Каждого СтандартнаяТабличнаяЧасть Из Коллекции.СтандартныеТабличныеЧасти Цикл + СтандартнаяТабличнаяЧасть = СтандартнаяТабличнаяЧасть; // ОписаниеСтандартнойТабличнойЧасти + Если СтандартнаяТабличнаяЧасть.Имя = ТабличнаяЧастьИмя Тогда + МетаданныеТаблицы = СтандартнаяТабличнаяЧасть; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если МетаданныеТаблицы = Неопределено Тогда + Отказ = Истина; + Прервать; + КонецЕсли; + + ТекстЗапросаТабличнойЧасти = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100 + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица + |ГДЕ + | ТекущаяТаблица.Ссылка = &СсылкаНаОбъект"; + ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапросаТабличнойЧасти, + ПолноеИмя + "." + ТабличнаяЧастьИмя, ТабличнаяЧасть.ВсеПоля, МетаданныеТаблицы, Отказ, Истина); + + ТекстЗапроса = ТекстЗапроса + ?(ТекстЗапроса = "", "", + ОбщегоНазначения.РазделительПакетаЗапросов()) + ТекстЗапросаТабличнойЧасти; + КонецЦикла; + + ИначеЕсли ЗначениеЗаполнено(ПоЗначениямПолей.ПоляШапки.ВсеПоля) Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 100 + | ТекущаяТаблица.Поле1 КАК Поле1 + |ИЗ + | ТекущаяТаблицаЭлементовДанных КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям"; + ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, + ПолноеИмя, ПоЗначениямПолей.ПоляШапки.ВсеПоля, ОбъектМетаданных, Отказ); + Иначе + ТекстЗапроса = ""; + КонецЕсли; + + ПоЗначениямПолей.Вставить("ТекстЗапроса", ТекстЗапроса); + Свойства.ПоЗначениямПолей = Новый ФиксированнаяСтруктура(ПоЗначениямПолей); + +КонецПроцедуры + +// Для процедуры ЗаполнитьТекстЗапросаСтарыхЗначенийДляПроверкиИзмененияПолейВедущегоСписка. +Процедура ЗаполнитьПоляВыбораТекущейТаблицы(ТекстЗапроса, ПолноеИмя, ОписаниеПолей, + МетаданныеТаблицы, Отказ, ЭтоТабличнаяЧасть = Ложь) + + КоллекцииПолей = Новый Структура("Реквизиты, Измерения, Ресурсы, СтандартныеРеквизиты"); + ЗаполнитьЗначенияСвойств(КоллекцииПолей, МетаданныеТаблицы); + + ПоляВыбора = ""; + Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл + ИмяПоля = ?(ТипЗнч(ОписаниеПолей) = Тип("ФиксированныйМассив"), ОписаниеПоля, ОписаниеПоля.Ключ); + + Если Не ПолеСуществует(КоллекцииПолей.Реквизиты, ИмяПоля) + И Не ПолеСуществует(КоллекцииПолей.Измерения, ИмяПоля) + И Не ПолеСуществует(КоллекцииПолей.Ресурсы, ИмяПоля) + И Не ПолеСуществует(КоллекцииПолей.СтандартныеРеквизиты, ИмяПоля) + И Не (ЭтоТабличнаяЧасть + И (ВРег(ИмяПоля) = ВРег("Ссылка") + Или ВРег(ИмяПоля) = ВРег("Ref"))) Тогда // @Non-NLS + + Отказ = Истина; + Прервать; + КонецЕсли; + + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", "," + Символы.ПС) + + "ТекущаяТаблица." + ИмяПоля + " КАК " + ИмяПоля; // @query-part-5 + КонецЦикла; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекущаяТаблица.Поле1 КАК Поле1", ТекстСОтступом(СокрЛ(ПоляВыбора), " ")); // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущаяТаблицаЭлементовДанных", ПолноеИмя); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПЕРВЫЕ 100", "ПЕРВЫЕ " + Формат( + МаксимальноеКоличествоКомбинацийЗначенийВедущихПолейПриВычисленииСоставаИзмененных() * 10, "ЧГ=")); // @query-part-1, @query-part-2 + +КонецПроцедуры + +// Для процедуры ЗаполнитьПоляВыбораТекущейТаблицы. +Функция ПолеСуществует(Коллекция, ИмяПоля) + + Если ТипЗнч(Коллекция) = Тип("КоллекцияОбъектовМетаданных") Тогда + Возврат Коллекция.Найти(ИмяПоля) <> Неопределено; + + ИначеЕсли ТипЗнч(Коллекция) = Тип("ОписанияСтандартныхРеквизитов") Тогда + Для Каждого СтандартныйРеквизит Из Коллекция Цикл + Если СтандартныйРеквизит.Имя = ИмяПоля Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +// Основная функция, возвращающая параметры, необходимые для проверки прав в момент записи элементов данных. +// +// Возвращаемое значение: +// см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция ПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции = Неопределено, ДляВнешнихПользователей = Неопределено) Экспорт + + УстановитьОтключениеБезопасногоРежима(Истина); + УстановитьПривилегированныйРежим(Истина); + + ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, Неопределено, Ложь); + Параметры = КэшПараметровОграничения().ОграниченияСписков.Получить(ПолноеИмя); + + Если Параметры = Неопределено Тогда + ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры); + КонецЕсли; + + Если ДляВнешнихПользователей = Null Тогда + Возврат Параметры; + КонецЕсли; + + Если ДляВнешнихПользователей = Неопределено Тогда + ДляВнешнихПользователей = Пользователи.ЭтоСеансВнешнегоПользователя(); + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + Возврат Параметры.ДляВнешнихПользователей; + КонецЕсли; + + Возврат Параметры.ДляПользователей; + +КонецФункции + +// Для функций СвойстваСпискаКакВедущего, ПараметрыОграничения. +Процедура ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры, + ОбщийКонтекст = Неопределено, ПовторныйВызов = Ложь) + + Если ОбщийКонтекст = Неопределено Тогда + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(ПолноеИмя); + ОбщийКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); + КонецЕсли; + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, Ложь); + + ВерсияОграничений = ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя); + ЕстьОшибка = Ложь; + Попытка + РассчитанныеПараметры = РассчитанныеПараметрыОграничения(ПолноеИмя, ОбщийКонтекст, ДействующиеПараметры); + Исключение + Если ПовторныйВызов Тогда + ВызватьИсключение; + КонецЕсли; + Попытка + Значение = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + Исключение + Значение = Неопределено; + КонецПопытки; + Если Значение = Неопределено Тогда + ВызватьИсключение; + КонецЕсли; + ЕстьОшибка = Истина; + КонецПопытки; + + Если ЕстьОшибка Или ВерсияОграничений <> РассчитанныеПараметры.Версия Тогда + Если ПовторныйВызов Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить параметры ограничения доступа списка ""%1"" + |из-за нестабильной строки свойств версии параметров для вычисления хеш-суммы.'"), + ПолноеИмя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, Истина); + ЗаполнитьПараметрыОграничения(ПолноеИмя, ИдентификаторТранзакции, Параметры, ОбщийКонтекст, Истина); + Возврат; + КонецЕсли; + + Параметры = ОбщегоНазначения.ФиксированныеДанные(РассчитанныеПараметры); + + КэшПараметровОграничения().ОграниченияСписков.Вставить(ПолноеИмя, Параметры); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыОграничения и функций +// ХранимыеПараметрыОграниченияДоступа, ОшибкиОграниченийДоступа. +// +// Возвращаемое значение: +// Структура: +// * СвойстваВидовДоступа - см. СвойстваВидовДоступа +// * ТипыПользователя - Массив из Тип +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ОтдельныеТаблицыНастроекПрав - ФиксированноеСоответствие +// * ВнешниеПользователиВключены - Булево +// * ИспользуемыеТипыЗначений - см. ИспользуемыеТипыЗначений +// * СпискиСОграничением - см. УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением +// +Функция ОбщийКонтекстРасчетаПараметровОграничения(ПолноеИмя = Неопределено, + ВсеВидыДоступаИспользуются = Неопределено, ЗаполнитьСпискиСОграничением = Истина) + + ТипыПользователя = Новый Массив; + ТипыПользователя.Добавить(Тип("СправочникСсылка.Пользователи")); + ТипыПользователя.Добавить(Тип("СправочникСсылка.ГруппыПользователей")); + ТипыПользователя.Добавить(Тип("СправочникСсылка.ВнешниеПользователи")); + ТипыПользователя.Добавить(Тип("СправочникСсылка.ГруппыВнешнихПользователей")); + + ОграничениеДоступаВключено = Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(); + Если УправлениеДоступом.ОграничиватьДоступНаУровнеЗаписей() <> ОграничениеДоступаВключено Тогда + ОбновитьПовторноИспользуемыеЗначения(); + КонецЕсли; + СвойстваВидовДоступа = СвойстваВидовДоступа(); + + ИспользуемыеТипыЗначений = ИспользуемыеТипыЗначений(СвойстваВидовДоступа, ПолноеИмя, ВсеВидыДоступаИспользуются); + Если ТипЗнч(ВсеВидыДоступаИспользуются) = Тип("Булево") Тогда + ОграничениеДоступаВключено = ВсеВидыДоступаИспользуются; + ВнешниеПользователиВключены = ВсеВидыДоступаИспользуются; + Иначе + ВнешниеПользователиВключены = Константы.ИспользоватьВнешнихПользователей.Получить(); + КонецЕсли; + + ВозможныеПрава = ВозможныеПраваДляНастройкиПравОбъектов(); + + ОбщийКонтекст = Новый Структура; + ОбщийКонтекст.Вставить("СвойстваВидовДоступа", СвойстваВидовДоступа); + ОбщийКонтекст.Вставить("ТипыПользователя", ТипыПользователя); + ОбщийКонтекст.Вставить("ТипыВладельцевНастроекПрав", ВозможныеПрава.ПоТипамСсылок); + ОбщийКонтекст.Вставить("ОтдельныеТаблицыНастроекПрав", ВозможныеПрава.ОтдельныеТаблицы); + ОбщийКонтекст.Вставить("ВнешниеПользователиВключены", ВнешниеПользователиВключены); + ОбщийКонтекст.Вставить("ОграничениеДоступаВключено", ОграничениеДоступаВключено); + ОбщийКонтекст.Вставить("ИспользуемыеТипыЗначений", ИспользуемыеТипыЗначений); + + Если ЗаполнитьСпискиСОграничением Тогда + ОбщийКонтекст.Вставить("СпискиСОграничением", УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением()); + КонецЕсли; + + Возврат ОбщийКонтекст; + +КонецФункции + +// Для функций ОбщийКонтекстРасчетаПараметровОграничения и ИспользованиеВидовДоступаИзменено. +// +// Параметры: +// СвойстваВидовДоступа - см. СвойстваВидовДоступа +// ПолноеИмя - Строка +// ВсеВидыДоступаИспользуются - Неопределено +// - Булево +// ТолькоХешСумма - Булево +// +// Возвращаемое значение: +// Структура: +// * ДляИБ - Соответствие из КлючИЗначение: +// ** Ключ - Тип +// ** Значение - Булево - Истина +// * ПоТаблицам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя объекта метаданных +// ** Значение - Соответствие из КлючИЗначение: +// *** Ключ - Тип +// *** Значение - Булево - Истина +// * ХешСумма - Строка - контрольная сумма настроек использования ДляИБ и ПоТаблицам. +// * ПолноеИмяТаблицы - Строка - полное имя таблицы, когда свойство ПоТаблицам +// заполнено только для одной таблицы. +// - Неопределено - когда свойство ПоТаблицам не заполнялось (ВсеВидыДоступаИспользуются = Истина). +// +Функция ИспользуемыеТипыЗначений(СвойстваВидовДоступа, ПолноеИмя = Неопределено, ВсеВидыДоступаИспользуются = Неопределено, ТолькоХешСумма = Ложь) + + ИспользуемыеТипыЗначений = Новый Структура; + ИспользуемыеТипыЗначений.Вставить("ДляИБ", Новый Соответствие); + ИспользуемыеТипыЗначений.Вставить("ПоТаблицам", Новый Соответствие); + ИспользуемыеТипыЗначений.Вставить("ХешСумма", ""); + ИспользуемыеТипыЗначений.Вставить("ПолноеИмяТаблицы", ""); + + Если ВсеВидыДоступаИспользуются = Ложь Тогда + Возврат ИспользуемыеТипыЗначений; + КонецЕсли; + + Если ВсеВидыДоступаИспользуются = Истина Тогда + ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Неопределено; + Иначе + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | ИспользуемыеВидыДоступа.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа + |ГДЕ + | ИспользуемыеВидыДоступа.Используется = ИСТИНА + | И &ОграничиватьДоступНаУровнеЗаписей + | + |УПОРЯДОЧИТЬ ПО + | ТипЗначенийДоступа + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ИспользуемыеВидыДоступаПоТаблицам.Таблица КАК Таблица, + | ИспользуемыеВидыДоступаПоТаблицам.ТипЗначенийДоступа КАК ТипЗначенийДоступа + |ИЗ + | РегистрСведений.ИспользуемыеВидыДоступаПоТаблицам КАК ИспользуемыеВидыДоступаПоТаблицам + |ГДЕ + | ИспользуемыеВидыДоступаПоТаблицам.Таблица = &Таблица + | + |УПОРЯДОЧИТЬ ПО + | Таблица, + | ТипЗначенийДоступа"; + + Если ПолноеИмя <> Неопределено Тогда + Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ПолноеИмя, Ложь); + Если Идентификатор <> Null Тогда + Запрос.УстановитьПараметр("Таблица", Идентификатор); + КонецЕсли; + КонецЕсли; + Если ПолноеИмя = Неопределено Или Идентификатор = Null Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ИспользуемыеВидыДоступаПоТаблицам.Таблица = &Таблица", "ИСТИНА"); + Иначе + ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = ПолноеИмя; + КонецЕсли; + СтрокаОграничениеДоступаВключено = + ?(Константы.ОграничиватьДоступНаУровнеЗаписей.Получить(), "ИСТИНА", "ЛОЖЬ"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОграничиватьДоступНаУровнеЗаписей", + СтрокаОграничениеДоступаВключено); + + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Используемые = РезультатыЗапроса[0].Выгрузить(); + ИспользуемыеПоТаблицам = РезультатыЗапроса[1].Выгрузить(); + Если ПолноеИмя = Неопределено Тогда + Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); + Хеширование.Добавить(СтрокаОграничениеДоступаВключено); + Хеширование.Добавить(СтрокаДанныхДляХеширования(Используемые)); + Хеширование.Добавить(СтрокаДанныхДляХеширования(ИспользуемыеПоТаблицам)); + ИспользуемыеТипыЗначений.ХешСумма = Base64Строка(Хеширование.ХешСумма); + Если ТолькоХешСумма Тогда + Возврат ИспользуемыеТипыЗначений; + КонецЕсли; + КонецЕсли; + Таблицы = ИспользуемыеПоТаблицам.Скопировать(, "Таблица"); + Таблицы.Свернуть("Таблица"); + Идентификаторы = Таблицы.ВыгрузитьКолонку("Таблица"); + ОбъектыМетаданных = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, Ложь); + ТекущаяТаблица = Неопределено; + Для Каждого Строка Из ИспользуемыеПоТаблицам Цикл + Если ТекущаяТаблица <> Строка.Таблица Тогда + ОбъектМетаданных = ОбъектыМетаданных.Получить(Строка.Таблица); + Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда + Продолжить; + КонецЕсли; + ТекущееПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ТекущаяТаблица = Строка.Таблица; + ТекущиеИспользуемыеТипы = Новый Соответствие; + ИспользуемыеТипыЗначений.ПоТаблицам.Вставить(ТекущееПолноеИмя, ТекущиеИспользуемыеТипы); + КонецЕсли; + ТекущиеИспользуемыеТипы.Вставить(ТипЗнч(Строка.ТипЗначенийДоступа), Истина); + КонецЦикла; + КонецЕсли; + + СвойстваВидовДоступаМассив = СвойстваВидовДоступа.Массив; // Массив Из см. СвойстваВидаДоступа + Для Каждого СвойстваВидаДоступа Из СвойстваВидовДоступаМассив Цикл + Если ВсеВидыДоступаИспользуются <> Истина + И Используемые.Найти(СвойстваВидаДоступа.Ссылка) = Неопределено Тогда + Продолжить; + КонецЕсли; + ИспользуемыеТипыЗначений.ДляИБ.Вставить(СвойстваВидаДоступа.ТипЗначений, Истина); + Для Каждого ОписаниеДополнительногоТипа Из СвойстваВидаДоступа.ДополнительныеТипы Цикл + ИспользуемыеТипыЗначений.ДляИБ.Вставить(ОписаниеДополнительногоТипа.ТипЗначений, Истина); + КонецЦикла; + КонецЦикла; + + Возврат ИспользуемыеТипыЗначений; + +КонецФункции + +// Для процедуры ДобавитьПараметрыОграниченияСписка. +// +// Возвращаемое значение: +// Структура: +// * Версия - Строка +// * ВедущиеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СвойстваСпискаКакВедущего +// * ДляПользователей - см. ПараметрыОграниченияПоСтруктуреОграничения +// * ДляВнешнихПользователей - см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция РассчитанныеПараметрыОграничения(ПолноеИмя, ОбщийКонтекст, ДействующиеПараметры) Экспорт + + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); + + // Для пользователей. + СтруктураОграниченияДляПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.Текст, ОписаниеОграничения.ТекстВМодулеМенеджера, Ложь); + + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДополнительныйКонтекст, ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Ложь); + + РезультатДляПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляПользователей, Ложь, ОбщийКонтекст, ДополнительныйКонтекст); + + // Для внешних пользователей. + СтруктураОграниченияДляВнешнихПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.ТекстДляВнешнихПользователей, ОписаниеОграничения.ТекстВМодулеМенеджера, Истина); + + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДополнительныйКонтекст, ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Истина); + + РезультатДляВнешнихПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляВнешнихПользователей, Истина, ОбщийКонтекст, ДополнительныйКонтекст); + + // Заполнение параметров на основе параметров обоих видов пользователей. + Версия = ОбщаяВерсия(ОбщийКонтекст, ПолноеИмя, РезультатДляПользователей.Версия, РезультатДляВнешнихПользователей.Версия); + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляПользователей); + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляВнешнихПользователей); + СЗаписьюДвухКлючей = Не РезультатДляПользователей.БезЗаписиКлючейДоступа И Не РезультатДляВнешнихПользователей.БезЗаписиКлючейДоступа; + БезЗаписиКлючей = РезультатДляПользователей.БезЗаписиКлючейДоступа И РезультатДляВнешнихПользователей.БезЗаписиКлючейДоступа; + РезультатДляПользователей.Вставить( "СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", СЗаписьюДвухКлючей); + РезультатДляВнешнихПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", СЗаписьюДвухКлючей); + РезультатДляПользователей.Вставить( "БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", БезЗаписиКлючей); + РезультатДляВнешнихПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", БезЗаписиКлючей); + + // Формирование текстов запросов. + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляПользователей); + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляВнешнихПользователей); + + ВедущиеСписки = Новый Структура; + ВедущиеСписки.Вставить("ДляПользователей", РезультатДляПользователей.ВедущиеСписки); + ВедущиеСписки.Вставить("ДляВнешнихПользователей", РезультатДляВнешнихПользователей.ВедущиеСписки); + + Параметры = Новый Структура; + Параметры.Вставить("Версия", Версия); + Параметры.Вставить("ВедущиеСписки", ВедущиеСписки); + Параметры.Вставить("ДляПользователей", РезультатДляПользователей); + Параметры.Вставить("ДляВнешнихПользователей", РезультатДляВнешнихПользователей); + + Возврат Параметры; + +КонецФункции + +// Для функции ОшибкиОграниченийДоступа. +Функция ОшибкаОграниченияДоступа(ОбщийКонтекст, ПолноеИмя) + + ТекстОшибкиДляПользователей = ""; + ТекстОшибкиДляВнешнихПользователей = ""; + + Попытка + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, Истина); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Возврат ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Если ТипЗнч(ОписаниеОграничения) = Тип("Строка") Тогда + Возврат ОписаниеОграничения; + КонецЕсли; + + // Для пользователей. + СтруктураОграниченияДляПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.Текст, ОписаниеОграничения.ТекстВМодулеМенеджера, Ложь, Истина); + + Если СтруктураОграниченияДляПользователей <> Неопределено + И СтруктураОграниченияДляПользователей.ОписаниеОшибок.ЕстьОшибки Тогда + + ТекстОшибкиДляПользователей = ТекстОшибокДляВызоваИсключения(ПолноеИмя, + СтруктураОграниченияДляПользователей.ОписаниеОшибок, Ложь, ОписаниеОграничения.ТекстВМодулеМенеджера); + Иначе + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Ложь); + + ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); + ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); + Попытка + РезультатДляПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляПользователей, Ложь, ОбщийКонтекст, ДополнительныйКонтекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать параметры ограничения доступа для пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + + Если Не ЗначениеЗаполнено(ТекстОшибкиДляПользователей) Тогда + РезультатДляПользователей.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляПользователей); + РезультатДляПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); + РезультатДляПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); + Попытка + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляПользователей); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа + |для пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + КонецЕсли; + КонецЕсли; + + // Для внешних пользователей. + СтруктураОграниченияДляВнешнихПользователей = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.ТекстДляВнешнихПользователей, ОписаниеОграничения.ТекстВМодулеМенеджера, Истина, Истина); + + Если СтруктураОграниченияДляВнешнихПользователей <> Неопределено + И СтруктураОграниченияДляВнешнихПользователей.ОписаниеОшибок.ЕстьОшибки Тогда + + ТекстОшибкиДляВнешнихПользователей = ТекстОшибокДляВызоваИсключения(ПолноеИмя, + СтруктураОграниченияДляВнешнихПользователей.ОписаниеОшибок, Истина, ОписаниеОграничения.ТекстВМодулеМенеджера); + Иначе + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, ОписаниеОграничения, Истина); + + ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); + ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); + Попытка + РезультатДляВнешнихПользователей = ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграниченияДляВнешнихПользователей, Истина, ОбщийКонтекст, ДополнительныйКонтекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляВнешнихПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляВнешнихПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать параметры ограничения доступа для внешних пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + + Если Не ЗначениеЗаполнено(ТекстОшибкиДляВнешнихПользователей) Тогда + РезультатДляВнешнихПользователей.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + УстановитьСвойстваЗаписиКлючейДоступа(РезультатДляВнешнихПользователей); + РезультатДляВнешнихПользователей.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); + РезультатДляВнешнихПользователей.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); + Попытка + ДобавитьТекстыЗапросовВПараметрыОграничения(РезультатДляВнешнихПользователей); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + ТекстОшибкиДляВнешнихПользователей = ОшибкаПриВызовеИсключения.Текст; + Иначе + ТекстОшибкиДляВнешнихПользователей = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа + |для внешних пользователей по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + КонецПопытки; + КонецЕсли; + КонецЕсли; + + Возврат СокрЛП(ТекстОшибкиДляПользователей + + Символы.ПС + Символы.ПС + ТекстОшибкиДляВнешнихПользователей); + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступа. +Функция РезультатПроверкиОграниченияДоступаОбъекта(ПолноеИмя, ДополнительныеПараметры) + + Параметры = Новый Структура; + Параметры.Вставить("Текст", Неопределено); + Параметры.Вставить("ТекстДляВнешнихПользователей", Неопределено); + Параметры.Вставить("УчитыватьЗависимости", Ложь); + Параметры.Вставить("ВсеВидыДоступаИспользуются", Истина); + + Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда + ЗаполнитьЗначенияСвойств(Параметры, ДополнительныеПараметры); + КонецЕсли; + + ДляПользователей = СтруктураРезультатаПроверкиОграниченияДляВидаПользователей(); + ДляВнешнихПользователей = СтруктураРезультатаПроверкиОграниченияДляВидаПользователей(); + + Результат = Новый Структура; + Результат.Вставить("ОшибкаОписанияОграничения", ""); + Результат.Вставить("ТекстВМодулеМенеджера", Неопределено); + Результат.Вставить("ДляПользователей", ДляПользователей); + Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Результат.Вставить("НастройкиВнедрения", Новый Структура); + + ОбщийКонтекст = Неопределено; + Попытка + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(, Параметры.ВсеВидыДоступаИспользуются, Ложь); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + + Если ОбщийКонтекст = Неопределено Тогда + Возврат Результат; + КонецЕсли; + + УчетЗависимостейДоступен = Истина; + СпискиСОграничением = Неопределено; + Попытка + СпискиСОграничением = УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + УчетЗависимостейДоступен = Ложь; + КонецПопытки; + + Если СпискиСОграничением <> Неопределено Тогда + СпискиСОграничением = Новый Соответствие(СпискиСОграничением); + Иначе + СпискиСОграничением = Новый Соответствие; + УчетЗависимостейДоступен = Ложь; + КонецЕсли; + ОбщийКонтекст.Вставить("СпискиСОграничением", СпискиСОграничением); + + ОписаниеОграничения = Неопределено; + Попытка + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, Истина); + Исключение + Результат.ОшибкаОписанияОграничения = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + УчетЗависимостейДоступен = Ложь; + КонецПопытки; + Если ТипЗнч(ОписаниеОграничения) = Тип("Строка") Тогда + Результат.ОшибкаОписанияОграничения = ОписаниеОграничения; + ОписаниеОграничения = Неопределено; + КонецЕсли; + + Если ОписаниеОграничения <> Неопределено Тогда + Результат.ТекстВМодулеМенеджера = ОписаниеОграничения.ТекстВМодулеМенеджера; + ДляПользователей.ОграничениеВМодуле = ОписаниеОграничения.Текст; + ДляПользователей.ПоВладельцуБезЗаписиКлючейДоступа = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступа; + ДляВнешнихПользователей.ОграничениеВМодуле = ОписаниеОграничения.ТекстДляВнешнихПользователей; + ДляВнешнихПользователей.ПоВладельцуБезЗаписиКлючейДоступа = + ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей; + + Если Параметры.Текст = Неопределено Тогда + ДляПользователей.ПроверяемоеОграничение = ДляПользователей.ОграничениеВМодуле; + Иначе + ДляПользователей.ПроверяемоеОграничение = Параметры.Текст; + ОписаниеОграничения.Текст = Параметры.Текст; + КонецЕсли; + + Если Параметры.ТекстДляВнешнихПользователей = Неопределено Тогда + ДляВнешнихПользователей.ПроверяемоеОграничение = ДляВнешнихПользователей.ОграничениеВМодуле; + Иначе + ДляВнешнихПользователей.ПроверяемоеОграничение = Параметры.ТекстДляВнешнихПользователей; + ОписаниеОграничения.ТекстДляВнешнихПользователей = Параметры.ТекстДляВнешнихПользователей; + КонецЕсли; + КонецЕсли; + + Если СпискиСОграничением.Получить(ПолноеИмя) = Неопределено Тогда + СпискиСОграничением.Вставить(ПолноеИмя, Истина); + Результат.ТекстВМодулеМенеджера = Неопределено; + КонецЕсли; + + Контекст = Новый Структура; + Контекст.Вставить("ПолноеИмя", ПолноеИмя); + Контекст.Вставить("ОбщийРезультат", Результат); + Контекст.Вставить("ОбщийКонтекст", ОбщийКонтекст); + Контекст.Вставить("ОписаниеОграничения", ОписаниеОграничения); + Контекст.Вставить("УчитыватьЗависимости", Параметры.УчитыватьЗависимости); + Контекст.Вставить("УчетЗависимостейДоступен", УчетЗависимостейДоступен); + Контекст.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + Контекст.Вставить("ВедущиеСписки", Новый Соответствие); + Контекст.Вставить("ДополнительныйКонтекст", Новый Структура("ДляПользователей, ДляВнешнихПользователей")); + + ПроверитьОграничениеДляВидаПользователей(Контекст, ДляПользователей, Ложь, + Контекст.ДополнительныйКонтекст.ДляПользователей); + + ПроверитьОграничениеДляВидаПользователей(Контекст, ДляВнешнихПользователей, Истина, + Контекст.ДополнительныйКонтекст.ДляВнешнихПользователей); + + Если Не Контекст.УчетЗависимостейДоступен Тогда + Возврат Результат; + КонецЕсли; + + Если Параметры.УчитыватьЗависимости Тогда + ОбщийКонтекст.Вставить("СпециальноеПолноеИмя", ПолноеИмя); + ОбщийКонтекст.Вставить("СпециальноеОписаниеОграничения", ОписаниеОграничения); + ОбщийКонтекст.Вставить("СпискиСОграничением", Новый ФиксированноеСоответствие(СпискиСОграничением)); + НовыеХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст); + ДействующиеПараметры = Новый Структура(НовыеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); // см. НоваяСтруктураХранимыхПараметровЗаписи + Если ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя) = Неопределено Тогда + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, Истина); + Иначе + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, + ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ПолноеИмя)); + КонецЕсли; + УстановитьОграничениеПоВладельцуИспользуется(ДляПользователей, + ПолноеИмя, ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей); + УстановитьОграничениеПоВладельцуИспользуется(ДляВнешнихПользователей, + ПолноеИмя, ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей); + Иначе + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, Истина); + ДействующиеПараметры = Новый Структура; + ДействующиеПараметры.Вставить("ДополнительныйКонтекст", Контекст.ДополнительныйКонтекст); + КонецЕсли; + ДействующиеПараметры.Вставить("ВерсииОграниченийСписков", Контекст.ВерсииОграниченийСписков); + ДействующиеПараметры.Вставить("ВедущиеСписки", Контекст.ВедущиеСписки); + + Настройки = НастройкиВнедрения(ДействующиеПараметры); + + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + УстановитьНастройкиВнедрения(Результат.НастройкиВнедрения, Настройки, ТипыТаблицПоИменам); + + Результат.ДляПользователей.ОграничениеВРолях = Настройки.ОграниченияВРолях.ДляПользователей.Получить( + ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам)); + + Результат.ДляВнешнихПользователей.ОграничениеВРолях = Настройки.ОграниченияВРолях.ДляВнешнихПользователей.Получить( + ПолноеИмяXML(ПолноеИмя, ТипыТаблицПоИменам)); + + Возврат Результат; + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта +Процедура УстановитьОграничениеПоВладельцуИспользуется(Результат, ПолноеИмя, ДополнительныйКонтекст) + + Свойства = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(ПолноеИмя); + Если Свойства = Неопределено Тогда + Возврат; + КонецЕсли; + + Результат.ОграничениеПоВладельцуИспользуется = + Свойства.ПолеВладельца <> Неопределено И Не Свойства.ПолеВладельца.Отключено; + +КонецПроцедуры + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта. +Процедура УстановитьНастройкиВнедрения(НастройкиВнедрения, Данные, ТипыТаблицПоИменам) + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, + Данные.ЗначенияДоступа, "ЗначениеДоступа"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, + Данные.ВладельцыЗначенийКлючейДоступа.Ссылки, "ВладелецЗначенийКлючейДоступа"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.Объекты, "ВладелецЗначенийКлючейДоступаОбъект"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.Документы, "ВладелецЗначенийКлючейДоступаДокумент"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписей, "ВладелецЗначенийКлючейДоступаНаборЗаписей"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета, + "ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета"); + + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Ложь, + Данные.ВладельцыЗначенийКлючейДоступа.НаборыЗаписейРегистраРасчета, + "ВладелецЗначенийКлючейДоступаНаборЗаписейРегистраРасчета"); + + НастройкиВнедрения.Вставить("ПолеРегистраКлючейДоступаКРегистрам", ""); + НастройкиВнедрения.Вставить("ТипыИзмеренийОтдельногоРегистраКлючей", Неопределено); + Для Каждого КлючИЗначение Из Данные.ТипыИзмеренийРегистровКлючей Цикл + Если СтрНайти(КлючИЗначение.Ключ, ".") > 0 Тогда + Продолжить; + КонецЕсли; + ИмяРегистраКлючей = КлючИЗначение.Ключ; + + Если ИмяРегистраКлючей = "КлючиДоступаКРегистрам" Тогда + ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, Истина, + КлючИЗначение.Значение.ИменаТипов, "ПолеРегистраКлючейДоступаКРегистрам"); + Иначе + ИзмеренияРегистра = Метаданные.РегистрыСведений[ИмяРегистраКлючей].Измерения; + СписокТипов = ""; + НомерПоля = 1; + Для Каждого ОписаниеПолейРегистра Из КлючИЗначение.Значение.ПоляРегистров Цикл + Прервать; + КонецЦикла; + Для Каждого ОписаниеПоля Из ОписаниеПолейРегистра.Значение Цикл + ИмяПоля = СтрШаблон("Поле%1", НомерПоля); + ПолеРегистра = ИзмеренияРегистра.Найти(ИмяПоля); + ОписаниеТипов = ?(ПолеРегистра = Неопределено, Новый ОписаниеТипов, ПолеРегистра.Тип); + СписокТипов = СписокТипов + ?(СписокТипов = "", "", Символы.ПС) + + НСтр("ru = '- для измерения'") + " " + ИмяПоля + ":" + Символы.ПС + + " " + ТекстСОтступом(СписокТиповИзМассива(ОписаниеПоля.Тип.Типы(), + Истина, ТипыТаблицПоИменам, ОписаниеТипов), " "); + НомерПоля = НомерПоля + 1; + КонецЦикла; + НастройкиВнедрения.Вставить("ТипыИзмеренийОтдельногоРегистраКлючей", + Новый Структура("ИмяРегистраСведений, ТипыИзмерений", ИмяРегистраКлючей, СписокТипов)); + КонецЕсли; + КонецЦикла; + + НастройкиВнедрения.Вставить("ПредопределенныйИдентификатор", Неопределено); + Для Каждого КлючИЗначение Из Данные.ПредопределенныеИдентификаторы Цикл + ЧастиИмени = СтрРазделить(КлючИЗначение.Ключ, ".", Ложь); + УжеДобавлен = Метаданные.Справочники[ЧастиИмени[0]].ПолучитьИменаПредопределенных().Найти(ЧастиИмени[1]) <> Неопределено; + НастройкиВнедрения.Вставить("ПредопределенныйИдентификатор", + Новый Структура("ИмяСправочника, ИмяПредопределенного", ЧастиИмени[0], + "- " + ЧастиИмени[1] + ?(УжеДобавлен, " (" + НСтр("ru = 'уже добавлен'") + ")", ""))); + Прервать; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры УстановитьНастройкиВнедрения. +Процедура ДобавитьТипыТребуемыеВОпределяемомТипе(НастройкиВнедрения, ТипыТаблицПоИменам, ТипыСсылок, ИменаТипов, ИмяОпределяемогоТипа) + + НастройкиВнедрения.Вставить(ИмяОпределяемогоТипа, ""); + Если ИменаТипов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + НастройкиВнедрения[ИмяОпределяемогоТипа] = СписокТиповИзМассива(ИменаТипов, + ТипыСсылок, ТипыТаблицПоИменам, Метаданные.ОпределяемыеТипы[ИмяОпределяемогоТипа].Тип); + +КонецПроцедуры + +// Для процедур УстановитьНастройкиВнедрения, ДобавитьТипыТребуемыеВОпределяемомТипе. +Функция СписокТиповИзМассива(ИменаТипов, ТипыСсылок, ТипыТаблицПоИменам, ОписаниеТипов) + + СписокТипов = ""; + Для Каждого ИмяТипа Из ИменаТипов Цикл + Если ТипЗнч(ИмяТипа) = Тип("Тип") Тогда + Тип = ИмяТипа; + Иначе + Тип = Тип(ИмяТипа); + КонецЕсли; + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + Если ОбъектМетаданных = Неопределено Тогда + ИмяТипа = Строка(Тип); + Иначе + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + ИмяТипа = ?(ТипыСсылок, ИмяТипаСсылки(ПолноеИмя, ТипыТаблицПоИменам), + ИмяТипаОбъектаИлиНабораЗаписей(ПолноеИмя, ТипыТаблицПоИменам)); + КонецЕсли; + + СписокТипов = СписокТипов + ?(СписокТипов = "", "", Символы.ПС) + "- " + ИмяТипа; + + Если ОписаниеТипов.СодержитТип(Тип) Тогда + СписокТипов = СписокТипов + " (" + НСтр("ru = 'уже добавлен'") + ")"; + КонецЕсли; + КонецЦикла; + + Возврат СписокТипов; + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта. +Функция СтруктураРезультатаПроверкиОграниченияДляВидаПользователей() + + Свойства = Новый Структура; + Свойства.Вставить("ПроверяемоеОграничение"); + Свойства.Вставить("ОписаниеОшибок"); + Свойства.Вставить("ОшибкаФормированияПараметровОграничения"); + Свойства.Вставить("ОшибкаФормированияТекстовЗапросов"); + Свойства.Вставить("ОграничениеПоВладельцуВозможно"); + Свойства.Вставить("ОграничениеПоВладельцуИспользуется"); + Свойства.Вставить("ОграничениеВРолях"); + Свойства.Вставить("ОграничениеВМодуле"); + Свойства.Вставить("ПоВладельцуБезЗаписиКлючейДоступа"); + + Возврат Свойства; + +КонецФункции + +// Для функции РезультатПроверкиОграниченияДоступаОбъекта. +Процедура ПроверитьОграничениеДляВидаПользователей(Контекст, Результат, ДляВнешнихПользователей, ДополнительныйКонтекст) + + ТекстОграничения = ?(ДляВнешнихПользователей, Контекст.ОбщийРезультат.ДляВнешнихПользователей, + Контекст.ОбщийРезультат.ДляПользователей).ПроверяемоеОграничение; + + СтруктураОграничения = РассчитаннаяСтруктураОграничения(Контекст.ПолноеИмя, + ТекстОграничения, Контекст.ОбщийРезультат.ТекстВМодулеМенеджера, ДляВнешнихПользователей, Истина); + + Если СтруктураОграничения <> Неопределено + И СтруктураОграничения.ОписаниеОшибок.ЕстьОшибки Тогда + + Результат.ОписаниеОшибок = СтруктураОграничения.ОписаниеОшибок; + Контекст.УчетЗависимостейДоступен = Ложь; + Возврат; + КонецЕсли; + + ДополнительныйКонтекст = НовыйДополнительныйКонтекст(); + ДобавитьДополнительныйКонтекст(Контекст.ПолноеИмя, + ДополнительныйКонтекст, Контекст.ОписаниеОграничения, ДляВнешнихПользователей); + + ОшибкаПриВызовеИсключения = Новый Структура("Текст", Неопределено); + ДополнительныйКонтекст.Вставить("ОшибкаПриВызовеИсключения", ОшибкаПриВызовеИсключения); + + Попытка + ПараметрыОграничения = ПараметрыОграниченияПоСтруктуреОграничения(Контекст.ПолноеИмя, + СтруктураОграничения, ДляВнешнихПользователей, Контекст.ОбщийКонтекст, ДополнительныйКонтекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ПараметрыОграничения = Неопределено; + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + Результат.ОшибкаФормированияПараметровОграничения = ОшибкаПриВызовеИсключения.Текст; + Иначе + Результат.ОшибкаФормированияПараметровОграничения = + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать параметры ограничения доступа по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + Контекст.УчетЗависимостейДоступен = Ложь; + КонецПопытки; + + Если ПараметрыОграничения <> Неопределено Тогда + Результат.ОграничениеПоВладельцуВозможно = ПараметрыОграничения.ПолеВладельца <> Неопределено; + ПараметрыОграничения.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + УстановитьСвойстваЗаписиКлючейДоступа(ПараметрыОграничения); + ПараметрыОграничения.Вставить("БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей", Ложь); + ПараметрыОграничения.Вставить("СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей", Истина); + Для Каждого КлючИЗначение Из ПараметрыОграничения.ВедущиеСписки.ПоЗначениямПолей Цикл + Контекст.ВедущиеСписки.Вставить(КлючИЗначение.Ключ, Неопределено); + КонецЦикла; + Для Каждого КлючИЗначение Из ПараметрыОграничения.ВедущиеСписки.ПоКлючамДоступа Цикл + Контекст.ВерсииОграниченийСписков.Вставить(КлючИЗначение.Ключ, Неопределено); + КонецЦикла; + Попытка + ДобавитьТекстыЗапросовВПараметрыОграничения(ПараметрыОграничения); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если ЗначениеЗаполнено(ОшибкаПриВызовеИсключения.Текст) Тогда + Результат.ОшибкаФормированияТекстовЗапросов = ОшибкаПриВызовеИсключения.Текст; + Иначе + Результат.ОшибкаФормированияТекстовЗапросов = + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось сформировать тексты запросов на основе параметров ограничения доступа по причине: + |%1'"), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + КонецЕсли; + Контекст.УчетЗависимостейДоступен = Ложь; + КонецПопытки; + КонецЕсли; + + Если Контекст.УчитыватьЗависимости Тогда + Возврат; + КонецЕсли; + + СокращенныеСвойства = Новый Структура; + СокращенныеСвойства.Вставить("ДоступЗапрещен", Ложь); + СокращенныеСвойства.Вставить("ПолеВладельца", Неопределено); + СокращенныеСвойства.Вставить("ОпорныеПоля", Неопределено); + СокращенныеСвойства.Вставить("ИмяОтдельногоРегистраКлючей", Неопределено); + ДополнительныйКонтекст.СвойстваОграниченияСписков.Вставить(Контекст.ПолноеИмя, СокращенныеСвойства); + + Если Не Контекст.УчетЗависимостейДоступен Тогда + Возврат; + КонецЕсли; + + ЗаполнитьЗначенияСвойств(СокращенныеСвойства, ПараметрыОграничения); + +КонецПроцедуры + +// Для функций ХранимыеПараметрыОграниченияДоступа, РассчитанныеПараметрыОграничения. +Функция ОбщаяВерсия(ОбщийКонтекст, ПолноеИмя, ВерсияДляПользователей, ВерсияДляВнешнихПользователей) + + Если ОбщийКонтекст.СпискиСОграничением.Получить(ПолноеИмя) = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Возврат СтрПолучитьСтроку(ВерсияДляПользователей, 1) + + Символы.ПС + СтрПолучитьСтроку(ВерсияДляВнешнихПользователей, 1) + + Символы.ПС + СтрПолучитьСтроку(ВерсияДляПользователей, 2) + + Символы.ПС + СтрПолучитьСтроку(ВерсияДляВнешнихПользователей, 2) + +КонецФункции + +// Для функции РассчитанныеПараметрыОграничения. +Процедура УстановитьСвойстваЗаписиКлючейДоступа(Результат) + + БезЗаписиКлючей = Ложь; + СЗаписьюКлючаДляЗависимыхСписковБезКлючей = Ложь; + + Если Результат.ОграничениеОтключено + Или Результат.ДоступЗапрещен + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + Если Результат.ИспользуетсяОграничениеПоВладельцу + Или Результат.Контекст.БезОбъектаМетаданных + Или Результат.Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить( + Результат.Список) = Неопределено Тогда + + БезЗаписиКлючей = Истина; + Иначе + СЗаписьюКлючаДляЗависимыхСписковБезКлючей = Истина; + КонецЕсли; + КонецЕсли; + + Результат.Вставить("БезЗаписиКлючейДоступа", БезЗаписиКлючей); + Результат.Вставить("СЗаписьюКлючаДоступаДляЗависимыхСписковБезКлючей", + СЗаписьюКлючаДляЗависимыхСписковБезКлючей); + +КонецПроцедуры + +// Для функций РассчитанныеПараметрыОграничения, ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * Текст - Строка +// * ТекстДляВнешнихПользователей - Строка +// * ПоВладельцуБезЗаписиКлючейДоступа - Булево +// - Неопределено +// * ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей - Булево +// - Неопределено +// * ТекстВМодулеМенеджера - Булево +// +Функция ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя, БезВызоваИсключения = Ложь) + + Ограничение = Новый Структура; + Ограничение.Вставить("Текст", ""); + Ограничение.Вставить("ТекстДляВнешнихПользователей", ""); + Ограничение.Вставить("ПоВладельцуБезЗаписиКлючейДоступа", Неопределено); + Ограничение.Вставить("ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", Неопределено); + Ограничение.Вставить("ТекстВМодулеМенеджера", Ложь); + + ТекстВМодулеМенеджера = ОбщийКонтекст.СпискиСОграничением.Получить(ПолноеИмя); + Если ТекстВМодулеМенеджера = Неопределено Тогда + Возврат Ограничение; + КонецЕсли; + + Ограничение.ТекстВМодулеМенеджера = ТекстВМодулеМенеджера; + + Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда + МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный"); + ЭтоСправочникФайлов = МодульРаботаСФайламиСлужебный.ЭтоСправочникФайловИлиВерсийФайлов(ПолноеИмя); + Иначе + ЭтоСправочникФайлов = Ложь; + КонецЕсли; + + Если ЭтоЖурналДокументов(ПолноеИмя) Или ЭтоСправочникФайлов Тогда + // Для журналов документов ограничение должно быть + // по документу-владельцу без записи ключей доступа, если не требуется другое. + // Аналогично (по умолчанию) для справочников файлов и версий файлов. + Ограничение.ПоВладельцуБезЗаписиКлючейДоступа = Истина; + Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей = Истина; + КонецЕсли; + + Если ТекстВМодулеМенеджера Тогда + Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПолноеИмя); + + Попытка + Менеджер.ПриЗаполненииОграниченияДоступа(Ограничение); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в модуле менеджера + |в процедуре %4 по причине: + | + |%5'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + + Если БезВызоваИсключения Тогда + Возврат ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецПопытки; + Иначе + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); + Попытка + УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа(ОбъектМетаданных, Ограничение); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в общем модуле %4 + |в процедуре %5 по причине: + | + |%6'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); + + Если БезВызоваИсключения Тогда + Возврат ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецПопытки; + КонецЕсли; + + Если ЭтоЖурналДокументов(ПолноеИмя) + И ( Ограничение.ПоВладельцуБезЗаписиКлючейДоступа <> Истина + Или Ограничение.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей <> Истина) Тогда + + Если ВариантВстроенногоЯзыкаРусский() Тогда + ШаблонОграничения = + "РазрешитьЧтениеИзменение + |ГДЕ + | ЧтениеОбъектаРазрешено(Ссылка)"; // @Non-NLS + Иначе + ШаблонОграничения = + "AllowReadWrite + |WHERE + | ObjectReadingAllowed(Ref)"; + КонецЕсли; + + Если ТекстВМодулеМенеджера Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в модуле менеджера + |в процедуре %4 по причине: + | + |Для журналов документов не поддерживается ограничение, как для регистров, + |то есть, кроме варианта ограничения по владельцу без записи ключей доступа: + | + |%5'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ШаблонОграничения); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = '""%1"" указан, как список с ограничением доступа в процедуре + |%2 общего модуля %3. + | + |Некорректно указано ограничение доступа этого списка в общем модуле %4 + |в процедуре %5 по причине: + | + |Для журналов документов не поддерживается ограничение, как для регистров, + |то есть, кроме варианта ограничения по владельцу без записи ключей доступа: + | + |%6'"), + ПолноеИмя, + "ПриЗаполненииСписковСОграничениемДоступа", + "УправлениеДоступомПереопределяемый", + "УправлениеДоступомПереопределяемый", + "ПриЗаполненииОграниченияДоступа", + ШаблонОграничения); + КонецЕсли; + Если БезВызоваИсключения Тогда + Возврат ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Возврат Ограничение; + +КонецФункции + +// Для функции ОписаниеОграниченияДанных. +Функция ЭтоЖурналДокументов(ПолноеИмя) + + Возврат СтрНачинаетсяС(ВРег(ПолноеИмя), ВРег("ЖурналДокументов.")) + Или СтрНачинаетсяС(ВРег(ПолноеИмя), ВРег("DocumentJournal.")); // @Non-NLS + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ПараметрыОграниченияДляВидаПользователей. +// +// Возвращаемое значение: +// см. СтруктураОграничения +// +Функция РассчитаннаяСтруктураОграничения(ПолноеИмя, ТекстОграничения, ТекстВМодулеМенеджера, ДляВнешнихПользователей, БезИсключения = Ложь) + + Если Не ЗначениеЗаполнено(ТекстОграничения) Тогда + Возврат Неопределено; + КонецЕсли; + + РазобранноеОграничение = РазобранноеОграничение(ПолноеИмя, ТекстОграничения); + + ПроверитьТаблицыПоляИТипыПолей(РазобранноеОграничение); + + СтруктураОграничения = СтруктураОграничения(РазобранноеОграничение); + + Если БезИсключения Или Не СтруктураОграничения.ОписаниеОшибок.ЕстьОшибки Тогда + Возврат СтруктураОграничения; + КонецЕсли; + + ТекстОшибок = ТекстОшибокДляВызоваИсключения(ПолноеИмя, + СтруктураОграничения.ОписаниеОшибок, ДляВнешнихПользователей, ТекстВМодулеМенеджера); + + ВызватьИсключение ТекстОшибок; + +КонецФункции + +// Для функций СвойстваСпискаКакВедущего, ПараметрыОграничения и процедур УстановкаПараметровСеанса, +// ЗаполнитьПараметрыОграничения, ДобавитьПараметрыОграниченияСписка. +// +// Возвращаемое значение: +// см. НоваяСтруктураХранимыхПараметровЗаписи +// +Функция ДействующиеПараметрыОграниченияДоступа(ИдентификаторТранзакции, ОбщийКонтекст, + Обновить, УстановкаПараметровСеансаДляШаблонов = Ложь, + УстановкаПараметровДляОтчетаПраваДоступа = Ложь, ЕстьИзменения = Ложь) Экспорт + + Если Обновить Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст, ЕстьИзменения); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст); + ПараметрыОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа + Возврат ПараметрыОграниченияДоступа.Параметры; + КонецЕсли; + + ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа + + Если Не ТекущиеПараметры.Свойство("Параметры") Или ТекущиеПараметры.Параметры = Неопределено Тогда + ТекущиеПараметры = Новый Структура("Версия, ХешСумма", "", ""); // См. СеансовыеПараметрыОграниченияДоступа + ИдентификаторыТранзакции = Новый Соответствие; + Иначе + ИдентификаторыТранзакции = КэшПараметровОграничения().ИдентификаторыТранзакции; + КонецЕсли; + + Если ТранзакцияАктивна() + И ИдентификаторыТранзакции.Получить(ИдентификаторТранзакции) <> Неопределено Тогда + + Возврат ТекущиеПараметры.Параметры; + КонецЕсли; + + Пока Истина Цикл + ОписаниеВерсии = ОписаниеПоследнейВерсии(); + Если ТекущиеПараметры.Версия = ОписаниеВерсии.Версия + И ТекущиеПараметры.ХешСумма = ОписаниеВерсии.ХешСумма Тогда + Прервать; + КонецЕсли; + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + Прервать; + КонецЕсли; + Если ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + Если Не УстановкаПараметровСеансаДляШаблонов + И Не УстановкаПараметровДляОтчетаПраваДоступа + И ТекущиеПараметры.Версия = ОписаниеВерсии.Версия + И ТекущиеПараметры.ХешСумма = ОписаниеВерсии.ХешСумма Тогда + + ОбновитьИдентификаторыТранзакции(ИдентификаторТранзакции); + Возврат ТекущиеПараметры.Параметры; + КонецЕсли; + + // Параметры в базе данных отличаются от параметров в памяти. + Если ЗначениеЗаполнено(ОписаниеВерсии.Версия) Тогда + ВерсияПараметров = ВерсияПараметров(ОписаниеВерсии.Версия, + УстановкаПараметровСеансаДляШаблонов, УстановкаПараметровДляОтчетаПраваДоступа); + Иначе + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + КонецЕсли; + + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов); + + ПараметрыОграниченияДоступа = ПараметрыСеанса.ПараметрыОграниченияДоступа; // См. СеансовыеПараметрыОграниченияДоступа + Возврат ПараметрыОграниченияДоступа.Параметры; + +КонецФункции + +// Для отчета ПраваДоступа. +// +// Возвращаемое значение: +// Структура: +// * ДляПользователей - Строка +// * ДляВнешнихПользователей - Строка +// +Функция ВсеВидыОграниченийПравДляОтчетаПраваДоступа() + + Кэш = КэшПараметровОграничения(); + + Если Кэш.ВидыОграниченийПравДляПользователей <> Неопределено + И Кэш.ВидыОграниченийПравДляВнешнихПользователей <> Неопределено Тогда + Возврат Новый Структура("ДляПользователей, ДляВнешнихПользователей", + Кэш.ВидыОграниченийПравДляПользователей, + Кэш.ВидыОграниченийПравДляВнешнихПользователей); + КонецЕсли; + + ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь, Ложь, Истина); + + Возврат ВсеВидыОграниченийПравДляОтчетаПраваДоступа(); + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Функция ЗаписьПараметровОграниченияДоступаВТекущемСеансе() + + УстановитьПривилегированныйРежим(Истина); + ТекущиеПараметры = ПараметрыСеанса.ПараметрыОграниченияДоступа; + УстановитьПривилегированныйРежим(Ложь); + + Возврат ТекущиеПараметры.Свойство("ЗаписьПараметровОграниченияДоступаВТекущемСеансе"); + +КонецФункции + +// Для функций ДействующиеПараметрыОграниченияДоступа, НоваяВерсияПараметровОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * Версия - Число +// - Неопределено +// * ХешСумма - Строка +// - Неопределено +// * ДатаСоздания - Дата +// - Неопределено +// * ВерсииПараметровШаблонов - ХранилищеЗначения +// - Неопределено +// +Функция ОписаниеПоследнейВерсии(ПрочитатьВерсииПараметровШаблонов = Ложь) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ПараметрыОграниченияДоступа.Версия КАК Версия, + | ПараметрыОграниченияДоступа.ХешСумма КАК ХешСумма, + | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания, + | ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов КАК ВерсииПараметровШаблонов + |ИЗ + | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа + | + |УПОРЯДОЧИТЬ ПО + | ПараметрыОграниченияДоступа.Версия УБЫВ"; + + Если Не ПрочитатьВерсииПараметровШаблонов Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов", "Неопределено"); + КонецЕсли; + + Выборка = Запрос.Выполнить().Выбрать(); + Выборка.Следующий(); + + Результат = Новый Структура("Версия, ХешСумма, ДатаСоздания, ВерсииПараметровШаблонов"); + ЗаполнитьЗначенияСвойств(Результат, Выборка); + + Возврат Результат; + +КонецФункции + +// Для функции ДействующиеПараметрыОграниченияДоступа. +Функция ВерсияПараметров(Версия, УстановкаПараметровСеансаДляШаблонов, УстановкаПараметровДляОтчетаПраваДоступа) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ПараметрыОграниченияДоступа.Версия КАК Версия, + | ПараметрыОграниченияДоступа.ХешСумма КАК ХешСумма, + | ПараметрыОграниченияДоступа.ДатаСоздания КАК ДатаСоздания, + | ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей КАК ДляШаблоновВСеансахПользователей, + | ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей КАК ДляШаблоновВСеансахВнешнихПользователей, + | ПараметрыОграниченияДоступа.ДляЗаписиОбъектовИПроверкиПрав КАК ДляЗаписиОбъектовИПроверкиПрав, + | ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов КАК ВерсииПараметровШаблонов, + | ПараметрыОграниченияДоступа.ДляОтчетаПоПравамДоступа КАК ДляОтчетаПоПравамДоступа + |ИЗ + | РегистрСведений.ПараметрыОграниченияДоступа КАК ПараметрыОграниченияДоступа + |ГДЕ + | ПараметрыОграниченияДоступа.Версия = &Версия"; + + Если УстановкаПараметровСеансаДляШаблонов Или УстановкаПараметровДляОтчетаПраваДоступа Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляЗаписиОбъектовИПроверкиПрав", "Неопределено"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ВерсииПараметровШаблонов", "Неопределено"); + КонецЕсли; + Если Не УстановкаПараметровДляОтчетаПраваДоступа Тогда + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляОтчетаПоПравамДоступа", "Неопределено"); + КонецЕсли; + + Если УстановкаПараметровСеансаДляШаблонов + Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + + Запрос.Текст = СтрЗаменить(Запрос.Текст, ?(Пользователи.ЭтоСеансВнешнегоПользователя(), + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей", + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей"), "Неопределено"); + Иначе + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахПользователей", "Неопределено"); + Запрос.Текст = СтрЗаменить(Запрос.Текст, + "ПараметрыОграниченияДоступа.ДляШаблоновВСеансахВнешнихПользователей", "Неопределено"); + КонецЕсли; + + Запрос.УстановитьПараметр("Версия", Версия); + + Выборка = Запрос.Выполнить().Выбрать(); + Выборка.Следующий(); + + Возврат Выборка; + +КонецФункции + +// Для функции ДействующиеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// см. ХранимыеПараметрыОграниченияДоступа +// +Функция НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст, ЕстьИзменения = Ложь) + + Попытка + ПроверитьАктуальностьМетаданных(); + Исключение + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "НоваяВерсияПараметровОграниченияДоступа", Истина); + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + + УдалитьСтрокиВерсииХранимыхПараметров = Ложь; + + Если ТипЗнч(ОбщийКонтекст) <> Тип("Структура") + Или ЗначениеЗаполнено(ОбщийКонтекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы) Тогда + ОбновитьПовторноИспользуемыеЗначения(); + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); + КонецЕсли; + + Если РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() Тогда + Если Не ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.Вставить("СтрокиВерсииХранимыхПараметров"); + УдалитьСтрокиВерсииХранимыхПараметров = Истина; + КонецЕсли; + КонецЕсли; + + ВерсииОграниченийСписков = Новый Соответствие; + ОбщийКонтекст.Вставить("ИнформацияДляЖурнала", НоваяИнформацияНесоответствияПараметровДляЖурнала()); + ХранимыеПараметры = ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст, ВерсииОграниченийСписков); + ВерсииОграниченийСписков.Вставить("Справочник.НаборыГруппДоступа", "1"); + + ПараметрыЗаписи = Новый Структура; + ПараметрыЗаписи.Вставить("ВерсииОграниченийСписков", ВерсииОграниченийСписков); + ПараметрыЗаписи.Вставить("ИдентификаторыВсехСписков"); + ПараметрыЗаписи.Вставить("ХранимыеПараметры", ХранимыеПараметры); + ПараметрыЗаписи.Вставить("ИдентификаторДоступа", ИдентификаторДоступа()); + ПараметрыЗаписи.Вставить("ИнформацияДляЖурнала", ОбщийКонтекст.ИнформацияДляЖурнала); + ОбщийКонтекст.Удалить("ИнформацияДляЖурнала"); + + Если ОбщийКонтекст.Свойство("СпискиСУстаревшимиВариантамиДоступа") Тогда + ПараметрыЗаписи.Вставить("СпискиСУстаревшимиВариантамиДоступа", + ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа); + Иначе + ПараметрыЗаписи.Вставить("СпискиСУстаревшимиВариантамиДоступа"); + КонецЕсли; + + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ПараметрыЗаписи.Вставить("СтрокиВерсии", ОбщийКонтекст.СтрокиВерсииХранимыхПараметров); + КонецЕсли; + + Если Не ТранзакцияАктивна() + Или МонопольныйРежим() + Или ОбщийКонтекст.Свойство("ЗаписатьВТекущейТранзакции") + Или ОбщегоНазначения.ИнформационнаяБазаФайловая() + Или СтандартныеПодсистемыСервер.ЭтоРазделенныйРежимСеансаБезРазделителей() + Или ЗаписьПараметровОграниченияДоступаВТекущемСеансе() Тогда + + НомерПопыткиБлокировки = 0; + Пока Истина Цикл + НомерПопыткиБлокировки = НомерПопыткиБлокировки + 1; + ЭтоОшибкаБлокировки = Ложь; + Попытка + ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа(ПараметрыЗаписи,, ЭтоОшибкаБлокировки); + Исключение + Если ЭтоОшибкаБлокировки + И НомерПопыткиБлокировки < 3 + И Не ТранзакцияАктивна() Тогда + Продолжить; + КонецЕсли; + Если СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке()) Тогда + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "НоваяВерсияПараметровОграниченияДоступа", Истина); + КонецЕсли; + ВызватьИсключение; + КонецПопытки; + Прервать; + КонецЦикла; + Иначе + ПараметрыЗаписиВХранилище = Новый ХранилищеЗначения(ПараметрыЗаписи); + ОписаниеВерсии = Неопределено; + Пока Истина Цикл + ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа( + ПараметрыЗаписиВХранилище.Получить(), Истина); + Если ОписаниеВерсии <> Неопределено Тогда + Прервать; + КонецЕсли; + Если ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() Тогда + Прервать; + КонецЕсли; + КонецЦикла; + Если ОписаниеВерсии = Неопределено Тогда + ПараметрыЗаписи.ИдентификаторыВсехСписков = ИдентификаторыВсехСписков(); + ПараметрыЗаписиВХранилище = Новый ХранилищеЗначения(ПараметрыЗаписи); + ИмяПроцедуры = ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа(); + АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено); + ПараметрыПроцедуры = Новый Массив; + ПараметрыПроцедуры.Добавить(АдресРезультата); + ПараметрыПроцедуры.Добавить(ПараметрыЗаписиВХранилище); + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + НаименованиеЗадания = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Управление доступом: Запись новой версии параметров ограничения доступа (из сеанса %1 от %2)'", + ОбщегоНазначения.КодОсновногоЯзыка()), + Формат(ТекущийСеанс.НомерСеанса, "ЧГ="), + Формат(ТекущийСеанс.НачалоСеанса, "ДЛФ=DT")); + ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяПроцедуры, ПараметрыПроцедуры,, НаименованиеЗадания); + ФоновоеЗадание = ФоновоеЗадание.ОжидатьЗавершенияВыполнения(60); + Результат = ПолучитьИзВременногоХранилища(АдресРезультата); + ЗаголовокОшибки = НСтр("ru = 'Не удалось записать новую версию параметров ограничения доступа по причине:'"); + Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Активно Тогда + ФоновоеЗадание.Отменить(); + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание выполняется более 60 секунд, поэтому отменено.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ФоновоеЗадание.Состояние = СостояниеФоновогоЗадания.Отменено Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание отменено администратором.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ФоновоеЗадание.Состояние <> СостояниеФоновогоЗадания.Завершено Тогда + Если ТипЗнч(ФоновоеЗадание.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ФоновоеЗадание.ИнформацияОбОшибке); + Иначе + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание завершилось аварийно.'"); + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если ТипЗнч(Результат) <> Тип("Структура") Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + + НСтр("ru = 'Фоновое задание не вернуло результат.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Если Результат.ТребуетсяПерезапускСеанса Тогда + ЗапланироватьОбновлениеПараметровОграниченияДоступа( + "НоваяВерсияПараметровОграниченияДоступа", Истина); + ПроверитьАктуальностьМетаданных(); + СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(Результат.ТекстОшибки); + ВызватьИсключение Результат.ТекстОшибки; + КонецЕсли; + Если ЗначениеЗаполнено(Результат.ТекстОшибки) Тогда + ТекстОшибки = ЗаголовокОшибки + Символы.ПС + Результат.ТекстОшибки; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ОписаниеВерсии = Результат.ОписаниеВерсии; + КонецЕсли; + КонецЕсли; + + Если ОбщийКонтекст.Свойство("СпискиСУстаревшимиВариантамиДоступа") Тогда + ОбщийКонтекст.СпискиСУстаревшимиВариантамиДоступа = + ОписаниеВерсии.СпискиСУстаревшимиВариантамиДоступа; + КонецЕсли; + + Если УдалитьСтрокиВерсииХранимыхПараметров Тогда + ОбщийКонтекст.Удалить("СтрокиВерсииХранимыхПараметров"); + + ИначеЕсли ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров = ОписаниеВерсии.СтрокиВерсии; + КонецЕсли; + + Если ОписаниеВерсии.ЕстьИзменения Тогда + ЕстьИзменения = Истина; + КонецЕсли; + + Для Каждого КлючИЗначение Из ОписаниеВерсии.ЗаполняемыеСвойстваВерсии Цикл + ХранимыеПараметры.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + + Возврат ХранимыеПараметры; + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Функция ИдентификаторыВсехСписков() + + Списки = Новый Массив; + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыОбмена); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Справочники); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Документы); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ЖурналыДокументов); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыВидовХарактеристик); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыСчетов); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.ПланыВидовРасчета); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыСведений); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыНакопления); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыБухгалтерии); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.РегистрыРасчета); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.БизнесПроцессы); + ДобавитьПолныеИменаКоллекции(Списки, Метаданные.Задачи); + + Возврат ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки); + +КонецФункции + +// Для функции ИдентификаторыВсехСписков. +Процедура ДобавитьПолныеИменаКоллекции(Списки, КоллекцияОбъектовМетаданных) + + Для Каждого ОбъектМетаданных Из КоллекцияОбъектовМетаданных Цикл + Списки.Добавить(ОбъектМетаданных.ПолноеИмя()); + КонецЦикла; + +КонецПроцедуры + +// Для функций НоваяВерсияПараметровОграниченияДоступа и +// ДействующиеПараметрыОграниченияДоступа. +// +Функция ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() + + ОтборЗаданий = Новый Структура("ИмяМетода, Состояние", + ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа(), + СостояниеФоновогоЗадания.Активно); + + НайденныеЗадания = ФоновыеЗадания.ПолучитьФоновыеЗадания(ОтборЗаданий); + + Если НайденныеЗадания.Количество() = 0 Тогда + Возврат Истина; + КонецЕсли; + + ФоновыеЗадания.ОжидатьЗавершенияВыполнения(НайденныеЗадания, 1); + + Возврат Ложь; + +КонецФункции + +// Для функций НоваяВерсияПараметровОграниченияДоступа и +// ЗавершеныЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа. +// +Функция ИмяПроцедурыЗаданияЗаписиНовойВерсииПараметровОграниченияДоступа() + + Возврат "УправлениеДоступомСлужебный.ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне"; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// Предупреждение - Строка +// Ошибка - Строка +// ВерсияТекстовОграниченияДоступа - Строка +// +Функция НоваяИнформацияНесоответствияПараметровДляЖурнала() + + Результат = Новый Структура; + Результат.Вставить("Предупреждение", ""); + Результат.Вставить("Ошибка", ""); + Результат.Вставить("ВерсияТекстовОграниченияДоступа", ""); + + Возврат Результат; + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Процедура ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне(АдресРезультата, ХранилищеПараметров) Экспорт + + ПользователиСлужебный.ПроверитьБезопасныйРежимОтключен( + "УправлениеДоступомСлужебный.ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне"); + + Результат = Новый Структура; + Результат.Вставить("ОписаниеВерсии", Новый Структура); + Результат.Вставить("ТекстОшибки", ""); + Результат.Вставить("ТребуетсяПерезапускСеанса", Ложь); + + УстановитьПривилегированныйРежим(Истина); + Попытка + Параметры = ХранилищеПараметров.Получить(); + Если Параметры.ИдентификаторДоступа = ИдентификаторДоступа() Тогда + Результат.ОписаниеВерсии = ОписаниеНовойВерсииПараметровОграниченияДоступа(Параметры); + Иначе + Результат.ТекстОшибки = НСтр("ru = 'Ошибка проверки доступа.'"); + КонецЕсли; + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если СтандартныеПодсистемыСервер.ТребуетсяПерезапускСеанса(Результат.ТекстОшибки) Тогда + Результат.ТребуетсяПерезапускСеанса = Истина; + КонецЕсли; + Если Не Результат.ТребуетсяПерезапускСеанса + Или Не СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + Результат.ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке); + КонецЕсли; + КонецПопытки; + УстановитьПривилегированныйРежим(Ложь); + + ПоместитьВоВременноеХранилище(Результат, АдресРезультата); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа и +// процедуры ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне. +// +Функция ИдентификаторДоступа() + + Возврат ПоследнееОбновлениеДоступа().ИдентификаторДоступа; + +КонецФункции + +// Для функции НоваяВерсияПараметровОграниченияДоступа и +// процедуры ЗаписатьНовуюВерсиюПараметровОграниченияДоступаВФоне. +// +Функция ОписаниеНовойВерсииПараметровОграниченияДоступа(Параметры, БезЗаписи = Ложь, ЭтоОшибкаБлокировки = Ложь) + + Запись = НоваяТаблицаРегистраСведенийПараметрыОграниченияДоступа().Добавить(); + ЗаполнитьЗначенияСвойств(Запись, Параметры.ХранимыеПараметры); + + ЗаполняемыеСвойстваВерсии = Новый Структура("Версия, ДатаСоздания, ХешСумма, + |ВерсииПараметровШаблонов, ХешСуммаПостоянныхПараметров, ХешСуммаПараметровШаблонов, + |ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей"); + + Результат = Новый Структура; + Результат.Вставить("ЕстьИзменения", Ложь); + Результат.Вставить("ЗаполняемыеСвойстваВерсии", ЗаполняемыеСвойстваВерсии); + Результат.Вставить("СпискиСУстаревшимиВариантамиДоступа", + Параметры.СпискиСУстаревшимиВариантамиДоступа); + Параметры.Вставить("СпискиСНовымОсновнымВариантомДоступа", Новый Массив); + Если Параметры.Свойство("СтрокиВерсии") Тогда + Результат.Вставить("СтрокиВерсии", Параметры.СтрокиВерсии); + КонецЕсли; + + Если БезЗаписи Тогда + ОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); + ЗаполнитьПараметрыДляШаблонов(Запись, Параметры, ОписаниеВерсии); + Если ОписаниеВерсии.ХешСумма <> Запись.ХешСумма Тогда + Возврат Неопределено; + КонецЕсли; + Иначе + НачатьТранзакцию(); + Попытка + Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда + ЗаблокироватьРегистрыПланированияОбновленияКлючейДоступаВФайловойИБ(ЭтоОшибкаБлокировки, Истина); + КонецЕсли; + ОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); + Пока Истина Цикл + ЗаполнитьПараметрыДляШаблонов(Запись, Параметры, ОписаниеВерсии); + Если ОписаниеВерсии.ХешСумма = Запись.ХешСумма Тогда + Прервать; + КонецЕсли; + + ПроверитьАктуальностьМетаданных(); + + Если ЗначениеЗаполнено(ОписаниеВерсии.Версия) Тогда + НоваяВерсия = ОписаниеВерсии.Версия + 1; + Иначе + НоваяВерсия = 1; + КонецЕсли; + + БлокировкаДанных = Новый БлокировкаДанных; + ЭлементБлокировки = БлокировкаДанных.Добавить("РегистрСведений.ПараметрыОграниченияДоступа"); + ЭлементБлокировки.УстановитьЗначение("Версия", НоваяВерсия); + БлокировкаДанных.Заблокировать(); + НовоеОписаниеВерсии = ОписаниеПоследнейВерсии(Истина); + + Если ОписаниеВерсии.Версия <> НовоеОписаниеВерсии.Версия + Или НовоеОписаниеВерсии.Версия = НоваяВерсия Тогда + + ОписаниеВерсии = НовоеОписаниеВерсии; + Продолжить; + КонецЕсли; + + ПроверитьАктуальностьМетаданных(); + + Запись.Версия = НоваяВерсия; + + НаборЗаписей = СлужебныйНаборЗаписей(РегистрыСведений.ПараметрыОграниченияДоступа); + ЗаполнитьЗначенияСвойств(НаборЗаписей.Добавить(), Запись); + Запись = НаборЗаписей[0]; + НаборЗаписей.Отбор.Версия.Установить(НоваяВерсия); + ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, Запись); + + ЗапланироватьОбновлениеДоступаПриИзмененииПараметров(ОписаниеВерсии.Версия, Параметры); + НаборЗаписей.Записать(); + Результат.ЕстьИзменения = Истина; + + ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Параметры.ИнформацияДляЖурнала.Предупреждение); + ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Параметры.ИнформацияДляЖурнала.Ошибка, Истина); + + Если РегистрироватьСтрокуВерсииПараметровОграниченияДоступа() Тогда + ЗарегистрироватьСтрокуВерсииПараметровОграниченияДоступа(НаборЗаписей[0], + Параметры.СтрокиВерсии); + КонецЕсли; + + Прервать; + КонецЦикла; + ЗафиксироватьТранзакцию(); + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + КонецЕсли; + + Если Не Результат.ЕстьИзменения Тогда + ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, ОписаниеВерсии, + "Версия, ДатаСоздания, ХешСумма, ВерсииПараметровШаблонов"); + ЗаполнитьЗначенияСвойств(ЗаполняемыеСвойстваВерсии, Запись, + "ХешСуммаПостоянныхПараметров, ХешСуммаПараметровШаблонов, + |ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей"); + ИначеЕсли Не ТранзакцияАктивна() Тогда + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ДатаПроверкиПараметровОграниченияДоступа"; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ТекущаяДатаСеанса(), Истина); + ВерсияТекстов = Параметры.ИнформацияДляЖурнала.ВерсияТекстовОграниченияДоступа; + ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВерсияТекстовОграниченияДоступа"; + СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, ВерсияТекстов, Истина); + УстановитьОбновлениеДоступа(Истина); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Версия - Число +// * ХешСумма - Строка +// * ХешСуммаПостоянныхПараметров - Строка +// * ДляЗаписиОбъектовИПроверкиПрав - ХранилищеЗначения +// * ДляОтчетаПоПравамДоступа - ХранилищеЗначения +// * ХешСуммаПараметровШаблонов - Строка +// * ДляШаблоновВСеансахПользователей - ХранилищеЗначения +// * ДляШаблоновВСеансахВнешнихПользователей - ХранилищеЗначения +// * ВерсииПараметровШаблонов - ХранилищеЗначения +// * ДатаСоздания - Дата +// +Функция НоваяТаблицаРегистраСведенийПараметрыОграниченияДоступа() + + ТипВерсии = Новый ОписаниеТипов("Число",,, Новый КвалификаторыЧисла(15, 0, ДопустимыйЗнак.Неотрицательный)); + ТипХешСуммы = Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(48, ДопустимаяДлина.Переменная)); + + Таблица = Новый ТаблицаЗначений; + Таблица.Колонки.Добавить("Версия", ТипВерсии); + Таблица.Колонки.Добавить("ХешСумма", ТипХешСуммы); + Таблица.Колонки.Добавить("ХешСуммаПостоянныхПараметров", ТипХешСуммы); + Таблица.Колонки.Добавить("ДляЗаписиОбъектовИПроверкиПрав", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ДляОтчетаПоПравамДоступа", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ХешСуммаПараметровШаблонов", ТипХешСуммы); + Таблица.Колонки.Добавить("ДляШаблоновВСеансахПользователей", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ДляШаблоновВСеансахВнешнихПользователей", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ВерсииПараметровШаблонов", Новый ОписаниеТипов("ХранилищеЗначения")); + Таблица.Колонки.Добавить("ДатаСоздания", Новый ОписаниеТипов("Дата")); + + Возврат Таблица; + +КонецФункции + +// Для функции ОписаниеНовойВерсииПараметровОграниченияДоступа. +Процедура ЗапланироватьОбновлениеДоступаПриИзмененииПараметров(СтараяВерсия, Параметры) + + НедоступныеСписки = Новый Массив; + СтараяВерсияСтруктурыКэша = "0"; + Списки = СпискиСИзменениемВерсий(СтараяВерсия, + Параметры.ВерсииОграниченийСписков, НедоступныеСписки, СтараяВерсияСтруктурыКэша); + + ПараметрыПланирования = ПараметрыПланированияОбновленияДоступа(); + ПараметрыПланирования.ВерсииОграниченийСписков = Параметры.ВерсииОграниченийСписков; + ПараметрыПланирования.ИдентификаторыВсехСписков = Параметры.ИдентификаторыВсехСписков; + ПараметрыПланирования.ЭтоПродолжениеОбновления = Истина; + ПараметрыПланирования.Описание = "НоваяВерсияПараметровОграниченияДоступа"; + + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(Списки, ПараметрыПланирования); + + Если ЗначениеЗаполнено(НедоступныеСписки) Тогда + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Ложь; + ЗапланироватьОбновлениеДоступа(НедоступныеСписки, ПараметрыПланирования); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(НедоступныеСписки, ПараметрыПланирования); + КонецЕсли; + + Если ЗначениеЗаполнено(Параметры.СпискиСНовымОсновнымВариантомДоступа) Тогда + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Ложь; + ЗапланироватьОбновлениеДоступа(Параметры.СпискиСНовымОсновнымВариантомДоступа, + ПараметрыПланирования); + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(Параметры.СпискиСНовымОсновнымВариантомДоступа, + ПараметрыПланирования); + КонецЕсли; + Если ЗначениеЗаполнено(Параметры.СпискиСУстаревшимиВариантамиДоступа) Тогда + ПараметрыПланирования.ЭтоОбработкаУстаревшихЭлементов = Истина; + ЗапланироватьОбновлениеДоступа(Параметры.СпискиСУстаревшимиВариантамиДоступа, + ПараметрыПланирования); + КонецЕсли; + + Если Списки = Неопределено + Или СтараяВерсияСтруктурыКэша = ВерсияСтруктурыКэша() Тогда + Возврат; + КонецЕсли; + + НовыеПараметры = Новый Структура(Параметры.ХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить()); + НовыеПараметры.Вставить("ИдентификаторыВсехСписков", Параметры.ИдентификаторыВсехСписков); + РегистрыСведений.ПараметрыОграниченияДоступа.ПриИзмененииВерсииСтруктурыКэша( + СтараяВерсияСтруктурыКэша, НовыеПараметры); + +КонецПроцедуры + +// Для процедуры ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений и +// функции НоваяВерсияПараметровОграниченияДоступа. +// +Процедура ПроверитьАктуальностьМетаданных() Экспорт + + КонфигурацияИзменена = КонфигурацияБазыДанныхИзмененаДинамически(); + РасширенияИзменены = Справочники.ВерсииРасширений.РасширенияИзмененыДинамически(); + + Если Не КонфигурацияИзменена И Не РасширенияИзменены Тогда + Возврат; + КонецЕсли; + + Попытка + Попытка + Если КонфигурацияИзменена Тогда + СтандартныеПодсистемыСервер.ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияВерсииПрограммы(); + ИначеЕсли РасширенияИзменены Тогда + СтандартныеПодсистемыСервер.ПотребоватьПерезапускСеансаПоПричинеДинамическогоОбновленияРасширенийПрограммы(); + КонецЕсли; + Исключение + Если ЭтоСеансФоновогоЗадания() + Или СтандартныеПодсистемыСервер.ЭтоРазделенныйРежимСеансаБезРазделителей() Тогда + ВызватьИсключение; + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось проверить или обновить права доступа по причине: + |%1 + | + |Повторите операцию через минуту, и если проблема останется, перезапустите сеанс.'"), + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); + ВызватьИсключение ТекстОшибки; + КонецПопытки; + Исключение + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); + СтандартныеПодсистемыСервер.УстановитьТребуетсяПерезапускСеанса(ТекстОшибки); + ПриОшибкеПроверкиАктуальностиМетаданных(ТекстОшибки); + ВызватьИсключение; + КонецПопытки; + +КонецПроцедуры + +// Для процедуры ПроверитьАктуальностьМетаданных +Функция ЭтоСеансФоновогоЗадания() + + Если ТекущийРежимЗапуска() <> Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + Возврат ТекущийСеанс.ИмяПриложения = "BackgroundJob"; + +КонецФункции + +// Для процедуры УстановитьОбновлениеДоступа +Функция ЭтоСеансФоновогоОбновленияДоступа() + + УстановитьПривилегированныйРежим(Истина); + Возврат ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЭтоСеансФоновогоОбновленияДоступа"); + +КонецФункции + +// Для процедур ВыполнитьОбновлениеДоступаНаУровнеЗаписей, ВыполнитьОбновлениеДоступаСпискаВФоне. +Процедура УстановитьЭтоСеансФоновогоОбновленияДоступа() + + Если ТекущийРежимЗапуска() <> Неопределено Тогда + Возврат; + КонецЕсли; + + ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы(); + Если ТекущийСеанс.ИмяПриложения <> "BackgroundJob" Тогда + Возврат; + КонецЕсли; + + УстановитьПривилегированныйРежим(Истина); + + Параметры = Новый Структура(ПараметрыСеанса.ПараметрыОграниченияДоступа); + Параметры.Вставить("ЭтоСеансФоновогоОбновленияДоступа"); + ПараметрыСеанса.ПараметрыОграниченияДоступа = Новый ФиксированнаяСтруктура(Параметры); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Процедура ЗаписатьНесоответствиеПараметровВЖурнал(Запись, Комментарий, ЭтоОшибка = Ложь) + + Если Не ЗначениеЗаполнено(Комментарий) Тогда + Возврат; + КонецЕсли; + + ИмяСобытия = НСтр("ru = 'Управление доступом.Параметры ограничения доступа.Несоответствие'", + ОбщегоНазначения.КодОсновногоЯзыка()); + ШаблонЗаголовка = + НСтр("ru = 'Есть несоответствие в записанных параметрах ограничения доступа + |Версия %1, Дата создания %2, Хеш-Сумма: %3, + |Хеш-сумма постоянных параметров: %4'"); + + Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗаголовка, + Запись.Версия, + Запись.ДатаСоздания, + Запись.ХешСумма, + Запись.ХешСуммаПостоянныхПараметров); + + УровеньЖурнала = ?(ЭтоОшибка, УровеньЖурналаРегистрации.Ошибка, + УровеньЖурналаРегистрации.Предупреждение); + + ЗаписьЖурналаРегистрации(ИмяСобытия, + УровеньЖурнала, + Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа,, + Заголовок + Символы.ПС + Символы.ПС + Комментарий, + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Процедура ЗарегистрироватьСтрокуВерсииПараметровОграниченияДоступа(Запись, СтрокиВерсии) + + Состав = Новый Массив; + Состав.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + "Версия = %1 + |ДатаСоздания = %2 + |ХешСумма = %3 + |ХешСуммаПостоянныхПараметров = %4 + |ХешСуммаПараметровШаблонов = %5", + Запись.Версия, + Формат(Запись.ДатаСоздания, "ДЛФ=DT"), + Запись.ХешСумма, + Запись.ХешСуммаПостоянныхПараметров, + Запись.ХешСуммаПараметровШаблонов)); + + Для Каждого Строка Из СтрокиВерсии.СтрокиВерсийСписков Цикл + Состав.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + "[Список = %1, ДляВнешнихПользователей = %2, Версия = %3] + |%4", + Строка.Список, + ?(Строка.ДляВнешнихПользователей, "Да", "Нет"), + Строка.Версия, + Строка.СтрокаВерсии)); + КонецЦикла; + + Состав.Добавить("[ВсеВерсииСтрокой] + |" + СтрокиВерсии.ВсеВерсииСтрокой); + + Состав.Добавить("[ВидыОграниченийПравДляПользователейСтрокой] + |" + СтрокиВерсии.ВидыОграниченийПравДляПользователейСтрокой); + + Состав.Добавить("[ВидыОграниченийПравДляВнешнихПользователейСтрокой] + |" + СтрокиВерсии.ВидыОграниченийПравДляВнешнихПользователейСтрокой); + + Состав.Добавить("[СпискиСОграничениемПоПолямВСеансахПользователей] + |" + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахПользователей); + + Состав.Добавить("[СпискиСОграничениемПоПолямВСеансахВнешнихПользователей] + |" + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахВнешнихПользователей); + + Комментарий = СтрСоединить(Состав, Символы.ПС); + + ЗаписьЖурналаРегистрации( + НСтр("ru = 'Управление доступом.Параметры ограничения доступа.Строка версии'", + ОбщегоНазначения.КодОсновногоЯзыка()), + УровеньЖурналаРегистрации.Информация, + Метаданные.РегистрыСведений.ПараметрыОграниченияДоступа,, + Комментарий, + РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +Функция СпискиСИзменениемВерсий(Версия, НовыеВерсииОграниченийСписков, НедоступныеСписки, + СтараяВерсияСтруктурыКэша) + + Если Не ЗначениеЗаполнено(Версия) Тогда + Возврат Неопределено; + КонецЕсли; + + ВерсияПараметров = ВерсияПараметров(Версия, Ложь, Ложь); + ПараметрыЗаписиХранилище = ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав; + + Если ТипЗнч(ПараметрыЗаписиХранилище) <> Тип("ХранилищеЗначения") Тогда + Возврат Неопределено; + КонецЕсли; + ПараметрыЗаписи = ЗначениеИзХранилища(ПараметрыЗаписиХранилище); + + Если ТипЗнч(ПараметрыЗаписи) <> Тип("ФиксированнаяСтруктура") + Или Не ПараметрыЗаписи.Свойство("ВерсииОграниченийСписков") + Или ТипЗнч(ПараметрыЗаписи.ВерсииОграниченийСписков) <> Тип("ФиксированноеСоответствие") Тогда + Возврат Неопределено; + КонецЕсли; + + Свойства = Новый Структура("ВерсияСтруктурыКэша", СтараяВерсияСтруктурыКэша); + ЗаполнитьЗначенияСвойств(Свойства, ПараметрыЗаписи); + СтараяВерсияСтруктурыКэша = Свойства.ВерсияСтруктурыКэша; + + Таблица = Новый ТаблицаЗначений; + Таблица.Колонки.Добавить("Список", Новый ОписаниеТипов("Строка")); + Таблица.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка")); + Таблица.Колонки.Добавить("ВидИзменения", Новый ОписаниеТипов("Число")); + + Для Каждого КлючИЗначение Из ПараметрыЗаписи.ВерсииОграниченийСписков Цикл + Строка = Таблица.Добавить(); + Строка.Список = КлючИЗначение.Ключ; + Строка.Версия = СтрПолучитьСтроку(КлючИЗначение.Значение, 1) + + Символы.ПС + СтрПолучитьСтроку(КлючИЗначение.Значение, 2); + Строка.ВидИзменения = -1; + КонецЦикла; + + Для Каждого КлючИЗначение Из НовыеВерсииОграниченийСписков Цикл + Строка = Таблица.Добавить(); + Строка.Список = КлючИЗначение.Ключ; + Строка.Версия = СтрПолучитьСтроку(КлючИЗначение.Значение, 1) + + Символы.ПС + СтрПолучитьСтроку(КлючИЗначение.Значение, 2); + Строка.ВидИзменения = 1; + КонецЦикла; + + Таблица.Свернуть("Список, Версия", "ВидИзменения"); + Списки = Новый Массив; + НенайденныеСписки = Новый Массив; + + Для Каждого Строка Из Таблица Цикл + Если Строка.ВидИзменения = 0 Тогда + Продолжить; + КонецЕсли; + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Строка.Список); + Если ОбъектМетаданных = Неопределено Тогда + НенайденныеСписки.Добавить(Строка.Список); + Продолжить; + КонецЕсли; + ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); + Если Списки.Найти(ПолноеИмя) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Списки.Добавить(ПолноеИмя); + КонецЦикла; + + Если НенайденныеСписки.Количество() > 0 Тогда + НедоступныеСписки = ВсеИдентификаторыСПодобнымиПолнымиИменами(НенайденныеСписки); + + ИначеЕсли Списки.Количество() = 1 И Списки[0] = "Справочник.НаборыГруппДоступа" Тогда + Списки = Новый Массив; + КонецЕсли; + + Возврат Списки; + +КонецФункции + +// Для функции СпискиСИзменениемВерсий и для процедуры ДобавитьЗависимыеСписки. +Функция ВсеИдентификаторыСПодобнымиПолнымиИменами(ПолныеИмена) + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | Идентификаторы.Ссылка КАК Ссылка + |ИЗ + | Справочник.ИдентификаторыОбъектовМетаданных КАК Идентификаторы + |ГДЕ + | &УсловияОтбораИОМ + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | Идентификаторы.Идентификатор + |ИЗ + | РегистрСведений.ИдентификаторыОбъектовВерсийРасширений КАК Идентификаторы + |ГДЕ + | &УсловияОтбораИОР"; + + УсловияОтбораИОМ = Новый Массив; + УсловияОтбораИОР = Новый Массив; + + НомерПараметра = 1; + Для Каждого ПолноеИмя Из ПолныеИмена Цикл + ИмяПараметра = "ПолноеИмя" + Формат(НомерПараметра, "ЧГ="); + Запрос.УстановитьПараметр(ИмяПараметра, ПолноеИмя); + УсловияОтбораИОМ.Добавить(СтрЗаменить("Идентификаторы.ПолноеИмя ПОДОБНО &ИмяПараметра СПЕЦСИМВОЛ ""~""", + "ИмяПараметра", ИмяПараметра)); // @query-part-1, @query-part-2 + УсловияОтбораИОР.Добавить(СтрЗаменить("Идентификаторы.ПолноеИмяОбъекта ПОДОБНО &ИмяПараметра СПЕЦСИМВОЛ ""~""", + "ИмяПараметра", ИмяПараметра)); // @query-part-1, @query-part-2 + НомерПараметра = НомерПараметра + 1; + КонецЦикла; + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловияОтбораИОМ", + СтрСоединить(УсловияОтбораИОМ, Символы.ПС + " ИЛИ ")); // @query-part-2 + + Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловияОтбораИОР", + СтрСоединить(УсловияОтбораИОР, Символы.ПС + " ИЛИ ")); // @query-part-2 + + Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); + +КонецФункции + +// Для процедуры ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Строка +// +Функция ВерсияСтруктурыКэша() Экспорт + + // Число нужно увеличивать при внесении изменений в состав параметров кэша + // (в том числе при изменении версии шаблонов). + Возврат "28.2" + ВерсияПеревода(); + +КонецФункции + +Функция ВерсияПеревода() + + Если ВариантВстроенногоЯзыкаРусский() Тогда + Возврат ""; + Иначе + Возврат "/" + Метаданные.Версия; + КонецЕсли; + +КонецФункции + +// Для процедур УстановкаПараметровСеанса, УточнитьВерсииШаблоновОграниченияДоступа и +// для функции СтруктураХранимыхПараметровШаблонов. +// +// Возвращаемое значение: +// Строка +// +Функция ВерсииШаблоновОграниченияДоступа() + + Возврат + ",ДляОбъекта9, + |,ДляРегистра9, + |,ПоЗначениям18, + |,ПоЗначениямРасширенный18, + |,ПоЗначениямИНаборамРасширенный18, + |,ПоНаборамЗначений18,"; + +КонецФункции + +// Для процедур УстановитьВерсиюПараметров, ЗаполнитьПараметрыДляШаблонов и +// функции НоваяСтруктураХранимыхВерсийПараметровШаблонов. +// +// +// Возвращаемое значение: +// Строка +// +Функция ВерсияСтруктурыВерсийПараметровШаблонов() + + // Число нужно увеличивать только при внесении изменений + // в состав параметра ВерсииПараметровШаблонов. + Возврат "1"; + +КонецФункции + +// Для функции ДействующиеПараметрыОграниченияДоступа. +Процедура ОбновитьИдентификаторыТранзакции(ИдентификаторТранзакции) + + Кэш = КэшПараметровОграничения(); + + Если Не ТранзакцияАктивна() И Кэш.ИдентификаторыТранзакции.Количество() = 0 + Или ТранзакцияАктивна() И ИдентификаторТранзакции = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ИдентификаторТранзакции <> Неопределено И ТранзакцияАктивна() Тогда + Кэш.ИдентификаторыТранзакции.Вставить(ИдентификаторТранзакции, Истина); + Иначе + Кэш.ИдентификаторыТранзакции.Очистить(); + КонецЕсли; + +КонецПроцедуры + +// Для функции ДействующиеПараметрыОграниченияДоступа. +Процедура УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов = Ложь, ПовторныйВызов = Ложь) + + Если Не ПовторныйВызов Тогда + Если УстановкаПараметровСеансаДляШаблонов Тогда + СброситьКэшПараметровОграничения(); + Иначе + ОбновитьПовторноИспользуемыеЗначения(); + КонецЕсли; + КонецЕсли; + + Если ИдентификаторТранзакции <> Неопределено И ТранзакцияАктивна() Тогда + Кэш = КэшПараметровОграничения(); + Кэш.ИдентификаторыТранзакции.Вставить(ИдентификаторТранзакции, Истина); + КонецЕсли; + + Если ТипЗнч(ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав) = Тип("ХранилищеЗначения") Тогда + ДляЗаписиОбъектовИПроверкиПрав = СтруктураХранимыхПараметровЗаписи( + ЗначениеИзХранилища(ВерсияПараметров.ДляЗаписиОбъектовИПроверкиПрав)); + + Если ДляЗаписиОбъектовИПроверкиПрав.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Иначе + ДляЗаписиОбъектовИПроверкиПрав = Неопределено; + КонецЕсли; + + Если ТипЗнч(ВерсияПараметров.ВерсииПараметровШаблонов) = Тип("ХранилищеЗначения") Тогда + ВерсииПараметровШаблонов = СтруктураХранимыхВерсийПараметровШаблонов( + ЗначениеИзХранилища(ВерсияПараметров.ВерсииПараметровШаблонов)); + + Если ВерсииПараметровШаблонов.ВерсияСтруктурыВерсий <> ВерсияСтруктурыВерсийПараметровШаблонов() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Иначе + ВерсииПараметровШаблонов = Неопределено; + КонецЕсли; + + Если ТипЗнч(ВерсияПараметров.ДляОтчетаПоПравамДоступа) = Тип("ХранилищеЗначения") Тогда + ДляОтчетаПоПравамДоступа = СтруктураХранимыхПараметровОтчета( + ЗначениеИзХранилища(ВерсияПараметров.ДляОтчетаПоПравамДоступа)); + + Если ДляОтчетаПоПравамДоступа.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Кэш = КэшПараметровОграничения(); + Кэш.ВидыОграниченийПравДляПользователей + = ДляОтчетаПоПравамДоступа.ВидыОграниченийПравДляПользователей; + Кэш.ВидыОграниченийПравДляВнешнихПользователей + = ДляОтчетаПоПравамДоступа.ВидыОграниченийПравДляВнешнихПользователей; + КонецЕсли; + + Если УстановкаПараметровСеансаДляШаблонов + Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + + ХранилищеДляШаблоновВСеансах = ?(Пользователи.ЭтоСеансВнешнегоПользователя(), + ВерсияПараметров.ДляШаблоновВСеансахВнешнихПользователей, + ВерсияПараметров.ДляШаблоновВСеансахПользователей); + + Если ТипЗнч(ХранилищеДляШаблоновВСеансах) = Тип("ХранилищеЗначения") Тогда + ДляШаблоновОграниченияДоступа = СтруктураХранимыхПараметровШаблонов( + ЗначениеИзХранилища(ХранилищеДляШаблоновВСеансах)); + + Если ДляШаблоновОграниченияДоступа.ВерсияСтруктурыКэша <> ВерсияСтруктурыКэша() Тогда + ВерсияПараметров = НоваяВерсияПараметровОграниченияДоступа(ОбщийКонтекст); + УстановитьВерсиюПараметров(ВерсияПараметров, ИдентификаторТранзакции, ОбщийКонтекст, + УстановкаПараметровСеансаДляШаблонов, Истина); + Возврат; + КонецЕсли; + Иначе + ДляШаблоновОграниченияДоступа = НоваяСтруктураХранимыхПараметровШаблонов(); + КонецЕсли; + + ВерсииШаблонов = СтрСоединить(СтрРазделить( + ДляШаблоновОграниченияДоступа.ВерсииШаблонов, Символы.ПС + Символы.ВК, Ложь), Символы.ПС); + УточнитьВерсииШаблоновОграниченияДоступа(ВерсииШаблонов); + + ПараметрыШаблонов = Новый Структура(СтруктураПараметровШаблонов( + ДляШаблоновОграниченияДоступа.ПараметрыШаблонов)); + ПараметрыШаблонов.Вставить("ВерсииШаблоновОграниченияДоступа", ВерсииШаблонов); + + ОбновитьПараметрыСеансаДляШаблонов = УстановкаПараметровСеансаДляШаблонов; + Если Не УстановкаПараметровСеансаДляШаблонов + И ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + + Для Каждого КлючИЗначение Из ПараметрыШаблонов Цикл + Если ПараметрыСеанса[КлючИЗначение.Ключ] <> КлючИЗначение.Значение Тогда + ОбновитьПараметрыСеансаДляШаблонов = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ОбновитьПараметрыСеансаДляШаблонов Тогда + ПередИзменениемПараметровСеансаДляШаблонов(ПараметрыШаблонов, УстановкаПараметровСеансаДляШаблонов); + ЗаполнитьЗначенияСвойств(ПараметрыСеанса, ПараметрыШаблонов); + КонецЕсли; + КонецЕсли; + + ОбновитьРазрешенныеНаборыВПараметрахСеанса(УстановкаПараметровСеансаДляШаблонов, Истина); + + Параметры = СеансовыеПараметрыОграниченияДоступа(ВерсияПараметров, + ДляЗаписиОбъектовИПроверкиПрав, ВерсииПараметровШаблонов, УстановкаПараметровСеансаДляШаблонов); + ПараметрыСеанса.ПараметрыОграниченияДоступа = Параметры; + +КонецПроцедуры + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Версия - Строка +// * ХешСумма - Строка +// * ДатаСоздания - Дата +// * Параметры - см. СтруктураХранимыхПараметровЗаписи +// +Функция СеансовыеПараметрыОграниченияДоступа(ВерсияПараметров, ДляЗаписиОбъектовИПроверкиПрав, + ВерсииПараметровШаблонов, УстановкаПараметровСеансаДляШаблонов) + + ПараметрыОграничения = Новый Структура; + ПараметрыОграничения.Вставить("Версия", ВерсияПараметров.Версия); + ПараметрыОграничения.Вставить("ХешСумма", ВерсияПараметров.ХешСумма); + ПараметрыОграничения.Вставить("ДатаСоздания", ВерсияПараметров.ДатаСоздания); + + Если ДляЗаписиОбъектовИПроверкиПрав = Неопределено Тогда + Параметры = Неопределено; + Иначе + ПрочитанныеПараметры = Новый Структура(ДляЗаписиОбъектовИПроверкиПрав); + ДополнительныйКонтекст = Новый Структура(ПрочитанныеПараметры.ДополнительныйКонтекст); + ДляПользователей = Новый Структура(ДополнительныйКонтекст.ДляПользователей); + ДляПользователей.ОсновныеВариантыДоступа = Новый ФиксированноеСоответствие( + ВерсииПараметровШаблонов.ДляПользователей.ОсновныеВариантыДоступа); + ДополнительныйКонтекст.ДляПользователей = Новый ФиксированнаяСтруктура(ДляПользователей); + ДляВнешнихПользователей = Новый Структура(ДополнительныйКонтекст.ДляВнешнихПользователей); + ДляВнешнихПользователей.ОсновныеВариантыДоступа = Новый ФиксированноеСоответствие( + ВерсииПараметровШаблонов.ДляВнешнихПользователей.ОсновныеВариантыДоступа); + ДополнительныйКонтекст.ДляВнешнихПользователей = Новый ФиксированнаяСтруктура(ДляВнешнихПользователей); + ПрочитанныеПараметры.ДополнительныйКонтекст = Новый ФиксированнаяСтруктура(ДополнительныйКонтекст); + Параметры = Новый ФиксированнаяСтруктура(ПрочитанныеПараметры); + КонецЕсли; + + ПараметрыОграничения.Вставить("Параметры", Параметры); + + Если УстановкаПараметровСеансаДляШаблонов + Или ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + ПараметрыОграничения.Вставить("ПараметрыСеансаДляШаблоновУстановлены"); + КонецЕсли; + + Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЗаписьПараметровОграниченияДоступаВТекущемСеансе") Тогда + ПараметрыОграничения.Вставить("ЗаписьПараметровОграниченияДоступаВТекущемСеансе", + ПараметрыСеанса.ПараметрыОграниченияДоступа.ЗаписьПараметровОграниченияДоступаВТекущемСеансе); + КонецЕсли; + + Если ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ЭтоСеансФоновогоОбновленияДоступа") Тогда + ПараметрыОграничения.Вставить("ЭтоСеансФоновогоОбновленияДоступа"); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ПараметрыОграничения); + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +Процедура УточнитьВерсииШаблоновОграниченияДоступа(ВерсииШаблонов) + + Если ВерсииШаблонов = ВерсииШаблоновОграниченияДоступа() Тогда + Возврат; + КонецЕсли; + + ВерсииШаблонов = ВерсииШаблоновОграниченияДоступа() + " + |,ТребуетсяПерезапуститьСеанс,"; + +КонецПроцедуры + +// Для процедуры УстановитьВерсиюПараметров, ПроверитьДоступКОбъекту, +// ПроверитьДоступКНаборуЗаписей и функции ДоступРазрешен. +// +Процедура ОбновитьРазрешенныеНаборыВПараметрахСеанса(УстановкаПараметровСеансаДляШаблонов = Ложь, + УстановкаПараметровОграниченияДоступа = Ложь) + + Если Не УстановкаПараметровСеансаДляШаблонов + И Не ПараметрыСеанса.ПараметрыОграниченияДоступа.Свойство("ПараметрыСеансаДляШаблоновУстановлены") Тогда + Возврат; + КонецЕсли; + + ПоследняяПроверка = УправлениеДоступомСлужебныйПовтИсп.ПоследняяПроверкаВерсииРазрешенныхНаборов(); + + Если Не УстановкаПараметровСеансаДляШаблонов + И Не УстановкаПараметровОграниченияДоступа + И ПоследняяПроверка.Дата + 5 >= ТекущаяДатаСеанса() Тогда + Возврат; + КонецЕсли; + + ПоследняяПроверка.Дата = ТекущаяДатаСеанса(); + + Состав = РазрешенныеНаборыПараметровЗапроса(); + + Если Не УстановкаПараметровСеансаДляШаблонов + И ПараметрыСеанса.РазрешенныйПользователь = Состав.РазрешенныйПользователь + И ПараметрыСеанса.РазрешенныйНаборГруппДоступа = Состав.РазрешенныйНаборГруппДоступа + И ПараметрыСеанса.РазрешенныйНаборГруппПользователей = Состав.РазрешенныйНаборГруппПользователей + И ПараметрыСеанса.РазрешенныйПустойНаборГруппДоступа = Состав.РазрешенныйПустойНаборГруппДоступа Тогда + + Возврат; + КонецЕсли; + + Состав.Вставить("ОбщиеПараметрыШаблоновОграниченияДоступа", ""); + УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса(Состав); + + ПередИзменениемПараметровСеансаДляШаблонов(Состав, УстановкаПараметровСеансаДляШаблонов); + ЗаполнитьЗначенияСвойств(ПараметрыСеанса, Состав); + +КонецПроцедуры + +// Для процедуры ОбновитьРазрешенныеНаборыВПараметрахСеанса и +// УстановитьРазрешенныеНаборыВПараметрыЗапроса. +// +// Параметры: +// Пользователь - СправочникСсылка.Пользователи +// - СправочникСсылка.ВнешниеПользователи +// - Неопределено - текущий пользователь. +// +// Возвращаемое значение: +// Структура: +// * РазрешенныйПользователь - СправочникСсылка.НаборыГруппДоступа +// * РазрешенныйНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа +// * РазрешенныйНаборГруппПользователей - СправочникСсылка.НаборыГруппДоступа +// * РазрешенныйПустойНаборГруппДоступа - СправочникСсылка.НаборыГруппДоступа +// +Функция РазрешенныеНаборыПараметровЗапроса(Знач Пользователь = Неопределено) + + ПустойНаборГруппДоступа = Справочники.НаборыГруппДоступа.ПустаяСсылка(); + + Состав = Новый Структура; + Состав.Вставить("РазрешенныйПользователь", ПустойНаборГруппДоступа); + Состав.Вставить("РазрешенныйНаборГруппДоступа", ПустойНаборГруппДоступа); + Состав.Вставить("РазрешенныйНаборГруппПользователей", ПустойНаборГруппДоступа); + Состав.Вставить("РазрешенныйПустойНаборГруппДоступа", + УправлениеДоступомСлужебныйПовтИсп.РазрешенныйПустойНаборГруппДоступа()); + + Если Пользователи.ЭтоПолноправныйПользователь(Пользователь,, Ложь) Тогда + Возврат Состав; + КонецЕсли; + + Если Пользователь = Неопределено Тогда + Пользователь = Пользователи.АвторизованныйПользователь(); + КонецЕсли; + + Состав.РазрешенныйПользователь = Справочники.НаборыГруппДоступа.ПолучитьСсылку( + Пользователь.УникальныйИдентификатор()); + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("РазрешенныйПользователь", Состав.РазрешенныйПользователь); + Запрос.Текст = + "ВЫБРАТЬ + | НаборыГруппДоступа.РазрешенныйНаборГруппДоступа КАК РазрешенныйНаборГруппДоступа, + | НаборыГруппДоступа.РазрешенныйНаборГруппПользователей КАК РазрешенныйНаборГруппПользователей + |ИЗ + | Справочник.НаборыГруппДоступа КАК НаборыГруппДоступа + |ГДЕ + | НаборыГруппДоступа.Ссылка = &РазрешенныйПользователь"; + + Выборка = Запрос.Выполнить().Выбрать(); + Если Выборка.Следующий() Тогда + Состав.РазрешенныйНаборГруппДоступа = Выборка.РазрешенныйНаборГруппДоступа; + Состав.РазрешенныйНаборГруппПользователей = Выборка.РазрешенныйНаборГруппПользователей; + КонецЕсли; + + Возврат Состав; + +КонецФункции + +// Для процедуры ОбновитьРазрешенныеНаборыВПараметрахСеанса. +Процедура УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса(Состав) + + Если Не УправлениеДоступомСлужебныйПовтИсп.ТребуетсяУточнениеПланаЗапроса() Тогда + Возврат; + КонецЕсли; + + Состав.ОбщиеПараметрыШаблоновОграниченияДоступа = ";УточнитьДляВсех;" + + ОписаниеХешСуммыНастроекПрав(Состав.РазрешенныйНаборГруппДоступа) + + ОписаниеХешСуммыНастроекПрав(Состав.РазрешенныйПользователь, "^"); + +КонецПроцедуры + +// Для процедуры УчестьНастройкиПравПриПостроенииПланаВыполненияЗапроса. +Функция ОписаниеХешСуммыНастроекПрав(НаборГруппДоступа, Символ = "") + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.CRC32); + ХешированиеДанных.Добавить(ПолучитьДвоичныеДанныеИзHexСтроки(СтрЗаменить( + НаборГруппДоступа.УникальныйИдентификатор(), "-", ""))); + Остаток = ХешированиеДанных.ХешСумма; + + Результат = ""; + Для Счетчик = 1 По 32 Цикл + Целое = Цел(Остаток / 2); + Результат = ?(Остаток - Целое * 2 = 0, "", XMLСтрока(Счетчик) + Символ + ";") + Результат; + Остаток = Целое; + КонецЦикла; + + Возврат Символы.ПС + ";" + Результат; + +КонецФункции + +// Для функции ДоступРазрешен и процедур ПроверитьДоступКОбъекту, ПроверитьДоступКНаборуЗаписей. +Процедура УстановитьРазрешенныеНаборыВПараметрыЗапроса(Запрос, Знач Пользователь = Неопределено) + + Если Пользователь = Неопределено Тогда + Параметры = ПараметрыСеанса; + Пользователь = Пользователи.АвторизованныйПользователь(); + Иначе + Параметры = РазрешенныеНаборыПараметровЗапроса(Пользователь); + КонецЕсли; + + Запрос.УстановитьПараметр("РазрешенныйНаборГруппДоступа", Параметры.РазрешенныйНаборГруппДоступа); + Запрос.УстановитьПараметр("РазрешенныйПустойНаборГруппДоступа", Параметры.РазрешенныйПустойНаборГруппДоступа); + Запрос.УстановитьПараметр("РазрешенныйНаборГруппПользователей", Параметры.РазрешенныйНаборГруппПользователей); + Запрос.УстановитьПараметр("РазрешенныйПользователь", Параметры.РазрешенныйПользователь); + Запрос.УстановитьПараметр("АвторизованныйПользователь", Пользователь); + +КонецПроцедуры + +// Для функции НоваяВерсияПараметровОграниченияДоступа. +// +// Параметры: +// ОбщийКонтекст - см. ОбщийКонтекстРасчетаПараметровОграничения +// ВерсииОграниченийСписков - Соответствие +// +// Возвращаемое значение: +// Структура: +// * ДатаСоздания - Дата +// * ДляЗаписиОбъектовИПроверкиПрав - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровЗаписи +// * ДляОтчетаПоПравамДоступа - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровОтчета +// * ХешСуммаПостоянныхПараметров - Строка +// * ДляШаблоновВСеансахПользователей - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровШаблонов +// * ДляШаблоновВСеансахВнешнихПользователей - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхПараметровШаблонов +// * ВерсииПараметровШаблонов - ХранилищеЗначения - содержит тип НоваяСтруктураХранимыхВерсийПараметровШаблонов +// * ХешСуммаПараметровШаблонов - Строка - заполняется при записи после обновления +// параметра ВерсииПараметровШаблонов и заполнения свойства СпискиСОграничениемПоПолям +// параметров ДляШаблоновВСеансахПользователей, ДляШаблоновВСеансахВнешнихПользователей. +// * ХешСумма - Строка - заполняется при записи, +// вычисляется из хеш-сумм ХешСуммаПостоянныхПараметров и ХешСуммаПараметровШаблонов. +// +Функция ХранимыеПараметрыОграниченияДоступа(ОбщийКонтекст, ВерсииОграниченийСписков = Неопределено) + + ДатаСоздания = ТекущаяДатаСеанса(); + + Если ОбщийКонтекст = Неопределено Тогда + ОбновитьПовторноИспользуемыеЗначения(); + ОбщийКонтекст = ОбщийКонтекстРасчетаПараметровОграничения(); + + ИначеЕсли ОбщийКонтекст.Свойство("СпециальноеПолноеИмя") Тогда + СпециальноеПолноеИмя = ОбщийКонтекст.СпециальноеПолноеИмя; + СпециальноеОписаниеОграничения = ОбщийКонтекст.СпециальноеОписаниеОграничения; + КонецЕсли; + + ДополнительныйКонтекстДляПользователей = НовыйДополнительныйКонтекст(); + ДополнительныйКонтекстДляВнешнихПользователей = НовыйДополнительныйКонтекст(); + + ОписаниеОграничений = Новый Соответствие; + ПолныеИменаСписков = Новый Массив; + Для Каждого ОписаниеСписка Из ОбщийКонтекст.СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + ПолныеИменаСписков.Добавить(ПолноеИмя); + Если ПолноеИмя = СпециальноеПолноеИмя Тогда + ОписаниеОграничения = СпециальноеОписаниеОграничения; + Иначе + ОписаниеОграничения = ОписаниеОграниченияДанных(ОбщийКонтекст, ПолноеИмя); + КонецЕсли; + ОписаниеОграничений.Вставить(ПолноеИмя, ОписаниеОграничения); + + ДобавитьДополнительныйКонтекст(ПолноеИмя, + ДополнительныйКонтекстДляПользователей, ОписаниеОграничения, Ложь); + + ДобавитьДополнительныйКонтекст(ПолноеИмя, + ДополнительныйКонтекстДляВнешнихПользователей, ОписаниеОграничения, Истина); + КонецЦикла; + + СпискиСДатой = Новый Соответствие; + ИдентификаторыСписков = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИменаСписков); + ВерсияТекстовОграниченияДоступа = + РегистрыСведений.ПараметрыОграниченияДоступа.ВерсияТекстовОграниченияДоступа(ОписаниеОграничений); + + ВидыОграниченийПравДляПользователей = Новый Соответствие; + ВидыОграниченийПравДляВнешнихПользователей = Новый Соответствие; + + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + СтрокиВерсийСписков = НовыеСтрокиВерсийСписков(); + СтрокиВерсииХранимыхПараметров = Новый Структура; + СтрокиВерсииХранимыхПараметров.Вставить("ВсеВерсииСтрокой", ""); + СтрокиВерсииХранимыхПараметров.Вставить("ВидыОграниченийПравДляПользователейСтрокой", ""); + СтрокиВерсииХранимыхПараметров.Вставить("ВидыОграниченийПравДляВнешнихПользователейСтрокой", ""); + СтрокиВерсииХранимыхПараметров.Вставить("СтрокиВерсийСписков", СтрокиВерсийСписков); + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров = СтрокиВерсииХранимыхПараметров; + КонецЕсли; + + Если ОбщийКонтекст.Свойство("ИнформацияДляЖурнала") Тогда + СпискиБезВнедрения = Новый Структура; + СпискиБезВнедрения.Вставить("ОбъектыПредупреждения", Новый Соответствие); + СпискиБезВнедрения.Вставить("ОбъектыОшибки", Новый Соответствие); + СпискиБезВнедрения.Вставить("РегистрыПредупреждения", Новый Массив); + Иначе + СпискиБезВнедрения = Неопределено; + КонецЕсли; + + // Заполнение для пользователей. + КонтекстДляПользователей = Новый Структура; + КонтекстДляПользователей.Вставить("ДляВнешнихПользователей", Ложь); + КонтекстДляПользователей.Вставить("ДатаСоздания", ДатаСоздания); + КонтекстДляПользователей.Вставить("ОбщийКонтекст", ОбщийКонтекст); + КонтекстДляПользователей.Вставить("ДополнительныйКонтекст", ДополнительныйКонтекстДляПользователей); + КонтекстДляПользователей.Вставить("ВедущиеСписки", Новый Соответствие); + КонтекстДляПользователей.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + КонтекстДляПользователей.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); + КонтекстДляПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + КонтекстДляПользователей.Вставить("СпискиСДатой", СпискиСДатой); + КонтекстДляПользователей.Вставить("ИдентификаторыСписков", ИдентификаторыСписков); + КонтекстДляПользователей.Вставить("ВсеВидыОграниченийПрав", ВидыОграниченийПравДляПользователей); + КонтекстДляПользователей.Вставить("ВедущиеРоли", Новый Соответствие); + КонтекстДляПользователей.Вставить("СпискиБезВнедрения", СпискиБезВнедрения); + + ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(КонтекстДляПользователей); + + // Заполнение для внешних пользователей. + КонтекстДляВнешнихПользователей = Новый Структура; + КонтекстДляВнешнихПользователей.Вставить("ДляВнешнихПользователей", Истина); + КонтекстДляВнешнихПользователей.Вставить("ДатаСоздания", ДатаСоздания); + КонтекстДляВнешнихПользователей.Вставить("ОбщийКонтекст", ОбщийКонтекст); + КонтекстДляВнешнихПользователей.Вставить("ДополнительныйКонтекст", ДополнительныйКонтекстДляВнешнихПользователей); + КонтекстДляВнешнихПользователей.Вставить("ВедущиеСписки", Новый Соответствие); + КонтекстДляВнешнихПользователей.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + КонтекстДляВнешнихПользователей.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); + КонтекстДляВнешнихПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + КонтекстДляВнешнихПользователей.Вставить("СпискиСДатой", СпискиСДатой); + КонтекстДляВнешнихПользователей.Вставить("ИдентификаторыСписков", ИдентификаторыСписков); + КонтекстДляВнешнихПользователей.Вставить("ВсеВидыОграниченийПрав", ВидыОграниченийПравДляВнешнихПользователей); + КонтекстДляВнешнихПользователей.Вставить("ВедущиеРоли", Новый Соответствие); + КонтекстДляВнешнихПользователей.Вставить("СпискиБезВнедрения", СпискиБезВнедрения); + + ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(КонтекстДляВнешнихПользователей); + + Если ОбщийКонтекст.Свойство("ИнформацияДляЖурнала") Тогда + ЗаполнитьНесоответствиеПараметровДляЖурнала(СпискиБезВнедрения, ОбщийКонтекст.ИнформацияДляЖурнала); + ОбщийКонтекст.ИнформацияДляЖурнала.ВерсияТекстовОграниченияДоступа = ВерсияТекстовОграниченияДоступа; + КонецЕсли; + + // Заполнение общей и отдельной частей ведущих списков для пользователей и внешних пользователей. + ВедущиеСписки = Новый Соответствие; + Для Каждого ОписаниеВедущихСписков Из КонтекстДляПользователей.ВедущиеСписки Цикл + ДобавитьВедущиеСписки(ВедущиеСписки, + "ДляПользователей", ОписаниеВедущихСписков.Ключ, ОписаниеВедущихСписков.Значение); + КонецЦикла; + Для Каждого ОписаниеВедущихСписков Из КонтекстДляВнешнихПользователей.ВедущиеСписки Цикл + ДобавитьВедущиеСписки(ВедущиеСписки, + "ДляВнешнихПользователей", ОписаниеВедущихСписков.Ключ, ОписаниеВедущихСписков.Значение); + КонецЦикла; + Свойства = ВедущийСписокПоЗначениямПолей(); + Для Каждого ВедущийСписок Из ВедущиеСписки Цикл + Свойства = ВедущийСписок.Значение; + Если Свойства.ПоЗначениямПолей <> Неопределено Тогда + ПоЗначениямПолей = Свойства.ПоЗначениямПолей; + Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда + ТабличныеЧасти = Новый Массив; + Для Каждого ОписаниеТабличнойЧасти Из ПоЗначениямПолей.ТабличныеЧасти Цикл + ТабличныеЧасти.Добавить(ОписаниеТабличнойЧасти.Значение); + КонецЦикла; + ПоЗначениямПолей.ТабличныеЧасти = ТабличныеЧасти; + КонецЕсли; + КонецЕсли; + КонецЦикла; + + // Заполнение ведущих ролей для пользователей и внешних пользователей. + ВедущиеРоли = Новый Соответствие; + ДобавитьВедущиеРоли(ВедущиеРоли, "ДляПользователей", КонтекстДляПользователей); + ДобавитьВедущиеРоли(ВедущиеРоли, "ДляВнешнихПользователей", КонтекстДляВнешнихПользователей); + + // Расчет версий ограничения доступа. + ВерсииОграниченийСписков = Новый Соответствие; + Версии = Новый СписокЗначений; + Версии.Добавить(ВерсияСтруктурыКэша()); + Для Каждого ОписаниеВерсии Из КонтекстДляПользователей.ВерсииОграниченийСписков Цикл + ОбщаяВерсия = ОбщаяВерсия(ОбщийКонтекст, ОписаниеВерсии.Ключ, ОписаниеВерсии.Значение, + КонтекстДляВнешнихПользователей.ВерсииОграниченийСписков.Получить(ОписаниеВерсии.Ключ)); + ВерсииОграниченийСписков.Вставить(ОписаниеВерсии.Ключ, ОбщаяВерсия); + Версии.Добавить(ОбщаяВерсия, ПолучитьHexСтрокуИзДвоичныхДанных( + ПолучитьДвоичныеДанныеИзСтроки(Строка(ОбщаяВерсия)))); + КонецЦикла; + Версии.СортироватьПоПредставлению(); + ВерсииСтрокой = СтрСоединить(Версии.ВыгрузитьЗначения(), Символы.ПС); + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + ХешированиеДанных.Добавить(ВерсииСтрокой); + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВсеВерсииСтрокой = ВерсииСтрокой; + КонецЕсли; + + // Подготовка дополнительного контекста для расчета параметров ограничения отдельного списка. + ДляПользователей = НовыйХранимыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДляПользователей, КонтекстДляПользователей.ДополнительныйКонтекст); + ДляВнешнихПользователей = НовыйХранимыйДополнительныйКонтекст(); + ЗаполнитьЗначенияСвойств(ДляВнешнихПользователей, КонтекстДляВнешнихПользователей.ДополнительныйКонтекст); + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("ДляПользователей", ДляПользователей); + ДополнительныйКонтекст.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + + ПараметрыЗаписи = НоваяСтруктураХранимыхПараметровЗаписи(); + ПараметрыЗаписи.ВерсииОграниченийСписков = ВерсииОграниченийСписков; + ПараметрыЗаписи.ВедущиеСписки = ВедущиеСписки; + ПараметрыЗаписи.ДополнительныйКонтекст = ДополнительныйКонтекст; + ПараметрыЗаписи.СпискиСДатой = СпискиСДатой; + ПараметрыЗаписи.ВедущиеРоли = ВедущиеРоли; + ПараметрыЗаписи.ИспользуемыеТипыЗначений = Новый ХранилищеЗначения( + Новый Структура("ХешСумма", ОбщийКонтекст.ИспользуемыеТипыЗначений.ХешСумма)); + ПараметрыЗаписи.ВнешниеПользователиВключены = ОбщийКонтекст.ВнешниеПользователиВключены; + ПараметрыЗаписи.ОграничениеДоступаВключено = ОбщийКонтекст.ОграничениеДоступаВключено; + ПараметрыЗаписи.ВерсияТекстовОграниченияДоступа = ВерсияТекстовОграниченияДоступа; + ХешированиеДанных.Добавить(ОбщийКонтекст.ИспользуемыеТипыЗначений.ХешСумма); + + ХранимыеПараметры = Новый Структура; + + ХранимыеПараметрыШаблоновДляПользователей = НоваяСтруктураХранимыхПараметровШаблонов(); + ХранимыеПараметрыШаблоновДляПользователей.ПараметрыШаблонов = КонтекстДляПользователей.ПараметрыШаблонов; + ХранимыеПараметры.Вставить("ДляШаблоновВСеансахПользователей", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыШаблоновДляПользователей))); + + ХранимыеПараметрыШаблоновДляВнешнихПользователей = НоваяСтруктураХранимыхПараметровШаблонов(); + ХранимыеПараметрыШаблоновДляВнешнихПользователей.ПараметрыШаблонов = КонтекстДляВнешнихПользователей.ПараметрыШаблонов; + ХранимыеПараметры.Вставить("ДляШаблоновВСеансахВнешнихПользователей", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыШаблоновДляВнешнихПользователей))); + + ХранимыеВерсииПараметровШаблонов = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + ХранимыеВерсииПараметровШаблонов.ДляПользователей.ВерсииПараметровШаблонов = + КонтекстДляПользователей.ВерсииПараметровШаблонов; + ХранимыеВерсииПараметровШаблонов.ДляВнешнихПользователей.ВерсииПараметровШаблонов = + КонтекстДляВнешнихПользователей.ВерсииПараметровШаблонов; + ХранимыеПараметры.Вставить("ВерсииПараметровШаблонов", + Новый ХранилищеЗначения(ХранимыеВерсииПараметровШаблонов)); + + ХранимыеПараметры.Вставить("ДляЗаписиОбъектовИПроверкиПрав", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ПараметрыЗаписи))); + + ХранимыеПараметрыОтчета = НоваяСтруктураХранимыхПараметровОтчета(); + ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей = + ВидыОграниченийПравСтрокой(ВидыОграниченийПравДляПользователей); + ХешированиеДанных.Добавить(ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей); + ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей = + ВидыОграниченийПравСтрокой(ВидыОграниченийПравДляВнешнихПользователей); + ХешированиеДанных.Добавить(ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей); + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВидыОграниченийПравДляПользователейСтрокой + = ХранимыеПараметрыОтчета.ВидыОграниченийПравДляПользователей; + ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.ВидыОграниченийПравДляВнешнихПользователейСтрокой + = ХранимыеПараметрыОтчета.ВидыОграниченийПравДляВнешнихПользователей; + КонецЕсли; + + ХранимыеПараметры.Вставить("ДляОтчетаПоПравамДоступа", + Новый ХранилищеЗначения(ОбщегоНазначения.ФиксированныеДанные(ХранимыеПараметрыОтчета))); + + ХранимыеПараметры.Вставить("ХешСуммаПостоянныхПараметров", Base64Строка(ХешированиеДанных.ХешСумма)); + ХранимыеПараметры.Вставить("ДатаСоздания", ДатаСоздания); + + Если ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + СтрокиВерсийСписков.Сортировать("Список, ДляВнешнихПользователей"); + КонецЕсли; + + Возврат ХранимыеПараметры; + +КонецФункции + +// Возвращаемое значение: +// ТаблицаЗначений: +// * Список - Строка +// * ДляВнешнихПользователей - Булево +// * Версия - Строка +// * СтрокаВерсии - Строка +// +Функция НовыеСтрокиВерсийСписков() + + СтрокиВерсийСписков = Новый ТаблицаЗначений; + СтрокиВерсийСписков.Колонки.Добавить("Список", Новый ОписаниеТипов("Строка")); + СтрокиВерсийСписков.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево")); + СтрокиВерсийСписков.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка")); + СтрокиВерсийСписков.Колонки.Добавить("СтрокаВерсии", Новый ОписаниеТипов("Строка")); + + Возврат СтрокиВерсийСписков; + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ОписанияОграничений - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СокращенноеОписаниеОграничения +// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * СпискиСОграничениемПоВладельцу - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - значение ПоВладельцу, кроме Неопределено. +// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// +Функция НовыйДополнительныйКонтекст() + + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("ОписанияОграничений", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СвойстваОграниченияСписков", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОграничениемПоВладельцу", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничением", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничениемЧтения", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей", Неопределено); + ДополнительныйКонтекст.Вставить("ОсновныеВариантыДоступа", Новый Соответствие); + + Возврат ДополнительныйКонтекст; + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// +Функция НовыйХранимыйДополнительныйКонтекст() + + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("СвойстваОграниченияСписков", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничением", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСОтключеннымОграничениемЧтения", Новый Соответствие); + ДополнительныйКонтекст.Вставить("СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей", Неопределено); + ДополнительныйКонтекст.Вставить("ОсновныеВариантыДоступа", Новый Соответствие); + + Возврат ДополнительныйКонтекст; + +КонецФункции + +// Для функций РассчитанныеПараметрыОграничения и ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьДополнительныйКонтекст(ПолноеИмя, ДополнительныйКонтекст, + ОписаниеОграничения, ДляВнешнихПользователей) + + Если ДляВнешнихПользователей Тогда + Текст = ОписаниеОграничения.ТекстДляВнешнихПользователей; + ПоВладельцу = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей; + Иначе + Текст = ОписаниеОграничения.Текст; + ПоВладельцу = ОписаниеОграничения.ПоВладельцуБезЗаписиКлючейДоступа; + КонецЕсли; + ВМодулеМенеджера = ОписаниеОграничения.ТекстВМодулеМенеджера; + + СокращенноеОписаниеОграничения = СокращенноеОписаниеОграничения(); + СокращенноеОписаниеОграничения.Вставить("Текст", Текст); + СокращенноеОписаниеОграничения.Вставить("ВМодулеМенеджера", ВМодулеМенеджера); + + ДополнительныйКонтекст.ОписанияОграничений.Вставить(ПолноеИмя, СокращенноеОписаниеОграничения); + + Если ПоВладельцу <> Неопределено Тогда + ДополнительныйКонтекст.СпискиСОграничениемПоВладельцу.Вставить(ПолноеИмя, ПоВладельцу); + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Текст - Строка +// * ВМодулеМенеджера - Булево +// +Функция СокращенноеОписаниеОграничения() + + Возврат Новый Структура; + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей(Контекст) + + // Подготовка параметров с учетом зависимостей только по ключам доступа. + ТаблицаСвойств = СвойстваСписковДляРасчетаХранимыхПараметров(); + ТаблицаСвойств = Новый ТаблицаЗначений; + ТаблицаСвойств.Колонки.Добавить("ПолноеИмя", Новый ОписаниеТипов("Строка")); + ТаблицаСвойств.Колонки.Добавить("Зависимый", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("Ведущие", Новый ОписаниеТипов("Массив")); + ТаблицаСвойств.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число")); + ТаблицаСвойств.Колонки.Добавить("Ведущий", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("Зависимые", Новый ОписаниеТипов("Массив")); + ТаблицаСвойств.Колонки.Добавить("Параметры", Новый ОписаниеТипов("Структура")); + ТаблицаСвойств.Колонки.Добавить("Обработан", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ОграничениеПоВладельцуВозможно", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ОграничениеПоВладельцуВключено", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("КлючиДоступаПользователей", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Новый ОписаниеТипов("Булево")); + ТаблицаСвойств.Колонки.Добавить("ЗависимыеСпискиБезЗаписиКлючейДоступа", Новый ОписаниеТипов("Соответствие")); + ТаблицаСвойств.Колонки.Добавить("КлючиДоступаПользователейИГруппДоступа", Новый ОписаниеТипов("Булево")); + + СпискиСОграничением = Новый Соответствие(Контекст.ОбщийКонтекст.СпискиСОграничением); + СпискиСОтключеннымОграничением = Новый Соответствие; + СпискиСОтключеннымОграничениемЧтения = Новый Соответствие; + + Для Каждого ОписаниеСписка Из СпискиСОграничением Цикл + ПолноеИмя = ОписаниеСписка.Ключ; + + Если ТипЗнч(ОписаниеСписка.Значение) = Тип("Булево") Тогда + Свойства = ТаблицаСвойств.Добавить(); + Свойства.ПолноеИмя = ПолноеИмя; + СпискиСОграничением.Вставить(ПолноеИмя, Свойства); + Параметры = ПараметрыОграниченияДляВидаПользователей(ПолноеИмя, Контекст); + Свойства.Параметры = Параметры; + Иначе + Свойства = ОписаниеСписка.Значение; // См. СвойстваСписковДляРасчетаХранимыхПараметров + Параметры = Свойства.Параметры; + КонецЕсли; + + Если Параметры.ОграничениеЧтенияОтключено Тогда + СпискиСОтключеннымОграничениемЧтения.Вставить(ПолноеИмя, Истина); + КонецЕсли; + Если Параметры.ОграничениеОтключено Тогда + СпискиСОтключеннымОграничением.Вставить(ПолноеИмя, Истина); + КонецЕсли; + Если Параметры.ЕстьОграничениеПоПользователям Тогда + Свойства.КлючиДоступаПользователей = Истина; + УстановитьСвойствоОграничения(ПолноеИмя, "РассчитыватьПраваПользователей", Истина, Контекст); + КонецЕсли; + Если Параметры.ПолеВладельца <> Неопределено Тогда + УстановитьСвойствоОграничения(ПолноеИмя, "ПолеВладельца", Параметры.ПолеВладельца, Контекст); + КонецЕсли; + + ВедущиеСписки = Параметры.ВедущиеСписки; + Если ВедущиеСписки.ПоКлючамДоступа.Количество() > 0 Тогда + Свойства.Зависимый = Истина; + Для Каждого КлючИЗначение Из ВедущиеСписки.ПоКлючамДоступа Цикл + ВедущийСписок = КлючИЗначение.Ключ; + Свойства.Ведущие.Добавить(ВедущийСписок); + СвойстваВедущего = СпискиСОграничением.Получить(ВедущийСписок); + Если СвойстваВедущего = Неопределено Или ТипЗнч(СвойстваВедущего) = Тип("Булево") Тогда + СвойстваВедущего = ТаблицаСвойств.Добавить(); + СвойстваВедущего.ПолноеИмя = ВедущийСписок; + СпискиСОграничением.Вставить(ВедущийСписок, СвойстваВедущего); + ПараметрыВедущего = ПараметрыОграниченияДляВидаПользователей(ВедущийСписок, Контекст); + СвойстваВедущего.Параметры = ПараметрыВедущего; + Если ПараметрыВедущего.ОграничениеЧтенияОтключено Тогда + СпискиСОтключеннымОграничениемЧтения.Вставить(ВедущийСписок, Истина); + КонецЕсли; + Если ПараметрыВедущего.ОграничениеОтключено Тогда + СпискиСОтключеннымОграничением.Вставить(ВедущийСписок, Истина); + КонецЕсли; + Если ПараметрыВедущего.ЕстьОграничениеПоПользователям Тогда + СвойстваВедущего.КлючиДоступаПользователей = Истина; + УстановитьСвойствоОграничения(ВедущийСписок, + "РассчитыватьПраваПользователей", Истина, Контекст); + КонецЕсли; + Если ПараметрыВедущего.ПолеВладельца <> Неопределено Тогда + УстановитьСвойствоОграничения(ВедущийСписок, + "ПолеВладельца", ПараметрыВедущего.ПолеВладельца, Контекст); + КонецЕсли; + КонецЕсли; + СвойстваВедущего.Ведущий = Истина; + СвойстваВедущего.Зависимые.Добавить(ПолноеИмя); + КонецЦикла; + КонецЕсли; + КонецЦикла; + + МаксимальныйУровень = 0; + Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Зависимый, Ведущий", Ложь, Истина)); + Для Каждого Строка Из Строки Цикл + УстановитьУровеньЗависимыхСписков(Строка, СпискиСОграничением, Новый Массив, МаксимальныйУровень); + КонецЦикла; + // Обработка зависимых списков, ведущих для самих себя (зацикленных на себя). + Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Обработан", Ложь)); + Для Каждого Строка Из Строки Цикл + УстановитьУровеньЗависимыхСписков(Строка, СпискиСОграничением, Новый Массив, МаксимальныйУровень); + КонецЦикла; + + Строки = ТаблицаСвойств.НайтиСтроки(Новый Структура("Зависимый, Ведущий", Истина, Ложь)); + Для Каждого Строка Из Строки Цикл + НастроитьОптимизациюПоПолюВладельцу(Строка, СпискиСОграничением, Контекст); + КонецЦикла; + + // Сокращение зависимостей по ключам доступа зависимых объектов. + СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Новый Соответствие; + Отбор = Новый Структура("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Истина); + Строки = ТаблицаСвойств.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Вставить(Строка.ПолноеИмя, Истина); + КонецЦикла; + ДополнительныйКонтекст = Контекст.ДополнительныйКонтекст; + ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения = СпискиСОтключеннымОграничениемЧтения; + ДополнительныйКонтекст.СпискиСОтключеннымОграничением = СпискиСОтключеннымОграничением; + ДополнительныйКонтекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей + = СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей; + + Отбор = Новый Структура("Уровень, ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", 0, Истина); + Строки = ТаблицаСвойств.НайтиСтроки(Отбор); + Для Каждого Строка Из Строки Цикл + Строка.Параметры = ПараметрыОграниченияДляВидаПользователей(Строка.ПолноеИмя, Контекст); + КонецЦикла; + + СвойстваСписковПоУровням = Новый Массив; + Для Уровень = 1 По МаксимальныйУровень Цикл + СвойстваСписков = ТаблицаСвойств.НайтиСтроки(Новый Структура("Уровень", Уровень)); + СвойстваСписковПоУровням.Добавить(СвойстваСписков); + КонецЦикла; + + ОбщийКонтекстСпискиСОграничением = Контекст.ОбщийКонтекст.СпискиСОграничением; + + Для Каждого СвойстваСписков Из СвойстваСписковПоУровням Цикл + Для Каждого СвойстваСписка Из СвойстваСписков Цикл + СвойстваСписка = СвойстваСписка; // См. СвойстваСписковДляРасчетаХранимыхПараметров + + ВсеВедущиеСпискиСОграничением = Истина; + ИзмененоСвойствоРассчитыватьПраваПользователей = Ложь; + КлючиДоступаПользователей = Ложь; + КлючиДоступаГруппДоступа = Ложь; + + Для Каждого Ведущий Из СвойстваСписка.Ведущие Цикл + СвойстваВедущего = СпискиСОграничением.Получить(Ведущий); + Если СвойстваВедущего.КлючиДоступаПользователей Тогда + КлючиДоступаПользователей = Истина; + Иначе + КлючиДоступаГруппДоступа = Истина; + КонецЕсли; + Если ОбщийКонтекстСпискиСОграничением.Получить(Ведущий) = Неопределено + Или СпискиСОтключеннымОграничением.Получить(Ведущий) <> Неопределено Тогда + ВсеВедущиеСпискиСОграничением = Ложь; + КонецЕсли; + КонецЦикла; + + Если КлючиДоступаПользователей Тогда + Если Не СвойстваСписка.ОграничениеПоВладельцуВключено + И Не СвойстваСписка.КлючиДоступаПользователей Тогда + + ИзмененоСвойствоРассчитыватьПраваПользователей = Истина; + УстановитьСвойствоОграничения(СвойстваСписка.ПолноеИмя, + "РассчитыватьПраваПользователей", Истина, Контекст); + КонецЕсли; + СвойстваСписка.КлючиДоступаПользователей = Истина; + Если СвойстваСписка.ОграничениеПоВладельцуВключено + И КлючиДоступаГруппДоступа Тогда + СвойстваСписка.КлючиДоступаПользователейИГруппДоступа = Истина; + КонецЕсли; + КонецЕсли; + + Если СвойстваСписка.ОграничениеПоВладельцуВключено + И ВсеВедущиеСпискиСОграничением + И Не ИзмененоСвойствоРассчитыватьПраваПользователей + И СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(СвойстваСписка.ПолноеИмя) = Неопределено + Тогда + Продолжить; + КонецЕсли; + + СвойстваСписка.Параметры = + ПараметрыОграниченияДляВидаПользователей(СвойстваСписка.ПолноеИмя, Контекст); + КонецЦикла; + КонецЦикла; + + // Заполнение хранимых свойств списков. + Для Каждого СвойстваСписка Из ТаблицаСвойств Цикл + ПолноеИмя = СвойстваСписка.ПолноеИмя; + + Если СвойстваСписка.Параметры.ДоступЗапрещен Тогда + УстановитьСвойствоОграничения(ПолноеИмя, "ДоступЗапрещен", Истина, Контекст); + КонецЕсли; + Если ЗначениеЗаполнено(СвойстваСписка.Параметры.ИмяОтдельногоРегистраКлючей) Тогда + УстановитьСвойствоОграничения(ПолноеИмя, + "ИмяОтдельногоРегистраКлючей", СвойстваСписка.Параметры.ИмяОтдельногоРегистраКлючей, Контекст); + КонецЕсли; + Если ЗначениеЗаполнено(СвойстваСписка.Параметры.ОпорныеПоля) Тогда + ОпорныеПоля = Новый Структура("Все, ТипыВсех, Используемые"); + ЗаполнитьЗначенияСвойств(ОпорныеПоля, СвойстваСписка.Параметры.ОпорныеПоля); + УстановитьСвойствоОграничения(ПолноеИмя, "ОпорныеПоля", ОпорныеПоля, Контекст); + КонецЕсли; + Если СвойстваСписка.КлючиДоступаПользователейИГруппДоступа Тогда + УстановитьСвойствоОграничения(ПолноеИмя, + "ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа", Истина, Контекст); + ИначеЕсли СвойстваСписка.КлючиДоступаПользователей Тогда + УстановитьСвойствоОграничения(ПолноеИмя, + "ОграничениеВШаблонахЧерезКлючиДоступаПользователей", Истина, Контекст); + КонецЕсли; + Если СвойстваСписка.Параметры.ОграничениеЧтенияОтключено Тогда + СпискиСОтключеннымОграничениемЧтения.Вставить(ПолноеИмя, Истина); + КонецЕсли; + Если СвойстваСписка.Параметры.ОграничениеОтключено Тогда + СпискиСОтключеннымОграничением.Вставить(ПолноеИмя, Истина); + КонецЕсли; + УстановитьСвойствоОграничения(ПолноеИмя, "ИспользуемыеТипыЗначенийДоступа", + Новый ХранилищеЗначения(СвойстваСписка.Параметры.ИспользуемыеТипыЗначенийДоступа), Контекст); + + Контекст.ВерсииОграниченийСписков.Вставить(ПолноеИмя, СвойстваСписка.Параметры.Версия); + Если Контекст.ОбщийКонтекст.Свойство("СтрокиВерсииХранимыхПараметров") Тогда + СтрокиВерсийСписков = Контекст.ОбщийКонтекст.СтрокиВерсииХранимыхПараметров.СтрокиВерсийСписков; // См. НовыеСтрокиВерсийСписков + НоваяСтрока = СтрокиВерсийСписков.Добавить(); + НоваяСтрока.Список = СвойстваСписка.ПолноеИмя; + НоваяСтрока.ДляВнешнихПользователей = Контекст.ДляВнешнихПользователей; + НоваяСтрока.Версия = СвойстваСписка.Параметры.Версия; + НоваяСтрока.СтрокаВерсии = СвойстваСписка.Параметры.Контекст.СтрокаСвойствВерсии; + КонецЕсли; + + ВедущиеСписки = СвойстваСписка.Параметры.ВедущиеСписки; + + Если ВедущиеСписки.ПоЗначениямПолей.Количество() > 0 + Или ВедущиеСписки.ПоКлючамДоступа.Количество() > 0 + Или ВедущиеСписки.ПоЗначениямСГруппами.Количество() > 0 Тогда + + Контекст.ВедущиеСписки.Вставить(ПолноеИмя, ВедущиеСписки); + КонецЕсли; + + НастроитьПараметрыШаблонов(СвойстваСписка, Контекст); + + Если СвойстваСписка.Параметры.СписокСДатой Тогда + Контекст.СпискиСДатой.Вставить(СвойстваСписка.ПолноеИмя, Истина); + КонецЕсли; + + Для Каждого КлючИЗначение Из СвойстваСписка.Параметры.ВсеВидыОграниченийПрав Цикл + Контекст.ВсеВидыОграниченийПрав.Вставить(СвойстваСписка.ПолноеИмя + "." + КлючИЗначение.Ключ, Истина); + КонецЦикла; + + Если ЗначениеЗаполнено(СвойстваСписка.Параметры.Контекст.ВедущиеРоли) Тогда + Для Каждого КлючИЗначение Из СвойстваСписка.Параметры.Контекст.ВедущиеРоли Цикл + ЗависимыеСписки = Контекст.ВедущиеРоли.Получить(КлючИЗначение.Ключ); + Если ЗависимыеСписки = Неопределено Тогда + ЗависимыеСписки = Новый Соответствие; + Контекст.ВедущиеРоли.Вставить(КлючИЗначение.Ключ, ЗависимыеСписки); + КонецЕсли; + ЗависимыеСписки.Вставить(СвойстваСписка.ПолноеИмя, Истина); + КонецЦикла; + КонецЕсли; + + ЗаполнитьСпискиБезВнедрения(Контекст.СпискиБезВнедрения, СвойстваСписка); + КонецЦикла; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ПолноеИмя - Строка +// * Зависимый - Булево +// * Ведущие - Массив +// * Уровень - Число +// * Ведущий - Булево +// * Параметры - Структура +// * Обработан - Булево +// * ОграничениеПоВладельцуВозможно - Булево +// * ОграничениеПоВладельцуВключено - Булево +// * КлючиДоступаПользователей - Булево +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево +// * КлючиДоступаПользователейИГруппДоступа - Булево +// +Функция СвойстваСписковДляРасчетаХранимыхПараметров() + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ХранимыеПараметрыОграниченияДляВидаПользователей. +// +// Возвращаемое значение: +// см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция ПараметрыОграниченияДляВидаПользователей(ПолноеИмя, Контекст) + + ОписаниеОграничения = Контекст.ДополнительныйКонтекст.ОписанияОграничений.Получить(ПолноеИмя); + + Если ОписаниеОграничения = Неопределено Тогда + СтруктураОграничения = Неопределено; + Иначе + СтруктураОграничения = РассчитаннаяСтруктураОграничения(ПолноеИмя, + ОписаниеОграничения.Текст, ОписаниеОграничения.ВМодулеМенеджера, Контекст.ДляВнешнихПользователей); + КонецЕсли; + + Возврат ПараметрыОграниченияПоСтруктуреОграничения(ПолноеИмя, + СтруктураОграничения, + Контекст.ДляВнешнихПользователей, + Контекст.ОбщийКонтекст, + Контекст.ДополнительныйКонтекст); + +КонецФункции + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура УстановитьУровеньЗависимыхСписков(СвойстваВедущегоСписка, СвойстваСписков, ПредыдущиеВедущие, + МаксимальныйУровень) + + ПредыдущиеВедущие.Добавить(СвойстваВедущегоСписка.ПолноеИмя); + + Для Каждого ЗависимыйСписок Из СвойстваВедущегоСписка.Зависимые Цикл + Если ПредыдущиеВедущие.Найти(ЗависимыйСписок) <> Неопределено Тогда + УчастникиЦикла = ""; + Индекс = ПредыдущиеВедущие.Количество() - 1; + Пока Истина Цикл + УчастникиЦикла = "- " + ПредыдущиеВедущие[Индекс] + Символы.ПС + УчастникиЦикла; + Если ПредыдущиеВедущие[Индекс] = ЗависимыйСписок Тогда + Прервать; + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + УчастникиЦикла = УчастникиЦикла + "(!) " + ЗависимыйСписок; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ограничения доступа, заполненные в процедурах %1 + |модулей менеджеров или общем модуле %2, + |содержат недопустимую циклическую зависимость при использовании функции + |%3 или %4 в одном или нескольких + |списках-участниках цикла: + |%5'"), + "ПриЗаполненииОграниченияДоступа", + "УправлениеДоступомПереопределяемый", + "ЧтениеОбъектаРазрешено", + "ИзменениеОбъектаРазрешено", + УчастникиЦикла); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + СвойстваЗависимогоСписка = СвойстваСписков.Получить(ЗависимыйСписок); + Если СвойстваЗависимогоСписка.Уровень < СвойстваВедущегоСписка.Уровень + 1 Тогда + СвойстваЗависимогоСписка.Уровень = СвойстваВедущегоСписка.Уровень + 1; + Если МаксимальныйУровень < СвойстваЗависимогоСписка.Уровень Тогда + МаксимальныйУровень = СвойстваЗависимогоСписка.Уровень; + КонецЕсли; + КонецЕсли; + Если Не СвойстваЗависимогоСписка.Ведущий Тогда + СвойстваЗависимогоСписка.Обработан = Истина; + Продолжить; + КонецЕсли; + УстановитьУровеньЗависимыхСписков(СвойстваЗависимогоСписка, СвойстваСписков, ПредыдущиеВедущие, МаксимальныйУровень); + КонецЦикла; + + ПредыдущиеВедущие.Удалить(ПредыдущиеВедущие.Количество() - 1); + СвойстваВедущегоСписка.Обработан = Истина; + +КонецПроцедуры + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура НастроитьОптимизациюПоПолюВладельцу(СвойстваЗависимогоСписка, СвойстваСписков, Контекст) + + СвойстваЗависимогоСписка.ОграничениеПоВладельцуВозможно = + СвойстваЗависимогоСписка.Параметры.ПолеВладельца <> Неопределено; + + СвойстваЗависимогоСписка.ОграничениеПоВладельцуВключено = + СвойстваЗависимогоСписка.ОграничениеПоВладельцуВозможно + И Не СвойстваЗависимогоСписка.Параметры.ПолеВладельца.Отключено; + + ЗависимыйСписокСОптимизацией = СвойстваЗависимогоСписка.ОграничениеПоВладельцуВключено; + + Для Каждого ВедущийСписок Из СвойстваЗависимогоСписка.Ведущие Цикл + СвойстваВедущегоСписка = СвойстваСписков.Получить(ВедущийСписок); // См. СвойстваСписковДляРасчетаХранимыхПараметров + Если СвойстваВедущегоСписка.Параметры.ДоступЗапрещен Тогда + Продолжить; + КонецЕсли; + Если Не СвойстваВедущегоСписка.Зависимый Тогда + Если ЗависимыйСписокСОптимизацией Тогда + УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка); + КонецЕсли; + Продолжить; + КонецЕсли; + Если ЗависимыйСписокСОптимизацией Тогда + Если СвойстваВедущегоСписка.Параметры.ПолеВладельца <> Неопределено + И Не СвойстваВедущегоСписка.Параметры.ПолеВладельца.Отключено Тогда + Если СвойстваВедущегоСписка.Параметры.ТребуетсяОграничениеПоВладельцу Тогда + ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, + "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", но такая + |оптимизация невозможна, так как она требуется для зависимого списка ""%2"".'"), + ИмяПризнакаОптимизации, + СвойстваЗависимогоСписка.ПолноеИмя); + КонтекстОшибки = Новый Структура("СпискиСОграничением, ОписанияОграничений"); + КонтекстОшибки.Вставить("Список", СвойстваВедущегоСписка.ПолноеИмя); + КонтекстОшибки.Вставить("ОписанияОграничений", Контекст.ДополнительныйКонтекст.ОписанияОграничений); + КонтекстОшибки.Вставить("ДляВнешнихПользователей", Контекст.ДляВнешнихПользователей); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, КонтекстОшибки); + ВызватьИсключение ТекстОшибки; + Иначе + СвойстваВедущегоСписка.ОграничениеПоВладельцуВключено = Ложь; + СвойстваВедущегоСписка.Параметры.ПолеВладельца.Отключено = Истина; + УстановитьСвойствоОграничения(СвойстваВедущегоСписка.ПолноеИмя, + "ПолеВладельца", СвойстваВедущегоСписка.Параметры.ПолеВладельца, Контекст); + КонецЕсли; + КонецЕсли; + УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка); + КонецЕсли; + НастроитьОптимизациюПоПолюВладельцу(СвойстваВедущегоСписка, СвойстваСписков, Контекст); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры НастроитьОптимизациюПоПолюВладельцу. +Процедура УстановитьЕстьЗависимыеСпискиБезЗаписиКлючейДоступа(СвойстваВедущегоСписка, СвойстваЗависимогоСписка) + + СвойстваВедущегоСписка.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина; + СвойстваВедущегоСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа.Вставить(СвойстваЗависимогоСписка.ПолноеИмя, Истина); + +КонецПроцедуры + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура ЗаполнитьСпискиБезВнедрения(СпискиБезВнедрения, СвойстваСписка) + + Если СпискиБезВнедрения = Неопределено Тогда + Возврат; + КонецЕсли; + + Параметры = СвойстваСписка.Параметры; + + Если Параметры.БезОбновленияКлючейДоступаКОбъектам + И СтрПолучитьСтроку(Параметры.Версия, 1) <> " " + И Не ЭтоУстаревшийОбъектМетаданных(СвойстваСписка.ПолноеИмя) Тогда + + Если СтрПолучитьСтроку(Параметры.Версия, 1) = " " Тогда + Списки = СпискиБезВнедрения.ОбъектыПредупреждения; + Иначе + Списки = СпискиБезВнедрения.ОбъектыОшибки; + КонецЕсли; + ЗависимыеСписки = Списки.Получить(СвойстваСписка.ПолноеИмя); + Если ЗначениеЗаполнено(ЗависимыеСписки) Тогда + Для Каждого КлючИЗначение Из СвойстваСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа Цикл + ЗависимыеСписки.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Иначе + ЗависимыеСписки = СвойстваСписка.ЗависимыеСпискиБезЗаписиКлючейДоступа; + Списки.Вставить(СвойстваСписка.ПолноеИмя, ЗависимыеСписки); + КонецЕсли; + Если ЗначениеЗаполнено(СтрПолучитьСтроку(Параметры.Версия, 1)) Тогда + ЗависимыеСписки.Вставить("ЕстьОграничениеСписка", Истина); + КонецЕсли; + КонецЕсли; + + Если Параметры.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей Тогда + Контекст = Параметры.Контекст; + ТекстОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список).Текст; + ОписаниеРегистра = Новый Структура; + ОписаниеРегистра.Вставить("ПолноеИмя", СвойстваСписка.ПолноеИмя); + ОписаниеРегистра.Вставить("ИмяОтдельногоРегистраКлючей", Параметры.ИмяОтдельногоРегистраКлючей); + ОписаниеРегистра.Вставить("НедостающиеТипы", Контекст.ОпорныеПоля.НедостающиеТипы); + ОписаниеРегистра.Вставить("ПоляНедостающихТипов", Контекст.ОпорныеПоля.ПоляНедостающихТипов); + ОписаниеРегистра.Вставить("ТекстОграничения", ТекстОграничения); + СпискиБезВнедрения.РегистрыПредупреждения.Добавить(ОписаниеРегистра); + КонецЕсли; + +КонецПроцедуры + +// Для функции ЗаполнитьСпискиБезВнедрения. +Функция ЭтоУстаревшийОбъектМетаданных(ПолноеИмя) + + ЧастиИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Если ЧастиИмени.Количество() <> 2 Тогда + Возврат Ложь; + КонецЕсли; + + Возврат СтрНачинаетсяС(ВРег(ЧастиИмени[1]), ВРег("Удалить")); + +КонецФункции + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура УстановитьСвойствоОграничения(ПолноеИмя, ИмяСвойства, ЗначениеСвойства, Контекст) + + Свойства = СвойстваОграниченияСписка(ПолноеИмя, Контекст.ДополнительныйКонтекст, Истина); + + Свойства[ИмяСвойства] = ЗначениеСвойства; + +КонецПроцедуры + +// Для процедур УстановитьСвойствоОграничения, ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Функция СвойстваОграниченияСписка(ПолноеИмя, Контекст, ДобавлятьВКоллекцию = Ложь) + + Свойства = Контекст.СвойстваОграниченияСписков.Получить(ПолноеИмя); + + Если Свойства = Неопределено Тогда + Свойства = НовыеСвойстваОграниченияСписка(); + Если ДобавлятьВКоллекцию Тогда + Контекст.СвойстваОграниченияСписков.Вставить(ПолноеИмя, Свойства); + КонецЕсли; + КонецЕсли; + + Возврат Свойства; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ДоступЗапрещен - Булево +// * ПолеВладельца - см. НовоеПолеВладельца +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ИмяОтдельногоРегистраКлючей - Строка +// * РассчитыватьПраваПользователей - Булево +// * ИспользуемыеТипыЗначенийДоступа - ХранилищеЗначения - содержит тип Массив из Тип +// * ОграничениеВШаблонахЧерезКлючиДоступаПользователей - Булево +// * ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа - Булево +// +Функция НовыеСвойстваОграниченияСписка() + + Свойства = Новый Структура; + Свойства.Вставить("ДоступЗапрещен", Ложь); + Свойства.Вставить("ПолеВладельца", Неопределено); + Свойства.Вставить("ОпорныеПоля", Неопределено); + Свойства.Вставить("ИмяОтдельногоРегистраКлючей", ""); + Свойства.Вставить("РассчитыватьПраваПользователей", Ложь); + Свойства.Вставить("ОграничениеВШаблонахЧерезКлючиДоступаПользователей", Ложь); + Свойства.Вставить("ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа", Ложь); + Свойства.Вставить("ИспользуемыеТипыЗначенийДоступа", Неопределено); + + Возврат Свойства; + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +// +// Параметры: +// СпискиБезВнедрения - Соответствие +// ИнформацияДляЖурнала - см. НоваяИнформацияНесоответствияПараметровДляЖурнала +// +Процедура ЗаполнитьНесоответствиеПараметровДляЖурнала(СпискиБезВнедрения, ИнформацияДляЖурнала); + + Если ЗначениеЗаполнено(СпискиБезВнедрения.ОбъектыПредупреждения) Тогда + ИнформацияДляЖурнала.Предупреждение = ОписаниеНесоответствияПараметров( + СпискиБезВнедрения.ОбъектыПредупреждения); + КонецЕсли; + + Если ЗначениеЗаполнено(СпискиБезВнедрения.ОбъектыОшибки) Тогда + ИнформацияДляЖурнала.Ошибка = ОписаниеНесоответствияПараметров( + СпискиБезВнедрения.ОбъектыОшибки); + КонецЕсли; + + Если Не ЗначениеЗаполнено(СпискиБезВнедрения.РегистрыПредупреждения) Тогда + Возврат; + КонецЕсли; + + Предупреждения = Новый СписокЗначений; + + Для Каждого ОписаниеРегистра Из СпискиБезВнедрения.РегистрыПредупреждения Цикл + Если ЗначениеЗаполнено(ОписаниеРегистра.ИмяОтдельногоРегистраКлючей) Тогда + Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В таблице %1 будут недоступны строки + |для значений которых в измерениях регистра сведений + | %2 + |не хватает типов: + | - %3, + |имеющихся у полей (%4) в ограничении доступа: + | %5'"), + ОписаниеРегистра.ПолноеИмя, + ОписаниеРегистра.ИмяОтдельногоРегистраКлючей, + СтрСоединить(ОписаниеРегистра.НедостающиеТипы, "," + Символы.ПС + " - "), + СтрСоединить(ОписаниеРегистра.ПоляНедостающихТипов, ", "), + ТекстСОтступом(ОписаниеРегистра.ТекстОграничения, " ")); + Иначе + Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В таблице %1 будут недоступны строки для значений которых + |в определяемом типе %2 не хватает типов: + | - %3, + |имеющихся у полей (%4) в ограничении доступа: + | %5'"), + ОписаниеРегистра.ПолноеИмя, + "ПолеРегистраКлючейДоступаКРегистрам", + СтрСоединить(ОписаниеРегистра.НедостающиеТипы, "," + Символы.ПС + " - "), + СтрСоединить(ОписаниеРегистра.ПоляНедостающихТипов, ", "), + ТекстСОтступом(ОписаниеРегистра.ТекстОграничения, " ")); + КонецЕсли; + Предупреждения.Добавить(Текст, ОписаниеРегистра.ПолноеИмя); + КонецЦикла; + + Предупреждения.СортироватьПоПредставлению(); + Если ЗначениеЗаполнено(ИнформацияДляЖурнала.Предупреждение) Тогда + Предупреждения.Вставить(0, ИнформацияДляЖурнала.Предупреждение); + КонецЕсли; + ИнформацияДляЖурнала.Предупреждение = + СтрСоединить(Предупреждения.ВыгрузитьЗначения(), Символы.ПС + Символы.ПС + Символы.ПС); + +КонецПроцедуры + +// Для процедуры ЗаполнитьНесоответствиеПараметровДляЖурнала. +Функция ОписаниеНесоответствияПараметров(СпискиБезВнедрения) + + Списки = Новый СписокЗначений; + ВедущиеСписки = Новый СписокЗначений; + + Для Каждого ВедущийСписок Из СпискиБезВнедрения Цикл + ЗависимыеСписки = Новый СписокЗначений; + Для Каждого ЗависимыйСписок Из ВедущийСписок.Значение Цикл + Если ЗависимыйСписок.Ключ = "ЕстьОграничениеСписка" Тогда + Списки.Добавить(ВедущийСписок.Ключ); + Иначе + ЗависимыеСписки.Добавить(ЗависимыйСписок.Ключ); + КонецЕсли; + КонецЦикла; + Если Не ЗначениеЗаполнено(ЗависимыеСписки) Тогда + Продолжить; + КонецЕсли; + ЗависимыеСписки.СортироватьПоЗначению(); + + ВедущиеСписки.Добавить(ВедущийСписок.Ключ + " {" + Символы.ПС + " " + + СтрСоединить(ЗависимыеСписки.ВыгрузитьЗначения(), Символы.ПС + " ") + + Символы.ПС + "}", ВедущийСписок.Ключ); + КонецЦикла; + + Результат = Новый Массив; + + Если ЗначениеЗаполнено(Списки) Тогда + Списки.СортироватьПоПредставлению(); + Результат.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Типы следующих таблиц не указаны в определяемом типе %1, + |поэтому их строки будут недоступны: + | + |%2'"), + "ВладелецЗначенийКлючейДоступа", + СтрСоединить(Списки.ВыгрузитьЗначения(), Символы.ПС))); + КонецЕсли; + + Если ЗначениеЗаполнено(ВедущиеСписки) Тогда + ВедущиеСписки.СортироватьПоПредставлению(); + Результат.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Типы следующих ведущих таблиц не указаны в определяемом типе %1, + |поэтому в зависимых от них таблицах (в фигурных скобках) + |будут недоступны строки, содержащие ссылки на объекты этих типов + |в тех полях, которые используются в ограничении доступа к ним: + | + |%2'"), + "ВладелецЗначенийКлючейДоступа", + СтрСоединить(ВедущиеСписки.ВыгрузитьЗначения(), Символы.ПС))); + КонецЕсли; + + Возврат СтрСоединить(Результат, Символы.ПС + Символы.ПС + Символы.ПС); + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьВедущиеРоли(ВедущиеРоли, ИмяСвойстваВидаПользователей, КонтекстВидаПользователей) + + Для Каждого ОписаниеВедущейРоли Из КонтекстВидаПользователей.ВедущиеРоли Цикл + ИмяРоли = ОписаниеВедущейРоли.Ключ; + ЗависимыеСписки = ВедущиеРоли.Получить(ИмяРоли); + Если ЗависимыеСписки = Неопределено Тогда + ЗависимыеСписки = Новый Структура("ДляПользователей, ДляВнешнихПользователей"); + ВедущиеРоли.Вставить(ИмяРоли, ЗависимыеСписки); + КонецЕсли; + ЗависимыеСписки[ИмяСвойстваВидаПользователей] = + Новый ФиксированноеСоответствие(ОписаниеВедущейРоли.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Процедура ДобавитьВедущиеСписки(ВедущиеСписки, ИмяСвойстваВидаПользователей, ЗависимыйСписок, + ВедущиеСпискиЗависимогоСписка) + + Для Каждого ОписаниеВедущегоСписка Из ВедущиеСпискиЗависимогоСписка.ПоЗначениямПолей Цикл + ВедущийСписок = ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ОписаниеВедущегоСписка.Ключ); + ВедущийСписок.ЗависимыеСписки.Вставить(ЗависимыйСписок, Истина); + ДобавляемыеПоля = ОписаниеВедущегоСписка.Значение; + + Если ВедущийСписок.ПоЗначениямПолей = Неопределено Тогда + ПоЗначениямПолей = Новый Структура; + ПоЗначениямПолей.Вставить("ЭтоСсылочныйТип", ДобавляемыеПоля.ЭтоСсылочныйТип); + ПоЗначениямПолей.Вставить("ПоляШапки", ОписаниеПолейВедущегоСписка()); + Если ПоЗначениямПолей.ЭтоСсылочныйТип Тогда + ПоЗначениямПолей.Вставить("ТабличныеЧасти", Новый Соответствие); + КонецЕсли; + ВедущийСписок.ПоЗначениямПолей = ПоЗначениямПолей; + Иначе + ПоЗначениямПолей = ВедущийСписок.ПоЗначениямПолей; + КонецЕсли; + + ДобавитьПоляВедущегоСписка(ПоЗначениямПолей.ПоляШапки, ДобавляемыеПоля.ДляОтслеживания.ПоляШапки, + ДобавляемыеПоля.ДляОтбора.ПоляШапки, ЗависимыйСписок, ИмяСвойстваВидаПользователей); + + Для Каждого ТабличнаяЧасть Из ДобавляемыеПоля.ДляОтслеживания.ТабличныеЧасти Цикл + ОписаниеТабличнойЧасти = ПоЗначениямПолей.ТабличныеЧасти.Получить(ТабличнаяЧасть.Ключ); + Если ОписаниеТабличнойЧасти = Неопределено Тогда + ОписаниеТабличнойЧасти = ОписаниеПолейВедущегоСписка(); + ОписаниеТабличнойЧасти.Вставить("Имя", ТабличнаяЧасть.Ключ); + ПоЗначениямПолей.ТабличныеЧасти.Вставить(ТабличнаяЧасть.Ключ, ОписаниеТабличнойЧасти); + КонецЕсли; + ТабличнаяЧастьПоляОтбора = ДобавляемыеПоля.ДляОтбора.ТабличныеЧасти.Получить(ТабличнаяЧасть.Ключ); + ДобавитьПоляВедущегоСписка(ОписаниеТабличнойЧасти, ТабличнаяЧасть.Значение, + ТабличнаяЧастьПоляОтбора, ЗависимыйСписок, ИмяСвойстваВидаПользователей); + КонецЦикла; + КонецЦикла; + + ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, + ИмяСвойстваВидаПользователей, ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, "ПоКлючамДоступа"); + + ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, + ИмяСвойстваВидаПользователей, ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, "ПоЗначениямСГруппами"); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * ЭтоСсылочныйТип - Булево +// * ПоляШапки - см. ОписаниеПолейВедущегоСписка +// * ТабличныеЧасти - Массив из см. ОписаниеПолейВедущегоСписка +// +Функция ВедущийСписокПоЗначениямПолей() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ДляПользователей - Массив из Строка - полные имена списков +// * ДляВнешнихПользователей - Массив из Строка - полные имена списков +// +Функция ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ДобавитьВедущиеСписки. +// +// Возвращаемое значение: +// Структура: +// * ВсеПоля - Массив +// * ТипыВсехПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя поля. +// ** Значение - ХранилищеЗначения - содержит тип ОписаниеТипов - тип поля. +// * НаборыПолей - Структура: +// ** ДляПользователей - Булево +// ** ДляВнешнихПользователей - Булево +// * Имя - Строка - имя табличной части (есть только у полей табличной части) +// +Функция ОписаниеПолейВедущегоСписка() + + Описание = Новый Структура; + Описание.Вставить("ВсеПоля", Новый Массив); + Описание.Вставить("ТипыВсехПолей", Новый Соответствие); + Описание.Вставить("НаборыПолей", Новый Структура("ДляПользователей, ДляВнешнихПользователей")); + + Возврат Описание; + +КонецФункции + +// Для процедуры ДобавитьВедущиеСписки. +Процедура ДобавитьВедущиеСпискиПоВидуЗависимости(ВедущиеСписки, ИмяСвойстваВидаПользователей, + ЗависимыйСписок, ВедущиеСпискиЗависимогоСписка, ВидЗависимости) + + Для Каждого ОписаниеВедущегоСписка Из ВедущиеСпискиЗависимогоСписка[ВидЗависимости] Цикл + ВедущийСписок = ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ОписаниеВедущегоСписка.Ключ); + ВедущийСписок.ЗависимыеСписки.Вставить(ЗависимыйСписок, Истина); + + Если ВедущийСписок[ВидЗависимости] = Неопределено Тогда + Свойства = ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами(); + Свойства.Вставить("ДляПользователей", Неопределено); + Свойства.Вставить("ДляВнешнихПользователей", Неопределено); + ВедущийСписок[ВидЗависимости] = Свойства; + Иначе + Свойства = ВедущийСписок[ВидЗависимости]; + КонецЕсли; + + Если Свойства[ИмяСвойстваВидаПользователей] = Неопределено Тогда + Свойства[ИмяСвойстваВидаПользователей] = Новый Массив; + КонецЕсли; + ЗависимыеСписки = Свойства[ИмяСвойстваВидаПользователей]; // Массив + ЗависимыеСписки.Добавить(ЗависимыйСписок); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьВедущиеСписки. +// +// Возвращаемое значение: +// Структура: +// * ЗависимыеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ПоЗначениямПолей - Структура - похожая на см. ВедущийСписокПоПоЗначениямПолей +// * ПоКлючамДоступа - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// * ПоЗначениямСГруппами - см. ВедущийСписокПоКлючамДоступаИлиЗначениямСГруппами +// +Функция ТекущиеСвойстваВедущегоСписка(ВедущиеСписки, ПолноеИмя) + + ВедущийСписок = ВедущиеСписки.Получить(ПолноеИмя); + Если ВедущийСписок = Неопределено Тогда + ВедущийСписок = Новый Структура; + ВедущийСписок.Вставить("ЗависимыеСписки", Новый Соответствие); + ВедущийСписок.Вставить("ПоЗначениямПолей", Неопределено); + ВедущийСписок.Вставить("ПоКлючамДоступа", Неопределено); + ВедущийСписок.Вставить("ПоЗначениямСГруппами", Неопределено); + ВедущиеСписки.Вставить(ПолноеИмя, ВедущийСписок) + КонецЕсли; + + Возврат ВедущийСписок; + +КонецФункции + +// Для процедуры ДобавитьВедущиеСписки. +Процедура ДобавитьПоляВедущегоСписка(ТекущиеПоля, ОписаниеПолей, ОписаниеПолейОтбора, ЗависимыйСписок, + ИмяСвойстваВидаПользователей) + + СписокПолей = Новый СписокЗначений; + Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл + Если ТекущиеПоля.ВсеПоля.Найти(ОписаниеПоля.Ключ) = Неопределено Тогда + ТекущиеПоля.ВсеПоля.Добавить(ОписаниеПоля.Ключ); + ТекущиеПоля.ТипыВсехПолей.Вставить(ОписаниеПоля.Ключ, ОписаниеПоля.Значение); + КонецЕсли; + СписокПолей.Добавить(ОписаниеПоля.Ключ); + КонецЦикла; + СписокПолей.СортироватьПоЗначению(); + НаборПолей = СтрСоединить(СписокПолей.ВыгрузитьЗначения(), ", "); + + НаборыПолей = ТекущиеПоля.НаборыПолей[ИмяСвойстваВидаПользователей]; + Если НаборыПолей = Неопределено Тогда + НаборыПолей = Новый Соответствие; + ТекущиеПоля.НаборыПолей[ИмяСвойстваВидаПользователей] = НаборыПолей; + КонецЕсли; + ЗависимыеСпискиПоПолямОтбора = НаборыПолей.Получить(НаборПолей); + Если ЗависимыеСпискиПоПолямОтбора = Неопределено Тогда + ЗависимыеСпискиПоПолямОтбора = Новый Соответствие; + НаборыПолей.Вставить(НаборПолей, ЗависимыеСпискиПоПолямОтбора); + КонецЕсли; + + СписокПолей = Новый СписокЗначений; + Для Каждого ОписаниеПоля Из ОписаниеПолейОтбора Цикл + СписокПолей.Добавить(ОписаниеПоля.Ключ); + КонецЦикла; + СписокПолей.СортироватьПоЗначению(); + НаборПолейОтбора = СтрСоединить(СписокПолей.ВыгрузитьЗначения(), ", "); + + ЗависимыеСписки = ЗависимыеСпискиПоПолямОтбора.Получить(НаборПолейОтбора); + Если ЗависимыеСписки = Неопределено Тогда + ЗависимыеСписки = Новый Массив; + ЗависимыеСпискиПоПолямОтбора.Вставить(НаборПолейОтбора, ЗависимыеСписки); + КонецЕсли; + ЗависимыеСписки.Добавить(ЗависимыйСписок); + +КонецПроцедуры + +// Для процедуры ДобавитьХранимыеПараметрыОграниченияДляВидаПользователей. +Процедура НастроитьПараметрыШаблонов(СвойстваСписка, Контекст) + + Параметры = СвойстваСписка.Параметры; + ПараметрыШаблонов = Контекст.ПараметрыШаблонов; + + Если Параметры.ДоступЗапрещен Тогда + Уточнение = ?(Контекст.ДляВнешнихПользователей + И Не Контекст.ОбщийКонтекст.ВнешниеПользователиВключены, "1", "0"); + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа + + СвойстваСписка.ПолноеИмя + ";" + Уточнение + Символы.ПС; + Возврат; + КонецЕсли; + + Если Не Параметры.ИспользуетсяОграничениеПоВладельцу + И Не Параметры.ЭтоСсылочныйТип + И Не Параметры.ОграничениеОтключено Тогда + + ОпорныеПоля = Параметры.ОпорныеПоля; + Версия = НоваяВерсияПараметровШаблонов(); + Версия.ДатаСоздания = Контекст.ДатаСоздания; + Версия.Список = СвойстваСписка.ПолноеИмя; + Версия.ПоляСоединения = СтрСоединить(ОпорныеПоля.Используемые, ","); + Версия.ПоляШаблона = СтрСоединить(ОпорныеПоля.Все, ","); + Версия.ВариантДоступа = ОпорныеПоля.Используемые.Количество() * 2 + + ?(Контекст.ДляВнешнихПользователей, 1, 0); + Версии = Новый Массив; + Версии.Добавить(Версия); + КлючТаблицы = КлючТаблицы(СвойстваСписка.ПолноеИмя, Параметры.Контекст.ИмяКоллекцииТипа); + Контекст.ВерсииПараметровШаблонов.Вставить(КлючТаблицы, Версии); + КонецЕсли; + + Если Параметры.ОграничениеЧтенияОтключено Тогда + ПараметрыШаблонов.СпискиСОтключеннымОграничениемЧтения = + ПараметрыШаблонов.СпискиСОтключеннымОграничениемЧтения + + СвойстваСписка.ПолноеИмя + ";" + Символы.ПС; + Возврат; + КонецЕсли; + + ПолеВладельцаОтключено = ""; + + Если Параметры.ИспользуетсяОграничениеПоВладельцу + Или Параметры.ЭтоСсылочныйТип Тогда + + ПолеВладельца = Параметры.ПолеВладельца; // См. НовоеПолеВладельца + Если ПолеВладельца <> Неопределено Тогда + Поля = ":" + ПолеВладельца.Имя; + Если Не Параметры.ИспользуетсяОграничениеПоВладельцу Тогда + ПолеВладельцаОтключено = ";-"; + КонецЕсли; + Иначе + Поля = ":"; + КонецЕсли; + Иначе + ОпорныеПоля = Параметры.ОпорныеПоля; + Если ЗначениеЗаполнено(Параметры.ИмяОтдельногоРегистраКлючей) Тогда + Поля = "КлючиДоступаКРегистру" + СтрРазделить(СвойстваСписка.ПолноеИмя, ".")[1]; + Иначе + Поля = УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных( + СвойстваСписка.ПолноеИмя); + КонецЕсли; + Поля = ":[" + Поля + "]"; + Номер = 1; + Для Каждого ИмяПоля Из ОпорныеПоля.Все Цикл + Поля = Поля + ":" + ИмяПоля; + Номер = Номер + 1; + КонецЦикла; + НомерПустогоПоля = ОпорныеПоля.Все.Количество() + 1; + Для Номер = НомерПустогоПоля По ОпорныеПоля.МаксимальноДопустимоеКоличество Цикл + Поля = Поля + ":"; + КонецЦикла; + КонецЕсли; + + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа = + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаГруппДоступа + + СвойстваСписка.ПолноеИмя + Поля + ";*" + ПолеВладельцаОтключено + Символы.ПС; + + Если СвойстваСписка.КлючиДоступаПользователейИГруппДоступа + Или СвойстваСписка.КлючиДоступаПользователей Тогда + + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаПользователей = + ПараметрыШаблонов.СпискиСОграничениемЧерезКлючиДоступаПользователей + + СвойстваСписка.ПолноеИмя + Поля + ";+" + ПолеВладельцаОтключено + Символы.ПС; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры НастроитьПараметрыШаблонов. +// +// Параметры: +// ПолноеИмя - Строка +// ИмяКоллекцииТипа - Строка +// ТипыТаблицПоИменам - Соответствие +// +// Возвращаемое значение: +// Строка +// +Функция КлючТаблицы(ПолноеИмя, ИмяКоллекцииТипа = Неопределено, ТипыТаблицПоИменам = Неопределено) + + Если ИмяКоллекцииТипа = Неопределено Тогда + СвойстваТипа = ТипыТаблицПоИменам.Получить(ВРег(СтрРазделить(ПолноеИмя, ".", Ложь)[0])); + ИмяКоллекцииТипа = СвойстваТипа.ИмяКоллекции; + КонецЕсли; + + Если ИмяКоллекцииТипа = "РегистрыСведений" + Или ИмяКоллекцииТипа = "РегистрыНакопления" + Или ИмяКоллекцииТипа = "РегистрыБухгалтерии" + Или ИмяКоллекцииТипа = "РегистрыРасчета" Тогда + + ТипКлючаТаблицы = ТипКлючаЗаписиПоПолномуИмениМетаданных(ПолноеИмя); + + ИначеЕсли ИмяКоллекцииТипа = "Последовательности" Тогда + ТипКлючаТаблицы = ТипНабораЗаписейПоПолномуИмениМетаданных(ПолноеИмя); + + ИначеЕсли ИмяКоллекцииТипа = "ЖурналыДокументов" Тогда + ТипКлючаТаблицы = ТипМенеджераОбъектаПоПолномуИмениМетаданных(ПолноеИмя); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Неизвестный нессылочный объект метаданных + |""%1"" + |с поддержкой ограничений на уровне записей.'"), ПолноеИмя); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + СтрокаДляХеширования = СтрокаДанныхДляХеширования(ТипКлючаТаблицы); + ХешированиеДанных.Добавить(СтрокаДляХеширования); + + Возврат Base64Строка(ХешированиеДанных.ХешСумма); + +КонецФункции + +// Для процедуры ОписаниеНовойВерсииПараметровОграниченияДоступа. +Процедура ЗаполнитьПараметрыДляШаблонов(Запись, ПараметрыЗаписи, ОписаниеВерсии) + + Если ТипЗнч(ОписаниеВерсии.ДатаСоздания) = Тип("Дата") Тогда + СтараяДатаСоздания = ОписаниеВерсии.ДатаСоздания; + Иначе + СтараяДатаСоздания = '00010101'; + КонецЕсли; + + ХранимыеТекущиеВерсии = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + ТекущиеСвойстваОграниченияСписковДляПользователей = Новый Соответствие; + ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = Новый Соответствие; + ВерсииПараметровШаблоновПолучены = Ложь; + + Если ТипЗнч(ОписаниеВерсии.ВерсииПараметровШаблонов) = Тип("ХранилищеЗначения") Тогда + СодержимоеХранилища = ЗначениеИзХранилища(ОписаниеВерсии.ВерсииПараметровШаблонов); + Если ЗначениеЗаполнено(СодержимоеХранилища) Тогда + ХранимыеТекущиеВерсии = СтруктураХранимыхВерсийПараметровШаблонов(СодержимоеХранилища); + Если ХранимыеТекущиеВерсии.ВерсияСтруктурыВерсий = ВерсияСтруктурыВерсийПараметровШаблонов() Тогда + ВерсииПараметровШаблоновПолучены = Истина; + ТекущиеСвойстваОграниченияСписковДляПользователей = Неопределено; + ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = Неопределено; + Иначе + ХранимыеТекущиеВерсии = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + КонецЕсли; + ИначеЕсли ТипЗнч(ОписаниеВерсии.Версия) = Тип("Число") Тогда + ТекущиеХранимыеПараметры = ВерсияПараметров(ОписаниеВерсии.Версия, Ложь, Ложь); + Если ТипЗнч(ТекущиеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав) = Тип("ХранилищеЗначения") Тогда + ТекущиеПараметрыЗаписи = СтруктураХранимыхПараметровЗаписи( + ЗначениеИзХранилища(ТекущиеХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав)); + Если ТекущиеПараметрыЗаписи.ВерсияСтруктурыКэша = ВерсияСтруктурыКэша() + Или ТекущиеПараметрыЗаписи.ВерсияСтруктурыКэша = "20" Тогда + ТекущиеСвойстваОграниченияСписковДляПользователей = + ТекущиеПараметрыЗаписи.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков; + ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей = + ТекущиеПараметрыЗаписи.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + Если Не ВерсииПараметровШаблоновПолучены Тогда + ОписаниеВерсии.ХешСумма = "#" + ОписаниеВерсии.ХешСумма; + КонецЕсли; + + Если ПараметрыЗаписи.Свойство("СтрокиВерсии") Тогда + СтрокиВерсии = ПараметрыЗаписи.СтрокиВерсии; + Иначе + СтрокиВерсии = Новый Структура; + КонецЕсли; + СтрокиВерсии.Вставить("СпискиСОграничениемПоПолямВСеансахПользователей"); + СтрокиВерсии.Вставить("СпискиСОграничениемПоПолямВСеансахВнешнихПользователей"); + + Если ТекущиеСвойстваОграниченияСписковДляПользователей <> Неопределено Тогда + НовыеПараметрыЗаписи = ПараметрыЗаписи.ХранимыеПараметры.ДляЗаписиОбъектовИПроверкиПрав.Получить(); + НовыеСвойстваОграниченияСписковДляПользователей = + НовыеПараметрыЗаписи.ДополнительныйКонтекст.ДляПользователей.СвойстваОграниченияСписков; + НовыеСвойстваОграниченияСписковДляВнешнихПользователей = + НовыеПараметрыЗаписи.ДополнительныйКонтекст.ДляВнешнихПользователей.СвойстваОграниченияСписков; + КонецЕсли; + + ХранимыеНовыеВерсии = ПараметрыЗаписи.ХранимыеПараметры.ВерсииПараметровШаблонов.Получить(); + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + + Параметры = НоваяСтруктураДляЗаполненияПараметровШаблонов(); + Параметры.Вставить("ИдентификаторыВсехСписков", ПараметрыЗаписи.ИдентификаторыВсехСписков); + Если ТипЗнч(ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа) = Тип("Массив") Тогда + Параметры.Вставить("ОтключитьДополнительныеВариантыДоступа"); + Иначе + ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа = Новый Массив; + КонецЕсли; + Параметры.Вставить("СтараяДатаСоздания", СтараяДатаСоздания); + Параметры.Вставить("ХешированиеДанных", ХешированиеДанных); + Параметры.Вставить("СпискиСНовымОсновнымВариантомДоступа", ПараметрыЗаписи.СпискиСНовымОсновнымВариантомДоступа); + Параметры.Вставить("СпискиСУстаревшимиВариантамиДоступа", ПараметрыЗаписи.СпискиСУстаревшимиВариантамиДоступа); + + Параметры.Вставить("ХранимыеТекущиеВерсии", ХранимыеТекущиеВерсии.ДляПользователей); + Параметры.Вставить("НовыеВерсииПолейСписков", ХранимыеНовыеВерсии.ДляПользователей.ВерсииПараметровШаблонов); + Параметры.Вставить("ТекущиеСвойстваОграниченияСписков", ТекущиеСвойстваОграниченияСписковДляПользователей); + Параметры.Вставить("НовыеСвойстваОграниченияСписков", НовыеСвойстваОграниченияСписковДляПользователей); + + ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, + Запись.ДляШаблоновВСеансахПользователей, + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахПользователей); + + Параметры.ХранимыеТекущиеВерсии = ХранимыеТекущиеВерсии.ДляВнешнихПользователей; + Параметры.НовыеВерсииПолейСписков = ХранимыеНовыеВерсии.ДляВнешнихПользователей.ВерсииПараметровШаблонов; + Параметры.ТекущиеСвойстваОграниченияСписков = ТекущиеСвойстваОграниченияСписковДляВнешнихПользователей; + Параметры.НовыеСвойстваОграниченияСписков = НовыеСвойстваОграниченияСписковДляВнешнихПользователей; + + ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, + Запись.ДляШаблоновВСеансахВнешнихПользователей, + СтрокиВерсии.СпискиСОграничениемПоПолямВСеансахВнешнихПользователей); + + Запись.ХешСуммаПараметровШаблонов = Base64Строка(ХешированиеДанных.ХешСумма); + Запись.ВерсииПараметровШаблонов = Новый ХранилищеЗначения(ХранимыеТекущиеВерсии); + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + ХешированиеДанных.Добавить(Запись.ХешСуммаПостоянныхПараметров); + ХешированиеДанных.Добавить(Запись.ХешСуммаПараметровШаблонов); + Запись.ХешСумма = Base64Строка(ХешированиеДанных.ХешСумма); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблонов. +// +// Возвращаемое значение: +// Структура: +// * СтараяДатаСоздания - Дата +// * ХешированиеДанных - ХешированиеДанных +// * СпискиСНовымОсновнымВариантомДоступа - Массив из Строка +// * СпискиСУстаревшимиВариантамиДоступа - Массив из Строка +// * ХранимыеТекущиеВерсии - Структура: +// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов +// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// * НовыеВерсииПолейСписков - см. НовыеВерсииПараметровШаблонов +// * ТекущиеСвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * НовыеСвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * ИдентификаторыВсехСписков - Неопределено +// - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных +// - СправочникСсылка.ИдентификаторыОбъектовРасширений +// +Функция НоваяСтруктураДляЗаполненияПараметровШаблонов() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ЗаполнитьПараметрыДляШаблонов. +// +// Параметры: +// Параметры - см. НоваяСтруктураДляЗаполненияПараметровШаблонов +// ХранилищеДляШаблоновВСеансах - ХранилищеЗначения - обновляемое значение +// СпискиСОграничениемПоПолям - Строка - возвращаемое значение +// +Процедура ЗаполнитьПараметрыДляШаблоновДляВидаПользователей(Параметры, + ХранилищеДляШаблоновВСеансах, СпискиСОграничениемПоПолям) + + МаксимальноеКоличествоВерсий = МаксимальноеКоличествоВерсийВВариантеДоступа(); + НастройкиОграниченийСписков = Новый СписокЗначений; + ТекущиеВерсииПолейСписков = Параметры.ХранимыеТекущиеВерсии.ВерсииПараметровШаблонов; + + Если Параметры.ТекущиеСвойстваОграниченияСписков <> Неопределено Тогда + ВариантыДоступаВБазеДанных = ВариантыДоступаВБазеДанных(Параметры); + Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл + ТекущиеВерсииПолейСписка = Новый Массив; + ДобавитьСуществующиеВерсииПолейСписка(ТекущиеВерсииПолейСписка, + КлючИЗначение.Значение[0], ВариантыДоступаВБазеДанных, Параметры); + Если ЗначениеЗаполнено(ТекущиеВерсииПолейСписка) Тогда + ТекущиеВерсииПолейСписков.Вставить(КлючИЗначение.Ключ, ТекущиеВерсииПолейСписка); + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ВозможноНеиспользуемыеВерсииПолейСписков = Новый Массив; + + Для Каждого КлючИЗначение Из ТекущиеВерсииПолейСписков Цикл + ТекущиеВерсииПолейСписка = КлючИЗначение.Значение; + НовыеВерсииПолейСписка = Параметры.НовыеВерсииПолейСписков.Получить(КлючИЗначение.Ключ); + + Если НовыеВерсииПолейСписка = Неопределено Тогда + ИспользованиеОтключалось = Ложь; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + Если Версия.Используется Тогда + Версия.Используется = Ложь; + ИспользованиеОтключалось = Истина; + КонецЕсли; + КонецЦикла; + Если ИспользованиеОтключалось И ТекущиеВерсииПолейСписка.Количество() > 0 Тогда + ПолноеИмя = ТекущиеВерсииПолейСписка[0].Список; + Если ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) <> Неопределено Тогда + Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + КонецЕсли; + Продолжить; + КонецЕсли; + + НоваяВерсия = НовыеВерсииПолейСписка[0]; + НоваяВерсияСуществует = Ложь; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + Если ВРег(Версия.ПоляСоединения) = ВРег(НоваяВерсия.ПоляСоединения) + И Версия.ВариантДоступа > 1 Тогда + НоваяВерсияСуществует = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + ОсновнаяВерсияИзменена = Истина; + Если НоваяВерсияСуществует Тогда + Индекс = ТекущиеВерсииПолейСписка.Найти(Версия); + Если Индекс > 0 Тогда + ТекущиеВерсииПолейСписка.Удалить(Индекс); + ТекущиеВерсииПолейСписка.Вставить(0, Версия); + Иначе + ОсновнаяВерсияИзменена = Ложь; + КонецЕсли; + ЗаполнитьЗначенияСвойств(Версия, НоваяВерсия,, "ВариантДоступа"); + Иначе + ИспользуемыеНомераВерсий = Новый Массив(МаксимальноеКоличествоВерсий); + СамаяСтараяВерсия = Неопределено; + УдаляемыеВерсии = Новый Массив; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + НомерВерсии = Цел(Версия.ВариантДоступа / 64); + Если НоваяВерсия.ВариантДоступа <> (Версия.ВариантДоступа - НомерВерсии * 64) Тогда + Продолжить; + КонецЕсли; + Если НомерВерсии < МаксимальноеКоличествоВерсий Тогда + ИспользуемыеНомераВерсий[НомерВерсии] = Версия; + СамаяСтараяВерсия = Версия; + Иначе + УдаляемыеВерсии.Добавить(Версия); + КонецЕсли; + КонецЦикла; + Для Индекс = 0 По МаксимальноеКоличествоВерсий - 1 Цикл + Если ИспользуемыеНомераВерсий[Индекс] = Неопределено Тогда + Прервать; + КонецЕсли; + КонецЦикла; + Если Индекс >= МаксимальноеКоличествоВерсий Тогда + УдаляемыеВерсии.Добавить(СамаяСтараяВерсия); + НоваяВерсия.ВариантДоступа = НоваяВерсия.ВариантДоступа + + ИспользуемыеНомераВерсий.Найти(СамаяСтараяВерсия) * 64; + Иначе + НоваяВерсия.ВариантДоступа = НоваяВерсия.ВариантДоступа + Индекс * 64; + КонецЕсли; + Для Каждого УдаляемаяВерсия Из УдаляемыеВерсии Цикл + ТекущиеВерсииПолейСписка.Удалить(ТекущиеВерсииПолейСписка.Найти(УдаляемаяВерсия)); + КонецЦикла; + ТекущиеВерсииПолейСписка.Вставить(0, НоваяВерсия); + КонецЕсли; + + Если ОсновнаяВерсияИзменена Тогда + Параметры.СпискиСНовымОсновнымВариантомДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + + ОбновитьИспользованиеВерсийПолейСписка(ТекущиеВерсииПолейСписка, ОсновнаяВерсияИзменена, + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры); + КонецЦикла; + + ОтключитьИспользованиеВерсийКромеОсновнойДляОбновленныхСписков( + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры); + + ОсновныеВариантыДоступа = Параметры.ХранимыеТекущиеВерсии.ОсновныеВариантыДоступа; + + Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл + ТекущиеВерсииПолейСписка = ТекущиеВерсииПолейСписков.Получить(КлючИЗначение.Ключ); + Если ТекущиеВерсииПолейСписка = Неопределено Тогда + ТекущиеВерсииПолейСписка = КлючИЗначение.Значение; + ТекущиеВерсииПолейСписков.Вставить(КлючИЗначение.Ключ, ТекущиеВерсииПолейСписка); + Параметры.СпискиСНовымОсновнымВариантомДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + ИспользуемыеВариантыДоступа = Новый Массив; + Для Каждого ВерсияПолейСписка Из ТекущиеВерсииПолейСписка Цикл + Если ВерсияПолейСписка.Используется Тогда + ИспользуемыйВариантДоступа = НовыйИспользуемыйВариантДоступа(); + ИспользуемыйВариантДоступа.ВариантДоступа = ВерсияПолейСписка.ВариантДоступа; + ИспользуемыйВариантДоступа.ПоляСоединения = ВерсияПолейСписка.ПоляСоединения; + ИспользуемыеВариантыДоступа.Добавить(Новый ФиксированнаяСтруктура(ИспользуемыйВариантДоступа)); + КонецЕсли; + КонецЦикла; + ОсновныеВариантыДоступа.Вставить(ТекущиеВерсииПолейСписка[0].Список, + Новый ФиксированныйМассив(ИспользуемыеВариантыДоступа)); + КонецЦикла; + + Для Каждого КлючИЗначение Из ТекущиеВерсииПолейСписков Цикл + ДобавитьПоляОграниченияСписка(НастройкиОграниченийСписков, КлючИЗначение.Значение); + КонецЦикла; + + НастройкиОграниченийСписков.СортироватьПоПредставлению(); + СпискиСОграничениемПоПолям = СтрСоединить(НастройкиОграниченийСписков.ВыгрузитьЗначения(), Символы.ПС); + Параметры.ХешированиеДанных.Добавить(СпискиСОграничениемПоПолям); + + ХранимыеПараметрыШаблонов = Новый Структура(ХранилищеДляШаблоновВСеансах.Получить()); + ПараметрыШаблонов = Новый Структура(ХранимыеПараметрыШаблонов.ПараметрыШаблонов); + ПараметрыШаблонов.СпискиСОграничениемПоПолям = СпискиСОграничениемПоПолям; + ХранимыеПараметрыШаблонов.ПараметрыШаблонов = Новый ФиксированнаяСтруктура(ПараметрыШаблонов); + ХранилищеДляШаблоновВСеансах = Новый ХранилищеЗначения( + Новый ФиксированнаяСтруктура(ХранимыеПараметрыШаблонов)); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ОбновитьИспользованиеВерсийПолейСписка(ТекущиеВерсииПолейСписка, ОсновнаяВерсияИзменена, + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры) + + МаксимальноеКоличествоВариантовСоединений = МаксимальноеКоличествоВариантовСоединений(); + НоваяВерсия = ТекущиеВерсииПолейСписка[0]; + ПоляШаблона = СтрРазделить(ВРег(НоваяВерсия.ПоляШаблона), ",", Ложь); + + КоличествоИспользуемыхВерсий = 0; + ИспользованиеОтключалось = Ложь; + + Для Каждого ТекущаяВерсия Из ТекущиеВерсииПолейСписка Цикл + Если Не ТекущаяВерсия.Используется Тогда + Продолжить; + КонецЕсли; + Если ВРег(ТекущаяВерсия.ПоляШаблона) <> ВРег(НоваяВерсия.ПоляШаблона) Тогда + ИменаПолей = СтрРазделить(ТекущаяВерсия.ПоляСоединения, ",", Ложь); + Для Каждого ИмяПоля Из ИменаПолей Цикл + Если ПоляШаблона.Найти(ВРег(ИмяПоля)) = Неопределено Тогда + ТекущаяВерсия.Используется = Ложь; + ИспользованиеОтключалось = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если Не ТекущаяВерсия.Используется Тогда + Продолжить; + КонецЕсли; + Если КоличествоИспользуемыхВерсий >= МаксимальноеКоличествоВариантовСоединений Тогда + ТекущаяВерсия.Используется = Ложь; + ИспользованиеОтключалось = Истина; + Иначе + КоличествоИспользуемыхВерсий = КоличествоИспользуемыхВерсий + 1; + КонецЕсли; + КонецЦикла; + + Если ИспользованиеОтключалось Тогда + Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить( + ТекущиеВерсииПолейСписка[0].Список); + КонецЕсли; + + Если Не ОсновнаяВерсияИзменена И КоличествоИспользуемыхВерсий > 1 Тогда + ВозможноНеиспользуемыеВерсииПолейСписков.Добавить(ТекущиеВерсииПолейСписка); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ДобавитьПоляОграниченияСписка(СпискиСОграничениемПоПолям, ТекущиеВерсииПолейСписка) + + НоваяВерсия = ТекущиеВерсииПолейСписка[0]; + ПолноеИмя = НоваяВерсия.Список; + ПоляШаблона = СтрРазделить(ВРег(НоваяВерсия.ПоляШаблона), ",", Ложь); + НастройкиОграниченийСписка = Новый Массив; + МаксимальноеКоличествоВариантов = МаксимальноеКоличествоВариантовСоединений(); + + НомерВарианта = 1; + Для Каждого Версия Из ТекущиеВерсииПолейСписка Цикл + Если Не Версия.Используется Тогда + Прервать; + КонецЕсли; + + НомерПоляСоединения = 1; + ИменаПолей = СтрРазделить(Версия.ПоляСоединения, ",", Ложь); + Для Каждого ИмяПоля Из ИменаПолей Цикл + НомерПоляШаблона = ПоляШаблона.Найти(ВРег(ИмяПоля)) + 1; + НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=%4;", + ПолноеИмя, + "Вариант" + XMLСтрока(НомерВарианта), + "Поле" + XMLСтрока(НомерПоляСоединения), + "Поле" + XMLСтрока(НомерПоляШаблона))); + НомерПоляСоединения = НомерПоляСоединения + 1; + КонецЦикла; + + Если Цел(Версия.ВариантДоступа / 2) = 0 Тогда + НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=0;", + ПолноеИмя, + "Вариант" + XMLСтрока(НомерВарианта), + "Версия" + XMLСтрока(НомерВарианта))); + Иначе + Остаток = Цел(Версия.ВариантДоступа / 64); + НомерБита = 0; + Пока Остаток > 0 Цикл + НовыйОстаток = Цел(Остаток / 2); + Если Остаток - НовыйОстаток * 2 > 0 Тогда + НастройкиОграниченийСписка.Добавить(СтрШаблон("%1:%2%3=1;", + ПолноеИмя, + "Версия" + XMLСтрока(НомерВарианта), + "Бит" + XMLСтрока(НомерБита))); + КонецЕсли; + Остаток = НовыйОстаток; + НомерБита = НомерБита + 1; + КонецЦикла; + КонецЕсли; + + НомерВарианта = НомерВарианта + 1; + Если НомерВарианта > МаксимальноеКоличествоВариантов Тогда + Прервать; + КонецЕсли; + КонецЦикла; + + СпискиСОграничениемПоПолям.Добавить( + СтрСоединить(НастройкиОграниченийСписка, Символы.ПС), ПолноеИмя); + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Функция ВариантыДоступаВБазеДанных(Параметры) + + Если Не ЗначениеЗаполнено(Параметры.НовыеВерсииПолейСписков) Тогда + Возврат Новый Соответствие; + КонецЕсли; + + ТекстОбщегоЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.Регистр КАК Регистр, + | ТекущаяТаблица.ВариантДоступа КАК ВариантДоступа + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК ТекущаяТаблица + |ГДЕ + | ВЫБОР + | КОГДА ТекущаяТаблица.ВариантДоступа = 0 + | ТОГДА ЛОЖЬ + | ИНАЧЕ ТекущаяТаблица.ВариантДоступа - (ВЫРАЗИТЬ(ТекущаяТаблица.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 + | КОНЕЦ = &ДляВнешнихПользователей + | + |УПОРЯДОЧИТЬ ПО + | Регистр, + | ВариантДоступа"; + + ТекстыЗапросов = Новый Массив; + ТекстыЗапросов.Добавить(ТекстОбщегоЗапроса); + + ПолныеИмена = Новый Массив; + ИндексыРезультатовЗапроса = Новый Соответствие; + + Для Каждого КлючИЗначение Из Параметры.НовыеВерсииПолейСписков Цикл + Список = КлючИЗначение.Значение[0].Список; + СвойстваСписка = Параметры.НовыеСвойстваОграниченияСписков.Получить(Список); + Если СвойстваСписка = Неопределено + Или Не ЗначениеЗаполнено(СвойстваСписка.ОпорныеПоля) Тогда + Продолжить; + КонецЕсли; + ПолныеИмена.Добавить(Список); + Если ЗначениеЗаполнено(СвойстваСписка.ИмяОтдельногоРегистраКлючей) Тогда + ИндексыРезультатовЗапроса.Вставить(Список, ТекстыЗапросов.Количество()); + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущаяТаблица.ВариантДоступа КАК ВариантДоступа + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | ВЫБОР + | КОГДА ТекущаяТаблица.ВариантДоступа = 0 + | ТОГДА ЛОЖЬ + | ИНАЧЕ ТекущаяТаблица.ВариантДоступа - (ВЫРАЗИТЬ(ТекущаяТаблица.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 + | КОНЕЦ = &ДляВнешнихПользователей + | + |УПОРЯДОЧИТЬ ПО + | ВариантДоступа"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", + "РегистрСведений." + СвойстваСписка.ИмяОтдельногоРегистраКлючей); + ТекстыЗапросов.Добавить(ТекстЗапроса); + Иначе + ИндексыРезультатовЗапроса.Вставить(Список, 0); + КонецЕсли; + КонецЦикла; + + ИдентификаторыСписков = ?(Параметры.ИдентификаторыВсехСписков = Неопределено, + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена, Ложь), + Параметры.ИдентификаторыВсехСписков); + + Запрос = Новый Запрос; + ВариантДоступа = КлючИЗначение.Значение[0].ВариантДоступа; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ВариантДоступа - Цел(ВариантДоступа / 2) * 2 > 0); + Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Выгрузка = РезультатыЗапроса[0].Выгрузить(); + Выгрузка.Индексы.Добавить("Регистр"); + + Результат = Новый Соответствие; + + Для Каждого КлючИЗначение Из ИндексыРезультатовЗапроса Цикл + Если КлючИЗначение.Значение = 0 Тогда + ИдентификаторСписка = ИдентификаторыСписков.Получить(КлючИЗначение.Ключ); + ВариантыДоступа = Новый Массив; + Если ИдентификаторСписка <> Неопределено И ИдентификаторСписка <> Null Тогда + НайденныеСтроки = Выгрузка.НайтиСтроки(Новый Структура("Регистр", ИдентификаторСписка)); + Для Каждого НайденнаяСтрока Из НайденныеСтроки Цикл + ВариантыДоступа.Добавить(НайденнаяСтрока.ВариантДоступа); + КонецЦикла; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не найден идентификатор объекта метаданных ""%1"".'"), КлючИЗначение.Ключ); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + Результат.Вставить(КлючИЗначение.Ключ, ВариантыДоступа); + Иначе + Результат.Вставить(КлючИЗначение.Ключ, + РезультатыЗапроса[КлючИЗначение.Значение].Выгрузить().ВыгрузитьКолонку("ВариантДоступа")); + КонецЕсли; + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ОтключитьИспользованиеВерсийКромеОсновнойДляОбновленныхСписков( + ВозможноНеиспользуемыеВерсииПолейСписков, Параметры) + + Если Не ЗначениеЗаполнено(ВозможноНеиспользуемыеВерсииПолейСписков) + Или Не Параметры.Свойство("ОтключитьДополнительныеВариантыДоступа") Тогда + Возврат; + КонецЕсли; + + Списки = Новый Массив; + ВерсииПолейСписков = Новый Соответствие; + Для Каждого ВерсииПолейСписка Из ВозможноНеиспользуемыеВерсииПолейСписков Цикл + Список = ВерсииПолейСписка[0].Список; + Списки.Добавить(Список); + ВерсииПолейСписков.Вставить(Список, ВерсииПолейСписка); + КонецЦикла; + + ДляВнешнихПользователей = ВерсииПолейСписка[0].ВариантДоступа + - Цел(ВерсииПолейСписка[0].ВариантДоступа / 2) * 2 = 1; + + ТипыИдентификаторов = Новый Массив; + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")); + ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений")); + + ИдентификаторыСписков = Новый ТаблицаЗначений; + ИдентификаторыСписков.Колонки.Добавить("ИдентификаторСписка", Новый ОписаниеТипов(ТипыИдентификаторов)); + + СпискиПоИдентификаторам = Новый Соответствие; + ИдентификаторыОбъектов = ?(Параметры.ИдентификаторыВсехСписков = Неопределено, + ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки, Ложь), + Параметры.ИдентификаторыВсехСписков); + + Для Каждого Список Из Списки Цикл + ИдентификаторСписка = ИдентификаторыОбъектов.Получить(Список); + Если ИдентификаторСписка <> Неопределено И ИдентификаторСписка <> Null Тогда + ИдентификаторыСписков.Добавить().ИдентификаторСписка = ИдентификаторСписка; + СпискиПоИдентификаторам.Вставить(ИдентификаторСписка, Список); + КонецЕсли; + КонецЦикла; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей); + Запрос.УстановитьПараметр("ИдентификаторыСписков", ИдентификаторыСписков); + Запрос.Текст = + "ВЫБРАТЬ + | ИдентификаторыСписков.ИдентификаторСписка КАК ИдентификаторСписка + |ПОМЕСТИТЬ ИдентификаторыСписков + |ИЗ + | &ИдентификаторыСписков КАК ИдентификаторыСписков + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ИдентификаторыСписков.ИдентификаторСписка КАК ИдентификаторСписка + |ИЗ + | ИдентификаторыСписков КАК ИдентификаторыСписков + |ГДЕ + | НЕ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | ГДЕ + | ОбновлениеКлючейДоступаКДанным.Список = ИдентификаторыСписков.ИдентификаторСписка + | И ОбновлениеКлючейДоступаКДанным.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ОбновлениеКлючейДоступаКДанным.РазмерЗадания = 3)"; + + Выборка = Запрос.Выполнить().Выбрать(); + Пока Выборка.Следующий() Цикл + Список = СпискиПоИдентификаторам.Получить(Выборка.ИдентификаторСписка); + ВерсииПолейСписка = ВерсииПолейСписков.Получить(Список); + ОсновнаяВерсия = ВерсииПолейСписка[0]; + Для Каждого ВерсияПолейСписка Из ВерсииПолейСписка Цикл + Если ВерсияПолейСписка = ОсновнаяВерсия Тогда + Продолжить; + КонецЕсли; + Если ВерсияПолейСписка.Используется Тогда + ВерсияПолейСписка.Используется = Ложь; + Параметры.СпискиСУстаревшимиВариантамиДоступа.Добавить(Список); + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Процедура ДобавитьСуществующиеВерсииПолейСписка(ТекущиеВерсииПолейСписка, НоваяВерсия, + ВариантыДоступаВБазеДанных, Параметры) + + ВариантыДоступа = ВариантыДоступаВБазеДанных.Получить(НоваяВерсия.Список); + Если Не ЗначениеЗаполнено(ВариантыДоступа) Тогда + Возврат; + КонецЕсли; + + ТекущиеСвойстваСписка = Параметры.ТекущиеСвойстваОграниченияСписков.Получить(НоваяВерсия.Список); + ОпорныеПоля = ?(ТекущиеСвойстваСписка = Неопределено, Неопределено, ТекущиеСвойстваСписка.ОпорныеПоля); + Если ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) И ЗначениеЗаполнено(ОпорныеПоля) Тогда + ТребуемыйВариантДоступа = ОпорныеПоля.Используемые.Количество() * 2 + + НоваяВерсия.ВариантДоступа - Цел(НоваяВерсия.ВариантДоступа / 2) * 2; + Иначе + ТребуемыйВариантДоступа = НоваяВерсия.ВариантДоступа; + КонецЕсли; + + Если ВариантыДоступа.Количество() = 1 + И (Не ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) + Или ЗначениеЗаполнено(ОпорныеПоля)) + И ( ВариантыДоступа[0] < 2 + Или ВариантыДоступа[0] - Цел(ВариантыДоступа[0] / 64) * 64 = ТребуемыйВариантДоступа) Тогда + + // Переход с версий конфигурации без поля ВариантДоступа или восстановление + // либо после очистки регистра ПараметрыОграниченияДоступа, + // либо после изменения номера в функции ВерсияСтруктурыВерсийПараметровШаблонов. + Если Не ЗначениеЗаполнено(Параметры.СтараяДатаСоздания) Тогда + ПоляСоединения = НоваяВерсия.ПоляСоединения; + ПоляШаблона = НоваяВерсия.ПоляСоединения; + Иначе + ПоляСоединения = СтрСоединить(ОпорныеПоля.Используемые, ","); + ПоляШаблона = СтрСоединить(ОпорныеПоля.Все, ","); + КонецЕсли; + + ПредыдущаяВерсия = НоваяВерсияПараметровШаблонов(); + ПредыдущаяВерсия.ДатаСоздания = Параметры.СтараяДатаСоздания; + ПредыдущаяВерсия.Список = НоваяВерсия.Список; + ПредыдущаяВерсия.ПоляСоединения = ПоляСоединения; + ПредыдущаяВерсия.ПоляШаблона = ПоляШаблона; + ПредыдущаяВерсия.ВариантДоступа = ВариантыДоступа[0]; + + ТекущиеВерсииПолейСписка.Добавить(ПредыдущаяВерсия); + Иначе + // Несколько версий существующих одновременно не могут быть сопоставлены + // одному набору полей и не могут использоваться для новых наборов полей. + Для Каждого ВариантДоступа Из ВариантыДоступа Цикл + НеизвестнаяВерсия = НоваяВерсияПараметровШаблонов(); + НеизвестнаяВерсия.ДатаСоздания = Параметры.СтараяДатаСоздания; + НеизвестнаяВерсия.Список = НоваяВерсия.Список; + НеизвестнаяВерсия.ВариантДоступа = ВариантДоступа; + НеизвестнаяВерсия.Используется = Ложь; + + ТекущиеВерсииПолейСписка.Добавить(НеизвестнаяВерсия); + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбновитьИспользованиеВерсийПолейСписка и ДобавитьПоляОграниченияСписка. +Функция МаксимальноеКоличествоВариантовСоединений() + + // При изменении нужно синхронно изменить шаблон ограничения доступа ДляРегистра. + Возврат 3; + +КонецФункции + +// Для процедур ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +Функция МаксимальноеКоличествоВерсийВВариантеДоступа() + + Возврат 16; + +КонецФункции + +// Для процедур УстановитьВерсиюПараметров, ЗаполнитьПараметрыДляШаблонов, +// ОбновитьТаблицыГруппДоступаДляПодключенныхРасширений и +// функции СпискиСИзменениемВерсий. +// +Функция ЗначениеИзХранилища(ХранилищеЗначения) + + Попытка + Значение = ХранилищеЗначения.Получить(); + Исключение + Значение = Неопределено; + КонецПопытки; + + Возврат Значение; + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров, и для функции ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииОграниченийСписков - ФиксированноеСоответствие +// * ВедущиеСписки - ФиксированноеСоответствие +// * ДополнительныйКонтекст - ФиксированнаяСтруктура +// * СпискиСДатой - ФиксированноеСоответствие +// * ВнешниеПользователиВключены - Булево +// * ОграничениеДоступаВключено - Булево +// * ИспользуемыеТипыЗначений - ХранилищеЗначения +// +Функция СтруктураХранимыхПараметровЗаписи(Значения) + + ХранимыеПараметрыЗаписи = НоваяСтруктураХранимыхПараметровЗаписи(); + ХранимыеПараметрыЗаписи.ВерсияСтруктурыКэша = ""; + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("ВерсияСтруктурыКэша") + И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") + И Значения.Свойство("ВерсииОграниченийСписков") + И ТипЗнч(Значения.ВерсииОграниченийСписков) = Тип("ФиксированноеСоответствие") + И Значения.Свойство("ВедущиеСписки") + И ТипЗнч(Значения.ВедущиеСписки) = Тип("ФиксированноеСоответствие") + И Значения.Свойство("ДополнительныйКонтекст") + И ТипЗнч(Значения.ДополнительныйКонтекст) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("СпискиСДатой") + И ТипЗнч(Значения.СпискиСДатой) = Тип("ФиксированноеСоответствие") + И Значения.Свойство("ВнешниеПользователиВключены") + И ТипЗнч(Значения.ВнешниеПользователиВключены) = Тип("Булево") + И Значения.Свойство("ОграничениеДоступаВключено") + И ТипЗнч(Значения.ОграничениеДоступаВключено) = Тип("Булево") + И Значения.Свойство("ИспользуемыеТипыЗначений") + И ТипЗнч(Значения.ИспользуемыеТипыЗначений) = Тип("ХранилищеЗначения") + И Значения.Свойство("ВерсияТекстовОграниченияДоступа") + И ТипЗнч(Значения.ВерсияТекстовОграниченияДоступа) = Тип("Строка") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеПараметрыЗаписи, Значения); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыЗаписи); + +КонецФункции + +// Для функций СтруктураХранимыхПараметровЗаписи и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииОграниченийСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Строка - общая версия ограничения списка +// первая строка - хеш-сумма свойств версии для пользователей и через Символы.ПС +// вторая строка - хеш-сумма свойств версии для внешних пользователей. +// +// * ВедущиеСписки - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СвойстваСпискаКакВедущего +// +// * ДополнительныйКонтекст - Структура: +// ** ДляПользователей - см. НовыйХранимыйДополнительныйКонтекст +// ** ДляВнешнихПользователей - см. НовыйХранимыйДополнительныйКонтекст +// +// * СпискиСДатой - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * ВнешниеПользователиВключены - Булево +// * ОграничениеДоступаВключено - Булево +// * ИспользуемыеТипыЗначений - ХранилищеЗначения - смотри функцию ИспользуемыеТипыЗначений. +// * ВерсияТекстовОграниченияДоступа - Строка +// +Функция НоваяСтруктураХранимыхПараметровЗаписи() Экспорт + + ХранимыеПараметрыЗаписи = Новый Структура; + ХранимыеПараметрыЗаписи.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); + ХранимыеПараметрыЗаписи.Вставить("ВерсииОграниченийСписков", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ВедущиеСписки", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ДополнительныйКонтекст", Новый Структура); + ХранимыеПараметрыЗаписи.Вставить("СпискиСДатой", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ВедущиеРоли", Новый Соответствие); + ХранимыеПараметрыЗаписи.Вставить("ВнешниеПользователиВключены", Ложь); + ХранимыеПараметрыЗаписи.Вставить("ОграничениеДоступаВключено", Ложь); + ХранимыеПараметрыЗаписи.Вставить("ИспользуемыеТипыЗначений", Новый ХранилищеЗначения(Новый Соответствие)); + ХранимыеПараметрыЗаписи.Вставить("ВерсияТекстовОграниченияДоступа", ""); + + Возврат ХранимыеПараметрыЗаписи; + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииШаблонов - см. ВерсииШаблоновОграниченияДоступа +// * ПараметрыШаблонов - см. СтруктураПараметровШаблонов +// +Функция СтруктураХранимыхПараметровШаблонов(Значения) + + ХранимыеПараметрыШаблонов = НоваяСтруктураХранимыхПараметровШаблонов(); + ХранимыеПараметрыШаблонов.ВерсияСтруктурыКэша = ""; + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("ВерсияСтруктурыКэша") + И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") + И Значения.Свойство("ВерсииШаблонов") + И ТипЗнч(Значения.ВерсииШаблонов) = Тип("Строка") + И Значения.Свойство("ПараметрыШаблонов") + И ТипЗнч(Значения.ПараметрыШаблонов) = Тип("ФиксированнаяСтруктура") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеПараметрыШаблонов, Значения); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыШаблонов); + +КонецФункции + +// Для функций СтруктураХранимыхПараметровШаблонов, СтруктураХранимыхПараметровЗаписи и +// ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВерсииШаблонов - см. ВерсииШаблоновОграниченияДоступа +// * ПараметрыШаблонов - см. СтруктураПараметровШаблонов +// +Функция НоваяСтруктураХранимыхПараметровШаблонов() + + ХранимыеПараметрыШаблонов = Новый Структура; + ХранимыеПараметрыШаблонов.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); + ХранимыеПараметрыШаблонов.Вставить("ВерсииШаблонов", ВерсииШаблоновОграниченияДоступа()); + ХранимыеПараметрыШаблонов.Вставить("ПараметрыШаблонов", НоваяСтруктураПараметровШаблонов()); + + Возврат ХранимыеПараметрыШаблонов; + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - Строка +// * СпискиСОграничениемЧерезКлючиДоступаПользователей - Строка +// * СпискиСОграничениемПоПолям - Строка +// * СпискиСОтключеннымОграничениемЧтения - Строка +// +Функция СтруктураПараметровШаблонов(Значения) + + ПараметрыШаблонов = НоваяСтруктураПараметровШаблонов(); + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Количество() = ПараметрыШаблонов.Количество() Тогда + + Совпадает = Истина; + Для Каждого КлючИЗначение Из ПараметрыШаблонов Цикл + Если Не Значения.Свойство(КлючИЗначение.Ключ) + Или Не ТипЗнч(Значения[КлючИЗначение.Ключ]) = ТипЗнч(КлючИЗначение.Значение) Тогда + Совпадает = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если Совпадает Тогда + ЗаполнитьЗначенияСвойств(ПараметрыШаблонов, Значения); + КонецЕсли; + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ПараметрыШаблонов); + +КонецФункции + +// Для функций СтруктураПараметровШаблонов, ХранимыеПараметрыОграниченияДоступа и +// НоваяСтруктураХранимыхПараметровШаблонов. +// +// Возвращаемое значение: +// Структура: +// * СпискиСОграничениемЧерезКлючиДоступаГруппДоступа - Строка +// * СпискиСОграничениемЧерезКлючиДоступаПользователей - Строка +// * СпискиСОграничениемПоПолям - Строка +// * СпискиСОтключеннымОграничениемЧтения - Строка +// +Функция НоваяСтруктураПараметровШаблонов() + + ПараметрыШаблонов = Новый Структура; + ПараметрыШаблонов.Вставить("СпискиСОграничениемЧерезКлючиДоступаГруппДоступа", ""); + ПараметрыШаблонов.Вставить("СпискиСОграничениемЧерезКлючиДоступаПользователей", ""); + ПараметрыШаблонов.Вставить("СпискиСОграничениемПоПолям", ""); + ПараметрыШаблонов.Вставить("СпискиСОтключеннымОграничениемЧтения", ""); + + Возврат ПараметрыШаблонов; + +КонецФункции + +// Для процедур УстановитьВерсиюПараметров и ЗаполнитьПараметрыДляШаблонов. +// +// Возвращаемое значение: +// см. НоваяСтруктураХранимыхВерсийПараметровШаблонов +// +Функция СтруктураХранимыхВерсийПараметровШаблонов(Значения) + + ХранимыеВерсийПараметровШаблонов = НоваяСтруктураХранимыхВерсийПараметровШаблонов(); + ХранимыеВерсийПараметровШаблонов.ВерсияСтруктурыВерсий = ""; + + Если ТипЗнч(Значения) = Тип("Структура") + И Значения.Свойство("ВерсияСтруктурыВерсий") + И ТипЗнч(Значения.ВерсияСтруктурыВерсий) = Тип("Строка") + И Значения.Свойство("ДляПользователей") + + И ТипЗнч(Значения.ДляПользователей) = Тип("Структура") + И Значения.ДляПользователей.Свойство("ВерсииПараметровШаблонов") + И ТипЗнч(Значения.ДляПользователей.ВерсииПараметровШаблонов) = Тип("Соответствие") + И Значения.ДляПользователей.Свойство("ОсновныеВариантыДоступа") + И ТипЗнч(Значения.ДляПользователей.ОсновныеВариантыДоступа) = Тип("Соответствие") + + И Значения.Свойство("ДляВнешнихПользователей") + И ТипЗнч(Значения.ДляВнешнихПользователей) = Тип("Структура") + И Значения.ДляВнешнихПользователей.Свойство("ВерсииПараметровШаблонов") + И ТипЗнч(Значения.ДляВнешнихПользователей.ВерсииПараметровШаблонов) = Тип("Соответствие") + И Значения.ДляВнешнихПользователей.Свойство("ОсновныеВариантыДоступа") + И ТипЗнч(Значения.ДляВнешнихПользователей.ОсновныеВариантыДоступа) = Тип("Соответствие") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеВерсийПараметровШаблонов, Значения); + КонецЕсли; + + Возврат ХранимыеВерсийПараметровШаблонов; + +КонецФункции + +// Для функций ХранимыеПараметрыОграниченияДоступа, СтруктураХранимыхВерсийПараметровШаблонов и +// процедуры ЗаполнитьПараметрыДляШаблонов. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыВерсий - см. ВерсияСтруктурыВерсийПараметровШаблонов +// * ДляПользователей - Структура: +// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов +// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// * ДляВнешнихПользователей - Структура: +// ** ВерсииПараметровШаблонов - см. НовыеВерсииПараметровШаблонов +// ** ОсновныеВариантыДоступа - см. НовыеОсновныеВариантыДоступа +// +Функция НоваяСтруктураХранимыхВерсийПараметровШаблонов() + + ДляПользователей = Новый Структура; + ДляПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + ДляПользователей.Вставить("ОсновныеВариантыДоступа", НовыеОсновныеВариантыДоступа()); + + ДляВнешнихПользователей = Новый Структура; + ДляВнешнихПользователей.Вставить("ВерсииПараметровШаблонов", НовыеВерсииПараметровШаблонов()); + ДляВнешнихПользователей.Вставить("ОсновныеВариантыДоступа", НовыеОсновныеВариантыДоступа()); + + ХранимыеПараметрыШаблонов = Новый Структура; + ХранимыеПараметрыШаблонов.Вставить("ВерсияСтруктурыВерсий", ВерсияСтруктурыВерсийПараметровШаблонов()); + ХранимыеПараметрыШаблонов.Вставить("ДляПользователей", ДляПользователей); + ХранимыеПараметрыШаблонов.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + + Возврат ХранимыеПараметрыШаблонов; + +КонецФункции + +// Для функций ХранимыеПараметрыОграниченияДоступа и +// НоваяСтруктураХранимыхВерсийПараметровШаблонов. +// +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - полное имя регистра. +// * Значение - Массив из см. НоваяВерсияПараметровШаблонов +// +Функция НовыеВерсииПараметровШаблонов() + + Возврат Новый Соответствие; + +КонецФункции + +// Для функции НовыеВерсииПараметровШаблонов и процедуры НастроитьПараметрыШаблонов. +// +// Возвращаемое значение: +// Структура: +// * ДатаСоздания - Дата - момент добавления новой версии. +// * Список - Строка - полное имя объекта метаданных. +// * ПоляСоединения - Строка - список полей, используемых в соединении. +// * ПоляШаблона - Строка - список полей, указанных в шаблоне #ДляРегистра. +// * Используется - Булево - признак того, что версия используется в шаблонах. +// * ВариантДоступа - Число - значение поля ВариантДоступа в регистрах КлючиДоступаКРегистрам, +// КлючиДоступаКРегистру*. +// +Функция НоваяВерсияПараметровШаблонов() + + ВерсияПараметров = Новый Структура; + ВерсияПараметров.Вставить("ДатаСоздания", '00010101'); + ВерсияПараметров.Вставить("Список", ""); + ВерсияПараметров.Вставить("ПоляСоединения", ""); + ВерсияПараметров.Вставить("ПоляШаблона", ""); + ВерсияПараметров.Вставить("Используется", Истина); + ВерсияПараметров.Вставить("ВариантДоступа", 0); + + Возврат ВерсияПараметров; + +КонецФункции + +// Для функции НоваяСтруктураХранимыхВерсийПараметровШаблонов. +// +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - полное имя регистра. +// * Значение - Массив из см. НовыйИспользуемыйВариантДоступа +// +Функция НовыеОсновныеВариантыДоступа() + + Возврат Новый Соответствие; + +КонецФункции + +// Для функции ЗаполнитьПараметрыДляШаблоновДляВидаПользователей. +// +// Возвращаемое значение: +// Структура: +// * ВариантДоступа - Число - значение поля ВариантДоступа +// в регистрах КлючиДоступаКРегистрам, КлючиДоступаКРегистру*, +// начиная с основного варианта доступа. +// * ПоляСоединения - Строка - имена полей соединения для варианта доступа через запятую. +// +Функция НовыйИспользуемыйВариантДоступа() + + Возврат Новый Структура("ВариантДоступа, ПоляСоединения"); + +КонецФункции + +// Для процедуры УстановитьВерсиюПараметров. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВидыОграниченийПравДляПользователей - Строка +// * ВидыОграниченийПравДляВнешнихПользователей - Строка +// +Функция СтруктураХранимыхПараметровОтчета(Значения) + + ХранимыеПараметрыОтчета = НоваяСтруктураХранимыхПараметровОтчета(); + ХранимыеПараметрыОтчета.ВерсияСтруктурыКэша = ""; + + Если ТипЗнч(Значения) = Тип("ФиксированнаяСтруктура") + И Значения.Свойство("ВерсияСтруктурыКэша") + И ТипЗнч(Значения.ВерсияСтруктурыКэша) = Тип("Строка") + И Значения.Свойство("ВидыОграниченийПравДляПользователей") + И ТипЗнч(Значения.ВидыОграниченийПравДляПользователей) = Тип("Строка") + И Значения.Свойство("ВидыОграниченийПравДляВнешнихПользователей") + И ТипЗнч(Значения.ВидыОграниченийПравДляВнешнихПользователей) = Тип("Строка") Тогда + + ЗаполнитьЗначенияСвойств(ХранимыеПараметрыОтчета, Значения); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ХранимыеПараметрыОтчета); + +КонецФункции + +// Для функций СтруктураХранимыхПараметровОтчета и ХранимыеПараметрыОграниченияДоступа. +// +// Возвращаемое значение: +// Структура: +// * ВерсияСтруктурыКэша - см. ВерсияСтруктурыКэша +// * ВидыОграниченийПравДляПользователей - Строка +// * ВидыОграниченийПравДляВнешнихПользователей - Строка +// +Функция НоваяСтруктураХранимыхПараметровОтчета() + + ХранимыеПараметрыОтчета = Новый Структура; + ХранимыеПараметрыОтчета.Вставить("ВерсияСтруктурыКэша", ВерсияСтруктурыКэша()); + ХранимыеПараметрыОтчета.Вставить("ВидыОграниченийПравДляПользователей", ""); + ХранимыеПараметрыОтчета.Вставить("ВидыОграниченийПравДляВнешнихПользователей", ""); + + Возврат ХранимыеПараметрыОтчета; + +КонецФункции + +// Для функции ХранимыеПараметрыОграниченияДоступа. +Функция ВидыОграниченийПравСтрокой(ВидыОграниченийПрав) + + Список = Новый СписокЗначений; + Для Каждого КлючИЗначение Из ВидыОграниченийПрав Цикл + Список.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + Список.СортироватьПоЗначению(); + ВидыОграниченийСтрокой = СтрСоединить(Список.ВыгрузитьЗначения(), Символы.ПС); + + Возврат ВидыОграниченийСтрокой; + +КонецФункции + +#КонецОбласти + +#Область ПараметрыОграниченияДоступаДляСпискаОтдельно + +// Основная функция области, возвращающая параметры ограничения доступа +// для вида пользователей списка без учета зависимости от других списков, +// как по ключам доступа, так и по наличию видов доступа Пользователи и ВнешниеПользователи. +// +// Возвращаемое значение: +// Структура: +// * Список - Строка - полное имя таблицы объекта метаданных. +// * ДляВнешнихПользователей - Булево - вид пользователей, для которых предназначены параметры. +// * Версия - Строка - хеш-сумма параметров ограничения доступа для отслеживания их изменения. +// * ВедущиеСписки - см. НовыеВедущиеСписки +// * ДоступЗапрещен - Булево - Истина, если текст ограничения "ГДЕ ЛОЖЬ", +// а также не указан для внешних пользователей. +// * ОграничениеОтключено - Булево - Истина, если текст ограничения не указан или указан, +// но ограничение отключено из-за отключения использования +// видов доступа, задействованных в нем. +// * ОграничениеЧтенияОтключено - Булево - Истина, если текст ограничения чтения не указан или указан, +// но ограничение отключено из-за отключения использования +// видов доступа, задействованных в нем. +// +// Поле владельца, когда возможно ограничение только по объекту-владельцу. +// * ПолеВладельца - см. НовоеПолеВладельца +// +// * ТребуетсяОграничениеПоВладельцу - Булево - признак оптимизации, указанный разработчиком +// рядом с текстом ограничения. +// * ИспользуетсяОграничениеПоВладельцу - Булево - признак использования оптимизации, +// вычисленный на втором проходе графа. +// * РассчитыватьПраваПользователей - Булево - признак расчета прав на ключи доступа для пользователей, +// а не для групп доступа, вычисленный на втором проходе графа. +// Имеет смысл только, когда признак +// ИспользуетсяОграничениеПоВладельцу = Ложь. +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево - признак того, что ведущий список должен записывать +// ключи для зависимых списков, которые не записывают +// своих ключей. Признак вычисляется на втором проходе графа. +// * БезОбновленияКлючейДоступаКОбъектам - Булево - когда Истина, запись связи объекта с ключом доступа +// пропускается так как тип списка не указан +// в определяемом типе ВладелецЗначенийКлючейДоступа. +// * БезОбновленияВсехКомбинацийЗначенийОпорныхПолей - Булево - когда Истина, запись связи строки регистра с ключом +// доступа пропускается, если тип значения опорного поля регистра не +// указан в определяемом типе ПолеРегистраКлючейДоступаКРегистрам +// или типе соответствующего поля отдельного регистра ключей. +// * ЧтениеРазрешеноДляВсехПользователей - Булево - признак, вычисленный на втором проходе графа. +// Когда ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина, +// тогда показывает наличие права Чтение в одной из ролей +// БазовыеПрава* или БазовыеПраваВнешнихПользователей*. +// * ИзменениеРазрешеноДляВсехПользователей - Булево - признак, вычисленный на втором проходе графа. +// Когда ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина, +// тогда показывает наличие права Изменение в одной из ролей +// БазовыеПрава* или БазовыеПраваВнешнихПользователей*. +// * ЕстьВедущиеКлючиДоступа - Булево - признак наличия ведущих ключей доступа в ограничении. +// * ЕстьВедущиеСпискиПоПравам - Булево - признак наличия ведущих списков по правам в ограничении. +// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево - признак наличия перечисленных функций в ограничении. +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие - типы владельцев настроек прав, используемые +// при расчете прав на ключи доступа (см. ПоТипамСсылок). +// * ИдентификаторТаблицыНастроекПрав - СправочникСсылка.ИдентификаторыОбъектовМетаданных - идентификатор +// списка, если для него используются отдельные настройки прав +// или пустой идентификатор. +// * ЕстьВладельцыНастроекПрав - Булево - признак наличия ограничения по владельцу настроек прав. +// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип - описание типов значений доступа, +// которые используются в ограничении доступа. +// * ВсеВидыОграниченийПрав - Соответствие - все виды ограничений прав без учета использования. +// * ПоляТаблицОбъекта - Массив из см. НовыеПоляТаблицыОбъекта +// * ИмяОтдельногоРегистраКлючей - Строка - для регистров. +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ВариантДоступа - Число - основной вариант доступа смотри также НовыеОсновныеВариантыДоступа. +// * СоставПолей - Число - число, описывающее реквизиты, используемые в ключе. +// * ЕстьОграничениеЧтения - Булево - установлено, если ограничение чтения отличается от "ГДЕ ИСТИНА". +// * ЕстьОграничениеИзменения - Булево - установлено, если ограничение изменения отличается от "ГДЕ ИСТИНА". +// * ЕстьОграничениеПоПользователям - Булево - установлено, если проверяются значения Пользователь +// или ГруппаПользователей или ВнешнийПользователь +// или ГруппаВнешнихПользователей для функций +// ЗначениеРазрешено или ЭтоАвторизованныйПользователь. +// * СтруктураРасчетаПраваЧтение - см. СтруктураРасчетаПрава +// * СтруктураРасчетаПраваИзменение - см. СтруктураРасчетаПрава +// * Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Функция ПараметрыОграниченияПоСтруктуреОграничения(Список, СтруктураОграничения, + ДляВнешнихПользователей, ОбщийКонтекст, ДополнительныйКонтекст) + + ВедущиеСписки = НовыеВедущиеСписки(); + + Результат = Новый Структура; + Результат.Вставить("Список", Список); + Результат.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Результат.Вставить("Версия", ""); + Результат.Вставить("ВедущиеСписки", ВедущиеСписки); + Результат.Вставить("ДоступЗапрещен", ДляВнешнихПользователей); + Результат.Вставить("ОграничениеОтключено", Не ДляВнешнихПользователей); + Результат.Вставить("ОграничениеЧтенияОтключено", Не ДляВнешнихПользователей); + Результат.Вставить("ПолеВладельца"); + Результат.Вставить("ТребуетсяОграничениеПоВладельцу", Ложь); + Результат.Вставить("ИспользуетсяОграничениеПоВладельцу", Ложь); + Результат.Вставить("РассчитыватьПраваПользователей", Ложь); + Результат.Вставить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Ложь); + Результат.Вставить("БезОбновленияКлючейДоступаКОбъектам", Ложь); + Результат.Вставить("БезОбновленияВсехКомбинацийЗначенийОпорныхПолей", Ложь); + Результат.Вставить("ЧтениеРазрешеноДляВсехПользователей", Ложь); + Результат.Вставить("ИзменениеРазрешеноДляВсехПользователей", Ложь); + Результат.Вставить("ЕстьВедущиеКлючиДоступа", Ложь); + Результат.Вставить("ЕстьВедущиеСпискиПоПравам", Ложь); + Результат.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступна", Ложь); + Результат.Вставить("ТипыВладельцевНастроекПрав", ОбщийКонтекст.ТипыВладельцевНастроекПрав); + Результат.Вставить("ИдентификаторТаблицыНастроекПрав", Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка()); + Результат.Вставить("ЕстьВладельцыНастроекПрав", Ложь); + Результат.Вставить("ИспользуемыеТипыЗначенийДоступа", Новый Массив); + Результат.Вставить("ВсеВидыОграниченийПрав", Новый Соответствие); + Результат.Вставить("ПоляТаблицОбъекта", Новый Массив); + Результат.Вставить("ИмяОтдельногоРегистраКлючей", ""); + Результат.Вставить("ОпорныеПоля"); + Результат.Вставить("ВариантДоступа"); + Результат.Вставить("СоставПолей"); + Результат.Вставить("ЕстьОграничениеЧтения", Ложь); + Результат.Вставить("ЕстьОграничениеИзменения", Ложь); + Результат.Вставить("ЕстьОграничениеПоПользователям", Ложь); + Результат.Вставить("СтруктураРасчетаПраваЧтение", СтруктураРасчетаПрава()); + Результат.Вставить("СтруктураРасчетаПраваИзменение", СтруктураРасчетаПрава()); + + ИмяКоллекцииТипа = ""; + Результат.Вставить("ЭтоСсылочныйТип", ?(ЗначениеЗаполнено(Список), + ЭтоСсылочныйТипТаблицы(Список, ИмяКоллекцииТипа), Ложь)); + + Результат.Вставить("СписокСДатой", + ИмяКоллекцииТипа = "Документы" + Или ИмяКоллекцииТипа = "БизнесПроцессы" + Или ИмяКоллекцииТипа = "Задачи"); + + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Список); + + Если Результат.ЭтоСсылочныйТип И ОбъектМетаданных <> Неопределено Тогда + ТипПоля = Метаданные.РегистрыСведений.КлючиДоступаКОбъектам.Измерения.Объект.Тип; + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + ТипСсылки = Тип(ИмяТипаСсылки(Список, ТипыТаблицПоИменам)); + Если Не ТипПоля.СодержитТип(ТипСсылки) Тогда + Результат.БезОбновленияКлючейДоступаКОбъектам = Истина; + КонецЕсли; + КонецЕсли; + + Если ИмяКоллекцииТипа = "РегистрыСведений" Тогда + Результат.Вставить("СписокСПериодом", ?(ОбъектМетаданных = Неопределено, Ложь, + ОбъектМетаданных.ПериодичностьРегистраСведений + <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический)); + Иначе + Результат.Вставить("СписокСПериодом", + ИмяКоллекцииТипа = "РегистрыНакопления" + Или ИмяКоллекцииТипа = "РегистрыБухгалтерии" + Или ИмяКоллекцииТипа = "РегистрыРасчета"); + КонецЕсли; + + Контекст = КонтекстПараметровПоСтруктуреОграничения(); + Контекст.Вставить("СтрокаСвойствВерсии", ""); + Результат.Вставить("Контекст", Контекст); + + Для Каждого КлючИЗначение Из ОбщийКонтекст Цикл + Контекст.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + Для Каждого КлючИЗначение Из ДополнительныйКонтекст Цикл + Контекст.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + + Контекст.Вставить("Список", Список); + Контекст.Вставить("ДляВнешнихПользователей", ДляВнешнихПользователей); + Контекст.Вставить("ЭтоСсылочныйТип", Результат.ЭтоСсылочныйТип); + Контекст.Вставить("СписокСДатой", Результат.СписокСДатой); + Контекст.Вставить("СписокСПериодом", Результат.СписокСПериодом); + Контекст.Вставить("ИмяКоллекцииТипа", ИмяКоллекцииТипа); + Контекст.Вставить("СвойстваВерсии", Новый Массив); + Контекст.Вставить("ВедущиеРоли", Новый Соответствие); + + ДобавитьСвойствоВерсии(Контекст, Контекст, "Список"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ДляВнешнихПользователей"); + + ОписаниеОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список); + Если ОписаниеОграничения = Неопределено Тогда + ОписаниеОграничения = Новый Структура("Текст", ""); + КонецЕсли; + ДобавитьСвойствоВерсии(Контекст, ОписаниеОграничения, "Текст"); + + ДобавитьСвойствоВерсии(Контекст, Контекст, "ЭтоСсылочныйТип"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "СписокСДатой"); + + // Поля таблиц требуются только для ссылочных объектов. + Контекст.Вставить("ПоляТаблицОбъекта", НовоеОписаниеПолейТаблицОбъекта(Результат)); + + // Опорные поля не требуются для ссылочных типов данных (всегда Ссылка). + ЗаполнитьНовоеОписаниеОпорныхПолей(Результат, Контекст); + + Контекст.Вставить("БезОбъектаМетаданных", ОбъектМетаданных = Неопределено); + + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено Тогда + Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); + Результат.РассчитыватьПраваПользователей = Свойства.РассчитыватьПраваПользователей; + Результат.ИспользуетсяОграничениеПоВладельцу = Свойства.ПолеВладельца <> Неопределено + И Не Свойства.ПолеВладельца.Отключено; + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей.Получить(Список) <> Неопределено Тогда + Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа = Истина; + Результат.ЧтениеРазрешеноДляВсехПользователей = + ПравоРазрешеноДляВсехПользователей("Чтение", ОбъектМетаданных, ДляВнешнихПользователей); + Результат.ИзменениеРазрешеноДляВсехПользователей = + ПравоРазрешеноДляВсехПользователей("Изменение", ОбъектМетаданных, ДляВнешнихПользователей); + КонецЕсли; + КонецЕсли; + Контекст.Вставить("ИспользуетсяОграничениеПоВладельцу", Результат.ИспользуетсяОграничениеПоВладельцу); + Контекст.Вставить("РассчитыватьПраваПользователей", Результат.РассчитыватьПраваПользователей); + Контекст.Вставить("ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа", Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа); + Контекст.Вставить("ЧтениеРазрешеноДляВсехПользователей", Результат.ЧтениеРазрешеноДляВсехПользователей); + Контекст.Вставить("ИзменениеРазрешеноДляВсехПользователей", Результат.ИзменениеРазрешеноДляВсехПользователей); + + Если СтруктураОграничения = Неопределено Тогда + Если Не Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа + Или Результат.ДоступЗапрещен + Или Контекст.БезОбъектаМетаданных Тогда + Возврат Результат; + КонецЕсли; + СтруктураОграничения = РассчитаннаяСтруктураОграничения(Список, + "РазрешитьЧтениеИзменение ГДЕ ИСТИНА", Истина, ДляВнешнихПользователей); + КонецЕсли; + + Контекст.Вставить("СтруктураОграничения", СтруктураОграничения); + Контекст.Вставить("ВедущиеСпискиПоЗначениямПолей", ОписаниеВедущихСписковПоЗначениямПолей()); + Контекст.Вставить("ВедущиеСпискиПоКлючамДоступа", ОписаниеВедущихСписковПоПолюСсылка()); + Контекст.Вставить("ВедущиеСпискиПоЗначениямСГруппами", ОписаниеВедущихСписковПоПолюСсылка()); + Контекст.Вставить("ЕстьПроверкаАвторизованногоПользователя", Ложь); + Контекст.Вставить("НеиспользуемыеТипыЗначенийДоступа", Новый Массив); + Контекст.Вставить("ВсеВидыОграниченийПрав", Результат.ВсеВидыОграниченийПрав); + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Результат.ИмяОтдельногоРегистраКлючей = Контекст.ИмяОтдельногоРегистраКлючей; + КонецЕсли; + + ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, Ложь); + ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения(Результат, Контекст); + + ЗаполнитьСвойстваПолей(Контекст); + + Результат.ЕстьФункцияПравоДоступаИлиРольДоступна = Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна; + + Если ДляВнешнихПользователей И Не ОбщийКонтекст.ВнешниеПользователиВключены + Или ЭтоБезусловноеОграничение(Контекст, Результат) Тогда + + Результат.ДоступЗапрещен = Истина; + Результат.Версия = " "; + Возврат Результат; + КонецЕсли; + + Результат.ДоступЗапрещен = Ложь; + Результат.ОграничениеОтключено = Истина; + Результат.ОграничениеЧтенияОтключено = Истина; + + ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, Истина); + ЗаполнитьОграничениеПоОбъектуВладельцуПослеУпрощения(Результат, Контекст); + ЗаполнитьНаличиеВедущихКлючейИСписковИВладельцевНастроекПрав(Результат, Контекст); + УдалитьПоляНеиспользуемыхВидовДоступа(Результат, Контекст); + ЗаполнитьНаличиеОграниченияПоВидуДоступаПользователи(Результат, Контекст); + ЗаполнитьНаличиеОграниченияЧтения(Результат, Контекст); + + Контекст.Вставить("ЕстьОграничениеПоПользователям", Результат.ЕстьОграничениеПоПользователям); + + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Неопределено Тогда + Результат.РассчитыватьПраваПользователей = Результат.ЕстьОграничениеПоПользователям; + Результат.ИспользуетсяОграничениеПоВладельцу = Результат.ПолеВладельца <> Неопределено + И Не Результат.ПолеВладельца.Отключено; + + Контекст.Вставить("ИспользуетсяОграничениеПоВладельцу", Результат.ИспользуетсяОграничениеПоВладельцу); + Контекст.Вставить("РассчитыватьПраваПользователей", Результат.РассчитыватьПраваПользователей); + КонецЕсли; + ДобавитьСвойствоВерсии(Контекст, Контекст, "ИспользуетсяОграничениеПоВладельцу"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "РассчитыватьПраваПользователей"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ЧтениеРазрешеноДляВсехПользователей"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "ИзменениеРазрешеноДляВсехПользователей"); + + Контекст.Вставить("ГруппыПолей"); + Контекст.Вставить("ПсевдонимыТабличныхЧастейОбъекта"); + Контекст.Вставить("ГруппыДополнительныхТаблиц"); + Контекст.Вставить("КоличествоТабличныхЧастейКлюча"); + + ЗаполнитьГруппыПолейИДополнительныхТаблиц(Контекст); + + Результат.СоставПолей = Контекст.СоставПолей; + + Если Результат.Контекст.СвойстваПолей.Количество() = 0 + И (Не Результат.ЭтоСсылочныйТип + Или Не Результат.ЕстьФункцияПравоДоступаИлиРольДоступна) Тогда // Ограничение отключено. + + Если Результат.ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа Тогда + НастроитьСозданиеКлючаДоступаДляЗависимыхСписковБезКлючей(Результат); + Если Контекст.СпискиСОграничением.Получить(Результат.Список) = Неопределено Тогда + Результат.Версия = " "; + Иначе + Результат.Версия = " "; + КонецЕсли; + Иначе + Результат.Версия = " "; + КонецЕсли; + КонецЕсли; + + Если Результат.Версия <> " " И Результат.БезОбновленияКлючейДоступаКОбъектам Тогда + ДобавитьСвойствоВерсии(Контекст, Результат, "БезОбновленияКлючейДоступаКОбъектам"); + КонецЕсли; + Если Результат.Версия <> " " + И Контекст.ИмяКоллекцииТипа <> "ЖурналыДокументов" + И УправлениеДоступомСлужебныйПовтИсп.ТаблицыВПодпискахПроверитьДоступ().Получить(Список) = Неопределено Тогда + ДобавитьЭлементВерсии(Контекст, "ОбъектВПодпискахПроверитьДоступ", Ложь) + КонецЕсли; + + Если Результат.Версия <> "" Тогда + Возврат Результат; + КонецЕсли; + + ЗаполнитьНедостающиеТипыОпорныхПолей(Результат, Контекст); + + Результат.ОграничениеОтключено = Ложь; + + Контекст.Вставить("ИмяПрава", "Чтение"); + ЗаполнитьСтруктуруРасчетаПрава(Результат.СтруктураРасчетаПраваЧтение, + Контекст.СтруктураОграничения.ОграничениеЧтения, Контекст); + + Контекст.Вставить("ИмяПрава", "Изменение"); + ЗаполнитьСтруктуруРасчетаПрава(Результат.СтруктураРасчетаПраваИзменение, + Контекст.СтруктураОграничения.ОграничениеИзменения, Контекст); + + Контекст.Удалить("ИмяПрава"); + ДобавитьСвойствоВерсииВедущиеРоли(Контекст); + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + Контекст.ВедущиеСпискиПоЗначениямПолей = ОписаниеВедущихСписковПоЗначениямПолей(); + КонецЕсли; + ВедущиеСписки.ПоЗначениямПолей = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля; + ВедущиеСписки.ПоКлючамДоступа = Контекст.ВедущиеСпискиПоКлючамДоступа.Списки; + ВедущиеСписки.ПоЗначениямСГруппами = Контекст.ВедущиеСпискиПоЗначениямСГруппами.Списки; + + ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.SHA256); + СтрокаСвойствВерсии = СтрСоединить(Контекст.СвойстваВерсии, Символы.ПС); + Контекст.СтрокаСвойствВерсии = СтрокаСвойствВерсии; + ХешированиеДанных.Добавить(СтрокаСвойствВерсии); + Результат.Версия = Base64Строка(ХешированиеДанных.ХешСумма); + + Возврат Результат; + +КонецФункции + +// Списки с полями от которых зависит ограничение доступа. +// +// Возвращаемое значение: +// Структура: +// * ПоЗначениямПолей - Соответствие - списки с полями, от которых зависит ограничение доступа +// (для регистрации заданий обновления). +// * ПоКлючамДоступа - Соответствие - списки от ключей доступа которых зависит ограничение доступа +// (для установки параметров сеанса и регистрации заданий обновления). +// * ПоЗначениямСГруппами - Соответствие - списки значений доступа с группами, от которых зависит +// ограничение доступа (для регистрации заданий обновления). +// +Функция НовыеВедущиеСписки() + + ВедущиеСписки = Новый Структура; + ВедущиеСписки.Вставить("ПоЗначениямПолей", Новый Соответствие); + ВедущиеСписки.Вставить("ПоКлючамДоступа", Новый Соответствие); + ВедущиеСписки.Вставить("ПоЗначениямСГруппами", Новый Соответствие); + + Возврат ВедущиеСписки; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * СтрокаСвойствВерсии - Строка +// * Список - Строка +// * ДляВнешнихПользователей - Булево +// * ЭтоСсылочныйТип - Булево +// * СписокСДатой - Булево +// * СписокСПериодом - Булево +// * ИмяКоллекцииТипа - Строка +// * СвойстваВерсии - Массив из Строка +// * ПоляТаблицОбъекта - см. НовоеОписаниеПолейТаблицОбъекта +// * ОпорныеПоля - см. НовоеОписаниеОпорныхПолей +// * ВариантДоступа - Число - основной вариант доступа смотри также НовыеОсновныеВариантыДоступа. +// * ИспользуетсяОграничениеПоВладельцу - Булево +// * РассчитыватьПраваПользователей - Булево +// * ЕстьЗависимыеСпискиБезЗаписиКлючейДоступа - Булево +// * ЧтениеРазрешеноДляВсехПользователей - Булево +// * ИзменениеРазрешеноДляВсехПользователей - Булево +// * БезОбъектаМетаданных - Булево +// * СтруктураОграничения - см. СтруктураОграничения +// * ИсходнаяСтруктураОграничения - см. СтруктураОграничения +// * ВедущиеСпискиПоЗначениямПолей - см. ОписаниеВедущихСписковПоЗначениямПолей +// * ВедущиеСпискиПоКлючамДоступа - см. ОписаниеВедущихСписковПоПолюСсылка +// * ВедущиеСпискиПоЗначениямСГруппами - см. ОписаниеВедущихСписковПоПолюСсылка +// * ЕстьПроверкаАвторизованногоПользователя - Булево +// * ЕстьФункцияПравоДоступаИлиРольДоступна - Булево +// * ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения - Булево +// * НеиспользуемыеТипыЗначенийДоступа - Массив из Тип +// * ВсеВидыОграниченийПрав - Соответствие +// * ЕстьОграничениеПоПользователям - Булево +// * ИспользуетсяОграничениеПоВладельцу - Булево +// * РассчитыватьПраваПользователей - Булево +// * СвойстваВсехПолей - Соответствие из КлючИЗначение: +// ** Ключ - см. ОписаниеУзла +// ** Значение - см. СвойстваПоля +// * ОставшиесяПоляПослеУпрощения - Соответствие из КлючИЗначение: +// ** Ключ - см. ОписаниеУзла +// ** Значение - Массив из см. ОписаниеУзла +// * ПоляКлючаДоступаПослеУпрощения - Массив из см. НовоеПолеКлючаДоступа +// * СвойстваПолейКлючаДоступа - Соответствие из КлючИЗначение: +// ** Ключ - см. ОписаниеУзла +// ** Значение - см. СвойстваПоля +// * ГруппыПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя группы полей (Шапка?, ТабличнаяЧасть?) +// ** Значение - Массив из см. СвойстваПоля +// * ПсевдонимыТабличныхЧастейОбъекта - Соответствие из КлючИЗначение: +// ** Ключ - Число - номер табличной части ключа +// ** Значение - Строка - псевдоним таблицы +// * ГруппыДополнительныхТаблиц - см. ГруппыДополнительныхТаблиц +// * КоличествоТабличныхЧастейКлюча - Число +// * ПоляУсловияСоединенияДополнительныхТаблиц - Массив из Структура: +// ** УзелПоле - см. ОписаниеУзла +// ** ПсевдонимТаблицыУсловия - Строка +// * ИмяПрава - Строка +// * ТребуемыеРеквизитыТабличныхЧастейКлюча - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя таблицы ключа (ИмяГруппыПолейКлючаДоступа) +// ** Значение - Массив из Строка - имя реквизита таблицы ключа (ИмяРеквизитаГруппыПолейКлючаДоступа) +// * СтруктураРасчетаПраваСвойстваВерсии - Массив из Строка +// * ВедущиеРоли - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя роли +// ** Значение - Булево - значение Истина. +// +// Свойства, скопированные от ОбщийКонтекст: +// * СвойстваВидовДоступа - см. СвойстваВидовДоступа +// * ТипыПользователя - Массив из Тип +// * ТипыВладельцевНастроекПрав - ФиксированноеСоответствие +// * ОтдельныеТаблицыНастроекПрав - ФиксированноеСоответствие +// * ИспользуемыеТипыЗначений - см. ИспользуемыеТипыЗначений +// * СпискиСОграничением - см. УправлениеДоступомСлужебныйПовтИсп.СпискиСОграничением +// * ВнешниеПользователиВключены - Булево +// +// Свойства, скопированные от ДополнительныйКонтекст: +// * ОписанияОграничений - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. СокращенноеОписаниеОграничения +// * СвойстваОграниченияСписков - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - см. НовыеСвойстваОграниченияСписка +// * СпискиСОграничениемПоВладельцу - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - значение ПоВладельцу, кроме Неопределено. +// * СпискиСОтключеннымОграничением - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСОтключеннымОграничениемЧтения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// * СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя списка +// ** Значение - Булево - Истина +// +Функция КонтекстПараметровПоСтруктуреОграничения() + + Возврат Новый Структура; + +КонецФункции + +// Структура ограничения, приведенную к формату размещения значений в ключах доступа. +// +// Возвращаемое значение: +// Структура: +// * Узел - Строка - одна из строк "Поле", "Константа", "И", "Или", "Не", "Выбор", +// "ЗначениеРазрешено", "ЭтоАвторизованныйПользователь", +// "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено", +// "ЧтениеСпискаРазрешено", "ИзменениеСпискаРазрешено", +// "ДляВсехСтрок", "ДляОднойИзСтрок". +// +// Свойства узла Поле. +// * Таблица - Строка - таблица ключа доступа (Шапка?, ТабличнаяЧасть?). +// * Реквизит - Строка - имя реквизита таблицы ключа доступа (Реквизит?). +// * ПроверкаЕстьNull - Булево - Истина (необязательное свойство). +// +// Свойства узла Константа. +// * Значение - Булево +// - Число +// - Строка +// - Неопределено - Ложь, Истина, произвольное +// целое число до 16 разрядов или произвольная строка до 150 символов. +// +// Свойства узлов И, Или. +// * Аргументы - Массив из см. СтруктураРасчетаПрава +// +// Свойства узла Не. +// * Аргумент - см. СтруктураРасчетаПрава +// +// * Узел - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла Выбор (Иначе может быть Неопределено). +// * Иначе - см. СтруктураРасчетаПрава +// * Когда - Массив из Структура: +// ** Условие - см. СтруктураРасчетаПрава +// ** Значение - см. СтруктураРасчетаПрава +// +// * Узел - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узлов ЗначениеРазрешено, ЭтоАвторизованныйПользователь, +// ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, +// ЧтениеСпискаРазрешено, ИзменениеСпискаРазрешено. +// * Поле - см. СтруктураРасчетаПрава +// * УточненияСравнения - Соответствие из КлючИЗначение: +// ** Ключ - Строка +// - Тип - уточняемое значение "Неопределено", "Null", "ПустаяСсылка", +// "Отключено", Тип (Ссылка, Число, Даты, Булево). +// ** Значение - Строка - результат "Ложь", "Истина". +// +// Свойства узлов ДляВсехСтрок, ДляОднойИзСтрок. +// * Аргумент - см. СтруктураРасчетаПрава +// +Функция СтруктураРасчетаПрава() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура НастроитьСозданиеКлючаДоступаДляЗависимыхСписковБезКлючей(Результат) + + Если Не Результат.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + Если Результат.СоставПолей <> 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Для списка %1 некорректно рассчиталось поле %2. + |Указано значение %3, ожидалось значение 0.'"), + Результат.Список, "СоставПолей", Формат(Результат.СоставПолей, "ЧН=0; ЧГ=")); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Результат.ЕстьОграничениеЧтения = Истина; + Результат.ЕстьОграничениеИзменения = Истина; + + Результат.ЕстьФункцияПравоДоступаИлиРольДоступна = Истина; + + СтруктураРасчетаПраваЧтение = Новый Структура; + СтруктураРасчетаПраваЧтение.Вставить("Узел", "ПравоДоступа"); + СтруктураРасчетаПраваЧтение.Вставить("ИмяПрава", "Чтение"); + СтруктураРасчетаПраваЧтение.Вставить("ПолноеИмяОбъектаМетаданных", Результат.Список); + СтруктураРасчетаПраваЧтение.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + Результат.СтруктураРасчетаПраваЧтение = СтруктураРасчетаПраваЧтение; + + СтруктураРасчетаПраваИзменение = Новый Структура; + СтруктураРасчетаПраваИзменение.Вставить("Узел", "ПравоДоступа"); + СтруктураРасчетаПраваИзменение.Вставить("ИмяПрава", "Изменение"); + СтруктураРасчетаПраваИзменение.Вставить("ПолноеИмяОбъектаМетаданных", Результат.Список); + СтруктураРасчетаПраваИзменение.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + Результат.СтруктураРасчетаПраваИзменение = СтруктураРасчетаПраваИзменение; + +КонецПроцедуры + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Функция ПравоРазрешеноДляВсехПользователей(ИмяПрава, ОбъектМетаданных, ДляВнешнихПользователей) + + Если ОбъектМетаданных = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ИменаРолейБазовыеПрава = УправлениеДоступомСлужебныйПовтИсп.ИменаРолейБазовыеПрава(ДляВнешнихПользователей); + МетаданныеРоли = Метаданные.Роли; + + Для Каждого ИмяРоли Из ИменаРолейБазовыеПрава Цикл + Если ПравоДоступа(ИмяПрава, ОбъектМетаданных, МетаданныеРоли[ИмяРоли]) Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура ДобавитьСвойствоВерсииВедущиеРоли(Контекст) + + Если Не ЗначениеЗаполнено(Контекст.ВедущиеРоли) Тогда + Возврат; + КонецЕсли; + + СписокЗначений = Новый СписокЗначений; + Для Каждого КлючИЗначение Из Контекст.ВедущиеРоли Цикл + СписокЗначений.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + СписокЗначений.СортироватьПоПредставлению(); + + ДобавитьЭлементВерсии(Контекст, "ВедущиеРоли", СписокЗначений.ВыгрузитьЗначения()); + +КонецПроцедуры + +// Для процедуры УдалитьПоляНеиспользуемыхВидовДоступа и функции ГруппыДополнительныхТаблиц. +Процедура ДобавитьСвойстваВерсии(Контекст, Структура, ИменаПолей = "") Экспорт + + Если ЗначениеЗаполнено(ИменаПолей) Тогда + СохраняемаяСтруктура = Новый Структура(ИменаПолей); + ЗаполнитьЗначенияСвойств(СохраняемаяСтруктура, Структура); + Иначе + СохраняемаяСтруктура = Структура; + КонецЕсли; + + СписокЗначений = Новый СписокЗначений; + Для Каждого КлючИЗначение Из СохраняемаяСтруктура Цикл + СписокЗначений.Добавить(КлючИЗначение.Значение, КлючИЗначение.Ключ) + КонецЦикла; + СписокЗначений.СортироватьПоПредставлению(); + + Для Каждого ЭлементСписка Из СписокЗначений Цикл + ДобавитьЭлементВерсии(Контекст, ЭлементСписка.Представление, ЭлементСписка.Значение); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура ДобавитьСвойствоВерсии(Контекст, Структура, ИмяПоля) + + ДобавитьЭлементВерсии(Контекст, ИмяПоля, Структура[ИмяПоля]); + +КонецПроцедуры + +// Для процедур ДобавитьСвойстваВерсии, ДобавитьСвойствоВерсии. +Процедура ДобавитьЭлементВерсии(Контекст, ИмяПоля, Значение) Экспорт + + Если ТипЗнч(Значение) = Тип("Строка") Тогда + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + Значение); + + ИначеЕсли ТипЗнч(Значение) = Тип("Число") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + Формат(Значение, "ЧГ=")); + + ИначеЕсли ТипЗнч(Значение) = Тип("Булево") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + ?(Значение, "Да", "Нет")); + + ИначеЕсли ТипЗнч(Значение) = Тип("Неопределено") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + "Неопределено"); + + ИначеЕсли ТипЗнч(Значение) = Тип("ФиксированныйМассив") Тогда + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + СтрокаДанныхДляХеширования(Новый Массив(Значение))); + + ИначеЕсли ТипЗнч(Значение) = Тип("ОписаниеТипов") + Или ТипЗнч(Значение) = Тип("Тип") + Или ТипЗнч(Значение) = Тип("Массив") Тогда + + Контекст.СвойстваВерсии.Добавить(ИмяПоля + " = " + СтрокаДанныхДляХеширования(Значение)); + Иначе + ТекстОшибки = НСтр("ru = 'Некорректный тип данных для версии ограничения доступа.'"); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения и формы ОбновлениеДоступаРучноеУправление. +// +// Возвращаемое значение: +// Булево +// +Функция ЭтоСсылочныйТипТаблицы(ПолноеИмя, ИмяКоллекцииТипа = "") Экспорт + + СинтаксисЯзыка = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка(); + СоставИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + + ТипТаблицы = СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0])); + Если ТипТаблицы = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ИмяКоллекцииТипа = ТипТаблицы.ИмяКоллекции; + + Возврат ТипТаблицы.ЭтоСсылочныйТип; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПолноеИмяТаблицы - Строка +// * ТабличнаяЧасть - Строка +// * Поля - Массив из Строка - с полем Ссылка +// * СписокПолей - Строка - без поля Ссылка +// * ТаблицаСПолями - ХранилищеЗначения - с объектом ТаблицаЗначений +// с типизированными полями (включая поле Ссылка). +// +Функция НовыеПоляТаблицыОбъекта() + + ПоляТаблицы = Новый Структура; + ПоляТаблицы.Вставить("ПолноеИмяТаблицы", ""); + ПоляТаблицы.Вставить("ТабличнаяЧасть", ""); + ПоляТаблицы.Вставить("Поля", Новый Массив); + ПоляТаблицы.Вставить("СписокПолей", ""); + ПоляТаблицы.Вставить("ТаблицаСПолями", Новый ХранилищеЗначения(Новый ТаблицаЗначений)); + + Возврат ПоляТаблицы; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Результат - Массив из см. НовыеПоляТаблицыОбъекта +// * Состав - Структура: +// ** Ключ - Строка - полное имя таблицы объекта. +// ** Значение - Структура: +// *** Ключ - Строка - имя поля. +// *** Значение - Структура: +// **** Тип - ОписаниеТипов - типы поля. +// **** Использование - Булево - использование поля. +// * ПоСвойствамПолей - Соответствие из КлючИЗначение: +// ** Ключ - см. НовыеСвойстваПоля +// ** Значение - Структура: +// *** Таблица - Строка - полное имя таблицы объекта. +// *** Поле - Строка - имя поля. +// * ПоДополнительнымТаблицам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - дополнительная таблица +// ** Значение - Структура: +// *** Ключ - Строка - полное имя таблицы объекта. +// *** Значение - Массив из Строка - имя поля. +// +Функция НовоеОписаниеПолейТаблицОбъекта(Результат) + + Возврат Новый Структура("Результат, Состав", Результат.ПоляТаблицОбъекта, Новый Структура); + +КонецФункции + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНовоеОписаниеОпорныхПолей(Результат, Контекст) + + ОпорныеПоля = НовоеОписаниеОпорныхПолей(); + Контекст.Вставить("ОпорныеПоля", ОпорныеПоля); + Контекст.Вставить("ВариантДоступа", Неопределено); + + Если Контекст.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + Если Контекст.Свойство("ОсновныеВариантыДоступа") Тогда + ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); + Если ИспользуемыеВариантыДоступа <> Неопределено Тогда + Результат.ВариантДоступа = ИспользуемыеВариантыДоступа[0].ВариантДоступа; + КонецЕсли; + Контекст.Вставить("ВариантДоступа", Результат.ВариантДоступа); + КонецЕсли; + + Если СтрРазделить(Контекст.Список, ".").Количество() > 1 Тогда + ИмяОтдельногоРегистраКлючей = "КлючиДоступаКРегистру" + СтрРазделить(Контекст.Список, ".")[1]; + Если Метаданные.РегистрыСведений.Найти(ИмяОтдельногоРегистраКлючей) = Неопределено Тогда + ИмяОтдельногоРегистраКлючей = ""; + КонецЕсли; + Иначе + ИмяОтдельногоРегистраКлючей = ""; + КонецЕсли; + Контекст.Вставить("ИмяОтдельногоРегистраКлючей", ИмяОтдельногоРегистраКлючей); + + ОпорныеПоля.МаксимальноеКоличество = + УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяОтдельногоРегистраКлючей); + + ОпорныеПоля.МаксимальноДопустимоеКоличество = + УправлениеДоступомСлужебныйПовтИсп.МаксимальноеКоличествоОпорныхПолейРегистра(); + + Если ОпорныеПоля.МаксимальноеКоличество > ОпорныеПоля.МаксимальноДопустимоеКоличество Тогда + // Превышение количества опорных полей в отдельном регистре. + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Количество опорных полей в регистре сведений %1 + |превышает максимально допустимое количество: %2'"), + ?(ИмяОтдельногоРегистраКлючей = "", "КлючиДоступаКРегистрам", ИмяОтдельногоРегистраКлючей), + ОпорныеПоля.МаксимальноДопустимоеКоличество); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, ОпорныеПоля, "МаксимальноеКоличество"); + + Результат.ОпорныеПоля = НовоеОписаниеОпорныхПолей(); + ЗаполнитьЗначенияСвойств(Результат.ОпорныеПоля, Контекст.ОпорныеПоля); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Все - Массив +// * ТипыВсех - Массив из ХранилищеЗначения - содержит тип ОписаниеТипов +// * Используемые - Массив +// * ТипыИспользуемых - Массив из ХранилищеЗначения - содержит тип ОписаниеТипов +// * МаксимальноеКоличество - Число +// * МаксимальноДопустимоеКоличество - Число +// +// * Список - СписокЗначений +// * ТипыПоИменамПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя опорного поля +// ** Значение - ОписаниеТипов - типы опорного поля +// * ПоСвойствамПолей - Соответствие из КлючИЗначение: +// ** Ключ - см. НовыеСвойстваПоля +// ** Значение - Строка - имя опорного поля +// * ПоДополнительнымТаблицам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - дополнительная таблица +// ** Значение - Массив из Строка - имена опорных полей +// * НедостающиеТипы - Массив из Строка - полные имена типов +// * ПоляНедостающихТипов - Массив из Строка - имена полей регистра ключей +// +Функция НовоеОписаниеОпорныхПолей() + + ОпорныеПоля = Новый Структура; + ОпорныеПоля.Вставить("Все", Новый Массив); + ОпорныеПоля.Вставить("ТипыВсех", Новый Массив); + ОпорныеПоля.Вставить("Используемые", Новый Массив); + ОпорныеПоля.Вставить("ТипыИспользуемых", Новый Массив); + ОпорныеПоля.Вставить("МаксимальноеКоличество", 0); + ОпорныеПоля.Вставить("МаксимальноДопустимоеКоличество", 0); + + Возврат ОпорныеПоля; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// +Функция ЭтоБезусловноеОграничение(Контекст, Результат) + + СтруктураОграничения = Контекст.СтруктураОграничения; + + Возврат ЗначениеЗаполнено(СтруктураОграничения.ОграничениеЧтения) + И СтруктураОграничения.ОграничениеЧтения.Узел = "Константа" + И СтруктураОграничения.ОграничениеЧтения.Значение = Ложь; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеОграниченияПоПравам(Контекст, Результат, ПослеУпрощения) + + СтруктураОграничения = Контекст.СтруктураОграничения; + + Результат.ЕстьОграничениеЧтения = + ЗначениеЗаполнено(СтруктураОграничения.ОграничениеЧтения) + И ( СтруктураОграничения.ОграничениеЧтения.Узел <> "Константа" + Или СтруктураОграничения.ОграничениеЧтения.Значение <> Истина); + + Результат.ЕстьОграничениеИзменения = + ЗначениеЗаполнено(СтруктураОграничения.ОграничениеИзменения) + И ( СтруктураОграничения.ОграничениеИзменения.Узел <> "Константа" + Или СтруктураОграничения.ОграничениеИзменения.Значение <> Истина); + + Если ПослеУпрощения Тогда + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеЧтения"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеИзменения"); + КонецЕсли; + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения(Результат, Контекст) + + НастройкаПоВладельцу = Контекст.СпискиСОграничениемПоВладельцу.Получить(Контекст.Список); + ПолеВладельца = НовоеПолеВладельца(); + + ТребуетсяОграничениеПоВладельцу = Ложь; + Если ТипЗнч(НастройкаПоВладельцу) = Тип("Булево") Тогда + ТребуетсяОграничениеПоВладельцу = НастройкаПоВладельцу; + КонецЕсли; + Результат.ТребуетсяОграничениеПоВладельцу = ТребуетсяОграничениеПоВладельцу; + + ОграничениеЧтения = Контекст.СтруктураОграничения.ОграничениеЧтения; + ОграничениеИзменения = Контекст.СтруктураОграничения.ОграничениеИзменения; + + ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, + "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); + + Если Результат.ЕстьОграничениеЧтения Тогда + + Если ТребуетсяОграничениеПоВладельцу Или Не Контекст.ЭтоСсылочныйТип Тогда + Если ОграничениеЧтения.Узел <> "ЧтениеОбъектаРазрешено" Тогда + Если Не ТребуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + Если ЗначениеЗаполнено(ОграничениеИзменения) Тогда + ШаблонОшибки = + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение чтения изменения не представлено одной функцией ""%2"".'"); + Иначе + ШаблонОшибки = + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение чтения не представлено одной функцией ""%2"".'"); + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Иначе + ОграничениеЧтения = ВозможноеОграничениеПоОбъектуВладельцу(ОграничениеЧтения, Ложь, Контекст); + Если ОграничениеЧтения = Неопределено Тогда + Возврат; + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(ОграничениеЧтения) Тогда + Если Не ФункцияБезУточненийТиповСПолемБезВложений(ОграничениеЧтения) Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но параметры функции ""%2"" не представлены + |только одним параметром - полем владельцем без других параметров.'"), + ИмяПризнакаОптимизации, + "ЧтениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + ОграничениеЧтенияПоле = ОграничениеЧтения.Поле; // См. ОписаниеУзла + ПолеВладельца.Имя = ОграничениеЧтенияПоле.Имя; + КонецЕсли; + КонецЕсли; + + Если Результат.ЕстьОграничениеИзменения Тогда + + Если ТребуетсяОграничениеПоВладельцу Или Не Контекст.ЭтоСсылочныйТип Тогда + + Если ОграничениеИзменения.Узел <> "ЧтениеОбъектаРазрешено" + И ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено" Тогда + + Если Не ТребуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение изменения не представлено одной функцией + |""%2"" или ""%3"".'"), + ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + Иначе + ОграничениеИзменения = ВозможноеОграничениеПоОбъектуВладельцу(ОграничениеИзменения, Истина, Контекст); + Если ОграничениеИзменения = Неопределено Тогда + Возврат; + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(ОграничениеИзменения) Тогда + Если Не ФункцияБезУточненийТиповСПолемБезВложений(ОграничениеИзменения) Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но параметры функции ""%2"" не представлены + |только одним параметром - полем владельцем без других параметров.'"), + ИмяПризнакаОптимизации, + ОграничениеИзменения.Узел); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + ОграничениеИзмененияПоле = ОграничениеИзменения.Поле; // См. ОписаниеУзла + + Если ПолеВладельца.Имя = "" Тогда + ПолеВладельца.Имя = ОграничениеИзмененияПоле.Имя; + + ИначеЕсли ПолеВладельца.Имя <> ОграничениеИзмененияПоле.Имя Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но поле владельца не совпадает в ограничениях чтения и изменения.'"), + ИмяПризнакаОптимизации, + ОграничениеИзменения.Узел); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + ПолеВладельца.ИзменениеКакЧтение = + ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено"; + Иначе + ПолеВладельца.ИзменениеКакЧтение = Истина; + КонецЕсли; + Иначе + ПолеВладельца.ИзменениеКакЧтение = Истина; + КонецЕсли; + + Если Не ЗначениеЗаполнено(ПолеВладельца.Имя) Тогда + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но указанное ограничение не содержит ни одной из функций + |""%2"", ""%3"".'"), + ИмяПризнакаОптимизации, "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено"); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + Возврат; + КонецЕсли; + КонецЕсли; + + Результат.ПолеВладельца = ПолеВладельца; + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Результат.ТребуетсяОграничениеПоВладельцу = Истина; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОграничениеПоОбъектуВладельцуДоУпрощения. +Функция ВозможноеОграничениеПоОбъектуВладельцу(Условие, ЭтоОграничениеИзменения, Контекст) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат Новый Структура; + КонецЕсли; + + Если Условие.Узел = "Поле" + Или Условие.Узел = "ЕстьNull" + Или Условие.Узел = "=" + Или Условие.Узел = "<>" + Или Условие.Узел = "В" + Или Условие.Узел = "Константа" + Или Условие.Узел = "ЗначениеРазрешено" Тогда + + Возврат Новый Структура; + + ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" + Или Условие.Узел = "ПравоДоступа" + Или Условие.Узел = "РольДоступна" Тогда + + Возврат Неопределено; + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + НайденноеОграничение = Новый Структура; + Для Каждого Аргумент Из Условие.Аргументы Цикл + Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Аргумент, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда + Возврат Неопределено; + КонецЕсли; + КонецЦикла; + Возврат НайденноеОграничение; + + ИначеЕсли Условие.Узел = "Не" + Или Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + Возврат ВозможноеОграничениеПоОбъектуВладельцу(Условие.Аргумент, + ЭтоОграничениеИзменения, Контекст); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + НайденноеОграничение = Новый Структура; + Для Каждого Когда Из Условие.Когда Цикл + Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Когда.Значение, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда + Возврат Неопределено; + КонецЕсли; + КонецЦикла; + Если Не ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Условие.Иначе, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) Тогда + Возврат Неопределено; + КонецЕсли; + Возврат НайденноеОграничение; + + ИначеЕсли Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" И ЭтоОграничениеИзменения Тогда + + Возврат Условие; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При заполнении возможного ограничения по объекту владельцу + |для списка ""%1"" + |узел не поддерживается ""%2"".'"), + Контекст.Список, + Условие.Узел); + + ВызватьИсключение ТекстОшибки; + +КонецФункции + +// Для функции ВозможноеОграничениеПоОбъектуВладельцу. +Функция ОбработаноВозможноеОграничениеПоОбъектуВладельцу(Условие, + ЭтоОграничениеИзменения, НайденноеОграничение, Контекст) + + ВложенноеОграничение = ВозможноеОграничениеПоОбъектуВладельцу(Условие, + ЭтоОграничениеИзменения, Контекст); + + Если ВложенноеОграничение = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Если ЗначениеЗаполнено(ВложенноеОграничение) Тогда + Если ЗначениеЗаполнено(НайденноеОграничение) Тогда + Возврат Ложь; + КонецЕсли; + НайденноеОграничение = ВложенноеОграничение; + КонецЕсли; + + Возврат Истина; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьОграничениеПоОбъектуВладельцуПослеУпрощения(Результат, Контекст) + + ПолеВладельца = Результат.ПолеВладельца; + Если ПолеВладельца = Неопределено Тогда + Возврат; + КонецЕсли; + ТребуетсяОграничениеПоВладельцу = Результат.ТребуетсяОграничениеПоВладельцу; + + НастройкаПоВладельцу = Контекст.СпискиСОграничениемПоВладельцу.Получить(Контекст.Список); + Если ТипЗнч(НастройкаПоВладельцу) = Тип("Булево") Тогда + ПолеВладельца.Отключено = Не НастройкаПоВладельцу; + Иначе + ПолеВладельца.Отключено = Ложь; + КонецЕсли; + + ОграничениеЧтения = Контекст.СтруктураОграничения.ОграничениеЧтения; + ОграничениеИзменения = Контекст.СтруктураОграничения.ОграничениеИзменения; + + ИмяПризнакаОптимизации = ?(Контекст.ДляВнешнихПользователей, + "ПоВладельцуБезЗаписиКлючейДоступаДляВнешнихПользователей", "ПоВладельцуБезЗаписиКлючейДоступа"); + + Если Не Результат.ЕстьОграничениеЧтения + И Не Результат.ЕстьОграничениеИзменения + Или Результат.ЕстьОграничениеЧтения + И ОграничениеЧтения.Узел <> "ЧтениеОбъектаРазрешено" + Или Результат.ЕстьОграничениеИзменения + И ОграничениеИзменения.Узел <> "ЧтениеОбъектаРазрешено" + И ОграничениеИзменения.Узел <> "ИзменениеОбъектаРазрешено" Тогда + + ПолеВладельца.Отключено = Истина; + Иначе + СвойстваПолей = Контекст.СвойстваПолей; + + Если СвойстваПолей.Количество() <> 1 Тогда + Если ТребуетсяОграничениеПоВладельцу И СвойстваПолей.Количество() <> 0 Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но количество полей, используемых в ограничении, не равно одному.'"), + ИмяПризнакаОптимизации); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + ПолеВладельца.Отключено = Истина; + КонецЕсли; + Иначе + СвойстваПоля = СвойстваПолей[0]; + + ТипИОМ = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных"); + ТипИОР = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений"); + + КоличествоТиповИдентификаторовВКонечномПоле = 0; + Если СвойстваПоля.ТипКонечногоПоля.СодержитТип(ТипИОМ) Тогда + КоличествоТиповИдентификаторовВКонечномПоле = 1; + КонецЕсли; + Если СвойстваПоля.ТипКонечногоПоля.СодержитТип(ТипИОР) Тогда + КоличествоТиповИдентификаторовВКонечномПоле = КоличествоТиповИдентификаторовВКонечномПоле + 1; + КонецЕсли; + + Если СвойстваПоля.ТипКонечногоПоля.Типы().Количество() - КоличествоТиповИдентификаторовВКонечномПоле + <> СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() Тогда + + НекорректныеТипы = Новый Массив; + Для Каждого Тип Из СвойстваПоля.ТипКонечногоПоля.Типы() Цикл + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Найти(Тип) <> Неопределено + Или Тип = ТипИОМ + Или Тип = ТипИОР Тогда + Продолжить; + КонецЕсли; + НекорректныеТипы.Добавить(ИмяТипаНаЯзыкеЗапросов(Тип)); + КонецЦикла; + Если ТребуетсяОграничениеПоВладельцу Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Установлен признак оптимизации ограничения ""%1"", + |но для следующих таблиц невозможно записать ключи доступа: + |%2'"), + ИмяПризнакаОптимизации, + СтрСоединить(НекорректныеТипы, Символы.ПС)); + ТекстОшибки = ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + Иначе + ПолеВладельца.Отключено = Истина; + КонецЕсли; + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "ИзменениеКакЧтение"); + ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "Имя"); + ДобавитьСвойствоВерсии(Контекст, ПолеВладельца, "Отключено"); + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Имя - Строка +// * ИзменениеКакЧтение - Булево +// * Отключено - Булево +// +Функция НовоеПолеВладельца() + + Возврат Новый Структура("Имя, ИзменениеКакЧтение, Отключено", "", Ложь, Истина); + +КонецФункции + +// Для функции ЗаполнитьОграничениеПоОбъектуВладельцу и процедуры НастроитьОптимизациюПоПолюВладельцу. +Функция ТекстОшибкиСЗаголовком(ТекстОшибки, Контекст) + + ОписаниеОшибок = ОписаниеОшибок(); + ОписаниеОшибок.ЕстьОшибки = Истина; + ОписаниеОшибок.ТекстОшибок = ТекстОшибки; + ОписаниеОшибок.Ошибки = Новый Массив(1); + + ОписаниеОграничения = Контекст.ОписанияОграничений.Получить(Контекст.Список); + + ОписаниеОшибок.Ограничение = + ПронумерованныйТекстОграниченияСОтметкамиОшибок(ОписаниеОграничения.Текст, + Новый Массив, СтрДлина(Формат(СтрЧислоСтрок(ОписаниеОграничения.Текст), "ЧГ="))); + + Возврат СокрЛП(ТекстОшибокДляВызоваИсключения(Контекст.Список, + ОписаниеОшибок, Контекст.ДляВнешнихПользователей, ОписаниеОграничения.ВМодулеМенеджера)); + +КонецФункции + +// Для процедуры ЗаполнитьОграничениеПоОбъектуВладельцу. +Функция ФункцияБезУточненийТиповСПолемБезВложений(Ограничение) + + Если Ограничение.Типы.Количество() <> 0 + Или Ограничение.УточненияСравнения.Количество() <> 0 Тогда + Возврат Ложь; + КонецЕсли; + + Поле = Ограничение.Поле; + + Возврат Не ЗначениеЗаполнено(Поле.Выразить) + И Не ЗначениеЗаполнено(Поле.Вложение) + И Не ЗначениеЗаполнено(Поле.ЕстьNull); + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеВедущихКлючейИСписковИВладельцевНастроекПрав(Результат, Контекст) + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() > 0 Тогда + Результат.ЕстьВедущиеКлючиДоступа = Истина; + КонецЕсли; + Если СвойстваПоля.ЕстьТипВедущегоСписка Тогда + Результат.ЕстьВедущиеСпискиПоПравам = Истина; + КонецЕсли; + Если СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда + Результат.ЕстьВладельцыНастроекПрав = Истина; + КонецЕсли; + Если СвойстваПоля.ЕстьПроверкаАвторизованногоПользователя Тогда + Контекст.ЕстьПроверкаАвторизованногоПользователя = Истина; + КонецЕсли; + Для Каждого Тип Из СвойстваПоля.ИспользуемыеТипыЗначенийДоступа Цикл + Если Результат.ИспользуемыеТипыЗначенийДоступа.Найти(Тип) = Неопределено Тогда + Результат.ИспользуемыеТипыЗначенийДоступа.Добавить(Тип); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Для Каждого КлючИЗначение Из Контекст.ОтдельныеТаблицыНастроекПрав Цикл + Если КлючИЗначение.Значение = Контекст.Список Тогда + Результат.ИдентификаторТаблицыНастроекПрав = КлючИЗначение.Ключ; + Прервать; + КонецЕсли; + КонецЦикла; + + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВедущиеКлючиДоступа"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВедущиеСпискиПоПравам"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьВладельцыНастроекПрав"); + ДобавитьСвойствоВерсии(Контекст, Результат, "ИспользуемыеТипыЗначенийДоступа"); + ДобавитьСвойствоВерсии(Контекст, Контекст, "НеиспользуемыеТипыЗначенийДоступа"); + + СохраняемыеСвойства = Новый Структура("ОтдельнаяТаблицаНастроекПрав", + ЗначениеЗаполнено(Результат.ИдентификаторТаблицыНастроекПрав)); + + ДобавитьСвойствоВерсии(Контекст, СохраняемыеСвойства, "ОтдельнаяТаблицаНастроекПрав"); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура УдалитьПоляНеиспользуемыхВидовДоступа(Результат, Контекст) + + СвойстваПолей = Контекст.СвойстваПолей; + + Если Не Результат.ЕстьВедущиеКлючиДоступа + И Не Результат.ЕстьВедущиеСпискиПоПравам + И Не Результат.ЕстьВладельцыНастроекПрав + И Не Результат.ЕстьФункцияПравоДоступаИлиРольДоступна + И Не Контекст.ЕстьПроверкаАвторизованногоПользователя + И Результат.ИспользуемыеТипыЗначенийДоступа.Количество() = 0 + И Контекст.НеиспользуемыеТипыЗначенийДоступа.Количество() > 0 Тогда + + СвойстваПолей.Очистить(); + Возврат; + КонецЕсли; + + Индекс = СвойстваПолей.Количество(); + Пока Индекс > 0 Цикл + Индекс = Индекс - 1; + СвойстваПоля = СвойстваПолей.Получить(Индекс); + УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, СвойстваПоля); + УстановитьИспользованиеОпорногоПоля(Контекст, СвойстваПоля); + ДобавитьСвойстваВерсии(Контекст, СвойстваПоля, + "ЕстьУточнениеNull, + |ЕстьУточнениеНеопределено, + |ИмяПоляДляЗапроса, + |НесколькоГруппЗначений, + |ТипКонечногоПоля, + |ТипыСохраненияГруппЗначений, + |ТипыСохраненияЗначений, + |ТипыСохраненияКлючейДоступа, + |ТипыСохраненияПустойСсылки, + |ТипыСохраненияТипаРазрешенный, + |ТипыСохраненияТипаЗапрещенный, + |ТипыСохраненияТипов, + |ТипыСохраненияТиповКонфигурации, + |ТипыСохраненияТиповПростых, + |ТипыСохраненияТиповРасширений, + |ТипыСтрокой"); + КонецЦикла; + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеОграниченияПоВидуДоступаПользователи(Результат, Контекст) + + Если Результат.ЕстьВладельцыНастроекПрав Тогда + Результат.ЕстьОграничениеПоПользователям = Истина; + Иначе + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ТипыСохраненияЗначений.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + ОписаниеТипов = Новый ОписаниеТипов(СвойстваПоля.ТипыСохраненияЗначений); + Если Не Результат.ДляВнешнихПользователей + И ( ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.Пользователи")) + Или ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ГруппыПользователей")) ) Тогда + + Результат.ЕстьОграничениеПоПользователям = Истина; + Прервать; + КонецЕсли; + Если Результат.ДляВнешнихПользователей + И ( ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ВнешниеПользователи")) + Или ОписаниеТипов.СодержитТип(Тип("СправочникСсылка.ГруппыВнешнихПользователей")) ) Тогда + + Результат.ЕстьОграничениеПоПользователям = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, Результат, "ЕстьОграничениеПоПользователям"); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Результат - см. ПараметрыОграниченияПоСтруктуреОграничения +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьНаличиеОграниченияЧтения(Результат, Контекст) + + Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения Тогда + Результат.ОграничениеЧтенияОтключено = Ложь; + Иначе + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.Чтение Тогда + Результат.ОграничениеЧтенияОтключено = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + ДобавитьСвойствоВерсии(Контекст, Результат, "ОграничениеЧтенияОтключено"); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьГруппыПолейИДополнительныхТаблиц(Контекст) + + // Поля шапки (начинаются от шапки - группировка по пустому псевдониму, если нет имени табличной части). + // Поля каждой ТЧ (начинаются от табличной части - группировка по имени табличной части). + // Поля группы связанных дополнительных таблиц (начинаются от экземпляра доп. таблицы - группировка + // по псевдониму, но если одна таблица ссылается на другую в соединении, тогда образуется группа таблиц). + + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = 0; + НомерПоследнейТабличнойЧастиОбъекта = 0; + НомераТабличныхЧастейОбъекта = Новый Соответствие; + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" + И СвойстваПоля.НесколькоГруппЗначений Тогда + + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + 1; + + ИначеЕсли СвойстваПоля.ПсевдонимТаблицы <> "ТекущийСписок" + И СтрНачинаетсяС(СвойстваПоля.ПсевдонимТаблицы, "ТекущийСписок") + И НомераТабличныхЧастейОбъекта.Получить(СвойстваПоля.ПсевдонимТаблицы) = Неопределено Тогда + + НомерПоследнейТабличнойЧастиОбъекта = НомерПоследнейТабличнойЧастиОбъекта + 1; + НомераТабличныхЧастейОбъекта.Вставить(СвойстваПоля.ПсевдонимТаблицы, НомерПоследнейТабличнойЧастиОбъекта); + КонецЕсли; + КонецЦикла; + + РазмерностьКлючаДоступа = УправлениеДоступомСлужебныйПовтИсп.РазмерностьКлючаДоступа(); + + КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта = Цел( + (НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + + РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти - 1) + / РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти); + + ГруппыДополнительныхТаблиц = ГруппыДополнительныхТаблиц(Контекст); + КоличествоТабличныхЧастейКлюча = НомерПоследнейТабличнойЧастиОбъекта + + ГруппыДополнительныхТаблиц.ТаблицыПоГруппам.Количество() + + КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта; + + ЗавершитьПодготовкуПолейТаблицОбъекта(Контекст); + ЗавершитьПодготовкуОпорныхПолей(Контекст); + + Если КоличествоТабличныхЧастейКлюча > РазмерностьКлючаДоступа.КоличествоТабличныхЧастей Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей, требующих отдельных табличных частей в ключе доступа, + |более, чем количество доступных табличных частей в ключе доступа. + | + |К таким полям относятся: + |- поля табличных частей, + |- поля дополнительных таблиц, присоединенных к списку, + |- поля шапки, у которых значение доступа может иметь более одной группы значений доступа.'"), + Контекст.Список); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Не Контекст.ЭтоСсылочныйТип + И Контекст.ОпорныеПоля.Все.Количество() > Контекст.ОпорныеПоля.МаксимальноеКоличество Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей списка, используемых в ограничении доступа, + |превышает максимально допустимое количество опорных полей: %2.'"), + Контекст.Список, + Контекст.ОпорныеПоля.МаксимальноеКоличество); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ГруппыПолей = Новый Соответствие; + ПсевдонимыТабличныхЧастейОбъекта = Новый Соответствие; + НомерПоследнегоРеквизитаШапки = 0; + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = 0; + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" Тогда + + Если СвойстваПоля.НесколькоГруппЗначений Тогда + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа = + НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + 1; + + НомерТабличнойЧастиКлюча = Цел(НомерПоследнегоРеквизитаШапкиСНесколькимиГруппамиЗначенийДоступа + / РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти) + 1; + + ИмяГруппыПолей = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + Иначе + НомерПоследнегоРеквизитаШапки = НомерПоследнегоРеквизитаШапки + 1; + Если НомерПоследнегоРеквизитаШапки < 6 Тогда + ИмяГруппыПолей = "Шапка0"; + ИначеЕсли НомерПоследнегоРеквизитаШапки < 11 Тогда + ИмяГруппыПолей = "Шапка1"; + ИначеЕсли НомерПоследнегоРеквизитаШапки < 16 Тогда + ИмяГруппыПолей = "Шапка2"; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей списка, используемых в ограничении доступа, + |превышает максимально допустимое количество: 15.'"), + Контекст.Список); + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЕсли; + Иначе + Если СвойстваПоля.ПсевдонимТаблицы <> "ТекущийСписок" + И СтрНачинаетсяС(СвойстваПоля.ПсевдонимТаблицы, "ТекущийСписок") Тогда + + НомерТабличнойЧастиКлюча = КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта + + НомераТабличныхЧастейОбъекта.Получить(СвойстваПоля.ПсевдонимТаблицы); + + Если ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча) = Неопределено Тогда + ПсевдонимыТабличныхЧастейОбъекта.Вставить(НомерТабличнойЧастиКлюча, СвойстваПоля.ПсевдонимТаблицы) + КонецЕсли; + Иначе + НомерТабличнойЧастиКлюча = КоличествоТабличныхЧастейКлючаДляРеквизитовШапкиОбъекта + + НомераТабличныхЧастейОбъекта.Количество() + + ГруппыДополнительныхТаблиц.НомераПоПсевдонимам.Получить(СвойстваПоля.ПсевдонимТаблицы); + КонецЕсли; + ИмяГруппыПолей = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + КонецЕсли; + ГруппаПолей = ГруппыПолей.Получить(ИмяГруппыПолей); + Если ГруппаПолей = Неопределено Тогда + ГруппаПолей = Новый Массив; + ГруппыПолей.Вставить(ИмяГруппыПолей, ГруппаПолей); + КонецЕсли; + ГруппаПолей.Добавить(СвойстваПоля); + СвойстваПоля.Вставить("ИмяГруппыПолейКлючаДоступа", ИмяГруппыПолей); + СвойстваПоля.Вставить("ИмяРеквизитаГруппыПолейКлючаДоступа", + "Значение" + XMLСтрока(ГруппаПолей.Количество() + ?(ИмяГруппыПолей = "Шапка1" Или ИмяГруппыПолей = "Шапка2", 5, 0))); + + Если Не СтрНачинаетсяС(ИмяГруппыПолей, "Шапка") + И ГруппаПолей.Количество() > РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |количество полей одной табличной части, используемых в ограничении доступа, + |превышает максимально допустимое количество: %2.'"), + Контекст.Список, + РазмерностьКлючаДоступа.КоличествоРеквизитовТабличнойЧасти); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЦикла; + + Контекст.Вставить("ГруппыПолей", ГруппыПолей); + Контекст.Вставить("ПсевдонимыТабличныхЧастейОбъекта", ПсевдонимыТабличныхЧастейОбъекта); + Контекст.Вставить("ГруппыДополнительныхТаблиц", ГруппыДополнительныхТаблиц); + Контекст.Вставить("КоличествоТабличныхЧастейКлюча", КоличествоТабличныхЧастейКлюча); + + // Расчет числа СоставПолей. + + // Шапка и табличные части: ТЧ4 ТЧ3 ТЧ2 ТЧ1 Ш. + // Двоичный формат: 0000 0000 0000 0000 0000. + // Шестнадцатеричный формат: x0 x0 x0 x0 x0. + // + // Например: Ш0=1, ТЧ1=1. + // Двоичный формат: 0000 0000 0000 0001 0001. + // Шестнадцатеричный формат: x0 x0 x0 x1 x1. + // Число = 1*16^0 + 1*16^1 = 1 + 16 = 17. + + СоставПолей = НомерПоследнегоРеквизитаШапки; + + Для НомерТабличнойЧастиКлюча = 1 По КоличествоТабличныхЧастейКлюча Цикл + ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + ГруппаПолей = ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); + СоставПолей = СоставПолей + ГруппаПолей.Количество() * Степень16(НомерТабличнойЧастиКлюча); + КонецЦикла; + + Контекст.Вставить("СоставПолей", СоставПолей); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияДоступа. +// +// Параметры: +// УсловиеРасчета - см. СтруктураРасчетаПрава +// Условие - см. ОписаниеУзла +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета, Условие, Контекст, КореньУсловия = Истина) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат; + КонецЕсли; + + Если КореньУсловия Тогда + Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + Контекст.Вставить("СтруктураРасчетаПраваСвойстваВерсии", Новый Массив); + КонецЕсли; + + СвойстваПоля = Неопределено; + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Узел", Условие.Узел); + + Если Условие.Узел = "Поле" Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие); + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + УсловиеРасчета = Новый Структура("Узел, Аргументы", Условие.Узел, Новый Массив); + Индекс = 0; + Для Каждого Аргумент Из Условие.Аргументы Цикл + УсловиеРасчета.Аргументы.Добавить(Неопределено); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргументы[Индекс], Аргумент, Контекст, Ложь); + Индекс = Индекс + 1; + КонецЦикла; + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "Не" Тогда + УсловиеРасчета = Новый Структура("Узел, Аргумент", Условие.Узел, Неопределено); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргумент, Условие.Аргумент, Контекст, Ложь); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + Если Не КореньУсловия Тогда + ТребуемыеРеквизитыТабличныхЧастейКлюча = Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча; + Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Новый Соответствие); + КонецЕсли; + + УсловиеРасчета = Новый Структура("Узел, Аргумент", Условие.Узел, Неопределено); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Аргумент, Условие.Аргумент, Контекст, Ложь); + + Если Не КореньУсловия Тогда + УсловиеРасчета.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча); + Контекст.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", ТребуемыеРеквизитыТабличныхЧастейКлюча); + КонецЕсли; + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ЕстьNull" Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.Аргумент); + + ИначеЕсли Условие.Узел = "=" + Или Условие.Узел = "<>" Тогда + + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.ПервыйАргумент); + Если СвойстваПоля = Неопределено Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.ВторойАргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "В" Тогда + СвойстваПоля = Контекст.СвойстваПолейКлючаДоступа.Получить(Условие.Искомое); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + УсловиеРасчета = Новый Структура("Узел, Когда, Иначе", Условие.Узел, Новый Массив, Неопределено); + Для Каждого Когда Из Условие.Когда Цикл + СтруктураКогда = Новый Структура("Условие, Значение"); + УсловиеРасчета.Когда.Добавить(СтруктураКогда); + Если Условие.Выбор = Неопределено Тогда + ЗаполнитьСтруктуруРасчетаПрава(СтруктураКогда.Условие, Когда.Условие, Контекст, Ложь); + Иначе + Свойства = Контекст.СвойстваПолейКлючаДоступа.Получить(Когда.Условие); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Узел", "Поле"); + УсловиеРасчетаПоле(СтруктураКогда.Условие, Свойства, Контекст); + КонецЕсли; + ЗаполнитьСтруктуруРасчетаПрава(СтруктураКогда.Значение, Когда.Значение, Контекст, Ложь); + КонецЦикла; + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Иначе, Условие.Иначе, Контекст, Ложь); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + УсловиеРасчета = Новый Структура("Узел, Поле", Условие.Узел, Неопределено); + УсловиеРасчета.Вставить("УточненияСравнения", Новый Соответствие); + Для Каждого КлючИЗначение Из Условие.УточненияСравнения Цикл + Если КлючИЗначение.Ключ = "Null" + Или КлючИЗначение.Ключ = "Неопределено" + Или КлючИЗначение.Ключ = "ПустаяСсылка" + Или КлючИЗначение.Ключ = "Отключено" Тогда + УсловиеРасчета.УточненияСравнения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + Иначе + ИмяТипа = СтрЗаменить(КлючИЗначение.Ключ, ".", "Ссылка."); + УсловиеРасчета.УточненияСравнения.Вставить(Тип(ИмяТипа), КлючИЗначение.Значение); + КонецЕсли; + КонецЦикла; + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "УточненияСравнения", Условие.УточненияСравнения); + ЗаполнитьСтруктуруРасчетаПрава(УсловиеРасчета.Поле, Условие.Поле, Контекст, Ложь); + + Если УсловиеРасчета.Поле = Null Тогда + УсловиеРасчета = Новый Структура("Узел, Значение", "Константа", Истина); + КонецЕсли; + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "Константа" Тогда + УсловиеРасчета = Новый Структура("Узел, Значение", Условие.Узел, Условие.Значение); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Значение", Условие.Значение); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "ПравоДоступа" Тогда + УсловиеРасчета = Новый Структура("Узел, ИмяПрава, ПолноеИмяОбъектаМетаданных", + Условие.Узел, Условие.ИмяПрава, Условие.ПолноеИмяОбъектаМетаданных); + ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ИмяПрава", Условие.ИмяПрава); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ПолноеИмяОбъектаМетаданных", + Условие.ПолноеИмяОбъектаМетаданных); + СвойстваПоля = Null; + + ИначеЕсли Условие.Узел = "РольДоступна" Тогда + УсловиеРасчета = Новый Структура("Узел, ИмяРоли", Условие.Узел, Условие.ИмяРоли); + ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ИмяРоли", Условие.ИмяРоли); + СвойстваПоля = Null; + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При заполнении структуры расчета права %1 на ключи доступа + |списка ""%2"" + |узел не поддерживается ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если СвойстваПоля = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При заполнении структуры расчета права %1 на ключи доступа + |списка ""%2"" + |свойства поля не определены для узла ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если СвойстваПоля <> Null Тогда + УсловиеРасчетаПоле(УсловиеРасчета, СвойстваПоля, Контекст); + КонецЕсли; + + Если КореньУсловия Тогда + УсловиеРасчета.Вставить("ТребуемыеРеквизитыТабличныхЧастейКлюча", + Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча); + + ДобавитьЭлементВерсии(Контекст, ?(Контекст.ИмяПрава = "Чтение", + "СтруктураРасчетаПраваЧтение", "СтруктураРасчетаПраваИзменение"), + Контекст.СтруктураРасчетаПраваСвойстваВерсии); + + Контекст.Удалить("СтруктураРасчетаПраваСвойстваВерсии"); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьСтруктуруРасчетаПрава. +Процедура УсловиеРасчетаПоле(УсловиеРасчета, СвойстваПоля, Контекст) + + Если Контекст.СвойстваПолей.Найти(СвойстваПоля) = Неопределено Тогда + УсловиеРасчета = Null; // Поле удалено из-за неиспользуемых типов значений доступа. + Иначе + УсловиеРасчета = Новый Структура("Узел", "Поле"); + УсловиеРасчета.Вставить("Таблица", СвойстваПоля.ИмяГруппыПолейКлючаДоступа); + УсловиеРасчета.Вставить("Реквизит", СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + Если СтрНачинаетсяС(УсловиеРасчета.Таблица, "ТабличнаяЧасть") Тогда + Реквизиты = Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча.Получить(УсловиеРасчета.Таблица); + Если Реквизиты = Неопределено Тогда + Реквизиты = Новый Массив; + Контекст.ТребуемыеРеквизитыТабличныхЧастейКлюча.Вставить(УсловиеРасчета.Таблица, Реквизиты); + КонецЕсли; + Если Реквизиты.Найти(УсловиеРасчета.Реквизит) = Неопределено Тогда + Реквизиты.Добавить(УсловиеРасчета.Реквизит); + КонецЕсли; + КонецЕсли; + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Таблица", УсловиеРасчета.Таблица); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "Реквизит", УсловиеРасчета.Реквизит); + Если СвойстваПоля.Свойство("ПроверкаЕстьNull") Тогда + УсловиеРасчета.Вставить("ПроверкаЕстьNull"); + ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, "ПроверкаЕстьNull", Истина); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьСтруктуруРасчетаПрава. +Процедура ДобавитьЗависимостьОтРолей(Контекст, УсловиеРасчета) + + Если УсловиеРасчета.Свойство("ИмяРоли") Тогда + Роль = Метаданные.Роли.Найти(УсловиеРасчета.ИмяРоли); + Контекст.ВедущиеРоли.Вставить(Роль.Имя, Истина); + Возврат; + КонецЕсли; + + ИмяСтандартногоРеквизита = Неопределено; + ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава( + УсловиеРасчета.ПолноеИмяОбъектаМетаданных, ИмяСтандартногоРеквизита); + + Для Каждого Роль Из Метаданные.Роли Цикл + Если ПравоДоступа(УсловиеРасчета.ИмяПрава, ОбъектМетаданных, Роль, ИмяСтандартногоРеквизита) Тогда + Контекст.ВедущиеРоли.Вставить(Роль.Имя, Истина); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ЗаполнитьСтруктуруРасчетаПрава, УсловиеРасчетаПоле. +Процедура ДобавитьСвойствоВерсииСтруктурыРасчета(Контекст, Имя, Значение); + + Если ТипЗнч(Значение) = Тип("Соответствие") Тогда + СписокЗначений = Новый СписокЗначений; + Для Каждого КлючИЗначение Из Значение Цикл + СписокЗначений.Добавить(КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЦикла; + СписокЗначений.СортироватьПоПредставлению(); + Для Каждого ЭлементСписка Из СписокЗначений Цикл + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(ЭлементСписка.Представление); + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(ЭлементСписка.Значение); + КонецЦикла; + Иначе + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(Имя); + Контекст.СтруктураРасчетаПраваСвойстваВерсии.Добавить(Значение); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. +Функция Степень16(Степень) + + Степень16 = 1; + + Для Счетчик = 1 По Степень Цикл + Степень16 = Степень16 * 16; + КонецЦикла; + + Возврат Степень16; + +КонецФункции + +// Для функции ЗаполнитьГруппыПолейИДополнительныхТаблиц. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +// Возвращаемое значение: +// Структура: +// * НомераПоПсевдонимам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - псевдоним дополнительной таблицы +// ** Значение - Число - номер группы дополнительных таблиц +// +// * ТаблицыПоГруппам - Соответствие из КлючИЗначение: +// ** Ключ - Число - номер группы дополнительных таблиц +// ** Значение - Массив из см. НовоеОписаниеСоединения +// +// * ПсевдонимыТаблицСПолями - Соответствие из КлючИЗначение: +// ** Ключ - Строка - псевдоним дополнительной таблицы +// с полями ключа доступа (кроме полей соединений). +// ** Значение - Булево - Истина. +// +Функция ГруппыДополнительныхТаблиц(Контекст) + + ДополнительныеТаблицы = Контекст.СтруктураОграничения.ДополнительныеТаблицы; + НомераГруппПоПсевдонимам = Новый Соответствие; + + Контекст.ОпорныеПоля.Вставить("ПоДополнительнымТаблицам", Новый Соответствие); + Контекст.ПоляТаблицОбъекта.Вставить("ПоДополнительнымТаблицам", Новый Соответствие); + Контекст.Вставить("ПоляУсловияСоединенияДополнительныхТаблиц", Новый Массив); + + ПоследняяГруппа = 0; + Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл + ДополнительнаяТаблица.Вставить("ПсевдонимыТребуемыхТаблиц", Новый Массив); + ДополнительнаяТаблица.Вставить("ПоляУсловияСоединения", Новый Массив); + + ТекстУсловияСоединения = ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст); + ДополнительнаяТаблица.Вставить("ТекстУсловияСоединения", ?(Лев(ТекстУсловияСоединения, 1) = "(", + ТекстУсловияСоединения, "(" + ТекстУсловияСоединения + ")")); + + ТекущаяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); + Если ТекущаяГруппа = Неопределено Тогда + ПоследняяГруппа = ПоследняяГруппа + 1; + ТекущаяГруппа = ПоследняяГруппа; + НомераГруппПоПсевдонимам.Вставить(ДополнительнаяТаблица.Псевдоним, ТекущаяГруппа); + КонецЕсли; + + Для Каждого Псевдоним Из ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц Цикл + ГруппаТребуемойТаблицы = НомераГруппПоПсевдонимам.Получить(Псевдоним); + Если ГруппаТребуемойТаблицы = Неопределено Тогда + НомераГруппПоПсевдонимам.Вставить(Псевдоним, ТекущаяГруппа); + Продолжить; + КонецЕсли; + Если ГруппаТребуемойТаблицы = ТекущаяГруппа Тогда + Продолжить; + КонецЕсли; + ПсевдонимыЗаменяемойГруппы = Новый Массив; + Для Каждого КлючИЗначение Из НомераГруппПоПсевдонимам Цикл + Если КлючИЗначение.Значение <> ГруппаТребуемойТаблицы Тогда + Продолжить; + КонецЕсли; + ПсевдонимыЗаменяемойГруппы.Добавить(КлючИЗначение.Ключ); + КонецЦикла; + Для Каждого Псевдоним Из ПсевдонимыЗаменяемойГруппы Цикл + НомераГруппПоПсевдонимам.Вставить(Псевдоним, ТекущаяГруппа); + КонецЦикла; + КонецЦикла; + КонецЦикла; + + ПсевдонимыТаблицСПолями = Новый Соответствие; + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + Если СвойстваПоля.ПсевдонимТаблицы = "ТекущийСписок" Тогда + Продолжить; + КонецЕсли; + ПсевдонимыТаблицСПолями.Вставить(СвойстваПоля.ПсевдонимТаблицы, Истина); + КонецЦикла; + + ИспользованиеГрупп = Новый Соответствие; + Для Группа = 1 По ПоследняяГруппа Цикл + Для Каждого КлючИЗначение Из НомераГруппПоПсевдонимам Цикл + Если КлючИЗначение.Значение <> Группа Тогда + Продолжить; + КонецЕсли; + Если ИспользованиеГрупп.Получить(Группа) = Неопределено Тогда + ИспользованиеГрупп.Вставить(Группа, Ложь); + КонецЕсли; + Если ПсевдонимыТаблицСПолями.Получить(КлючИЗначение.Ключ) <> Неопределено Тогда + ИспользованиеГрупп.Вставить(Группа, Истина); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + НоваяГруппа = 1; + НовыеГруппы = Новый Соответствие; + Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл + СтараяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); + Если Не ИспользованиеГрупп.Получить(СтараяГруппа) Тогда + Продолжить; + КонецЕсли; + Если НовыеГруппы.Получить(СтараяГруппа) <> Неопределено Тогда + Продолжить; + КонецЕсли; + НовыеГруппы.Вставить(СтараяГруппа, НоваяГруппа); + НоваяГруппа = НоваяГруппа + 1; + КонецЦикла; + + Группы = Новый Структура; + Группы.Вставить("НомераПоПсевдонимам", Новый Соответствие); + Группы.Вставить("ТаблицыПоГруппам", Новый Соответствие); + Группы.Вставить("ПсевдонимыТаблицСПолями", ПсевдонимыТаблицСПолями); + + Для Каждого ДополнительнаяТаблица Из ДополнительныеТаблицы Цикл + СтараяГруппа = НомераГруппПоПсевдонимам.Получить(ДополнительнаяТаблица.Псевдоним); + Если Не ИспользованиеГрупп.Получить(СтараяГруппа) Тогда + Продолжить; + КонецЕсли; + УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, , ДополнительнаяТаблица); + УстановитьИспользованиеОпорногоПоля(Контекст, , ДополнительнаяТаблица); + Группа = НовыеГруппы.Получить(СтараяГруппа); + Группы.НомераПоПсевдонимам.Вставить(ДополнительнаяТаблица.Псевдоним, Группа); + ГруппаТаблиц = Группы.ТаблицыПоГруппам.Получить(Группа); + Если ГруппаТаблиц = Неопределено Тогда + ГруппаТаблиц = Новый Массив; + Группы.ТаблицыПоГруппам.Вставить(Группа, ГруппаТаблиц); + КонецЕсли; + ГруппаТаблиц.Добавить(ДополнительнаяТаблица); + КонецЦикла; + + Для Каждого СвойстваПоля Из Контекст.СвойстваПолей Цикл + ТекущиеСвойства = СвойстваПоля; + Пока ТекущиеСвойства <> Неопределено Цикл + ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, + ТекущиеСвойства.УзелПоле, + ТекущиеСвойства.СвойстваВложения, + ?(ТекущиеСвойства.ЭтоПолеСписка, Неопределено, ТекущиеСвойства.ПсевдонимТаблицы)); + ТекущиеСвойства = ТекущиеСвойства.СвойстваВложения; + КонецЦикла; + КонецЦикла; + + Для Каждого ОписаниеПоляУсловия Из Контекст.ПоляУсловияСоединенияДополнительныхТаблиц Цикл + Группа = Группы.НомераПоПсевдонимам.Получить(ОписаниеПоляУсловия.ПсевдонимТаблицыУсловия); + Если Группа <> Неопределено Тогда + УзелПоле = ОписаниеПоляУсловия.УзелПоле; + ДобавитьСвойстваВерсии(Контекст, УзелПоле, "Псевдоним, Имя, ТипыСтрокой"); + ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, УзелПоле,, + Группы.ТаблицыПоГруппам.Получить(Группа), ОписаниеПоляУсловия.ПсевдонимТаблицыУсловия); + КонецЕсли; + КонецЦикла; + + Для Каждого Описание Из Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов Цикл + ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка(Описание.Ключ, + Описание.Значение, Группы, Контекст); + КонецЦикла; + ЗаполнитьОтборыВедущихСписковПоПолюСсылка(Контекст.ВедущиеСпискиПоКлючамДоступа, Группы, Контекст); + ЗаполнитьОтборыВедущихСписковПоПолюСсылка(Контекст.ВедущиеСпискиПоЗначениямСГруппами, Группы, Контекст); + + Возврат Группы; + +КонецФункции + +// Для функции ГруппыДополнительныхТаблиц. +Функция ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст, + Условие = Null, Поле = Неопределено, Псевдоним = Неопределено) + + Если Условие = Null Тогда + Условие = ДополнительнаяТаблица.УсловиеСоединения; + КонецЕсли; + + // Возможные узлы: "Поле", "Значение", "Константа", "И", "=". + + Если Условие.Узел = "Поле" Тогда + Контекст.ПоляУсловияСоединенияДополнительныхТаблиц.Добавить(Новый Структура( + "УзелПоле, ПсевдонимТаблицыУсловия", Условие, ДополнительнаяТаблица.Псевдоним)); + ДобавитьПолеТаблицыОбъекта(Контекст, Условие, , ДополнительнаяТаблица); + Если Условие.Псевдоним = Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + ДобавитьОпорноеПоле(Контекст, Условие, , ДополнительнаяТаблица); + Псевдоним = "ТекущийСписок"; + Поле = Псевдоним + "." + Условие.Имя; + Возврат ИмяПоляСРазверткойОпорногоПоляПоТипам(Псевдоним, Условие); + КонецЕсли; + Псевдоним = Условие.Псевдоним; + Если Псевдоним <> ДополнительнаяТаблица.Псевдоним + И ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц.Найти(Псевдоним) = Неопределено Тогда + ДополнительнаяТаблица.ПсевдонимыТребуемыхТаблиц.Добавить(Псевдоним); + КонецЕсли; + Поле = Псевдоним + "." + Условие.Имя; + Возврат Поле; + КонецЕсли; + + Если Условие.Узел = "Значение" + Или Условие.Узел = "Константа" Тогда + + Поле = ВыражениеУзлаЗначениеИлиКонстанта(Условие); + Возврат Поле; + КонецЕсли; + + Если Условие.Узел = "И" Тогда + Текст = ""; + Для Каждого Аргумент Из Условие.Аргументы Цикл + Текст = Текст + ?(Текст = "", "", Символы.ПС + "И "); + Текст = Текст + ТекстУсловияСоединения(ДополнительнаяТаблица, Контекст, Аргумент); + КонецЦикла; + Возврат Текст; + КонецЕсли; + + Если Условие.Узел = "=" Тогда + ПервоеПоле = НовоеПолеУсловияСоединения(); + ВтороеПоле = НовоеПолеУсловияСоединения(); + + ПервыйАргумент = ТекстУсловияСоединения(ДополнительнаяТаблица, + Контекст, Условие.ПервыйАргумент, ПервоеПоле.Поле, ПервоеПоле.Псевдоним); + + ВторойАргумент = ТекстУсловияСоединения(ДополнительнаяТаблица, + Контекст, Условие.ВторойАргумент, ВтороеПоле.Поле, ВтороеПоле.Псевдоним); + + Если ПервоеПоле.Псевдоним = ДополнительнаяТаблица.Псевдоним + Или Не ЗначениеЗаполнено(ВтороеПоле.Псевдоним) Тогда + ТекстУсловия = "(" + ПервыйАргумент + " = " + ВторойАргумент + ")"; + ПоляУсловия = ПараПолейУсловияСоединения(ПервоеПоле, ВтороеПоле); + Иначе + ТекстУсловия = "(" + ВторойАргумент + " = " + ПервыйАргумент + ")"; + ПоляУсловия = ПараПолейУсловияСоединения(ВтороеПоле, ПервоеПоле); + КонецЕсли; + ДополнительнаяТаблица.ПоляУсловияСоединения.Добавить(ПоляУсловия); + Возврат ТекстУсловия; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка узла ""%1""'"), Условие.Узел); + + ВызватьИсключение ТекстОшибки; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПервоеПоле - см. НовоеПолеУсловияСоединения +// * ВтороеПоле - см. НовоеПолеУсловияСоединения +// +Функция ПараПолейУсловияСоединения(ПервоеПоле, ВтороеПоле) + + Возврат Новый Структура("ПервоеПоле, ВтороеПоле", ПервоеПоле, ВтороеПоле); + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Поле - Строка +// * Псевдоним - Строка +// +Функция НовоеПолеУсловияСоединения() + + Возврат Новый Структура("Поле, Псевдоним"); + +КонецФункции + +// Для функций СвойстваПоля, ТекстУсловияСоединения. +Процедура ДобавитьПолеТаблицыОбъекта(Контекст, УзелПоле, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено, ТабличнаяЧасть = "") + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + ИмяТаблицыОбъекта = Контекст.Список; + + Если ЗначениеЗаполнено(УзелПоле.Псевдоним) + И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы + И ВРег(Контекст.Список) <> ВРег(УзелПоле.Таблица) Тогда + + ЧастиИмениТаблицы = СтрРазделить(УзелПоле.Таблица, ".", Ложь); + Если ЧастиИмениТаблицы.Количество() <> 3 Тогда + Возврат; + КонецЕсли; + ИмяТаблицыОбъекта = Контекст.Список + "." + ЧастиИмениТаблицы[2]; + КонецЕсли; + + ЧастиИмениПоля = СтрРазделить(УзелПоле.Имя, ".", Ложь); + Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда + ИмяПоляТаблицы = ЧастиИмениПоля[1]; + ТипыПоляТаблицы = УзелПоле.ТипыПоля[1]; + ИмяТаблицыОбъекта = Контекст.Список + "." + ТабличнаяЧасть; + Иначе + ИмяПоляТаблицы = ЧастиИмениПоля[0]; + ТипыПоляТаблицы = УзелПоле.ТипыПоля[0]; + КонецЕсли; + + ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; + ИмяТаблицыОбъекта = СтрЗаменить(ИмяТаблицыОбъекта, ".", "_"); + + Если СвойстваПоля <> Неопределено Тогда + ОписаниеПоляТаблицы = Новый Структура("Таблица, Поле", ИмяТаблицыОбъекта, ИмяПоляТаблицы); + ПоляТаблицОбъекта.ПоСвойствамПолей.Вставить(СвойстваПоля, ОписаниеПоляТаблицы); + КонецЕсли; + + Если ДополнительнаяТаблица <> Неопределено Тогда + ПоляТаблиц = ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ПоляТаблиц = Неопределено Тогда + ПоляТаблиц = Новый Структура; + ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Вставить(ДополнительнаяТаблица, ПоляТаблиц); + КонецЕсли; + Если Не ПоляТаблиц.Свойство(ИмяТаблицыОбъекта) Тогда + ПоляТаблиц.Вставить(ИмяТаблицыОбъекта, Новый Массив); + КонецЕсли; + ПоляТаблицы = ПоляТаблиц[ИмяТаблицыОбъекта]; // Массив + ПоляТаблицы.Добавить(ИмяПоляТаблицы); + КонецЕсли; + + Если Не ПоляТаблицОбъекта.Состав.Свойство(ИмяТаблицыОбъекта) Тогда + ПоляТаблицОбъекта.Состав.Вставить(ИмяТаблицыОбъекта, Новый Структура); + КонецЕсли; + ПоляТаблицы = ПоляТаблицОбъекта.Состав[ИмяТаблицыОбъекта]; + Если Не ПоляТаблицы.Свойство(ИмяПоляТаблицы) Тогда + ПоляТаблицы.Вставить(ИмяПоляТаблицы, Новый Структура("Тип, Использование", ТипыПоляТаблицы, Ложь)); + КонецЕсли; + +КонецПроцедуры + +// Для функций СвойстваПоля, ТекстУсловияСоединения. +Процедура ДобавитьОпорноеПоле(Контекст, УзелПоле, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) + + Если Не УзелПоле.Свойство("ОсновнойПорядок") Тогда + Возврат; + КонецЕсли; + + Позиция = СтрНайти(УзелПоле.Имя, "."); + Если Позиция = 0 Тогда + ИмяОпорногоПоля = УзелПоле.Имя; + Иначе + ИмяОпорногоПоля = Лев(УзелПоле.Имя, Позиция - 1); + КонецЕсли; + + ОпорныеПоля = Контекст.ОпорныеПоля; + + Если СвойстваПоля <> Неопределено Тогда + ОпорныеПоля.ПоСвойствамПолей.Вставить(СвойстваПоля, ИмяОпорногоПоля); + КонецЕсли; + + Если ДополнительнаяТаблица <> Неопределено Тогда + ИменаОпорныхПолей = ОпорныеПоля.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ИменаОпорныхПолей = Неопределено Тогда + ИменаОпорныхПолей = Новый Массив; + ОпорныеПоля.ПоДополнительнымТаблицам.Вставить(ДополнительнаяТаблица, ИменаОпорныхПолей); + КонецЕсли; + ИменаОпорныхПолей.Добавить(ИмяОпорногоПоля); + КонецЕсли; + + Если ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля) = Неопределено Тогда + ОпорныеПоля.Список.Добавить(ИмяОпорногоПоля, УзелПоле.ОсновнойПорядок); + ТипыОпорногоПоля = УзелПоле.ТипыПоля[0]; + ОпорныеПоля.ТипыПоИменамПолей.Вставить(ИмяОпорногоПоля, ТипыОпорногоПоля); + Если Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + ЗапрещенныеТипы = Новый Массив; + Если ЕстьПростойТип(ТипыОпорногоПоля) Тогда + Для Каждого Тип Из ТипыОпорногоПоля.Типы() Цикл + Если ЭтоПростойТип(Тип) Тогда + ЗапрещенныеТипы.Добавить(Строка(Тип)); + КонецЕсли; + КонецЦикла; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В ограничении доступа списка %1 + |опорное поле %2 содержит простые типы: %3. + | + |Это недопустимо при использовании общего регистра сведений %4. + |Либо исключите простые типы из состава типов опорного поля, + |либо создайте отдельный регистр ключей доступа для этого списка.'"), + Контекст.Список, + ИмяОпорногоПоля, + СтрСоединить(ЗапрещенныеТипы, ", "), + "КлючиДоступаКРегистрам"); + + Если Контекст.Свойство("ОшибкаПриВызовеИсключения") Тогда + Контекст.ОшибкаПриВызовеИсключения.Текст = ТекстОшибки; + КонецЕсли; + ВызватьИсключение ТекстОшибки; + КонецЕсли; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур УдалитьПоляНеиспользуемыхВидовДоступа, ГруппыДополнительныхТаблиц. +Процедура УстановитьИспользованиеПоляТаблицыОбъекта(Контекст, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) + + Если Не Контекст.ЭтоСсылочныйТип Тогда + Возврат; + КонецЕсли; + + ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; + + Если СвойстваПоля <> Неопределено Тогда + ОписаниеПоля = ПоляТаблицОбъекта.ПоСвойствамПолей.Получить(СвойстваПоля); + Если ОписаниеПоля <> Неопределено Тогда + ПоляТаблицОбъекта.Состав[ОписаниеПоля.Таблица][ОписаниеПоля.Поле].Использование = Истина; + КонецЕсли; + Иначе + ПоляТаблиц = ПоляТаблицОбъекта.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ПоляТаблиц <> Неопределено Тогда + Для Каждого ОписаниеПолей Из ПоляТаблиц Цикл + ПоляТаблицы = ПоляТаблицОбъекта.Состав[ОписаниеПолей.Ключ]; + Для Каждого ИмяПоля Из ОписаниеПолей.Значение Цикл + ПоляТаблицы[ИмяПоля].Использование = Истина; + КонецЦикла; + КонецЦикла; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедур УдалитьПоляНеиспользуемыхВидовДоступа, ГруппыДополнительныхТаблиц. +Процедура УстановитьИспользованиеОпорногоПоля(Контекст, СвойстваПоля = Неопределено, ДополнительнаяТаблица = Неопределено) + + ОпорныеПоля = Контекст.ОпорныеПоля; + + Если СвойстваПоля <> Неопределено Тогда + ИмяОпорногоПоля = ОпорныеПоля.ПоСвойствамПолей.Получить(СвойстваПоля); + Если ИмяОпорногоПоля <> Неопределено Тогда + ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля).Пометка = Истина; + КонецЕсли; + Иначе + ИменаОпорныхПолей = ОпорныеПоля.ПоДополнительнымТаблицам.Получить(ДополнительнаяТаблица); + Если ИменаОпорныхПолей <> Неопределено Тогда + Для Каждого ИмяОпорногоПоля Из ИменаОпорныхПолей Цикл + ОпорныеПоля.Список.НайтиПоЗначению(ИмяОпорногоПоля).Пометка = Истина; + КонецЦикла; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗавершитьПодготовкуПолейТаблицОбъекта(Контекст) + + ПоляТаблицОбъекта = Контекст.ПоляТаблицОбъекта; + + Если Не Контекст.ЭтоСсылочныйТип Тогда + ПоляТаблицОбъекта.Удалить("ПоСвойствамПолей"); + ПоляТаблицОбъекта.Удалить("ПоДополнительнымТаблицам"); + Возврат; + КонецЕсли; + + ПолноеИмяОсновнойТаблицы = СтрЗаменить(Контекст.Список, ".", "_"); + ТипСсылки = Тип(ИмяТипаСсылки(Контекст.Список, Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам)); + ОписаниеТипаСсылки = Новый ОписаниеТипов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ТипСсылки)); + СвойстваВидаДоступа = Контекст.СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ПоТипамСсылок.Получить(ТипСсылки); + Если СвойстваВидаДоступа <> Неопределено И Не СвойстваВидаДоступа.НесколькоГруппЗначений Тогда + МетаданныеТаблицы = Метаданные.НайтиПоТипу(ТипСсылки); + РеквизитГруппаДоступа = МетаданныеТаблицы.Реквизиты.Найти("ГруппаДоступа"); + КонецЕсли; + + ЕстьОсновнаяТаблица = Ложь; + ЕстьТабличнаяЧасть = Ложь; + + Для Каждого ОписаниеТаблицы Из ПоляТаблицОбъекта.Состав Цикл + ПоляТаблицы = НовыеПоляТаблицыОбъекта(); + ПоляТаблицы.ПолноеИмяТаблицы = ОписаниеТаблицы.Ключ; + ТаблицаЗначений = Новый ТаблицаЗначений; + ЕстьИспользуемыеПоля = Ложь; + Для Каждого ОписаниеПоля Из ОписаниеТаблицы.Значение Цикл + Если Не ОписаниеПоля.Значение.Использование Тогда + Продолжить; + КонецЕсли; + ЕстьИспользуемыеПоля = Истина; + Если ВРег("Ссылка") = ВРег(ОписаниеПоля.Ключ) Тогда + Продолжить; + КонецЕсли; + ПоляТаблицы.Поля.Добавить(ОписаниеПоля.Ключ); + ТаблицаЗначений.Колонки.Добавить(ОписаниеПоля.Ключ, ОписаниеПоля.Значение.Тип); + КонецЦикла; + Если Не ЕстьИспользуемыеПоля Тогда + Продолжить; + КонецЕсли; + Если ТипЗнч(РеквизитГруппаДоступа) = Тип("ОбъектМетаданных") + И ПоляТаблицы.Поля.Найти("ГруппаДоступа") = Неопределено Тогда + ПоляТаблицы.Поля.Добавить("ГруппаДоступа"); + ТаблицаЗначений.Колонки.Добавить("ГруппаДоступа", РеквизитГруппаДоступа.Тип); + КонецЕсли; + ПоляТаблицы.СписокПолей = СтрСоединить(ПоляТаблицы.Поля, ", "); + ПоляТаблицы.Поля.Вставить(0, "Ссылка"); + ТаблицаЗначений.Колонки.Добавить("Ссылка", ОписаниеТипаСсылки); + ПоляТаблицы.ТаблицаСПолями = Новый ХранилищеЗначения(ТаблицаЗначений); + Если ПоляТаблицы.ПолноеИмяТаблицы = ПолноеИмяОсновнойТаблицы Тогда + ЕстьОсновнаяТаблица = Истина; + Иначе + ЕстьТабличнаяЧасть = Истина; + ПоляТаблицы.ТабличнаяЧасть = Сред(ПоляТаблицы.ПолноеИмяТаблицы, + СтрДлина(ПолноеИмяОсновнойТаблицы) + 2); + КонецЕсли; + ПоляТаблицОбъекта.Результат.Добавить(ПоляТаблицы); + КонецЦикла; + + Если ЕстьТабличнаяЧасть И Не ЕстьОсновнаяТаблица Тогда + ПоляТаблицы = НовыеПоляТаблицыОбъекта(); + ПоляТаблицы.ПолноеИмяТаблицы = ПолноеИмяОсновнойТаблицы; + ПоляТаблицы.Поля.Вставить(0, "Ссылка"); + ТаблицаЗначений = Новый ТаблицаЗначений; + ТаблицаЗначений.Колонки.Добавить("Ссылка", ОписаниеТипаСсылки); + ПоляТаблицы.ТаблицаСПолями = Новый ХранилищеЗначения(ТаблицаЗначений); + ПоляТаблицОбъекта.Результат.Вставить(0, ПоляТаблицы); + КонецЕсли; + + ПоляТаблицОбъекта.Удалить("ПоСвойствамПолей"); + ПоляТаблицОбъекта.Удалить("ПоДополнительнымТаблицам"); + +КонецПроцедуры + +// Для процедуры ЗаполнитьГруппыПолейИДополнительныхТаблиц. +// +// Параметры: +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ЗавершитьПодготовкуОпорныхПолей(Контекст) + + ОпорныеПоля = Контекст.ОпорныеПоля; + ОпорныеПоля.Список.СортироватьПоПредставлению(); + + Для Каждого ЭлементСписка Из ОпорныеПоля.Список Цикл + ОпорныеПоля.Все.Добавить(ЭлементСписка.Значение); + ОпорныеПоля.ТипыВсех.Добавить(Новый ХранилищеЗначения( + ОпорныеПоля.ТипыПоИменамПолей.Получить(ЭлементСписка.Значение))); + + Если ЭлементСписка.Пометка Тогда + ОпорныеПоля.Используемые.Добавить(ЭлементСписка.Значение); + ОпорныеПоля.ТипыИспользуемых.Добавить(Новый ХранилищеЗначения( + ОпорныеПоля.ТипыПоИменамПолей.Получить(ЭлементСписка.Значение))); + КонецЕсли; + КонецЦикла; + + ОпорныеПоля.Удалить("Список"); + ОпорныеПоля.Удалить("ТипыПоИменамПолей"); + ОпорныеПоля.Удалить("ПоСвойствамПолей"); + ОпорныеПоля.Удалить("ПоДополнительнымТаблицам"); + +КонецПроцедуры + +// Для функций ТекстУсловияСоединения, СвойстваПоля. +Функция ИмяПоляСРазверткойОпорногоПоляПоТипам(Псевдоним, УзелПоле) + + Если Не УзелПоле.Свойство("ОсновнойПорядок") + Или Не УзелПоле.Свойство("ТаблицыСледующегоПоля") Тогда + + Возврат Псевдоним + "." + УзелПоле.Имя; + КонецЕсли; + + КоличествоТаблиц = УзелПоле.ТаблицыСледующегоПоля[0].Количество(); + + Если КоличествоТаблиц >= 70 Тогда // Ограничение платформы. + Возврат Псевдоним + "." + УзелПоле.Имя; + КонецЕсли; + + Позиция = СтрНайти(УзелПоле.Имя, "."); + ОпорноеПоле = Псевдоним + "." + Лев(УзелПоле.Имя, Позиция - 1); + ОстальныеПоля = Сред(УзелПоле.Имя, Позиция + 1); + + ИмяПоля = ""; + Для Каждого ИмяТипа Из УзелПоле.ТаблицыСледующегоПоля[0] Цикл + ТекущееИмяПоля = СтрШаблон("ВЫРАЗИТЬ(%1 КАК %2).%3", ОпорноеПоле, ИмяТипа, ОстальныеПоля); // @query-part-1 + Если ЗначениеЗаполнено(ИмяПоля) Тогда + ИмяПоля = + "ЕСТЬNULL(" + ТекущееИмяПоля + ", + | " + ТекстСОтступом(ИмяПоля, " ") + ")"; // @query-part-1 + Иначе + ИмяПоля = ТекущееИмяПоля; + КонецЕсли; + КонецЦикла; + + Возврат ИмяПоля; + +КонецФункции + +// Для функции ПараметрыОграниченияДоступа. +Процедура ЗаполнитьСвойстваПолей(Контекст) + + // 1. Для полей-аргументов узлов сравнения =, <>, В, ЕстьNull + // вычисляется результат сравнения и сохраняется в ключе. + + // 2. Для значений типа Булево сохраняются значения: + // - Перечисления.ДополнительныеЗначенияДоступа.ЗначениеИстина, + // - Перечисления.ДополнительныеЗначенияДоступа.ЗначениеЛожь. + + // 3. Для значений типов Число, Дата, Строка сохраняется результат + // сравнения со значением Истина, как указано в пункте 2. + + Контекст.ОпорныеПоля.Вставить("Список", Новый СписокЗначений); + Контекст.ОпорныеПоля.Вставить("ТипыПоИменамПолей", Новый Соответствие); + Контекст.ОпорныеПоля.Вставить("ПоСвойствамПолей", Новый Соответствие); + Контекст.ПоляТаблицОбъекта.Вставить("ПоСвойствамПолей", Новый Соответствие); + + СвойстваВсехПолей = Новый Соответствие; + ПоляКлючаДоступаДоУпрощения = Контекст.СтруктураОграничения.ВнутренниеДанные.ПоляКлючаДоступа; + Для Каждого ОписаниеПоля Из ПоляКлючаДоступаДоУпрощения Цикл + СвойстваПоля = СвойстваПоля(ОписаниеПоля.Поле, Контекст); + СвойстваВсехПолей.Вставить(ОписаниеПоля.Поле, СвойстваПоля); + КонецЦикла; + Контекст.Вставить("СвойстваВсехПолей", СвойстваВсехПолей); + + Контекст.Вставить("ОставшиесяПоляПослеУпрощения", Новый Соответствие); + Контекст.Вставить("ИсходнаяСтруктураОграничения", Контекст.СтруктураОграничения); + Контекст.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступна", Ложь); + + СтруктураОграничения = Новый Структура(Новый ФиксированнаяСтруктура(Контекст.СтруктураОграничения)); // см. СтруктураОграничения + Контекст.Вставить("ИмяПрава", "Чтение"); + СтруктураОграничения.ОграничениеЧтения = УпрощенноеУсловиеОграничения( + СтруктураОграничения.ОграничениеЧтения, Контекст, Истина); + Контекст.Вставить("ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения", + Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна); + Контекст.Вставить("ИмяПрава", "Изменение"); + СтруктураОграничения.ОграничениеИзменения = УпрощенноеУсловиеОграничения( + СтруктураОграничения.ОграничениеИзменения, Контекст, Истина); + Контекст.Вставить("СтруктураОграничения", СтруктураОграничения); + + Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступнаВОграниченииЧтения Тогда + ДобавитьВидОграниченияПрав("ФункцияПравоДоступаИлиРольДоступна", + Новый Структура("Чтение, Изменение", Истина, Ложь), Контекст); + КонецЕсли; + Если Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна Тогда + ДобавитьВидОграниченияПрав("ФункцияПравоДоступаИлиРольДоступна", + Новый Структура("Чтение, Изменение", Ложь, Истина), Контекст); + КонецЕсли; + + ПоляКлючаДоступаПослеУпрощения = Новый Массив; // Массив Из см. НовоеПолеКлючаДоступа + Для Каждого ОписаниеПоля Из ПоляКлючаДоступаДоУпрощения Цикл + РодителиПоля = Контекст.ОставшиесяПоляПослеУпрощения.Получить(ОписаниеПоля.Поле); // Массив из см. ОписаниеУзла + Если РодителиПоля = Неопределено Тогда + Продолжить; + КонецЕсли; + РодителиПоля.Добавить(Новый Структура("Узел", "")); + ОписаниеПоля.Вставить("Родители", РодителиПоля); + ПоляКлючаДоступаПослеУпрощения.Добавить(ОписаниеПоля); + КонецЦикла; + Контекст.Вставить("ПоляКлючаДоступаПослеУпрощения", ПоляКлючаДоступаПослеУпрощения); + + Контекст.Вставить("СвойстваПолейКлючаДоступа", Новый Соответствие); + Контекст.Вставить("ОбратныйТипПользователя", ?(Контекст.ДляВнешнихПользователей, + Тип("СправочникСсылка.Пользователи"), Тип("СправочникСсылка.ВнешниеПользователи"))); + Контекст.Вставить("ОбратныйТипГруппыПользователей", ?(Контекст.ДляВнешнихПользователей, + Тип("СправочникСсылка.ГруппыПользователей"), Тип("СправочникСсылка.ГруппыВнешнихПользователей"))); + ДобавленныеПоля = Новый Соответствие; + ИменаПолейДляЗапроса = Новый Массив; + Для Каждого ОписаниеПоля Из ПоляКлючаДоступаПослеУпрощения Цикл + СвойстваПоля = СвойстваВсехПолей.Получить(ОписаниеПоля.Поле); // см. СвойстваПоля + СвойстваПоля.Вставить("Чтение", ОписаниеПоля.Чтение); + СвойстваПоля.Вставить("Изменение", ОписаниеПоля.Изменение); + УточнитьСвойстваПоляСравнения(СвойстваПоля, ОписаниеПоля, Контекст); + НаборПолей = НаборПолейУсловияКогда(СвойстваПоля, ОписаниеПоля, Контекст); + Для Каждого СвойстваПоля Из НаборПолей Цикл + ДобавитьСвойстваТиповПоля(СвойстваПоля, ОписаниеПоля, Контекст); + ОдинаковыеПоля = ДобавленныеПоля.Получить(ВРег(СвойстваПоля.ИмяПоляДляЗапроса)); + Если ОдинаковыеПоля = Неопределено Тогда + ОдинаковыеПоля = Новый Массив; + ДобавленныеПоля.Вставить(ВРег(СвойстваПоля.ИмяПоляДляЗапроса), ОдинаковыеПоля); + ИменаПолейДляЗапроса.Добавить(СвойстваПоля.ИмяПоляДляЗапроса); + КонецЕсли; + ОдинаковыеПоля.Добавить(СвойстваПоля); + КонецЦикла; + КонецЦикла; + + СвойстваПолей = Новый Массив; // Массив из см. СвойстваПоля + СовмещенныеПоля = Новый Соответствие; + Для Каждого ИмяПоляДляЗапроса Из ИменаПолейДляЗапроса Цикл + ОдинаковыеПоля = ДобавленныеПоля.Получить(ВРег(ИмяПоляДляЗапроса)); + ОбработанныеОдинаковыеПоля = Новый Массив; + Для Каждого СвойстваПоля Из ОдинаковыеПоля Цикл + СовмещенноеПоле = ОбработанноеСовмещенноеПоле(ОбработанныеОдинаковыеПоля, СвойстваПоля); + Если СовмещенноеПоле <> Неопределено Тогда + СовмещенныеПоля.Вставить(СвойстваПоля, СовмещенноеПоле); + Продолжить; + КонецЕсли; + ОбработанныеОдинаковыеПоля.Добавить(СвойстваПоля); + КонецЦикла; + Для Каждого СвойстваПоля Из ОбработанныеОдинаковыеПоля Цикл + СвойстваПолей.Добавить(СвойстваПоля); + КонецЦикла; + КонецЦикла; + + Для Каждого Описание Из Контекст.СвойстваПолейКлючаДоступа Цикл + СовмещенноеПоле = СовмещенныеПоля.Получить(Описание.Значение); + Если СовмещенноеПоле <> Неопределено Тогда + Контекст.СвойстваПолейКлючаДоступа[Описание.Ключ] = СовмещенноеПоле; + КонецЕсли; + КонецЦикла; + + Для Каждого СвойстваПоля Из СвойстваПолей Цикл + СвойстваПоля.Вставить("ТипыСохраненияТиповКонфигурации", Новый Массив); + СвойстваПоля.Вставить("ТипыСохраненияТиповРасширений", Новый Массив); + СвойстваПоля.Вставить("ТипыСохраненияТиповПростых", Новый Массив); + + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипов Цикл + ОбъектМетаданных = Неопределено; + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип, ОбъектМетаданных); + + Если СтрНайти(ИмяТипа, ".") = 0 Тогда + СвойстваПоля.ТипыСохраненияТиповПростых.Добавить(Тип); + + ИначеЕсли ОбъектМетаданных.РасширениеКонфигурации() = Неопределено Тогда + СвойстваПоля.ТипыСохраненияТиповКонфигурации.Добавить(Тип); + Иначе + СвойстваПоля.ТипыСохраненияТиповРасширений.Добавить(Тип); + КонецЕсли; + КонецЦикла; + КонецЦикла; + + Контекст.Вставить("СвойстваПолей", СвойстваПолей); + +КонецПроцедуры + +// Для процедуры ЗаполнитьСвойстваПолей. +Функция УпрощенноеУсловиеОграничения(Знач Условие, Контекст, КореньУсловия = Ложь, ДобавитьОставшиесяПоля = Истина) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат Условие; + КонецЕсли; + + ОставшиесяПоляПослеУпрощения = Контекст.ОставшиесяПоляПослеУпрощения; + Контекст.ОставшиесяПоляПослеУпрощения = Новый Соответствие; + + Если Условие.Узел = "Поле" Тогда + Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие, Новый Массив); + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + БезусловныйРезультат = ?(Условие.Узел = "И", Ложь, Истина); + ЕстьБезусловныйРезультат = Ложь; + Аргументы = Новый Массив; + ЕстьФункцияПравоДоступаИлиРольДоступна = Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна; + Для Каждого ТекущийАргумент Из Условие.Аргументы Цикл + Аргумент = УпрощенноеУсловиеОграничения(ТекущийАргумент, Контекст); + Если Аргумент.Узел <> "Константа" Тогда + Аргументы.Добавить(Аргумент); + ИначеЕсли Аргумент.Значение = БезусловныйРезультат Тогда + ЕстьБезусловныйРезультат = Истина; + КонецЕсли; + КонецЦикла; + Если ЕстьБезусловныйРезультат Или Аргументы.Количество() = 0 Тогда + Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна = ЕстьФункцияПравоДоступаИлиРольДоступна; + Условие = Новый Структура("Узел, Значение", "Константа", + ?(ЕстьБезусловныйРезультат, БезусловныйРезультат, Истина)); + ИначеЕсли Аргументы.Количество() = 1 Тогда + Условие = Аргументы[0]; + Иначе + Условие = Новый Структура("Узел, Аргументы", Условие.Узел, Аргументы); + КонецЕсли; + + ИначеЕсли Условие.Узел = "Не" Тогда + Аргумент = УпрощенноеУсловиеОграничения(Условие.Аргумент, Контекст); + Если Аргумент.Узел = "Константа" Тогда + Условие = Новый Структура("Узел, Значение", "Константа", + ?(Аргумент.Значение = "Пусто", "Пусто", Не Аргумент.Значение)); + Иначе + Условие = Новый Структура("Узел, Аргумент", Условие.Узел, Аргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" + Или Условие.Узел = "ЕстьNull" + Или Условие.Узел = "ТипЗначения" Тогда + + Аргумент = УпрощенноеУсловиеОграничения(Условие.Аргумент, Контекст); + Если Аргумент.Узел = "Константа" Тогда + Условие = Аргумент; + Иначе + Условие = Новый Структура("Узел, Аргумент", Условие.Узел, Аргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "=" + Или Условие.Узел = "<>" Тогда + + ПервыйАргумент = УпрощенноеУсловиеОграничения(Условие.ПервыйАргумент, Контекст); + ВторойАргумент = УпрощенноеУсловиеОграничения(Условие.ВторойАргумент, Контекст); + + Если ПервыйАргумент.Узел = "Константа" + И ВторойАргумент.Узел = "Константа" Тогда + + Условие = Новый Структура("Узел, Значение", "Константа", ?(Условие.Узел = "=", + ПервыйАргумент.Значение = ВторойАргумент.Значение, + ПервыйАргумент.Значение <> ВторойАргумент.Значение)); + Иначе + Условие = Новый Структура("Узел, ПервыйАргумент, ВторойАргумент", + Условие.Узел, ПервыйАргумент, ВторойАргумент); + КонецЕсли; + + ИначеЕсли Условие.Узел = "В" Тогда + Условие = Новый Структура("Узел, Искомое, Значения", + Условие.Узел, + УпрощенноеУсловиеОграничения(Условие.Искомое, Контекст), + Условие.Значения); + + ИначеЕсли Условие.Узел = "Выбор" Тогда + ВсеЗначенияВыбораИстина = Истина; + ВсеЗначенияВыбораЛожь = Истина; + ВсеЗначенияВыбораПусто = Истина; + Выбор = Новый Структура("Узел, Выбор, Когда, Иначе", Условие.Узел, Условие.Выбор, Новый Массив); + НовоеУсловиеИначе = Неопределено; + Для Каждого Когда Из Условие.Когда Цикл + Если Условие.Выбор = Неопределено Тогда + УсловиеКогда = УпрощенноеУсловиеОграничения(Когда.Условие, Контекст); + Если УсловиеКогда.Узел = "Константа" Тогда + Если УсловиеКогда.Значение Тогда + НовоеУсловиеИначе = ?(НовоеУсловиеИначе = Неопределено, Когда.Значение, НовоеУсловиеИначе); + КонецЕсли; + ЗначениеКогда = УпрощенноеУсловиеОграничения(Когда.Значение, Контекст, , Ложь); + Продолжить; + КонецЕсли; + Иначе + УсловиеКогда = Когда.Условие; + КонецЕсли; + ЗначениеКогда = УпрощенноеУсловиеОграничения(Когда.Значение, Контекст); + ОбработатьУпрощенноеЗначениеВыбора(ЗначениеКогда, + ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто); + СтруктураКогда = Новый Структура("Условие, Значение", УсловиеКогда, ЗначениеКогда); + Выбор.Когда.Добавить(СтруктураКогда); + КонецЦикла; + УсловиеИначе = ?(НовоеУсловиеИначе = Неопределено, Условие.Иначе, НовоеУсловиеИначе); + Выбор.Иначе = УпрощенноеУсловиеОграничения(УсловиеИначе, Контекст); + ОбработатьУпрощенноеЗначениеВыбора(Выбор.Иначе, + ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто); + Если ВсеЗначенияВыбораИстина Или ВсеЗначенияВыбораЛожь Или ВсеЗначенияВыбораПусто Тогда + Условие = Новый Структура("Узел, Значение", "Константа", + ?(ВсеЗначенияВыбораПусто, "Пусто", ВсеЗначенияВыбораИстина)); + ИначеЕсли Выбор.Когда.Количество() = 0 Тогда + Условие = Выбор.Иначе; + Иначе + Условие = Выбор; + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" Тогда + + СвойстваПоля = Контекст.СвойстваВсехПолей.Получить(Условие.Поле); + Если СвойстваПоля = Неопределено Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При упрощении условия ограничения права %1 + |списка ""%2"" + |свойства поля не определены для узла ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + ТипыКонечногоПоля = СвойстваПоля.ТипКонечногоПоля.Типы(); + + Если Условие.Узел = "ЗначениеРазрешено" Тогда + Результат = РезультатФункцииЗначениеРазрешено(Условие, ТипыКонечногоПоля, Контекст); + Иначе + Результат = РезультатФункцииПравоОбъектаРазрешено(Условие, ТипыКонечногоПоля, Контекст); + КонецЕсли; + + Если Результат <> Неопределено Тогда + Условие = Новый Структура("Узел, Значение", "Константа", Результат); + Иначе + Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие.Поле, Новый Массив); + КонецЕсли; + + ИначеЕсли Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + Контекст.ОставшиесяПоляПослеУпрощения.Вставить(Условие.Поле, Новый Массив); + + ИначеЕсли Условие.Узел = "ПравоДоступа" + Или Условие.Узел = "РольДоступна" Тогда + + Контекст.ЕстьФункцияПравоДоступаИлиРольДоступна = Истина; + + ИначеЕсли Условие.Узел <> "Константа" + И Условие.Узел <> "Значение" + И Условие.Узел <> "Тип" Тогда + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'При упрощении условия ограничения права %1 + |списка ""%2"" + |узел не поддерживается ""%3"".'"), + Контекст.ИмяПрава, + Контекст.Список, + Условие.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + Если Условие.Узел = "Константа" Тогда + Если КореньУсловия И Условие.Значение = "Пусто" Тогда + Условие.Значение = Истина; + КонецЕсли; + ИначеЕсли ДобавитьОставшиесяПоля Тогда + Для Каждого КлючИЗначение Из Контекст.ОставшиесяПоляПослеУпрощения Цикл + Если Условие.Узел <> "Поле" Тогда + РодителиПоля = КлючИЗначение.Значение; // Массив Из см. ОписаниеУзла + РодителиПоля.Добавить(Условие); + КонецЕсли; + ОставшиесяПоляПослеУпрощения.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение); + КонецЦикла; + КонецЕсли; + Контекст.ОставшиесяПоляПослеУпрощения = ОставшиесяПоляПослеУпрощения; + + Возврат Условие; + +КонецФункции + +// Для функции УпрощенноеУсловиеОграничения. +Процедура ОбработатьУпрощенноеЗначениеВыбора(Условие, + ВсеЗначенияВыбораИстина, ВсеЗначенияВыбораЛожь, ВсеЗначенияВыбораПусто) + + Если Условие.Узел <> "Константа" Тогда + ВсеЗначенияВыбораИстина = Ложь; + ВсеЗначенияВыбораЛожь = Ложь; + ВсеЗначенияВыбораПусто = Ложь; + + ИначеЕсли Условие.Значение = "Пусто" Тогда + ВсеЗначенияВыбораИстина = Ложь; + ВсеЗначенияВыбораЛожь = Ложь; + + ИначеЕсли Условие.Значение Тогда + ВсеЗначенияВыбораЛожь = Ложь; + ВсеЗначенияВыбораПусто = Ложь; + Иначе + ВсеЗначенияВыбораИстина = Ложь; + ВсеЗначенияВыбораПусто = Ложь; + КонецЕсли; + +КонецПроцедуры + +// Для функции УпрощенноеУсловиеОграничения. +Функция РезультатФункцииЗначениеРазрешено(Условие, ТипыКонечногоПоля, Контекст) + + СвойстваВидовДоступаПоТипам = Контекст.СвойстваВидовДоступа.ПоТипамГруппИЗначений; + ОтключеноКакЛожь = УточнениеТипа(Условие, "Отключено") = "Ложь"; + + РезультатВсегдаЛожь = Истина; + РезультатВсегдаИстина = Истина; + ЕстьРезультатПусто = Ложь; + + Для Каждого Тип Из ТипыКонечногоПоля Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Условие, ИмяТипа); + Если Уточнение = "Истина" Тогда + РезультатВсегдаЛожь = Ложь; + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + РезультатВсегдаИстина = Ложь; + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Условие, ИмяТипа) Тогда + РезультатВсегдаИстина = Ложь; + Продолжить; + КонецЕсли; + + СвойстваВидаДоступа = СвойстваВидовДоступаПоТипам.Получить(Тип); + Если СвойстваВидаДоступа = Неопределено Тогда + РезультатВсегдаЛожь = Ложь; + Продолжить; + КонецЕсли; + + Если Не ТипЗначенийДоступаИспользуется(Контекст, СвойстваВидаДоступа.ТипЗначений) Тогда + Если Контекст.НеиспользуемыеТипыЗначенийДоступа.Найти(СвойстваВидаДоступа.ТипЗначений) = Неопределено Тогда + Контекст.НеиспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); + КонецЕсли; + Если ОтключеноКакЛожь Тогда + РезультатВсегдаИстина = Ложь; + ЕстьРезультатПусто = Истина; + Иначе + РезультатВсегдаЛожь = Ложь; + КонецЕсли; + Иначе + РезультатВсегдаИстина = Ложь; + РезультатВсегдаЛожь = Ложь; + КонецЕсли; + КонецЦикла; + + Если РезультатВсегдаИстина Тогда + Возврат Истина; + ИначеЕсли РезультатВсегдаЛожь Тогда + Если ЕстьРезультатПусто Тогда + Возврат "Пусто"; + Иначе + Возврат Ложь; + КонецЕсли; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для функции РезультатФункцииЗначениеРазрешено и процедуры ДобавитьСвойстваТиповПоля. +Функция ТипЗначенийДоступаИспользуется(Контекст, ТипЗначений) + + Если Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Неопределено Тогда + ИспользуемыеТипыЗначений = Контекст.ИспользуемыеТипыЗначений.ДляИБ; + Иначе + ИспользуемыеТипыЗначений = Контекст.ИспользуемыеТипыЗначений.ПоТаблицам.Получить(Контекст.Список); + КонецЕсли; + + Если ИспользуемыеТипыЗначений = Неопределено Тогда + Если Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы = Контекст.Список + Или Не ЗначениеЗаполнено(Контекст.ИспользуемыеТипыЗначений.ПолноеИмяТаблицы) Тогда + Возврат Ложь; + КонецЕсли; + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ошибка вызова функции %1 общего модуля %2: + |Для таблицы %3 + |не заполнены используемые типы значений доступа.'"), + "ТипЗначенийДоступаИспользуется", + "УправлениеДоступомСлужебный", + Контекст.Список); + ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации); + КонецЕсли; + + Возврат ИспользуемыеТипыЗначений.Получить(ТипЗначений) <> Неопределено; + +КонецФункции + +// Для функции УпрощенноеУсловиеОграничения. +Функция РезультатФункцииПравоОбъектаРазрешено(Условие, ТипыКонечногоПоля, Контекст) + + Если Контекст.ОграничениеДоступаВключено Тогда + Возврат Неопределено; + КонецЕсли; + + РезультатВсегдаИстина = Истина; + + Для Каждого Тип Из ТипыКонечногоПоля Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Условие, ИмяТипа); + Если Уточнение = "Истина" Тогда + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + РезультатВсегдаИстина = Ложь; + Прервать; + КонецЕсли; + + Если Не ТипПроверяется(Условие, ИмяТипа) Тогда + РезультатВсегдаИстина = Ложь; + Прервать; + КонецЕсли; + + Значение = Контекст.ТипыВладельцевНастроекПрав.Получить(Тип); + Если Значение = Неопределено + Или ВРег(Контекст.Список) <> ВРег(Значение[0].ВладелецПрав) Тогда + + РезультатВсегдаИстина = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + + Если РезультатВсегдаИстина Тогда + Возврат Истина; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ЗаполнитьСвойстваПолей. +Функция ОбработанноеСовмещенноеПоле(ОбработанныеОдинаковыеПоля, СвойстваПоля) + + Для Каждого Поле Из ОбработанныеОдинаковыеПоля Цикл + Совместимо = Истина; + Если Поле.ПсевдонимТаблицы = "ТекущийСписок" + И Поле.НесколькоГруппЗначений <> СвойстваПоля.НесколькоГруппЗначений Тогда + Продолжить; + КонецЕсли; + // По пустой ссылке на ключ доступа или значению Null невозможно определить тип значения, + // поэтому сохранение ключа доступа несовместимо с остальными вариантами. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияКлючейДоступа Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияГруппЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Тип Из Поле.ТипыСохраненияКлючейДоступа Цикл + Если СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияГруппЗначений.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если Не Совместимо Тогда + Продолжить; + КонецЕсли; + // По значению Null вместо группы значений невозможно определить тип значения, + // поэтому сохранение группы значений несовместимо с остальными вариантами. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияГруппЗначений Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Тип Из Поле.ТипыСохраненияГруппЗначений Цикл + Если СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + // Вместо простых типов сохраняется значения ТипРазрешенный или ТипЗапрещенный, + // поэтому сохранение запрещенного простого типа несовместимо с остальными вариантами. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаЗапрещенный Цикл + Если Не ЭтоПростойТип(Тип) Тогда + Продолжить; + КонецЕсли; + Если Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Для Каждого Тип Из Поле.ТипыСохраненияТипаЗапрещенный Цикл + Если Не ЭтоПростойТип(Тип) Тогда + Продолжить; + КонецЕсли; + Если СвойстваПоля.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или СвойстваПоля.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Совместимо = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + Если Не Совместимо Тогда + Продолжить; + КонецЕсли; + // Объединение уточнений специальных значений. + Поле.ЕстьУточнениеNull = + Поле.ЕстьУточнениеNull Или СвойстваПоля.ЕстьУточнениеNull; + Поле.ЕстьУточнениеНеопределено = + Поле.ЕстьУточнениеНеопределено Или СвойстваПоля.ЕстьУточнениеНеопределено; + Поле.ЕстьТипВедущегоСписка = + Поле.ЕстьТипВедущегоСписка Или СвойстваПоля.ЕстьТипВедущегоСписка; + Поле.ЕстьТипВладельцаНастроекПрав = + Поле.ЕстьТипВладельцаНастроекПрав Или СвойстваПоля.ЕстьТипВладельцаНастроекПрав; + Поле.ЕстьПроверкаАвторизованногоПользователя = + Поле.ЕстьПроверкаАвторизованногоПользователя Или СвойстваПоля.ЕстьПроверкаАвторизованногоПользователя; + // Объединение типов сохранения пустой ссылки. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияПустойСсылки Цикл + Если Поле.ТипыСохраненияПустойСсылки.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Поле.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения значения ТипРазрешенный. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаРазрешенный Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); + Поле.ТипыСохраненияТипов.Добавить(Тип); + Продолжить; + КонецЕсли; + Поле.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения значения ТипЗапрещенный. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипаЗапрещенный Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); + Поле.ТипыСохраненияТипов.Добавить(Тип); + Продолжить; + КонецЕсли; + Поле.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения типа значения. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияТипов Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено + Или Поле.ТипыСохраненияТипов.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); + КонецЕсли; + Поле.ТипыСохраненияТипов.Добавить(Тип); + КонецЦикла; + // Объединение типов сохранения значения. + Для Каждого Тип Из СвойстваПоля.ТипыСохраненияЗначений Цикл + Если Поле.ТипыСохраненияЗначений.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипов.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипов.Удалить(Индекс); + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаЗапрещенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаЗапрещенный.Удалить(Индекс); + КонецЕсли; + Индекс = Поле.ТипыСохраненияТипаРазрешенный.Найти(Тип); + Если Индекс <> Неопределено Тогда + Поле.ТипыСохраненияТипаРазрешенный.Удалить(Индекс); + КонецЕсли; + Поле.ТипыСохраненияЗначений.Добавить(Тип); + КонецЦикла; + // Объединение неиспользуемых типов значений доступа. + Для Каждого Тип Из СвойстваПоля.НеиспользуемыеТипыЗначенийДоступа Цикл + Если Поле.НеиспользуемыеТипыЗначенийДоступа.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Поле.НеиспользуемыеТипыЗначенийДоступа.Добавить(Тип); + КонецЦикла; + // Объединение используемых типов значений доступа. + Для Каждого Тип Из СвойстваПоля.ИспользуемыеТипыЗначенийДоступа Цикл + Если Поле.ИспользуемыеТипыЗначенийДоступа.Найти(Тип) <> Неопределено Тогда + Продолжить; + КонецЕсли; + Поле.ИспользуемыеТипыЗначенийДоступа.Добавить(Тип); + КонецЦикла; + Поле.Чтение = Поле.Чтение Или СвойстваПоля.Чтение; + Если Поле.ТипыСтрокой <> СвойстваПоля.ТипыСтрокой Тогда + Поле.ТипыСтрокой = Поле.ТипыСтрокой + Символы.ПС + СвойстваПоля.ТипыСтрокой; + КонецЕсли; + Возврат Поле; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ЗаполнитьСвойстваПолей. +Процедура УточнитьСвойстваПоляСравнения(Свойства, ОписаниеПоля, Контекст) + + Контекст.СвойстваПолейКлючаДоступа.Вставить(ОписаниеПоля.Поле, Свойства); + + Родитель = ОписаниеПоля.Родители[0]; + + Узлы = ",ТипЗначения,=,<>,В,ЕстьNull,"; // В ключ сохраняется результат сравнения. + Если СтрНайти(Узлы, "," + Родитель.Узел + ",") = 0 Тогда + Возврат; + КонецЕсли; + + Если Родитель.Узел = "ТипЗначения" Тогда + РодительУзлаСравнения = ОписаниеПоля.Родители[1]; + + Если РодительУзлаСравнения.ВторойАргумент = Родитель Тогда + УзелТип = РодительУзлаСравнения.ПервыйАргумент; // См. ОписаниеУзла + УзелТипЗначения = РодительУзлаСравнения.ВторойАргумент; + Иначе + УзелТип = РодительУзлаСравнения.ВторойАргумент; // См. ОписаниеУзла + УзелТипЗначения = РодительУзлаСравнения.ПервыйАргумент; + КонецЕсли; + Контекст.СвойстваПолейКлючаДоступа.Вставить(УзелТипЗначения, Свойства); + + ВыражениеТипаЗначения = "ТИПЗНАЧЕНИЯ(" + Свойства.ИмяПоляДляЗапроса + ")"; // @query-part-1 + ВыражениеТипа = "ТИП(" + УзелТип.Имя + ")"; // @query-part-1 + ОднойСтрокой = СтрДлина(ВыражениеТипаЗначения) + СтрДлина(ВыражениеТипа) < 60; + + Свойства.ИмяПоляДляЗапроса = ВыражениеТипаЗначения + ?(ОднойСтрокой, " ", " + | ") + РодительУзлаСравнения.Узел + " " + ВыражениеТипа; + + ИначеЕсли Родитель.Узел = "=" + Или Родитель.Узел = "<>" Тогда + + УзелЗначениеИлиКонстанта = ?(Родитель.ВторойАргумент = ОписаниеПоля.Поле, + Родитель.ПервыйАргумент, Родитель.ВторойАргумент); + + ВыражениеУзла = ВыражениеУзлаЗначениеИлиКонстанта(УзелЗначениеИлиКонстанта); + ОднойСтрокой = СтрДлина(Свойства.ИмяПоляДляЗапроса) + СтрДлина(ВыражениеУзла) < 60; + + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + ?(ОднойСтрокой, " ", " + | ") + Родитель.Узел + " " + ВыражениеУзла; + + ИначеЕсли Родитель.Узел = "В" Тогда + + СписокЗначений = ""; + Для Каждого УзелЗначениеИлиКонстанта Из Родитель.Значения Цикл + СписокЗначений = СписокЗначений + ?(СписокЗначений = "", "", ","); + ПоследняяСтрока = СтрПолучитьСтроку(СписокЗначений, СтрЧислоСтрок(СписокЗначений)); + Если СтрДлина(ПоследняяСтрока) > 40 Тогда + СписокЗначений = СписокЗначений + " + | "; + Иначе + СписокЗначений = СписокЗначений + " "; + КонецЕсли; + СписокЗначений = СписокЗначений + + ВыражениеУзлаЗначениеИлиКонстанта(УзелЗначениеИлиКонстанта); + КонецЦикла; + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " + | В (" + СписокЗначений + ")"; + + Иначе // Родитель.Узел = "ЕстьNull". + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " ЕСТЬ NULL"; + Свойства.Вставить("ПроверкаЕстьNull"); + КонецЕсли; + + Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); + +КонецПроцедуры + +// Для процедуры ЗаполнитьСвойстваПолей. +Функция НаборПолейУсловияКогда(ИсходныеСвойстваПоля, ОписаниеПоля, Контекст) + + Родитель = ОписаниеПоля.Родители[0]; + НаборПолей = Новый Массив; + + Если Родитель.Узел <> "Выбор" + Или Родитель.Выбор = Неопределено Тогда + + НаборПолей.Добавить(ИсходныеСвойстваПоля); + Возврат НаборПолей; + КонецЕсли; + + // Для "ВЫБОР <Поле> КОГДА <Значение>" в ключ сохраняется + // результат сравнения "<Поле> = <Значение>". + + Для Каждого ОписаниеКогда Из Родитель.Когда Цикл + ФиксированныеСвойства = Новый ФиксированнаяСтруктура(ИсходныеСвойстваПоля); + Свойства = Новый Структура(ФиксированныеСвойства); + + ВыражениеУзла = ВыражениеУзлаЗначениеИлиКонстанта(ОписаниеКогда.Условие); + ОднойСтрокой = СтрДлина(Свойства.ИмяПоляДляЗапроса) + СтрДлина(ВыражениеУзла) < 60; + + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + ?(ОднойСтрокой, " = ", " + | = ") + ВыражениеУзла; + + Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); + НаборПолей.Добавить(Свойства); + + Контекст.СвойстваПолейКлючаДоступа.Вставить(ОписаниеКогда.Условие, Свойства); + КонецЦикла; + + Возврат НаборПолей; + +КонецФункции + +// Для функций СвойстваПоля, УточнитьСвойстваПоляСравнения, НаборПолейУсловияКогда. +Функция БезЗначенияNull(СвойстваПоля) + + Возврат СтрЧислоВхождений(СвойстваПоля.ИмяПоляДляЗапроса, ".") = 1 + И Не СвойстваПоля.Свойство("ПолеСодержитNull") + И СтрНачинаетсяС(СвойстваПоля.ИмяПоляДляЗапроса, "ТекущийСписок."); + +КонецФункции + +// Для процедуры ЗаполнитьСвойстваПолей. +// +// Параметры: +// Свойства - см. СвойстваПоля +// ОписаниеПоля - см. НовоеПолеКлючаДоступа +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// +Процедура ДобавитьСвойстваТиповПоля(Свойства, ОписаниеПоля, Контекст) + + Свойства.Вставить("ТипыСохраненияКлючейДоступа", Новый Массив); + Свойства.Вставить("ТипыСохраненияГруппЗначений", Новый Массив); + Свойства.Вставить("ТипыСохраненияЗначений", Новый Массив); + Свойства.Вставить("ТипыСохраненияПустойСсылки", Новый Массив); + Свойства.Вставить("ТипыСохраненияТипов", Новый Массив); + Свойства.Вставить("ТипыСохраненияТипаЗапрещенный", Новый Массив); + Свойства.Вставить("ТипыСохраненияТипаРазрешенный", Новый Массив); + Свойства.Вставить("НеиспользуемыеТипыЗначенийДоступа", Новый Массив); + Свойства.Вставить("ИспользуемыеТипыЗначенийДоступа", Новый Массив); + Свойства.Вставить("НесколькоГруппЗначений", Ложь); + Свойства.Вставить("ЭтоСписокЗначенийДоступаСГруппамиЗначений", Ложь); + Свойства.Вставить("ЕстьУточнениеNull", Ложь); + Свойства.Вставить("ЕстьУточнениеНеопределено", Ложь); + Свойства.Вставить("ЕстьТипВедущегоСписка", Ложь); + Свойства.Вставить("ЕстьТипВладельцаНастроекПрав", Ложь); + Свойства.Вставить("ЕстьПроверкаАвторизованногоПользователя", Ложь); + + Родитель = ОписаниеПоля.Родители[0]; + + Если Родитель.Узел = "ЧтениеОбъектаРазрешено" + Или Родитель.Узел = "ИзменениеОбъектаРазрешено" + Или Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ИзменениеСпискаРазрешено" + Или Родитель.Узел = "ЗначениеРазрешено" + Или Родитель.Узел = "ЭтоАвторизованныйПользователь" Тогда + + ЕстьУточнениеПустойСсылки = ТипУточнен(Родитель, "ПустаяСсылка"); + Свойства.ЕстьУточнениеNull = ТипУточнен(Родитель, "Null") Или Свойства.Свойство("ЕстьВыразить"); + Свойства.ЕстьУточнениеНеопределено = ТипУточнен(Родитель, "Неопределено"); + КонецЕсли; + + Если Родитель.Узел = "ЧтениеОбъектаРазрешено" + Или Родитель.Узел = "ИзменениеОбъектаРазрешено" + Или Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ИзменениеСпискаРазрешено" Тогда + + Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Родитель, ИмяТипа); + Если Уточнение = "Истина" Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если ЭтоПростойТип(Тип) Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") + Или Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Свойства.ЕстьТипВедущегоСписка = Истина; + + ВидОграничения = ?(Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ЧтениеОбъектаРазрешено", "ПравоЧтения", "ПравоИзменения"); + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Если Родитель.Узел = "ЧтениеСпискаРазрешено" + Или Родитель.Узел = "ИзменениеСпискаРазрешено" Тогда + + Свойства.ТипыСохраненияТипов.Добавить(Тип); + Свойства.ЕстьТипВедущегоСписка = Истина; + + ВидОграничения = ?(Родитель.Узел = "ЧтениеСпискаРазрешено", "ПравоЧтения", "ПравоИзменения"); + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено + И Не Контекст.ИспользуетсяОграничениеПоВладельцу + И ( Контекст.СпискиСОграничением.Получить(ИмяТипа) = Неопределено + Или Контекст.СпискиСОтключеннымОграничением.Получить(ИмяТипа) <> Неопределено) Тогда + + Свойства.ТипыСохраненияТипов.Добавить(Тип); + Свойства.ЕстьТипВедущегоСписка = Истина; + + ВидОграничения = ?(Родитель.Узел = "ЧтениеОбъектаРазрешено", "ПравоЧтения", "ПравоИзменения"); + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Если ЕстьУточнениеПустойСсылки Тогда + Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЕсли; + + ИмяВедущегоПрава = ?(Родитель.Узел = "ЧтениеОбъектаРазрешено", "Чтение", "Изменение"); + + Значение = Контекст.ТипыВладельцевНастроекПрав.Получить(Тип); + Если Значение <> Неопределено + И (ВРег(Контекст.Список) = ВРег(Значение[0].ВладелецПрав) + Или Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей <> Неопределено + И Не Контекст.ИспользуетсяОграничениеПоВладельцу) Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Свойства.ЕстьТипВладельцаНастроекПрав = Истина; + ВидОграничения = "НастройкиПрав." + ИмяТипа + "." + ИмяВедущегоПрава; + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + Продолжить; + КонецЕсли; + + Свойства.ТипыСохраненияКлючейДоступа.Добавить(Тип); + Если Контекст.СпискиСЗаписьюКлючейДляЗависимыхСписковБезКлючей = Неопределено + Или ( Контекст.СпискиСОграничением.Получить(ИмяТипа) <> Неопределено + И Контекст.СпискиСОтключеннымОграничением.Получить(ИмяТипа) = Неопределено) Тогда + + ДобавитьВедущийСписокПоПолюСсылка(Контекст.ВедущиеСпискиПоКлючамДоступа, + ИмяТипа, ОписаниеПоля, Свойства, Контекст); + + ВидОграничения = "Объект." + ИмяТипа + "." + ИмяВедущегоПрава; + ДобавитьВидОграниченияПрав(ВидОграничения, Свойства, Контекст, Истина); + КонецЕсли; + КонецЦикла; + + Возврат; + КонецЕсли; + + Если Родитель.Узел = "ЗначениеРазрешено" Тогда + СвойстваВидовДоступа = Контекст.СвойстваВидовДоступа; + ОтключеноКакЛожь = УточнениеТипа(Родитель, "Отключено") = "Ложь"; + + Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Родитель, ИмяТипа); + Если Уточнение = "Истина" Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + СвойстваВидаДоступа = СвойстваВидовДоступа.ПоТипамГруппИЗначений.Получить(Тип); // См. СвойстваВидаДоступа + Если СвойстваВидаДоступа = Неопределено Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Тип = Контекст.ОбратныйТипПользователя + Или Тип = Контекст.ОбратныйТипГруппыПользователей Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + ДобавитьВидОграниченияПрав(СвойстваВидаДоступа.Имя, Свойства, Контекст); + + Если Не ТипЗначенийДоступаИспользуется(Контекст, СвойстваВидаДоступа.ТипЗначений) Тогда + Свойства.НеиспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); + + Если ОтключеноКакЛожь Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Иначе + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + КонецЕсли; + Продолжить; + КонецЕсли; + + Свойства.ИспользуемыеТипыЗначенийДоступа.Добавить(СвойстваВидаДоступа.ТипЗначений); + + Если СвойстваВидовДоступа.ПоТипамЗначений.Получить(Тип) = Неопределено Тогда + // Тип группы значений доступа. + Если Контекст.Список = Метаданные.НайтиПоТипу(Тип).ПолноеИмя() + Или Контекст.ТипыПользователя.Найти(Тип) <> Неопределено Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Иначе + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + КонецЕсли; + Продолжить; + КонецЕсли; + + Если ЕстьУточнениеПустойСсылки Тогда + Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЕсли; + + Если СвойстваВидовДоступа.ТипыЗначенийДоступаСГруппами.Получить(Тип) = Неопределено + Или Контекст.ТипыПользователя.Найти(Тип) <> Неопределено Тогда + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + Продолжить; + КонецЕсли; + Свойства.ТипыСохраненияГруппЗначений.Добавить(Тип); + + Если Контекст.Список = ИмяТипа + И ВРег(Свойства.ИмяПоляДляЗапроса) = ВРег("ТекущийСписок.Ссылка") Тогда // @query-part-1 + + Свойства.ЭтоСписокЗначенийДоступаСГруппамиЗначений = Истина; + Иначе + ДобавитьВедущийСписокПоПолюСсылка(Контекст.ВедущиеСпискиПоЗначениямСГруппами, + ИмяТипа, ОписаниеПоля, Свойства, Контекст); + КонецЕсли; + + Если Не СвойстваВидаДоступа.НесколькоГруппЗначений Тогда + Продолжить; + КонецЕсли; + Свойства.НесколькоГруппЗначений = Истина; + КонецЦикла; + + Возврат; + КонецЕсли; + + Если Родитель.Узел = "ЭтоАвторизованныйПользователь" Тогда + Свойства.ЕстьПроверкаАвторизованногоПользователя = Истина; + ДобавитьВидОграниченияПрав("ФункцияЭтоАвторизованныйПользователь", Свойства, Контекст); + + Для Каждого Тип Из Свойства.ТипКонечногоПоля.Типы() Цикл + ИмяТипа = ИмяТипаНаЯзыкеЗапросов(Тип); + + Уточнение = УточнениеТипа(Родитель, ИмяТипа); + Если Уточнение = "Истина" Тогда + Свойства.ТипыСохраненияТипаРазрешенный.Добавить(Тип); + Продолжить; + ИначеЕсли Уточнение = "Ложь" Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Не ТипПроверяется(Родитель, ИмяТипа) Тогда + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если Тип <> Тип("СправочникСсылка.Пользователи") + И Тип <> Тип("СправочникСсылка.ВнешниеПользователи") Тогда + + Свойства.ТипыСохраненияТипаЗапрещенный.Добавить(Тип); + Продолжить; + КонецЕсли; + + Если ЕстьУточнениеПустойСсылки Тогда + Свойства.ТипыСохраненияПустойСсылки.Добавить(Тип); + КонецЕсли; + + Свойства.ТипыСохраненияЗначений.Добавить(Тип); + КонецЦикла; + + Возврат; + КонецЕсли; + + // Остались только узлы Поле для получения значения Булево. + Свойства.ТипыСохраненияЗначений.Добавить(Тип("Булево")); + + Если Свойства.ТипКонечногоПоля.Типы().Количество() = 1 + И Свойства.ТипКонечногоПоля.СодержитТип(Тип("Булево")) Тогда + Возврат; + КонецЕсли; + Свойства.ТипКонечногоПоля = Новый ОписаниеТипов("Булево"); + Свойства.ИмяПоляДляЗапроса = Свойства.ИмяПоляДляЗапроса + " = ИСТИНА"; // @query-part-1 + +КонецПроцедуры + +// Для функций СвойстваПоля, ДобавитьСвойстваТиповПоля. +Функция ИмяТипаНаЯзыкеЗапросов(Тип, ОбъектМетаданных = Неопределено) + + ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); + Если ОбъектМетаданных <> Неопределено Тогда + Возврат ОбъектМетаданных.ПолноеИмя(); + КонецЕсли; + + Возврат Строка(Тип); + +КонецФункции + +// Для процедуры ДобавитьСвойстваТиповПоля. +Процедура ДобавитьВидОграниченияПрав(ВидОграничения, СвойстваПоля, Контекст, ПоОбъекту = Ложь) + + Если СвойстваПоля.Чтение Тогда + Контекст.ВсеВидыОграниченийПрав.Вставить("Чтение." + ВидОграничения, Истина); + КонецЕсли; + Если Не ПоОбъекту Или СвойстваПоля.Изменение Тогда + Контекст.ВсеВидыОграниченийПрав.Вставить("Изменение." + ВидОграничения, Истина); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьСвойстваПолей. +// +// Параметры: +// УзелПоле - см. ОписаниеУзла +// Контекст - см. КонтекстПараметровПоСтруктуреОграничения +// СвойстваПоля - см. СвойстваПоля +// +// Возвращаемое значение: +// Структура: +// * ПсевдонимТаблицы - Строка +// * ИмяПоляДляЗапроса - Строка +// * ТабличнаяЧасть - Строка +// * ЭтоПолеСписка - Булево +// * БезЗначенияNull - Булево +// * ПолеСодержитNull - Неопределено +// * ЕстьВыразить - Неопределено +// * УзелПоле - см. ОписаниеУзла +// * СвойстваВложения - см. СвойстваПоля +// * Чтение - Булево +// * ПроверкаЕстьNull - Неопределено +// * ТипыСохраненияКлючейДоступа - Массив из Тип +// * ТипыСохраненияГруппЗначений - Массив из Тип +// * ТипыСохраненияЗначений - Массив из Тип +// * ТипыСохраненияПустойСсылки - Массив из Тип +// * ТипыСохраненияТипов - Массив из Тип +// * ТипыСохраненияТипаЗапрещенный - Массив из Тип +// * ТипыСохраненияТипаРазрешенный - Массив из Тип +// * НеиспользуемыеТипыЗначенийДоступа - Массив из Тип +// * ИспользуемыеТипыЗначенийДоступа - Массив из Тип +// * НесколькоГруппЗначений - Булево +// * ЭтоСписокЗначенийДоступаСГруппамиЗначений - Булево +// * ЕстьУточнениеNull - Булево +// * ЕстьУточнениеНеопределено - Булево +// * ЕстьТипВедущегоСписка - Булево +// * ЕстьТипВладельцаНастроекПрав - Булево +// * ЕстьПроверкаАвторизованногоПользователя - Булево +// * ТипыСохраненияТиповКонфигурации - Массив из Тип +// * ТипыСохраненияТиповРасширений - Массив из Тип +// * ТипыСохраненияТиповПростых - Массив из Тип +// * ИмяГруппыПолейКлючаДоступа - Строка +// * ИмяРеквизитаГруппыПолейКлючаДоступа - Строка +// +Функция СвойстваПоля(УзелПоле, Контекст, СвойстваПоля = Неопределено) + + Свойства = Новый Структура; + ЭтоКорневойУзел = СвойстваПоля = Неопределено; + + Если ЭтоКорневойУзел Тогда + СвойстваПоля = Свойства; + // Внутри функции ЕстьNull() может быть только поле, т.е. функции Выразить() не может быть. + Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + Типы = Новый Массив; + Типы.Добавить(ТипСсылкиПоПолномуИмениМетаданных(УзелПоле.Выразить)); + ТипКонечногоПоля = Новый ОписаниеТипов(Типы); + Иначе + ТипКонечногоПоля = УзелПоле.ТипыПоля[УзелПоле.ТипыПоля.Количество() - 1]; + Если ЗначениеЗаполнено(УзелПоле.ЕстьNull) Тогда + Типы = Новый Массив; + Типы.Добавить(ТипЗначенияУзлаЗначениеИлиКонстанта(УзелПоле.ЕстьNull)); + ТипКонечногоПоля = Новый ОписаниеТипов(ТипКонечногоПоля, Типы); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если УзелПоле.Вложение <> Неопределено Тогда + СвойстваВложения = СвойстваПоля(УзелПоле.Вложение, Контекст, СвойстваПоля); + ТабличнаяЧасть = СвойстваВложения.ТабличнаяЧасть; + ПсевдонимТаблицы = СвойстваВложения.ПсевдонимТаблицы; + ИмяПоляДляЗапроса = СвойстваВложения.ИмяПоляДляЗапроса + "." + УзелПоле.Имя; + ТипыСтрокой = СвойстваВложения.ТипыСтрокой + Символы.ПС + УзелПоле.ТипыСтрокой; + Иначе + Если ТипЗнч(УзелПоле.ТипыПоля[0]) = Тип("ОписаниеТипов") Тогда + ТабличнаяЧасть = ""; + Если ЗначениеЗаполнено(УзелПоле.Псевдоним) + И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + + ПсевдонимТаблицы = УзелПоле.Псевдоним; + ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + УзелПоле.Имя; + Иначе + ПсевдонимТаблицы = "ТекущийСписок"; + ДобавитьОпорноеПоле(Контекст, УзелПоле, СвойстваПоля); + Если Не ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + ИмяПоляДляЗапроса = ТекстСОтступом( + ИмяПоляСРазверткойОпорногоПоляПоТипам(ПсевдонимТаблицы, УзелПоле), " "); + Иначе + ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + УзелПоле.Имя; + КонецЕсли; + КонецЕсли; + Иначе // Первая часть имени поля - это имя табличной части. + ТабличнаяЧасть = УзелПоле.ТипыПоля[0]; + ПсевдонимТаблицы = "ТекущийСписок" + ТабличнаяЧасть; + ЧастиИмени = СтрРазделить(УзелПоле.Имя, "."); + ЧастиИмени.Удалить(0); + ИмяПоляДляЗапроса = ПсевдонимТаблицы + "." + СтрСоединить(ЧастиИмени, "."); + КонецЕсли; + ДобавитьПолеТаблицыОбъекта(Контекст, УзелПоле, СвойстваПоля,, ТабличнаяЧасть); + ТипыСтрокой = УзелПоле.ТипыСтрокой; + КонецЕсли; + + // Внутри функции ЕстьNull() может быть только поле, т.е. функции Выразить() не может быть. + Если ЗначениеЗаполнено(УзелПоле.ЕстьNull) Тогда + ИмяПоляДляЗапроса = "ЕСТЬNULL(" + ИмяПоляДляЗапроса + ", " + + ВыражениеУзлаЗначениеИлиКонстанта(УзелПоле.ЕстьNull) + ")"; // @query-part-1 + + Если ЭтоКорневойУзел Тогда + Свойства.Вставить("БезЗначенияNull", Истина); + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + ИмяПоляДляЗапроса = "ВЫРАЗИТЬ(" + ИмяПоляДляЗапроса + " КАК " + УзелПоле.Выразить + ")"; // @query-part-1, @query-part-2 + СвойстваПоля.Вставить("ЕстьВыразить"); + КонецЕсли; + + Свойства.Вставить("ПсевдонимТаблицы", ПсевдонимТаблицы); + Свойства.Вставить("ИмяПоляДляЗапроса", ИмяПоляДляЗапроса); + Свойства.Вставить("ТипКонечногоПоля", ТипКонечногоПоля); + Свойства.Вставить("ТипыСтрокой", ТипыСтрокой); + + Если УзелПоле.Свойство("ПолеСодержитNull") Тогда + Свойства.Вставить("ПолеСодержитNull"); + КонецЕсли; + + // Для расчета ведущих списков. + Свойства.Вставить("ТабличнаяЧасть", ТабличнаяЧасть); + Свойства.Вставить("СвойстваВложения", СвойстваВложения); + Свойства.Вставить("УзелПоле", УзелПоле); + Свойства.Вставить("ЭтоПолеСписка", + ПсевдонимТаблицы = "ТекущийСписок" + Или СвойстваВложения <> Неопределено + И ЗначениеЗаполнено(СвойстваВложения.ТабличнаяЧасть)); + + Возврат Свойства; + +КонецФункции + + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения. +// +// Возвращаемое значение: +// Структура: +// * Поля - Соответствие +// * СоединенияОтборов - Соответствие +// +Функция ОписаниеВедущихСписковПоЗначениямПолей() + + Возврат Новый Структура("Поля, СоединенияОтборов", Новый Соответствие, Новый Соответствие); + +КонецФункции + +// Для функций ГруппыДополнительныхТаблиц. +Процедура ДобавитьВедущиеСпискиПоЗначениямПолей(Контекст, УзелПоле, СвойстваВложения = Неопределено, + ГруппаТаблиц = Неопределено, ПсевдонимТаблицыУсловия = Неопределено) + + ДополнительныйКонтекст = Новый Структура; + ДополнительныйКонтекст.Вставить("СвойстваПоляРодителя", СвойстваВложения); + ДополнительныйКонтекст.Вставить("ГруппаТаблиц", ГруппаТаблиц); + ДополнительныйКонтекст.Вставить("ПсевдонимТаблицыУсловия", ПсевдонимТаблицыУсловия); + ДополнительныйКонтекст.Вставить("ПсевдонимТаблицыПоля", УзелПоле.Псевдоним); + + ИменаПолей = СтрРазделить(УзелПоле.Имя, "."); + + Если УзелПоле.Вложение <> Неопределено Тогда + ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, УзелПоле.Таблица, ИменаПолей[0], + УзелПоле.ТипыПоля[0], ДополнительныйКонтекст, Истина, Истина); + + ИначеЕсли ЗначениеЗаполнено(УзелПоле.Псевдоним) + И УзелПоле.Псевдоним <> Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + + ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, УзелПоле.Таблица, ИменаПолей[0], + УзелПоле.ТипыПоля[0], ДополнительныйКонтекст); + КонецЕсли; + + ИндексПервогоПоля = ?(ТипЗнч(УзелПоле.ТипыПоля[0]) = Тип("ОписаниеТипов"), 0, 1); + + Если ИндексПервогоПоля + 2 > ИменаПолей.Количество() Тогда + Возврат; + КонецЕсли; + + СвойстваПоляРодителя = Новый Структура("ИмяПоляДляЗапроса, ТабличнаяЧасть"); + Если СвойстваВложения <> Неопределено Тогда + ЗаполнитьЗначенияСвойств(СвойстваПоляРодителя, СвойстваВложения); + СвойстваПоляРодителя.ИмяПоляДляЗапроса = СвойстваПоляРодителя.ИмяПоляДляЗапроса + "." + ИменаПолей[ИндексПервогоПоля]; + Иначе + Если ИндексПервогоПоля > 0 Тогда + СвойстваПоляРодителя.ТабличнаяЧасть = ИменаПолей[0]; + КонецЕсли; + Если Не ЗначениеЗаполнено(УзелПоле.Псевдоним) + Или УзелПоле.Псевдоним = Контекст.СтруктураОграничения.ПсевдонимОсновнойТаблицы Тогда + + ПсевдонимПоляРодителя = "ТекущийСписок"; + ДополнительныйКонтекст.ГруппаТаблиц = Неопределено; + Иначе + ПсевдонимПоляРодителя = УзелПоле.Псевдоним; + КонецЕсли; + СвойстваПоляРодителя.ИмяПоляДляЗапроса = ПсевдонимПоляРодителя + "." + ИменаПолей[ИндексПервогоПоля]; + КонецЕсли; + ДополнительныйКонтекст.СвойстваПоляРодителя = СвойстваПоляРодителя; + + Для Индекс = ИндексПервогоПоля + 1 По ИменаПолей.Количество()-1 Цикл + Поле = ИменаПолей[Индекс]; + ТипПоля = УзелПоле.ТипыПоля[Индекс]; + Для Каждого Таблица Из УзелПоле.ТаблицыСледующегоПоля[Индекс-1] Цикл + ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, Таблица, Поле, + ТипПоля, ДополнительныйКонтекст, Истина, Истина); + КонецЦикла; + СвойстваПоляРодителя.ИмяПоляДляЗапроса = СвойстваПоляРодителя.ИмяПоляДляЗапроса + "." + Поле; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьВедущиеСпискиПоЗначениямПолей. +Процедура ДобавитьПолеВедущегоСпискаПоЗначениямПолей(Контекст, Таблица, Поле, ТипПоля, ДополнительныйКонтекст, + ЭтоОсновнаяТаблица = Ложь, ЭтоСсылочныйТипТаблицы = Неопределено) + + Если Не ЭтоОсновнаяТаблица + И СтрЧислоВхождений(Таблица, ".") = 2 Тогда + + СоставИмени = СтрРазделить(Таблица, "."); + ТабличнаяЧасть = СоставИмени[2]; + СоставИмени.Удалить(2); + ПолноеИмя = СтрСоединить(СоставИмени, "."); + Иначе + ТабличнаяЧасть = ""; + ПолноеИмя = Таблица; + КонецЕсли; + + Если ТипЗнч(ДополнительныйКонтекст.ГруппаТаблиц) <> Тип("Массив") + И ( ВРег(Поле) = ВРег("Ссылка") + Или ВРег(Поле) = ВРег("Ref")) Тогда // @Non-NLS-2 + + Если ЭтоСсылочныйТипТаблицы = Неопределено Тогда + СоставИмени = СтрРазделить(Таблица, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ЭтоСсылочныйТипТаблицы = ТипТаблицы.ЭтоСсылочныйТип; + КонецЕсли; + Если ЭтоСсылочныйТипТаблицы Тогда + Возврат; + КонецЕсли; + КонецЕсли; + + ОписаниеПолей = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Получить(ПолноеИмя); + ОписаниеСоединений = Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов.Получить(ПолноеИмя); + + Если ОписаниеПолей = Неопределено Тогда + Если ЭтоСсылочныйТипТаблицы = Неопределено Тогда + СоставИмени = СтрРазделить(Таблица, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ЭтоСсылочныйТипТаблицы = ТипТаблицы.ЭтоСсылочныйТип; + КонецЕсли; + ОписаниеПолей = Новый Структура; + ОписаниеПолей.Вставить("ЭтоСсылочныйТип", ЭтоСсылочныйТипТаблицы); + ОписаниеПолей.Вставить("ДляОтслеживания", Новый Структура("ПоляШапки, ТабличныеЧасти", + Новый Соответствие, Новый Соответствие)); + ОписаниеПолей.Вставить("ДляОтбора", Новый Структура("ПоляШапки, ТабличныеЧасти", + Новый Соответствие, Новый Соответствие)); + Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Вставить(ПолноеИмя, ОписаниеПолей); + + ОписаниеСоединений = Новый Структура("ПоляШапки, ТабличныеЧасти", Новый Соответствие, Новый Соответствие); + Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов.Вставить(ПолноеИмя, ОписаниеСоединений); + КонецЕсли; + + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтслеживания, ТабличнаяЧасть, Поле, ТипПоля); + + Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда + СоединенияОтборов = ОписаниеСоединений.ТабличныеЧасти.Получить(ТабличнаяЧасть); + Если СоединенияОтборов = Неопределено Тогда + СоединенияОтборов = Новый Соответствие; + ОписаниеСоединений.ТабличныеЧасти.Вставить(ТабличнаяЧасть, СоединенияОтборов); + КонецЕсли; + Иначе + СоединенияОтборов = ОписаниеСоединений.ПоляШапки; + КонецЕсли; + + Если ДополнительныйКонтекст.СвойстваПоляРодителя <> Неопределено Тогда + Если СоставИмени = Неопределено Тогда + СоставИмени = СтрРазделить(Таблица, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + КонецЕсли; + ТипСсылки = Новый ОписаниеТипов(ТипТаблицы.ЯзыкРусский + "Ссылка." + СоставИмени[1]); // @Non-NLS + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтслеживания, "", "Ссылка", ТипСсылки); + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтбора, "", "Ссылка", ТипСсылки); + ИмяПоляДляЗапроса = ДополнительныйКонтекст.СвойстваПоляРодителя.ИмяПоляДляЗапроса; + СоединениеОтбора = СоединенияОтборов.Получить(ВРег(ИмяПоляДляЗапроса)); + Если СоединениеОтбора = Неопределено Тогда + СоединениеОтбора = Новый Структура; + СоединениеОтбора.Вставить("ПолеИлиПсевдоним", ИмяПоляДляЗапроса); + СоединениеОтбора.Вставить("ПоляДляОтбора", "Ссылка"); + СоединениеОтбора.Вставить("ТабличнаяЧасть", ДополнительныйКонтекст.СвойстваПоляРодителя.ТабличнаяЧасть); + СоединениеОтбора.Вставить("ГруппаТаблиц", ДополнительныйКонтекст.ГруппаТаблиц); + СоединенияОтборов.Вставить(ВРег(ИмяПоляДляЗапроса), СоединениеОтбора); + КонецЕсли; + Иначе + Если ТипЗнч(ДополнительныйКонтекст.ГруппаТаблиц) = Тип("Массив") Тогда + СоединениеОтбора = СоединенияОтборов.Получить(ВРег(ДополнительныйКонтекст.ПсевдонимТаблицыПоля)); + Если СоединениеОтбора = Неопределено Тогда + СоединениеОтбора = Новый Структура; + СоединениеОтбора.Вставить("ПолеИлиПсевдоним", ДополнительныйКонтекст.ПсевдонимТаблицыПоля); + СоединениеОтбора.Вставить("ПоляДляОтбора", Новый Массив); + СоединениеОтбора.Вставить("ТабличнаяЧасть", Неопределено); + СоединениеОтбора.Вставить("ГруппаТаблиц", ДополнительныйКонтекст.ГруппаТаблиц); + СоединенияОтборов.Вставить(ВРег(ДополнительныйКонтекст.ПсевдонимТаблицыПоля), СоединениеОтбора); + КонецЕсли; + Если СоединениеОтбора.ПоляДляОтбора.Найти(Поле) = Неопределено + И ДополнительныйКонтекст.ПсевдонимТаблицыПоля = ДополнительныйКонтекст.ПсевдонимТаблицыУсловия Тогда + + СоединениеОтбора.ПоляДляОтбора.Добавить(Поле); + ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей.ДляОтбора, ТабличнаяЧасть, Поле, ТипПоля); + КонецЕсли; + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуру ДобавитьПолеВедущегоСпискаПоЗначениямПолей. +Процедура ВставитьПолеВедущегоСпискаПоЗначениямПолей(ОписаниеПолей, ТабличнаяЧасть, Поле, ТипПоля) + + Если ЗначениеЗаполнено(ТабличнаяЧасть) Тогда + Поля = ОписаниеПолей.ТабличныеЧасти.Получить(ТабличнаяЧасть); + Если Поля = Неопределено Тогда + Поля = Новый Соответствие; + ОписаниеПолей.ТабличныеЧасти.Вставить(ТабличнаяЧасть, Поля); + КонецЕсли; + Иначе + Поля = ОписаниеПолей.ПоляШапки; + КонецЕсли; + + Если Поля.Получить(Поле) <> Неопределено Тогда + Возврат; + КонецЕсли; + + Поля.Вставить(Поле, Новый ХранилищеЗначения(ТипПоля)); + +КонецПроцедуры + +// Для функции ПараметрыОграниченияПоСтруктуреОграничения. +// +// Возвращаемое значение: +// Структура: +// * Списки - Соответствие +// * КлючиЗапросовПоТипам - Соответствие +// * СоединенияОтборов - Соответствие +// * ТипСсылки - ОписаниеТипов +// +Функция ОписаниеВедущихСписковПоПолюСсылка() + + Описание = Новый Структура; + Описание.Вставить("Списки", Новый Соответствие); + Описание.Вставить("КлючиЗапросовПоТипам", Новый Соответствие); + Описание.Вставить("СоединенияОтборов", Новый Соответствие); + Описание.Вставить("ТипСсылки", Новый ОписаниеТипов); + + Возврат Описание; + +КонецФункции + +// Для процедуры ДобавитьСвойстваТиповПоля. +Процедура ДобавитьВедущийСписокПоПолюСсылка(ВедущиеСписки, ВедущийСписок, УзелПоле, СвойстваПоля, Контекст) + + СоставИмени = СтрРазделить(ВедущийСписок, "."); + ТипТаблицы = Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + ИмяТипаСсылки = ТипТаблицы.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS + + ВедущиеСписки.ТипСсылки = Новый ОписаниеТипов(ВедущиеСписки.ТипСсылки, ИмяТипаСсылки); + ТипСсылки = Тип(ИмяТипаСсылки); + + Ключи = ВедущиеСписки.КлючиЗапросовПоТипам.Получить(ТипСсылки); + Если Ключи = Неопределено Тогда + Ключи = Новый Массив; + ВедущиеСписки.КлючиЗапросовПоТипам.Вставить(ТипСсылки, Ключи); + ВедущиеСписки.Списки.Вставить(ВедущийСписок, Истина); + КонецЕсли; + + Ключ = ВРег(СвойстваПоля.ИмяПоляДляЗапроса); + Если Ключи.Найти(Ключ) = Неопределено Тогда + Ключи.Добавить(Ключ); + КонецЕсли; + + ГруппаТаблиц = ?(СвойстваПоля.ЭтоПолеСписка, Неопределено, СвойстваПоля.ПсевдонимТаблицы); + + СоединениеОтбора = ВедущиеСписки.СоединенияОтборов.Получить(Ключ); + Если СоединениеОтбора = Неопределено Тогда + СоединениеОтбора = Новый Структура; + СоединениеОтбора.Вставить("ПолеИлиПсевдоним", СвойстваПоля.ИмяПоляДляЗапроса); + СоединениеОтбора.Вставить("ПоляДляОтбора", "Ссылка"); // @query-part-2 + СоединениеОтбора.Вставить("ТабличнаяЧасть", СвойстваПоля.ТабличнаяЧасть); + СоединениеОтбора.Вставить("ГруппаТаблиц", ГруппаТаблиц); + ВедущиеСписки.СоединенияОтборов.Вставить(Ключ, СоединениеОтбора); + КонецЕсли; + +КонецПроцедуры + +// Для функции ГруппыДополнительныхТаблиц. +Процедура ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка(ВедущийСписок, Описание, Группы, Контекст) + + СоединенияОтборов = Новый Массив; + Для Каждого СоединениеОтбора Из Описание.ПоляШапки Цикл + СоединенияОтборов.Добавить(ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); + КонецЦикла; + Описание.ПоляШапки = СоединенияОтборов; + + ТабличныеЧасти = Новый Соответствие; + Для Каждого ОписаниеТабличнойЧасти Из Описание.ТабличныеЧасти Цикл + СоединенияОтборов = Новый Массив; + ТабличныеЧасти.Вставить(ОписаниеТабличнойЧасти.Ключ, СоединенияОтборов); + Для Каждого СоединениеОтбора Из ОписаниеТабличнойЧасти.Значение Цикл + СоединенияОтборов.Добавить(ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); + КонецЦикла; + КонецЦикла; + Описание.ТабличныеЧасти = ТабличныеЧасти; + +КонецПроцедуры + +// Для функции ГруппыДополнительныхТаблиц. +Процедура ЗаполнитьОтборыВедущихСписковПоПолюСсылка(ВедущиеСписки, Группы, Контекст) + + СоединенияОтборов = Новый Соответствие; + Для Каждого СоединениеОтбора Из ВедущиеСписки.СоединенияОтборов Цикл + СоединенияОтборов.Вставить(СоединениеОтбора.Ключ, + ТекстСоединенияОтбораПоЗначениямПолей(СоединениеОтбора.Значение, Группы, Контекст)); + КонецЦикла; + ВедущиеСписки.СоединенияОтборов = СоединенияОтборов; + +КонецПроцедуры + +// Для процедуры ЗаполнитьОтборыПоЗначениямПолейВедущегоСписка. +Функция ТекстСоединенияОтбораПоЗначениямПолей(Условие, Группы, Контекст) + + Если Контекст.ЭтоСсылочныйТип Тогда + ДополнительноеУсловие = " + | И (&УточнениеПланаЗапроса)"; // @query-part-1 + Иначе + ДополнительноеУсловие = ?(Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей), " + | И (ТекущийСписок.Регистр = &ИдентификаторРегистра)", "") + " + | И (ТекущийСписок.ВариантДоступа = &ВариантДоступа) + | И (&УточнениеПланаЗапроса)"; // @query-part-1, @query-part-3 + КонецЕсли; + + Если Условие.ГруппаТаблиц = Неопределено Или ЗначениеЗаполнено(Условие.ТабличнаяЧасть) Тогда + ТекстСоединения = + "#ТекущиеДанныеДляОтбора КАК ТекущиеДанныеДляОтбора + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО (" + Условие.ПолеИлиПсевдоним + " = ТекущиеДанныеДляОтбора." + Условие.ПоляДляОтбора + ")"; // @query-part-1 + Если ЗначениеЗаполнено(Условие.ТабличнаяЧасть) Тогда + ТекстСоединения = СтрЗаменить(ТекстСоединения, + "&ТекущийСписок", "&ТекущийСписок." + Условие.ТабличнаяЧасть); + ТекстСоединения = СтрЗаменить(ТекстСоединения, + "ТекущийСписок" + Условие.ТабличнаяЧасть + ".", "ТекущийСписок."); + КонецЕсли; + Возврат ТекстСоединения + ДополнительноеУсловие; + КонецЕсли; + + Если ТипЗнч(Условие.ГруппаТаблиц) = Тип("Строка") Тогда + ЭтоПолеУсловияСоединения = Ложь; + ПсевдонимПолейОтбора = Условие.ГруппаТаблиц; + Группа = Группы.НомераПоПсевдонимам.Получить(ПсевдонимПолейОтбора); + ГруппаТаблиц = Группы.ТаблицыПоГруппам.Получить(Группа); + Иначе + ЭтоПолеУсловияСоединения = Истина; + ГруппаТаблиц = Условие.ГруппаТаблиц; + ЗаменяемоеПоле = Условие.ПолеИлиПсевдоним; + ПсевдонимПолейОтбора = СтрРазделить(ЗаменяемоеПоле, ".")[0]; + КонецЕсли; + + Индекс = ГруппаТаблиц.Количество(); + ПерваяДополнительнаяТаблицаНайдена = Ложь; + ОбратнаяГруппаТаблиц = Новый Массив; + ТребуемыеПсевдонимы = Новый Соответствие; + + Пока Индекс >= 1 Цикл + Индекс = Индекс - 1; + ДополнительнаяТаблица = ГруппаТаблиц[Индекс]; + ТекущийПсевдоним = ДополнительнаяТаблица.Псевдоним; + Если Не ПерваяДополнительнаяТаблицаНайдена И ТекущийПсевдоним <> ПсевдонимПолейОтбора Тогда + Продолжить; + КонецЕсли; + ПерваяДополнительнаяТаблицаНайдена = Истина; + Если ТекущийПсевдоним <> ПсевдонимПолейОтбора + И ТребуемыеПсевдонимы.Получить(ДополнительнаяТаблица.Псевдоним) = Неопределено Тогда + Продолжить; + КонецЕсли; + СвойстваТаблицы = Новый Структура("Таблица, Псевдоним, ПоляУсловияСоединения", + ДополнительнаяТаблица.Таблица, ДополнительнаяТаблица.Псевдоним, Новый Массив); + ОбратнаяГруппаТаблиц.Добавить(СвойстваТаблицы); + Для Каждого ПараПолей Из ДополнительнаяТаблица.ПоляУсловияСоединения Цикл + ТребуемыеПсевдонимы.Вставить(ПараПолей.ПервоеПоле.Псевдоним, Истина); + ТребуемыеПсевдонимы.Вставить(ПараПолей.ВтороеПоле.Псевдоним, Истина); + СвойстваТаблицы.ПоляУсловияСоединения.Добавить( + Новый Структура(Новый ФиксированнаяСтруктура(ПараПолей))); + КонецЦикла; + КонецЦикла; + + ВспомогательнаяТаблица = Неопределено; + ПерваяТаблица = ОбратнаяГруппаТаблиц[0]; + ВсеПервыеПоляЗаменяемые = Истина; + + Если ЭтоПолеУсловияСоединения Тогда + Для Каждого ПараПолей Из ПерваяТаблица.ПоляУсловияСоединения Цикл + Если СтрНайти(ПараПолей.ПервоеПоле.Поле, ПерваяТаблица.Псевдоним + ".") > 0 + И СтрНайти(ПараПолей.ПервоеПоле.Поле, ЗаменяемоеПоле + ".") = 0 Тогда + ВсеПервыеПоляЗаменяемые = Ложь; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Если Не ЭтоПолеУсловияСоединения Или Не ВсеПервыеПоляЗаменяемые Тогда + ВспомогательнаяТаблица = Новый Структура("Таблица, Псевдоним, ПоляУсловияСоединения", + ПерваяТаблица.Таблица, "ТекущиеДанныеДляОтбора", Новый Массив); + ОбратнаяГруппаТаблиц.Вставить(0, ВспомогательнаяТаблица); + ПараПолей = Новый Структура("ПервоеПоле, ВтороеПоле"); + ВспомогательнаяТаблица.ПоляУсловияСоединения.Добавить(ПараПолей); + ПараПолей.ПервоеПоле = Новый Структура("Поле, Псевдоним", + Условие.ПолеИлиПсевдоним, "ТекущиеДанныеДляОтбора"); + ПараПолей.ВтороеПоле = Новый Структура("Поле, Псевдоним", + "ТекущиеДанныеДляОтбора." + Условие.ПоляДляОтбора, ПсевдонимПолейОтбора); + КонецЕсли; + + ТекстСоединения = + "#ТекущиеДанныеДляОтбора КАК ТекущиеДанныеДляОтбора"; + ОставшиесяПсевдонимы = Новый Соответствие; + ОставшиесяПсевдонимы.Вставить("ТекущийСписок", Новый Массив); + + Для Каждого ДополнительнаяТаблица Из ОбратнаяГруппаТаблиц Цикл + ОставшиесяПсевдонимы.Вставить(ДополнительнаяТаблица.Псевдоним, + Новый Массив(Новый ФиксированныйМассив(ДополнительнаяТаблица.ПоляУсловияСоединения))); + КонецЦикла; + + ПервыеПсевдонимы = Новый Соответствие; + Индекс = -1; + Для Каждого ДополнительнаяТаблица Из ОбратнаяГруппаТаблиц Цикл + Индекс = Индекс + 1; + + ПервыйПсевдоним = ДополнительнаяТаблица.Псевдоним; + ПоляУсловияСоединения = ОставшиесяПсевдонимы.Получить(ПервыйПсевдоним); + ОставшиесяПсевдонимы.Удалить(ПервыйПсевдоним); + ПервыеПсевдонимы.Вставить(ПервыйПсевдоним, Истина); + + Если Индекс >= ОбратнаяГруппаТаблиц.Количество() - 1 Тогда + ВторойПсевдоним = "ТекущийСписок"; + Иначе + ВторойПсевдоним = ОбратнаяГруппаТаблиц[Индекс + 1].Псевдоним; + КонецЕсли; + ОстальныеПоляУсловияСоединения = ОставшиесяПсевдонимы.Получить(ВторойПсевдоним); + Для Каждого ПараПолей Из ОстальныеПоляУсловияСоединения Цикл + ПоляУсловияСоединения.Добавить(ПараПолей); + КонецЦикла; + ОставшиесяПсевдонимы.Вставить(ВторойПсевдоним, Новый Массив); + + УсловияСоединения = Новый Массив; + Для Каждого ПараПолей Из ПоляУсловияСоединения Цикл + Если Не ЗначениеЗаполнено(ПараПолей.ПервоеПоле.Псевдоним) + И Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) Тогда + + УсловияСоединения.Добавить(ПараПолей.ПервоеПоле.Поле + + " = " + ПараПолей.ВтороеПоле.Поле); + + ИначеЕсли ПервыеПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним) <> Неопределено + И (Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) + Или ПараПолей.ВтороеПоле.Псевдоним = ВторойПсевдоним) + Или ПараПолей.ПервоеПоле.Псевдоним = ВторойПсевдоним + И Не ЗначениеЗаполнено(ПараПолей.ВтороеПоле.Псевдоним) Тогда + + ПервоеПоле = ПараПолей.ПервоеПоле.Поле; + + Если ПервыеПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним) <> Неопределено + И ПараПолей.ПервоеПоле.Псевдоним = ПсевдонимПолейОтбора + И ВспомогательнаяТаблица = Неопределено + И СтрНачинаетсяС(ПервоеПоле, ЗаменяемоеПоле) Тогда + + КонецПоля = Сред(ПервоеПоле, СтрДлина(ЗаменяемоеПоле) + 1); + ПервоеПоле = "ТекущиеДанныеДляОтбора" + + ?(ЗаменяемоеПоле <> ПсевдонимПолейОтбора, ".Ссылка", "") + КонецПоля; // @query-part-2 + КонецЕсли; + Если СтрНачинаетсяС(ПервоеПоле, "ТекущиеДанныеДляОтбора.") Тогда + УсловияСоединения.Добавить(ПараПолей.ВтороеПоле.Поле + " = " + ПервоеПоле); + + ИначеЕсли СтрНачинаетсяС(ПараПолей.ВтороеПоле.Поле, "ТекущиеДанныеДляОтбора.") Тогда + УсловияСоединения.Добавить(ПервоеПоле + " = " + ПараПолей.ВтороеПоле.Поле); + + ИначеЕсли ПараПолей.ВтороеПоле.Псевдоним = ВторойПсевдоним Тогда + УсловияСоединения.Добавить(ПараПолей.ВтороеПоле.Поле + " = " + ПервоеПоле); + Иначе + УсловияСоединения.Добавить(ПервоеПоле + " = " + ПараПолей.ВтороеПоле.Поле); + КонецЕсли; + Иначе + ОставшиесяУсловия = ОставшиесяПсевдонимы.Получить(ПараПолей.ПервоеПоле.Псевдоним); + Если ОставшиесяУсловия = Неопределено Тогда + ОставшиесяУсловия = ОставшиесяПсевдонимы.Получить(ПараПолей.ВтороеПоле.Псевдоним); + КонецЕсли; + ОставшиесяУсловия.Добавить(ПараПолей); + КонецЕсли; + КонецЦикла; + Если ВторойПсевдоним = "ТекущийСписок" Тогда + ТаблицаИПсевдоним = "&ТекущийСписок КАК ТекущийСписок"; + Иначе + СледующаяТаблица = ОбратнаяГруппаТаблиц[Индекс + 1]; + ТаблицаИПсевдоним = СледующаяТаблица.Таблица + " КАК " + СледующаяТаблица.Псевдоним; + КонецЕсли; + ТекстСоединения = ТекстСоединения + " + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ " + ТаблицаИПсевдоним + " + | ПО (" + СтрСоединить(УсловияСоединения, ") + | И (") + ")"; // @query-part-1, @query-part-2, @query-part-3 + КонецЦикла; + + Возврат ТекстСоединения + ДополнительноеУсловие; + +КонецФункции + + +// Для процедур ДобавитьОпорноеПоле, ДобавитьТипыИзмерения, ДобавитьСвойстваТиповПоля, +// ДобавитьПроверкуПоТипам и функции СвойстваПоля. +// +Функция ЭтоПростойТип(Тип) + + Возврат Тип = Тип("Булево") + Или Тип = Тип("Дата") + Или Тип = Тип("Строка") + Или Тип = Тип("Число") + Или Тип = Тип("УникальныйИдентификатор") + Или Тип = Тип("ХранилищеЗначения"); + +КонецФункции + +// Для функции ДобавитьСвойстваТиповПоля. +Функция ТипПроверяется(Узел, ПолноеИмя) + + Если Узел.Типы.Количество() = 0 Тогда + Возврат Истина; + КонецЕсли; + + ТипУказан = Ложь; + Для Каждого ИмяТаблицы Из Узел.Типы Цикл + Если ВРег(ИмяТаблицы) = ВРег(ПолноеИмя) Тогда + ТипУказан = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Узел.ПроверятьТипыКромеУказанных И Не ТипУказан + Или Не Узел.ПроверятьТипыКромеУказанных И ТипУказан; + +КонецФункции + +// Для функции ДобавитьСвойстваТиповПоля. +Функция ТипУточнен(Узел, ИмяТипаНаЯзыкеЗапросов) + + ТипУточнен = Ложь; + Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл + Если ВРег(УточнениеСравнения.Ключ) = ВРег(ИмяТипаНаЯзыкеЗапросов) Тогда + ТипУточнен = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат ТипУточнен; + +КонецФункции + +// Для функции ДобавитьСвойстваТиповПоля. +Функция УточнениеТипа(Узел, ИмяТипаНаЯзыкеЗапросов) + + Уточнение = ""; + Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл + Если ВРег(УточнениеСравнения.Ключ) = ВРег(ИмяТипаНаЯзыкеЗапросов) Тогда + Уточнение = УточнениеСравнения.Значение; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Уточнение; + +КонецФункции + +// Для функции СвойстваПоля. +Функция ТипЗначенияУзлаЗначениеИлиКонстанта(Узел) + + Если Узел.Узел = "Значение" Тогда + Возврат ТипСсылкиПоПолномуИмениПредопределенного(Узел.Имя); + КонецЕсли; + + Возврат ТипЗнч(Узел.Значение); + +КонецФункции + +// Для функций ТекстУсловияСоединения, СвойстваПоля, НаборПолейУсловияКогда и +// процедуры УточнитьСвойстваПоляСравнения. +// +Функция ВыражениеУзлаЗначениеИлиКонстанта(Узел) + + Если Узел.Узел = "Значение" Тогда + Выражение = "Значение(" + Узел.Имя + ")"; + + ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Булево") Тогда + Выражение = ?(Узел.Значение, "Истина", "Ложь"); + + ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Число") Тогда + Выражение = Формат(Узел.Значение, "ЧН=0; ЧГ="); + + ИначеЕсли ТипЗнч(Узел.Значение) = Тип("Неопределено") Тогда + Выражение = "Неопределено"; + Иначе + Выражение = """" + Узел.Значение + """"; + КонецЕсли; + + Возврат Выражение; + +КонецФункции + +// Для функции ТипЗначенияУзлаЗначениеИлиКонстанта. +Функция ТипСсылкиПоПолномуИмениПредопределенного(ПолноеИмяПредопределенного) + + ЧастиИмени = СтрРазделить(ПолноеИмяПредопределенного, "."); + ЧастиИмени.Удалить(2); + + ПолноеИмя = СтрСоединить(ЧастиИмени, "."); + + Возврат ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя); + +КонецФункции + +// Для функций СвойстваПоля, ТипСсылкиПоПолномуИмениПредопределенного. +Функция ТипСсылкиПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаСсылки = СтрЗаменить(ПолноеИмя, ".", "Ссылка."); // @Non-NLS-2 + Иначе + ИмяТипаСсылки = СтрЗаменить(ПолноеИмя, ".", "Ref."); + КонецЕсли; + + Возврат Тип(ИмяТипаСсылки); + +КонецФункции + +// Для функции КлючТаблицы. +Функция ТипКлючаЗаписиПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаКлючаЗаписи = СтрЗаменить(ПолноеИмя, ".", "КлючЗаписи."); // @Non-NLS-2 + Иначе + ИмяТипаКлючаЗаписи = СтрЗаменить(ПолноеИмя, ".", "RecordKey."); + КонецЕсли; + + Возврат Тип(ИмяТипаКлючаЗаписи); + +КонецФункции + +// Для функции КлючТаблицы. +Функция ТипНабораЗаписейПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаНабораЗаписей = СтрЗаменить(ПолноеИмя, ".", "НаборЗаписей."); // @Non-NLS-2 + Иначе + ИмяТипаНабораЗаписей = СтрЗаменить(ПолноеИмя, ".", "RecordSet."); + КонецЕсли; + + Возврат Тип(ИмяТипаНабораЗаписей); + +КонецФункции + +// Для функции КлючТаблицы. +Функция ТипМенеджераОбъектаПоПолномуИмениМетаданных(ПолноеИмя) + + Если ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) Тогда + ИмяТипаМенеджера = СтрЗаменить(ПолноеИмя, ".", "Менеджер."); // @Non-NLS-2 + Иначе + ИмяТипаМенеджера = СтрЗаменить(ПолноеИмя, ".", "Manager."); + КонецЕсли; + + Возврат Тип(ИмяТипаМенеджера); + +КонецФункции + +// Для функций ТипСсылкиПоПолномуИмениМетаданных, ТипКлючаЗаписиПоПолномуИмениМетаданных, +// ТипНабораЗаписейПоПолномуИмениМетаданных, ТипМенеджераОбъектаПоПолномуИмениМетаданных. +// +Функция ЭтоРусскийВариантВидаОбъектаМетаданных(ПолноеИмя) + + ПервыйСимвол = Лев(ПолноеИмя, 1); + + Возврат ПервыйСимвол > "А" + И ПервыйСимвол < "Я" + Или ПервыйСимвол > "а" + И ПервыйСимвол < "я"; // @Non-NLS-1, @Non-NLS-2, @Non-NLS-3, @Non-NLS-4 + +КонецФункции + +#КонецОбласти + +#Область ПараметрыОграниченияДоступаТекстыЗапросовДляСписка + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка +// * Значение - Массив из Строка +// +Функция НовыеРеквизитыТаблицКлюча() + Возврат Новый Соответствие; +КонецФункции + +// Основная функция области, которая является второй частью +// функции ПараметрыОграниченияПоСтруктуреОграничения, но +// не используется при подготовке хранимых параметров ограничения доступа, +// а используется при вызове функции ПараметрыОграничения. +// +Процедура ДобавитьТекстыЗапросовВПараметрыОграничения(Результат) + + Контекст = Результат.Контекст; + Результат.Удалить("Контекст"); + + // Проверка прав Чтение и Изменение объекта или набора записей в базе данных. + Результат.Вставить("ТекстЗапросаПроверкиПравЧтениеИзменение"); + // Проверка права Чтение объекта или набора записей в базе данных. + Результат.Вставить("ТекстЗапросаПроверкиПраваЧтение"); + // Текст извлечения владельца из ссылки объекта. + Результат.Вставить("ПолеОбъектаВладельцаВЗапросеПроверкиПрав"); + // Получение прав пользователей на список элементов данных. + Результат.Вставить("ТекстЗапросаПравПользователей"); + + ДобавитьТекстЗапросаДатыСледующегоЭлементаДанных(Результат, Контекст); + ЗаполнитьЗапросыПравПользователей(Результат, Контекст); + + Если Результат.БезЗаписиКлючейДоступа Тогда + // Запрос объектов или отборов записей для удаления или установки пустых ключей. + Результат.Вставить("ТекстЗапросаУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаПроверкиУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра"); + ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст); + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + // Формирование запросов проверки прав. + ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст); + КонецЕсли; + + Возврат; + КонецЕсли; + + // Имена используемых таблиц ключа. + Результат.Вставить("ТаблицыКлюча"); + // Имена используемых реквизитов таблиц ключа. + Результат.Вставить("РеквизитыТаблицКлюча"); + + // Запрос объекта или отбора записей для вычисления диапазона требуемого размера. + Результат.Вставить("ТекстЗапросаДиапазонаЭлементовДанных"); + // Запрос объектов или отборов записей, у которых устарели ключи доступа. + Результат.Вставить("ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами"); + // Запрос проверки актуальности ключа доступа у объекта. + Результат.Вставить("ТекстЗапросаПроверкиКлючаДоступаОбъекта"); + // Запрос отборов записей, которых нет в регистре ключей доступа регистров при фоновом обновлении. + Результат.Вставить("ТекстЗапросаЭлементовДанныхБезКлючейДоступа"); + // Запрос отборов записей, которых нет в регистре ключей доступа регистров при записи нового набора. + Результат.Вставить("ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей"); + Результат.Вставить("ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей"); + // Запросы объектов или отборов записей, у которых устарели ключи доступа + // по составу изменений ведущих объектов (для точечного задания). + Результат.Вставить("ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам", Новый Соответствие); + // Запрос несуществующих объектов и отборов записей, которые не используются. + Результат.Вставить("ТекстЗапросаУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаПроверкиУстаревшихЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанных"); + Результат.Вставить("ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра"); + + // Запрос текущих ключей доступа отборов записей регистра перед записью рассчитанных ключей доступа. + Результат.Вставить("ТекстЗапросаТекущихКлючейДоступаРегистра"); + + // Запрос значений объектов или отборов записей. + Результат.Вставить("ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа"); + // Запрос значений объектов в памяти. + Результат.Вставить("ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа"); + // Запрос значений из используемых ключей доступа для сравнения со значениями из объектов или отборов записей. + Результат.Вставить("ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения"); + // Запрос значений из всех ключей доступа для сравнения со значениями из объектов или + // отборов записей перед записью нового ключа. + Результат.Вставить("ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения"); + // Запрос проверки существования ключа доступа перед записью нового ключа. + Результат.Вставить("ТекстЗапросаСуществованияКлючейДляСравнения"); + + // Запрос ключей доступа для обновления пользователей и групп доступа, которым они разрешены. + Результат.Вставить("ТекстЗапросаКлючейДоступаДляОбновленияПрав"); + // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. + Результат.Вставить("ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав"); + // Запрос значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + Результат.Вставить("ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав"); + // Запрос неиспользуемых ключей доступа для установки даты неиспользования или удаления. + Результат.Вставить("ТекстЗапросаУстаревшихКлючейДоступа"); + + Контекст.Вставить("ОтдельныйРегистр", Истина); // Уточнение регистра ключей для нессылочных типов. + + Контекст.Вставить("ТаблицыКлюча", Новый Массив); + Контекст.Вставить("РеквизитыТаблицКлюча", НовыеРеквизитыТаблицКлюча()); + Контекст.Вставить("ИспользуемыеПоляОсновнойТаблицы", ""); + Контекст.Вставить("ЧастиУсловияПроверки", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзОбъектов", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзОбъектовВПамяти", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзКлючейДляСравнения", Новый Массив); + Контекст.Вставить("ЧастиЗапросаСуществованияКлючейДляСравнения", Новый Массив); + Контекст.Вставить("ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав", Новый Массив); + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихКлючейДоступа", Новый Массив); + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписков", Новый Массив); + Контекст.Вставить("ЧастиУсловияВыбораПравПоВладельцамНастроекПрав", Новый Массив); + Контекст.Вставить("ЧастиУсловияОтбораПоВедущимКлючамДоступа", Новый Массив); + Контекст.Вставить("ОписаниеЗапросовПроверкиПоВедущимОбъектам", Новый Соответствие); + + // Формирование запроса элементов данных с устаревшими ключами. + ЗаполнитьШаблоныЧастейЗапросаПроверки(Контекст); + ЗаполнитьИспользуемыеПоляОсновнойТаблицы(Контекст); + + Для НомерШапки = 0 По 2 Цикл + ДобавитьПроверкуШапкиКлюча(Контекст, НомерШапки); + КонецЦикла; + + Для НомерТабличнойЧастиКлюча = 1 По Контекст.КоличествоТабличныхЧастейКлюча Цикл + ДобавитьПроверкуТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча); + КонецЦикла; + СобратьЧастиЗапросаПроверки(Результат, Контекст); + + // Формирование запросов значений из элементов данных и из ключей. + Для НомерШапки = 0 По 2 Цикл + ДобавитьЗаполнениеШапкиКлюча(Контекст, НомерШапки); + КонецЦикла; + ДобавитьВыборКлючейБезПолейВШапке(Контекст); + + Для НомерТабличнойЧастиКлюча = 1 По Контекст.КоличествоТабличныхЧастейКлюча Цикл + ДобавитьЗаполнениеТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча); + КонецЦикла; + СобратьЧастиЗапросовЗаполнения(Результат, Контекст); + + Результат.ТаблицыКлюча = Контекст.ТаблицыКлюча; + Результат.РеквизитыТаблицКлюча = Контекст.РеквизитыТаблицКлюча; + + ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст); + + // Формирование запросов проверки прав. + ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст); + +КонецПроцедуры + +// Для процедуры ПараметрыОграниченияПоСтруктуреОграничения. +Процедура ЗаполнитьНедостающиеТипыОпорныхПолей(Результат, Контекст) + + Если Контекст.ЭтоСсылочныйТип Или Контекст.ИспользуетсяОграничениеПоВладельцу Тогда + Возврат; + КонецЕсли; + + Если ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + Измерения = Метаданные.РегистрыСведений[Контекст.ИмяОтдельногоРегистраКлючей].Измерения; + Иначе + Измерения = Метаданные.РегистрыСведений.КлючиДоступаКРегистрам.Измерения; + КонецЕсли; + + НедостающиеТипы = Новый Соответствие; + Поля = Новый Соответствие; + СписокНедостающихТипов = Новый СписокЗначений; + СписокПолей = Новый СписокЗначений; + + КоличествоПолей = Контекст.ОпорныеПоля.ТипыИспользуемых.Количество(); + Индекс = 0; + Пока Индекс < КоличествоПолей Цикл + ТребуемыйТип = Контекст.ОпорныеПоля.ТипыИспользуемых.Получить(Индекс).Получить(); + ТипИзмерения = Измерения[СтрШаблон("Поле%1", Индекс + 1)].Тип; + НедостающийТип = Новый ОписаниеТипов(ТребуемыйТип, , ТипИзмерения.Типы()); + Для Каждого Тип Из НедостающийТип.Типы() Цикл + Если НедостающиеТипы.Получить(Тип) = Неопределено Тогда + НедостающиеТипы.Вставить(Тип, Истина); + СписокНедостающихТипов.Добавить(ИмяТипаСсылки(ИмяТипаНаЯзыкеЗапросов(Тип), + Контекст.СтруктураОграничения.ВнутренниеДанные.ТипыТаблицПоИменам)); + Поле = Контекст.ОпорныеПоля.Все.Получить(Индекс); + Если Поля.Получить(Поле) = Неопределено Тогда + Поля.Вставить(Поле, Истина); + СписокПолей.Добавить(Поле); + КонецЕсли; + КонецЕсли; + КонецЦикла; + Индекс = Индекс + 1; + КонецЦикла; + + Если СписокНедостающихТипов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Результат.БезОбновленияВсехКомбинацийЗначенийОпорныхПолей = Истина; + + СписокНедостающихТипов.СортироватьПоЗначению(); + Контекст.ОпорныеПоля.Вставить("НедостающиеТипы", СписокНедостающихТипов.ВыгрузитьЗначения()); + Контекст.ОпорныеПоля.Вставить("ПоляНедостающихТипов", СписокПолей.ВыгрузитьЗначения()); + + ДобавитьСвойствоВерсии(Контекст, Результат, "БезОбновленияВсехКомбинацийЗначенийОпорныхПолей"); + ДобавитьСвойствоВерсии(Контекст, Контекст.ОпорныеПоля, "НедостающиеТипы"); + ДобавитьСвойствоВерсии(Контекст, Контекст.ОпорныеПоля, "ПоляНедостающихТипов"); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьТекстЗапросаДатыСледующегоЭлементаДанных(Результат, Контекст) + + Если Не Результат.СписокСДатой И Не Результат.СписокСПериодом Тогда + Возврат; + КонецЕсли; + + Если Результат.СписокСДатой Тогда + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Дата КАК Дата + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.Дата < &ДатаНачала + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Дата УБЫВ"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Период КАК Период + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.Период < &ДатаНачала + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Период УБЫВ"; + Если Контекст.ИмяКоллекцииТипа = "РегистрыРасчета" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ".Период", ".ПериодРегистрации"); // @query-part-1, @query-part-2 + КонецЕсли; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + Результат.Вставить("ТекстЗапросаДатыСледующегоЭлементаДанных", ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьТекстЗапросаУстаревшихЭлементовДанных(Результат, Контекст) + + Если Результат.ЭтоСсылочныйТип Тогда + ТипСсылки = ?(ЗначениеЗаполнено(СтрПолучитьСтроку(Результат.Версия, 1)) + Или ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Результат.Список) <> Неопределено, + ТипСсылкиПоПолномуИмениМетаданных(Результат.Список), Неопределено); + ТипыСсылок = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ВладелецЗначенийКлючейДоступа"); + + Если ТипыСсылок.Получить(ТипСсылки) = Неопределено Тогда + ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); + ТекстЗапросаНекорректных = ПризнакПустогоЗапроса(); + + ИначеЕсли Результат.БезЗаписиКлючейДоступаДляПользователейИВнешнихПользователей Тогда + ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); + ТекстЗапросаНекорректных = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, + | ИСТИНА КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступаКОбъектам.Объект"; // @query-part-1 + + Иначе + Если Результат.ДляВнешнихПользователей Тогда + ТекстЗапросаУстаревших = ПризнакПустогоЗапроса(); + Иначе + ТекстЗапросаУстаревших = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, + | ЛОЖЬ КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО (ТекущийСписок.Ссылка = КлючиДоступаКОбъектам.Объект) + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка + | И ТекущийСписок.Ссылка ЕСТЬ NULL + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступаКОбъектам.Объект"; // @query-part-1 + ТекстЗапросаУстаревших = СтрЗаменить(ТекстЗапросаУстаревших, "&ТекущийСписок", Результат.Список); + + ТекстЗапроса = // ТекстЗапросаПроверкиУстаревшихЭлементовДанных + "ВЫБРАТЬ + | ЭлементыДанных.ТекущаяСсылка КАК Объект + |ПОМЕСТИТЬ КлючиДоступаКОбъектам + |ИЗ + | &ЭлементыДанных КАК ЭлементыДанных + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка + |ИЗ + | КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО (ТекущийСписок.Ссылка = КлючиДоступаКОбъектам.Объект) + |ГДЕ + | ТекущийСписок.Ссылка ЕСТЬ NULL + | И &УточнениеПланаЗапроса"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + Результат.ТекстЗапросаПроверкиУстаревшихЭлементовДанных = ТекстЗапроса; + КонецЕсли; + Если Не Результат.СЗаписьюКлючейДоступаДляПользователейИВнешнихПользователей + И Не Результат.БезЗаписиКлючейДоступа Тогда + ТекстЗапросаНекорректных = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступаКОбъектам.Объект КАК ТекущаяСсылка, + | ЛОЖЬ КАК Удалить, + | ИСТИНА КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.Объект > &ПоследняяОбработаннаяСсылка + | И КлючиДоступаКОбъектам.#КлючДоступаПользователей <> ЗНАЧЕНИЕ(Справочник.КлючиДоступа.ПустаяСсылка) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступаКОбъектам.Объект"; // @query-part-1 + ТекстЗапросаНекорректных = СтрЗаменить(ТекстЗапросаНекорректных, "#КлючДоступаПользователей", + ?(Результат.ДляВнешнихПользователей, "КлючДоступаПользователей", "КлючДоступаВнешнихПользователей")); + + ТекстЗапроса = // ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных + "ВЫБРАТЬ + | ЭлементыДанных.ТекущаяСсылка КАК ТекущаяСсылка + |ПОМЕСТИТЬ ЭлементыДанных + |ИЗ + | &ЭлементыДанных КАК ЭлементыДанных + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | КлючиДоступаКОбъектам.Объект КАК Объект, + | КлючиДоступаКОбъектам.КлючДоступаПользователей КАК КлючДоступаПользователей, + | КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей КАК КлючДоступаВнешнихПользователей + |ИЗ + | ЭлементыДанных КАК ЭлементыДанных + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ЭлементыДанных.ТекущаяСсылка)"; + Результат.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных = ТекстЗапроса; + Иначе + ТекстЗапросаНекорректных = ПризнакПустогоЗапроса(); + КонецЕсли; + КонецЕсли; + ТекстЗапросаНекорректных = СтрЗаменить(ТекстЗапросаНекорректных, "&ТекущийСписок", Результат.Список); + Результат.ТекстЗапросаУстаревшихЭлементовДанных = ТекстЗапросаУстаревших; + Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапросаНекорректных; + Возврат; + КонецЕсли; + + ОпорныеПоляВыбора = "КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа"; + + Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистра = Результат.ИмяОтдельногоРегистраКлючей; + ОсновнойОтбор = "ИСТИНА"; // @query-part-1 + Иначе + ИмяРегистра = "КлючиДоступаКРегистрам"; + ОсновнойОтбор = "КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра"; + ОпорныеПоляВыбора = "КлючиДоступаКРегистрам.Регистр КАК Регистр, + | " + ОпорныеПоляВыбора; + КонецЕсли; + + ОтборПоВидуПользователей = "ВЫБОР + | КОГДА КлючиДоступаКРегистрам.ВариантДоступа = 0 + | ТОГДА ЛОЖЬ + | ИНАЧЕ КлючиДоступаКРегистрам.ВариантДоступа - (ВЫРАЗИТЬ(КлючиДоступаКРегистрам.ВариантДоступа / 2 - 0.5 КАК ЧИСЛО(15, 0))) * 2 = 1 + | КОНЕЦ = " + ?(Результат.ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ"); // @query-part-1 + + ОпорныеПоля = Контекст.ОпорныеПоля; + Если ОпорныеПоля = Неопределено Тогда + МаксимальноеКоличествоОпорныхПолей = + УправлениеДоступомСлужебныйПовтИсп.КоличествоОпорныхПолейРегистра(ИмяРегистра); + Иначе + МаксимальноеКоличествоОпорныхПолей = ОпорныеПоля.МаксимальноеКоличество; + КонецЕсли; + + ОпорныеПоляДляОтбора = "КлючиДоступаКРегистрам.ВариантДоступа >= &ВариантДоступа + | И (КлючиДоступаКРегистрам.ВариантДоступа > &ВариантДоступа + | ИЛИ КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа"; // @query-part-1 + ОпорныеПоляДляУпорядочения = "ВариантДоступа"; + СтрокаТабуляций = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(" ", + 2 + МаксимальноеКоличествоОпорныхПолей * 2); + + Для Номер = 1 По МаксимальноеКоличествоОпорныхПолей Цикл + // Поля для выбора. + ОпорныеПоляВыбора = ОпорныеПоляВыбора + СтрШаблон(", + | КлючиДоступаКРегистрам.Поле%1 КАК Поле%1", Номер); // @query-part-1 + + // Поля для отбора. + Если Номер = МаксимальноеКоличествоОпорныхПолей Тогда + Отбор = "КлючиДоступаКРегистрам.Поле%1 > &Поле%1"; // @query-part-1 + Иначе + Отбор = "(КлючиДоступаКРегистрам.Поле%1 > &Поле%1 + | ИЛИ КлючиДоступаКРегистрам.Поле%1 = &Поле%1"; // @query-part-1 + КонецЕсли; + ОпорныеПоляДляОтбора = ОпорныеПоляДляОтбора + ТекстСОтступом(" + |И " + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, 2 + Номер * 2)); // @query-part-1 + + // Поля для упорядочения. + ОпорныеПоляДляУпорядочения = ОпорныеПоляДляУпорядочения + + ?(ОпорныеПоляДляУпорядочения = "", "", ", ") + СтрШаблон("Поле%1", Номер); + КонецЦикла; + ОпорныеПоляДляОтбора = ОпорныеПоляДляОтбора + + УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", МаксимальноеКоличествоОпорныхПолей); + + Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда + // Запрос очистки общего регистра. + ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра + "ВЫБРАТЬ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора, + | ИСТИНА КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра + | И &ОтборПоВидуПользователей + | И &ОпорныеПоляДляОтбора + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); + Результат.ТекстЗапросаНекорректныхЭлементовДанныхИзОбщегоРегистра = ТекстЗапроса; + КонецЕсли; + + Если Результат.БезЗаписиКлючейДоступа Тогда + Результат.ТекстЗапросаУстаревшихЭлементовДанных = ПризнакПустогоЗапроса(); + ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора, + | ИСТИНА КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + |ГДЕ + | &ОсновнойОтбор + | И &ОтборПоВидуПользователей + | И &ОпорныеПоляДляОтбора + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); + Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапроса; + Возврат; + КонецЕсли; + + КоличествоИспользуемыхОпорныхПолей = ОпорныеПоля.Используемые.Количество(); + Номер = 1; + ОпорныеПоляВыбораПриПроверке = ?(ОсновнойОтбор = "ИСТИНА", "", + "КлючиДоступаКРегистрам.Регистр КАК Регистр, + | ") + "КлючиДоступаКРегистрам.ВариантДоступа КАК ВариантДоступа"; + ОпорныеПоляВыбораИзСписка = ""; + ОпорныеПоляДляСравнения = ""; + ОпорныеПоляДляСоединения = ?(ОсновнойОтбор = "ИСТИНА", "", + "(КлючиДоступаКРегистрам.Регистр = ЭлементыДанных.Регистр) + |И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = ЭлементыДанных.ВариантДоступа)"; + ОпорныеПоляДляОтбора2 = + "КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа + | И "; // @query-part-1 + УсловиеПроверкиПервогоПоля = ""; + ОпорныеПоляДляУпорядоченияПриПроверке = ""; + Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл + // Поля для выбора. + ОпорныеПоляВыбораПриПроверке = ОпорныеПоляВыбораПриПроверке + СтрШаблон(", + | КлючиДоступаКРегистрам.Поле%1 КАК Поле%1", Номер); // @query-part-1 + ОпорныеПоляВыбораИзСписка = ОпорныеПоляВыбораИзСписка + ?(ОпорныеПоляВыбораИзСписка = "", "", ", + | ") + СтрШаблон("ТекущийСписок.%1", ИмяОпорногоПоля); + + // Поля для отбора. + Если Номер = КоличествоИспользуемыхОпорныхПолей Тогда + Отбор = "КлючиДоступаКРегистрам.Поле%1 > &Поле%1"; // @query-part-1 + Иначе + Отбор = "(КлючиДоступаКРегистрам.Поле%1 > &Поле%1 + | ИЛИ КлючиДоступаКРегистрам.Поле%1 = &Поле%1"; // @query-part-1 + КонецЕсли; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + + // Поля для сравнения и соединения. + ОпорныеПоляДляСравнения = ОпорныеПоляДляСравнения + ?(ОпорныеПоляДляСравнения = "", "", " + |И ") + СтрШаблон("(ТекущийСписок.%2 = КлючиДоступаКРегистрам.Поле%1)", Номер, ИмяОпорногоПоля); // @query-part-3 + ОпорныеПоляДляСоединения = ОпорныеПоляДляСоединения + ?(ОпорныеПоляДляСоединения = "", "", " + |И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ЭлементыДанных.Поле%1)", Номер); // @query-part-3 + + // Условие проверки по первому полю. + Если УсловиеПроверкиПервогоПоля = "" Тогда + УсловиеПроверкиПервогоПоля = СтрШаблон("ТекущийСписок.%1 ЕСТЬ NULL", ИмяОпорногоПоля); // @query-part-1 + КонецЕсли; + + // Поля для упорядочения. + ОпорныеПоляДляУпорядоченияПриПроверке = ОпорныеПоляДляУпорядоченияПриПроверке + + ?(ОпорныеПоляДляУпорядоченияПриПроверке = "", "", ", ") + СтрШаблон("Поле%1", Номер); + + Номер = Номер + 1; + КонецЦикла; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + + УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", КоличествоИспользуемыхОпорныхПолей - 1); + + ТекстЗапроса = // ТекстЗапросаУстаревшихЭлементовДанных + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ОпорныеПоляВыбора1 + |ПОМЕСТИТЬ ЗначенияИспользуемыхОпорныхПолей + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + | + |ИНДЕКСИРОВАТЬ ПО + | &ОпорныеПоляВыбора1 + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора2, + | ЛОЖЬ КАК Удалить, + | ЛОЖЬ КАК Обновить + |ИЗ + | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + | ЛЕВОЕ СОЕДИНЕНИЕ ЗначенияИспользуемыхОпорныхПолей КАК ТекущийСписок + | ПО &ОпорныеПоляДляСравнения + |ГДЕ + | &ОсновнойОтбор + | И &ОпорныеПоляДляОтбора + | И &УсловиеПроверкиПервогоПоля + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора1", ОпорныеПоляВыбораИзСписка); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора2", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСравнения", + ТекстСОтступом(ОпорныеПоляДляСравнения, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиПервогоПоля", УсловиеПроверкиПервогоПоля); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядоченияПриПроверке); + + ВариантДоступаСтрокой = XMLСтрока(Контекст.ВариантДоступа); + ВариантДоступаСтрокой = ?(ЗначениеЗаполнено(ВариантДоступаСтрокой), ВариантДоступаСтрокой, "NULL"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойВариантДоступа", ВариантДоступаСтрокой); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + Результат.ТекстЗапросаУстаревшихЭлементовДанных = ТекстЗапроса; + + ТекстЗапроса = // ТекстЗапросаПроверкиУстаревшихЭлементовДанных + "ВЫБРАТЬ + | &ОпорныеПоляВыбораПриПроверке + |ПОМЕСТИТЬ КлючиДоступаКРегистрам + |ИЗ + | &КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | &ОпорныеПоляВыбораПриПроверке + |ИЗ + | КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК ТекущийСписок + | ПО &ОпорныеПоляДляСравнения + |ГДЕ + | &УсловиеПроверкиПервогоПоля + | И &УточнениеПланаЗапроса"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораПриПроверке", ОпорныеПоляВыбораПриПроверке); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСравнения", + ТекстСОтступом(ОпорныеПоляДляСравнения, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиПервогоПоля", УсловиеПроверкиПервогоПоля); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + Результат.ТекстЗапросаПроверкиУстаревшихЭлементовДанных = ТекстЗапроса; + + Если Номер <= МаксимальноеКоличествоОпорныхПолей Тогда + ПроверкаNULL = ""; + Для Счетчик = Номер По МаксимальноеКоличествоОпорныхПолей Цикл + ПроверкаNULL = ПроверкаNULL + ?(ПроверкаNULL = "", "", " + |ИЛИ ") + СтрШаблон("КлючиДоступаКРегистрам.Поле%1 <> ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)", Счетчик); // @query-part-3 + КонецЦикла; + Иначе + ПроверкаNULL = "ЛОЖЬ"; + КонецЕсли; + + ТекстЗапроса = // ТекстЗапросаНекорректныхЭлементовДанных + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляВыбора, + | НЕ КлючиДоступаКРегистрам.ВариантДоступа В (&ИспользуемыеВариантыДоступа) КАК Удалить, + | КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа + | И &ПроверкаNULL2 КАК Обновить + |ИЗ + | &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + |ГДЕ + | &ОсновнойОтбор + | И &ОтборПоВидуПользователей + | И &ОпорныеПоляДляОтбора + | И (НЕ КлючиДоступаКРегистрам.ВариантДоступа В (&ИспользуемыеВариантыДоступа) + | ИЛИ КлючиДоступаКРегистрам.ВариантДоступа = &ОсновнойВариантДоступа + | И &ПроверкаNULL1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбора", ОпорныеПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойОтбор", ОсновнойОтбор); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОтборПоВидуПользователей", ОтборПоВидуПользователей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверкаNULL1", + "(" + ТекстСОтступом(ПроверкаNULL, " ") + ")"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверкаNULL2", + "(" + ТекстСОтступом(ПроверкаNULL, " ") + ")"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоляДляУпорядочения); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОсновнойВариантДоступа", ВариантДоступаСтрокой); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Результат.Список); + + ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); + ВариантыДоступаСтрокой = Новый Массив; + Если ИспользуемыеВариантыДоступа = Неопределено Тогда + ВариантыДоступаСтрокой.Добавить("NULL"); + Иначе + Для Каждого ИспользуемыйВариантДоступа Из ИспользуемыеВариантыДоступа Цикл + ВариантыДоступаСтрокой.Добавить(XMLСтрока(ИспользуемыйВариантДоступа.ВариантДоступа)); + КонецЦикла; + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИспользуемыеВариантыДоступа", + СтрСоединить(ВариантыДоступаСтрокой, ",")); + + Результат.ТекстЗапросаНекорректныхЭлементовДанных = ТекстЗапроса; + + ОпорныеПоляВыбораДляОбновления = ОпорныеПоляВыбора + ", + | КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа"; // @query-part-1 + + ТекстЗапроса = // ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных + "ВЫБРАТЬ + | &ОпорныеПоляВыбораПриПроверке + |ПОМЕСТИТЬ ЭлементыДанных + |ИЗ + | &ЭлементыДанных КАК КлючиДоступаКРегистрам + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | &ОпорныеПоляВыбораДляОбновления + |ИЗ + | ЭлементыДанных КАК ЭлементыДанных + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТекущийРегистрКлючей КАК КлючиДоступаКРегистрам + | ПО &ОпорныеПоляДляСоединения"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораПриПроверке", ОпорныеПоляВыбораПриПроверке); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляВыбораДляОбновления", ОпорныеПоляВыбораДляОбновления); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистрКлючей", "РегистрСведений." + ИмяРегистра); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляСоединения", + ТекстСОтступом(ОпорныеПоляДляСоединения, " ")); + + Результат.ТекстЗапросаДляОбновленияУстаревшихЭлементовДанных = ТекстЗапроса; + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьИспользуемыеПоляОсновнойТаблицы(Контекст) + + Если Не ЗначениеЗаполнено(Контекст.ПоляТаблицОбъекта.Результат) Тогда + Возврат; + КонецЕсли; + + ОписаниеОсновнойТаблицы = Неопределено; + Для Каждого ОписаниеТаблицы Из Контекст.ПоляТаблицОбъекта.Результат Цикл + Если Не ЗначениеЗаполнено(ОписаниеТаблицы.ТабличнаяЧасть) Тогда + ОписаниеОсновнойТаблицы = ОписаниеТаблицы; + Прервать; + КонецЕсли; + КонецЦикла; + + Если ОписаниеОсновнойТаблицы = Неопределено Тогда + Возврат; + КонецЕсли; + + ДополнительныеПоля = ""; + Для Каждого ИмяПоля Из ОписаниеОсновнойТаблицы.Поля Цикл + Если ИмяПоля = "Ссылка" Тогда + Продолжить; + КонецЕсли; + ДополнительныеПоля = ДополнительныеПоля + СтрШаблон(", + |ТекущийСписок.%1 КАК %1", ИмяПоля); + КонецЦикла; + + Контекст.ИспользуемыеПоляОсновнойТаблицы = ДополнительныеПоля; + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьШаблоныЧастейЗапросаПроверки(Контекст) + + Если Контекст.ЭтоСсылочныйТип Тогда + ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта(Контекст); + Иначе + ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра(Контекст); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьШаблоныЧастейЗапросаПроверки. +Процедура ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта(Контекст) + + Контекст.Вставить("ТекстЗапросаДиапазонаЭлементовДанных"); + Контекст.Вставить("ТекстЗапросаПроверки"); + Контекст.Вставить("ТекстЗапросаПроверкиСвязи"); + Контекст.Вставить("ТекстЗапросаПроверкиШапки"); + Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧасти"); + Контекст.Вставить("ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта"); + Контекст.Вставить("ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта"); + Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверки"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиСвязи"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиШапки"); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиТабличнойЧасти"); + + Если Контекст.СписокСДатой Тогда + Контекст.ТекстЗапросаДиапазонаЭлементовДанных = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЭлементыДанных.Дата КАК ДатаНачалаДиапазона, + | ЭлементыДанных.Ссылка КАК СсылкаДатыНачалаДиапазона + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Дата >= &ДатаНачала + | И ТекущийСписок.Дата <= &ДатаОкончанияДиапазона + | И (ТекущийСписок.Дата < &ДатаОкончанияДиапазона + | ИЛИ ТекущийСписок.Дата = &ДатаОкончанияДиапазона + | И ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона) + | + | УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Дата УБЫВ, + | ТекущийСписок.Ссылка УБЫВ) КАК ЭлементыДанных + | + |УПОРЯДОЧИТЬ ПО + | ЭлементыДанных.Дата, + | ЭлементыДанных.Ссылка"; + + Контекст.ТекстЗапросаПроверки = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля1, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2 + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Дата >= &ДатаНачалаДиапазона + | И (ТекущийСписок.Дата > &ДатаНачалаДиапазона + | ИЛИ ТекущийСписок.Дата = &ДатаНачалаДиапазона + | И ТекущийСписок.Ссылка >= &СсылкаДатыНачалаДиапазона) + | И ТекущийСписок.Дата <= &ДатаОкончанияДиапазона + | И (ТекущийСписок.Дата < &ДатаОкончанияДиапазона + | ИЛИ ТекущийСписок.Дата = &ДатаОкончанияДиапазона + | И ТекущийСписок.Ссылка < &СсылкаДатыОкончанияДиапазона)) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Дата УБЫВ, + | ТекущийСписок.Ссылка УБЫВ"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиСвязи = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ТекущийКлючДоступа ЕСТЬ NULL"; + + Контекст.ТекстЗапросаПроверкиШапки = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиТабличнойЧасти = + "ВЫБРАТЬ + | ТекущийСписок.Дата КАК Дата, + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Дата, + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + Иначе + Контекст.ТекстЗапросаДиапазонаЭлементовДанных = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЭлементыДанных.Ссылка КАК СсылкаОкончанияДиапазона + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Ссылка > &СсылкаНачалаДиапазона + | + | УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка) КАК ЭлементыДанных + | + |УПОРЯДОЧИТЬ ПО + | ЭлементыДанных.Ссылка УБЫВ"; + + Контекст.ТекстЗапросаПроверки = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля1, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2 + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Ссылка > &СсылкаНачалаДиапазона + | И ТекущийСписок.Ссылка <= &СсылкаОкончанияДиапазона) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + | + |УПОРЯДОЧИТЬ ПО + | ТекущийСписок.Ссылка"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиСвязи = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок + |ГДЕ + | ТекущийСписок.ТекущийКлючДоступа ЕСТЬ NULL"; + + Контекст.ТекстЗапросаПроверкиШапки = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиТабличнойЧасти = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + КонецЕсли; + + Контекст.ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |ГДЕ + | КлючиДоступаКОбъектам.Объект ЕСТЬ NULL"; + + Контекст.ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + | ГДЕ + | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + | ГДЕ + | ТекущийСписок.Ссылка = &Ссылка) КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + // Запросы точечной проверки. + Контекст.ТекстЗапросаТочечнойПроверки = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + |ГДЕ + | &УточнениеПланаЗапроса"; + + Контекст.ТекстЗапросаТочечнойПроверкиСвязи = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам + | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка)) КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка) + |ГДЕ + | КлючиДоступаКОбъектам.Объект ЕСТЬ NULL"; + + Контекст.ТекстЗапросаТочечнойПроверкиШапки = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам + | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка)) КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + Контекст.ТекстЗапросаТочечнойПроверкиТабличнойЧасти = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | (ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК Ссылка,&ДополнительныеПоля2, + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК ТекущийКлючДоступа + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущийСписокПоВедущимОбъектам КАК ТекущийСписокПоВедущимОбъектам + | ПО (ТекущийСписокПоВедущимОбъектам.Ссылка = ТекущийСписок.Ссылка) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = ТекущийСписок.Ссылка)) КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | ТекущийСписок.Ссылка, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + Если Не Контекст.Свойство("ОписаниеЗапросовПроверкиПоВедущимОбъектам") Тогда + Возврат; + КонецЕсли; + + ТекстЗапроса = // ТекстЗапросаОберткиВыбораДанных + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам + |ИЗ + | #ЗапросыВыбораДанных КАК ТекущийСписок"; + + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаОберткиВыбораДанных", ТекстЗапроса); + + ШаблонЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | ТекущийСписок.Ссылка КАК Ссылка + |ИЗ + | "; // @query-part-1 + ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст); + +КонецПроцедуры + +// Для процедуры ЗаполнитьШаблоныЧастейЗапросаПроверки. +Процедура ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра(Контекст) + + ОпорныеПоля = Контекст.ОпорныеПоля; + ОпорныеПоля.Вставить("ДляВыбора", ""); + ОпорныеПоля.Вставить("ДляУпорядочения", ""); + + КоличествоИспользуемыхПолей = ОпорныеПоля.Используемые.Количество(); + ДобавлятьОтборПоПервомуПолю = КоличествоИспользуемыхПолей > 1 + И ОпорныеПоля.ТипыИспользуемых[0].Получить().Типы().Количество() = 1; + + // Для запроса новых комбинаций. + ОпорныеПоляДляВыбора = ""; + ОпорныеПоляУсловиеСоединения = ""; + ОпорныеПоляДляГруппировкиИлиУпорядочения = ""; + ОпорныеПоляДляОтбора1 = ""; // СписокСПериодом + ОпорныеПоляДляОтбора2 = ?(Не ДобавлятьОтборПоПервомуПолю, "", СтрШаблон( + "ТекущийРегистр.%2 >= &Поле%1 + | И ", 1, ОпорныеПоля.Используемые[0])); + + // Для запроса текущих ключей доступа. + УсловиеОтбора = ""; + ПоляОтбора = ""; + + Если Не ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + Контекст.ОтдельныйРегистр = Ложь; + // Для запроса новых комбинаций. + ОпорныеПоляУсловиеСоединения = "(КлючиДоступаКРегистрам.Регистр = &ИдентификаторРегистра)"; + // Для запроса текущих ключей доступа. + УсловиеОтбора = "ТекущийСписок.Регистр = &ИдентификаторРегистра"; + // Для запроса комбинаций с устаревшими ключами. + ПоляОтбора = "ТекущийСписок.Регистр = &ИдентификаторРегистра"; + КонецЕсли; + + // Для запроса новых комбинаций. + ОпорныеПоляУсловиеСоединения = ОпорныеПоляУсловиеСоединения + ?(ОпорныеПоляУсловиеСоединения = "", "", " + | И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа)"; // @query-part-3 + + // Для запроса текущих ключей доступа. + УсловиеОтбора = УсловиеОтбора + ?(УсловиеОтбора = "", "", " + | И ") + "ТекущийСписок.ВариантДоступа = &ВариантДоступа"; // @query-part-3 + + // Для запроса комбинаций с устаревшими ключами. + ПоляОтбора = ПоляОтбора + ?(ПоляОтбора = "", "", " + | И ") + "ТекущийСписок.ВариантДоступа = &ВариантДоступа"; // @query-part-3 + + ПоляДляВыбораДиапазона = ""; + + ПоляОтбора1 = ""; + ПоляОтбора2 = ""; + + СтрокаТабуляций = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(" ", + КоличествоИспользуемыхПолей * 3); + + Номер = 0; + Для Каждого ИмяОпорногоПоля Из ОпорныеПоля.Используемые Цикл + Номер = Номер + 1; + + // Для запроса новых комбинаций. + ОпорныеПоляДляВыбора = ОпорныеПоляДляВыбора + ?(ОпорныеПоляДляВыбора = "", "", ", + | ") + СтрШаблон("ТекущийРегистр.%2 КАК Поле%1", Номер, ИмяОпорногоПоля); // @query-part-4 + + ОпорныеПоляУсловиеСоединения = ОпорныеПоляУсловиеСоединения + ?(ОпорныеПоляУсловиеСоединения = "", "", " + | И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ТекущийРегистр.%2)", Номер, ИмяОпорногоПоля); // @query-part-3 + + ОпорныеПоляДляГруппировкиИлиУпорядочения = ОпорныеПоляДляГруппировкиИлиУпорядочения + + ?(ОпорныеПоляДляГруппировкиИлиУпорядочения = "", "", ", ") + ИмяОпорногоПоля; + + Если Номер = КоличествоИспользуемыхПолей Тогда + Отбор = "ТекущийРегистр.%2 > &Поле%1"; // @query-part-1 + Иначе + Отбор = "(ТекущийРегистр.%2 > &Поле%1 + | ИЛИ ТекущийРегистр.%2 = &Поле%1"; // @query-part-1 + КонецЕсли; + Отбор = ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер, ИмяОпорногоПоля), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + ОпорныеПоляДляОтбора1 = ОпорныеПоляДляОтбора1 + Отбор; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + Отбор; + + // Для запроса текущих ключей доступа. + УсловиеОтбора = УсловиеОтбора + ?(УсловиеОтбора = "", "", " + | И ") + СтрШаблон("ТекущийСписок.Поле%1 = &Поле%1", Номер) + "_%1"; // @query-part-3 + + // Для запроса комбинаций с устаревшими ключами. + ОпорныеПоля.ДляВыбора = ОпорныеПоля.ДляВыбора + ?(ОпорныеПоля.ДляВыбора = "", "", ", + | ") + СтрШаблон("ТекущийСписок.Поле%1 КАК Поле%1", Номер); // @query-part-4 + + ПоляДляВыбораДиапазона = ПоляДляВыбораДиапазона + ?(ПоляДляВыбораДиапазона = "", "", ", + | ") + СтрШаблон("ЭлементыДанных.Поле%1 КАК Поле%1ОкончанияДиапазона", Номер); // @query-part-4 + + Если Номер = КоличествоИспользуемыхПолей Тогда + Отбор = "ТекущийСписок.Поле%1 > &Поле%1НачалаДиапазона"; // @query-part-1 + Иначе + Отбор = "(ТекущийСписок.Поле%1 > &Поле%1НачалаДиапазона + | ИЛИ ТекущийСписок.Поле%1 = &Поле%1НачалаДиапазона"; // @query-part-1 + КонецЕсли; + ПоляОтбора1 = ПоляОтбора1 + ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + + Если Номер = КоличествоИспользуемыхПолей Тогда + Отбор = "ТекущийСписок.Поле%1 <= &Поле%1ОкончанияДиапазона"; // @query-part-1 + Иначе + Отбор = "(ТекущийСписок.Поле%1 < &Поле%1ОкончанияДиапазона + | ИЛИ ТекущийСписок.Поле%1 = &Поле%1ОкончанияДиапазона"; // @query-part-1 + КонецЕсли; + ПоляОтбора2 = ПоляОтбора2 + ТекстСОтступом(?(Номер = 1, "", " + |И ") + СтрШаблон(Отбор, Номер), Лев(СтрокаТабуляций, Номер * 2)); // @query-part-2 + + ОпорныеПоля.ДляУпорядочения = ОпорныеПоля.ДляУпорядочения + + ?(ОпорныеПоля.ДляУпорядочения = "", "", ", ") + СтрШаблон("Поле%1", Номер); + КонецЦикла; + + Если КоличествоИспользуемыхПолей > 1 Тогда + Скобки = УправлениеДоступомСлужебныйПовтИсп.СтрокаСимволов(")", КоличествоИспользуемыхПолей - 1); + ОпорныеПоляДляОтбора1 = ОпорныеПоляДляОтбора1 + Скобки; + ОпорныеПоляДляОтбора2 = ОпорныеПоляДляОтбора2 + Скобки; + ПоляОтбора1 = ПоляОтбора1 + Скобки; + ПоляОтбора2 = ПоляОтбора2 + Скобки; + КонецЕсли; + ПоляОтбора1 = ПоляОтбора + " + | И " + ПоляОтбора1; // @query-part-1 + ПоляОтбора2 = ПоляОтбора1 + " + | И " + ПоляОтбора2; // @query-part-1 + + // Запросы комбинаций с устаревшими ключами. + ТекстЗапроса = // ТекстЗапросаДиапазонаЭлементовДанных + "ВЫБРАТЬ ПЕРВЫЕ 1 + | &ПоляДляВыбораДиапазона + |ИЗ + | (ВЫБРАТЬ ПЕРВЫЕ 993 + | &ОпорныеПоляДляВыбора + | ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ГДЕ + | &ОпорныеПоляДляОтбора + | + | УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения) КАК ЭлементыДанных + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляОбратногоУпорядочения"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляДляВыбораДиапазона", ПоляДляВыбораДиапазона); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ТекстСОтступом(ОпорныеПоля.ДляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ТекстСОтступом(ПоляОтбора1, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоля.ДляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОбратногоУпорядочения", + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ",", " УБЫВ,") + " УБЫВ"); // @query-part-3, @query-part-4 + Контекст.Вставить("ТекстЗапросаДиапазонаЭлементовДанных", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверки + "ВЫБРАТЬ ПЕРВЫЕ 993 + | &ОпорныеПоляДляВыбора, + | ТекущийСписок.КлючДоступа КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущаяПорцияЭлементовДанных + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | &ОпорныеПоляДляОтбора + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ОпорныеПоляДляВыбора + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляУпорядочения"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ПоляОтбора2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", ОпорныеПоля.ДляУпорядочения); + Контекст.Вставить("ТекстЗапросаПроверки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверкиШапки + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.Вставить("ТекстЗапросаПроверкиШапки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверкиТабличнойЧасти + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущаяПорцияЭлементовДанных КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | &ОпорныеПоляДляГруппировки, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировки", + "ТекущийСписок." + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ", ", ", + | ТекущийСписок.")); + Контекст.Вставить("ТекстЗапросаПроверкиТабличнойЧасти", ТекстЗапроса); + + // Запросы точечной проверки. + ТекстЗапроса = // ТекстЗапросаТочечнойПроверки + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ОпорныеПоляДляВыбора + |ИЗ + | &ЧастиЗапросаПроверки КАК ТекущийСписок + |ГДЕ + | &УточнениеПланаЗапроса"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.Вставить("ТекстЗапросаТочечнойПроверки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаТочечнойПроверкиШапки + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущийСписокПоВедущимОбъектам КАК ТекущийСписок #Соединения + |ГДЕ + | &УсловиеЗапроса"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиШапки", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаПроверкиТабличнойЧасти + "ВЫБРАТЬ + | &ОпорныеПоляДляВыбора + |ИЗ + | ТекущийСписокПоВедущимОбъектам КАК ТекущийСписок #Соединения + | + |СГРУППИРОВАТЬ ПО + | &ОпорныеПоляДляГруппировки, + | ТекущийСписок.ТекущийКлючДоступа + | + |ИМЕЮЩИЕ + | (МАКСИМУМ(ТабличнаяЧасть?.НомерСтроки ЕСТЬ NULL) = ИСТИНА + | ИЛИ НЕ КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ТабличнаяЧасть?.НомерСтроки) В + | (ВЫБРАТЬ + | КОЛИЧЕСТВО(ТабличнаяЧасть?.Ссылка) КАК КоличествоСтрок + | ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ГДЕ + | ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа))"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировки", + "ТекущийСписок." + СтрЗаменить(ОпорныеПоля.ДляУпорядочения, ", ", ", + | ТекущийСписок.")); + Контекст.Вставить("ТекстЗапросаТочечнойПроверкиТабличнойЧасти", ТекстЗапроса); + + ТекстЗапроса = // ТекстЗапросаОберткиВыбораДанныхДляТочечнойПроверкиКомбинаций + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляДляВыбора, + | ТекущийСписок.ТекущийКлючДоступа КАК ТекущийКлючДоступа + |ПОМЕСТИТЬ ТекущийСписокПоВедущимОбъектам + |ИЗ + | #ЗапросыВыбораДанных КАК ТекущийСписок"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаОберткиВыбораДанных", ТекстЗапроса); + + ШаблонЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляДляВыбора, + | ТекущийСписок.КлючДоступа КАК ТекущийКлючДоступа + |ИЗ + | "; // @query-part-1 + ШаблонЗапроса = СтрЗаменить(ШаблонЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоля.ДляВыбора); + ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст); + + // Запросы новых комбинаций значений полей. + Если Контекст.СписокСПериодом Тогда + ТекстЗапроса = // ТекстЗапросаНовыхКомбинаций + "ВЫБРАТЬ ПЕРВЫЕ 995 + | МАКСИМУМ(ТекущийРегистр.Период) КАК Период, + | &ОпорныеПоляДляВыбора + |ИЗ + | &ТекущийРегистр КАК ТекущийРегистр + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО &ОпорныеПоляУсловиеСоединения + |ГДЕ + | ТекущийРегистр.Период >= &ДатаНачала + | И ТекущийРегистр.Период <= &ДатаОкончания + | И (ТекущийРегистр.Период < &ДатаОкончания + | ИЛИ ТекущийРегистр.Период = &ДатаОкончания + | И &ОпорныеПоляДляОтбора) + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL + | И &УточнениеПланаЗапроса + | + |СГРУППИРОВАТЬ ПО + | &ОпорныеПоляДляГруппировкиИлиУпорядочения + | + |УПОРЯДОЧИТЬ ПО + | Период УБЫВ, &ОпорныеПоляДляГруппировкиИлиУпорядочения"; + Если Контекст.ИмяКоллекцииТипа = "РегистрыРасчета" Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + ".Период", ".ПериодРегистрации"); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоляДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляУсловиеСоединения", ОпорныеПоляУсловиеСоединения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ТекстСОтступом(ОпорныеПоляДляОтбора1, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировкиИлиУпорядочения", + ОпорныеПоляДляГруппировкиИлиУпорядочения); + Иначе + ТекстЗапроса = // ТекстЗапросаНовыхКомбинаций + "ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ 995 + | &ОпорныеПоляДляВыбора + |ИЗ + | &ТекущийРегистр КАК ТекущийРегистр + | ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО &ОпорныеПоляУсловиеСоединения + |ГДЕ + | &ОпорныеПоляДляОтбора + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | &ОпорныеПоляДляГруппировкиИлиУпорядочения"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", ОпорныеПоляДляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляУсловиеСоединения", ОпорныеПоляУсловиеСоединения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляОтбора", ОпорныеПоляДляОтбора2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляГруппировкиИлиУпорядочения", + ОпорныеПоляДляГруппировкиИлиУпорядочения); + КонецЕсли; + Контекст.Вставить("ТекстЗапросаНовыхКомбинаций", ТекстЗапроса); + + // Запрос текущих ключей доступа. + ТекстЗапроса = // ТекстЗапросаТекущихКлючейДоступа + "ВЫБРАТЬ ПЕРВЫЕ 2 + | ТекущийСписок.КлючДоступа КАК КлючДоступа + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + |ГДЕ + | &УсловиеОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + Контекст.Вставить("ТекстЗапросаТекущихКлючейДоступа", ТекстЗапроса); + +КонецПроцедуры + +// Для процедур ЗаполнитьШаблоныЧастейЗапросаПроверкиОбъекта, ЗаполнитьШаблоныЧастейЗапросаПроверкиРегистра. +Процедура ДобавитьЗапросыПроверкиПоВедущимСпискам(ШаблонЗапроса, Контекст) + + ОписаниеЗапросов = Новый Соответствие; + Для Каждого СоединениеОтбора Из Контекст.ВедущиеСпискиПоЗначениямПолей.СоединенияОтборов Цикл + ОписаниеСоединения = СоединениеОтбора.Значение; + Поля = Контекст.ВедущиеСпискиПоЗначениямПолей.Поля.Получить(СоединениеОтбора.Ключ); + ВедущаяТаблица = СоединениеОтбора.Ключ; + Если ОписаниеСоединения.ПоляШапки.Количество() > 0 Тогда + ОписаниеЗапросов.Вставить(ВедущаяТаблица, + ОписаниеЗапросовПроверкиПоВедущейТаблице(ОписаниеСоединения.ПоляШапки, + Поля.ДляОтбора.ПоляШапки, ВедущаяТаблица, ШаблонЗапроса, Контекст)); + КонецЕсли; + Для Каждого ОписаниеТабличнойЧасти Из ОписаниеСоединения.ТабличныеЧасти Цикл + ВедущаяТаблица = СоединениеОтбора.Ключ + "." + ОписаниеТабличнойЧасти.Ключ; + ТипыПолей = Поля.ДляОтбора.ТабличныеЧасти.Получить(ОписаниеТабличнойЧасти.Ключ); + ОписаниеЗапросов.Вставить(ВедущаяТаблица, + ОписаниеЗапросовПроверкиПоВедущейТаблице(ОписаниеТабличнойЧасти.Значение, + ТипыПолей, ВедущаяТаблица, ШаблонЗапроса, Контекст)); + КонецЦикла; + КонецЦикла; + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ПоЗначениямПолей", ОписаниеЗапросов); + + ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков("ПоЗначениямСГруппами", ШаблонЗапроса, Контекст); + ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков("ПоКлючамДоступа", ШаблонЗапроса, Контекст); + +КонецПроцедуры + +// Для процедуры ДобавитьЗапросыПроверкиПоВедущимСпискам. +Функция ОписаниеЗапросовПроверкиПоВедущейТаблице(СоединенияОтборов, ТипыПолей, + ВедущаяТаблица, ШаблонЗапроса, Контекст) + + ВедущаяТаблицаБезТочек = СтрЗаменить(ВедущаяТаблица, ".", "_"); + + Поля = Новый Массив; + Для Каждого ОписаниеПоля Из ТипыПолей Цикл + Поля.Добавить(ОписаниеПоля.Ключ + " КАК " + ОписаниеПоля.Ключ); + КонецЦикла; + + ТекстЗапроса = // ТекстЗапросаПараметров + "ВЫБРАТЬ + | &ПоляТаблицы + |ПОМЕСТИТЬ #ВедущаяТаблицаБезТочек + |ИЗ + | &ВедущаяТаблицаБезТочек КАК ТекущиеДанныеДляОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляТаблицы", + "ТекущиеДанныеДляОтбора." + СтрСоединить(Поля, ", + | ТекущиеДанныеДляОтбора.")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ВедущаяТаблицаБезТочек", ВедущаяТаблицаБезТочек); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВедущаяТаблицаБезТочек", "&" + ВедущаяТаблицаБезТочек); + + ОписаниеЗапросов = Новый Структура; + ОписаниеЗапросов.Вставить("ТипыПолей", ТипыПолей); + ОписаниеЗапросов.Вставить("ТекстЗапросаПараметров", ТекстЗапроса); + ОписаниеЗапросов.Вставить("ТекстыЗапросовДанных", Новый Массив); + + Для Каждого СоединениеОтбора Из СоединенияОтборов Цикл + ТекстЗапроса = ШаблонЗапроса + ТекстСОтступом(СоединениеОтбора, " "); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТекущиеДанныеДляОтбора", ВедущаяТаблицаБезТочек); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + ОписаниеЗапросов.ТекстыЗапросовДанных.Добавить(ТекстЗапроса); + КонецЦикла; + + Возврат ОписаниеЗапросов; + +КонецФункции + +// Для процедуры ДобавитьЗапросыПроверкиПоВедущимСпискам. +Процедура ДобавитьЗапросыПроверкиПоПолюСсылкаВедущихСписков(ВидВедущегоСписка, ШаблонЗапроса, Контекст) + + Свойства = ?(ВидВедущегоСписка = "ПоКлючамДоступа", + Контекст.ВедущиеСпискиПоКлючамДоступа, Контекст.ВедущиеСпискиПоЗначениямСГруппами); + + Если Не ЗначениеЗаполнено(Свойства.СоединенияОтборов) Тогда + Возврат; + КонецЕсли; + + ИмяВременнойТаблицы = "ТекущиеДанныеДляОтбора" + ВидВедущегоСписка; + + ТекстЗапросаПараметров = + "ВЫБРАТЬ + | ТекущиеДанныеДляОтбора.Ссылка + |ПОМЕСТИТЬ #ИмяВременнойТаблицы + |ИЗ + | &ВидВедущегоСписка КАК ТекущиеДанныеДляОтбора"; + ТекстЗапросаПараметров = СтрЗаменить(ТекстЗапросаПараметров, "#ИмяВременнойТаблицы", ИмяВременнойТаблицы); + ТекстЗапросаПараметров = СтрЗаменить(ТекстЗапросаПараметров, "&ВидВедущегоСписка", "&" + ВидВедущегоСписка); + + ТекстыЗапросовПоКлючам = Новый Соответствие; + Для Каждого СоединениеОтбора Из Свойства.СоединенияОтборов Цикл + ТекстЗапроса = ШаблонЗапроса + ТекстСОтступом(СоединениеОтбора.Значение, " "); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ТекущиеДанныеДляОтбора", ИмяВременнойТаблицы); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + ТекстыЗапросовПоКлючам.Вставить(СоединениеОтбора.Ключ, ТекстЗапроса); + КонецЦикла; + + ОписаниеЗапросов = Новый Структура; + ОписаниеЗапросов.Вставить("ТипСсылки", Новый ХранилищеЗначения(Свойства.ТипСсылки)); + ОписаниеЗапросов.Вставить("КлючиЗапросовПоТипам", Свойства.КлючиЗапросовПоТипам); + ОписаниеЗапросов.Вставить("ТекстыЗапросовПоКлючам", ТекстыЗапросовПоКлючам); + ОписаниеЗапросов.Вставить("ТекстЗапросаПараметров", ТекстЗапросаПараметров); + + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить(ВидВедущегоСписка, ОписаниеЗапросов); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура СобратьЧастиЗапросаПроверки(Результат, Контекст) + + ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаДиапазонаЭлементовДанных, Контекст); + Результат.ТекстЗапросаДиапазонаЭлементовДанных = Контекст.ТекстЗапросаДиапазонаЭлементовДанных; + + ЧастиЗапроса1 = Новый Массив; + ЧастиЗапроса2 = Новый Массив; + ЧастиЗапроса3 = Новый Массив; + Если Контекст.ЭтоСсылочныйТип Тогда + ЧастиЗапроса1.Добавить(Контекст.ТекстЗапросаПроверкиСвязи); + ЧастиЗапроса2.Добавить(Контекст.ТекстЗапросаТочечнойПроверкиСвязи); + ЧастиЗапроса3.Добавить(Контекст.ТекстЗапросаПроверкиСвязиКлючаДоступаОбъекта); + КонецЕсли; + + Для Каждого ЧастьУсловияПроверки Из Контекст.ЧастиУсловияПроверки Цикл + ДобавитьЧастьЗапроса(ЧастиЗапроса1, ЧастьУсловияПроверки, Контекст, + Контекст.ТекстЗапросаПроверкиШапки, + Контекст.ТекстЗапросаПроверкиТабличнойЧасти); + + ДобавитьЧастьЗапроса(ЧастиЗапроса2, ЧастьУсловияПроверки, Контекст, + Контекст.ТекстЗапросаТочечнойПроверкиШапки, + Контекст.ТекстЗапросаТочечнойПроверкиТабличнойЧасти); + + Если Контекст.ЭтоСсылочныйТип Тогда + ДобавитьЧастьЗапроса(ЧастиЗапроса3, ЧастьУсловияПроверки, Контекст, + Контекст.ТекстЗапросаПроверкиШапкиКлючаДоступаОбъекта, + Контекст.ТекстЗапросаПроверкиТабличнойЧастиКлючаДоступаОбъекта); + КонецЕсли; + КонецЦикла; + + ТекстЧастейЗапроса = СтрСоединить(ЧастиЗапроса1, ОбщегоНазначения.ТекстОбъединитьВсе()); + ТекстЗапроса = СтрЗаменить(Контекст.ТекстЗапросаПроверки, ",&ДополнительныеПоля1", + ТекстСОтступом(Контекст.ИспользуемыеПоляОсновнойТаблицы, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ДополнительныеПоля2", + ТекстСОтступом(Контекст.ИспользуемыеПоляОсновнойТаблицы, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ЧастиЗапросаПроверки", + "(" + ТекстСОтступом(ТекстЧастейЗапроса, " ") + ")"); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЭлементовДанныхСУстаревшимиКлючами = ТекстЗапроса; + + ТекстЧастейЗапроса = СтрСоединить(ЧастиЗапроса2, ОбщегоНазначения.ТекстОбъединитьВсе()); + ТекстЗапроса = СтрЗаменить(Контекст.ТекстЗапросаТочечнойПроверки, "&ЧастиЗапросаПроверки", + "(" + ТекстСОтступом(ТекстЧастейЗапроса, " ") + ")"); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам.Вставить("ТекстЗапросаТочечнойПроверки", ТекстЗапроса); + + Результат.ОписаниеЗапросовУстаревшихКлючейДоступаПоВедущимОбъектам = + Контекст.ОписаниеЗапросовПроверкиПоВедущимОбъектам; + + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = СтрСоединить(ЧастиЗапроса3, ОбщегоНазначения.ТекстОбъединитьВсе()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаПроверкиКлючаДоступаОбъекта = ТекстЗапроса; + Иначе + ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаНовыхКомбинаций, Контекст); + Результат.ТекстЗапросаЭлементовДанныхБезКлючейДоступа = Контекст.ТекстЗапросаНовыхКомбинаций; + + ПодставитьОбщиеПараметрыВЗапрос(Контекст.ТекстЗапросаТекущихКлючейДоступа, Контекст); + Результат.ТекстЗапросаТекущихКлючейДоступаРегистра = Контекст.ТекстЗапросаТекущихКлючейДоступа; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросаПроверки. +Процедура ДобавитьЧастьЗапроса(ЧастиЗапроса, ЧастьУсловияПроверки, Контекст, + ТекстДляШапки, ТекстДляТабличнойЧасти) + + Если ЗначениеЗаполнено(ЧастьУсловияПроверки.ИмяТабличнойЧастиКлюча) Тогда + ТекущийТекст = ТекстДляТабличнойЧасти; + Иначе + ТекущийТекст = ТекстДляШапки; + КонецЕсли; + + ТекущийТекст = СтрЗаменить(ТекущийТекст, ",&ДополнительныеПоля2", + ТекстСОтступом(ЧастьУсловияПроверки.ДополнительныеПоля, " ")); + + ТекущийТекст = СтрЗаменить(ТекущийТекст, " #Соединения", " + | " + ТекстСОтступом(ЧастьУсловияПроверки.Соединения, " ")); + + ТекущийТекст = СтрЗаменить(ТекущийТекст, + "ТабличнаяЧасть?", ЧастьУсловияПроверки.ИмяТабличнойЧастиКлюча); + + ЧастиЗапроса.Добавить(СтрЗаменить(ТекущийТекст, + "&УсловиеЗапроса", ТекстСОтступом(ЧастьУсловияПроверки.Условие, " "))); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура СобратьЧастиЗапросовЗаполнения(Результат, Контекст) + + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзОбъектов, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийЭлементовДанныхДляКлючейДоступа = ТекстЗапроса; + + Если ЗначениеЗаполнено(Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти) Тогда + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ИмяВременнойТаблицы = СтрЗаменить(Контекст.Список, ".", "_"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок.", ИмяВременнойТаблицы + "_"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", ИмяВременнойТаблицы); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийОбъектовВПамятиДляКлючейДоступа = ТекстЗапроса; + КонецЕсли; + + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийИзИспользуемыхКлючейДоступаДляСравнения = ТекстЗапроса; + Результат.ТекстЗапросаЗначенийИзВсехКлючейДоступаДляСравнения = СтрЗаменить(ТекстЗапроса, + ".НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1)", ".Список = &Список"); // @query-part-1 + + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаСуществованияКлючейДляСравнения = ТекстЗапроса; + + ДобавитьЧастьЗапросаВыбораПравВедущихКлючейДоступа(Контекст); + ДобавитьЧастьЗапросаВыбораПравВедущихСписков(Контекст); + ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав(Контекст); + ТекстЗапроса = СтрСоединить(Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав, + ОбщегоНазначения.РазделительПакетаЗапросов()); + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Результат.ТекстЗапросаЗначенийИзКлючейДоступаДляРасчетаПрав = ТекстЗапроса; + + Результат.ТекстЗапросаКлючейДоступаДляОбновленияПрав = + ТекстЗапросаКлючейДоступаДляОбновленияПрав(Контекст); + + Результат.ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав = + ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав(Контекст); + + Результат.ТекстЗапросаУстаревшихКлючейДоступа = + ТекстЗапросаУстаревшихКлючейДоступа(Контекст); + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Процедура ДобавитьЧастьЗапросаВыбораПравВедущихКлючейДоступа(Контекст) + + Если Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа[0]; + Иначе + УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа, + Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаСпискиВедущихКлючейДоступа.Таблица КАК Список, + | ПраваНаСпискиВедущихКлючейДоступа.ГруппаДоступа КАК ГруппаДоступа, + | ПраваНаСпискиВедущихКлючейДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСпискиВедущихКлючейДоступа + |ГДЕ + | ПраваНаСпискиВедущихКлючейДоступа.Таблица В + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | СпискиВедущихКлючейДоступа.Список + | ИЗ + | Справочник.КлючиДоступа КАК СпискиВедущихКлючейДоступа + | ГДЕ + | &УсловиеОтбора) + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | Список"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", + СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "СпискиВедущихКлючейДоступа.Ссылка")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + ТекстЗапроса = + "ВЫБРАТЬ + | СпискиВедущихКлючейДоступа.Ссылка КАК КлючДоступа, + | СпискиВедущихКлючейДоступа.Список КАК Список + |ИЗ + | Справочник.КлючиДоступа КАК СпискиВедущихКлючейДоступа + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса"; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", + СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "СпискиВедущихКлючейДоступа.Ссылка")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + Если Не Контекст.РассчитыватьПраваПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, + | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа + |ГДЕ + | ТИПЗНАЧЕНИЯ(ПраваНаКлючиДоступа.ГруппаДоступа) = ТИП(Справочник.ГруппыДоступа) + | И &УсловиеОтбора + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | КлючДоступа"; + ИначеЕсли Не Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, + | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа, + | ПраваНаКлючиДоступа.Пользователь.Пользователь, + | ПраваНаКлючиДоступа.ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК ПраваНаКлючиДоступа + |ГДЕ + | ПраваНаКлючиДоступа.ЭтоПраваНабораГрупп = ЛОЖЬ + | И ЕСТЬNULL(ПраваНаКлючиДоступа.Пользователь.Пользователь, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И &УсловиеОтбора + |ИТОГИ ПО + | КлючДоступа"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа КАК КлючДоступа, + | ПраваНаКлючиДоступа.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаКлючиДоступа.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаГруппДоступа КАК ПраваНаКлючиДоступа + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + | + |ОБЪЕДИНИТЬ ВСЕ + | + |ВЫБРАТЬ + | ПраваНаКлючиДоступа.КлючДоступа, + | ПраваНаКлючиДоступа.ВнешнийПользователь.Пользователь, + | ПраваНаКлючиДоступа.ПравоИзменение + |ИЗ + | РегистрСведений.КлючиДоступаВнешнихПользователей КАК ПраваНаКлючиДоступа + |ГДЕ + | ПраваНаКлючиДоступа.ЭтоПраваНабораГрупп = ЛОЖЬ + | И ЕСТЬNULL(ПраваНаКлючиДоступа.ВнешнийПользователь.Пользователь, ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) + | И &УсловиеОтбора + |ИТОГИ ПО + | КлючДоступа"; + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", + СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "ПраваНаКлючиДоступа.КлючДоступа")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Процедура ДобавитьЧастьЗапросаВыбораПравВедущихСписков(Контекст) + + Если Контекст.ЧастиУсловияВыбораПравВедущихСписков.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если Контекст.Свойство("ЧастиУсловияВыбораПравВедущихСписковСТипами") Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаСписки.Таблица КАК Список, + | ТИПЗНАЧЕНИЯ(ПраваНаСписки.Таблица.ЗначениеПустойСсылки) КАК ТипЗначения, + | ПраваНаСписки.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаСписки.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСписки + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | Список"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваНаСписки.Таблица КАК Список, + | ПраваНаСписки.ГруппаДоступа КАК ВладелецПрав, + | ПраваНаСписки.ПравоИзменение КАК ПравоИзменение + |ИЗ + | РегистрСведений.ТаблицыГруппДоступа КАК ПраваНаСписки + |ГДЕ + | &УсловиеОтбора + | И &УточнениеПланаЗапроса + |ИТОГИ ПО + | Список"; + КонецЕсли; + + Если Контекст.ЧастиУсловияВыбораПравВедущихСписков.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравВедущихСписков[0]; + Иначе + УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияВыбораПравВедущихСписков, + Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 + КонецЕсли; + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "ПраваНаСписки.Таблица"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Процедура ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав(Контекст) + + Если Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + ТекстЗапроса = ТекстЗапросаВыбораПравПоВладельцамНастроекПрав(); + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + Если Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав[0]; + Иначе + УсловиеОтбора = СтрСоединить(Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав, + Символы.ПС + " ИЛИ "); // @query-part-1 + КонецЕсли; + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "#ПроверяемоеПоле", "НаследованиеНастроек.Объект"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", ТекстСОтступом(УсловиеОтбора, " ")); + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьЧастьЗапросаВыбораПравПоВладельцамНастроекПрав и +// функции ТекстЗапросаПравПользователейПоВладельцамНастроекПрав. +// +Функция ТекстЗапросаВыбораПравПоВладельцамНастроекПрав() + + Возврат + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект + |ПОМЕСТИТЬ ОбъектыСЗапрещениемЧтения + |ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияЧтения) + | И (&УсловиеОтбора) + | И (&УточнениеПланаЗапроса) + | + |ИНДЕКСИРОВАТЬ ПО + | Объект + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект + |ПОМЕСТИТЬ ОбъектыСЗапрещениемИзменения + |ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения) + | И (&УсловиеОтбора) + | И (&УточнениеПланаЗапроса) + | + |ИНДЕКСИРОВАТЬ ПО + | Объект + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НастройкиПравЧтения.Объект КАК Объект, + | НастройкиПравЧтения.Пользователь КАК Пользователь + |ПОМЕСТИТЬ НастройкиПравЧтения + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект, + | ВЫБОР + | КОГДА НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемЧтения.Объект + | ИЗ + | ОбъектыСЗапрещениемЧтения) + | ТОГДА СоставыГруппПользователей.Пользователь + | ИНАЧЕ СоставыГруппПользователей.ГруппаПользователей + | КОНЕЦ КАК Пользователь, + | ИСТИНА КАК ЧтениеРазрешено, + | ЛОЖЬ КАК ЧтениеЗапрещено + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияЧтения) + | И (&УсловиеОтбора) + | И (&УточнениеПланаЗапроса) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект, + | СоставыГруппПользователей.Пользователь, + | ЛОЖЬ, + | ИСТИНА + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО (НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемЧтения.Объект + | ИЗ + | ОбъектыСЗапрещениемЧтения)) + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияЧтения) + | И (&УсловиеОтбора) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор)) КАК НастройкиПравЧтения + | + |СГРУППИРОВАТЬ ПО + | НастройкиПравЧтения.Объект, + | НастройкиПравЧтения.Пользователь + | + |ИМЕЮЩИЕ + | МАКСИМУМ(НастройкиПравЧтения.ЧтениеРазрешено) = ИСТИНА И + | МАКСИМУМ(НастройкиПравЧтения.ЧтениеЗапрещено) = ЛОЖЬ + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НастройкиПравИзменения.Объект КАК Объект, + | НастройкиПравИзменения.Пользователь КАК Пользователь + |ПОМЕСТИТЬ НастройкиПравИзменения + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект КАК Объект, + | ВЫБОР + | КОГДА НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемИзменения.Объект + | ИЗ + | ОбъектыСЗапрещениемИзменения) + | ТОГДА СоставыГруппПользователей.Пользователь + | ИНАЧЕ СоставыГруппПользователей.ГруппаПользователей + | КОНЕЦ КАК Пользователь, + | ИСТИНА КАК ИзменениеРазрешено, + | ЛОЖЬ КАК ИзменениеЗапрещено + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияИзменения) + | И (&УсловиеОтбора) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НастройкиПравЧтения КАК НастройкиПравЧтения + | ПО (НастройкиПравЧтения.Объект = НаследованиеНастроек.Объект) + | И (НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | ИЛИ НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.Пользователь) + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ РАЗЛИЧНЫЕ + | НаследованиеНастроек.Объект, + | СоставыГруппПользователей.Пользователь, + | ЛОЖЬ, + | ИСТИНА + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО (НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | ОбъектыСЗапрещениемИзменения.Объект + | ИЗ + | ОбъектыСЗапрещениемИзменения)) + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И (НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав) + | И (НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения) + | И (&УсловиеОтбора) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)) + | И (СоставыГруппПользователей.Используется) + | И (СоставыГруппПользователей.Пользователь.ИдентификаторПользователяИБ <> &ПустойУникальныйИдентификатор) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ НастройкиПравЧтения КАК НастройкиПравЧтения + | ПО (НастройкиПравЧтения.Объект = НаследованиеНастроек.Объект) + | И (НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.ГруппаПользователей + | ИЛИ НастройкиПравЧтения.Пользователь = СоставыГруппПользователей.Пользователь)) КАК НастройкиПравИзменения + | + |СГРУППИРОВАТЬ ПО + | НастройкиПравИзменения.Объект, + | НастройкиПравИзменения.Пользователь + | + |ИМЕЮЩИЕ + | МАКСИМУМ(НастройкиПравИзменения.ИзменениеРазрешено) = ИСТИНА И + | МАКСИМУМ(НастройкиПравИзменения.ИзменениеЗапрещено) = ЛОЖЬ + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | НастройкиПрав.Объект КАК ВладелецНастроекПрав, + | НастройкиПрав.Пользователь КАК ВладелецПрав, + | МАКСИМУМ(НастройкиПрав.ПравоИзменение) КАК ПравоИзменение + |ИЗ + | (ВЫБРАТЬ + | НастройкиПрав.Объект КАК Объект, + | НастройкиПрав.Пользователь КАК Пользователь, + | ЛОЖЬ КАК ПравоИзменение + | ИЗ + | НастройкиПравЧтения КАК НастройкиПрав + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ + | НастройкиПрав.Объект, + | НастройкиПрав.Пользователь, + | ИСТИНА + | ИЗ + | НастройкиПравИзменения КАК НастройкиПрав) КАК НастройкиПрав + | + |СГРУППИРОВАТЬ ПО + | НастройкиПрав.Объект, + | НастройкиПрав.Пользователь + |ИТОГИ ПО + | ВладелецНастроекПрав"; + +КонецФункции + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Функция ТекстЗапросаКлючейДоступаДляОбновленияПрав(Контекст) + + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.СоставПолей = &СоставПолей + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Функция ТекстЗапросаКлючейПоВедущимКлючамДляОбновленияПрав(Контекст) + + Если Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Количество() = 0 Тогда + Возврат ""; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.СоставПолей = &СоставПолей + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И &УсловиеОтбора + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Если Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Количество() = 1 Тогда + УсловиеОтбора = Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа[0]; + Иначе + УсловиеОтбора = "(" + СтрСоединить(Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа, + Символы.ПС + " ИЛИ ") + ")"; // @query-part-2 + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры СобратьЧастиЗапросовЗаполнения. +Функция ТекстЗапросаУстаревшихКлючейДоступа(Контекст) + + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапросаИспользуемых = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаКОбъектам.#КлючДоступаПользователей КАК КлючДоступа + |ПОМЕСТИТЬ ИспользуемыеКлючиДоступа + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | ТИПЗНАЧЕНИЯ(КлючиДоступаКОбъектам.Объект) = ТИП(&ТекущийСписок) + | И КлючиДоступаКОбъектам.#КлючДоступаПользователей > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |ИНДЕКСИРОВАТЬ ПО + | КлючДоступа"; // @query-part + Иначе + ТекстЗапросаИспользуемых = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | КлючиДоступаКРегистрам.КлючДоступа КАК КлючДоступа + |ПОМЕСТИТЬ ИспользуемыеКлючиДоступа + |ИЗ + | &ТекущийСписок КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = &Список + | И КлючиДоступаКРегистрам.ВариантДоступа = &ВариантДоступа + | И КлючиДоступаКРегистрам.КлючДоступа > &ПоследнийКлючДоступа + | И &УточнениеПланаЗапроса + | + |ИНДЕКСИРОВАТЬ ПО + | КлючДоступа"; + Если ЗначениеЗаполнено(Контекст.ИмяОтдельногоРегистраКлючей) Тогда + ТекстЗапросаИспользуемых = СтрЗаменить(ТекстЗапросаИспользуемых, + "КлючиДоступаКРегистрам.Регистр = &Список + | И ", ""); // @query-part-1 + КонецЕсли; + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 995 + | КлючиДоступа.Ссылка КАК Ссылка, + | КлючиДоступа.Список КАК Список, + | КлючиДоступа.СоставПолей КАК СоставПолей, + | КлючиДоступа.Хеш КАК Хеш, + | НЕ ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL КАК Используется, + | КлючиДоступа.НеИспользуетсяС <> ДАТАВРЕМЯ(1, 1, 1) + | И КлючиДоступа.НеИспользуетсяС < &ДатаУстаревания КАК Удалить + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + | ЛЕВОЕ СОЕДИНЕНИЕ ИспользуемыеКлючиДоступа КАК ИспользуемыеКлючиДоступа + | ПО (ИспользуемыеКлючиДоступа.КлючДоступа = КлючиДоступа.Ссылка) + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.Ссылка > &ПоследнийКлючДоступа + | И ВЫБОР + | КОГДА КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | ТОГДА ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL + | ИНАЧЕ НЕ ИспользуемыеКлючиДоступа.КлючДоступа ЕСТЬ NULL + | ИЛИ КлючиДоступа.НеИспользуетсяС < &ДатаУстаревания + | КОНЕЦ + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | КлючиДоступа.Ссылка"; + + ТекстЗапроса = ТекстЗапросаИспользуемых + + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапроса; + + ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст); + Возврат ТекстЗапроса; + +КонецФункции + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьЗапросыПравПользователей(Результат, Контекст) + + Если Контекст.БезОбъектаМетаданных + Или Не Контекст.ЭтоСсылочныйТип + И Контекст.ИмяКоллекцииТипа <> "РегистрыСведений" + И Контекст.ИмяКоллекцииТипа <> "РегистрыНакопления" + И Контекст.ИмяКоллекцииТипа <> "РегистрыБухгалтерии" + И Контекст.ИмяКоллекцииТипа <> "РегистрыРасчета" Тогда + Возврат; + КонецЕсли; + + Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); + ТекстыЗапросов = Новый Массив; + ЧастиЗапроса = Новый Массив; + + Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа + Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда + + ТекстЗапроса = + "ВЫБРАТЬ + | НаборыПользователей.Пользователь КАК ПользовательСПравом, + | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа + | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыПользователей + | ПО (НаборыПользователей.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) + | И (ВЫБОР + | КОГДА НаборыПользователей.Ссылка = РазрешенныеКлючиДоступа.Пользователь + | ТОГДА ИСТИНА + | ИНАЧЕ НаборыПользователей.РазрешенныйНаборГруппПользователей = РазрешенныеКлючиДоступа.Пользователь + | КОНЕЦ) + | И (&ОтборПользователей1)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | НаборыПользователей.Пользователь КАК ПользовательСПравом, + | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.НаборыГруппДоступа КАК НаборыПользователей + | ПО (НаборыПользователей.ТипЭлементовНабора = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)) + | И (НаборыПользователей.РазрешенныйНаборГруппДоступа = РазрешенныеКлючиДоступа.НаборГруппДоступа) + | И (&ОтборПользователей1)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + + ТекстЗапроса = + "ВЫБРАТЬ + | &РазрешенныйПустойНаборГруппДоступа КАК ПользовательСПравом, + | РазрешенныеКлючиДоступа.ПравоИзменение КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ПО (КлючиДоступаКОбъектам.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав1) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | И (РазрешенныеКлючиДоступа.НаборГруппДоступа = &РазрешенныйПустойНаборГруппДоступа)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + + ТекстыЗапросов = Новый Массив; + УсловиеПроверкиТипаВладельцаНастроекПрав1 = "ИСТИНА"; + УсловиеПроверкиТипаВладельцаНастроекПрав2 = "ИСТИНА"; + + Если Не Результат.ИспользуетсяОграничениеПоВладельцу Тогда + ТипыВладельцевНастроекПравПоля = Неопределено; + Иначе + ТипКонечногоПоля = Контекст.СвойстваПолей[0].ТипКонечногоПоля; + ТипыВладельцевНастроекПравПоля = Новый Соответствие; + Если Контекст.ОграничениеДоступаВключено Тогда + Для Каждого КлючИЗначение Из Контекст.ТипыВладельцевНастроекПрав Цикл + Если ТипКонечногоПоля.СодержитТип(КлючИЗначение.Ключ) Тогда + ТипыВладельцевНастроекПравПоля.Вставить(КлючИЗначение.Ключ, + ИмяТипаНаЯзыкеЗапросов(КлючИЗначение.Ключ)); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ТипыВладельцевНастроекПравПоля.Количество() = 0 Тогда + ТипыВладельцевНастроекПравПоля = Неопределено; + + ИначеЕсли ТипКонечногоПоля.Типы().Количество() = ТипыВладельцевНастроекПравПоля.Количество() Тогда + ЧастиЗапроса.Очистить(); + Иначе + Условие1 = ""; + Условие2 = ""; + Для Каждого СвойстваТипа Из ТипыВладельцевНастроекПравПоля Цикл + Условие1 = Условие1 + ?(Условие1 = "", "", " + | И ") + "ТИПЗНАЧЕНИЯ(&ПолеОбъекта) <> ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 + Условие2 = Условие2 + ?(Условие2 = "", "", " + | ИЛИ ") + "ТИПЗНАЧЕНИЯ(&ПолеОбъекта) = ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 + КонецЦикла; + УсловиеПроверкиТипаВладельцаНастроекПрав1 = Условие1; + УсловиеПроверкиТипаВладельцаНастроекПрав2 = Условие2; + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(ТипыВладельцевНастроекПравПоля) Тогда + ДобавитьТекстЗапросаПравПользователейПоВладельцамНастроекПрав(Контекст.ДляВнешнихПользователей, + ЧастиЗапроса, ТекстыЗапросов); + КонецЕсли; + + ТекстЗапроса = + "ВЫБРАТЬ + | ПраваПользователей.ПользовательСПравом КАК ПользовательСПравом, + | МАКСИМУМ(ПраваПользователей.ПравоИзменение) КАК ПравоИзменение, + | ПраваПользователей.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПользователиСПравамиНаЭлементыДанных + |ИЗ + | (#ЧастиЗапроса) КАК ПраваПользователей + | + |СГРУППИРОВАТЬ ПО + | ПраваПользователей.Ссылка, + | ПраваПользователей.ПользовательСПравом"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ЧастиЗапроса", + ТекстСОтступом(СтрСоединить(ЧастиЗапроса, ОбщегоНазначения.ТекстОбъединитьВсе()), " ")); + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", + "РегистрСведений.КлючиДоступаВнешнихПользователей"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", + "РазрешенныеКлючиДоступа.ВнешнийПользователь"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", + "Справочник.ВнешниеПользователи"); + + Если Контекст.ЭтоСсылочныйТип + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", + "КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей"); + КонецЕсли; + КонецЕсли; + + ТекстыЗапросов.Добавить(ТекстЗапроса); + ТекстЗапроса = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + + Если Контекст.ЭтоСсылочныйТип + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав1", + УсловиеПроверкиТипаВладельцаНастроекПрав1); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав2", + УсловиеПроверкиТипаВладельцаНастроекПрав2); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеПроверкиТипаВладельцаНастроекПрав3", + ТекстСОтступом(УсловиеПроверкиТипаВладельцаНастроекПрав2, " ")); + КонецЕсли; + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + Если Контекст.ЭтоСсылочныйТип Тогда + ПолеОбъекта = "Ссылка." + Результат.ПолеВладельца.Имя; + Иначе + ЧастиПоляВладельца = СтрРазделить(Результат.ПолеВладельца.Имя, "."); + ЧастиПоляВладельца[0] = "Ссылка"; + ПолеОбъекта = СтрСоединить(ЧастиПоляВладельца, "."); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеОбъекта", "ТекущаяТаблица." + ПолеОбъекта); + + ИначеЕсли Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолеОбъекта", "ТекущаяТаблица.Ссылка"); + + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "КлючиДоступаКОбъектам.Объект = &ПолеОбъекта", + "КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)"); // @query-part-1, @query-part-2 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + " И (&УсловиеПроверкиТипаВладельцаНастроекПрав1)", + " И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + | И (&ОтборПоИзмерениям)"); // @query-part-1 @query-part-2 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", + "КлючиДоступаКРегистрам.КлючДоступа"); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам", "КлючиДоступаКРегистрам"); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ТекущаяТаблица КАК ТекущаяТаблица", + Контекст.Список + " КАК ТекущаяТаблица"); // @query-part-1, @query-part-2 + + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст); + + УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, Контекст.Список); + КонецЕсли; + + Результат.ТекстЗапросаПравПользователей = ТекстЗапроса; + +КонецПроцедуры + +// Для процедуры ЗаполнитьЗапросыПравПользователей. +Процедура УстановитьПоляИзмеренийДляВыбораИГруппировки(ТекстЗапроса, ПолноеИмяРегистра) + + ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра); + + ИзмеренияДляВыбора = Новый Массив; + ИзмеренияДляГруппировки = Новый Массив; + Для Каждого ОписаниеПоля Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл + УточненноеИмя = УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ОписаниеПоля.Имя); + ИзмеренияДляВыбора.Добавить(СтрШаблон("ТекущаяТаблица.%1 КАК %2", ОписаниеПоля.Имя, УточненноеИмя)); + ИзмеренияДляГруппировки.Добавить(СтрШаблон("ПраваПользователей.%1,", УточненноеИмя)); + КонецЦикла; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущаяТаблица.Ссылка КАК Ссылка", + СтрСоединить(ИзмеренияДляВыбора, ", + | ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка КАК Ссылка", + СтрЗаменить(СтрСоединить(ИзмеренияДляВыбора, ", + | "), "ТекущаяТаблица.", "ПраваПользователей.")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПраваПользователей.Ссылка,", + СтрСоединить(ИзмеренияДляГруппировки, " + | ")); + +КонецПроцедуры + +// Для процедуры УстановитьПоляИзмеренийДляВыбораИГруппировки +Функция УточненноеИмяПоляКлючаЗаписиДляВыбораПравДоступаКДанным(ИмяПоля) + + Если ВРег(ИмяПоля) = ВРег("ПользовательСПравом") + Или ВРег(ИмяПоля) = ВРег("ПравоИзменение") Тогда + Возврат ИмяПоля + "_"; + КонецЕсли; + + Возврат ИмяПоля; + +КонецФункции + +// Для процедуры ЗаполнитьЗапросыПравПользователей. +Процедура ДобавитьТекстЗапросаПравПользователейПоВладельцамНастроекПрав(ДляВнешнихПользователей, + ЧастиЗапроса, ТекстыЗапросов) + + ТекстЗапроса = ТекстЗапросаВыбораПравПоВладельцамНастроекПрав(); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УточнениеПланаЗапроса", "ИСТИНА"); + + Если ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", "Справочник.ВнешниеПользователи"); + КонецЕсли; + + УсловиеОтбора = + "НаследованиеНастроек.Объект В + | (ВЫБРАТЬ + | &ПолеОбъекта + | ИЗ + | ТекущаяТаблица КАК ТекущаяТаблица + | ГДЕ + | &УсловиеПроверкиТипаВладельцаНастроекПрав3)"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + + ЗапросыПакета = СтрРазделить(ТекстЗапроса, ";"); + ЗапросыПакета.Удалить(ЗапросыПакета.Количество() - 1); + ТекстыЗапросов.Добавить(СокрП(СтрСоединить(ЗапросыПакета, ";"))); + + ТекстЗапроса = + "ВЫБРАТЬ + | СоставыГруппПользователей.Пользователь КАК ПользовательСПравом, + | ЛОЖЬ КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | НастройкиПравЧтения КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица + | ПО (НастройкиПрав.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав2) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (&ОтборПользователей2)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + + ТекстЗапроса = + "ВЫБРАТЬ + | СоставыГруппПользователей.Пользователь КАК ПользовательСПравом, + | ИСТИНА КАК ПравоИзменение, + | ТекущаяТаблица.Ссылка КАК Ссылка + |ИЗ + | НастройкиПравИзменения КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТекущаяТаблица КАК ТекущаяТаблица + | ПО (НастройкиПрав.Объект = &ПолеОбъекта) + | И (&УсловиеПроверкиТипаВладельцаНастроекПрав2) + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО (СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И (&ОтборПользователей2)"; + ЧастиЗапроса.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ЗаполнитьЗапросыПроверкиПравЧтениеИзменение(Результат, Контекст) + + Если Контекст.ИмяКоллекцииТипа = "ЖурналыДокументов" Тогда + Возврат; + КонецЕсли; + + Свойства = СвойстваОграниченияСписка(Контекст.Список, Контекст); + + Если Контекст.ЭтоСсылочныйТип + Или Результат.ИспользуетсяОграничениеПоВладельцу Тогда + + Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа + Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + |ГДЕ + | КлючиДоступаКОбъектам.Объект = &Объект + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей + | И РазрешенныеКлючиДоступа.Пользователь В (&РазрешенныйПользователь, &РазрешенныйНаборГруппПользователей) + | И РазрешенныеКлючиДоступа.ПравоИзменение) + | ИЛИ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей + | И РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа) + | И РазрешенныеКлючиДоступа.ПравоИзменение))"; + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", + "РегистрСведений.КлючиДоступаВнешнихПользователей"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", + "РазрешенныеКлючиДоступа.ВнешнийПользователь"); + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (КлючиДоступаКОбъектам.Объект = &Объект) + | И (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКОбъектам.КлючДоступаПользователей) + | И (РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа)) + | И (РазрешенныеКлючиДоступа.ПравоИзменение)"; + КонецЕсли; + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "КлючиДоступаКОбъектам.КлючДоступаПользователей", + "КлючиДоступаКОбъектам.КлючДоступаВнешнихПользователей"); + КонецЕсли; + КонецЕсли; + + Если Не Результат.ИспользуетсяОграничениеПоВладельцу Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = ""; + Иначе + ТипКонечногоПоля = Контекст.СвойстваПолей[0].ТипКонечногоПоля; + ТипыВладельцевНастроекПравПоля = Новый Соответствие; + Если Контекст.ОграничениеДоступаВключено Тогда + Для Каждого КлючИЗначение Из Контекст.ТипыВладельцевНастроекПрав Цикл + Если ТипКонечногоПоля.СодержитТип(КлючИЗначение.Ключ) Тогда + ТипыВладельцевНастроекПравПоля.Вставить(КлючИЗначение.Ключ, + ИмяТипаНаЯзыкеЗапросов(КлючИЗначение.Ключ)); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если ТипыВладельцевНастроекПравПоля.Количество() = 0 Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = ""; + + ИначеЕсли ТипКонечногоПоля.Типы().Количество() = ТипыВладельцевНастроекПравПоля.Количество() Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав(); + Иначе + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ГДЕ + | ВЫБОР + | КОГДА &УсловиеПроверкиТипаВладельцаНастроекПрав + | ТОГДА &УсловиеСПроверкойПоВладельцамНастроекПрав + | ИНАЧЕ ИСТИНА В + | (&ТекстЗапросаСтандартнойПроверки) + | КОНЕЦ"; + Иначе + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ КАК ЗначениеЛожь + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям + | И ВЫБОР + | КОГДА &УсловиеПроверкиТипаВладельцаНастроекПрав + | ТОГДА &УсловиеСПроверкойПоВладельцамНастроекПрав + | ИНАЧЕ ИСТИНА В + | (&ТекстЗапросаСтандартнойПроверки) + | КОНЕЦ"; + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&ТекущаяТаблица", Контекст.Список) + КонецЕсли; + УсловиеПроверкиТипа = ""; + Для Каждого СвойстваТипа Из ТипыВладельцевНастроекПравПоля Цикл + УсловиеПроверкиТипа = УсловиеПроверкиТипа + ?(УсловиеПроверкиТипа = "", "", " + | ИЛИ ") + "ТИПЗНАЧЕНИЯ(&Объект) = ТИП(" + СвойстваТипа.Значение + ")"; // @query-part-3, @query-part-4 + КонецЦикла; + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&УсловиеПроверкиТипаВладельцаНастроекПрав", + УсловиеПроверкиТипа); + + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&УсловиеСПроверкойПоВладельцамНастроекПрав", + ТекстСОтступом(УсловиеИзЗапросаСПроверкойПоВладельцамНастроекПрав(), + " ")); + + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = СтрЗаменить( + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, + "&ТекстЗапросаСтандартнойПроверки", + ТекстСОтступом(ТекстЗапроса, " ")); + КонецЕсли; + КонецЕсли; + + Если Результат.ИспользуетсяОграничениеПоВладельцу Тогда + Если Контекст.ЭтоСсылочныйТип Тогда + ПолеОбъекта = "ВЫРАЗИТЬ(&Объект КАК " + Контекст.Список + ")." + Результат.ПолеВладельца.Имя; // @query-part-1 + Результат.ПолеОбъектаВладельцаВЗапросеПроверкиПрав = ПолеОбъекта; + Иначе + ПолеОбъекта = "ТекущаяТаблица." + Результат.ПолеВладельца.Имя; + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Объект", ПолеОбъекта); + ТекстЗапросаСПроверкойПоВладельцамНастроекПрав = + СтрЗаменить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав, "&Объект", ПолеОбъекта); + + ИначеЕсли Не Контекст.ЭтоСсылочныйТип Тогда + + Если Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователейИГруппДоступа + Или Свойства.ОграничениеВШаблонахЧерезКлючиДоступаПользователей Тогда + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + |ГДЕ + | КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка) + | И КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1 + | И (ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаПользователей КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа + | И РазрешенныеКлючиДоступа.Пользователь В (&РазрешенныйПользователь, &РазрешенныйНаборГруппПользователей) + | И РазрешенныеКлючиДоступа.ПравоИзменение) + | ИЛИ ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ГДЕ + | РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа + | И РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа) + | И РазрешенныеКлючиДоступа.ПравоИзменение))"; + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РегистрСведений.КлючиДоступаПользователей", + "РегистрСведений.КлючиДоступаВнешнихПользователей"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РазрешенныеКлючиДоступа.Пользователь", + "РазрешенныеКлючиДоступа.ВнешнийПользователь"); + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаНаборовГруппДоступа КАК РазрешенныеКлючиДоступа + | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) + | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + | И (РазрешенныеКлючиДоступа.КлючДоступа = КлючиДоступаКРегистрам.КлючДоступа) + | И (РазрешенныеКлючиДоступа.НаборГруппДоступа В (&РазрешенныйНаборГруппДоступа, &РазрешенныйПустойНаборГруппДоступа)) + | И (РазрешенныеКлючиДоступа.ПравоИзменение)"; + КонецЕсли; + + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст); + + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ТекущаяТаблицаПоле1 КАК Поле1 + |ИЗ + | &Список КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) + | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + |ГДЕ + | &ОтборПоИзмерениям + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей = + "ВЫБРАТЬ + | &ТекущаяТаблицаПоле1 КАК ТекущаяТаблицаПоле1 + |ПОМЕСТИТЬ КомбинацииЗначенийОпорныхПолей + |ИЗ + | &КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ТекущаяТаблицаПоле1 КАК Поле1 + |ИЗ + | КомбинацииЗначенийОпорныхПолей КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКРегистрам КАК КлючиДоступаКРегистрам + | ПО (КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) + | И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1) + |ГДЕ + | КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей, + Результат, Контекст, Истина); + УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей, + Результат, Контекст, Истина); + + Результат.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей = + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейСуществующихЗаписей; + Результат.ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей = + ТекстЗапросаНовыхКомбинацийЗначенийОпорныхПолейНовыхЗаписей; + КонецЕсли; + + Если Не Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапросаРегистра = + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ КАК ЗначениеЛожь + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &ОтборПоИзмерениям + | И НЕ ИСТИНА В + | (&УсловиеЗапроса)"; + ТекстЗапросаРегистра = СтрЗаменить(ТекстЗапросаРегистра, "&ТекущаяТаблица", Контекст.Список); + ТекстЗапроса = СтрЗаменить(ТекстЗапросаРегистра, "&УсловиеЗапроса", ТекстСОтступом(ТекстЗапроса, " ")); + КонецЕсли; + + Если ЗначениеЗаполнено(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав) Тогда + Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = ТекстЗапросаСПроверкойПоВладельцамНастроекПрав; + Иначе + Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = ТекстЗапроса; + КонецЕсли; + + Если Не Результат.ОграничениеЧтенияОтключено Тогда + Результат.ТекстЗапросаПроверкиПраваЧтение = СтрЗаменить(ТекстЗапроса, + "РазрешенныеКлючиДоступа.ПравоИзменение", "Истина"); + КонецЕсли; + + Если Результат.ИспользуетсяОграничениеПоВладельцу + И Результат.ПолеВладельца.ИзменениеКакЧтение Тогда + + Результат.ТекстЗапросаПроверкиПравЧтениеИзменение = Результат.ТекстЗапросаПроверкиПраваЧтение; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Функция УсловиеИзЗапросаСПроверкойПоВладельцамНастроекПрав() + + Строки = СтрРазделить(ТекстЗапросаСПроверкойПоВладельцамНастроекПрав(), Символы.ПС, ""); + Строки.Удалить(0); + Строки.Удалить(0); + Строки.Удалить(0); + + Возврат СокрЛП(СтрСоединить(Строки, Символы.ПС)); + +КонецФункции + +// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Функция ТекстЗапросаСПроверкойПоВладельцамНастроекПрав() + + Возврат + "ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА КАК ЗначениеИстина + |ГДЕ + | ИСТИНА В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ИСТИНА + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО + | НаследованиеНастроек.Объект = &Объект + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав + | И НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньРазрешенияИзменения + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь + | И СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь) + | И НЕ ЛОЖЬ В + | (ВЫБРАТЬ ПЕРВЫЕ 1 + | ЛОЖЬ + | ИЗ + | РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаследованиеНастроекПравОбъектов КАК НаследованиеНастроек + | ПО + | НаследованиеНастроек.Объект = &Объект + | И НастройкиПрав.Объект = НаследованиеНастроек.Родитель + | И НастройкиПрав.Таблица = &ИдентификаторТаблицыНастроекПрав + | И НаследованиеНастроек.УровеньИспользования < НастройкиПрав.УровеньЗапрещенияИзменения + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей + | ПО + | СоставыГруппПользователей.Пользователь = &АвторизованныйПользователь + | И СоставыГруппПользователей.ГруппаПользователей = НастройкиПрав.Пользователь)"; + +КонецФункции + +// Для процедуры ЗаполнитьЗапросыПроверкиПравЧтениеИзменение. +Процедура УточнитьРегистрКлючейИУсловиеСоединения(ТекстЗапроса, Результат, Контекст, ДобавитьПоляВыбора = Ложь) + + Если ЗначениеЗаполнено(Результат.ИмяОтдельногоРегистраКлючей) Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "РегистрСведений.КлючиДоступаКРегистрам", + "РегистрСведений." + Результат.ИмяОтдельногоРегистраКлючей); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "КлючиДоступаКРегистрам.Регистр = ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)", // @query-part-1 + "ИСТИНА"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "ИдентификаторыОбъектовМетаданных.ПустаяСсылка", + УправлениеДоступомСлужебныйПовтИсп.ОписаниеПредопределенногоИдентификатораОбъектаМетаданных( + Контекст.Список)); + КонецЕсли; + + ИспользуемыеВариантыДоступа = Контекст.ОсновныеВариантыДоступа.Получить(Контекст.Список); + Если ИспользуемыеВариантыДоступа = Неопределено Тогда + ИспользуемыйВариантДоступа = НовыйИспользуемыйВариантДоступа(); + ИспользуемыйВариантДоступа.ВариантДоступа = Результат.ВариантДоступа; + ИспользуемыйВариантДоступа.ПоляСоединения = СтрСоединить(Результат.ОпорныеПоля.Используемые, ","); + ИспользуемыеВариантыДоступа = Новый Массив; + ИспользуемыеВариантыДоступа.Добавить(ИспользуемыйВариантДоступа); + КонецЕсли; + Если ДобавитьПоляВыбора Тогда + ИспользуемыйВариантДоступа = ИспользуемыеВариантыДоступа[0]; + ИспользуемыеВариантыДоступа = Новый Массив; + ИспользуемыеВариантыДоступа.Добавить(ИспользуемыйВариантДоступа); + КонецЕсли; + + УсловияОтбора = Новый Массив; + УсловияСоединения = Новый Массив; + Для Каждого ИспользуемыйВариантДоступа Из ИспользуемыеВариантыДоступа Цикл + Условие = Новый Массив; + ВариантДоступаСтрокой = XMLСтрока(ИспользуемыйВариантДоступа.ВариантДоступа); + ВариантДоступаСтрокой = ?(ЗначениеЗаполнено(ВариантДоступаСтрокой), ВариантДоступаСтрокой, "NULL"); + Условие.Добавить("КлючиДоступаКРегистрам.ВариантДоступа = " + ВариантДоступаСтрокой); + НомерПоля = 1; + ИменаПолей = СтрРазделить(ИспользуемыйВариантДоступа.ПоляСоединения, ",", Ложь); + Для Каждого ИмяПоля Из ИменаПолей Цикл + Условие.Добавить(СтрШаблон("КлючиДоступаКРегистрам.Поле%1 = ТекущаяТаблица.%2", НомерПоля, ИмяПоля)); + НомерПоля = НомерПоля + 1; + КонецЦикла; + Если ИспользуемыеВариантыДоступа.Количество() = 1 Тогда + УсловияОтбора.Добавить("И " + СтрСоединить(Условие, Символы.ПС + "И ")); // @query-part-1, @query-part-2 + УсловияСоединения.Добавить("И (" + СтрСоединить(Условие, ")" + Символы.ПС + "И (") + ")"); // @query-part-1, @query-part-3 + Иначе + УсловияОтбора.Добавить(СтрСоединить(Условие, Символы.ПС + " И ")); + УсловияСоединения.Добавить(СтрСоединить(Условие, Символы.ПС + " И ")); + КонецЕсли; + КонецЦикла; + + Если ИспользуемыеВариантыДоступа.Количество() = 1 Тогда + УсловиеОтбора = УсловияОтбора[0]; + УсловиеСоединения = УсловияСоединения[0]; + Иначе + УсловиеОтбора = "И (" + СтрСоединить(УсловияОтбора, Символы.ПС + " ИЛИ ") + ")"; // @query-part-1, @query-part-2 + УсловиеСоединения = "И (" + СтрСоединить(УсловияСоединения, Символы.ПС + " ИЛИ ") + ")"; // @query-part-1, @query-part-2 + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "И КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1", + ТекстСОтступом(СокрЛ(УсловиеОтбора), " ")); // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "И (КлючиДоступаКРегистрам.Поле1 = &ТекущаяТаблицаПоле1)", + ТекстСОтступом(СокрЛ(УсловиеСоединения), " ")); // @query-part-1 + + Если Не ДобавитьПоляВыбора Тогда + Возврат; + КонецЕсли; + + ОпорныеПоля = ""; + ПоляВыбора = ""; + НомерПоля = 1; + Для Каждого Поле Из Результат.ОпорныеПоля.Используемые Цикл + ОпорныеПоля = ОпорныеПоля + ?(ОпорныеПоля = "", "", "," + Символы.ПС) + + СтрШаблон("ТекущаяТаблица.%1 КАК %1", Поле); // @query-part-4 + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", "," + Символы.ПС) + + СтрШаблон("ТекущаяТаблица.%2 КАК Поле%1", НомерПоля, Поле); // @query-part-4 + НомерПоля = НомерПоля + 1; + КонецЦикла; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "&ТекущаяТаблицаПоле1 КАК ТекущаяТаблицаПоле1", + ТекстСОтступом(СокрЛ(ОпорныеПоля), " ")); // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, + "&ТекущаяТаблицаПоле1 КАК Поле1", + ТекстСОтступом(СокрЛ(ПоляВыбора), " ")); // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Список", Контекст.Список); + +КонецПроцедуры + +// Для функции СобратьЧастиЗапросов. +Процедура ПодставитьОбщиеПараметрыВЗапрос(ТекстЗапроса, Контекст) + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователейКОбъекту", "КлючДоступаВнешнихПользователей"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователейКОбъекту", "КлючДоступаПользователей"); + КонецЕсли; + + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", Контекст.Список); + + Если Контекст.ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступаВнешнихПользователей"); + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступаПользователей"); + КонецЕсли; + Иначе + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийРегистр", Контекст.Список); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок.Регистр = &ИдентификаторРегистра", "#1"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок.ВариантДоступа = &ВариантДоступа", "#2"); + Номер = 0; + Для Каждого ИмяОпорногоПоля Из Контекст.ОпорныеПоля.Используемые Цикл + Номер = Номер + 1; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, СтрШаблон("ТекущийСписок.%1", ИмяОпорногоПоля), + СтрШаблон("ТекущийСписок.Поле%1", Номер)); + КонецЦикла; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#1", "ТекущийСписок.Регистр = &ИдентификаторРегистра"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#2", "ТекущийСписок.ВариантДоступа = &ВариантДоступа"); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущийСписок", ?(Контекст.ИмяОтдельногоРегистраКлючей = "", + "РегистрСведений.КлючиДоступаКРегистрам", "РегистрСведений." + Контекст.ИмяОтдельногоРегистраКлючей)); + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#КлючДоступаПользователей", "КлючДоступа"); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СоставПолей", Формат(Контекст.СоставПолей, "ЧН=0; ЧГ=")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ВариантДоступа", XMLСтрока(Контекст.ВариантДоступа)); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДляВнешнихПользователей", + ?(Контекст.ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ")); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьПроверкуШапкиКлюча(Контекст, НомерШапки) + + ГруппаПолей = Контекст.ГруппыПолей.Получить(СтрШаблон("Шапка%1", НомерШапки)); + Если ГруппаПолей = Неопределено Тогда + Если НомерШапки > 0 Тогда + Возврат; + КонецЕсли; + СоединенияИПоля = Новый Структура("Соединения, Поля", "", ""); + Иначе + СоединенияИПоля = СоединенияИПоляПоТаблицам(ГруппаПолей, + Ложь, НомерШапки).Получить("ТекущийСписок"); + КонецЕсли; + + Если НомерШапки = 0 Тогда + Соединения = СоединенияИПоля.Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа КАК Шапка0 + |ПО (Шапка0.Ссылка = ТекущийСписок.ТекущийКлючДоступа)" + + ?(Контекст.СоставПолей = 0, " + | И (Шапка0.Список = &Список)", "") + + " + | И (Шапка0.СоставПолей = &СоставПолей)"; // @query-part-1, @query-part-2, @query-part-4 + Иначе + Соединения = СоединенияИПоля.Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа.Шапка КАК Шапка? + |ПО (Шапка?.Ссылка = ТекущийСписок.ТекущийКлючДоступа) + | И (Шапка?.НомерСтроки = &НомерШапки)"; // @query-part-1 + Соединения = СтрЗаменить(Соединения, "&НомерШапки", НомерШапки); + КонецЕсли; + + Соединения = СокрЛ(Соединения) + ТекстСОтступом(СоединенияИПоля.Поля, " "); + Условие = "Шапка?.Ссылка ЕСТЬ NULL"; // @query-part-1 + + Соединения = СтрЗаменить(Соединения, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Условие = СтрЗаменить(Условие, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + + Контекст.ЧастиУсловияПроверки.Добавить(ЧастьУсловияПроверки(Соединения, Условие, + Контекст.ИспользуемыеПоляОсновнойТаблицы)); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьПроверкуТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча) + + ТаблицыПоГруппам = Контекст.ГруппыДополнительныхТаблиц.ТаблицыПоГруппам; + ГруппаДополнительныхТаблиц = ТаблицыПоГруппам.Получить(НомерТабличнойЧастиКлюча + - (Контекст.КоличествоТабличныхЧастейКлюча - ТаблицыПоГруппам.Количество())); + + ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + ГруппаПолей = Контекст.ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); + + СоединенияИПоляПоТаблицам = СоединенияИПоляПоТаблицам(ГруппаПолей, Истина); + + Соединения = ""; + Поля = ""; + + Если ГруппаДополнительныхТаблиц = Неопределено Тогда + ПсевдонимТабличнойЧастиОбъекта = Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча); + Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить("ТекущийСписок"); + Иначе + ИмяТабличнойЧастиОбъекта = СтрЗаменить(ПсевдонимТабличнойЧастиОбъекта, "ТекущийСписок", ""); + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ПсевдонимТабличнойЧастиОбъекта); + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок." + ИмяТабличнойЧастиОбъекта + " КАК " + ПсевдонимТабличнойЧастиОбъекта + " + |ПО " + ПсевдонимТабличнойЧастиОбъекта + ".Ссылка = ТекущийСписок.Ссылка"; // @query-part-1, @query-part-2, @query-part-3, @query-part-4 + КонецЕсли; + Соединения = Соединения + СоединенияИПоля.Соединения; + Поля = СоединенияИПоля.Поля; + Иначе + Для Каждого ДополнительнаяТаблица Из ГруппаДополнительныхТаблиц Цикл + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3 + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ДополнительнаяТаблица.Псевдоним); + Если СоединенияИПоля = Неопределено Тогда + Продолжить; + КонецЕсли; + Соединения = Соединения + СоединенияИПоля.Соединения; + Поля = Поля + СоединенияИПоля.Поля; + КонецЦикла; + КонецЕсли; + + // Прямое соединение (проверка наличия требуемых записей в ключе). + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + |ПО (ТабличнаяЧасть?.Ссылка = ТекущийСписок.ТекущийКлючДоступа)"; // @query-part + Соединения = СокрЛ(Соединения) + ТекстСОтступом(Поля, " "); + Условие = "ТабличнаяЧасть?.Ссылка ЕСТЬ NULL"; // @query-part-1 + + Соединения = СтрЗаменить(Соединения, "ТабличнаяЧасть?", ИмяТабличнойЧастиКлюча); + Условие = СтрЗаменить(Условие, "ТабличнаяЧасть?", ИмяТабличнойЧастиКлюча); + + ДополнительныеПоля = ""; + Если Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча) = Неопределено Тогда + ДополнительныеПоля = Контекст.ИспользуемыеПоляОсновнойТаблицы; + КонецЕсли; + + Контекст.ЧастиУсловияПроверки.Добавить(ЧастьУсловияПроверки(Соединения, + Условие, ДополнительныеПоля, ИмяТабличнойЧастиКлюча)); + +КонецПроцедуры + +// Для процедур ДобавитьПроверкуШапкиКлюча, ДобавитьПроверкуТабличнойЧастиКлюча. +// +// Возвращаемое значение: +// Структура: +// * Соединения - Строка +// * Условие - Строка +// * ДополнительныеПоля - Строка +// * ИмяТабличнойЧастиКлюча - Строка +// +Функция ЧастьУсловияПроверки(Соединения, Условие, ДополнительныеПоля, ИмяТабличнойЧастиКлюча = "") + + Результат = Новый Структура; + Результат.Вставить("Соединения", Соединения); + Результат.Вставить("Условие", Условие); + Результат.Вставить("ИмяТабличнойЧастиКлюча", ИмяТабличнойЧастиКлюча); + Результат.Вставить("ДополнительныеПоля", ДополнительныеПоля); + + Возврат Результат; + +КонецФункции + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьЗаполнениеШапкиКлюча(Контекст, НомерШапки) + + Если Не Контекст.ЭтоСсылочныйТип И НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка, + | &ОпорныеПоляДляВыбора + |ПОМЕСТИТЬ ТекущийСписок + |ИЗ + | &ЗначенияОпорныхПолей КАК ТекущийСписок"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляВыбора", Контекст.ОпорныеПоля.ДляВыбора); + Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); + + ИначеЕсли НомерШапки = 0 Тогда + Для Каждого ОписаниеТаблицы Из Контекст.ПоляТаблицОбъекта.Результат Цикл + ТекстЗапроса = + "ВЫБРАТЬ + | &ПоляТаблицы + | ПОМЕСТИТЬ #ПолноеИмяТаблицы + |ИЗ + | &ПолноеИмяТаблицы КАК ТекущаяТаблица"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляТаблицы", + "ТекущаяТаблица." + СтрСоединить(ОписаниеТаблицы.Поля, ", + | ТекущаяТаблица.")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ПолноеИмяТаблицы", ОписаниеТаблицы.ПолноеИмяТаблицы); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяТаблицы", "&" + ОписаниеТаблицы.ПолноеИмяТаблицы); + Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить(ТекстЗапроса); + КонецЦикла; + КонецЕсли; + + ГруппаПолей = Контекст.ГруппыПолей.Получить(СтрШаблон("Шапка%1", НомерШапки)); + Если ГруппаПолей = Неопределено Тогда + Возврат; + КонецЕсли; + ДобавитьОписаниеТаблицыКлюча(СтрШаблон("Шапка%1", НомерШапки), ГруппаПолей, Контекст); + + СоединенияИПоля = СоединенияИПоляПоТаблицам(ГруппаПолей, Ложь, + НомерШапки, Истина).Получить("ТекущийСписок"); + + // Выбор значений из объектов для поиска и создания ключей доступа. + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляЗапроса + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка,&ПоляЗапроса + |ИЗ + | ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ОпорныеПоляДляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ОпорныеПоляДляУпорядочения", Контекст.ОпорныеПоля.ДляУпорядочения); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляЗапроса", ТекстСОтступом(СоединенияИПоля.Поля, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(СоединенияИПоля.Соединения, " ")); + + Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); + Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить(ТекстЗапроса); + + // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | Шапка0.Ссылка КАК ТекущаяСсылка,&Реквизиты + |ИЗ + | Справочник.КлючиДоступа КАК Шапка0 + |ГДЕ + | Шапка0.Хеш В(&Хеши) + | И Шапка0.Список = &Список + | И Шапка0.СоставПолей = &СоставПолей + | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И Шапка0.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка + |ИТОГИ ПО + | ТекущаяСсылка"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | Шапка?.Ссылка КАК ТекущаяСсылка,&Реквизиты + |ИЗ + | Справочник.КлючиДоступа.Шапка КАК Шапка? + |ГДЕ + | Шапка?.НомерСтроки = &НомерШапки + | И Шапка?.Ссылка.Хеш В(&Хеши) + | И Шапка?.Ссылка.Список = &Список + | И Шапка?.Ссылка.СоставПолей = &СоставПолей + | И Шапка?.Ссылка.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И Шапка?.Ссылка.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&НомерШапки", НомерШапки); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(СоединенияИПоля.Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Проверка существования ключа доступа перед записью нового ключа. + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.КлючиДоступа КАК Шапка0 + |ГДЕ + | Шапка0.Хеш = &Хеш + | И Шапка0.Список = &Список + | И Шапка0.СоставПолей = &СоставПолей + | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И &УточнениеПланаЗапроса"; + Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения.Добавить(ТекстЗапроса); + КонецЕсли; + + // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. + ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, НомерШапки); + + // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступа.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПорцияКлючей + |ИЗ + | &КлючиДоступа КАК КлючиДоступа + | + |ИНДЕКСИРОВАТЬ ПО + | Ссылка"; + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + КонецЕсли; + + Если НомерШапки = 0 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты + |ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка0 + | ПО + | Шапка0.Ссылка = ПорцияКлючей.Ссылка + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | Ссылка + |ИТОГИ ПО + | Ссылка"; // @query-part + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты + |ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.Шапка КАК Шапка? + | ПО + | Шапка?.Ссылка = ПорцияКлючей.Ссылка + | И &УсловиеНомераШапки + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | Ссылка + |ИТОГИ ПО + | Ссылка"; // @query-part + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеНомераШапки", + СтрШаблон("Шапка%1.НомерСтроки = %1", НомерШапки)); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(СоединенияИПоля.Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + // Условие отбора прав ведущих ключей доступа. + ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВедущихКлючей"); + + // Условие отбора прав ведущих списков. + ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВедущихСписков"); + + // Условие отбора прав по владельцам настроек прав. + ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, "ДляВладельцевНастроекПрав"); + +КонецПроцедуры + +// Для процедуры ДобавитьЗаполнениеШапкиКлюча. +Процедура ДобавитьУсловиеОтбораПравДляШапкиКлюча(Контекст, ГруппаПолей, НомерШапки, НазначениеУсловия) + + // Условие выбора прав ведущих ключей доступа. + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + Если НазначениеУсловия = "ДляВедущихКлючей" + И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 + Или НазначениеУсловия = "ДляВедущихСписков" + И Не СвойстваПоля.ЕстьТипВедущегоСписка + Или НазначениеУсловия = "ДляВладельцевНастроекПрав" + И Не СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда + Продолжить; + КонецЕсли; + + Если НазначениеУсловия = "ДляВедущихСписков" + И СвойстваПоля.ТипыСохраненияЗначений.Количество() > 0 Тогда + + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписковСТипами"); + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | ЕСТЬNULL(ТипыКонфигурации.Ссылка, ЕСТЬNULL(ТипыРасширений.Ссылка, Шапка?.Реквизит?)) + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка? + | ПО + | Шапка?.Ссылка = ПорцияКлючей.Ссылка + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации + | ПО + | Шапка?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовМетаданных) + | И ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовРасширений) + | И ТИПЗНАЧЕНИЯ(ТипыКонфигурации.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?) + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений + | ПО + | Шапка?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(ТипыРасширений.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(Шапка?.Реквизит?))"; // @query-part-1 + Иначе + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | Шапка?.Реквизит? + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа КАК Шапка? + | ПО + | Шапка?.Ссылка = ПорцияКлючей.Ссылка)"; // @query-part-1 + КонецЕсли; + Если НомерШапки > 0 Тогда + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, + "Справочник.КлючиДоступа КАК Шапка?", "Справочник.КлючиДоступа.Шапка КАК Шапка?"); // @query-part-1, @query-part-2 + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, + "Шапка?.Ссылка = ПорцияКлючей.Ссылка", ТекстСОтступом( + "Шапка?.Ссылка = ПорцияКлючей.Ссылка" + СтрШаблон(" + | И Шапка?.НомерСтроки = %1", НомерШапки), " ")); // @query-part-3 + КонецЕсли; + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Реквизит?", СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + + Если НазначениеУсловия = "ДляВедущихКлючей" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Добавить(УсловиеОтбора); + + ИначеЕсли НазначениеУсловия = "ДляВедущихСписков" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихСписков.Добавить(УсловиеОтбора); + Иначе + Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Добавить(УсловиеОтбора); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьВыборКлючейБезПолейВШапке(Контекст) + + Если Контекст.ГруппыПолей.Получить("Шапка0") <> Неопределено Тогда + Возврат; + КонецЕсли; + + // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступа.Ссылка КАК ТекущаяСсылка + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Хеш В(&Хеши) + | И КлючиДоступа.Список = &Список + | И КлючиДоступа.СоставПолей = &СоставПолей + | И КлючиДоступа.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И КлючиДоступа.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка"; + + Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Проверка существования ключа доступа перед записью нового ключа. + ТекстЗапроса = + "ВЫБРАТЬ + | ИСТИНА КАК ЗначениеИстина + |ИЗ + | Справочник.КлючиДоступа КАК Шапка0 + |ГДЕ + | Шапка0.Хеш = &Хеш + | И Шапка0.Список = &Список + | И Шапка0.СоставПолей = &СоставПолей + | И Шапка0.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И &УточнениеПланаЗапроса"; + Контекст.ЧастиЗапросаСуществованияКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + ТекстЗапроса = + "ВЫБРАТЬ + | КлючиДоступа.Ссылка КАК Ссылка + |ПОМЕСТИТЬ ПорцияКлючей + |ИЗ + | &КлючиДоступа КАК КлючиДоступа + | + |ИНДЕКСИРОВАТЬ ПО + | Ссылка"; + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + +КонецПроцедуры + +// Для процедуры ДобавитьТекстыЗапросовВПараметрыОграничения. +Процедура ДобавитьЗаполнениеТабличнойЧастиКлюча(Контекст, НомерТабличнойЧастиКлюча) + + ТаблицыПоГруппам = Контекст.ГруппыДополнительныхТаблиц.ТаблицыПоГруппам; + ГруппаДополнительныхТаблиц = ТаблицыПоГруппам.Получить(НомерТабличнойЧастиКлюча + - (Контекст.КоличествоТабличныхЧастейКлюча - ТаблицыПоГруппам.Количество())); + + ИмяТабличнойЧастиКлюча = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + ГруппаПолей = Контекст.ГруппыПолей.Получить(ИмяТабличнойЧастиКлюча); + + ДобавитьОписаниеТаблицыКлюча(ИмяТабличнойЧастиКлюча, ГруппаПолей, Контекст); + + СоединенияИПоляПоТаблицам = СоединенияИПоляПоТаблицам(ГруппаПолей, Истина, , Истина); + + // Выбор значений из объектов для поиска и создания ключей доступа. + Если ГруппаДополнительныхТаблиц = Неопределено Тогда + ПсевдонимТабличнойЧастиОбъекта = Контекст.ПсевдонимыТабличныхЧастейОбъекта.Получить(НомерТабличнойЧастиКлюча); + Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить("ТекущийСписок"); + Иначе + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ПсевдонимТабличнойЧастиОбъекта); + КонецЕсли; + ПоляВыбора = СоединенияИПоля.Поля; + Соединения = СоединенияИПоля.Соединения; + ПоляУпорядочения = СоединенияИПоля.ПоляУпорядочения; + Реквизиты = СоединенияИПоля.Реквизиты; + Если ПсевдонимТабличнойЧастиОбъекта = Неопределено Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + Иначе + ИмяТабличнойЧастиОбъекта = СтрЗаменить(ПсевдонимТабличнойЧастиОбъекта, "ТекущийСписок", ""); + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок + | ЛЕВОЕ СОЕДИНЕНИЕ ИмяТабличнойЧастиОбъекта КАК ПсевдонимТабличнойЧастиОбъекта + | ПО (ПсевдонимТабличнойЧастиОбъекта.Ссылка = ТекущийСписок.Ссылка) #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПсевдонимТабличнойЧастиОбъекта", ПсевдонимТабличнойЧастиОбъекта); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИмяТабличнойЧастиОбъекта", "&ТекущийСписок." + ИмяТабличнойЧастиОбъекта); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); + Иначе + ПоляВыбора = ""; + Соединения = ""; + СоединенияВБазеДанных = ""; + СоединенияВПамяти = ""; + ПоляУпорядочения = ""; + Реквизиты = ""; + Для Каждого ДополнительнаяТаблица Из ГруппаДополнительныхТаблиц Цикл + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(ДополнительнаяТаблица.Псевдоним); + ТекущееСоединение = " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3 + Соединения = Соединения + ТекущееСоединение; + Если Контекст.ЭтоСсылочныйТип Тогда + Если ВРег(Контекст.Список) = ВРег(ДополнительнаяТаблица.Таблица) Тогда + ДополнительноеИмя = "&ТекущийСписок"; + ИначеЕсли СтрНачинаетсяС(ВРег(ДополнительнаяТаблица.Таблица), ВРег(Контекст.Список) + ".") Тогда + ДополнительноеИмя = "&ТекущийСписок." + СтрРазделить(ДополнительнаяТаблица.Таблица, ".")[2]; + Иначе + ДополнительноеИмя = ДополнительнаяТаблица.Таблица; + КонецЕсли; + Если ДополнительноеИмя = ДополнительнаяТаблица.Таблица Тогда + СоединенияВБазеДанных = СоединенияВБазеДанных + ТекущееСоединение; + СоединенияВПамяти = СоединенияВПамяти + ТекущееСоединение; + Иначе + СоединенияВБазеДанных = СоединенияВБазеДанных + " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительнаяТаблица.Таблица + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " ") + " + | И НЕ " + ДополнительнаяТаблица.Псевдоним + ".Ссылка В (&СсылкиНаОбъекты)"; // @query-part-1, @query-part-2, @query-part-3, @query-part-5, @query-part-6 + + СоединенияВПамяти = СоединенияВПамяти + " + |ЛЕВОЕ СОЕДИНЕНИЕ " + ДополнительноеИмя + " КАК " + ДополнительнаяТаблица.Псевдоним + " + |ПО " + ТекстСОтступом(ДополнительнаяТаблица.ТекстУсловияСоединения, " "); // @query-part-1, @query-part-2, @query-part-3, + КонецЕсли; + КонецЕсли; + Если СоединенияИПоля = Неопределено Тогда + Продолжить; + КонецЕсли; + Соединения = Соединения + СоединенияИПоля.Соединения; + Если Контекст.ЭтоСсылочныйТип Тогда + СоединенияВБазеДанных = СоединенияВБазеДанных + СоединенияИПоля.Соединения; + СоединенияВПамяти = СоединенияВПамяти + СоединенияИПоля.Соединения; + КонецЕсли; + ПоляВыбора = ПоляВыбора + СоединенияИПоля.Поля; + ПоляУпорядочения = ПоляУпорядочения + СоединенияИПоля.ПоляУпорядочения; + Реквизиты = Реквизиты + СоединенияИПоля.Реквизиты; + КонецЦикла; + Если Контекст.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #Соединения + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); + + Если СоединенияВПамяти <> СоединенияВБазеДанных Тогда + // АПК:96-выкл - №434 Использование ОБЪЕДИНИТЬ допустимо, так как + // строки не должны повторятся и объем данных небольшой. + ТекстЗапросаВПамяти = + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #СоединенияВБазеДанных + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |ОБЪЕДИНИТЬ + | + |ВЫБРАТЬ РАЗЛИЧНЫЕ + | ТекущийСписок.Ссылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | &ТекущийСписок КАК ТекущийСписок #СоединенияВПамяти + |ГДЕ + | ТекущийСписок.Ссылка В (&СсылкиНаОбъекты) + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + // АПК:96-вкл. + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, " #СоединенияВБазеДанных", + ТекстСОтступом(СоединенияВБазеДанных, " ")); + ТекстЗапросаВПамяти = СтрЗаменить(ТекстЗапросаВПамяти, " #СоединенияВПамяти", + ТекстСОтступом(СоединенияВПамяти, " ")); + КонецЕсли; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | ТекущийСписок.ТекущаяСсылка КАК ТекущаяСсылка,&ПоляВыбора + |ИЗ + | ТекущийСписок КАК ТекущийСписок #Соединения + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка, &ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part-1 + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляВыбора", ТекстСОтступом(ПоляВыбора, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляУпорядочения", + Контекст.ОпорныеПоля.ДляУпорядочения + ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, " #Соединения", ТекстСОтступом(Соединения, " ")); + КонецЕсли; + КонецЕсли; + + Контекст.ЧастиЗапросаЗначенийИзОбъектов.Добавить(ТекстЗапроса); + Контекст.ЧастиЗапросаЗначенийИзОбъектовВПамяти.Добавить( + ?(ЗначениеЗаполнено(ТекстЗапросаВПамяти), ТекстЗапросаВПамяти, ТекстЗапроса)); + + // Запрос ключей доступа по ведущим ключам для обновления пользователей и групп доступа, которым они разрешены. + ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, , НомерТабличнойЧастиКлюча); + + // Выбор значений из ключей доступа для сравнения со значениями требуемых ключей. + ТекстЗапроса = + "ВЫБРАТЬ + | ТабличнаяЧасть?.Ссылка КАК ТекущаяСсылка,&Реквизиты + |ИЗ + | Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + |ГДЕ + | ТабличнаяЧасть?.Ссылка.Хеш В(&Хеши) + | И ТабличнаяЧасть?.Ссылка.Список = &Список + | И ТабличнаяЧасть?.Ссылка.СоставПолей = &СоставПолей + | И ТабличнаяЧасть?.Ссылка.ДляВнешнихПользователей = &ДляВнешнихПользователей + | И ТабличнаяЧасть?.Ссылка.НеИспользуетсяС = ДАТАВРЕМЯ(1, 1, 1) + | И &УточнениеПланаЗапроса + | + |УПОРЯДОЧИТЬ ПО + | ТекущаяСсылка,&ПоляУпорядочения + |ИТОГИ ПО + | ТекущаяСсылка"; // @query-part + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&ПоляУпорядочения", ПоляУпорядочения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТабличнаяЧасть?", СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляСравнения.Добавить(ТекстЗапроса); + + // Выбор значений из ключей доступа для вычисления пользователей и групп доступа, которым они разрешены. + ТекстЗапроса = + "ВЫБРАТЬ + | ПорцияКлючей.Ссылка КАК Ссылка,&Реквизиты + |ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ПО + | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка + | + |УПОРЯДОЧИТЬ ПО + | Ссылка + |ИТОГИ ПО + | Ссылка"; // @query-part-1 + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ",&Реквизиты", ТекстСОтступом(Реквизиты, " ")); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТабличнаяЧасть?", СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); + Контекст.ЧастиЗапросаЗначенийИзКлючейДляРасчетаПрав.Добавить(ТекстЗапроса); + + // Условие отбора прав ведущих ключей доступа. + ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, + ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВедущихКлючей"); + + // Условие отбора прав ведущих списков. + ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, + ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВедущихСписков"); + + // Условие отбора прав по владельцам настроек прав. + ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, + ГруппаПолей, НомерТабличнойЧастиКлюча, "ДляВладельцевНастроекПрав"); + +КонецПроцедуры + +// Для процедуры ДобавитьЗаполнениеТабличнойЧастиКлюча. +Процедура ДобавитьУсловиеОтбораПравДляТабличнойЧастиКлюча(Контекст, ГруппаПолей, + НомерТабличнойЧастиКлюча, НазначениеУсловия) + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + Если НазначениеУсловия = "ДляВедущихКлючей" + И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 + Или НазначениеУсловия = "ДляВедущихСписков" + И Не СвойстваПоля.ЕстьТипВедущегоСписка + Или НазначениеУсловия = "ДляВладельцевНастроекПрав" + И Не СвойстваПоля.ЕстьТипВладельцаНастроекПрав Тогда + Продолжить; + КонецЕсли; + + Если НазначениеУсловия = "ДляВедущихСписков" + И СвойстваПоля.ТипыСохраненияЗначений.Количество() > 0 Тогда + + Контекст.Вставить("ЧастиУсловияВыбораПравВедущихСписковСТипами"); + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | ЕСТЬNULL(ТипыКонфигурации.Ссылка, ЕСТЬNULL(ТипыРасширений.Ссылка, ТабличнаяЧасть?.Реквизит?)) + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ПО + | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации + | ПО + | ТабличнаяЧасть?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовМетаданных) + | И ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) <> ТИП(Справочник.ИдентификаторыОбъектовРасширений) + | И ТИПЗНАЧЕНИЯ(ТипыКонфигурации.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?) + | + | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений + | ПО + | ТабличнаяЧасть?.Реквизит? <> НЕОПРЕДЕЛЕНО + | И ТИПЗНАЧЕНИЯ(ТипыРасширений.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(ТабличнаяЧасть?.Реквизит?))"; // @query-part-1 + Иначе + УсловиеОтбора = + "#ПроверяемоеПоле В + | (ВЫБРАТЬ + | ТабличнаяЧасть?.Реквизит? + | ИЗ + | ПорцияКлючей КАК ПорцияКлючей + | ЛЕВОЕ СОЕДИНЕНИЕ @Справочник.КлючиДоступа.ТабличнаяЧасть? КАК ТабличнаяЧасть? + | ПО + | ТабличнаяЧасть?.Ссылка = ПорцияКлючей.Ссылка)"; // @query-part-1 + КонецЕсли; + + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "ТабличнаяЧасть?", + СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча)); + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Реквизит?", + СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + + Если НазначениеУсловия = "ДляВедущихКлючей" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихКлючейДоступа.Добавить(УсловиеОтбора); + + ИначеЕсли НазначениеУсловия = "ДляВедущихСписков" Тогда + Контекст.ЧастиУсловияВыбораПравВедущихСписков.Добавить(УсловиеОтбора); + Иначе + Контекст.ЧастиУсловияВыбораПравПоВладельцамНастроекПрав.Добавить(УсловиеОтбора); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ДобавитьЗаполнениеШапкиКлюча, ДобавитьЗаполнениеТабличнойЧастиКлюча. +Процедура ДобавитьОписаниеТаблицыКлюча(ИмяТаблицыКлюча, ГруппаПолей, Контекст) + + ПоляТаблицыКлюча = Новый Массив; + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + ПоляТаблицыКлюча.Добавить(СвойстваПоля.ИмяРеквизитаГруппыПолейКлючаДоступа); + КонецЦикла; + + Контекст.ТаблицыКлюча.Добавить(ИмяТаблицыКлюча); + Контекст.РеквизитыТаблицКлюча.Вставить(ИмяТаблицыКлюча, ПоляТаблицыКлюча); + +КонецПроцедуры + +// Для процедуры ДобавитьЗаполнениеШапкиКлюча, ДобавитьЗаполнениеТабличнойЧастиКлюча. +Процедура ДобавитьУсловиеОтбораПоВедущимКлючамДоступа(Контекст, ГруппаПолей, НомерШапки = 0, НомерТабличнойЧастиКлюча = 0) + + УсловиеОтбора = ""; + НомерРеквизита = ?(НомерШапки = 0, 0, 5); + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + НомерРеквизита = НомерРеквизита + 1; + + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + + УсловиеОтбора = + "КлючиДоступа.Ссылка В + | (ВЫБРАТЬ + | Шапка?.Ссылка + | ИЗ + | Справочник.КлючиДоступа КАК Шапка? + | ГДЕ + | Шапка?.Значение? В (&ВедущиеКлючиДоступа))"; // @query-part-1 + + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Значение?", + СтрШаблон("Значение%1", НомерРеквизита)); + + Если НомерШапки > 0 Тогда + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, + "Справочник.КлючиДоступа КАК Шапка?", + "Справочник.КлючиДоступа.Шапка КАК Шапка?"); // @query-part-1, @query-part-2 + КонецЕсли; + + Если НомерТабличнойЧастиКлюча = 0 Тогда + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", СтрШаблон("Шапка%1", НомерШапки)); + Иначе + ИмяТабличнойЧасти = СтрШаблон("ТабличнаяЧасть%1", НомерТабличнойЧастиКлюча); + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, " КАК", "." + ИмяТабличнойЧасти + " КАК"); // @query-part-1, @query-part-3 + УсловиеОтбора = СтрЗаменить(УсловиеОтбора, "Шапка?", ИмяТабличнойЧасти); + КонецЕсли; + + Контекст.ЧастиУсловияОтбораПоВедущимКлючамДоступа.Добавить(УсловиеОтбора); + КонецЦикла; + +КонецПроцедуры + +// Для процедур ДобавитьПроверкуШапкиКлюча, ДобавитьПроверкуТабличнойЧастиКлюча. +Функция СоединенияИПоляПоТаблицам(ГруппаПолей, ТабличнаяЧастьКлюча, НомерШапки = 0, ДляВыбораЗначений = Ложь) + + СоединенияИПоляПоТаблицам = Новый Соответствие; + НомерРеквизита = 1 + ?(НомерШапки = 0, 0, 5); + + Для Каждого СвойстваПоля Из ГруппаПолей Цикл + + СоединенияИПоля = СоединенияИПоляПоТаблицам.Получить(СвойстваПоля.ПсевдонимТаблицы); + Если СоединенияИПоля = Неопределено Тогда + СоединенияИПоля = Новый Структура; + СоединенияИПоля.Вставить("Соединения", ""); + СоединенияИПоля.Вставить("Поля", ""); + СоединенияИПоля.Вставить("ПоляУпорядочения", ""); + СоединенияИПоля.Вставить("Реквизиты", ""); + СоединенияИПоляПоТаблицам.Вставить(СвойстваПоля.ПсевдонимТаблицы, СоединенияИПоля); + КонецЕсли; + + Соединения = ""; + Если СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() > 0 Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаКОбъектам КАК КлючиДоступаКОбъектам? + |ПО (КлючиДоступаКОбъектам?.Объект = #ИмяПоляДляЗапроса)"; // @query-part-1 + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияГруппЗначений.Количество() > 0 Тогда + Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначений? + |ПО (ГруппыЗначений?.ЗначениеДоступа = #ИмяПоляДляЗапроса) + | И (ГруппыЗначений?.ГруппаДанных = 0)"; // @query-part-1 + ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ &ТекущийСписок.ГруппыДоступа КАК ГруппыЗначений? + |ПО (ГруппыЗначений?.Ссылка = #ИмяПоляДляЗапроса)"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияТиповКонфигурации.Количество() > 0 Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовМетаданных КАК ТипыКонфигурации? + |ПО (#ИмяПоляДляЗапроса <> НЕОПРЕДЕЛЕНО) + | И (ТИПЗНАЧЕНИЯ(ТипыКонфигурации?.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса))"; // @query-part-1 + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияТиповРасширений.Количество() > 0 Тогда + Соединения = Соединения + " + |ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ИдентификаторыОбъектовРасширений КАК ТипыРасширений? + |ПО (#ИмяПоляДляЗапроса <> НЕОПРЕДЕЛЕНО) + | И (ТИПЗНАЧЕНИЯ(ТипыРасширений?.ЗначениеПустойСсылки) = ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса))"; // @query-part-1 + КонецЕсли; + + Поле = СравнениеПоля(СвойстваПоля); + + Если ДляВыбораЗначений Тогда + Поле = СтрЗаменить(Поле, "Шапка?.Значение? = ", ""); + Поле = СтрЗаменить(Поле, " ", " "); + Позиция = СтрДлина(Символы.ПС + "И ()"); // @query-part-1 + Поле = "," + Символы.ПС + Сред(Поле, Позиция, СтрДлина(Поле) - Позиция) + " КАК " + "Значение?"; // @query-part-2 + + СоединенияИПоля.ПоляУпорядочения = СоединенияИПоля.ПоляУпорядочения + + ", " + СтрШаблон("Значение%1", НомерРеквизита); + + СоединенияИПоля.Реквизиты = СоединенияИПоля.Реквизиты + СтрШаблон(", + |Шапка?.Значение%1 КАК Значение%1", НомерРеквизита); // @query-part-1 + КонецЕсли; + + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "Значение?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ГруппыЗначений?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "КлючиДоступаКОбъектам?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ТипыКонфигурации?"); + ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, "ТипыРасширений?"); + + Соединения = СтрЗаменить(Соединения, "#ИмяПоляДляЗапроса", СвойстваПоля.ИмяПоляДляЗапроса); + Поле = СтрЗаменить(Поле, "#ИмяПоляДляЗапроса", СвойстваПоля.ИмяПоляДляЗапроса); + + Если ТабличнаяЧастьКлюча Тогда + Поле = СтрЗаменить(Поле, "Шапка?", "ТабличнаяЧасть?"); + СоединенияИПоля.Реквизиты = СтрЗаменить(СоединенияИПоля.Реквизиты, "Шапка?", "ТабличнаяЧасть?"); + КонецЕсли; + + СоединенияИПоля.Соединения = СоединенияИПоля.Соединения + Соединения; + СоединенияИПоля.Поля = СоединенияИПоля.Поля + Поле; + НомерРеквизита = НомерРеквизита + 1; + КонецЦикла; + + Возврат СоединенияИПоляПоТаблицам; + +КонецФункции + +// Для функции СоединенияИПоляПоТаблицам. +Функция СравнениеПоля(СвойстваПоля) + + КоличествоТиповПоля = СвойстваПоля.ТипКонечногоПоля.Типы().Количество(); + + БезЗначенияНеопределено = КоличествоТиповПоля = 1; + Если СвойстваПоля.Свойство("БезЗначенияNull") Тогда + БезЗначенияNull = СвойстваПоля.БезЗначенияNull; + Иначе + БезЗначенияNull = БезЗначенияNull(СвойстваПоля); + КонецЕсли; + + БезУточненияНеопределено = Не СвойстваПоля.ЕстьУточнениеНеопределено Или БезЗначенияНеопределено; + БезУточненияNull = Не СвойстваПоля.ЕстьУточнениеNull Или БезЗначенияNull; + + // Сохранение только ключей доступа. + Если СвойстваПоля.ТипыСохраненияПустойСсылки.Количество() = 0 + И БезУточненияНеопределено + И БезУточненияNull + И СвойстваПоля.ТипыСохраненияКлючейДоступа.Количество() = КоличествоТиповПоля Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(КлючиДоступаКОбъектам?.#КлючДоступаПользователейКОбъекту, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + КонецЕсли; + + // Сохранение только групп значений доступа. + Если СвойстваПоля.ТипыСохраненияПустойСсылки.Количество() = 0 + И БезУточненияНеопределено + И БезУточненияNull + И СвойстваПоля.ТипыСохраненияГруппЗначений.Количество() = КоличествоТиповПоля Тогда + + Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаЗначенийДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + Иначе + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ТекущийСписок.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + // Сохранение только значений. + Если Не ЕстьПростойТип(СвойстваПоля.ТипКонечногоПоля) + И КоличествоТиповПоля = 1 + И СвойстваПоля.ТипыСохраненияЗначений.Количество() = КоличествоТиповПоля Тогда + + Если БезЗначенияNull Тогда + Возврат " + |И (Шапка?.Значение? = #ИмяПоляДляЗапроса)"; // @query-part-1 + Иначе + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(#ИмяПоляДляЗапроса, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)))"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + // Сохранение одного ссылочного типа. + Если БезУточненияNull + И КоличествоТиповПоля = 1 + И СвойстваПоля.ТипыСохраненияТипов.Количество() = КоличествоТиповПоля + И СвойстваПоля.ТипыСохраненияТиповПростых.Количество() = 0 Тогда + + Если СвойстваПоля.ТипыСохраненияТиповРасширений.Количество() = 0 Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ТипыКонфигурации?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)))"; // @query-part-1 + ИначеЕсли СвойстваПоля.ТипыСохраненияТиповКонфигурации.Количество() = 0 Тогда + Возврат " + |И (Шапка?.Значение? = ЕСТЬNULL(ТипыРасширений?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовРасширений.ПустаяСсылка)))"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + // Сохранение одного простого типа. + Если БезУточненияNull + И КоличествоТиповПоля = 1 + И СвойстваПоля.ТипыСохраненияТиповПростых.Количество() = 1 Тогда + + Возврат " + |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный))"; // @query-part-1 + КонецЕсли; + + Если СвойстваПоля.ТипыСохраненияТипаЗапрещенный.Количество() = КоличествоТиповПоля Тогда + Возврат " + |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипЗапрещенный))"; // @query-part-1 + КонецЕсли; + + // Сохранение только значения ТипРазрешенный. + Если СвойстваПоля.ТипыСохраненияТипаРазрешенный.Количество() = КоличествоТиповПоля Тогда + Возврат " + |И (Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный))"; // @query-part-1 + КонецЕсли; + + СравнениеПоля = " + |И (ВЫБОР + | #СодержаниеВыбора + |КОНЕЦ)"; // @query-part-1 + СодержаниеВыбора = ""; + + СохранениеЗначенияБулево = СвойстваПоля.ТипыСохраненияЗначений.Найти(Тип("Булево")) <> Неопределено; + + Если Не БезЗначенияNull + И Не (СохранениеЗначенияБулево И КоличествоТиповПоля = 1) Тогда + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса ЕСТЬ NULL + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null)"; // @query-part-1 + КонецЕсли; + Если КоличествоТиповПоля > 1 Тогда + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса = НЕОПРЕДЕЛЕНО + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Неопределено)"; // @query-part-1 + КонецЕсли; + Если СохранениеЗначенияБулево Тогда + Если КоличествоТиповПоля > 1 Тогда + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Истина) + |КОГДА НЕ #ИмяПоляДляЗапроса + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Ложь)"; // @query-part-1 + Иначе + СодержаниеВыбора = СодержаниеВыбора + " + |КОГДА #ИмяПоляДляЗапроса + | ТОГДА Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Истина) + |ИНАЧЕ Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Ложь)"; // @query-part-1 + КонецЕсли; + КонецЕсли; + + ПроверкиПоТипам = Новый СписокЗначений; + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповПростых, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный)"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияКлючейДоступа, + "Шапка?.Значение? = ЕСТЬNULL(КлючиДоступаКОбъектам?.#КлючДоступаПользователейКОбъекту, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + + Если Не СвойстваПоля.ЭтоСписокЗначенийДоступаСГруппамиЗначений Тогда + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, + "Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаЗначенийДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + ИначеЕсли СвойстваПоля.НесколькоГруппЗначений Тогда + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, + "Шапка?.Значение? = ЕСТЬNULL(ГруппыЗначений?.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + Иначе + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияГруппЗначений, + "Шапка?.Значение? = ЕСТЬNULL(ТекущийСписок.ГруппаДоступа, + | ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.Null))"); // @query-part-1 + КонецЕсли; + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияЗначений, + "Шапка?.Значение? = #ИмяПоляДляЗапроса", , СохранениеЗначенияБулево); + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияПустойСсылки, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ПустаяСсылкаЛюбогоТипа)", + "ЭтоПроверкаПустойСсылки"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповКонфигурации, + "Шапка?.Значение? = ЕСТЬNULL(ТипыКонфигурации?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка))"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТиповРасширений, + "Шапка?.Значение? = ЕСТЬNULL(ТипыРасширений?.Ссылка, + | ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовРасширений.ПустаяСсылка))"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТипаЗапрещенный, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипЗапрещенный)"); // @query-part-1 + + ДобавитьПроверкуПоТипам(ПроверкиПоТипам, СвойстваПоля.ТипыСохраненияТипаРазрешенный, + "Шапка?.Значение? = ЗНАЧЕНИЕ(Перечисление.ДополнительныеЗначенияДоступа.ТипРазрешенный)"); // @query-part-1 + + ПроверкиПоТипам.СортироватьПоПредставлению(); + + Для Каждого ПроверкаПоТипам Из ПроверкиПоТипам Цикл + Если ПроверкаПоТипам.Значение.Типы.Количество() = 0 Тогда + Продолжить; + КонецЕсли; + Если ПроверкиПоТипам.Индекс(ПроверкаПоТипам) < ПроверкиПоТипам.Количество() - 1 Тогда + ПроверкаТипов = ""; + Для Каждого Тип Из ПроверкаПоТипам.Значение.Типы Цикл + Если ЭтоПростойТип(Тип) Тогда + ИмяТипа = Строка(Тип); + Иначе + ИмяТипа = Метаданные.НайтиПоТипу(Тип).ПолноеИмя(); + КонецЕсли; + Если ПроверкаТипов <> "" Тогда + ПроверкаТипов = ПроверкаТипов + " + | ИЛИ "; + КонецЕсли; + ШаблонПроверки = ?(ПроверкаПоТипам.Значение.Свойство("ЭтоПроверкаПустойСсылки"), + "#ИмяПоляДляЗапроса = ЗНАЧЕНИЕ(#ИмяТипа.ПустаяСсылка)", + "ТИПЗНАЧЕНИЯ(#ИмяПоляДляЗапроса) = ТИП(#ИмяТипа)"); // @query-part-3 + ПроверкаТипов = ПроверкаТипов + СтрЗаменить(ШаблонПроверки, "#ИмяТипа", ИмяТипа); + КонецЦикла; + Проверка = " + |КОГДА #ПроверкаТипов + | ТОГДА #Проверка"; // @query-part-1 + Проверка = СтрЗаменить(Проверка, "#ПроверкаТипов", ПроверкаТипов); + Иначе + Проверка = " + |ИНАЧЕ #Проверка"; // @query-part-1 + КонецЕсли; + Проверка = СтрЗаменить(Проверка, "#Проверка", ПроверкаПоТипам.Значение.Проверка); + СодержаниеВыбора = СодержаниеВыбора + Проверка; + КонецЦикла; + + Возврат СтрЗаменить(СравнениеПоля, "#СодержаниеВыбора", ТекстСОтступом(СокрЛ(СодержаниеВыбора), " ")); + +КонецФункции + +// Для функции СравнениеПоля. +Процедура ДобавитьПроверкуПоТипам(ПроверкиПоТипам, ИсходныеТипы, Проверка, ДополнительноеСвойство = "", ПропуститьБулево = Ложь) + + Типы = Новый Массив; + Для Каждого Тип Из ИсходныеТипы Цикл + Если ПропуститьБулево И Тип = Тип("Булево") Тогда + Продолжить; + КонецЕсли; + Типы.Добавить(Тип); + КонецЦикла; + + Если Типы.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Структура = Новый Структура("Типы, Проверка", Типы, Проверка); + ПроверкиПоТипам.Добавить(Структура, Формат(Структура.Типы.Количество(), "ЧЦ=10; ЧВН=; ЧГ=")); + + Если ДополнительноеСвойство = "" Тогда + Возврат; + КонецЕсли; + + Структура.Вставить(ДополнительноеСвойство); + +КонецПроцедуры + +// Для функции ДобавитьПроверкуШапкиКлюча. +Процедура ЗаполнитьПсевдонимПоНомеруРеквизита(Соединения, Поле, НомерРеквизита, Псевдоним) + + ПсевдонимСНомером = СтрЗаменить(Псевдоним, "?", НомерРеквизита); + + Соединения = СтрЗаменить(Соединения, Псевдоним, ПсевдонимСНомером); + Поле = СтрЗаменить(Поле, Псевдоним, ПсевдонимСНомером); + +КонецПроцедуры + +// Для функций ДобавитьПроверкуШапкиКлюча, СравнениеПоля. +Функция ТекстСОтступом(Текст, Отступ) + + Возврат СтрЗаменить(Текст, Символы.ПС, Символы.ПС + Отступ); + +КонецФункции + +// Для функции СравнениеПоля, ДобавитьОпорноеПоле. +Функция ЕстьПростойТип(ОписаниеТипов) + + Возврат ОписаниеТипов.СодержитТип(Тип("Булево")) + Или ОписаниеТипов.СодержитТип(Тип("Дата")) + Или ОписаниеТипов.СодержитТип(Тип("Строка")) + Или ОписаниеТипов.СодержитТип(Тип("Число")) + Или ОписаниеТипов.СодержитТип(Тип("УникальныйИдентификатор")) + Или ОписаниеТипов.СодержитТип(Тип("ХранилищеЗначения")); + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область ПреобразованиеТекстовОграниченийВСтруктуры + +// См. также УправлениеДоступом.РазобранноеОграничение. +// +// Возвращаемое значение: +// Структура: +// * ПоляТаблиц - см. НовыеПоляТаблиц +// * ВнутренниеДанные - см. НовыеВнутренниеДанные +// +Функция РазобранноеОграничение(ОсновнаяТаблица, ТекстОграничения) Экспорт + + ВнутренниеДанные = НовыеВнутренниеДанные(); + ВнутренниеДанные.Вставить("ОсновнаяТаблица", ОсновнаяТаблица); + ВнутренниеДанные.Вставить("ТекстОграничения", СокрЛП(ТекстОграничения)); + + ВнутренниеДанные.Вставить("СинтаксисЯзыка", УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка()); + ВнутренниеДанные.Вставить("ПоляТаблиц", НовыеПоляТаблиц()); + ВнутренниеДанные.Вставить("Псевдонимы", Новый Соответствие); + + ВнутренниеДанные.Вставить("ПоляКлючаДоступа", Новый Массив); + + ВнутренниеДанные.Вставить("ТаблицаНаборовСимволов", ТаблицаНаборовСимволов(ВнутренниеДанные)); + ВнутренниеДанные.Вставить("ЧастиОграничения", ЧастиОграничения(ВнутренниеДанные)); + + Результат = Новый Структура; + Результат.Вставить("ВнутренниеДанные", ВнутренниеДанные); + Результат.Вставить("ПоляТаблиц", ВнутренниеДанные.ПоляТаблиц); + + Возврат Результат; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ОсновнаяТаблица - Строка - таблица, которая ограничивается. +// * ТекстОграничения - Строка +// * СинтаксисЯзыка - см. СинтаксисЯзыка +// * ПоляТаблиц - см. НовыеПоляТаблиц +// * Псевдонимы - Соответствие +// * ПоляКлючаДоступа - Массив из см. НовоеПолеКлючаДоступа +// * ТаблицаНаборовСимволов - см. ТаблицаНаборовСимволов +// * ЧастиОграничения - см. ЧастиОграничения +// +Функция НовыеВнутренниеДанные() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ОсновнаяТаблица - Строка - таблица, которая ограничивается. +// * ТекстОграничения - Строка +// * СинтаксисЯзыка - см. СинтаксисЯзыка +// * ПоляТаблиц - см. НовыеПоляТаблиц +// * Псевдонимы - Соответствие +// * ПоляКлючаДоступа - Массив из см. НовоеПолеКлючаДоступа +// * ТаблицаНаборовСимволов - см. ТаблицаНаборовСимволов +// * ЧастиОграничения - см. ЧастиОграничения +// * ЭтоУсловиеСоединения - Булево +// * ЭтоУсловиеКогда - Булево +// * ЭтоЗначениеТогдаИначе - Булево +// * КорневойУзел - см. ОписаниеУзла +// +Функция РасширенныеВнутренниеДанные(ВнутренниеДанные) + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ВнутренниеДанные); + Возврат Новый Структура(ФиксированныйКонтекст); + +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - имя коллекции объектов метаданных, например, Справочники. +// * Значение - см. НовыйСоставКоллекции +// +Функция НовыеПоляТаблиц() + + Возврат Новый Соответствие; + +КонецФункции + +// Возвращаемое значение: +// Соответствие из КлючИЗначение: +// * Ключ - Строка - имя таблицы (объекта метаданных) в верхнем регистре. +// * Значение - см. НовыеСвойстваТаблицы +// +Функция НовыйСоставКоллекции() + + Возврат Новый Соответствие; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ТаблицаСуществует - Булево - Ложь (для заполнения Истина, если существует). +// * ЭтоОсновнаяТаблица - Булево +// * Источники - Массив +// * ПервоеПоле - Неопределено +// * Поля - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя реквизита в верхнем регистре, в том числе через точки, +// например, "ВЛАДЕЛЕЦ.ОРГАНИЗАЦИЯ", "ТОВАРЫ.НОМЕНКЛАТУРА". +// ** Значение - см. НовыеСвойстваПоля +// * Предопределенные - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя предопределенного элемента. +// ** Значение - см. НовыеСвойстваПредопределенного +// * Расширения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя третьего имени таблицы, например, имя табличной части. +// ** Значение - см. НовыеСвойстваРасширения +// +Функция НовыеСвойстваТаблицы() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ПолеСОшибкой - Число - 0 (для заполнения, если поле содержит ошибку, +// если 1, то ошибка в имени первой части поля, +// если 2, то ошибка в имени второй части поля, т.е. после первой точки). +// * ВидОшибки - Строка - "НеНайдено", "ТабличнаяЧастьБезПоля", +// "ТабличнаяЧастьПослеТочки". +// * Коллекция - Строка - пустая строка (для заполнения, если первая часть +// поля существует, т.е. часть поля до первой точки). Варианты: "Реквизиты", +// "ТабличныеЧасти", "СтандартныеРеквизиты", "СтандартныеТабличныеЧасти", +// "Измерения", "Ресурсы", "Графы", "ПризнакиУчета", "ПризнакиУчетаСубконто", +// "РеквизитыАдресации", "СпециальныеПоля". Специальные поля - это +// "Значение" - у таблиц "Константа.*", +// "Регистратор" и "Период" - у таблиц "Последовательность.*", +// "ОбъектПерерасчета", "ВидРасчета" у таблиц "РегистрРасчета.<Имя>.<ИмяПерерасчета>". +// Поля после первой точки могут относится только к коллекциям: "Реквизиты", +// "СтандартныеРеквизиты", "ПризнакиУчета", "РеквизитыАдресации". Для этих +// частей имени поля не требуется уточнять коллекцию. +// * СодержитТипы - Соответствие из КлючИЗначение: +// ** Ключ - Строка - полное имя ссылочной таблицы в верхнем регистре. +// ** Значение - Структура: +// *** ИмяТипа - Строка - имя типа, наличие которого нужно проверить. +// *** СодержитТип - Булево - Ложь (для заполнения Истина, +// если у поля последнего поля есть тип). +// * ПервыйИсточник - Структура: +// ** Ключ - СтрокаТаблицыЗначений - строка-источник первого поля. +// ** Значение - Строка - таблица +// +Функция НовыеСвойстваПоля() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ИмяСуществует - Булево - Ложь (для заполнения Истина, если предопределенный есть). +// * Источники - Массив +// +Функция НовыеСвойстваПредопределенного() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ТаблицаСуществует - Булево - Ложь (для заполнения Истина, если существует). +// * Источники - Массив +// * ПервоеПоле - Неопределено +// * Поля - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя реквизита в верхнем регистре, в том числе через точки, +// например, "ВЛАДЕЛЕЦ.ОРГАНИЗАЦИЯ", "ТОВАРЫ.НОМЕНКЛАТУРА". +// ** Значение - см. НовыеСвойстваПоля +// +Функция НовыеСвойстваРасширения() + + Возврат Новый Структура; + +КонецФункции + + +// Смотри также УправлениеДоступом.СтруктураОграничения +// +// Параметры: +// РазобранноеОграничение - см. РазобранноеОграничение +// +// Возвращаемое значение: +// Структура: +// * ОписаниеОшибок - см. ОписаниеОшибок +// * ДополнительныеТаблицы - Массив из см. НовоеОписаниеСоединения +// * ПсевдонимОсновнойТаблицы - Строка - заполнено, если указаны дополнительные таблицы. +// * ОграничениеЧтения - см. ОписаниеУзла +// * ОграничениеИзменения - см. ОписаниеУзла +// +Функция СтруктураОграничения(РазобранноеОграничение) Экспорт + + ВнутренниеДанные = РазобранноеОграничение.ВнутренниеДанные; + + ОтметитьНекорректныеИменаТаблицПолейИТиповПолей(РазобранноеОграничение.ПоляТаблиц, + ВнутренниеДанные); + + // Заполнение найденных ошибок. + ОписаниеОшибок = ОписаниеОшибок(); + + Таблица = ВнутренниеДанные.ТаблицаНаборовСимволов; + ОтборСтрокБезОшибок = Новый Структура("ТекстОшибки", ""); + Если Таблица.Количество() <> Таблица.НайтиСтроки(ОтборСтрокБезОшибок).Количество() Тогда + ОписаниеОшибок.ЕстьОшибки = Истина; + ТребуетсяДополнение = Ложь; + ДлинаНомераСтроки = СтрДлина(Формат(СтрЧислоСтрок(ВнутренниеДанные.ТекстОграничения), "ЧГ=")); + Для Каждого Строка Из Таблица Цикл + Если Строка.ТекстОшибки = "" Тогда + Продолжить; + КонецЕсли; + ДобавитьОшибку(Строка, ОписаниеОшибок, ВнутренниеДанные, ДлинаНомераСтроки); + Если Строка.ПозицияОшибки = -1 Тогда + ТребуетсяДополнение = Истина; + КонецЕсли; + КонецЦикла; + ОписаниеОшибок.Ограничение = ПронумерованныйТекстОграниченияСОтметкамиОшибок( + ВнутренниеДанные.ТекстОграничения, ОписаниеОшибок.Ошибки, ДлинаНомераСтроки); + Если ТребуетсяДополнение Тогда + ОписаниеОшибок.Дополнение = ОписаниеДопустимыхШаблонов(); + КонецЕсли; + КонецЕсли; + + ЧастиОграничения = ВнутренниеДанные.ЧастиОграничения; + + СтруктураОграничения = Новый Структура; + СтруктураОграничения.Вставить("ОписаниеОшибок", ОписаниеОшибок); + СтруктураОграничения.Вставить("ДополнительныеТаблицы", ЧастиОграничения.ДополнительныеТаблицы); + СтруктураОграничения.Вставить("ПсевдонимОсновнойТаблицы", ЧастиОграничения.ПсевдонимОсновнойТаблицы); + СтруктураОграничения.Вставить("ОграничениеЧтения", ЧастиОграничения.ОграничениеЧтения); + СтруктураОграничения.Вставить("ОграничениеИзменения", ЧастиОграничения.ОграничениеИзменения); + + // Дополнительные сведения для внутреннего использования. + ИмяТипаТаблицы = СтрРазделить(ВнутренниеДанные.ОсновнаяТаблица, ".")[0]; + СвойстваТипаТаблиц = ВнутренниеДанные.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + + НовыеВнутренниеДанные = Новый Структура; + НовыеВнутренниеДанные.Вставить("ПоляКлючаДоступа", ВнутренниеДанные.ПоляКлючаДоступа); + НовыеВнутренниеДанные.Вставить("ЭтоСсылочныйТип", СвойстваТипаТаблиц.ЭтоСсылочныйТип); + НовыеВнутренниеДанные.Вставить("ИмяКоллекцииТипа", СвойстваТипаТаблиц.ИмяКоллекции); + НовыеВнутренниеДанные.Вставить("ТипыТаблицПоИменам", ВнутренниеДанные.СинтаксисЯзыка.ТипыТаблиц.ПоИменам); + + СтруктураОграничения.Вставить("ВнутренниеДанные", НовыеВнутренниеДанные); + + Для Каждого Строка Из ВнутренниеДанные.ТаблицаНаборовСимволов Цикл + Строка.Строки.Очистить(); + Строка.КонечнаяСтрока = Неопределено; + КонецЦикла; + ВнутренниеДанные.ТаблицаНаборовСимволов.Очистить(); + ВнутренниеДанные.ЧастиОграничения.Очистить(); + ВнутренниеДанные.Очистить(); + + Возврат СтруктураОграничения; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * ЕстьОшибки - Булево +// * ТекстОшибок - Строка +// * Ограничение - Строка +// * Ошибки - Массив из см. СвойстваОшибки +// * Дополнение - Строка +// +Функция ОписаниеОшибок() + + ОписаниеОшибок = Новый Структура; + ОписаниеОшибок.Вставить("ЕстьОшибки", Ложь); + ОписаниеОшибок.Вставить("ТекстОшибок", ""); + ОписаниеОшибок.Вставить("Ограничение", ""); + ОписаниеОшибок.Вставить("Ошибки", Новый Массив); + ОписаниеОшибок.Вставить("Дополнение", ""); + + Возврат ОписаниеОшибок; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * НомерСтроки - Число - номер строки текста ограничения, в которой найдена ошибка. +// * ПозицияВСтроке - Число - позиция в строке текста ограничения, в которой найдена ошибка. +// * ТекстОшибки - Строка - описание ошибки. +// * СтрокаОшибки - Строка - строка текста ограничения, в которой найдена ошибка. +// +Функция СвойстваОшибки() + + Возврат Новый Структура; + +КонецФункции + +// Формирует полный текст ошибок описания ограничения доступа с дополнением, +// который можно указать, как текст для вызова исключения. +// +// Параметры: +// ПолноеИмя - Строка - полное имя таблицы списка. +// ОписаниеОшибок - Структура - значение возвращаемое функцией СтруктураОграничения. +// ДляВнешнихПользователей - Булево - если передать Истина, тогда текст ошибки будет содержать +// назначение ограничения для внешних пользователей. +// +// Возвращаемое значение: +// Строка - текст для вызова исключения. +// +Функция ТекстОшибокДляВызоваИсключения(ПолноеИмя, ОписаниеОшибок, ДляВнешнихПользователей, ВМодулеМенеджера) + + Если Не ОписаниеОшибок.ЕстьОшибки Тогда + Возврат ""; + КонецЕсли; + + Если ОписаниеОшибок.Ошибки.Количество() = 1 Тогда + Уточнение = ""; + Если ВМодулеМенеджера = Неопределено Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"":'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"":'"); + КонецЕсли; + ИначеЕсли ВМодулеМенеджера Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + КонецЕсли; + Уточнение = "ПриЗаполненииОграниченияДоступа"; + Иначе + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибка в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + КонецЕсли; + Уточнение = "УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа"; + КонецЕсли; + Иначе + Если ВМодулеМенеджера = Неопределено Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"":'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"":'"); + КонецЕсли; + ИначеЕсли ВМодулеМенеджера Тогда + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2 модуля менеджера объекта метаданных:'"); + КонецЕсли; + Уточнение = "ПриЗаполненииОграниченияДоступа"; + Иначе + Если ДляВнешнихПользователей Тогда + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа внешних пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + Иначе + ЗаголовокОшибки = + НСтр("ru = 'Ошибки в ограничении доступа пользователей к списку ""%1"", + |указанному в процедуре %2:'"); + КонецЕсли; + Уточнение = "УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа"; + КонецЕсли; + КонецЕсли; + + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ЗаголовокОшибки, ПолноеИмя, Уточнение); + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.ТекстОшибок; + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.Ограничение; + + Если ЗначениеЗаполнено(ОписаниеОшибок.Дополнение) Тогда + ТекстОшибки = ТекстОшибки + Символы.ПС + Символы.ПС + ОписаниеОшибок.Дополнение; + КонецЕсли; + + Возврат Символы.ПС + ТекстОшибки + Символы.ПС; + +КонецФункции + +// Для функции СтруктураОграничения. +Процедура ДобавитьОшибку(Строка, ОписаниеОшибок, ВнутренниеДанные, ДлинаНомераСтроки) + + ПозицияВТексте = Строка.Позиция; + ПозицияОшибкиВКонцеСтроки = Ложь; + ТекстОграничения = ВнутренниеДанные.ТекстОграничения; + + Если Строка.ПозицияОшибки > 0 Тогда + ПозицияВТексте = ПозицияВТексте + Строка.ПозицияОшибки; + Если Строка.ПозицияОшибки = СтрДлина(Строка.Символы) Тогда + ПозицияВТексте = ПозицияВТексте - 1; + ПозицияОшибкиВКонцеСтроки = Истина; + КонецЕсли; + ИначеЕсли Строка.Позиция > СтрДлина(ТекстОграничения) Тогда + ПозицияВТексте = ПозицияВТексте - 1; + ПозицияОшибкиВКонцеСтроки = Истина; + КонецЕсли; + + Координаты = КоординатыПозицииВТексте(ТекстОграничения, ПозицияВТексте); + Координаты.ПозицияВСтроке = Координаты.ПозицияВСтроке + ?(ПозицияОшибкиВКонцеСтроки, 1, 0); + + СтрокаОшибки = СтрПолучитьСтроку(ТекстОграничения, Координаты.НомерСтроки); + СтрокаОшибки = Лев(СтрокаОшибки, Координаты.ПозицияВСтроке - 1) + + "<>" + Сред(СтрокаОшибки, Координаты.ПозицияВСтроке); + + Ошибка = СвойстваОшибки(); + Ошибка.Вставить("НомерСтроки", Координаты.НомерСтроки); + Ошибка.Вставить("ПозицияВСтроке", Координаты.ПозицияВСтроке); + Ошибка.Вставить("ТекстОшибки", Строка.ТекстОшибки); + Ошибка.Вставить("СтрокаОшибки", СтрокаОшибки); + + ОписаниеОшибок.Ошибки.Добавить(Ошибка); + + Если ЗначениеЗаполнено(ОписаниеОшибок.ТекстОшибок) Тогда + ОписаниеОшибок.ТекстОшибок = ОписаниеОшибок.ТекстОшибок + Символы.ПС + Символы.ПС; + КонецЕсли; + + ОписаниеОшибок.ТекстОшибок = ОписаниеОшибок.ТекстОшибок + + "{(" + Формат(Ошибка.НомерСтроки, "ЧЦ=" + ДлинаНомераСтроки + "; ЧВН=; ЧГ=") + + ", " + Формат(Ошибка.ПозицияВСтроке, "ЧГ=") + ")}:" + + " " + Ошибка.ТекстОшибки + Символы.ПС + Ошибка.СтрокаОшибки; + +КонецПроцедуры + +// Для функции СтруктураОграничения. +Функция ПронумерованныйТекстОграниченияСОтметкамиОшибок(ТекстОграничения, Ошибки, ДлинаНомераСтроки) + + КоличествоСтрок = СтрЧислоСтрок(ТекстОграничения); + СтрокиТекстаОграничений = Новый Массив; + + Для НомерСтроки = 1 По КоличествоСтрок Цикл + Строка = СтрПолучитьСтроку(ТекстОграничения, НомерСтроки); + СтрокиТекстаОграничений.Добавить(Строка); + КонецЦикла; + + Индекс = Ошибки.Количество() - 1; + Пока Индекс >= 0 Цикл + Ошибка = Ошибки[Индекс]; + Строка = СтрокиТекстаОграничений[Ошибка.НомерСтроки - 1]; + СтрокиТекстаОграничений[Ошибка.НомерСтроки - 1] = Лев(Строка, Ошибка.ПозицияВСтроке - 1) + + "<>" + Сред(Строка, Ошибка.ПозицияВСтроке); + Индекс = Индекс - 1; + КонецЦикла; + + Текст = ""; + НомерСтроки = 1; + + Для Каждого Строка Из СтрокиТекстаОграничений Цикл + Текст = Текст + ?(Текст = "", "", Символы.ПС) + + ?(СтрНайти(Строка, "<>") > 0, "*", " ") + + " " + Формат(НомерСтроки, "ЧЦ=" + ДлинаНомераСтроки + "; ЧВН=; ЧГ=") + " " + Строка; + НомерСтроки = НомерСтроки + 1; + КонецЦикла; + + Возврат Текст; + +КонецФункции + +// Для функции СтруктураОграничения. +Функция ОписаниеДопустимыхШаблонов() + + Если ВариантВстроенногоЯзыкаРусский() Тогда + Шаблон1 = + " РазрешитьЧтениеИзменение + | ГДЕ ..."; // @Non-NLS + + Шаблон2 = + " РазрешитьЧтение + | ГДЕ ... + | ; + | РазрешитьИзменениеЕслиРазрешеноЧтение + | ГДЕ ..."; // @Non-NLS + + Шаблон3 = + " ПрисоединитьДополнительныеТаблицы + | ЭтотСписок КАК <Псевдоним> + | ЛЕВОЕ СОЕДИНЕНИЕ ... + | ; + | РазрешитьЧтение + | ГДЕ ... + | ; + | РазрешитьИзменениеЕслиРазрешеноЧтение + | ГДЕ ..."; // @Non-NLS + Иначе + Шаблон1 = + " AllowReadWrite + | WHERE ..."; + + Шаблон2 = + " AllowRead + | WHERE ... + | ; + | AllowWriteIfAllowRead + | WHERE ..."; + + Шаблон3 = + " AttachAdditionalTables + | LIST AS + | LEFT/INNER JOIN ... + | ; + | AllowRead + | WHERE ... + | ; + | AllowWriteIfAllowRead + | WHERE ..."; + КонецЕсли; + + Описание = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ограничение может состоять из 1-3 частей в одном из 4 вариантов: + |1) одинаковое ограничение чтения и изменения: + |%1 + |2) разные ограничения чтения и изменения: + |%2 + |3) любой из вариантов выше с дополнительными таблицами, например: + |%3'"), + Шаблон1, Шаблон2, Шаблон3); + + Возврат Описание; + +КонецФункции + +// Для процедуры ДобавитьОшибку. +Функция КоординатыПозицииВТексте(Текст, ПозицияВТексте) + + Результат = Новый Структура; + Результат.Вставить("НомерСтроки", 0); + Результат.Вставить("ПозицияВСтроке", 0); + + КоличествоСтрок = СтрЧислоСтрок(Текст); + ПозицияНачалаСтроки = 1; + Для НомерСтроки = 1 По КоличествоСтрок Цикл + ДлинаТекущейСтроки = СтрДлина(СтрПолучитьСтроку(Текст, НомерСтроки)); + Если ПозицияВТексте < ПозицияНачалаСтроки + ДлинаТекущейСтроки Тогда + Прервать; + КонецЕсли; + ПозицияНачалаСтроки = ПозицияНачалаСтроки + ДлинаТекущейСтроки + 1; + КонецЦикла; + + Результат.НомерСтроки = НомерСтроки; + Результат.ПозицияВСтроке = ПозицияВТексте - ПозицияНачалаСтроки + 1; + + Возврат Результат; + +КонецФункции + +#Область ЛексическийАнализ + +// Для функции РазобранноеОграничение. +// Раскладывает текст в таблицу наборов символов, в которых: +// - нет символов отступа (пробелов, табуляций, переводов строки); +// - выделены символы произвольных строк и чисел; +// - определены ключевые слова и операции; +// - проверен формат имен и чисел; +// - добавлены ошибки с описанием. +// +// Параметры: +// ТекстОграничения - Строка - текст ограничения доступа. +// +// Возвращаемое значение: +// ТаблицаЗначений: +// * Символы - Строка - символ, пара символов или слово. +// * Позиция - Число - позиция символов в тексте ограничения. +// * Вид - Строка - "КлючевоеСлово", "Операция", "Имя", "Разделитель", +// "Число", "ПроизвольнаяСтрока", "НедопустимыйСимвол", "Конец". +// * Тип - Строка - тип для для видов "КлючевоеСлово" и "Операция". +// * Приоритет - Число - приоритет для видов "КлючевоеСлово" и "Операция". +// * Уточнение - Число - числовое значение для вида "Число". +// - Строка - имя для вида "КлючевоеСлово", строка символов для вида "ПроизвольнаяСтрока". +// * ЭтоРезерв - Булево - если Истина, значит это зарезервированная операция или ключевое слово. +// * ПозицияОшибки - Число - позиция ошибки в тексте ограничения, если текст ошибки не пустой. +// * ТекстОшибки - Строка - текст ошибки, если найдена ошибка. +// +Функция ТаблицаНаборовСимволов(ВнутренниеДанные) + + ТаблицаНаборовСимволов = Новый ТаблицаЗначений; + ТаблицаНаборовСимволов.Колонки.Добавить("Символы", Новый ОписаниеТипов("Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("Позиция", Новый ОписаниеТипов("Число")); + ТаблицаНаборовСимволов.Колонки.Добавить("Вид", Новый ОписаниеТипов("Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("Тип", Новый ОписаниеТипов("Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("Приоритет", Новый ОписаниеТипов("Число")); + ТаблицаНаборовСимволов.Колонки.Добавить("Уточнение", Новый ОписаниеТипов("Число, Строка")); + ТаблицаНаборовСимволов.Колонки.Добавить("ЭтоРезерв", Новый ОписаниеТипов("Булево")); + ТаблицаНаборовСимволов.Колонки.Добавить("ПозицияОшибки", Новый ОписаниеТипов("Число")); + ТаблицаНаборовСимволов.Колонки.Добавить("ТекстОшибки", Новый ОписаниеТипов("Строка")); + + ТекстОграничения = ВнутренниеДанные.ТекстОграничения; + + Если Не ЗначениеЗаполнено(ТекстОграничения) Тогда + Возврат ТаблицаНаборовСимволов; + КонецЕсли; + + ДлинаТекстаОграничения = СтрДлина(ТекстОграничения); + + СинтаксисЯзыка = ВнутренниеДанные.СинтаксисЯзыка; + СимволыЯзыка = СинтаксисЯзыка.СимволыЯзыка; + + ВидНабораСимволов = ""; // Слово, ПроизвольнаяСтрока, Операция. + ПозицияНабораСимволов = 0; + НаборСимволов = Новый Массив; + СтрокаТаблицы = Неопределено; + + Для НомерСимвола = 1 По ДлинаТекстаОграничения Цикл + Символ = Сред(ТекстОграничения, НомерСимвола, 1); + ТипСимвола = СимволыЯзыка.Получить(Символ); + // Сначала обработка символов слов, так как они встречаются наиболее часто. + Если ТипСимвола = "СимволСлова" И ВидНабораСимволов = "Слово" Тогда + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + // Обработка произвольной строки символов. + Если ВидНабораСимволов = "ПроизвольнаяСтрока" Тогда + Если ТипСимвола = "ОграничительСтроки" Тогда + Если Сред(ТекстОграничения, НомерСимвола + 1, 1) <> Символ Тогда + СтрокаТаблицы.Уточнение = СтрСоединить(НаборСимволов); + СтрокаТаблицы.Позиция = ПозицияНабораСимволов; + НаборСимволов = Новый Массив; + ВидНабораСимволов = ""; + Продолжить; + Иначе + НомерСимвола = НомерСимвола + 1; + КонецЕсли; + КонецЕсли; + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + Если ВидНабораСимволов = "Слово" Тогда + // Вначале цикла уже обработан случай, когда ТипСимвола = "СимволСлова", + // для остальных типов символов слово завершено и его нужно добавить в дерево. + ВидНабораСимволов = ""; + ДобавитьСловоВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + НаборСимволов = Новый Массив; + КонецЕсли; + // Обработка набора составных разделителей. + Если ВидНабораСимволов = "Операция" Тогда + Если ТипСимвола = "СимволОперации" Тогда + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + ВидНабораСимволов = ""; + ДобавитьОперациюВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + НаборСимволов = Новый Массив; + КонецЕсли; + // Обработка первого символа наборов символов. + Если ВидНабораСимволов = "" Тогда + Если ТипСимвола = "СимволСлова" Тогда + ВидНабораСимволов = "Слово"; + ПозицияНабораСимволов = НомерСимвола; + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + Если ТипСимвола = "СимволОперации" Тогда + ВидНабораСимволов = "Операция"; + ПозицияНабораСимволов = НомерСимвола; + НаборСимволов.Добавить(Символ); + Продолжить; + КонецЕсли; + Если ТипСимвола = "ОграничительСтроки" Тогда + ВидНабораСимволов = "ПроизвольнаяСтрока"; + ПозицияНабораСимволов = НомерСимвола; + СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); + СтрокаТаблицы.Символы = Символ; + СтрокаТаблицы.Вид = ВидНабораСимволов; + Продолжить; + КонецЕсли; + КонецЕсли; + // Обработка отдельных символов. + Если ТипСимвола = "Отступ" Тогда + Продолжить; + КонецЕсли; + Если ТипСимвола = "Разделитель" Тогда + СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); + СтрокаТаблицы.Символы = Символ; + СтрокаТаблицы.Позиция = НомерСимвола; + СтрокаТаблицы.Вид = "Разделитель"; + Продолжить; + КонецЕсли; + СтрокаТаблицы = ТаблицаНаборовСимволов.Добавить(); + СтрокаТаблицы.Символы = Символ; + СтрокаТаблицы.Позиция = НомерСимвола; + СтрокаТаблицы.Вид = "НедопустимыйСимвол"; + СтрокаТаблицы.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимый символ ""%1"" с кодом %2'"), Символ, КодСимвола(Символ)); + КонецЦикла; + + Если ВидНабораСимволов = "Слово" Тогда + ДобавитьСловоВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + + ИначеЕсли ВидНабораСимволов = "Операция" Тогда + ДобавитьОперациюВТаблицуНаборовСимволов(ТаблицаНаборовСимволов, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка); + + ИначеЕсли ВидНабораСимволов = "ПроизвольнаяСтрока" Тогда + СтрокаТаблицы.Уточнение = СтрСоединить(НаборСимволов); + СтрокаТаблицы.Позиция = ПозицияНабораСимволов; + СтрокаТаблицы.ПозицияОшибки = НомерСимвола - ПозицияНабораСимволов; + СтрокаТаблицы.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не указан символ окончания произвольной строки %1'"), СтрокаТаблицы.Символы); + КонецЕсли; + + ПоследняяСтрока = ТаблицаНаборовСимволов.Добавить(); + ПоследняяСтрока.Позиция = СтрДлина(ТекстОграничения) + 1; + ПоследняяСтрока.Вид = "Конец"; // Для установки текста ошибки недостатка описания. + ТаблицаНаборовСимволов.Индексы.Добавить("Вид, Уточнение"); + + Возврат ТаблицаНаборовСимволов; + +КонецФункции + +// Для функции ТаблицаНаборовСимволов. +Процедура ДобавитьСловоВТаблицуНаборовСимволов(Таблица, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка) + + СтрокаСимволов = СтрСоединить(НаборСимволов); + СвойстваСлова = СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(СтрокаСимволов)); // См. СвойстваСлова + + НоваяСтрока = Таблица.Добавить(); + НоваяСтрока.Символы = СтрокаСимволов; + НоваяСтрока.Позиция = ПозицияНабораСимволов; + + Если СвойстваСлова <> Неопределено Тогда + НоваяСтрока.Вид = "КлючевоеСлово"; + НоваяСтрока.Тип = СвойстваСлова.Тип; + НоваяСтрока.Приоритет = СвойстваСлова.Приоритет; + НоваяСтрока.Уточнение = СвойстваСлова.Идентификатор; + НоваяСтрока.ЭтоРезерв = СвойстваСлова.ЭтоРезерв; + + Если СвойстваСлова.ЭтоРезерв Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ключевое слово ""%1"" не поддерживается'"), СтрокаСимволов); + КонецЕсли; + Возврат; + КонецЕсли; + + // Слово является именем или числом. + СимволыЦифр = СинтаксисЯзыка.СимволыЦифр; + + Если НаборСимволов[0] = "." Тогда + Если НаборСимволов.Количество() > 1 Тогда + ЭтоЧисло = Ложь; + Иначе + НоваяСтрока.Вид = "Имя"; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'Имя не может начинаться с точки'"); + Возврат; + КонецЕсли; + Иначе + ЭтоЧисло = СимволыЦифр.Получить(НаборСимволов[0]) <> Неопределено; + КонецЕсли; + + Если ЭтоЧисло Тогда + НоваяСтрока.Вид = "Число"; + НомерСимвола = 1; + Для Каждого Символ Из НаборСимволов Цикл + Если СимволыЦифр.Получить(Символ) = Неопределено Тогда + НоваяСтрока.ПозицияОшибки = НомерСимвола - 1; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'Число может состоять только из цифр'"); + Возврат; + КонецЕсли; + НомерСимвола = НомерСимвола + 1; + КонецЦикла; + СимволыЧисла = Лев(СтрокаСимволов, НомерСимвола - 1); + Если СтрДлина(СимволыЧисла) > 16 Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Слишком большое число ""%1""'"), СимволыЧисла); + Возврат; + КонецЕсли; + НоваяСтрока.Уточнение = Число(СимволыЧисла); + Иначе + НоваяСтрока.Вид = "Имя"; + ЧастиИмени = СтрРазделить(СтрокаСимволов, "."); + ПозицияЧастиИмени = 1; + Для Каждого ЧастьИмени Из ЧастиИмени Цикл + Если ЧастьИмени = "" И ПозицияЧастиИмени > 1 Тогда + НоваяСтрока.ПозицияОшибки = ПозицияЧастиИмени - 1; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'После точки не указано имя'"); + Возврат; + ИначеЕсли СимволыЦифр.Получить(Лев(ЧастьИмени, 1)) <> Неопределено Тогда + НоваяСтрока.ПозицияОшибки = ПозицияЧастиИмени - 1; + НоваяСтрока.ТекстОшибки = НСтр("ru = 'После точки в имени не может следовать число'"); + Возврат; + КонецЕсли; + ПозицияЧастиИмени = ПозицияЧастиИмени + СтрДлина(ЧастьИмени) + 1; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + +// Для функции ТаблицаНаборовСимволов. +Процедура ДобавитьОперациюВТаблицуНаборовСимволов(Таблица, + НаборСимволов, ПозицияНабораСимволов, СинтаксисЯзыка) + + СтрокаСимволов = СтрСоединить(НаборСимволов); + СвойстваОперации = СинтаксисЯзыка.ОперацииЯзыка.Получить(СтрокаСимволов); + + НоваяСтрока = Таблица.Добавить(); + НоваяСтрока.Символы = СтрокаСимволов; + НоваяСтрока.Позиция = ПозицияНабораСимволов; + НоваяСтрока.Вид = "Операция"; + НоваяСтрока.Тип = СвойстваОперации.Тип; + НоваяСтрока.Приоритет = СвойстваОперации.Приоритет; + НоваяСтрока.ЭтоРезерв = СвойстваОперации.ЭтоРезерв; + + Если СвойстваОперации = Неопределено Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимая операция ""%1""'"), СтрокаСимволов); + + ИначеЕсли СвойстваОперации.ЭтоРезерв Тогда + НоваяСтрока.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Операция ""%1"" не поддерживается'"), СтрокаСимволов); + КонецЕсли; + +КонецПроцедуры + +// Для функции РазобранноеОграничение и косвенно для многих других. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * СимволыЯзыка - см. СимволыЯзыка +// * СимволыЦифр - см. СимволыЦифр +// * ОперацииЯзыка - см. ОперацииЯзыка +// * СловаЯзыка - см. СловаЯзыка +// * ТипыТаблиц - см. ТипыТаблиц +// +Функция СинтаксисЯзыка() Экспорт + + СинтаксисЯзыка = Новый Структура; + СинтаксисЯзыка.Вставить("СимволыЯзыка", СимволыЯзыка()); + СинтаксисЯзыка.Вставить("СимволыЦифр", СимволыЦифр()); + СинтаксисЯзыка.Вставить("ОперацииЯзыка", ОперацииЯзыка()); + СинтаксисЯзыка.Вставить("СловаЯзыка", СловаЯзыка()); + СинтаксисЯзыка.Вставить("ТипыТаблиц", ТипыТаблиц()); + + Возврат Новый ФиксированнаяСтруктура(СинтаксисЯзыка); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - символ +// * Значение - Строка - вид символа +// +Функция СимволыЯзыка() + + СимволыЯзыка = Новый Соответствие; + + Для КодСимвола = КодСимвола("А") // @Non-NLS + По КодСимвола("Я") Цикл // @Non-NLS + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + Для КодСимвола = КодСимвола("а") // @Non-NLS + По КодСимвола("я") Цикл // @Non-NLS + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + Для КодСимвола = КодСимвола("A") По КодСимвола("Z") Цикл + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + Для КодСимвола = КодСимвола("a") По КодСимвола("z") Цикл + + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + + СимволыЯзыка.Вставить("_", "СимволСлова"); + СимволыЯзыка.Вставить(".", "СимволСлова"); + + Для КодСимвола = КодСимвола("0") По КодСимвола("9") Цикл + СимволыЯзыка.Вставить(Символ(КодСимвола), "СимволСлова"); + КонецЦикла; + + СимволыЯзыка.Вставить(" ", "Отступ"); + СимволыЯзыка.Вставить(Символы.Таб, "Отступ"); + СимволыЯзыка.Вставить(Символы.ПС, "Отступ"); + + СимволыЯзыка.Вставить("""", "ОграничительСтроки"); + + СимволыЯзыка.Вставить("(", "Разделитель"); + СимволыЯзыка.Вставить(")", "Разделитель"); + СимволыЯзыка.Вставить(",", "Разделитель"); + СимволыЯзыка.Вставить(";", "Разделитель"); + СимволыЯзыка.Вставить("=", "СимволОперации"); + СимволыЯзыка.Вставить("<", "СимволОперации"); + СимволыЯзыка.Вставить(">", "СимволОперации"); + + // Не поддерживаются. + СимволыЯзыка.Вставить("+", "СимволОперации"); + СимволыЯзыка.Вставить("-", "СимволОперации"); + СимволыЯзыка.Вставить("*", "СимволОперации"); + СимволыЯзыка.Вставить("/", "СимволОперации"); + + Возврат Новый ФиксированноеСоответствие(СимволыЯзыка); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - символ +// * Значение - Булево - Истина +// +Функция СимволыЦифр() + + СимволыЦифр = Новый Соответствие; + + Для КодСимвола = КодСимвола("0") По КодСимвола("9") Цикл + СимволыЦифр.Вставить(Символ(КодСимвола), Истина); + КонецЦикла; + + Возврат Новый ФиксированноеСоответствие(СимволыЦифр); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - слово на русском и английском языках. +// * Значение - см. СвойстваСлова +// +Функция СловаЯзыка() + + Слова = Новый Соответствие; + + ДобавитьСловоЯзыка(Слова, "ПрисоединитьДополнительныеТаблицы", + "AttachAdditionalTables", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЭтотСписок", + "ThisList", "НачалоСписок", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазрешитьЧтениеИзменение", + "AllowReadUpdate", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазрешитьЧтение", + "AllowRead", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазрешитьИзменениеЕслиРазрешеноЧтение", + "AllowUpdateIfReadingAllowed", "Начало", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Где", + "Where", "НачалоГде"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "Левое", + "Left", "Присоединение"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Соединение", + "Join", "Присоединение"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "По", + "On", "Присоединение"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "И", + "And", "Соединитель", , 2); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Или", + "Or", "Соединитель", , 1); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "В", + "In", "Соединитель", , 5); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Как", + "As", "Соединитель"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Кроме", + "Except", "Соединитель"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Только", + "Only", "Соединитель"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Есть", + "Is", "Соединитель", , 7); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Не", + "Not", "Оператор", , 3); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "Выбор", + "Case", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Когда", + "When", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Тогда", + "Then", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Иначе", + "Else", "СловоВыбора"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Конец", + "End", "СловоВыбора"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "ЕстьNull", + "IsNull", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Выразить", + "Cast", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Значение", + "Value", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ТипЗначения", + "ValueType", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Тип", + "Type", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЗначениеРазрешено", + "ValueAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЧтениеОбъектаРазрешено", + "ObjectReadingAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ИзменениеОбъектаРазрешено", + "ObjectUpdateAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЧтениеСпискаРазрешено", + "ListReadingAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ИзменениеСпискаРазрешено", + "ListUpdateAllowed", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДляВсехСтрок", + "ForAllRows", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДляОднойИзСтрок", + "ForAtLeastOneRow", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ЭтоАвторизованныйПользователь", + "IsAuthorizedUser", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ПравоДоступа", + "AccessRight", "Функция", Ложь); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РольДоступна", + "IsInRole", "Функция", Ложь); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "ПустаяСсылка", + "EmptyRef", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Отключено", + "Disabled", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Неопределено", + "Undefined", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Null", + "Null", "ЗначениеСравнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Ложь", + "False", "ЗначениеУточнения"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Истина", + "True", "ЗначениеУточнения"); // @Non-NLS + + ДобавитьСловоЯзыка(Слова, "Строка", + "String", "ИмяТипа"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Число", + "Number", "ИмяТипа"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Дата", + "Date", "ИмяТипа"); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Булево", + "Boolean", "ИмяТипа"); // @Non-NLS + + // Неподдерживаемые, зарезервированные слова. + ДобавитьСловоЯзыка(Слова, "Выбрать", + "Select", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Первые", + "Top", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Различные", + "Distinct", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Из", + "From", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Внутреннее", + "Inner", "Присоединение", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Полное", + "Full", "Присоединение", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Сгруппировать", + "Group", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Имеющие", + "Having", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Упорядочить", + "Order", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Итоги", + "Totals", "Неопределен", , , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Год", + "Year", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Квартал", + "Quarter", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Месяц", + "Month", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДеньГода", + "DayOfYear", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "День", + "Day", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Неделя", + "Week", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДеньНедели", + "Weekday", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Час", + "Hour", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Минута", + "Minute", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Секунда", + "Second", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "НачалоПериода", + "BeginOfPeriod", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "КонецПериода", + "EndOfPeriod", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ДобавитьКДате", + "DateAdd", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "РазностьДат", + "DateDiff", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Сумма", + "Sum", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Минимум", + "Min", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Максимум", + "Max", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Среднее", + "Avg", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Количество", + "Count", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "Представление", + "Presentation", "Функция", Ложь, , Истина); // @Non-NLS + ДобавитьСловоЯзыка(Слова, "ПредставлениеСсылки", + "RefPresentation", "Функция", Ложь, , Истина); // @Non-NLS + + Возврат Новый ФиксированноеСоответствие(Слова); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - слово на русском и английском языках. +// * Значение - см. СвойстваСлова +// +Функция ОперацииЯзыка() + + ОперацииЯзыка = Новый Соответствие; + + ДобавитьСловоЯзыка(ОперацииЯзыка, "=", "=", "Соединитель", , 4); + ДобавитьСловоЯзыка(ОперацииЯзыка, "<>", "<>", "Соединитель", , 4); + + // Неподдерживаемые, зарезервированные операции. + ДобавитьСловоЯзыка(ОперацииЯзыка, "<", "<", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "<=", "<=", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, ">", ">", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, ">=", ">=", "Соединитель", , 4, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "+", "+", "Соединитель", , 1, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "-", "-", "Соединитель", , 1, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "*", "*", "Соединитель", , 6, Истина); + ДобавитьСловоЯзыка(ОперацииЯзыка, "/", "/", "Соединитель", , 6, Истина); + + Возврат Новый ФиксированноеСоответствие(ОперацииЯзыка); + +КонецФункции + +// Для функций СловаЯзыка и ОперацииЯзыка. +Процедура ДобавитьСловоЯзыка(Слова, ЯзыкРусский, ЯзыкАнглийский, ТипСлова, + ВерхнийРегистр = Истина, Приоритет = 0, ЭтоРезерв = Ложь) + + СвойстваСлова = СвойстваСлова(ЯзыкРусский, + ЯзыкАнглийский, ТипСлова, ВерхнийРегистр, Приоритет, ЭтоРезерв); + + Слова.Вставить(ВРег(ЯзыкРусский), СвойстваСлова); + Слова.Вставить(ВРег(ЯзыкАнглийский), СвойстваСлова); + +КонецПроцедуры + +// Для процедуры ДобавитьСловоЯзыка. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * Идентификатор - Строка - слово языка на языке конфигурации (русском или английском). +// * ЯзыкРусский - Строка - слово языка на русском языке. +// * ЯзыкАнглийский - Строка - слово языка на английском языке. +// * Тип - Строка - имя типа слова. +// * ВерхнийРегистр - Булево +// * Приоритет - Число +// * ЭтоРезерв - Булево +// +Функция СвойстваСлова(ЯзыкРусский, ЯзыкАнглийский, ТипСлова, ВерхнийРегистр, Приоритет, ЭтоРезерв) + + СвойстваСлова = Новый Структура; + СвойстваСлова.Вставить("Идентификатор", ?(КодСимвола(Лев(ТипСлова, 1)) > 122, ЯзыкРусский, ЯзыкАнглийский)); + СвойстваСлова.Вставить("ЯзыкРусский", ЯзыкРусский); + СвойстваСлова.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + СвойстваСлова.Вставить("Тип", ТипСлова); + СвойстваСлова.Вставить("ВерхнийРегистр", ВерхнийРегистр); + СвойстваСлова.Вставить("Приоритет", Приоритет); + СвойстваСлова.Вставить("ЭтоРезерв", ЭтоРезерв); + + Возврат Новый ФиксированнаяСтруктура(СвойстваСлова); + +КонецФункции + +// Для функции СинтаксисЯзыка. +// +// Возвращаемое значение: +// Структура: +// * ПоИменам - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя типа таблиц на русском и на английском языках. +// ** Значение - см. СвойстваТипаТаблиц +// * ПоКоллекциям - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя коллекции на языке конфигурации (русском или английском). +// ** Значение - см. СвойстваТипаТаблиц +// +Функция ТипыТаблиц() + + ТипыТаблиц = Новый Структура; + ТипыТаблиц.Вставить("ПоИменам", Новый Соответствие); + ТипыТаблиц.Вставить("ПоКоллекциям", Новый Соответствие); + + // Установка имен типов таблиц. + ДобавитьТипТаблиц(ТипыТаблиц, "ПланОбмена", + "ExchangePlan", "ПланыОбмена"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "КритерийОтбора", + "FilterCriterion", "КритерииОтбора"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Константы", + "Constants", ""); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Константа", + "Constant", "Константы"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Справочник", + "Catalog", "Справочники"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Последовательность", + "Sequence", "Последовательности"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Документ", + "Document", "Документы"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ЖурналДокументов", + "DocumentJournal", "ЖурналыДокументов"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Перечисление", + "Enum", "Перечисления"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ПланВидовХарактеристик", + "ChartOfCharacteristicTypes", "ПланыВидовХарактеристик"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ПланСчетов", + "ChartOfAccounts", "ПланыСчетов"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "ПланВидовРасчета", + "ChartOfCalculationTypes", "ПланыВидовРасчета"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрСведений", + "InformationRegister", "РегистрыСведений"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрНакопления", + "AccumulationRegister", "РегистрыНакопления"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрБухгалтерии", + "AccountingRegister", "РегистрыБухгалтерии"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "РегистрРасчета", + "CalculationRegister", "РегистрыРасчета"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "БизнесПроцесс", + "BusinessProcess", "БизнесПроцессы"); // @Non-NLS + ДобавитьТипТаблиц(ТипыТаблиц, "Задача", + "Task", "Задачи"); // @Non-NLS + + // Установка основных свойств основных типов таблиц. + ИменаТиповТаблиц = "ПланОбмена,Справочник,Документ,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета,БизнесПроцесс,Задача"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЭтоСсылочныйТип", Истина); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьОграничение", Истина); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Разрешены"); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Использование", "Разрешено"); + + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Разрешены"); + + ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ТабличныеЧасти", "Разрешены"); + + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ВерсияДанных", + "DataVersion", "Запрещено"); // @Non-NLS + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Представление", + "Presentation", "Запрещено"); // @Non-NLS + + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Изменения", + "Changes", "Запрещено"); // @Non-NLS + + // Установка основных свойств регистров. + ИменаТиповТаблиц = "РегистрСведений,РегистрРасчета"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Ресурсы", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Разрешены"); + + ИменаТиповТаблиц = "РегистрНакопления,РегистрБухгалтерии"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ОбщиеРеквизиты", "Недопустимы"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Ресурсы", "Недопустимы"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Реквизиты", "Недопустимы"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "СтандартныеРеквизиты", "Недопустимы"); + + ИменаТиповТаблиц = "РегистрСведений,РегистрНакопления,РегистрБухгалтерии,РегистрРасчета"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьОграничение", Истина); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Измерения", "Разрешены"); + + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Изменения", + "Changes", "Запрещено"); // @Non-NLS + + // Установка некоторых из указанных ранее свойств для остальных типов таблиц. + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "Последовательность", "ЕстьОграничение", Истина); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Последовательность", "Измерения", "Разрешены"); + + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "ОбщиеРеквизиты", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "СтандартныеРеквизиты", "Разрешены"); + + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "Перечисление", "ЭтоСсылочныйТип", Истина); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Перечисление", "СтандартныеРеквизиты", "Разрешены"); + + ИменаТиповТаблиц = "Константа,РегистрСведений"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "Использование", "Разрешено"); + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "КритерийОтбора", "Использование", "Недопустимо"); + + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "Константа", "Изменения", + "Changes", + "Запрещено"); // @Non-NLS-2 + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "РегистрСведений", "СрезПервых", + "SliceFirst", + "Недопустимо"); // @Non-NLS-2 + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "РегистрСведений", "СрезПоследних", + "SliceLast", + "Недопустимо"); // @Non-NLS-2 + ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, "БизнесПроцесс", "Точки", + "Points", + "Запрещено"); // @Non-NLS-2 + + // Установка специализированных свойств. + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, "ПланСчетов", "ПризнакиУчетаСубконто", "Разрешены"); + + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "Графы", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "ПланСчетов", "ПризнакиУчета", "Разрешены"); + ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, "Задача", "РеквизитыАдресации", "Разрешены"); + + ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, "ПланСчетов", "СтандартныеТабличныеЧасти", "Разрешены"); + ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, "ПланВидовРасчета", "СтандартныеТабличныеЧасти", "Разрешены"); + + ИменаТиповТаблиц = "Справочник,Перечисление,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета"; + УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ЕстьПредопределенные", Истина); + + // Уточнение стандартных полей типов таблиц. + ИменаТиповТаблиц = "Документ,РегистрСведений,РегистрНакопления,РегистрБухгалтерии"; + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "МоментВремени", + "PointInTime", "Недопустимо"); // @Non-NLS + + ИменаТиповТаблиц = "Справочник,ПланВидовХарактеристик,ПланСчетов,ПланВидовРасчета"; + ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, "ИмяПредопределенныхДанных", + "PredefinedDataName", "Запрещено"); // @Non-NLS + + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Константа", "Значение", + "Value", + "Разрешено"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Последовательность", "Регистратор", + "Recorder", + "Разрешено"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Последовательность", "Период", + "Period", + "Разрешено"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "ЖурналДокументов", "Тип", + "Type", + "Недопустимо"); // @Non-NLS-2 + ДобавитьПолеТипаТаблиц(ТипыТаблиц, "Перечисление", "Порядок", + "Order", + "Запрещено"); // @Non-NLS-2 + + Возврат ТипыТаблиц; + +КонецФункции + +// Для функции ТипыТаблиц. +Процедура ДобавитьТипТаблиц(ТипыТаблиц, ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции) + + СвойстваТипаТаблиц = СвойстваТипаТаблиц(ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции); + + ТипыТаблиц.ПоИменам.Вставить(ВРег(ЯзыкРусский), СвойстваТипаТаблиц); + ТипыТаблиц.ПоИменам.Вставить(ВРег(ЯзыкАнглийский), СвойстваТипаТаблиц); + + Если ЗначениеЗаполнено(ИмяКоллекции) Тогда + ТипыТаблиц.ПоКоллекциям.Вставить(ИмяКоллекции, СвойстваТипаТаблиц); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьСловоЯзыка. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура: +// * ИмяКоллекции - Строка - имя коллекции на языке конфигурации (русском или английском). +// * ЯзыкРусский - Строка - имя типа таблиц на русском языке. +// * ЯзыкАнглийский - Строка - имя типа таблиц на английском языке. +// * ЭтоСсылочныйТип - Булево +// * ЕстьОграничение - Булево +// * ЕстьПредопределенные - Булево +// * КоллекцииПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя коллекции полей на языке конфигурации (русском или английском). +// ** Значение - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// +// * КоллекцииТабличныхЧастей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя коллекции табличных частей на языке конфигурации (русском или английском). +// ** Значение - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// +// * ОбщиеРеквизиты - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Отсутствуют" - не существуют у объекта метаданных. +// +// * ПризнакиУчетаСубконто - Строка - +// "Разрешены" - можно использовать без ограничений. +// "Недопустимы" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Отсутствуют" - не существуют у объекта метаданных. +// +// * УточнениеПолей - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя поля таблиц на русском и на английском языках. +// ** Значение - см. УточнениеПоля +// +// * УточнениеТаблиц - Соответствие из КлючИЗначение: +// ** Ключ - Строка - имя расширения таблиц на русском и на английском языках. +// ** Значение - см. УточнениеТаблиц +// +// * Использование - Строка - +// "Разрешено" - можно использовать без ограничений. +// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Запрещено" - запрещено присоединять, как дополнительную таблицу в ограничении доступа БСП. +// +Функция СвойстваТипаТаблиц(ЯзыкРусский, ЯзыкАнглийский, ИмяКоллекции) + + СвойстваТипаТаблиц = Новый Структура; + СвойстваТипаТаблиц.Вставить("ИмяКоллекции", ИмяКоллекции); + СвойстваТипаТаблиц.Вставить("ЯзыкРусский", ЯзыкРусский); + СвойстваТипаТаблиц.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + СвойстваТипаТаблиц.Вставить("ЭтоСсылочныйТип", Ложь); + СвойстваТипаТаблиц.Вставить("ЕстьОграничение", Ложь); + СвойстваТипаТаблиц.Вставить("ЕстьПредопределенные", Ложь); + СвойстваТипаТаблиц.Вставить("КоллекцииПолей", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("КоллекцииТабличныхЧастей", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("ОбщиеРеквизиты", "Отсутствуют"); + СвойстваТипаТаблиц.Вставить("ПризнакиУчетаСубконто", "Отсутствуют"); + СвойстваТипаТаблиц.Вставить("УточнениеПолей", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("УточнениеТаблиц", Новый Соответствие); + СвойстваТипаТаблиц.Вставить("Использование", "Запрещено"); + + Возврат СвойстваТипаТаблиц; + +КонецФункции + +// Для функции ТипыТаблиц. +Процедура УстановитьСвойствоТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, Свойство, Значение) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + СвойстваТипаТаблиц[Свойство] = Значение; + КонецЦикла; + +КонецПроцедуры + +// Для функции ТипыТаблиц. +Процедура ДобавитьКоллекциюПолейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ИмяКоллекции, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + СвойстваТипаТаблиц.КоллекцииПолей.Вставить(ИмяКоллекции, Использование); + КонецЦикла; + +КонецПроцедуры + +// Для функции ТипыТаблиц. +Процедура ДобавитьКоллекциюТабличныхЧастейТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ИмяКоллекции, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + СвойстваТипаТаблиц.КоллекцииТабличныхЧастей.Вставить(ИмяКоллекции, Использование); + КонецЦикла; + +КонецПроцедуры + +// Для функции ТипыТаблиц. +Процедура ДобавитьПолеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ЯзыкРусский, ЯзыкАнглийский, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + УточнениеПоля = УточнениеПоля(ЯзыкРусский, ЯзыкАнглийский, Использование); + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + + СвойстваТипаТаблиц.УточнениеПолей.Вставить(ВРег(ЯзыкРусский), УточнениеПоля); + СвойстваТипаТаблиц.УточнениеПолей.Вставить(ВРег(ЯзыкАнглийский), УточнениеПоля); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьПолеТипаТаблиц. +// +// Возвращаемое значение: +// Структура: +// * ЯзыкРусский - Строка - имя поля таблиц на русском языке. +// * ЯзыкАнглийский - Строка - имя поля таблиц на английском языке. +// * Использование - Строка - +// "Разрешено" - можно использовать без ограничений. +// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Запрещено" - запрещено использовать в ограничении доступа БСП. +// +Функция УточнениеПоля(ЯзыкРусский, ЯзыкАнглийский, Использование) + + УточнениеПоля = Новый Структура; + УточнениеПоля.Вставить("ЯзыкРусский", ЯзыкРусский); + УточнениеПоля.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + УточнениеПоля.Вставить("Использование", Использование); + + Возврат УточнениеПоля; + +КонецФункции + +// Для функции ТипыТаблиц. +Процедура ДобавитьРасширениеТипаТаблиц(ТипыТаблиц, ИменаТиповТаблиц, ЯзыкРусский, ЯзыкАнглийский, Использование) + + Для Каждого ИмяТипаТаблицы Из СтрРазделить(ИменаТиповТаблиц, ",", Ложь) Цикл + УточнениеТаблиц = УточнениеТаблиц(ЯзыкРусский, ЯзыкАнглийский, Использование); + СвойстваТипаТаблиц = ТипыТаблиц.ПоИменам.Получить(ВРег(ИмяТипаТаблицы)); + + СвойстваТипаТаблиц.УточнениеТаблиц.Вставить(ВРег(ЯзыкРусский), УточнениеТаблиц); + СвойстваТипаТаблиц.УточнениеТаблиц.Вставить(ВРег(ЯзыкАнглийский), УточнениеТаблиц); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ДобавитьПолеТипаТаблиц. +// +// Возвращаемое значение: +// Структура: +// * ЯзыкРусский - Строка - имя расширения таблиц на русском языке. +// * ЯзыкАнглийский - Строка - имя расширения таблиц на английском языке. +// * Использование - Строка - +// "Разрешено" - можно использовать без ограничений. +// "Недопустимо" - нельзя использовать в ограничении доступа платформы 1С:Предприятия. +// "Запрещено" - запрещено использовать в ограничении доступа БСП. +// +Функция УточнениеТаблиц(ЯзыкРусский, ЯзыкАнглийский, Использование) + + УточнениеТаблиц = Новый Структура; + УточнениеТаблиц.Вставить("ЯзыкРусский", ЯзыкРусский); + УточнениеТаблиц.Вставить("ЯзыкАнглийский", ЯзыкАнглийский); + УточнениеТаблиц.Вставить("Использование", Использование); + + Возврат УточнениеТаблиц; + +КонецФункции + +#КонецОбласти + +#Область СинтаксическийАнализ + +// Для функции РазобранноеОграничение. +// +// Параметры: +// ВнутренниеДанные - см. НовыеВнутренниеДанные +// +// Возвращаемое значение: +// Структура: +// * ДополнительныеТаблицы - Массив из см. НовоеОписаниеСоединения +// * ПсевдонимОсновнойТаблицы - Строка +// * ОграничениеЧтения - Структура +// * ОграничениеИзменения - Структура +// +Функция ЧастиОграничения(ВнутренниеДанные) + + ЧастиОграничения = Новый Структура; + ЧастиОграничения.Вставить("ДополнительныеТаблицы", Новый Массив); + ЧастиОграничения.Вставить("ПсевдонимОсновнойТаблицы", ""); + ЧастиОграничения.Вставить("ОграничениеЧтения", Новый Структура); + ЧастиОграничения.Вставить("ОграничениеИзменения", Новый Структура); + + ТаблицаНаборовСимволов = ВнутренниеДанные.ТаблицаНаборовСимволов; + + Если ТаблицаНаборовСимволов.Количество() = 0 Тогда + Возврат ЧастиОграничения; + КонецЕсли; + + ТаблицаНаборовСимволов.Колонки.Добавить("Строки", Новый ОписаниеТипов("Массив")); + ТаблицаНаборовСимволов.Колонки.Добавить("КонечнаяСтрока"); + + // Разделение ограничения на основные части. + Строки = ТаблицаНаборовСимволов.НайтиСтроки(Новый Структура("Символы, Вид", ";", "Разделитель")); + + ИндексыСтрокРазделителя = Новый Массив; + Для Каждого Строка Из Строки Цикл + ИндексыСтрокРазделителя.Добавить(ТаблицаНаборовСимволов.Индекс(Строка)); + КонецЦикла; + ИндексыСтрокРазделителя.Добавить(ТаблицаНаборовСимволов.Количество() - 1); + + СвойстваЧастей = Новый Массив; // Массив из см. НовыеСвойстваЧасти + ИндексСтроки = 0; + Для Каждого ИндексСтрокиРазделителя Из ИндексыСтрокРазделителя Цикл + СтрокиЧасти = Новый Массив; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + Пока ИндексСтроки < ИндексСтрокиРазделителя Цикл + СтрокаЧасти = ТаблицаНаборовСимволов[ИндексСтроки]; + Если СтрокаЧасти.Вид <> "НедопустимыйСимвол" Тогда + СтрокиЧасти.Добавить(СтрокаЧасти); + КонецЕсли; + ИндексСтроки = ИндексСтроки + 1; + КонецЦикла; + СтрокаРазделителя = ТаблицаНаборовСимволов[ИндексСтрокиРазделителя]; + Если СтрокиЧасти.Количество() = 0 Тогда + СтрокиЧасти.Добавить(СтрокаРазделителя); + КонецЕсли; + СвойстваЧасти = НовыеСвойстваЧасти(); + СвойстваЧасти.Вставить("Строки", СтрокиЧасти); + СвойстваЧасти.Вставить("СтрокаРазделителя", СтрокаРазделителя); + СвойстваЧастей.Добавить(СвойстваЧасти); + ПерваяСтрокаЧасти = СтрокиЧасти[0]; + Если ПерваяСтрокаЧасти.Вид = "КлючевоеСлово" + И ПерваяСтрокаЧасти.Тип = "Начало" Тогда + + СвойстваЧасти.Вставить("Имя", ПерваяСтрокаЧасти.Уточнение); + СвойстваЧасти.Вставить("Представление", ПерваяСтрокаЧасти.Символы); + + РазобратьЧастьОграничения(СвойстваЧасти, ВнутренниеДанные); + Иначе + СвойстваЧасти.Вставить("Имя", ""); + СвойстваЧасти.Вставить("Представление", ""); + КонецЕсли; + ИндексСтроки = ИндексСтрокиРазделителя + 1; + КонецЦикла; + + ДобавитьПсевдонимыПоУмолчанию(ВнутренниеДанные); + + // Анализ части 1. + СвойстваЧасти1 = СвойстваЧастей[0]; + + Если СвойстваЧасти1.Имя = "" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти1, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале первой части текста ограничения нет ни одного из ключевых слов + |""%1"", ""%2"", ""%3""'"), + "РазрешитьЧтениеИзменение,РазрешитьЧтение,ПрисоединитьДополнительныеТаблицы")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧасти1.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти1, + НСтр("ru = 'В начале первой части текста ограничения найдено недопустимое ключевое слово'")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧастей.Количество() = 1 + И ( СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы" + Или СвойстваЧасти1.Имя = "РазрешитьЧтение" ) Тогда + + УстановитьОшибкуНачалаЧасти(ТаблицаНаборовСимволов, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Текст ограничения не может быть только из одной части + |с ключевым словом ""%1""'"), СвойстваЧасти1.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти1); + + Если СвойстваЧастей.Количество() < 2 Тогда + Возврат ЧастиОграничения; + КонецЕсли; + + // Анализ части 2. + СвойстваЧасти2 = СвойстваЧастей[1]; + + Если СвойстваЧасти1.Имя = "РазрешитьЧтениеИзменение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти1.СтрокаРазделителя, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Второй части текста ограничения не должно быть, когда + |в первой части указано ключевое слово ""%1""'"), СвойстваЧасти1.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + Если СвойстваЧасти2.Имя = "" Тогда + Если СвойстваЧасти1.Имя = "РазрешитьЧтение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале второй части текста ограничения нет + |ключевого слова ""%1""'"), + "РазрешитьИзменениеЕслиРазрешеноЧтение")); + Иначе // СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы". + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале второй части текста ограничения нет ни одного из ключевых слов + |""%1"", ""%2""'"), + "РазрешитьЧтениеИзменение,РазрешитьЧтение")); + КонецЕсли; + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧасти1.Имя = "РазрешитьЧтение" + И СвойстваЧасти2.Имя <> "РазрешитьИзменениеЕслиРазрешеноЧтение" + Или СвойстваЧасти1.Имя = "ПрисоединитьДополнительныеТаблицы" + И СвойстваЧасти2.Имя <> "РазрешитьЧтениеИзменение" + И СвойстваЧасти2.Имя <> "РазрешитьЧтение" Тогда + + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2, + НСтр("ru = 'В начале второй части текста ограничения найдено недопустимое ключевое слово'")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧастей.Количество() = 2 + И СвойстваЧасти2.Имя = "РазрешитьЧтение" Тогда + + УстановитьОшибкуНачалаЧасти(ТаблицаНаборовСимволов, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Текст ограничения не может быть только из двух частей, когда + |во второй части указано ключевое слово ""%1""'"), СвойстваЧасти2.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти2); + + Если СвойстваЧастей.Количество() < 3 Тогда + Возврат ЧастиОграничения; + КонецЕсли; + + // Анализ части 3. + СвойстваЧасти3 = СвойстваЧастей[2]; + + Если СвойстваЧасти2.Имя = "РазрешитьЧтениеИзменение" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти2.СтрокаРазделителя, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Третьей части текста ограничения не должно быть, когда + |во второй части указано ключевое слово ""%1""'"), СвойстваЧасти2.Представление)); + Возврат ЧастиОграничения; + КонецЕсли; + + Если СвойстваЧасти3.Имя = "" Тогда + УстановитьОшибкуНачалаЧасти(СвойстваЧасти3, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'В начале третьей части текста ограничения нет + |ключевого слово ""%1""'"), + "РазрешитьИзменениеЕслиРазрешеноЧтение")); + Возврат ЧастиОграничения; + + ИначеЕсли СвойстваЧасти2.Имя = "РазрешитьЧтение" + И СвойстваЧасти3.Имя <> "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда + + УстановитьОшибкуНачалаЧасти(СвойстваЧасти3, + НСтр("ru = 'В начале третьей части текста ограничения найдено недопустимое ключевое слово'")); + Возврат ЧастиОграничения; + КонецЕсли; + + УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти3); + + Возврат ЧастиОграничения; + +КонецФункции + +// Процедура: +// Родитель - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// - Структура +// Строка - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// Контекст - Структура: +// * Таблица - см. ТаблицаНаборовСимволов +// +Процедура СтрокаДобавить(Родитель, Строка, Контекст) + + Если ТипЗнч(Строка) = Тип("СтрокаТаблицыЗначений") Тогда + Родитель.Строки.Добавить(Контекст.ТаблицаНаборовСимволов.Индекс(Строка)); + Иначе + Родитель.Строки.Добавить(Строка); + КонецЕсли; + +КонецПроцедуры + +// Параметры: +// ОписаниеСтроки - Число - индекс таблицы значений. +// - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// - Структура - см. ДополнительнаяСтрока +// Контекст - Структура: +// * Таблица - см. ТаблицаНаборовСимволов +// +// Возвращаемое значение: +// см. ДополнительнаяСтрока +// +Функция СтрокаТаблицы(ОписаниеСтроки, Контекст) + + Если ТипЗнч(ОписаниеСтроки) = Тип("Число") Тогда + Строка = Контекст.ТаблицаНаборовСимволов[ОписаниеСтроки]; + Иначе + Строка = ОписаниеСтроки; + КонецЕсли; + + Возврат Строка; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// * СтрокаРазделителя - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// * Имя - Строка +// * Представление - Строка +// +Функция НовыеСвойстваЧасти() + + Возврат Новый Структура; + +КонецФункции + +// Возвращаемое значение: +// Структура: +// * Таблица - Строка +// * Псевдоним - Строка +// * УсловиеСоединения - см. ОписаниеУзла +// * ПсевдонимыТребуемыхТаблиц - Массив из Строка +// * ПоляУсловияСоединения - Массив из см. ПараПолейУсловияСоединения +// * ТекстУсловияСоединения - Строка +// +Функция НовоеОписаниеСоединения() + + Возврат Новый Структура; + +КонецФункции + + +// Возвращаемое значение: +// Структура: +// * Источник - СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов +// +// * Узел - Строка - одна из строк "Поле", "Значение", "Константа", +// "И", "Или", "Не", "=", "<>", "В", "ЕстьNull", "Тип", "ТипЗначения", "Выбор", +// "ЗначениеРазрешено", "ЭтоАвторизованныйПользователь", +// "ЧтениеОбъектаРазрешено", "ИзменениеОбъектаРазрешено", +// "ЧтениеСпискаРазрешено", "ИзменениеСпискаРазрешено", +// "ДляВсехСтрок", "ДляОднойИзСтрок", +// "ПравоДоступа", "РольДоступна". +// +// Свойства узла Поле. +// * Имя - Строка - имя поля, например, "Организация" или "ОсновнаяОрганизация". +// * Таблица - Строка - имя таблицы этого поля (или пустая строка для основной таблицы). +// * Псевдоним - Строка - имя псевдонима присоединяемой таблицы этого поля (или пустая строка для основной таблицы), +// например, "РегистрСведенийНастройки" для поля "ОсновнаяОрганизация". +// * Выразить - Строка - имя таблицы (если используется), например, для описания поля в виде: +// "ВЫРАЗИТЬ(ВЫРАЗИТЬ(Владелец КАК Справочник.Файлы).ВладелецФайла КАК Справочник.Организации).Ссылка". +// * Вложение - Структура - узел Поле, содержащий вложенное действие ВЫРАЗИТЬ (с или без ЕстьNull). +// - Неопределено - нет вложенного поля. +// * ЕстьNull - Структура - узел Значение Или Константа, например, для описания выражения вида +// "ЕстьNULL(Владелец, Значение(Справочник.Файлы.ПустаяСсылка))". +// - Неопределено - если ЕстьNull не используется (в том числе, когда свойство Вложение заполнено). +// * ИмяИсточник - СтрокаТаблицыЗначений +// - Неопределено +// * ВыразитьИсточник - СтрокаТаблицыЗначений +// - Неопределено +// * ЕстьNullИсточник - СтрокаТаблицыЗначений +// - Неопределено +// +// Свойства узлов Значение и Тип. +// * Имя - Строка - имя значения, например, "Справочник.Организации.Основная", +// "Справочник.Организации.ПустаяСсылка", +// имя таблицы, например, "Справочник.Организации". +// +// Свойства узла Константа. +// * Значение - Булево +// - Число +// - Строка +// - Неопределено - Ложь, Истина, произвольное +// целое число до 16 разрядов или произвольная строка до 150 символов. +// +// Свойства узлов И, Или (любой узел, кроме Значение и Константа). +// * Аргументы - Массив из см. ОписаниеУзла +// +// Свойства узла Не (любой узел, кроме Значение и Константа). +// * Аргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узлов =, <> (ПервыйАргумент - узел Поле, +// ВторойАргумент - узел Значение, Константа, а узел Поле только для условия соединения). +// * ПервыйАргумент - см. ОписаниеУзла +// * ВторойАргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла В (Искомое - узел Поле, Значения - узлы Значение и/или Константа). +// * Искомое - см. ОписаниеУзла +// * Значения - Массив из см. ОписаниеУзла +// +// Свойства узла ЕстьNull (узел Поле - выражение вида "<Поле> ЕСТЬ NULL"). +// * Аргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла ТипЗначения (узел Поле). +// * Аргумент - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узла Выбор +// В свойстве Выбор +// узел Поле +// Неопределено - условия содержат выражение, а не узел Значение +// В свойстве Когда +// Условие - узел Значение, если свойство Выбор указано, в противном случае +// узлы И, Или, Не, =, <>, В (распространяется на вложенное содержимое) +// Значение - узел, кроме Выбор +// В свойстве Иначе +// узел, кроме ВЫБОР и Значение (Поле и Константа может быть только типа Булево). +// * Выбор - см. ОписаниеУзла +// * Когда - Массив из Структура: +// ** Условие - см. ОписаниеУзла +// ** Значение - см. ОписаниеУзла +// * Иначе - см. ОписаниеУзла +// +// * Имя - Строка - заглушка к предыдущей строке (для определения типа в EDT) +// +// Свойства узлов ЗначениеРазрешено, ЭтоАвторизованныйПользователь, +// ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, +// ЧтениеСпискаРазрешено, ИзменениеСпискаРазрешено. +// В свойстве Поле - узел Поле. +// * Поле - см. ОписаниеУзла +// * Типы - Массив из Строка - полное имя таблицы +// * ПроверятьТипыКромеУказанных - Булево - если Истина, то все типы свойства Поле, +// кроме указанных в свойстве Типы. +// * УточненияСравнения - Соответствие из КлючИЗначение: +// ** Ключ - Строка - уточняемое значение "Неопределено", "Null", "ПустаяСсылка", +// <полное имя таблицы>, "Число", "Строка", "Дата", "Булево". +// ** Значение - Строка - результат "Ложь", "Истина". +// +// Свойства узлов ДляВсехСтрок, ДляОднойИзСтрок (любой узел). +// * Аргумент - см. ОписаниеУзла. +// +Функция ОписаниеУзла() + + Возврат Новый Структура; + +КонецФункции + +// Для функции ЧастиОграничения. +Процедура УстановитьЧастьОграничения(ЧастиОграничения, СвойстваЧасти) + + Если СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" + Или СвойстваЧасти.Имя = "РазрешитьЧтение" Тогда + + ИмяСвойства = "ОграничениеЧтения"; + + ИначеЕсли СвойстваЧасти.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение" Тогда + + ИмяСвойства = "ОграничениеИзменения"; + + Иначе // ПрисоединитьДополнительныеТаблицы. + + ИмяСвойства = "ДополнительныеТаблицы"; + ЧастиОграничения.ПсевдонимОсновнойТаблицы = СвойстваЧасти.ПсевдонимОсновнойТаблицы; + КонецЕсли; + + ЧастиОграничения[ИмяСвойства] = СвойстваЧасти.Состав; + +КонецПроцедуры + +// Для функции ЧастиОграничения, процедур РазобратьДополнительныеТаблицы, РазобратьУсловиеОграничения. +// Параметры: +// СвойстваЧасти - см. НовыеСвойстваЧасти +// ТекстОшибки - Строка +// +Процедура УстановитьОшибкуНачалаЧасти(СвойстваЧасти, ТекстОшибки) + + Если ТипЗнч(СвойстваЧасти) = Тип("ТаблицаЗначений") Тогда + СтрокаСОшибкой = СвойстваЧасти[СвойстваЧасти.Количество() - 1]; + + ИначеЕсли ТипЗнч(СвойстваЧасти) = Тип("СтрокаТаблицыЗначений") Тогда + СтрокаСОшибкой = СвойстваЧасти; + Иначе + СтрокаСОшибкой = СвойстваЧасти.Строки[0]; + КонецЕсли; + + СтрокаСОшибкой.ТекстОшибки = ТекстОшибки; + + // Требуется описание вариантов первых ключевых слов частей. + СтрокаСОшибкой.ПозицияОшибки = -1; + +КонецПроцедуры + +// Для процедуры РазобратьСоединение. +// Параметры: +// Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// ИндексСтроки - Число +// ТекстОшибки - Строка +// +Процедура УстановитьОшибкуВнутриЧасти(Строки, ИндексСтроки, ТекстОшибки) + + Если ИндексСтроки < Строки.Количество() Тогда + СтрокаСОшибкой = Строки[ИндексСтроки]; + Иначе + СтрокаСОшибкой = Строки[ИндексСтроки - 1]; + // Ошибка в конце слова. + СтрокаСОшибкой.ПозицияОшибки = СтрДлина(СтрокаСОшибкой.Символы); + КонецЕсли; + + СтрокаСОшибкой.ТекстОшибки = ТекстОшибки; + +КонецПроцедуры + +// Для функции ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. +Процедура УстановитьОшибкуВСтроке(Строка, ТекстОшибки, ВКонцеСлова = Ложь, НомерСлова = 1) + + Если ЗначениеЗаполнено(Строка.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если ВКонцеСлова Тогда + Строка.ПозицияОшибки = СтрДлина(Строка.Символы); + + ИначеЕсли НомерСлова > 1 Тогда + СоставИмени = СтрРазделить(Строка.Символы, "."); + Если СоставИмени.Количество() > 1 Тогда + Строка.ПозицияОшибки = СтрДлина(СоставИмени[0]) + 1; + КонецЕсли; + КонецЕсли; + + Строка.ТекстОшибки = ТекстОшибки; + +КонецПроцедуры + +// Для функции ЧастиОграничения. +Процедура РазобратьЧастьОграничения(СвойстваЧасти, ВнутренниеДанные) + + Если СвойстваЧасти.Имя = "ПрисоединитьДополнительныеТаблицы" Тогда + СвойстваЧасти.Вставить("Состав", Новый Массив); + СвойстваЧасти.Вставить("ПсевдонимОсновнойТаблицы", ""); + РазобратьДополнительныеТаблицы(СвойстваЧасти, ВнутренниеДанные); + Иначе + СвойстваЧасти.Вставить("Состав", ОписаниеУзла()); + РазобратьУсловиеОграничения(СвойстваЧасти, ВнутренниеДанные); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьЧастьОграничения. +Процедура РазобратьДополнительныеТаблицы(СвойстваЧасти, ВнутренниеДанные) + + СтрокиЧасти = СвойстваЧасти.Строки; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + + Если СтрокиЧасти.Количество() < 2 + Или СтрокиЧасти[1].Вид <> "КлючевоеСлово" + Или СтрокиЧасти[1].Уточнение <> "ЭтотСписок" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 3, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[1]), + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет + |ключевого слово ""%2""'"), + СвойстваЧасти.Представление, + КлючевоеСловоСУчетомЯзыка("ЭтотСписок", ВнутренниеДанные))); + Возврат; + КонецЕсли; + + ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти, СтрокиЧасти[1]); + + Если СтрокиЧасти.Количество() < 3 + Или СтрокиЧасти[2].Вид <> "КлючевоеСлово" + Или СтрокиЧасти[2].Уточнение <> "Как" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 3, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[2]), + ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%1"" нет ключевого слово ""%2""'"), + "ЭтотСписок,Как")); + Возврат; + КонецЕсли; + + Если СтрокиЧасти.Количество() < 4 + Или СтрокиЧасти[3].Вид <> "Имя" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 4, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[3]), + ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%1"" нет псевдонима'"), + "Как")); + Возврат; + КонецЕсли; + + УстановитьПсевдоним(СтрокиЧасти[3], СвойстваЧасти.ПсевдонимОсновнойТаблицы, ВнутренниеДанные); + + // Разделение описания на группы левых соединений. + Соединения = Новый Массив; + ТекущееСоединение = Новый Массив; // Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + + Для Индекс = 4 По СтрокиЧасти.Количество()-1 Цикл + СтрокаЧасти = СтрокиЧасти[Индекс]; + + Если СтрокаЧасти.Вид = "КлючевоеСлово" + И СтрокаЧасти.Уточнение = "Левое" Тогда + + Если ТекущееСоединение.Количество() > 0 Тогда + Соединения.Добавить(ТекущееСоединение); + КонецЕсли; + ТекущееСоединение = Новый Массив; + ТекущееСоединение.Добавить(СтрокаЧасти); + + Если Индекс + 1 < СтрокиЧасти.Количество() + И СтрокиЧасти[Индекс + 1].Вид = "КлючевоеСлово" + И СтрокиЧасти[Индекс + 1].Уточнение = "Соединение" Тогда + + Индекс = Индекс + 1; + ТекущееСоединение.Добавить(СтрокиЧасти[Индекс]); + КонецЕсли; + + Продолжить; + КонецЕсли; + ТекущееСоединение.Добавить(СтрокаЧасти); + КонецЦикла; + + Если ТекущееСоединение.Количество() > 0 + Или Соединения.Количество() = 0 Тогда + + Соединения.Добавить(ТекущееСоединение); + КонецЕсли; + + ВнутренниеДанные.Вставить("ДоступныеПсевдонимы", + Новый Соответствие(Новый ФиксированноеСоответствие(ВнутренниеДанные.Псевдонимы))); + + Для Каждого Соединение Из Соединения Цикл + // Условие разбирается универсально (по максимуму возможностей) + // после чего устанавливаются ошибки на запрещенные возможности. + РазобратьСоединение(Соединение, СвойстваЧасти, ВнутренниеДанные); + КонецЦикла; + + // Продолжение разбора после заполнения псевдонимов всех дополнительных таблиц. + Для Каждого ОписаниеСоединения Из СвойстваЧасти.Состав Цикл + ВнутренниеДанные.ДоступныеПсевдонимы.Вставить(ВРег(ОписаниеСоединения.Псевдоним), Истина); + // Допустимы только простые условия: + // Поле1 = Поле2 [И Поле3 = Поле4] [И Поле5 = Константа]. + РазобратьПоляУсловияСоединенияИОтметитьЗапреты(ОписаниеСоединения, ВнутренниеДанные); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьДополнительныеТаблицы. +// +// Параметры: +// Соединение - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьСоединение(Соединение, СвойстваЧасти, ВнутренниеДанные) + + ОписаниеСоединения = НовоеОписаниеСоединения(); + ОписаниеСоединения.Вставить("Таблица", ""); + ОписаниеСоединения.Вставить("Псевдоним", ""); + ОписаниеСоединения.Вставить("УсловиеСоединения", Неопределено); + + Если Соединение[0].Вид <> "КлючевоеСлово" + Или Соединение[0].Уточнение <> "Левое" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 0, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'Нет ключевого слова ""%1""'"), "Левое")); + + Если Соединение[0].Вид <> "КлючевоеСлово" + Или Соединение[0].Уточнение <> "Внутреннее" + И Соединение[0].Уточнение <> "Полное" Тогда + + Возврат; + КонецЕсли; + КонецЕсли; + + Если Соединение.Количество() < 2 + Или Соединение[1].Вид <> "КлючевоеСлово" + Или Соединение[1].Уточнение <> "Соединение" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 1, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет ключевого слова ""%2""'"), + Соединение[0].Символы, + КлючевоеСловоСУчетомЯзыка("Соединение", ВнутренниеДанные))); + Возврат; + КонецЕсли; + + Если Соединение.Количество() < 3 + Или Соединение[2].Вид <> "Имя" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 2, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет имени таблицы'"), + Соединение[1].Символы)); + Возврат; + КонецЕсли; + + УстановитьИмяТаблицы(Соединение[2], ОписаниеСоединения, ВнутренниеДанные); + + Если Соединение.Количество() < 4 + Или Соединение[3].Вид <> "КлючевоеСлово" + Или Соединение[3].Уточнение <> "Как" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 3, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После имени таблицы нет ключевого слова ""%1""'"), "Как")); + Возврат; + КонецЕсли; + + Если Соединение.Количество() < 5 + Или Соединение[4].Вид <> "Имя" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 4, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%1"" нет псевдонима таблицы'"), "Как")); + Возврат; + КонецЕсли; + + УстановитьПсевдоним(Соединение[4], ОписаниеСоединения, ВнутренниеДанные); + + Если Соединение.Количество() < 6 + Или Соединение[5].Вид <> "КлючевоеСлово" + Или Соединение[5].Уточнение <> "По" Тогда + УстановитьОшибкуВнутриЧасти(Соединение, 5, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После псевдонима таблицы нет ключевого слова ""%1""'"), "По")); + Возврат; + КонецЕсли; + + Условие = Новый Массив(Новый ФиксированныйМассив(Соединение)); + Для Индекс = 0 По 5 Цикл + Условие.Удалить(0); + КонецЦикла; + + РазобратьУсловие(Условие, ОписаниеСоединения.УсловиеСоединения, ВнутренниеДанные); + + СвойстваЧасти.Состав.Добавить(ОписаниеСоединения); + +КонецПроцедуры + +// Для процедуры РазобратьДополнительныеТаблицы. +Процедура РазобратьПоляУсловияСоединенияИОтметитьЗапреты(ОписаниеСоединения, ВнутренниеДанные) + + // Отметка некорректных аргументов операций и запрещенных возможностей. + ОбщиеУзлы = Новый Соответствие(УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( + "Поле,Значение,Константа,И,=", Ложь)); + + ОбщиеУзлы.Вставить("Поле", Новый Структура("Выразить, Вложение, ЕстьNull", Ложь, Ложь, Ложь)); + + ДоступныеУзлы = Новый Структура; + ДоступныеУзлы.Вставить("Общие", ОбщиеУзлы); + ДоступныеУзлы.Вставить("УзлыКогда", ОбщиеУзлы); + ДоступныеУзлы.Вставить("УзлыТогдаИначе", ОбщиеУзлы); + + Контекст = РасширенныеВнутренниеДанные(ВнутренниеДанные); + Контекст.Вставить("ЭтоУсловиеСоединения", Истина); + Контекст.Вставить("ЭтоУсловиеКогда", Ложь); + Контекст.Вставить("ЭтоЗначениеТогдаИначе", Ложь); + Контекст.Вставить("КорневойУзел", ОписаниеСоединения.УсловиеСоединения); + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(ОписаниеСоединения.УсловиеСоединения, + ДоступныеУзлы, Контекст); + + УдалитьСвойствоИсточник(ОписаниеСоединения.УсловиеСоединения); + +КонецПроцедуры + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +// +// Параметры: +// Список - Строка - список имен узлов через запятую. +// ЭтоСписокИсключений - Булево - если Истина, добавить узлы, кроме указанных. +// +// Возвращаемое значение: +// ФиксированноеСоответствие из КлючИЗначение: +// * Ключ - Строка - имя узла +// * Значение - Булево +// - Структура: +// ** Выразить - Булево +// ** Вложение - Булево +// ** ЕстьNull - Булево +// +Функция УзлыДляПроверкиДоступности(Список, ЭтоСписокИсключений) Экспорт + + ВсеУзлы = Новый Соответствие; + ВсеУзлы.Вставить("Поле", Новый Структура("Выразить, Вложение, ЕстьNull", Истина, Истина, Истина)); + ВсеУзлы.Вставить("Значение", Истина); + ВсеУзлы.Вставить("Константа", Истина); + ВсеУзлы.Вставить("И", Истина); + ВсеУзлы.Вставить("Или", Истина); + ВсеУзлы.Вставить("Не", Истина); + ВсеУзлы.Вставить("=", Истина); + ВсеУзлы.Вставить("<>", Истина); + ВсеУзлы.Вставить("В", Истина); + ВсеУзлы.Вставить("ЕстьNull", Истина); + ВсеУзлы.Вставить("Тип", Истина); + ВсеУзлы.Вставить("ТипЗначения", Истина); + ВсеУзлы.Вставить("Выбор", Истина); + ВсеУзлы.Вставить("ЗначениеРазрешено", Истина); + ВсеУзлы.Вставить("ЭтоАвторизованныйПользователь", Истина); + ВсеУзлы.Вставить("ЧтениеОбъектаРазрешено", Истина); + ВсеУзлы.Вставить("ИзменениеОбъектаРазрешено", Истина); + ВсеУзлы.Вставить("ЧтениеСпискаРазрешено", Истина); + ВсеУзлы.Вставить("ИзменениеСпискаРазрешено", Истина); + ВсеУзлы.Вставить("ДляВсехСтрок", Истина); + ВсеУзлы.Вставить("ДляОднойИзСтрок", Истина); + ВсеУзлы.Вставить("ПравоДоступа", Истина); + ВсеУзлы.Вставить("РольДоступна", Истина); + + МассивУзлов = СтрРазделить(Список, ",", Ложь); + Узлы = Новый Соответствие; + + Для Каждого Узел Из ВсеУзлы Цикл + Если ЭтоСписокИсключений Тогда + Если МассивУзлов.Найти(Узел.Ключ) = Неопределено Тогда + Узлы.Вставить(Узел.Ключ, Узел.Значение); + КонецЕсли; + Иначе + Если МассивУзлов.Найти(Узел.Ключ) <> Неопределено Тогда + Узлы.Вставить(Узел.Ключ, Узел.Значение); + КонецЕсли; + КонецЕсли; + КонецЦикла; + + Возврат Новый ФиксированноеСоответствие(Узлы); + +КонецФункции + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +// +// Параметры: +// Условие - см. ОписаниеУзла +// ДоступныеУзлы - Структура +// Контекст - см. РасширенныеВнутренниеДанные +// Родитель - см. ОписаниеУзла +// +Процедура ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие, ДоступныеУзлы, Контекст, Родитель = Неопределено) + + Если Не ЗначениеЗаполнено(Условие) Тогда + Возврат; + КонецЕсли; + + Если Контекст.ЭтоУсловиеКогда Тогда + ТекущиеДоступныеУзлы = ДоступныеУзлы.УзлыКогда; + + ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда + ТекущиеДоступныеУзлы = ДоступныеУзлы.УзлыТогдаИначе; + Иначе + ТекущиеДоступныеУзлы = ДоступныеУзлы.Общие; + КонецЕсли; + + ДоступностьУзла = ТекущиеДоступныеУзлы.Получить(Условие.Узел); + + Если ДоступностьУзла = Неопределено Тогда + УстановитьОшибкуУзелЗапрещен(Условие.Источник, Контекст); + КонецЕсли; + + Если Условие.Узел = "Поле" Тогда + + Если Не Контекст.ЭтоУсловиеСоединения Тогда + ПолеКлючаДоступа = НовоеПолеКлючаДоступа(); + ПолеКлючаДоступа.Вставить("Поле", Условие); + ПолеКлючаДоступа.Вставить("Чтение", Контекст.Чтение); + ПолеКлючаДоступа.Вставить("Изменение", Контекст.Изменение); + Контекст.ПоляКлючаДоступа.Добавить(ПолеКлючаДоступа); + КонецЕсли; + + ВыделитьПсевдонимПоля(Условие, Контекст); + + Если Не ДоступностьУзла.Выразить + И Условие.Выразить <> Неопределено Тогда + + УстановитьОшибкуУзелЗапрещен(Условие.Источник, Контекст); + + ИначеЕсли Не ДоступностьУзла.Вложение + И Условие.Вложение <> Неопределено Тогда + + УстановитьОшибкуУзелЗапрещен(Условие.Вложение.Источник, Контекст); + + ИначеЕсли Не ДоступностьУзла.ЕстьNull + И Условие.ЕстьNull <> Неопределено Тогда + + УстановитьОшибкуУзелЗапрещен(Условие.ЕстьNullИсточник, Контекст); + КонецЕсли; + + ИначеЕсли Условие.Узел = "И" + Или Условие.Узел = "Или" Тогда + + Для Каждого Аргумент Из Условие.Аргументы Цикл + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Аргумент, ДоступныеУзлы, Контекст); + КонецЦикла; + + ИначеЕсли Условие.Узел = "Не" + Или Условие.Узел = "ЕстьNull" + Или Условие.Узел = "ДляВсехСтрок" + Или Условие.Узел = "ДляОднойИзСтрок" Тогда + + // Проверка корректности параметра. + Если Условие.Узел = "ЕстьNull" + И ( Условие.Аргумент = Неопределено + Или Условие.Аргумент.Узел <> "Поле" ) Тогда + + УстановитьОшибкуВСтроке(Условие.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Операция ""%1"" допустима только после поля'"), + Условие.Источник.Символы)); + КонецЕсли; + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Аргумент, ДоступныеУзлы, Контекст); + + ИначеЕсли Условие.Узел = "=" + Или Условие.Узел = "<>" Тогда + + СочетанияУзлов = Новый Соответствие; + СочетанияУзлов.Вставить("Значение", ",Поле,"); + СочетанияУзлов.Вставить("Константа", ",Поле,Константа,"); + + Если Контекст.ЭтоУсловиеСоединения Тогда + СочетанияУзлов.Вставить("Поле", ",Поле,Значение,Константа,"); + Иначе + СочетанияУзлов.Вставить("Поле", ",Значение,Константа,"); + СочетанияУзлов.Вставить("Тип", ",ТипЗначения,"); + СочетанияУзлов.Вставить("ТипЗначения", ",Тип,"); + КонецЕсли; + + СочетанияПервогоАргумента = СочетанияУзлов.Получить(Условие.ПервыйАргумент.Узел); + СочетанияВторогоАргумента = СочетанияУзлов.Получить(Условие.ВторойАргумент.Узел); + + ОшибкаВПервомАргументе = СочетанияПервогоАргумента = Неопределено; + ОшибкаВоВторомАргументе = СочетанияВторогоАргумента = Неопределено + Или СочетанияПервогоАргумента <> Неопределено + И СтрНайти(СочетанияПервогоАргумента, "," + Условие.ВторойАргумент.Узел + ",") = 0; + + Если ОшибкаВПервомАргументе Или ОшибкаВоВторомАргументе Тогда + Если Контекст.ЭтоУсловиеСоединения Тогда + ТекстОшибки = + НСтр("ru = 'Операция ""%1"" допустима только для поля с полем, значением или константой'"); + Иначе + ТекстОшибки = + НСтр("ru = 'Операция ""%1"" допустима только для поля со значением или константой, + |а также для типа значения с типом'"); + КонецЕсли; + Если ОшибкаВПервомАргументе Тогда + УсловиеПервыйАргумент = Условие.ПервыйАргумент; // См. ОписаниеУзла + УстановитьОшибкуВСтроке(УсловиеПервыйАргумент.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ТекстОшибки, Условие.Источник.Символы), + Истина); + КонецЕсли; + Если ОшибкаВоВторомАргументе Тогда + УсловиеВторойАргумент = Условие.ВторойАргумент; // См. ОписаниеУзла + УстановитьОшибкуВСтроке(УсловиеВторойАргумент.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ТекстОшибки, Условие.Источник.Символы)); + КонецЕсли; + КонецЕсли; + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.ПервыйАргумент, ДоступныеУзлы, Контекст, Условие); + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.ВторойАргумент, ДоступныеУзлы, Контекст, Условие); + + ИначеЕсли Условие.Узел = "В" Тогда + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Искомое, ДоступныеУзлы, Контекст); + Для Каждого Значение Из Условие.Значения Цикл + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Значение, ДоступныеУзлы, Контекст); + КонецЦикла; + + ИначеЕсли Условие.Узел = "ТипЗначения" + Или Условие.Узел = "Тип" Тогда + + Если Родитель = Неопределено + Или Родитель.Узел <> "=" + И Родитель.Узел <> "<>" Тогда + + УстановитьОшибкуВСтроке(Условие.Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Функция ""%1"" допустима только в операциях ""="" и ""<>""'"), + Условие.Источник.Символы)); + КонецЕсли; + + Если Условие.Узел = "ТипЗначения" Тогда + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Аргумент, ДоступныеУзлы, Контекст); + КонецЕсли; + + ИначеЕсли Условие.Узел = "Выбор" Тогда + Если Условие.Выбор <> Неопределено Тогда + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Выбор, ДоступныеУзлы, Контекст); + КонецЕсли; + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(Контекст); + КонтекстКогда = Новый Структура(ФиксированныйКонтекст); + КонтекстКогда.ЭтоУсловиеКогда = Истина; + КонтекстТогдаИначе = Новый Структура(ФиксированныйКонтекст); + КонтекстТогдаИначе.ЭтоЗначениеТогдаИначе = Истина; + + Для Каждого Когда Из Условие.Когда Цикл + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Когда.Условие, ДоступныеУзлы, КонтекстКогда); + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Когда.Значение, ДоступныеУзлы, КонтекстТогдаИначе); + КонецЦикла; + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Иначе, ДоступныеУзлы, КонтекстТогдаИначе); + + ИначеЕсли Условие.Узел = "ЗначениеРазрешено" + Или Условие.Узел = "ЭтоАвторизованныйПользователь" + Или Условие.Узел = "ЧтениеОбъектаРазрешено" + Или Условие.Узел = "ИзменениеОбъектаРазрешено" + Или Условие.Узел = "ЧтениеСпискаРазрешено" + Или Условие.Узел = "ИзменениеСпискаРазрешено" Тогда + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(Условие.Поле, ДоступныеУзлы, Контекст); + ОтметитьПовторыТиповСредиПроверяемыхИУточняемых(Условие, Контекст); + + // Добавление типов, наличие которых нужно проверить у полей. + Поле = Условие.Поле; // См. ОписаниеУзла + Уточнения = Новый Соответствие; + Для Каждого УточнениеСравнения Из Условие.УточненияСравнения Цикл + Если ТипЗнч(УточнениеСравнения.Ключ) <> Тип("СтрокаТаблицыЗначений") Тогда + Уточнения.Вставить(УточнениеСравнения.Ключ, УточнениеСравнения.Значение); + Продолжить; + КонецЕсли; + Уточнения.Вставить(УточнениеСравнения.Ключ.Символы, УточнениеСравнения.Значение); + ДобавитьТребуемоеПолеТаблицы(Контекст, Поле.Таблица, Поле.Имя, Поле.ИмяИсточник, + УточнениеСравнения.Ключ.Символы, УточнениеСравнения.Ключ); + КонецЦикла; + + // Удаление источников типов. + Условие.УточненияСравнения = Уточнения; + + Типы = Новый Массив; + Для Каждого Тип Из Условие.Типы Цикл + Типы.Добавить(Тип.Символы); + КонецЦикла; + Условие.Типы = Типы; + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Структура: +// * Поле - см. ОписаниеУзла +// * Чтение - Булево +// * Родители - Массив из см. ОписаниеУзла +// +Функция НовоеПолеКлючаДоступа() + + Возврат Новый Структура; + +КонецФункции + +// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. +Процедура ВыделитьПсевдонимПоля(УзелПоле, Контекст) + + Если УзелПоле.Вложение <> Неопределено Тогда + Вложение = УзелПоле.Вложение; + ВыделитьПсевдонимПоля(Вложение, Контекст); + Если ЗначениеЗаполнено(Вложение.Выразить) Тогда + УзелПоле.Таблица = Вложение.Выразить; + КонецЕсли; + + ИначеЕсли Не ЗначениеЗаполнено(УзелПоле.Имя) Тогда + Возврат; + Иначе + СоставИмени = СтрРазделить(УзелПоле.Имя, "."); + Если СоставИмени.Количество() > 1 Тогда + Свойства = Контекст.Псевдонимы.Получить(ВРег(СоставИмени[0])); + Если Свойства <> Неопределено Тогда + УзелПоле.Псевдоним = Свойства.Псевдоним; + СоставИмени.Удалить(0); + УзелПоле.Имя = СтрСоединить(СоставИмени, "."); + Если ЗначениеЗаполнено(Свойства.Таблица) Тогда + УзелПоле.Таблица = Свойства.Таблица; + КонецЕсли; + КонецЕсли; + КонецЕсли; + Если Контекст.ЭтоУсловиеСоединения Тогда + Если Не ЗначениеЗаполнено(УзелПоле.Псевдоним) Тогда + УстановитьОшибкуВСтроке(УзелПоле.ИмяИсточник, + НСтр("ru = 'В условии соединения перед именем поля требуется псевдоним'")); + ИначеЕсли Контекст.ДоступныеПсевдонимы.Получить(ВРег(УзелПоле.Псевдоним)) = Неопределено Тогда + УстановитьОшибкуВСтроке(УзелПоле.ИмяИсточник, + НСтр("ru = 'Нельзя указывать псевдоним из следующего соединения'")); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + Если ЗначениеЗаполнено(УзелПоле.Выразить) Тогда + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, УзелПоле.Выразить, УзелПоле.ВыразитьИсточник); + КонецЕсли; + + ДобавитьТребуемоеПолеТаблицы(Контекст, УзелПоле.Таблица, УзелПоле.Имя, УзелПоле.ИмяИсточник, + УзелПоле.Выразить, УзелПоле.ВыразитьИсточник, УзелПоле); + +КонецПроцедуры + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +Процедура УдалитьСвойствоИсточник(Условие) + + Если ТипЗнч(Условие) = Тип("СтрокаТаблицыЗначений") Тогда + ТекстОшибки = НСтр("ru = 'Не все источники наборов символов удалены'"); + ВызватьИсключение ТекстОшибки; + + ИначеЕсли ТипЗнч(Условие) <> Тип("Структура") Тогда + Возврат; + КонецЕсли; + + Если Условие.Свойство("Источник") Тогда + Условие.Удалить("Источник"); + КонецЕсли; + + Если Условие.Свойство("ИмяИсточник") Тогда + Условие.Удалить("ИмяИсточник"); + КонецЕсли; + + Если Условие.Свойство("ВыразитьИсточник") Тогда + Условие.Удалить("ВыразитьИсточник"); + КонецЕсли; + + Если Условие.Свойство("ЕстьNullИсточник") Тогда + Условие.Удалить("ЕстьNullИсточник"); + КонецЕсли; + + Для Каждого КлючИЗначение Из Условие Цикл + Значение = КлючИЗначение.Значение; + + Если ТипЗнч(Значение) = Тип("Массив") Тогда + Для Каждого Элемент Из Значение Цикл + УдалитьСвойствоИсточник(Элемент); + КонецЦикла; + + ИначеЕсли ТипЗнч(Значение) = Тип("Соответствие") Тогда + Для Каждого КлючИЗначение Из Значение Цикл + УдалитьСвойствоИсточник(КлючИЗначение.Ключ); + УдалитьСвойствоИсточник(КлючИЗначение.Значение); + КонецЦикла; + Иначе + УдалитьСвойствоИсточник(Значение); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. +Процедура УстановитьОшибкуУзелЗапрещен(Строка, Контекст) + + Если Строка.Тип = "Функция" Тогда + Если Контекст.ЭтоУсловиеСоединения Тогда + ШаблонОшибки = НСтр("ru = 'Функция ""%1"" запрещена в условии соединения'"); + + ИначеЕсли Контекст.ЭтоУсловиеКогда Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Функция ""%3"" запрещена в условии ограничения в операции ""%1"" в предложении ""%2""'"), + "Выбор,Когда", Строка.Символы); + + ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Функция ""%4"" запрещена в условии ограничения в операции ""%1"" в предложениях ""%2"" и ""%3""'"), + "Выбор,Тогда,Иначе", Строка.Символы); + Иначе + ШаблонОшибки = НСтр("ru = 'Функция ""%1"" запрещена в условии ограничения'"); + КонецЕсли; + Иначе + Если Контекст.ЭтоУсловиеСоединения Тогда + ШаблонОшибки = НСтр("ru = 'Операция ""%1"" запрещена в условии соединения'"); + + ИначеЕсли Контекст.ЭтоУсловиеКогда Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Операция ""%3"" запрещена в условии ограничения в операции ""%1"" в предложении ""%2""'"), + "Выбор,Когда", Строка.Символы); + + ИначеЕсли Контекст.ЭтоЗначениеТогдаИначе Тогда + ШаблонОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Операция ""%4"" запрещена в условии ограничения в операции ""%1"" в предложениях ""%2"" и ""%3""'"), + "Выбор,Тогда,Иначе", Строка.Символы); + Иначе + ШаблонОшибки = НСтр("ru = 'Операция ""%1"" запрещена в условии ограничения'"); + КонецЕсли; + КонецЕсли; + + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + ШаблонОшибки, Строка.Символы)); + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. +Процедура ОтметитьПовторыТиповСредиПроверяемыхИУточняемых(Узел, Контекст) + + ТипыВСписке = Новый Соответствие; + + Для Каждого ТипВСписке Из Узел.Типы Цикл + Если ТипыВСписке.Получить(ВРег(ТипВСписке.Символы)) = Неопределено Тогда + ТипыВСписке.Вставить(ВРег(ТипВСписке.Символы), Истина); + Иначе + УстановитьОшибкуВСтроке(ТипВСписке, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Тип ""%1"" уже указан'"), ТипВСписке.Символы)); + КонецЕсли; + КонецЦикла; + + УточняемыеТипы = Новый Соответствие; + + Для Каждого УточнениеСравнения Из Узел.УточненияСравнения Цикл + Если ТипЗнч(УточнениеСравнения.Ключ) <> Тип("СтрокаТаблицыЗначений") Тогда + Продолжить; + КонецЕсли; + ИсточникТипа = УточнениеСравнения.Ключ; + + Если Не Узел.ПроверятьТипыКромеУказанных + И ТипыВСписке.Получить(ВРег(ИсточникТипа.Символы)) <> Неопределено Тогда + + УстановитьОшибкуВСтроке(ИсточникТипа, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Тип ""%2"" уже указан среди типов ключевого слова ""%1""'"), + "Только", + ИсточникТипа.Символы)); + + ИначеЕсли Узел.ПроверятьТипыКромеУказанных + И ТипыВСписке.Получить(ВРег(ИсточникТипа.Символы)) = Неопределено Тогда + + УстановитьОшибкуВСтроке(ИсточникТипа, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Тип ""%2"" не указан среди типов ключевого слова ""%1""'"), + "Кроме", + ИсточникТипа.Символы)); + + ИначеЕсли УточняемыеТипы.Получить(ВРег(ИсточникТипа.Символы)) <> Неопределено Тогда + УстановитьОшибкуВСтроке(ИсточникТипа, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Уточнение типа ""%1"" уже указано'"), ИсточникТипа.Символы)); + Иначе + УточняемыеТипы.Вставить(ВРег(ИсточникТипа.Символы), Истина); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьЧастьОграничения. +// +// Параметры: +// СвойстваЧасти - см. НовыеСвойстваЧасти +// ВнутренниеДанные - см. НовыеВнутренниеДанные +// +Процедура РазобратьУсловиеОграничения(СвойстваЧасти, ВнутренниеДанные) + + СтрокиЧасти = СвойстваЧасти.Строки; + ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти); + + Если СтрокиЧасти.Количество() < 2 + Или СтрокиЧасти[1].Вид <> "КлючевоеСлово" + Или СтрокиЧасти[1].Уточнение <> "Где" Тогда + УстановитьОшибкуНачалаЧасти( + ?(СтрокиЧасти.Количество() < 2, СвойстваЧасти.СтрокаРазделителя, СтрокиЧасти[1]), + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" нет + |ключевого слова ""%2""'"), + СвойстваЧасти.Представление, + КлючевоеСловоСУчетомЯзыка("Где", ВнутренниеДанные))); + Возврат; + КонецЕсли; + + Условие = Новый Массив(Новый ФиксированныйМассив(СтрокиЧасти)); + Для Индекс = 0 По 1 Цикл + Условие.Удалить(0); + КонецЦикла; + + РазобратьУсловие(Условие, СвойстваЧасти.Состав, ВнутренниеДанные); + + // Отметка некорректных параметров операций и неподдерживаемого функционала. + ОбщиеУзлы = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности("", Истина); + + УзлыКогда = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( + "Поле,Значение,Константа,И,Или,Не,=,<>,В,ЕстьNull,Тип,ТипЗначения", Ложь); + + УзлыТогдаИначе = УправлениеДоступомСлужебныйПовтИсп.УзлыДляПроверкиДоступности( + "Выбор,ДляВсехСтрок,ДляОднойИзСтрок", Истина); + + ДоступныеУзлы = Новый Структура; + ДоступныеУзлы.Вставить("Общие", ОбщиеУзлы); + ДоступныеУзлы.Вставить("УзлыКогда", УзлыКогда); + ДоступныеУзлы.Вставить("УзлыТогдаИначе", УзлыТогдаИначе); + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ВнутренниеДанные); + Контекст = Новый Структура(ФиксированныйКонтекст); + Контекст.Вставить("ЭтоУсловиеСоединения", Ложь); + Контекст.Вставить("ЭтоУсловиеКогда", Ложь); + Контекст.Вставить("ЭтоЗначениеТогдаИначе", Ложь); + Контекст.Вставить("КорневойУзел", СвойстваЧасти.Состав); + Контекст.Вставить("Чтение", + СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" + Или СвойстваЧасти.Имя = "РазрешитьЧтение"); + Контекст.Вставить("Изменение", + СвойстваЧасти.Имя = "РазрешитьЧтениеИзменение" + Или СвойстваЧасти.Имя = "РазрешитьИзменениеЕслиРазрешеноЧтение"); + + ДобавитьПсевдонимыПоУмолчанию(Контекст); + + ОтметитьНекорректныеАргументыИЗапрещенныеУзлы(СвойстваЧасти.Состав, ДоступныеУзлы, Контекст); + + УдалитьСвойствоИсточник(СвойстваЧасти.Состав); + +КонецПроцедуры + +// Для процедур ЧастиОграничения, РазобратьУсловиеОграничения. +Процедура ДобавитьПсевдонимыПоУмолчанию(Контекст); + + Если Контекст.Псевдонимы.Количество() > 0 Тогда + Возврат; + КонецЕсли; + + Контекст.Псевдонимы.Вставить(ВРег("ЭтотСписок"), Новый Структура("Псевдоним, Таблица", "ЭтотСписок")); + Контекст.Псевдонимы.Вставить(ВРег("ThisList"), Новый Структура("Псевдоним, Таблица", "ThisList")); + +КонецПроцедуры + +// Для процедур РазобратьУсловиеСоединения, РазобратьУсловиеОграничения. +// +// Параметры: +// Условие - Массив из СтрокаТаблицыЗначений +// Состав - см. ОписаниеУзла +// ВнутренниеДанные - см. НовыеВнутренниеДанные +// +Процедура РазобратьУсловие(Условие, Состав, ВнутренниеДанные) + + ВыраженияВСкобкахВоВложениях = ВыраженияВСкобкахВоВложениях(Условие, ВнутренниеДанные); + + ФункцииСВыражениямиВСкобках = ФункцииСВыражениямиВСкобках( + ВыраженияВСкобкахВоВложениях, ВнутренниеДанные); + + ВыраженияВыборКогдаТогдаВоВложениях = ВыраженияВыборКогдаТогдаВоВложениях( + ФункцииСВыражениямиВСкобках, ВнутренниеДанные); + + Условие = ВыраженияВыборКогдаТогдаВоВложениях; + + РазобратьВыражение(Условие, Состав, ВнутренниеДанные, Ложь); + + ОбъединитьВложенныеЛогическиеОперации(Состав); + +КонецПроцедуры + +// Для процедуры РазобратьУсловие. +Процедура ОбъединитьВложенныеЛогическиеОперации(Состав) + + Если Состав = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Состав.Узел = "И" + Или Состав.Узел = "Или" Тогда + + Индекс = Состав.Аргументы.Количество() - 1; + Пока Индекс >= 0 Цикл + + Аргумент = Состав.Аргументы[Индекс]; + ОбъединитьВложенныеЛогическиеОперации(Аргумент); + + Если Аргумент.Узел = Состав.Узел Тогда + Состав.Аргументы.Удалить(Индекс); + ВложенныйИндекс = Аргумент.Аргументы.Количество() - 1; + Пока ВложенныйИндекс >= 0 Цикл + Состав.Аргументы.Вставить(Индекс, Аргумент.Аргументы[ВложенныйИндекс]); + ВложенныйИндекс = ВложенныйИндекс - 1; + КонецЦикла; + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + КонецЕсли; + +КонецПроцедуры + + +// Для процедур РазобратьУсловие, РазобратьФункцию, РазобратьВыбор. +// +// Параметры: +// Условие - Массив из см. СтрокаТаблицы.ОписаниеСтроки +// +Процедура РазобратьВыражение(Условие, Состав, ТекущийКонтекст, ВложенноеВыражение = Истина) + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(ТекущийКонтекст); + Контекст = Новый Структура(ФиксированныйКонтекст); + Контекст.Вставить("Вложения", Новый Массив); + Контекст.Вставить("Описание"); + Контекст.Вставить("Строка"); + + Для Каждого ОписаниеСтроки Из Условие Цикл + Строка = СтрокаТаблицы(ОписаниеСтроки, ТекущийКонтекст); + Контекст.Строка = Строка; + + Если Строка.Вид = "Имя" + Или Строка.Вид = "Число" + Или Строка.Вид = "ПроизвольнаяСтрока" + Или Строка.Вид = "КлючевоеСлово" + И ( Строка.Уточнение = "Истина" + Или Строка.Уточнение = "Ложь" + Или Строка.Уточнение = "Неопределено" ) Тогда + + НовоеОписание = ОписаниеУзлаПолеИлиУзлаКонстанта(Строка); + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + + ИначеЕсли Строка.Вид = "КлючевоеСлово" Тогда + + Если Строка.Тип = "Функция" + Или Строка.Уточнение = "В" Тогда + + Если Строка.Тип = "Функция" Тогда + РазобратьФункцию(Контекст); + Иначе + РазобратьСоединительВ(Контекст); + КонецЕсли; + + ИначеЕсли Строка.Тип = "Соединитель" Тогда + РазобратьСоединитель(Контекст); + + ИначеЕсли Строка.Тип = "Оператор" Тогда + РазобратьОператор(Контекст); + + ИначеЕсли Строка.Тип = "СловоВыбора" Тогда + РазобратьВыбор(Контекст); + Иначе + РазобратьОшибочноеКлючевоеСлово(Контекст); + КонецЕсли; + + ИначеЕсли Строка.Вид = "Операция" Тогда + РазобратьСоединитель(Контекст, Истина); + + ИначеЕсли Строка.Вид = "Разделитель" Тогда + Если Строка.Символы = "(" Тогда + НовоеОписание = Неопределено; // См. ОписаниеУзла + РазобратьВыражение(Строка.Строки, НовоеОписание, Контекст); + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + Если НовоеОписание <> Неопределено Тогда + НовоеОписание.Источник.Приоритет = 99; + КонецЕсли; + Иначе + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, + НСтр("ru = 'Запятая может использоваться только для разделения параметров функций'")); + КонецЕсли; + Иначе + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); + КонецЕсли; + + Если Контекст.Описание = Неопределено Тогда + // Возникала ошибка, останавливающая дальнейший разбор (предотвращение ложных срабатываний). + Прервать; + КонецЕсли; + КонецЦикла; + + Если Контекст.Описание = Неопределено Тогда + Если ВложенноеВыражение Тогда + Состав = Новый Структура("Источник, Узел, Значение", Строка, "Константа", Ложь); + Иначе + Состав = Неопределено; + КонецЕсли; + + ИначеЕсли Контекст.Вложения.Количество() = 0 Тогда + Состав = Контекст.Описание; + Иначе + Состав = Контекст.Вложения[Контекст.Вложения.Количество() - 1]; + КонецЕсли; + +КонецПроцедуры + +// Для процедур РазобратьВыражение, РазобратьПервыйПараметрПроверочнойФункции, +// РазобратьПараметрыФункцииТипЗначения, РазобратьВыбор и +// для функции ОписаниеУзлаПолеИзФункцииЕстьNull. +// +Функция ОписаниеУзлаПолеИлиУзлаКонстанта(Строка) + + // <Имя поля>, <Число>, <Произвольная строка>, Истина, Ложь, Неопределено. + + Если Строка.Вид = "Имя" Тогда + НовоеОписание = ОписаниеУзлаПоле(Строка); + НовоеОписание.Имя = Строка.Символы; + НовоеОписание.ИмяИсточник = Строка; + Иначе + СвойстваУзла = "Источник, Узел, Значение"; + НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Константа"); + + Если Строка.Вид = "КлючевоеСлово" Тогда + Если Строка.Уточнение = "Истина" Тогда + НовоеОписание.Значение = Истина; + + ИначеЕсли Строка.Уточнение = "Ложь" Тогда + НовоеОписание.Значение = Ложь; + + Иначе // Строка.Вид = "Неопределено". + НовоеОписание.Значение = Неопределено; + КонецЕсли; + Иначе // "Число" или "ПроизвольнаяСтрока". + НовоеОписание.Значение = Строка.Уточнение; + КонецЕсли; + КонецЕсли; + + Возврат НовоеОписание; + +КонецФункции + +// Для функций ОписаниеУзлаПолеИлиУзлаКонстанта, ОписаниеУзлаПолеИзФункцииВыразить, ОписаниеУзлаПолеИзФункцииЕстьNull. +Функция ОписаниеУзлаПоле(Строка) + + СвойстваУзла = "Источник, Узел, Имя, Таблица, Псевдоним, Выразить, Вложение, ЕстьNull"; + НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Поле"); + + НовоеОписание.Вставить("ИмяИсточник", Неопределено); + НовоеОписание.Вставить("ВыразитьИсточник", Неопределено); + НовоеОписание.Вставить("ЕстьNullИсточник", Неопределено); + + Возврат НовоеОписание; + +КонецФункции + +// Для процедуры РазобратьВыражение. +Процедура РазобратьСоединитель(Контекст, ЭтоОперация = Ложь) + + // И, Или, Как, Кроме, Только, Есть и любая операция =, <>, ... + // Ключевое слово В разбирается отдельно в процедуре "РазобратьСоединительВ". + + Строка = Контекст.Строка; // СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов + + НовоеОписание = Новый Структура("Источник, Узел", Строка, + ?(Строка.Вид = "Операция", Строка.Символы, Строка.Уточнение)); + + Если Строка.Уточнение = "И" + Или Строка.Уточнение = "Или" Тогда + + НовоеОписание.Вставить("Аргументы", Новый Массив); + НовоеОписание.Аргументы.Добавить(Неопределено); + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Аргументы[0]); + + ИначеЕсли Строка.Уточнение = "Есть" Тогда + НовоеОписание.Узел = "ЕстьNull"; + НовоеОписание.Вставить("Аргумент", Неопределено); + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Аргумент); + // Проверка корректности параметров выполняется + // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. + + ИначеЕсли Строка.Вид = "Операция" Тогда + НовоеОписание.Вставить("ПервыйАргумент", Неопределено); + НовоеОписание.Вставить("ВторойАргумент", Неопределено); + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.ПервыйАргумент); + // Проверка корректности аргументов выполняется + // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. + + ИначеЕсли Строка.Уточнение = "Как" + Или Строка.Уточнение = "Кроме" + Или Строка.Уточнение = "Только" Тогда + + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ключевое слово ""%1"" может использоваться только в параметрах функций'"), Строка.Символы)); + Иначе + Контекст.Описание = Неопределено; + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьВыражение. +Процедура РазобратьСоединительВ(Контекст) + + Строка = Контекст.Строка; + + НовоеОписание = Новый Структура("Источник, Узел", Строка, Строка.Уточнение); + НовоеОписание.Вставить("Искомое", Неопределено); + НовоеОписание.Вставить("Значения", Новый Массив); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + + Для Каждого ОписаниеПараметра Из СоставПараметров Цикл + СтрокиОписанияПараметра = ОписаниеПараметра.Строки; // Массив Из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов + Для Каждого Подстрока Из СтрокиОписанияПараметра Цикл + + РазобратьЗначениеСоединителяВ(Контекст, Подстрока, НовоеОписание); + + Если ОписаниеПараметра.Строки[0] <> Подстрока Тогда + УстановитьОшибкуВСтроке(Подстрока, НСтр("ru = 'Перед параметром не указана запятая'")); + КонецЕсли; + + КонецЦикла; + КонецЦикла; + + ДобавитьСоединитель(Контекст, НовоеОписание, НовоеОписание.Искомое); + + Если НовоеОписание.Искомое.Узел <> "Поле" Тогда + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Операцию ""%1"" можно указывать только после имени поля'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьСоединительВ. +Процедура РазобратьЗначениеСоединителяВ(Контекст, Подстрока, НовоеОписание) + + Строка = Контекст.Строка; + + Если Подстрока.Вид = "Число" + Или Подстрока.Вид = "ПроизвольнаяСтрока" Тогда + + ОписаниеКонстанты = Новый Структура("Источник, Узел", Подстрока, "Константа"); + ОписаниеКонстанты.Вставить("Значение", Подстрока.Уточнение); + НовоеОписание.Значения.Добавить(ОписаниеКонстанты); + + ИначеЕсли Подстрока.Вид = "КлючевоеСлово" Тогда + + Если Подстрока.Уточнение = "Значение" Тогда + НовыйКонтекст = НовыйКонтекст(Контекст, Подстрока, Неопределено); + РазобратьФункцию(НовыйКонтекст); + Если НовыйКонтекст.Описание <> Неопределено Тогда + НовоеОписание.Значения.Добавить(НовыйКонтекст.Описание); + КонецЕсли; + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" ключевое слово ""%2"" недопустимо'"), + Строка.Символы, Подстрока.Символы)); + КонецЕсли; + + ИначеЕсли Подстрока.Вид = "Имя" Тогда + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" имя поля недопустимо'"), Строка.Символы)); + + ИначеЕсли Подстрока.Символы = "(" Тогда + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" скобки допустимы только для параметров функции'"), Строка.Символы)); + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" можно указывать только значения'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьЗначениеСоединителяВ. +Функция НовыйКонтекст(Контекст, Строка = null, Описание = null) + + ФиксированныйКонтекст = Новый ФиксированнаяСтруктура(Контекст); + НовыйКонтекст = Новый Структура(ФиксированныйКонтекст); + + Если Строка <> null Тогда + НовыйКонтекст.Строка = Строка; + КонецЕсли; + + Если Описание <> null Тогда + НовыйКонтекст.Описание = Описание; + КонецЕсли; + + Возврат НовыйКонтекст; + +КонецФункции + +// Для процедур РазобратьСоединитель, РазобратьСоединительВ, ВставитьСоединительСУчетомПриоритета. +Процедура ДобавитьСоединитель(Контекст, НовоеОписание, ПервыйАргумент); + + // Добавляемый соединитель: И, Или, В, Есть и любая операция (=, <>, ...). + + Описание = Контекст.Описание; // См. ОписаниеУзла + + Если Описание = Неопределено Тогда + Контекст.Описание = НовоеОписание; + + ИначеЕсли Описание.Узел = "И" + Или Описание.Узел = "Или" Тогда + + Если Описание.Аргументы.Количество() = 1 Тогда + Описание.Аргументы.Добавить(Неопределено); + ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.Аргументы[1]); + КонецЕсли; + ВставитьСоединительСУчетомПриоритета(Контекст, + Описание.Аргументы[1], НовоеОписание, ПервыйАргумент); + + ИначеЕсли Описание.Узел = "Не" Тогда + Если Не ЗначениеЗаполнено(Описание.Аргумент) Тогда + ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.Аргумент); + КонецЕсли; + ВставитьСоединительСУчетомПриоритета(Контекст, + Описание.Аргумент, НовоеОписание, ПервыйАргумент); + + ИначеЕсли Описание.Источник.Вид = "Операция" Тогда + Если Не ЗначениеЗаполнено(Описание.ВторойАргумент) Тогда + ОбработатьПропущенныйАргументПослеСоединителя(Контекст, Описание.ВторойАргумент, Ложь); + КонецЕсли; + ВставитьСоединительСУчетомПриоритета(Контекст, + Описание.ВторойАргумент, НовоеОписание, ПервыйАргумент); + + ИначеЕсли СтрНайти(",Поле,Значение,Константа,В,ЕстьNull,Выбор,", "," + Описание.Узел + ",") > 0 + Или Описание.Источник.Тип = "Функция" Тогда + // Второй аргумент операции В уже разобран в процедуре РазобратьСоединительВ. + // Второй аргумент Null операции Есть уже разобран в функции ФункцииСВыражениямиВСкобках. + // Остальные узлы не имеют второго аргумента. + ВставитьСоединительСУчетомПриоритета(Контекст, Неопределено, НовоеОписание, ПервыйАргумент); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка узла ""%1""'"), Описание.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьСоединитель. +Процедура ОбработатьПропущенныйАргументПослеСоединителя(Контекст, ВторойАргумент, ЛогическаяОперация = Истина) + + Описание = Контекст.Описание; // См. ОписаниеУзла + + УстановитьОшибкуВСтроке(Описание.Источник, + ?(ЛогическаяОперация, + НСтр("ru = 'Не указан аргумент после логической операции'"), + НСтр("ru = 'Не указан аргумент после операции'")), + Истина); + + ВторойАргумент = Новый Структура("Источник, Узел, Значение", Контекст.Строка, "Константа", Истина); + +КонецПроцедуры + +// Для процедур ДобавитьСоединитель, ОбработатьПропущеннуюЛогическуюОперацию. +Процедура ВставитьСоединительСУчетомПриоритета(Контекст, + ПоследнийАргументОписания, НовоеОписание, ПервыйАргументНовогоОписания) + + Вложения = Контекст.Вложения; + Описание = Контекст.Описание; // См. ОписаниеУзла + + Если ПоследнийАргументОписания <> Неопределено + И Контекст.Строка.Приоритет >= Описание.Источник.Приоритет Тогда + + // Замена аргумента текущего узла на соединитель (случай "А Или Б И ..."). + ПервыйАргументНовогоОписания = ПоследнийАргументОписания; + ПоследнийАргументОписания = НовоеОписание; + + Вложения.Вставить(0, Контекст.Описание); + Контекст.Описание = НовоеОписание; + Возврат; + КонецЕсли; + + Если Вложения.Количество() = 0 Тогда + // Вложение текущего узла, как первого аргумента соединителя (случай "А И Б Или ..."). + ПервыйАргументНовогоОписания = Контекст.Описание; + Контекст.Описание = НовоеОписание; + Возврат; + КонецЕсли; + + // Вложение предыдущего узла, как первого аргумента соединителя (случай "А И Не Б Или ..."). + Контекст.Описание = Вложения[0]; + Вложения.Удалить(0); + + ДобавитьСоединитель(Контекст, НовоеОписание, ПервыйАргументНовогоОписания); + +КонецПроцедуры + +// Для процедуры РазобратьВыражение. +Процедура РазобратьОператор(Контекст) + + // Оператор Не. + + НовоеОписание = Новый Структура("Источник, Узел, Аргумент", + Контекст.Строка, Контекст.Строка.Уточнение); + + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + + Контекст.Вложения.Вставить(0, Контекст.Описание); + Контекст.Описание = НовоеОписание; + +КонецПроцедуры + +// Для процедур РазобратьВыражение, РазобратьЗначениеСоединителяВ. +Процедура РазобратьФункцию(Контекст) + + Строка = Контекст.Строка; + + НовоеОписание = Новый Структура("Источник, Узел", Строка, Строка.Уточнение); + + Если Строка.Уточнение = "ЗначениеРазрешено" + Или Строка.Уточнение = "ЧтениеОбъектаРазрешено" + Или Строка.Уточнение = "ИзменениеОбъектаРазрешено" + Или Строка.Уточнение = "ЧтениеСпискаРазрешено" + Или Строка.Уточнение = "ИзменениеСпискаРазрешено" + Или Строка.Уточнение = "ЭтоАвторизованныйПользователь" Тогда + + РазобратьПараметрыПроверочнойФункции(Контекст, НовоеОписание); + + ИначеЕсли Строка.Уточнение = "ДляВсехСтрок" + Или Строка.Уточнение = "ДляОднойИзСтрок" Тогда + + ОписаниеВыражения = Неопределено; + РазобратьВыражение(Строка.Строки, ОписаниеВыражения, Контекст); + НовоеОписание.Вставить("Аргумент", ОписаниеВыражения); + + ИначеЕсли Строка.Уточнение = "Значение" Тогда + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, Истина, Контекст); + + ИначеЕсли Строка.Уточнение = "Тип" Тогда + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, Ложь, Контекст); + + ИначеЕсли Строка.Уточнение = "ТипЗначения" Тогда + РазобратьПараметрыФункцииТипЗначения(Контекст, НовоеОписание); + + ИначеЕсли Строка.Уточнение = "ЕстьNull" Тогда + НовоеОписание = ОписаниеУзлаПолеИзФункцииЕстьNull(Контекст.Строка, Контекст); + + ИначеЕсли Строка.Уточнение = "Выразить" Тогда + НовоеОписание = ОписаниеУзлаПолеИзФункцииВыразить(Контекст.Строка, Контекст); + + ИначеЕсли Строка.Уточнение = "ПравоДоступа" Тогда + РазобратьПараметрыФункцииПравоДоступа(Строка, НовоеОписание, Контекст); + + ИначеЕсли Строка.Уточнение = "РольДоступна" Тогда + РазобратьПараметрыФункцииРольДоступна(Строка, НовоеОписание, Контекст); + + ИначеЕсли Не Строка.ЭтоРезерв Тогда + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка функции ""%1""'"), Строка.Уточнение); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыПроверочнойФункции(Контекст, НовоеОписание) + + Строка = Контекст.Строка; + + НовоеОписание.Вставить("Поле", Неопределено); + НовоеОписание.Вставить("Типы", Новый Массив); + НовоеОписание.Вставить("ПроверятьТипыКромеУказанных", Ложь); + НовоеОписание.Вставить("УточненияСравнения", Новый Соответствие); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + РазобратьПервыйПараметрПроверочнойФункции(Контекст, СоставПараметров[0], НовоеОписание); + + Для Индекс = 1 По СоставПараметров.Количество() - 1 Цикл + РазобратьДополнительныйПараметрПроверочнойФункции(Контекст, + СоставПараметров[Индекс], НовоеОписание); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыПроверочнойФункции. +// +// Параметры: +// ПервыйПараметр - Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьПервыйПараметрПроверочнойФункции(Контекст, ПервыйПараметр, НовоеОписание) + + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Поле = ОписаниеУзлаПолеИлиУзлаКонстанта(ПервыйПараметр.Строки[0]); + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "Выразить" Тогда + + НовоеОписание.Поле = ОписаниеУзлаПолеИзФункцииВыразить(ПервыйПараметр.Строки[0], Контекст); + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "ЕстьNull" Тогда + + НовоеОписание.Поле = ОписаниеУзлаПолеИзФункцииЕстьNull(ПервыйПараметр.Строки[0], Контекст); + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Первым параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), + "Выразить,ЕстьNull")); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 2 Тогда + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "Выразить" + И НовоеОписание.Поле.Вложение = Неопределено Тогда + + УстановитьОшибкуВСтроке(СтрокаТаблицы(ПервыйПараметр.Строки[0].КонечнаяСтрока, Контекст), + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После вложенной функции ""%3"" должно быть указано имя поля через точку, + |если в параметре функции ""%4"" используется ключевое слово ""%1"" или ""%2""'"), + "Только,Кроме", + ПервыйПараметр.Строки[0].Символы, + Контекст.Строка.Символы), + Истина); + КонецЕсли; + + Если ПервыйПараметр.Строки[1].Вид <> "КлючевоеСлово" + Или ( ПервыйПараметр.Строки[1].Уточнение <> "Только" + И ПервыйПараметр.Строки[1].Уточнение <> "Кроме" ) Тогда + + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После описания поля может быть указано, либо ключевое слово ""%1"", либо ""%2""'"), + "Только,Кроме")); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки[1].Уточнение = "Кроме" Тогда + НовоеОписание.ПроверятьТипыКромеУказанных = Истина; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" не указан тип (имя таблицы)'"), ПервыйПараметр.Строки[1].Символы)); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки[2].Вид <> "Имя" + И ПервыйПараметр.Строки[2].Символы <> "(" Тогда + + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[2], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" должен быть указан, либо тип (имя таблицы), либо список типов в скобках'"), + ПервыйПараметр.Строки[1].Символы)); + Возврат; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[3], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед параметром функции ""%1"" не указана запятая'"), Контекст.Строка.Символы)); + КонецЕсли; + + Если ПервыйПараметр.Строки[2].Вид = "Имя" Тогда + НовоеОписание.Типы.Добавить(ПервыйПараметр.Строки[2]); + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, ПервыйПараметр.Строки[2].Символы, ПервыйПараметр.Строки[2]); + Возврат; + КонецЕсли; + + СоставПараметров = ПараметрыРазделенныеЗапятыми(ПервыйПараметр.Строки[2], Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Для Каждого Параметр Из СоставПараметров Цикл + + Если Параметр.Строки[0].Вид = "Имя" + И Параметр.Строки.Количество() < 2 Тогда + + НовоеОписание.Типы.Добавить(Параметр.Строки[0]); + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[?(Параметр.Строки.Количество() < 2, 0, 1)], + НСтр("ru = 'В списке типов могут быть указаны только имена таблицы через запятую'")); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыПроверочнойФункции. +// +// Параметры: +// Параметр - Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьДополнительныйПараметрПроверочнойФункции(Контекст, Параметр, НовоеОписание) + + Если Параметр.Строки[0].Вид = "Имя" + Или Параметр.Строки[0].Вид = "КлючевоеСлово" + И ( Параметр.Строки[0].Тип = "ЗначениеСравнения" + Или Параметр.Строки[0].Тип = "ИмяТипа" ) Тогда + + Если Параметр.Строки[0].Вид = "Имя" Тогда + ЗначениеСравнения = Параметр.Строки[0]; + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, Параметр.Строки[0].Символы, Параметр.Строки[0]); + Иначе + ЗначениеСравнения = Параметр.Строки[0].Уточнение; + КонецЕсли; + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Дополнительным параметром может быть тип (имя таблицы), + |""%1"", ""%2"", ""%3"", ""%4"", ""%5"", ""%6"" и ""%7""'"), + "ПустаяСсылка,Неопределено,Null,Число,Строка,Дата,Булево")); + Возврат; + КонецЕсли; + + Если Параметр.Строки.Количество() < 2 Тогда + Если Параметр.Строки[0].Вид = "Имя" Тогда + Шаблон = НСтр("ru = 'После типа (имени таблицы) ""%2"" должно быть указано ключевое слово ""%1""'"); + Иначе + Шаблон = НСтр("ru = 'После ключевого слова ""%2"" должно быть указано ключевое слово ""%1""'"); + КонецЕсли; + УстановитьОшибкуВСтроке(Параметр.Строки[0], ПодставитьКлючевыеСловаВСтроку(Контекст, + Шаблон, "Как", Параметр.Строки[0].Символы), + Истина); + Возврат; + КонецЕсли; + + Если Параметр.Строки[1].Вид <> "КлючевоеСлово" + Или Параметр.Строки[1].Уточнение <> "Как" Тогда + + Если Параметр.Строки[0].Вид = "Имя" Тогда + Шаблон = НСтр("ru = 'После типа (имени таблицы) ""%2"" должно быть указано ключевое слово ""%1""'"); + Иначе + Шаблон = НСтр("ru = 'После ключевого слова ""%2"" должно быть указано ключевое слово ""%1""'"); + КонецЕсли; + УстановитьОшибкуВСтроке(Параметр.Строки[1], ПодставитьКлючевыеСловаВСтроку(Контекст, + Шаблон, "Как", Параметр.Строки[0].Символы)); + Возврат; + КонецЕсли; + + Если Параметр.Строки.Количество() < 3 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%4"" не указано значение уточнения ""%1"", ""%2"" или ""%3""'"), + "Ложь,Истина,Пусто", + Параметр.Строки[1].Символы), + Истина); + Возврат; + КонецЕсли; + + Если Параметр.Строки[2].Вид <> "КлючевоеСлово" + Или Параметр.Строки[2].Тип <> "ЗначениеУточнения" Тогда + + УстановитьОшибкуВСтроке(Параметр.Строки[2], ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%4"" должно быть указано значение уточнения ""%1"", ""%2"" или ""%3""'"), + "Ложь,Истина,Пусто", + Параметр.Строки[1].Символы)); + Иначе + НовоеОписание.УточненияСравнения.Вставить(ЗначениеСравнения, Параметр.Строки[2].Уточнение); + КонецЕсли; + + Если Параметр.Строки.Количество() > 3 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[3], + НСтр("ru = 'Перед параметром не указана запятая или лишний параметр'")); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииЗначениеИлиФункцииТип(Строка, НовоеОписание, ЭтоФункцияЗначение, Контекст) + + НовоеОписание.Вставить("Имя", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Параметр = СоставПараметров[0]; + Если Параметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Имя = Параметр.Строки[0].Символы; + + Если ЭтоФункцияЗначение Тогда + ДобавитьТребуемыйПредопределенныйЭлемент(Контекст, НовоеОписание.Имя, Параметр.Строки[0]); + Иначе + ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, НовоеОписание.Имя, Параметр.Строки[0]); + КонецЕсли; + + ИначеЕсли ЭтоФункцияЗначение Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" можно указать только имя предопределенного значения'"), Строка.Символы)); + + ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Тип = "ИмяТипа" Тогда + + НовоеОписание.Имя = Параметр.Строки[0].Уточнение; + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'В функции ""%5"" можно указать имя таблицы или ""%1"", ""%2"", ""%3"" и ""%4""'"), + "Число,Строка,Дата,Булево", + Строка.Символы)); + КонецЕсли; + + Если Параметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииРольДоступна(Строка, НовоеОписание, Контекст) + + НовоеОписание.Вставить("ИмяРоли", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Параметр = СоставПараметров[0]; + Если Параметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.ИмяРоли = Параметр.Строки[0].Символы; + + ПроверитьИмяРоли(НовоеОписание.ИмяРоли, Параметр.Строки[0]); + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" можно указать только имя роли'"), Строка.Символы)); + КонецЕсли; + + Если Параметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииПравоДоступа(Строка, НовоеОписание, Контекст) + + НовоеОписание.Вставить("ИмяПрава", Неопределено); + НовоеОписание.Вставить("ПолноеИмяОбъектаМетаданных", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + ПервыйПараметр = СоставПараметров[0]; + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.ИмяПрава = ПервыйПараметр.Строки[0].Символы; + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" в первом параметре можно указать только имя права'"), Строка.Символы)); + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед параметром ""%1"" функции ""%2"" не указана запятая'"), + ПервыйПараметр.Строки[1].Символы, + Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() < 2 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" должно быть два параметра'"), Строка.Символы)); + Возврат; + КонецЕсли; + + ВторойПараметр = СоставПараметров[1]; + Если ВторойПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.ПолноеИмяОбъектаМетаданных = ВторойПараметр.Строки[0].Символы; + + ПроверитьИмяПраваОбъектаМетаданных(НовоеОписание.ИмяПрава, ПервыйПараметр.Строки[0], + НовоеОписание.ПолноеИмяОбъектаМетаданных, ВторойПараметр.Строки[0]); + Иначе + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В функции ""%1"" во втором параметре можно указать только полное имя объекта метаданных'"), + Строка.Символы)); + КонецЕсли; + + Если ВторойПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 2 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[2].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьФункцию. +Процедура РазобратьПараметрыФункцииТипЗначения(Контекст, НовоеОписание) + + Строка = Контекст.Строка; + НовоеОписание.Вставить("Аргумент", Неопределено); + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + Возврат; // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + КонецЕсли; + + Параметр = СоставПараметров[0]; + + Если Параметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Аргумент = ОписаниеУзлаПолеИлиУзлаКонстанта(Параметр.Строки[0]); + + ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Уточнение = "Выразить" Тогда + + НовоеОписание.Аргумент = ОписаниеУзлаПолеИзФункцииВыразить(Параметр.Строки[0], Контекст); + + ИначеЕсли Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Уточнение = "ЕстьNull" Тогда + + НовоеОписание.Аргумент = ОписаниеУзлаПолеИзФункцииЕстьNull(Параметр.Строки[0], Контекст); + Иначе + УстановитьОшибкуВСтроке(Параметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), + "Выразить,ЕстьNull")); + Возврат; + КонецЕсли; + + Если Параметр.Строки[0].Вид = "КлючевоеСлово" + И Параметр.Строки[0].Уточнение = "Выразить" + И НовоеОписание.Аргумент.Вложение = Неопределено Тогда + + УстановитьОшибкуВСтроке(СтрокаТаблицы(Параметр.Строки[0].КонечнаяСтрока, Контекст), + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После вложенной функции ""%1"" должно быть указано имя поля через точку'"), + Параметр.Строки[0].Символы), + Истина); + КонецЕсли; + + Если Параметр.Строки.Количество() < 2 Тогда + Возврат; + КонецЕсли; + + Если Параметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(Параметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[1].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедур РазобратьФункцию, РазобратьПервыйПараметрПроверочнойФункции, РазобратьПараметрыФункцииТипЗначения. +Функция ОписаниеУзлаПолеИзФункцииВыразить(Строка, Контекст) + + НовоеОписание = ОписаниеУзлаПоле(Строка); + + Если Строка.Строки.Количество() > 0 Тогда + ПоследняяСтрока = СтрокаТаблицы(Строка.Строки[Строка.Строки.Количество() - 1], Контекст); + Если ПоследняяСтрока.Тип = "ДополнениеКВыразить" Тогда + Строка.Строки.Удалить(Строка.Строки.Количество() - 1); + НовоеОписание.Имя = Сред(ПоследняяСтрока.Символы, 2); + НовоеОписание.ИмяИсточник = ПоследняяСтрока; + НовоеОписание.Вложение = ОписаниеУзлаПолеИзФункцииВыразить(Строка, Контекст); + Возврат НовоеОписание; + КонецЕсли; + КонецЕсли; + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + Возврат НовоеОписание; + КонецЕсли; + + ПервыйПараметр = СоставПараметров[0]; + + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Имя = ПервыйПараметр.Строки[0].Символы; + НовоеОписание.ИмяИсточник = ПервыйПараметр.Строки[0]; + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "Выразить" Тогда + + НовоеОписание.Вложение = ОписаниеУзлаПолеИзФункцииВыразить(ПервыйПараметр.Строки[0], Контекст); + Если НовоеОписание.Вложение.Вложение = Неопределено Тогда + УстановитьОшибкуВСтроке(СтрокаТаблицы(ПервыйПараметр.Строки[0].КонечнаяСтрока, Контекст), + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После вложенной функции ""%1"" должно быть указано имя поля через точку'"), + ПервыйПараметр.Строки[0].Символы), + Истина); + Иначе + НовоеОписание = НовоеОписание.Вложение; + КонецЕсли; + + ИначеЕсли ПервыйПараметр.Строки[0].Вид = "КлючевоеСлово" + И ПервыйПараметр.Строки[0].Уточнение = "ЕстьNull" Тогда + + НовоеОписание = ОписаниеУзлаПолеИзФункцииЕстьNull(ПервыйПараметр.Строки[0], Контекст); + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Первым параметром может быть имя поля, функция ""%1"" или функция ""%2""'"), + "Выразить,ЕстьNull")); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 2 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После описания поля должно быть указано ключевое слово ""%1""'"), "Как"), Истина); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки[1].Вид <> "КлючевоеСлово" + Или ПервыйПараметр.Строки[1].Уточнение <> "Как" Тогда + + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], + ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После описания поля должно быть указано ключевое слово ""%1""'"), "Как")); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() < 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" не указан тип (имя таблицы)'"), ПервыйПараметр.Строки[1].Символы)); + Возврат НовоеОписание; + КонецЕсли; + + Если ПервыйПараметр.Строки[2].Вид <> "Имя" Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[2], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" должен быть указан тип (имя таблицы)'"), + ПервыйПараметр.Строки[1].Символы)); + Иначе + НовоеОписание.Выразить = ПервыйПараметр.Строки[2].Символы; + НовоеОписание.ВыразитьИсточник = ПервыйПараметр.Строки[2]; + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 3 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[3], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только один параметр'"), Строка.Символы)); + КонецЕсли; + + Возврат НовоеОписание; + +КонецФункции + +// Для процедур РазобратьФункцию, РазобратьПервыйПараметрПроверочнойФункции, +// РазобратьПараметрыФункцииТипЗначения и +// для функции ОписаниеУзлаПолеИзФункцииВыразить. +// +Функция ОписаниеУзлаПолеИзФункцииЕстьNull(Строка, Контекст) + + НовоеОписание = ОписаниеУзлаПоле(Строка); + НовоеОписание.ЕстьNullИсточник = Строка; + + СоставПараметров = ПараметрыРазделенныеЗапятыми(Строка, Контекст); + + Если СоставПараметров.Количество() = 0 Тогда + // Ошибка отсутствия параметров уже установлена в функции ФункцииСВыражениямиВСкобках. + Возврат НовоеОписание; + КонецЕсли; + + ПервыйПараметр = СоставПараметров[0]; + + Если ПервыйПараметр.Строки[0].Вид = "Имя" Тогда + НовоеОписание.Имя = ПервыйПараметр.Строки[0].Символы; + НовоеОписание.ИмяИсточник = ПервыйПараметр.Строки[0]; + Иначе + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Первым параметром функции ""%1"" может быть только имя поля'"), Строка.Символы)); + КонецЕсли; + + Если ПервыйПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед параметром функции ""%1"" не указана запятая'"), Строка.Символы)); + Возврат НовоеОписание; + КонецЕсли; + + Если СоставПараметров.Количество() < 2 Тогда + УстановитьОшибкуВСтроке(ПервыйПараметр.КонечнаяСтрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" должно быть два параметра'"), Строка.Символы)); + Возврат НовоеОписание; + КонецЕсли; + + ВторойПараметр = СоставПараметров[1]; + + Если ВторойПараметр.Строки[0].Вид = "Число" + Или ВторойПараметр.Строки[0].Вид = "ПроизвольнаяСтрока" + Или ВторойПараметр.Строки[0].Вид = "КлючевоеСлово" + И ( ВторойПараметр.Строки[0].Уточнение = "Истина" + Или ВторойПараметр.Строки[0].Уточнение = "Ложь" + Или ВторойПараметр.Строки[0].Уточнение = "Неопределено" + Или ВторойПараметр.Строки[0].Уточнение = "Значение" ) Тогда + + Если ВторойПараметр.Строки[0].Уточнение = "Значение" Тогда + НовоеОписание.ЕстьNull = Новый Структура("Источник, Узел", + ВторойПараметр.Строки[0], ВторойПараметр.Строки[0].Уточнение); + + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(ВторойПараметр.Строки[0], НовоеОписание.ЕстьNull, Истина, Контекст); + Иначе + НовоеОписание.ЕстьNull = ОписаниеУзлаПолеИлиУзлаКонстанта(ВторойПараметр.Строки[0]); + КонецЕсли; + Иначе + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" второй параметр может быть, либо предопределенным значением, либо константой'"), + Строка.Символы)); + КонецЕсли; + + Если ВторойПараметр.Строки.Количество() > 1 Тогда + УстановитьОшибкуВСтроке(ВторойПараметр.Строки[1], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" может быть только два параметра'"), Строка.Символы)); + КонецЕсли; + + Если СоставПараметров.Количество() > 2 Тогда + УстановитьОшибкуВСтроке(СоставПараметров[2].Строки[0], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" должно быть только два параметра'"), Строка.Символы)); + КонецЕсли; + + Возврат НовоеОписание; + +КонецФункции + +// Для процедур РазобратьСоединительВ, РазобратьПараметрыПроверочнойФункции, +// РазобратьПараметрыФункцииЗначениеИлиФункцииТип, РазобратьПараметрыФункцииТипЗначения и +// для функций ОписаниеУзлаПолеИзФункцииВыразить, ОписаниеУзлаПолеИзФункцииЕстьNull. +// +// Параметры: +// ОписаниеСтроки - см. СтрокаТаблицы.ОписаниеСтроки +// +// Возвращаемое значение: +// Массив из Структура: +// * Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Функция ПараметрыРазделенныеЗапятыми(ОписаниеСтроки, Контекст) + + СоставПараметров = Новый Массив; + Строка = СтрокаТаблицы(ОписаниеСтроки, Контекст); + + Если Строка.Строки.Количество() = 0 Тогда + Возврат СоставПараметров; + КонецЕсли; + + ОписаниеПараметра = Новый Структура("Строки, КонечнаяСтрока", Новый Массив); + ПредыдущаяПодстрокаЭтоЧастьАргумента = Ложь; + + Для Каждого ОписаниеПодстроки Из Строка.Строки Цикл + Подстрока = СтрокаТаблицы(ОписаниеПодстроки, Контекст); + Если Подстрока.Символы = "," Тогда + Если Не ПредыдущаяПодстрокаЭтоЧастьАргумента Тогда + Если Строка.Строки[0] = ОписаниеПодстроки Тогда + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Перед запятой не указан параметр'"), Подстрока.Символы)); + ОписаниеПараметра.Строки.Добавить(ДополнительнаяСтрока(Подстрока, "")); + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Пропущен параметр или лишняя запятая'"), Подстрока.Символы)); + КонецЕсли; + КонецЕсли; + Если ОписаниеПараметра.Строки.Количество() > 0 Тогда + СоставПараметров.Добавить(ОписаниеПараметра); + ОписаниеПараметра.КонечнаяСтрока = Подстрока; + КонецЕсли; + ОписаниеПараметра = Новый Структура("Строки, КонечнаяСтрока", Новый Массив); + ПредыдущаяПодстрокаЭтоЧастьАргумента = Ложь; + Продолжить; + КонецЕсли; + + ПредыдущаяПодстрокаЭтоЧастьАргумента = Истина; + + ОписаниеПараметра.Строки.Добавить(Подстрока); + КонецЦикла; + + Если ОписаниеПараметра.Строки.Количество() > 0 Тогда + СоставПараметров.Добавить(ОписаниеПараметра); + ОписаниеПараметра.КонечнаяСтрока = СтрокаТаблицы(Строка.КонечнаяСтрока, Контекст); + Иначе + УстановитьОшибкуВСтроке(Подстрока, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Лишняя запятая или после запятой не указан параметр'"), Подстрока.Символы), Истина); + КонецЕсли; + + Возврат СоставПараметров; + +КонецФункции + +// Для процедуры РазобратьВыражение. +// +// Параметры: +// Контекст - Структура: +// * Строка - Структура: +// ** Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура РазобратьВыбор(Контекст) + + Строка = Контекст.Строка; + + СвойстваУзла = "Источник, Узел, Выбор, Когда, Иначе"; + НовоеОписание = Новый Структура(СвойстваУзла, Строка, "Выбор"); + НовоеОписание.Когда = Новый Массив; + + ПропуститьАнализКогда = Ложь; + + Выбор = СтрокаТаблицы(Строка.Строки[0], Контекст); + Если Выбор.Строки.Количество() > 0 Тогда + ПерваяСтрокаВыбора = СтрокаТаблицы(Выбор.Строки[0], Контекст); + Если ПерваяСтрокаВыбора.Вид = "Имя" Тогда + НовоеОписание.Выбор = ОписаниеУзлаПолеИлиУзлаКонстанта(ПерваяСтрокаВыбора); + Иначе + ПропуститьАнализКогда = Истина; + УстановитьОшибкуВСтроке(ПерваяСтрокаВыбора, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Когда аргумент ключевого слова ""%1"" указан, то это может быть только имя поля'"), + Строка.Символы)); + КонецЕсли; + КонецЕсли; + + Индекс = 1; + Пока Истина Цикл + СледующаяСтрока = СтрокаТаблицы(Строка.Строки[Индекс], Контекст); + Если СледующаяСтрока.Уточнение <> "Когда" Тогда + Прервать; + КонецЕсли; + ОписаниеКогдаТогда = Новый Структура("Условие, Значение"); + НовоеОписаниеКогда = НовоеОписание.Когда; // Массив + НовоеОписаниеКогда.Добавить(ОписаниеКогдаТогда); + + Когда = СледующаяСтрока; + + Если Не ПропуститьАнализКогда Тогда + ПерваяПодстрокаКогда = ?(Когда.Строки.Количество() = 0, Неопределено, + СтрокаТаблицы(Когда.Строки[0], Контекст)); + + Если НовоеОписание.Выбор = Неопределено Тогда + РазобратьВыражение(Когда.Строки, ОписаниеКогдаТогда.Условие, Контекст); + + ИначеЕсли Когда.Строки.Количество() = 0 Тогда + Если ЗначениеЗаполнено(Когда.Символы) Тогда + УстановитьОшибкуВСтроке(Когда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Так как после ключевого слова ""%1"" указано поле, то после ключевого слова ""%2"" + |должно быть указано, либо предопределенное значение, либо константа'"), + Строка.Символы, + Когда.Символы)); + КонецЕсли; + + ИначеЕсли ПерваяПодстрокаКогда.Вид = "Число" + Или ПерваяПодстрокаКогда.Вид = "ПроизвольнаяСтрока" + Или ПерваяПодстрокаКогда.Вид = "КлючевоеСлово" + И ( ПерваяПодстрокаКогда.Уточнение = "Истина" + Или ПерваяПодстрокаКогда.Уточнение = "Ложь" + Или ПерваяПодстрокаКогда.Уточнение = "Неопределено" + Или ПерваяПодстрокаКогда.Уточнение = "Значение" ) Тогда + + Если ПерваяПодстрокаКогда.Уточнение = "Значение" Тогда + ОписаниеКогдаТогда.Условие = Новый Структура("Источник, Узел", + ПерваяПодстрокаКогда, ПерваяПодстрокаКогда.Уточнение); + + РазобратьПараметрыФункцииЗначениеИлиФункцииТип(ПерваяПодстрокаКогда, + ОписаниеКогдаТогда.Условие, Истина, Контекст); + Иначе + ОписаниеКогдаТогда.Условие = ОписаниеУзлаПолеИлиУзлаКонстанта(ПерваяПодстрокаКогда); + КонецЕсли; + ИначеЕсли ЗначениеЗаполнено(Когда.Символы) Тогда + УстановитьОшибкуВСтроке(ПерваяПодстрокаКогда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Так как после ключевого слова ""%1"" указано поле, то после ключевого слова ""%2"" + |должно быть указано, либо предопределенное значение, либо константа'"), + Строка.Символы, + Когда.Символы)); + КонецЕсли; + КонецЕсли; + + СоставТогда = СтрокаТаблицы(Строка.Строки[Индекс + 1], Контекст); + Если СоставТогда.Строки.Количество() > 0 Тогда + РазобратьВыражение(СоставТогда.Строки, ОписаниеКогдаТогда.Значение, Контекст); + + ИначеЕсли ЗначениеЗаполнено(СоставТогда.Символы) Тогда + УстановитьОшибкуВСтроке(ПерваяПодстрокаКогда, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" должно быть указано логическое выражение'"), СоставТогда.Символы)); + КонецЕсли; + + Индекс = Индекс + 2; + КонецЦикла; + + РазобратьВыражение(СледующаяСтрока.Строки, НовоеОписание.Иначе, Контекст); + + ДобавитьАргументФункциюВыборОператор(Контекст, НовоеОписание); + +КонецПроцедуры + +// Для процедуры РазобратьВыражение. +Процедура РазобратьОшибочноеКлючевоеСлово(Контекст) + + Строка = Контекст.Строка; + Контекст.Описание = Неопределено; + + Если Строка.Тип = "Неопределен" Тогда + // Для зарезервированных слов ошибка уже установлена. + Возврат; + КонецЕсли; + + Если Строка.Тип = "ЗначениеСравнения" Тогда + Если Строка.Уточнение = "Отключено" Тогда + // "Отключено". + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Значение ""%1"" может использоваться только как уточняемое значение + |в параметрах функции ""%2""'"), + Строка.Символы, + КлючевоеСловоСУчетомЯзыка("ЗначениеРазрешено", Контекст))); + Иначе + // "ПустаяСсылка" или "Null". + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Значение ""%1"" может использоваться только как уточняемое значение + |в параметрах функций проверки разрешений'"), + Строка.Символы)); + КонецЕсли; + + ИначеЕсли Строка.Тип = "ИмяТипа" Тогда + // "Число", "Строка", "Дата", "Булево". + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Имя типа ""%1"" может использоваться только, как параметр функции ""%2"" или + |как уточняемое значение в параметрах функций проверки разрешений'"), + Строка.Символы, + "Тип")); + Иначе + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Обработка ключевого слова ""%1"" не определена'"), Строка.Символы)); + КонецЕсли; + +КонецПроцедуры + +// Для процедур РазобратьВыражение, РазобратьОператор, РазобратьФункцию, РазобратьВыбор. +Процедура ДобавитьАргументФункциюВыборОператор(Контекст, ДобавляемоеОписание) + + // Текущий узел: Любой. + // Добавляемое описание: Поле, Значение, Константа, Не, Выбор, любая функция. + + Описание = Контекст.Описание; // См. ОписаниеУзла + + Если Описание = Неопределено Тогда + Контекст.Описание = ДобавляемоеОписание; + + ИначеЕсли Описание.Узел = "И" + Или Описание.Узел = "Или" Тогда + + Если Описание.Аргументы.Количество() = 1 Тогда + Описание.Аргументы.Добавить(ДобавляемоеОписание); + Иначе + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.Аргументы[1], ДобавляемоеОписание); + КонецЕсли; + + ИначеЕсли Описание.Узел = "Не" Тогда + + Если Не ЗначениеЗаполнено(Описание.Аргумент) Тогда + Описание.Аргумент = ДобавляемоеОписание; + Иначе + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.Аргумент, ДобавляемоеОписание); + КонецЕсли; + + ИначеЕсли Описание.Источник.Вид = "Операция" Тогда + + Если Не ЗначениеЗаполнено(Описание.ВторойАргумент) Тогда + Описание.ВторойАргумент = ДобавляемоеОписание; + // Проверка корректности аргументов выполняется + // в процедуре ОтметитьНекорректныеАргументыИЗапрещенныеУзлы. + Иначе + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Описание.ВторойАргумент, ДобавляемоеОписание); + КонецЕсли; + + ИначеЕсли СтрНайти(",Поле,Значение,Константа,В,ЕстьNull,Выбор,", "," + Описание.Узел + ",") > 0 + Или Описание.Источник.Тип = "Функция" Тогда + // Второй аргумент операции В уже разобран в процедуре РазобратьСоединительВ. + // Второй аргумент Null операции Есть уже разобран в функции ФункцииСВыражениямиВСкобках. + // Остальные узлы не имеют второго аргумента. + ОбработатьПропущеннуюЛогическуюОперацию(Контекст, Неопределено, ДобавляемоеОписание); + Иначе + ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не определена обработка узла ""%1""'"), Описание.Узел); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ДобавитьАргументФункциюВыборОператор +Процедура ОбработатьПропущеннуюЛогическуюОперацию(Контекст, ПоследнийАргументОписания, ДобавляемоеОписание) + + УстановитьОшибкуВСтроке(Контекст.Строка, НСтр("ru = 'Не указана логическая операция'")); + + // Восстановление. + ДополнительнаяСтрока = ДополнительнаяСтрока(Контекст.Строка, "И", Контекст); + + НовоеОписание = Новый Структура("Источник, Узел, Аргументы", ДополнительнаяСтрока, "И", Новый Массив); + НовоеОписание.Аргументы.Добавить(); + + ТекущаяСтрока = Контекст.Строка; + Контекст.Строка = ДополнительнаяСтрока; + + ВставитьСоединительСУчетомПриоритета(Контекст, + ПоследнийАргументОписания, НовоеОписание, НовоеОписание.Аргументы[0]); + + Контекст.Строка = ТекущаяСтрока; + + НовоеОписание.Аргументы.Добавить(ДобавляемоеОписание); + +КонецПроцедуры + +// Для процедуры РазобратьУсловие. +// +// Возвращаемое значение: +// Массив из СтрокаТаблицыЗначений +// +Функция ВыраженияВСкобкахВоВложениях(Строки, Контекст) + + Результат = Новый Массив; + + ТекущееВложение = Новый Структура("Строки", Результат); + Вложения = Новый Массив; + Вложения.Добавить(ТекущееВложение); + + Для Каждого Строка Из Строки Цикл + Если Строка.Символы = "(" Тогда + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + ИначеЕсли Строка.Символы = ")" Тогда + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, + НСтр("ru = 'Указана закрывающаяся скобка до открывающейся скобки'")); + Иначе + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст, Строка); + КонецЕсли; + Иначе + СтрокаДобавить(ТекущееВложение, Строка, Контекст); + КонецЕсли; + КонецЦикла; + + Пока Вложения.Количество() > 1 Цикл + ИндексПоследнегоВложения = Вложения.Количество() - 1; + Вложение = Вложения[ИндексПоследнегоВложения]; + Вложение.КонечнаяСтрока = Строка; + Вложения.Удалить(ИндексПоследнегоВложения); + УстановитьОшибкуВСтроке(Вложение, + НСтр("ru = 'Указана открывающаяся скобка без закрывающейся скобки'"), Истина); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для процедуры РазобратьУсловие. +// +// Параметры: +// Строки - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Функция ВыраженияВыборКогдаТогдаВоВложениях(Строки, Контекст) + + Результат = Новый Массив; + + ТекущееВложение = Новый Структура("Строки, Уточнение", Результат, ""); + Вложения = Новый Массив; + Вложения.Добавить(ТекущееВложение); + + Для Каждого ОписаниеСтроки Из Строки Цикл + Строка = СтрокаТаблицы(ОписаниеСтроки, Контекст); + + Если Строка.Вид <> "КлючевоеСлово" + Или Строка.Тип <> "СловоВыбора" Тогда + + Если ТекущееВложение.Уточнение = "Выбор" Тогда + СтрокаДобавить(СтрокаТаблицы(ТекущееВложение.Строки[0], Контекст), Строка, Контекст); + Иначе + СтрокаДобавить(ТекущееВложение, Строка, Контекст); + Если Строка.Символы = "(" Тогда + Строка.Строки = ВыраженияВыборКогдаТогдаВоВложениях(Строка.Строки, Контекст); + КонецЕсли; + КонецЕсли; + ИначеЕсли Строка.Уточнение = "Выбор" Тогда + Если Вложения.Количество() = 1 Тогда + // Стандартная обработка после условия. + Иначе + Если ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Выбор,Когда"), Истина); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда", Контекст); + КонецЕсли; + КонецЕсли; + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + ТекущееВложение.Строки.Добавить(ДополнительнаяСтрока(ТекущееВложение, "Выбор", Контекст)); + + ИначеЕсли Строка.Уточнение = "Когда" Тогда + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Когда,Выбор")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + // Стандартная обработка после условия. + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Когда,Тогда"), Истина); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе" + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" должно быть до ключевого слова ""%2""'"), "Когда,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + КонецЕсли; + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + ИначеЕсли Строка.Уточнение = "Тогда" Тогда + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Тогда,Выбор,Когда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Тогда,Когда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + // Стандартная обработка после условия. + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + УстановитьОшибкуВСтроке(ТекущееВложение, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слова ""%2""'"), "Тогда,Когда"), Истина); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда", Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе" + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" должно быть до ключевого слова ""%2""'"), "Тогда,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда", Контекст); + КонецЕсли; + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + ИначеЕсли Строка.Уточнение = "Иначе" Тогда + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"" и ""%4""'"), "Иначе,Выбор,Когда,Тогда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда,Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Иначе,Когда,Тогда")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда,Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Иначе,Тогда")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Тогда", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + // Стандартная обработка после условия. + + Иначе // ТекущееВложение.Уточнение = "Иначе" + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано повторно'"), "Иначе")); + КонецЕсли; + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст); + + Иначе // Строка.Уточнение = "Конец" + + Если Вложения.Количество() = 1 Тогда + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"", ""%4"" и ""%5""'"), "Конец,Выбор,Когда,Тогда,Иначе")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Выбор,Когда,Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Выбор" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"", ""%3"" и ""%4""'"), "Конец,Когда,Тогда,Иначе")); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Когда,Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевых слов ""%2"" и ""%3""'"), "Конец,Тогда,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'Ключевое слово ""%1"" указано до ключевого слова ""%2""'"), "Конец,Иначе")); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, "Иначе", Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе". + // Стандартная обработка после условия. + КонецЕсли; + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + КонецЕсли; + КонецЦикла; + + Пока Вложения.Количество() > 1 Цикл + ТекущееВложение = Вложения[Вложения.Количество() - 1]; + + Если ТекущееВложение.Уточнение = "Выбор" Тогда + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"", ""%3"", ""%4"" и ""%5""'"), "Выбор,Когда,Тогда,Иначе,Конец"); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Когда,Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Когда" Тогда + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"", ""%3"", ""%4""'"), "Когда,Тогда,Иначе,Конец"); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Тогда,Иначе", Контекст); + + ИначеЕсли ТекущееВложение.Уточнение = "Тогда" Тогда + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указаны ключевые слова ""%2"" и ""%3""'"), "Тогда,Иначе,Конец"); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + ВосстановитьСтруктуруВыбора(ТекущееВложение, Вложения, ТекущееВложение, "Иначе", Контекст); + + Иначе // ТекущееВложение.Уточнение = "Иначе" + ТекстОшибки = ПодставитьКлючевыеСловаВСтроку(Контекст, + НСтр("ru = 'После ключевого слова ""%1"" не указано ключевое слово ""%2""'"), "Иначе,Конец"); + КонецЕсли; + УстановитьОшибкуВСтроке(ТекущееВложение, ТекстОшибки, Истина); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для процедуры РазобратьУсловие. +// +// Параметры: +// Строки - Массив из см. СтрокаТаблицы.ОписаниеСтроки +// +Функция ФункцииСВыражениямиВСкобках(Строки, ВнутренниеДанные) + + Результат = Новый Массив; + СтрокаРезультата = Новый Структура("Строки", Результат); + + КоличествоСтрок = Строки.Количество(); + + Строка = Неопределено; + Индекс = 0; + Пока Индекс < КоличествоСтрок Цикл + ПредыдущаяСтрока = Строка; // СтрокаТаблицыЗначений из см. ТаблицаНаборовСимволов + Строка = СтрокаТаблицы(Строки[Индекс], ВнутренниеДанные); + + Если Строка.Символы = "(" Тогда + Строка.Строки = ФункцииСВыражениямиВСкобках(Строка.Строки, ВнутренниеДанные); + + ИначеЕсли Строка.Вид = "КлючевоеСлово" + И ( Строка.Тип = "Функция" + Или Строка.Уточнение = "В" ) Тогда + + СледующаяСтрока = ?(Индекс + 1 < Строки.Количество(), + СтрокаТаблицы(Строки[Индекс + 1], ВнутренниеДанные), Неопределено); + + Если Индекс + 1 < Строки.Количество() + И СледующаяСтрока.Символы = "(" Тогда + + Индекс = Индекс + 1; + Строка.Строки = ФункцииСВыражениямиВСкобках(СледующаяСтрока.Строки, ВнутренниеДанные); + Строка.КонечнаяСтрока = СледующаяСтрока.КонечнаяСтрока; + + Если Строка.Строки.Количество() = 0 Тогда + Если Строка.Тип = "Функция" Тогда + УстановитьОшибкуВСтроке(Строки[Индекс], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У функции ""%1"" не указано ни одного параметра'"), Строка.Символы), Истина); + Иначе + УстановитьОшибкуВСтроке(Строки[Индекс], СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В списке значений операции ""%1"" не указано ни одного значения'"), Строка.Символы), Истина); + КонецЕсли; + КонецЕсли; + Иначе + Строка.Строки = Новый Массив; + Если Строка.Тип = "Функция" Тогда + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После функции ""%1"" не указаны параметры в скобках'"), Строка.Символы), Истина); + Иначе + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'После ключевого слова ""%1"" не указаны значения в скобках'"), Строка.Символы), Истина); + КонецЕсли; + КонецЕсли; + + ИначеЕсли Строка.Вид = "КлючевоеСлово" + И Строка.Уточнение = "Есть" Тогда + + СледующаяСтрока = ?(Индекс + 1 < Строки.Количество(), + СтрокаТаблицы(Строки[Индекс + 1], ВнутренниеДанные), Неопределено); + + Если Индекс + 1 < Строки.Количество() + И СледующаяСтрока.Вид = "КлючевоеСлово" + И СледующаяСтрока.Уточнение = "Null" Тогда + + Индекс = Индекс + 1; + СтрокаДобавить(Строка, СледующаяСтрока, ВнутренниеДанные); + Иначе + Строка.Строки = Новый Массив; + УстановитьОшибкуВСтроке(Строка, ПодставитьКлючевыеСловаВСтроку(ВнутренниеДанные, + НСтр("ru = 'После ключевого слова ""%2"" не указано ключевое слово ""%1""'"), + "Null", + Строка.Символы), + Истина); + КонецЕсли; + + ИначеЕсли Строка.Вид = "Имя" + И СтрНачинаетсяС(Строка.Символы, ".") + И ПредыдущаяСтрока <> Неопределено Тогда + + Если ПредыдущаяСтрока <> Неопределено + И ПредыдущаяСтрока.Вид = "КлючевоеСлово" + И ПредыдущаяСтрока.Уточнение = "Выразить" Тогда + + Строка.Тип = "ДополнениеКВыразить"; + СтрокаДобавить(ПредыдущаяСтрока, Строка, ВнутренниеДанные); + Индекс = Индекс + 1; + Продолжить; + Иначе + УстановитьОшибкуВСтроке(Строка, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Имя поля не может начинаться с символа "".""'"), Строка.Символы)); + КонецЕсли; + КонецЕсли; + + СтрокаДобавить(СтрокаРезультата, Строка, ВнутренниеДанные); + Индекс = Индекс + 1; + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Для функций ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. +Процедура ДобавитьВложение(Строка, Вложения, ТекущееВложение, Контекст) + + СтрокаДобавить(ТекущееВложение, Строка, Контекст); + ТекущееВложение = Строка; + Вложения.Добавить(ТекущееВложение); + +КонецПроцедуры + +// Для функций ВыраженияВСкобкахВоВложениях, ВыраженияВыборКогдаТогдаВоВложениях. +Процедура УдалитьПоследнееВложение(Вложения, ТекущееВложение, Контекст, КонечнаяСтрока = Неопределено) + + Если КонечнаяСтрока = Неопределено Тогда + Если ТекущееВложение.Строки.Количество() = 0 Тогда + КонечнаяСтрока = ТекущееВложение; + Иначе + КонечнаяСтрока = СтрокаТаблицы(ТекущееВложение.Строки[ТекущееВложение.Строки.Количество() - 1], Контекст); + Если КонечнаяСтрока.КонечнаяСтрока <> Неопределено Тогда + КонечнаяСтрока = СтрокаТаблицы(КонечнаяСтрока.КонечнаяСтрока, Контекст); + КонецЕсли; + КонецЕсли; + КонецЕсли; + + ТекущееВложение.КонечнаяСтрока = Контекст.ТаблицаНаборовСимволов.Индекс(КонечнаяСтрока); + + ИндексПоследнегоВложения = Вложения.Количество() - 1; + Вложения.Удалить(ИндексПоследнегоВложения); + ТекущееВложение = Вложения[ИндексПоследнегоВложения - 1]; + +КонецПроцедуры + +// Для функции ВыраженияВыборКогдаТогдаВоВложениях. +Процедура ВосстановитьСтруктуруВыбора(Строка, Вложения, ТекущееВложение, СписокНедостающихСлов, Контекст) + + НедостающиеСлова = СтрРазделить(СписокНедостающихСлов, ",", Ложь); + + Для Каждого НедостающееСлово Из НедостающиеСлова Цикл + НоваяСтрока = ДополнительнаяСтрока(Строка, НедостающееСлово, Контекст); + ТекущееВложение.Строки.Добавить(НоваяСтрока); + + Если НедостающееСлово = "Выбор" Тогда + ТекущееВложение = НоваяСтрока; + Вложения.Добавить(ТекущееВложение); + КонецЕсли; + КонецЦикла; + + Если НедостающееСлово <> "Выбор" Тогда + ТекущееВложение = НоваяСтрока; + Вложения.Добавить(ТекущееВложение); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ОбработатьПропущеннуюЛогическуюОперацию, ВыраженияВыборКогдаТогдаВоВложениях, +// ВосстановитьСтруктуруВыбора и для функции ПараметрыРазделенныеЗапятыми. +// +// Возвращаемое значение: +// Структура: +// * Символы - Строка +// * Вид - Строка +// * Тип - Строка +// * Приоритет - Число +// * Уточнение - Строка +// * Строки - Массив из Число - индексы строк ТаблицаНаборовСимволов +// * КонечнаяСтрока - Число - индекс строки ТаблицаНаборовСимволов +// * ПозицияОшибки - Число +// * ТекстОшибки - Строка +// +Функция ДополнительнаяСтрока(Строка, Уточнение = "", Контекст = Неопределено) + + НоваяСтрока = Новый Структура; + НоваяСтрока.Вставить("Символы"); + НоваяСтрока.Вставить("Вид"); + НоваяСтрока.Вставить("Тип"); + НоваяСтрока.Вставить("Приоритет"); + НоваяСтрока.Вставить("Уточнение", Уточнение); + НоваяСтрока.Вставить("Строки", Новый Массив); + НоваяСтрока.Вставить("КонечнаяСтрока"); + НоваяСтрока.Вставить("ПозицияОшибки"); + НоваяСтрока.Вставить("ТекстОшибки"); + + СвойстваСлова = ?(Контекст = Неопределено, + Неопределено, Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(Уточнение))); + + Если СвойстваСлова <> Неопределено Тогда + НоваяСтрока.Вид = "КлючевоеСлово"; + НоваяСтрока.Тип = СвойстваСлова.Тип; + НоваяСтрока.Приоритет = СвойстваСлова.Приоритет; + КонецЕсли; + + Возврат НоваяСтрока; + +КонецФункции + +// Для процедур РазобратьДополнительныеТаблицы, РазобратьУсловиеОграничения. +// +// Параметры: +// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура ИзменитьВидКлючевогоСловаСписокНаИмя(СтрокиЧасти, ИсключаемаяСтрока = Неопределено) + + Для Каждого Строка Из СтрокиЧасти Цикл + Если Строка = ИсключаемаяСтрока + Или Строка.Вид <> "КлючевоеСлово" + Или Строка.Уточнение <> "ЭтотСписок" Тогда + Продолжить; + КонецЕсли; + Строка.Вид = "Имя"; + Строка.Уточнение = ""; + КонецЦикла; + +КонецПроцедуры + +// Для процедур РазобратьДополнительныеТаблицы, РазобратьСоединение. +// +// Параметры: +// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура УстановитьПсевдоним(СтрокаЧасти, ОписаниеСоединения, ВнутренниеДанные) + + Если ЗначениеЗаполнено(СтрокаЧасти.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + ПозицияТочки = СтрНайти(СтрокаЧасти.Символы, "."); + Если ПозицияТочки > 0 Тогда + СтрокаЧасти.ПозицияОшибки = ПозицияТочки - 1; + СтрокаЧасти.ТекстОшибки = + НСтр("ru = 'Псевдоним не может содержать символа "".""'"); + + ИначеЕсли ТипЗнч(ОписаниеСоединения) = Тип("Строка") Тогда + ОписаниеСоединения = СтрокаЧасти.Символы; + ВнутренниеДанные.Псевдонимы.Вставить(ВРег(СтрокаЧасти.Символы), + Новый Структура("Псевдоним, Таблица", СтрокаЧасти.Символы)); + Иначе + ОписаниеСоединения.Псевдоним = СтрокаЧасти.Символы + "Псевдоним"; + Если ВнутренниеДанные.Псевдонимы.Получить(ВРег(СтрокаЧасти.Символы)) = Неопределено Тогда + Если ЗначениеЗаполнено(ОписаниеСоединения.Таблица) Тогда + ВнутренниеДанные.Псевдонимы.Вставить(ВРег(СтрокаЧасти.Символы), + Новый Структура("Псевдоним, Таблица", + ОписаниеСоединения.Псевдоним, ОписаниеСоединения.Таблица)); + КонецЕсли; + Иначе + СтрокаЧасти.ТекстОшибки = НСтр("ru = 'Псевдоним повторяется'"); + КонецЕсли; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры РазобратьСоединение. +// +// Параметры: +// СтрокиЧасти - Массив из СтрокаТаблицыЗначений: см. ТаблицаНаборовСимволов +// +Процедура УстановитьИмяТаблицы(СтрокаЧасти, ОписаниеСоединения, ВнутренниеДанные) + + Если ЗначениеЗаполнено(СтрокаЧасти.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если СтрНачинаетсяС(СтрокаЧасти.Символы, ".") Тогда + СтрокаЧасти.ТекстОшибки = + НСтр("ru = 'Имя таблицы не может начинаться с символа "".""'"); + Возврат; + КонецЕсли; + + Если СтрЧислоВхождений(СтрокаЧасти.Символы, ".") > 2 Тогда + + ПозицияТочки = СтрНайти(СтрокаЧасти.Символы, "."); + ПозицияТочки = ПозицияТочки + СтрНайти(Сред(СтрокаЧасти.Символы, ПозицияТочки + 1), "."); + + ПозицияТочки = ПозицияТочки + СтрНайти(Сред(СтрокаЧасти.Символы, ПозицияТочки + 1), "."); + СтрокаЧасти.ТекстОшибки = + НСтр("ru = 'Полное имя таблицы не может содержать более двух символов "".""'"); + + СтрокаЧасти.ПозицияОшибки = ПозицияТочки - 1; + Возврат; + КонецЕсли; + + ОписаниеСоединения.Таблица = СтрокаЧасти.Символы; + + ДобавитьТребуемуюТаблицуКакИсточникДанных(ВнутренниеДанные, ОписаниеСоединения.Таблица, СтрокаЧасти); + +КонецПроцедуры + +// Для процедуры УстановитьИмяТаблицы. +Процедура ДобавитьТребуемуюТаблицуКакИсточникДанных(Контекст, Таблица, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); + + Если СвойстваИмени.ЧислоЧастейИмени < 2 + Или СвойстваИмени.ЧислоЧастейИмени > 3 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени присоединяемой таблицы должна быть одна или две точки'")); + Возврат; + КонецЕсли; + + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), СвойстваИмени.ИмяТипа, Таблица)); + Возврат; + КонецЕсли; + + Если СвойстваИмени.ЧислоЧастейИмени = 3 Тогда + СвойстваУточнения = СвойстваИмени.СвойстваТипаТаблиц.УточнениеТаблиц.Получить( + ВРег(СвойстваИмени.Расширение)); + + Если СвойстваУточнения <> Неопределено + И СвойстваУточнения.Использование <> "Разрешено" Тогда + + Если СвойстваУточнения.Использование = "Недопустимо" Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Недопустимо использовать таблицы ""%1"" группы таблиц ""%2""'"), + СвойстваИмени.Расширение, СвойстваИмени.ИмяТипа)); + Иначе + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Запрещено присоединять таблицы ""%1"" группы таблиц ""%2""'"), + СвойстваИмени.Расширение, СвойстваИмени.ИмяТипа)); + КонецЕсли; + Возврат; + КонецЕсли; + КонецЕсли; + + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); + Свойства.Источники.Добавить(Источник); + +КонецПроцедуры + +// Для процедур ВыделитьПсевдонимПоля, РазобратьПервыйПараметрПроверочнойФункции, +// РазобратьДополнительныйПараметрПроверочнойФункции, РазобратьПараметрыФункцииЗначениеИлиФункцииТип. +// +Процедура ДобавитьТребуемуюТаблицуКакСсылочныйТип(Контекст, Таблица, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); + + Если СвойстваИмени.ЧислоЧастейИмени <> 2 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени таблицы, указанной в качестве типа, должна быть одна точка'")); + Возврат; + КонецЕсли; + + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), СвойстваИмени.ИмяТипа, Таблица)); + Возврат; + КонецЕсли; + + Если Не СвойстваИмени.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Группа таблиц ""%1"" не входит в состав ссылочных типов'"), СвойстваИмени.ИмяТипа, Таблица)); + Возврат; + КонецЕсли; + + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); + Свойства.Источники.Добавить(Источник); + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыФункцииЗначениеИлиФункцииТип. +Процедура ДобавитьТребуемыйПредопределенныйЭлемент(Контекст, ПолноеИмяПредопределенного, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, ПолноеИмяПредопределенного); + + Если СвойстваИмени.ЧислоЧастейИмени <> 3 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени предопределенного значения должно быть две точки'")); + Возврат; + КонецЕсли; + + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Некорректное начало ""%1"" имени таблицы ""%2""'"), + СвойстваИмени.ИмяТипа, + СвойстваИмени.ИмяТипа + "." + СвойстваИмени.ИмяБезТипа)); + Возврат; + КонецЕсли; + + Если Не СвойстваИмени.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Группа таблиц ""%1"" не входит в состав ссылочных типов'"), СвойстваИмени.ИмяТипа)); + Возврат; + КонецЕсли; + + СвойстваСлова = Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(СвойстваИмени.Расширение)); // См. СвойстваСлова + + Если Не СвойстваИмени.СвойстваТипаТаблиц.ЕстьПредопределенные + И Не СвойстваИмени.ИмяТипа = "Перечисление" + И ( СвойстваСлова = Неопределено + Или СвойстваСлова.Идентификатор <> "ПустаяСсылка") Тогда + + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'В группе таблиц ""%1"" нет предопределенных элементов'"), СвойстваИмени.ИмяТипа)); + Возврат; + КонецЕсли; + + СвойстваИмениТаблицы = СвойстваИмениТаблицы(Контекст, СвойстваИмени.ИмяТипа + "." + СвойстваИмени.ИмяБезТипа); + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмениТаблицы, Истина); + + СвойстваПредопределенного = Свойства.Предопределенные.Получить(ВРег(СвойстваИмени.Расширение)); + Если СвойстваПредопределенного = Неопределено Тогда + СвойстваПредопределенного = НовыеСвойстваПредопределенного(); + СвойстваПредопределенного.Вставить("ИмяСуществует", Ложь); + СвойстваПредопределенного.Вставить("Источники", Новый Массив); + Свойства.Предопределенные.Вставить(ВРег(СвойстваИмени.Расширение), СвойстваПредопределенного); + КонецЕсли; + СвойстваПредопределенного.Источники.Добавить(Источник); + +КонецПроцедуры + +// Для процедуры РазобратьПараметрыФункцииРольДоступна. +Процедура ПроверитьИмяРоли(ИмяРоли, Источник) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если СтрНайти(ИмяРоли, ".") > 0 Тогда + УстановитьОшибкуВСтроке(Источник, + НСтр("ru = 'В имени роли не должно быть точек'")); + Возврат; + КонецЕсли; + + Если Метаданные.Роли.Найти(ИмяРоли) = Неопределено Тогда + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Роль ""%1"" отсутствует в метаданных'"), ИмяРоли)); + Возврат; + КонецЕсли; + +КонецПроцедуры + +Процедура ПроверитьИмяПраваОбъектаМетаданных(ИмяПрава, ИсточникПрава, ИмяОбъекта, ИсточникОбъекта) + + Если ЗначениеЗаполнено(ИсточникПрава.ТекстОшибки) + Или ИсточникОбъекта <> Неопределено + И ЗначениеЗаполнено(ИсточникОбъекта.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если СтрНайти(ИмяПрава, ".") > 0 Тогда + УстановитьОшибкуВСтроке(ИсточникПрава, + НСтр("ru = 'В имени права не должно быть точек'")); + Возврат; + КонецЕсли; + + ИмяСтандартногоРеквизита = Неопределено; + ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава(ИмяОбъекта, ИмяСтандартногоРеквизита); + Если ОбъектМетаданных = Неопределено Тогда + УстановитьОшибкуВСтроке(ИсточникОбъекта, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Объект метаданных ""%1"" не существует'"), ИмяОбъекта)); + Возврат; + КонецЕсли; + + ТекстОшибки = ""; + Попытка + ПравоДоступа(ИмяПрава, ОбъектМетаданных, , ИмяСтандартногоРеквизита); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + + Если ЗначениеЗаполнено(ТекстОшибки) Тогда + УстановитьОшибкуВСтроке(ИсточникПрава, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось проверить право ""%1"" объекта метаданных ""%2"" по причине: + |%3'"), ИмяПрава, ИмяОбъекта, ТекстОшибки)); + Возврат; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьИмяПраваОбъектаМетаданных +Функция ОбъектМетаданныхПоПолномуИмениДляПроверкиПрава(ПолноеИмя, ИмяСтандартногоРеквизита = Неопределено) + + ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмя); + Если ОбъектМетаданных <> Неопределено Тогда + Возврат ОбъектМетаданных; + КонецЕсли; + + ЧастиИмени = СтрРазделить(ПолноеИмя, "."); + Если ЧастиИмени.Количество() < 4 Тогда + Возврат Неопределено; + КонецЕсли; + + ИмяОсновногоОбъектаМетаданных = ЧастиИмени[0] + "." + ЧастиИмени[1]; + ОсновнойОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОсновногоОбъектаМетаданных); + Если ОсновнойОбъектМетаданных = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Если ВРег(ЧастиИмени[2]) = ВРег("СтандартнаяТабличнаяЧасть") + Или ВРег(ЧастиИмени[2]) = ВРег("StandardTabularSection") Тогда // @Non-NLS + + Свойства = Новый Структура("СтандартныеТабличныеЧасти"); + ЗаполнитьЗначенияСвойств(Свойства, ОсновнойОбъектМетаданных); + Если Свойства.СтандартныеТабличныеЧасти = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + ИмяСтандартнойТабличнойЧасти = ЧастиИмени[3]; + Для Каждого СтандартнаяТабличнаяЧасть Из Свойства.СтандартныеТабличныеЧасти Цикл + Если ВРег(СтандартнаяТабличнаяЧасть.Имя) = ВРег(ИмяСтандартнойТабличнойЧасти) Тогда + СтандартныеРеквизиты = СтандартнаяТабличнаяЧасть.СтандартныеРеквизиты; + Прервать; + КонецЕсли; + КонецЦикла; + Если СтандартныеРеквизиты = Неопределено + Или ЧастиИмени.Количество() <> 6 Тогда + Возврат Неопределено; + КонецЕсли; + ЧастиИмени.Удалить(0); + ЧастиИмени.Удалить(0); + ВладелецСтандартныхРеквизитов = СтандартнаяТабличнаяЧасть; + Иначе + ВладелецСтандартныхРеквизитов = ОсновнойОбъектМетаданных; + КонецЕсли; + + Если ВРег(ЧастиИмени[2]) <> ВРег("СтандартныйРеквизит") + И ВРег(ЧастиИмени[2]) <> ВРег("StandardAttribute") Тогда // @Non-NLS + Возврат Неопределено; + КонецЕсли; + + Свойства = Новый Структура("СтандартныеРеквизиты"); + ЗаполнитьЗначенияСвойств(Свойства, ВладелецСтандартныхРеквизитов); + Если Свойства.СтандартныеРеквизиты = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + ИмяСтандартногоРеквизита = ЧастиИмени[3]; + СтандартныеРеквизиты = Свойства.СтандартныеРеквизиты; // ОписанияСтандартныхРеквизитов + + Для Каждого СтандартныйРеквизит Из СтандартныеРеквизиты Цикл + Если ВРег(СтандартныйРеквизит.Имя) = ВРег(ИмяСтандартногоРеквизита) Тогда + Если ЗначениеЗаполнено(ИмяСтандартнойТабличнойЧасти) Тогда + ИмяСтандартногоРеквизита = ИмяСтандартнойТабличнойЧасти + "." + ИмяСтандартногоРеквизита; + КонецЕсли; + Возврат ОсновнойОбъектМетаданных; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +// Для процедур ОтметитьНекорректныеАргументыИЗапрещенныеУзлы, ВыделитьПсевдонимПоля, +// ДобавитьТипыВидовДоступаПользователиИВнешниеПользователиДляПроверкиОтсутствия. +// +Процедура ДобавитьТребуемоеПолеТаблицы(Контекст, Таблица, ИмяПоля, Источник, + ТипПоля = "", ИсточникТипаПоля = Неопределено, УзелПоле = Неопределено) + + Если ЗначениеЗаполнено(Источник.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваИмени = СвойстваИмениТаблицы(Контекст, Таблица); + Если СвойстваИмени.СвойстваТипаТаблиц = Неопределено Тогда + + Если СвойстваИмени.ЭтоОсновнаяТаблица + И Не Контекст.Свойство("ОшибкаНаПервоеПолеОсновнойТаблицыУстановлена") Тогда + + Контекст.Вставить("ОшибкаНаПервоеПолеОсновнойТаблицыУстановлена"); + УстановитьОшибкуВСтрокеИмениПоля(Контекст, Источник, + НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , + Контекст.ОсновнаяТаблица); + КонецЕсли; + + Возврат; + КонецЕсли; + + Свойства = СвойстваТребуемойТаблицы(Контекст, СвойстваИмени); + + СвойстваПоля = Свойства.Поля.Получить(ВРег(ИмяПоля)); + Если СвойстваПоля = Неопределено Тогда + СвойстваПоля = НовыеСвойстваПоля(); + СвойстваПоля.Вставить("ПолеСОшибкой", 0); + СвойстваПоля.Вставить("ВидОшибки", ""); + СвойстваПоля.Вставить("Коллекция", ""); + СвойстваПоля.Вставить("СодержитТипы", Новый Соответствие); + СвойстваПоля.Вставить("Источники", Новый Соответствие); + СвойстваПоля.Вставить("УзлыПоле", Новый Массив); + Свойства.Поля.Вставить(ВРег(ИмяПоля), СвойстваПоля); + + Если Свойства.Свойство("ПервоеПоле") + И Свойства.ПервоеПоле = Неопределено + И Источник <> Неопределено Тогда + + СвойстваПоля.Вставить("ПервыйИсточник", Новый Структура("Ключ,Значение", Источник, Таблица)); + Свойства.ПервоеПоле = СвойстваПоля; + КонецЕсли; + КонецЕсли; + СвойстваПоля.Источники.Вставить(Источник, Таблица); + Если УзелПоле <> Неопределено Тогда + СвойстваПоля.УзлыПоле.Добавить(УзелПоле); + КонецЕсли; + + Если Не ЗначениеЗаполнено(ТипПоля) Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ИсточникТипаПоля) = Тип("СтрокаТаблицыЗначений") + И ЗначениеЗаполнено(ИсточникТипаПоля.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + СвойстваТипа = СвойстваПоля.СодержитТипы.Получить(ВРег(ТипПоля)); + Если СвойстваТипа = Неопределено Тогда + СоставИмени = СтрРазделить(ТипПоля, "."); + СвойстваТипаТаблиц = Контекст.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0])); + Если СвойстваТипаТаблиц = Неопределено Тогда + ИмяТипа = ТипПоля; + ИмяКоллекцииТипа = ""; + ИмяОбъектаКоллекцииТипа = ""; + Иначе + ИмяТипа = СвойстваТипаТаблиц.ЯзыкРусский + "Ссылка." + СоставИмени[1]; // @Non-NLS + ИмяКоллекцииТипа = СвойстваТипаТаблиц.ИмяКоллекции; + ИмяОбъектаКоллекцииТипа = СоставИмени[1]; + КонецЕсли; + СвойстваТипа = Новый Структура; + СвойстваТипа.Вставить("СодержитТип", Ложь); + СвойстваТипа.Вставить("ИмяТипа", ИмяТипа); + СвойстваТипа.Вставить("ИмяКоллекцииТипа", ИмяКоллекцииТипа); + СвойстваТипа.Вставить("ИмяОбъектаКоллекцииТипа", ИмяОбъектаКоллекцииТипа); + СвойстваТипа.Вставить("Источники", Новый Соответствие); + СвойстваПоля.СодержитТипы.Вставить(ВРег(ТипПоля), СвойстваТипа); + КонецЕсли; + СвойстваТипа.Источники.Вставить(ИсточникТипаПоля, Источник); + +КонецПроцедуры + +// Для процедур ДобавитьТребуемуюТаблицуКакИсточникДанных, ДобавитьТребуемуюТаблицуКакСсылочныйТип, +// ДобавитьТребуемыйПредопределенныйЭлемент, ДобавитьТребуемоеПолеТаблицы. +// +Функция СвойстваИмениТаблицы(Контекст, ПолноеИмя) + + Если ЗначениеЗаполнено(ПолноеИмя) Тогда + Таблица = ПолноеИмя; + Иначе + Таблица = Контекст.ОсновнаяТаблица; + КонецЕсли; + + СоставИмени = СтрРазделить(Таблица, ".", Ложь); + + Свойства = Новый Структура; + Свойства.Вставить("ЧислоЧастейИмени", СоставИмени.Количество()); + Свойства.Вставить("ИмяТипа", СоставИмени[0]); + Свойства.Вставить("ИмяБезТипа", ?(СоставИмени.Количество() > 1, СоставИмени[1], Неопределено)); + Свойства.Вставить("Расширение", ?(СоставИмени.Количество() = 3, СоставИмени[2], Неопределено)); + Свойства.Вставить("ЭтоОсновнаяТаблица", ВРег(Таблица) = ВРег(Контекст.ОсновнаяТаблица)); + Свойства.Вставить("СвойстваТипаТаблиц", + Контекст.СинтаксисЯзыка.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставИмени[0]))); + + Возврат Свойства; + +КонецФункции + +// Для процедур ДобавитьТребуемуюТаблицуКакИсточникДанных, ДобавитьТребуемуюТаблицуКакСсылочныйТип, +// ДобавитьТребуемыйПредопределенныйЭлемент, ДобавитьТребуемоеПолеТаблицы. +// +Функция СвойстваТребуемойТаблицы(Контекст, СвойстваИмени, БезРасширения = Ложь) + + ИмяКоллекции = СвойстваИмени.СвойстваТипаТаблиц.ИмяКоллекции; + + СоставКоллекции = Контекст.ПоляТаблиц.Получить(ИмяКоллекции); + Если СоставКоллекции = Неопределено Тогда + СоставКоллекции = НовыйСоставКоллекции(); + Контекст.ПоляТаблиц.Вставить(ИмяКоллекции, СоставКоллекции); + КонецЕсли; + + Свойства = СоставКоллекции.Получить(ВРег(СвойстваИмени.ИмяБезТипа)); + Если Свойства = Неопределено Тогда + Свойства = НовыеСвойстваТаблицы(); + Свойства.Вставить("ТаблицаСуществует", Ложь); + Свойства.Вставить("ЭтоОсновнаяТаблица", СвойстваИмени.ЭтоОсновнаяТаблица); + Свойства.Вставить("Источники", Новый Массив); + Свойства.Вставить("Поля", Новый Соответствие); + Свойства.Вставить("Предопределенные", Новый Соответствие); + Свойства.Вставить("Расширения", Новый Соответствие); + Если СвойстваИмени.ЭтоОсновнаяТаблица И СвойстваИмени.Расширение = Неопределено Тогда + Свойства.Вставить("ПервоеПоле"); + КонецЕсли; + СоставКоллекции.Вставить(ВРег(СвойстваИмени.ИмяБезТипа), Свойства); + КонецЕсли; + + Если СвойстваИмени.Расширение = Неопределено Или БезРасширения Тогда + Возврат Свойства; + КонецЕсли; + + СвойстваРасширения = Свойства.Расширения.Получить(ВРег(СвойстваИмени.Расширение)); + Если СвойстваРасширения = Неопределено Тогда + СвойстваРасширения = НовыеСвойстваРасширения(); + СвойстваРасширения.Вставить("ТаблицаСуществует", Ложь); + СвойстваРасширения.Вставить("Источники", Новый Массив); + СвойстваРасширения.Вставить("Поля", Новый Соответствие); + Если СвойстваИмени.ЭтоОсновнаяТаблица Тогда + СвойстваРасширения.Вставить("ПервоеПоле"); + КонецЕсли; + Свойства.Расширения.Вставить(ВРег(СвойстваИмени.Расширение), СвойстваРасширения); + КонецЕсли; + + Возврат СвойстваРасширения; + +КонецФункции + +// Для процедур и функций ЧастиОграничения, РазобратьДополнительныеТаблицы, РазобратьСоединение, +// РазобратьУсловиеОграничения, ВыраженияВыборКогдаТогдаВоВложениях. +// +Функция ПодставитьКлючевыеСловаВСтроку(Контекст, Строка, СписокСлов, ПараметрОдин = "", ПараметрДва = "", ПараметрТри = "") + + Слова = СтрРазделить(СписокСлов, ",", Ложь); + СловаДляПодстановки = Новый Соответствие; + + Для Каждого Слово Из Слова Цикл + СловаДляПодстановки.Вставить(Слова.Найти(Слово), + КлючевоеСловоСУчетомЯзыка(СокрЛП(Слово), Контекст)); + КонецЦикла; + + Индекс = СловаДляПодстановки.Количество(); + СловаДляПодстановки.Вставить(Индекс, ПараметрОдин); + СловаДляПодстановки.Вставить(Индекс + 1, ПараметрДва); + СловаДляПодстановки.Вставить(Индекс + 2, ПараметрТри); + + Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Строка, + СловаДляПодстановки[0], СловаДляПодстановки[1], СловаДляПодстановки[2], + СловаДляПодстановки[3], СловаДляПодстановки[4], СловаДляПодстановки[5], + СловаДляПодстановки[6], СловаДляПодстановки[7], СловаДляПодстановки[8]); + +КонецФункции + +// Для процедур РазобратьДополнительныеТаблицы, РазобратьСоединение, РазобратьУсловиеОграничения. +Функция КлючевоеСловоСУчетомЯзыка(ИдентификаторСлова, Контекст) + + СвойстваСлова = Контекст.СинтаксисЯзыка.СловаЯзыка.Получить(ВРег(ИдентификаторСлова)); + + Если ВариантВстроенногоЯзыкаРусский() Тогда + Слово = СвойстваСлова.ЯзыкРусский; + Иначе + Слово = СвойстваСлова.ЯзыкАнглийский; + КонецЕсли; + + Если СвойстваСлова.ВерхнийРегистр Тогда + Слово = ВРег(Слово); + КонецЕсли; + + Возврат Слово; + +КонецФункции + +#КонецОбласти + +#Область АнализИменТаблицИПолейТаблиц + +// Проверка таблиц, полей таблиц и типов полей, найденных при разборе текста ограничения. +// Аналогичная процедура реализуется в СППР. +// +// Параметры: +// РазобранноеОграничение - см. РазобранноеОграничение +// +Процедура ПроверитьТаблицыПоляИТипыПолей(РазобранноеОграничение) + + Контекст = Новый Структура; + Контекст.Вставить("ТипыТаблиц", УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц); + + Для Каждого ТипТаблиц Из РазобранноеОграничение.ПоляТаблиц Цикл + КоллекцияТаблиц = Метаданные[ТипТаблиц.Ключ]; // КоллекцияОбъектовМетаданных + + Для Каждого ПоляТаблицы Из ТипТаблиц.Значение Цикл + + МетаданныеТаблицы = КоллекцияТаблиц.Найти(ПоляТаблицы.Ключ); + Если МетаданныеТаблицы = Неопределено Тогда + Продолжить; + КонецЕсли; + ПоляТаблицы.Значение.ТаблицаСуществует = Истина; + + Контекст.Вставить("МетаданныеТаблицы", МетаданныеТаблицы); + Контекст.Вставить("СвойстваТипаТаблиц", Контекст.ТипыТаблиц.ПоКоллекциям.Получить(ТипТаблиц.Ключ)); + Контекст.Вставить("ЭтоОсновнаяТаблица", ПоляТаблицы.Значение.ЭтоОсновнаяТаблица); + + Для Каждого ПолеТаблицы Из ПоляТаблицы.Значение.Поля Цикл + ОписаниеПоля = Новый Структура; + ОписаниеПоля.Вставить("СоставИмени", СтрРазделить(ПолеТаблицы.Ключ, ".")); + ОписаниеПоля.Вставить("Свойства", ПолеТаблицы.Значение); + ОписаниеПоля.Вставить("ТипПоля", Новый ОписаниеТипов); + ПроверитьПолеТаблицы(ОписаниеПоля, Контекст); + Если ОписаниеПоля.Свойства.ПолеСОшибкой = 0 Тогда + ПроверитьТипыПоля(ОписаниеПоля, Контекст); + КонецЕсли; + КонецЦикла; + + ПроверитьРасширенияТаблицы(ПоляТаблицы, Контекст); + ПроверитьПредопределенныеЗначенияТаблицы(ПоляТаблицы, Контекст); + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедур ПроверитьТаблицыПоляИТипыПолей, ПроверитьСледующееПолеЧерезТочку. +Процедура ПроверитьПолеТаблицы(ОписаниеПоля, Контекст, Индекс = 0, ПервыйВызов = Истина) + + СоставИмени = ОписаниеПоля.СоставИмени; + СвойстваПоля = ОписаниеПоля.Свойства; + + УточнениеПоля = Контекст.СвойстваТипаТаблиц.УточнениеПолей.Получить(ВРег(СоставИмени[Индекс])); + + Если УточнениеПоля <> Неопределено + И УточнениеПоля.Использование <> "Разрешено" Тогда + + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = УточнениеПоля; + Возврат; + КонецЕсли; + + Свойства = СвойстваПоляИлиТабличнойЧасти(СоставИмени[Индекс], Контекст, Индекс = 0); + Если Свойства = Неопределено Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "НеНайдено"; + Возврат; + КонецЕсли; + Если Индекс = 0 Тогда + СвойстваПоля.Коллекция = Свойства.Коллекция; + КонецЕсли; + + Если Свойства.ЭтоТабличнаяЧасть Тогда + Если Индекс > 0 Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "ТабличнаяЧастьПослеТочки"; + Возврат; + КонецЕсли; + Если Не Контекст.ЭтоОсновнаяТаблица Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "ТабличнаяЧастьДополнительнойТаблицы"; + Возврат; + КонецЕсли; + Если Индекс + 1 = СоставИмени.Количество() Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "ТабличнаяЧастьБезПоля"; + Возврат; + КонецЕсли; + Индекс = Индекс + 1; + Свойства = СвойстваПоляТабличнойЧасти(СоставИмени[Индекс], + Свойства.Метаданные, Свойства.Коллекция, Контекст.МетаданныеТаблицы); + Если Свойства = Неопределено Тогда + СвойстваПоля.ПолеСОшибкой = Индекс + 1; + СвойстваПоля.ВидОшибки = "НеНайдено"; + Возврат; + КонецЕсли; + КонецЕсли; + + ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, Свойства, Контекст); + + Если ПервыйВызов Тогда + ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля); + КонецЕсли; + +КонецПроцедуры + +// Для процедур ПроверитьПолеТаблицы и ПроверитьРасширенияТаблицы. +Процедура ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст) + + ДобавитьТипыПоляДополнительно(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст); + + Индекс = Индекс + 1; + Если Индекс = ОписаниеПоля.СоставИмени.Количество() Тогда + ОписаниеПоля.ТипПоля = Новый ОписаниеТипов(ОписаниеПоля.ТипПоля, СвойстваТекущегоПоля.Тип.Типы()); + Возврат; + КонецЕсли; + + СвойстваПоля = ОписаниеПоля.Свойства; + ПолеНайдено = Ложь; + + Если ОписаниеПоля.Свойство("ТаблицыСледующегоПоля") Тогда + // См. процедуру ДобавитьТипыПоляДополнительно. + Если ОписаниеПоля.ТаблицыСледующегоПоля.Количество() < Индекс + 1 Тогда + ТаблицыСледующегоПоля = Новый Массив; + ОписаниеПоля.ТаблицыСледующегоПоля.Добавить(ТаблицыСледующегоПоля); + Иначе + ТаблицыСледующегоПоля = ОписаниеПоля.ТаблицыСледующегоПоля[Индекс]; + КонецЕсли; + КонецЕсли; + + Для Каждого Тип Из СвойстваТекущегоПоля.Тип.Типы() Цикл + Если Не ОбщегоНазначения.ЭтоСсылка(Тип) Тогда + Продолжить; + КонецЕсли; + СвойстваПоля.ПолеСОшибкой = 0; + СвойстваПоля.ВидОшибки = ""; + + // Сохранение текущего контекста. + ТекущиеМетаданныеТаблицы = Контекст.МетаданныеТаблицы; + ТекущиеСвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + Контекст.МетаданныеТаблицы = Метаданные.НайтиПоТипу(Тип); + ПолноеИмя = Контекст.МетаданныеТаблицы.ПолноеИмя(); + СоставПолногоИмени = СтрРазделить(ПолноеИмя, ".", Ложь); + Контекст.СвойстваТипаТаблиц = Контекст.ТипыТаблиц.ПоИменам.Получить(ВРег(СоставПолногоИмени[0])); + + ТекущийИндекс = Индекс; + ПроверитьПолеТаблицы(ОписаниеПоля, Контекст, ТекущийИндекс, Ложь); + + // Восстановление текущего контекста. + Контекст.МетаданныеТаблицы = ТекущиеМетаданныеТаблицы; + Контекст.СвойстваТипаТаблиц = ТекущиеСвойстваТипаТаблиц; + + Если СвойстваПоля.ПолеСОшибкой = 0 Тогда + ПолеНайдено = Истина; + Если ТаблицыСледующегоПоля <> Неопределено Тогда + // См. процедуру ДобавитьТипыПоляДополнительно. + ТаблицыСледующегоПоля.Добавить(ПолноеИмя); + КонецЕсли; + ИначеЕсли СвойстваПоля.ВидОшибки <> "НеНайдено" Тогда + Возврат; + КонецЕсли; + КонецЦикла; + + Если ПолеНайдено Тогда + СвойстваПоля.ПолеСОшибкой = 0; + СвойстваПоля.ВидОшибки = ""; + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьПолеТаблицы. +Функция СвойстваПоляИлиТабличнойЧасти(ИмяПоляИлиТабличнойЧасти, Контекст, ЭтоПервоеПоле) + + Результат = Новый Структура; + Результат.Вставить("ЭтоТабличнаяЧасть", Ложь); + Результат.Вставить("Коллекция"); + Результат.Вставить("Метаданные"); + Результат.Вставить("Тип"); + + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; + СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + Для Каждого КоллекцияТабличныхЧастей Из СвойстваТипаТаблиц.КоллекцииТабличныхЧастей Цикл + Если КоллекцияТабличныхЧастей.Ключ = "СтандартныеТабличныеЧасти" Тогда + СтандартныеТабличныеЧасти = МетаданныеТаблицы.СтандартныеТабличныеЧасти; // ОписанияСтандартныхТабличныхЧастей + Для Каждого СтандартнаяТабличнаяЧасть Из СтандартныеТабличныеЧасти Цикл + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег(СтандартнаяТабличнаяЧасть.Имя) Тогда + Результат.Метаданные = СтандартнаяТабличнаяЧасть; + Прервать; + КонецЕсли; + КонецЦикла; + Иначе + Результат.Метаданные = МетаданныеТаблицы[КоллекцияТабличныхЧастей.Ключ].Найти(ИмяПоляИлиТабличнойЧасти); + КонецЕсли; + Если Результат.Метаданные <> Неопределено Тогда + Результат.ЭтоТабличнаяЧасть = Истина; + Результат.Коллекция = КоллекцияТабличныхЧастей.Ключ; + Возврат Результат; + КонецЕсли; + КонецЦикла; + + Для Каждого КоллекцияПолей Из СвойстваТипаТаблиц.КоллекцииПолей Цикл + Если КоллекцияПолей.Ключ = "СтандартныеРеквизиты" Тогда + Номер = 0; + СтандартныеРеквизиты = МетаданныеТаблицы.СтандартныеРеквизиты; // ОписанияСтандартныхРеквизитов + Для Каждого СтандартныйРеквизит Из СтандартныеРеквизиты Цикл + Номер = Номер + 1; + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Метаданные = СтандартныйРеквизит; + Прервать; + КонецЕсли; + КонецЦикла; + Иначе + Результат.Метаданные = МетаданныеТаблицы[КоллекцияПолей.Ключ].Найти(ИмяПоляИлиТабличнойЧасти); + КонецЕсли; + Если Результат.Метаданные <> Неопределено Тогда + Результат.Коллекция = КоллекцияПолей.Ключ; + Если Результат.Коллекция = "Графы" Тогда + Результат.Тип = Новый ОписаниеТипов; + МетаданныеГрафыЖурнала = Результат.Метаданные; // ОбъектМетаданныхГрафа + Для Каждого МетаданныеСсылки Из МетаданныеГрафыЖурнала.Ссылки Цикл + Результат.Тип = Новый ОписаниеТипов(Результат.Тип, МетаданныеСсылки.Тип.Типы()); + КонецЦикла; + Иначе + Результат.Тип = Результат.Метаданные.Тип; + КонецЕсли; + Возврат Результат; + КонецЕсли; + КонецЦикла; + + Если СвойстваТипаТаблиц.ОбщиеРеквизиты <> "Отсутствуют" Тогда + Результат.Метаданные = Метаданные.ОбщиеРеквизиты.Найти(ИмяПоляИлиТабличнойЧасти); + Если Результат.Метаданные <> Неопределено Тогда + Результат.Коллекция = "ОбщиеРеквизиты"; + Результат.Тип = Результат.Метаданные.Тип; + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Если СвойстваТипаТаблиц.ИмяКоллекции = "Константы" Тогда + + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Значение") + Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Value") Тогда + + Результат.Коллекция = "СпециальныеПоля"; + Результат.Тип = МетаданныеТаблицы.Тип; + Результат.Вставить("ОсновнойПорядок", "001"); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + + ИначеЕсли СвойстваТипаТаблиц.ИмяКоллекции = "Последовательности" Тогда + + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Период") + Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Period") Тогда + + Результат.Коллекция = "СпециальныеПоля"; + Результат.Тип = Новый ОписаниеТипов("Дата"); + Результат.Вставить("ОсновнойПорядок", "001"); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + + Если ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Регистратор") + Или ВРег(ИмяПоляИлиТабличнойЧасти) = ВРег("Recorder") Тогда + + Результат.Коллекция = "СпециальныеПоля"; + Результат.Тип = Новый ОписаниеТипов; + МетаданныеПоследовательности = МетаданныеТаблицы; // ОбъектМетаданныхПоследовательность + Для Каждого ДокументМетаданные Из МетаданныеПоследовательности.Документы Цикл + Результат.Тип = Новый ОписаниеТипов(Результат.Тип, "ДокументСсылка." + ДокументМетаданные.Имя); + КонецЦикла; + Результат.Вставить("ОсновнойПорядок", "002"); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедур ПроверитьРасширенияТаблицы, ПроверитьПолеТаблицы. +Функция СвойстваПоляТабличнойЧасти(ИмяПоляТабличнойЧасти, МетаданныеТабличнойЧасти, ИмяКоллекции, МетаданныеТаблицы) + + Результат = Новый Структура; + Результат.Вставить("Тип"); + Результат.Вставить("ИмяТабличнойЧасти", МетаданныеТабличнойЧасти.Имя); + + Если ВРег(ИмяПоляТабличнойЧасти) = ВРег("Ссылка") + Или ВРег(ИмяПоляТабличнойЧасти) = ВРег("Ref") Тогда + + Для Каждого СтандартныйРеквизит Из МетаданныеТаблицы.СтандартныеРеквизиты Цикл + Если ВРег(ИмяПоляТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Тип = СтандартныйРеквизит.Тип; + Возврат Результат; + КонецЕсли; + КонецЦикла; + КонецЕсли; + + Для Каждого СтандартныйРеквизит Из МетаданныеТабличнойЧасти.СтандартныеРеквизиты Цикл + Если ВРег(ИмяПоляТабличнойЧасти) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Тип = СтандартныйРеквизит.Тип; + Возврат Результат; + КонецЕсли; + КонецЦикла; + + Если ИмяКоллекции = "ТабличныеЧасти" Тогда + МетаданныеПоля = МетаданныеТабличнойЧасти.Реквизиты.Найти(ИмяПоляТабличнойЧасти); + Если МетаданныеПоля <> Неопределено Тогда + Результат.Тип = МетаданныеПоля.Тип; + Результат.Вставить("МетаданныеТабличнойЧасти", МетаданныеТабличнойЧасти); + Возврат Результат; + КонецЕсли; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедур ПроверитьРасширенияТаблицы, ПроверитьПолеТаблицы. +Функция СвойстваПоляПерерасчета(ИмяПоляПерерасчета, МетаданныеПерерасчета, МетаданныеТаблицы) + + Результат = Новый Структура; + Результат.Вставить("Тип"); + Результат.Вставить("Коллекция"); + Результат.Вставить("Метаданные"); + + Если ВРег(ИмяПоляПерерасчета) = ВРег("ОбъектПерерасчета") + Или ВРег(ИмяПоляПерерасчета) = ВРег("RecalculationObject") Тогда + + ИмяПоля = "Регистратор"; + + ИначеЕсли ВРег(ИмяПоляПерерасчета) = ВРег("ВидРасчета") + Или ВРег(ИмяПоляПерерасчета) = ВРег("CalculationType") Тогда + + ИмяПоля = "ВидРасчета"; + КонецЕсли; + + МетаданныеРегистра = МетаданныеТаблицы; // ОбъектМетаданныхРегистрРасчета + Если ЗначениеЗаполнено(ИмяПоля) Тогда + Для Каждого СтандартныйРеквизит Из МетаданныеРегистра.СтандартныеРеквизиты Цикл + Если ВРег(ИмяПоля) = ВРег(СтандартныйРеквизит.Имя) Тогда + Результат.Коллекция = "СтандартныеРеквизиты"; + Результат.Метаданные = СтандартныйРеквизит; + Результат.Тип = СтандартныйРеквизит.Тип; + Возврат Результат; + КонецЕсли; + КонецЦикла; + Возврат Неопределено; + КонецЕсли; + + МетаданныеПоля = МетаданныеПерерасчета.Измерения.Найти(ИмяПоляПерерасчета); + Если МетаданныеПоля <> Неопределено Тогда + Результат.Тип = МетаданныеПоля.ИзмерениеРегистра.Тип; + Результат.Коллекция = "СпециальныеПоля"; + Номер = 200 + МетаданныеРегистра.Измерения.Индекс(МетаданныеПоля) + 1; + Результат.Вставить("ОсновнойПорядок", Номер); // См. процедуру ДобавитьОсновнойПорядокПоля. + Возврат Результат; + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Для процедуры ПроверитьПолеТаблицы. +Процедура ДобавитьТипыПоляДополнительно(ОписаниеПоля, Индекс, СвойстваТекущегоПоля, Контекст) + + // Дополнительный сбор типов для использования в служебных процедурах. + + // Расширение свойств узла Поле для использования в служебных процедурах. + Если Индекс = 0 Или Индекс = 1 И СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда + Если ОписаниеПоля.СоставИмени.Количество() > 1 Тогда + ОписаниеПоля.Вставить("ТаблицыСледующегоПоля", Новый Массив); + Если Индекс = 1 Тогда + ОписаниеПоля.ТаблицыСледующегоПоля.Добавить(Неопределено); + КонецЕсли; + КонецЕсли; + Если Индекс = 0 И Не Контекст.СвойстваТипаТаблиц.ЭтоСсылочныйТип Тогда + ДобавитьОсновнойПорядокПоля(СвойстваТекущегоПоля, Контекст); + КонецЕсли; + КонецЕсли; + + Для Каждого УзелПоле Из ОписаниеПоля.Свойства.УзлыПоле Цикл + Если СвойстваТекущегоПоля.Свойство("ОсновнойПорядок") + И Не УзелПоле.Свойство("ОсновнойПорядок") Тогда + УзелПоле.Вставить("ОсновнойПорядок", СвойстваТекущегоПоля.ОсновнойПорядок); + КонецЕсли; + Если ОписаниеПоля.Свойство("ТаблицыСледующегоПоля") + И Не УзелПоле.Свойство("ТаблицыСледующегоПоля") Тогда + УзелПоле.Вставить("ТаблицыСледующегоПоля", ОписаниеПоля.ТаблицыСледующегоПоля); + КонецЕсли; + Если Не УзелПоле.Свойство("ТипыПоля") Тогда + УзелПоле.Вставить("ТипыПоля", Новый Массив); + УстановитьПолеСодержитNull(УзелПоле, СвойстваТекущегоПоля, Контекст); + КонецЕсли; + Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") + И ВРег(СвойстваТекущегоПоля.ИмяТабличнойЧасти) = ВРег(ОписаниеПоля.СоставИмени[0]) Тогда + + УзелПоле.ТипыПоля.Добавить(СвойстваТекущегоПоля.ИмяТабличнойЧасти); + КонецЕсли; + Если Индекс > УзелПоле.ТипыПоля.Количество() - 1 Тогда + УзелПоле.ТипыПоля.Добавить(СвойстваТекущегоПоля.Тип); + КонецЕсли; + УзелПоле.ТипыПоля[Индекс] = Новый ОписаниеТипов(УзелПоле.ТипыПоля[Индекс], + СвойстваТекущегоПоля.Тип.Типы()); + КонецЦикла; + + // Добавление типов поля строкой для проверки изменения в служебных процедурах. + ПолноеИмяПоля = Контекст.СвойстваТипаТаблиц.ЯзыкРусский + "." + ВРег(Контекст.МетаданныеТаблицы.Имя); + + Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда + ПолноеИмяПоля = ПолноеИмяПоля + "." + ВРег(СвойстваТекущегоПоля.ИмяТабличнойЧасти); + КонецЕсли; + + ПолноеИмяПоля = ПолноеИмяПоля + "." + ОписаниеПоля.СоставИмени[Индекс]; + + Если Не ОписаниеПоля.Свойство("ВсеПоля") Тогда + ОписаниеПоля.Вставить("ВсеПоля", Новый Соответствие); + ОписаниеПоля.Вставить("ТипыВсехПолей", Новый СписокЗначений); + КонецЕсли; + Если ОписаниеПоля.ВсеПоля.Получить(ПолноеИмяПоля) <> Неопределено Тогда + Возврат; + КонецЕсли; + ОписаниеПоля.ВсеПоля.Вставить(ПолноеИмяПоля, Истина); + + ТипыСтрокой = СтрокаДанныхДляХеширования(СвойстваТекущегоПоля.Тип); + ОписаниеПоля.ТипыВсехПолей.Добавить(ТипыСтрокой, ПолноеИмяПоля); + +КонецПроцедуры + +// Для процедуры ПроверитьПолеТаблицы. +Процедура ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля) + + Если ОписаниеПоля.ТипыВсехПолей.Количество() > 1 Тогда + ОписаниеПоля.ТипыВсехПолей.СортироватьПоПредставлению(); + КонецЕсли; + ТипыСтрокой = СтрСоединить(ОписаниеПоля.ТипыВсехПолей.ВыгрузитьЗначения(), Символы.ПС); + УзлыПоле = ОписаниеПоля.Свойства.УзлыПоле; + + Для Каждого УзелПоле Из УзлыПоле Цикл + УзелПоле.Вставить("ТипыСтрокой", ТипыСтрокой); + КонецЦикла; + + ОписаниеПоля.Удалить("ВсеПоля"); + ОписаниеПоля.Удалить("ТипыВсехПолей"); + +КонецПроцедуры + +// Для процедуры ДобавитьТипыПоляДополнительно. +Процедура ДобавитьОсновнойПорядокПоля(СвойстваТекущегоПоля, Контекст) + + Если СвойстваТекущегоПоля.Коллекция = "СпециальныеПоля" Тогда + Возврат; // Установлен в функции СвойстваПоляИлиТабличнойЧасти. + КонецЕсли; + + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; // ОбъектМетаданныхРегистрСведений + МетаданныеПоля = СвойстваТекущегоПоля.Метаданные; + + Если СвойстваТекущегоПоля.Коллекция = "СтандартныеРеквизиты" Тогда + Индекс = 0; + Для Каждого СтандартныйРеквизит Из МетаданныеТаблицы.СтандартныеРеквизиты Цикл + Если СтандартныйРеквизит = МетаданныеПоля Тогда + Прервать; + КонецЕсли; + Индекс = Индекс + 1; + КонецЦикла; + Номер = 100 + Индекс + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Измерения" Тогда + Номер = 200 + МетаданныеТаблицы.Измерения.Индекс(МетаданныеПоля) + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Ресурсы" Тогда + Номер = 300 + МетаданныеТаблицы.Ресурсы.Индекс(МетаданныеПоля) + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "Реквизиты" Тогда + Номер = 400 + МетаданныеТаблицы.Реквизиты.Индекс(МетаданныеПоля) + 1; + + ИначеЕсли СвойстваТекущегоПоля.Коллекция = "ОбщиеРеквизиты" Тогда + Номер = 500 + Метаданные.ОбщиеРеквизиты.Индекс(МетаданныеПоля) + 1; + КонецЕсли; + + СвойстваТекущегоПоля.Вставить("ОсновнойПорядок", Строка(Номер)); + +КонецПроцедуры + +// Для процедуры ДобавитьТипыПоляДополнительно. +Процедура УстановитьПолеСодержитNull(УзелПоле, СвойстваТекущегоПоля, Контекст) + + Если Контекст.СвойстваТипаТаблиц.ИмяКоллекции <> "Справочники" + И Контекст.СвойстваТипаТаблиц.ИмяКоллекции <> "ПланыВидовХарактеристик" + Или Не Контекст.МетаданныеТаблицы.Иерархический Тогда + + Возврат; + КонецЕсли; + + Если Контекст.СвойстваТипаТаблиц.ИмяКоллекции = "Справочники" + И Контекст.МетаданныеТаблицы.ВидИерархии + <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда + + Возврат; + КонецЕсли; + + Если СвойстваТекущегоПоля.Свойство("ИмяТабличнойЧасти") Тогда + Если СвойстваТекущегоПоля.Свойство("МетаданныеТабличнойЧасти") + И СвойстваТекущегоПоля.МетаданныеТабличнойЧасти.Использование + <> Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда + + УзелПоле.Вставить("ПолеСодержитNull"); + КонецЕсли; + + Возврат; + КонецЕсли; + + Если СвойстваТекущегоПоля.Коллекция = "Реквизиты" + И СвойстваТекущегоПоля.Метаданные.Использование + <> Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда + + УзелПоле.Вставить("ПолеСодержитNull"); + КонецЕсли; + +КонецПроцедуры + +// Для процедуры ПроверитьТаблицыПоляИТипыПолей. +Процедура ПроверитьРасширенияТаблицы(ПоляТаблицы, Контекст) + + СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + Если СвойстваТипаТаблиц.КоллекцииТабличныхЧастей.Количество() = 0 + И СвойстваТипаТаблиц.ИмяКоллекции <> "РегистрыРасчета" Тогда + Возврат; + КонецЕсли; + + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; + + Для Каждого РасширениеТаблицы Из ПоляТаблицы.Значение.Расширения Цикл + + Если СвойстваТипаТаблиц.ИмяКоллекции = "РегистрыРасчета" Тогда + МетаданныеРасширения = МетаданныеТаблицы.Перерасчеты.Найти(РасширениеТаблицы.Ключ); + Иначе + Для Каждого КоллекцияТабличныхЧастей Из СвойстваТипаТаблиц.КоллекцииТабличныхЧастей Цикл + Если КоллекцияТабличныхЧастей.Ключ = "СтандартныеТабличныеЧасти" Тогда + СтандартныеТабличныеЧасти = МетаданныеТаблицы.СтандартныеТабличныеЧасти; // ОписанияСтандартныхТабличныхЧастей + Для Каждого СтандартнаяТабличнаяЧасть Из СтандартныеТабличныеЧасти Цикл + Если ВРег(РасширениеТаблицы.Ключ) = ВРег(СтандартнаяТабличнаяЧасть.Имя) Тогда + МетаданныеРасширения = СтандартнаяТабличнаяЧасть; + Прервать; + КонецЕсли; + КонецЦикла; + Иначе + МетаданныеРасширения = МетаданныеТаблицы[КоллекцияТабличныхЧастей.Ключ].Найти(РасширениеТаблицы.Ключ); + КонецЕсли; + Если МетаданныеРасширения <> Неопределено Тогда + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; + Если МетаданныеРасширения = Неопределено Тогда + Продолжить; + КонецЕсли; + РасширениеТаблицы.Значение.ТаблицаСуществует = Истина; + + Для Каждого ПолеТаблицы Из РасширениеТаблицы.Значение.Поля Цикл + ОписаниеПоля = Новый Структура; + ОписаниеПоля.Вставить("СоставИмени", СтрРазделить(ПолеТаблицы.Ключ, ".")); + ОписаниеПоля.Вставить("Свойства", ПолеТаблицы.Значение); + ОписаниеПоля.Вставить("ТипПоля", Новый ОписаниеТипов); + + Индекс = 0; + Если СвойстваТипаТаблиц.ИмяКоллекции = "РегистрыРасчета" Тогда + СвойстваПоля = СвойстваПоляПерерасчета(ОписаниеПоля.СоставИмени[Индекс], + МетаданныеРасширения, МетаданныеТаблицы); + Иначе + СвойстваПоля = СвойстваПоляТабличнойЧасти(ОписаниеПоля.СоставИмени[Индекс], + МетаданныеРасширения, КоллекцияТабличныхЧастей.Ключ, МетаданныеТаблицы); + КонецЕсли; + + Если СвойстваПоля = Неопределено Тогда + ОписаниеПоля.Свойства.ПолеСОшибкой = Индекс + 1; + ОписаниеПоля.Свойства.ВидОшибки = "НеНайдено"; + Продолжить; + КонецЕсли; + ПроверитьСледующееПолеЧерезТочку(ОписаниеПоля, Индекс, СвойстваПоля, Контекст); + ЗаполнитьТипыПоляСтрокойДополнительно(ОписаниеПоля); + Если ОписаниеПоля.Свойства.ПолеСОшибкой = 0 Тогда + ПроверитьТипыПоля(ОписаниеПоля, Контекст); + КонецЕсли; + КонецЦикла; + + КонецЦикла; + +КонецПроцедуры + +// Для процедур ПроверитьТаблицыПоляИТипыПолей и ПроверитьРасширенияТаблицы. +Процедура ПроверитьТипыПоля(ОписаниеПоля, Контекст) + + ОписаниеТиповПоля = ОписаниеПоля.ТипПоля; + + Для Каждого ОписаниеТипа Из ОписаниеПоля.Свойства.СодержитТипы Цикл + СвойстваТипа = ОписаниеТипа.Значение; + Если ЗначениеЗаполнено(СвойстваТипа.ИмяКоллекцииТипа) + И Метаданные[СвойстваТипа.ИмяКоллекцииТипа].Найти(СвойстваТипа.ИмяОбъектаКоллекцииТипа) = Неопределено Тогда + Продолжить; + КонецЕсли; + Тип = Тип(ОписаниеТипа.Значение.ИмяТипа); + СвойстваТипа.СодержитТип = ОписаниеТиповПоля.СодержитТип(Тип); + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ПроверитьТаблицыПоляИТипыПолей. +// +// Параметры: +// ПоляТаблицы - см. НовыйСоставКоллекции +// +Процедура ПроверитьПредопределенныеЗначенияТаблицы(ПоляТаблицы, Контекст) + + СвойстваТипаТаблиц = Контекст.СвойстваТипаТаблиц; + + СвойстваТаблицы = ПоляТаблицы.Значение; // см. НовыеСвойстваТаблицы + Если СвойстваТаблицы.Предопределенные.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + Если СвойстваТипаТаблиц.ЕстьПредопределенные Тогда + МетаданныеТаблицы = Контекст.МетаданныеТаблицы; + + Если СвойстваТипаТаблиц.ИмяКоллекции = "Перечисления" Тогда + ИменаПредопределенных = Новый Массив; + Для Каждого ЗначениеПеречисления Из МетаданныеТаблицы.ЗначенияПеречисления Цикл + ТекущееЗначениеПеречисления = ЗначениеПеречисления; // ОбъектМетаданныхЗначениеПеречисления + ИменаПредопределенных.Добавить(ТекущееЗначениеПеречисления.Имя); + КонецЦикла; + Иначе + ИменаПредопределенных = Новый Массив(МетаданныеТаблицы.ПолучитьИменаПредопределенных()); + КонецЕсли; + Иначе + ИменаПредопределенных = Новый Массив; + КонецЕсли; + + ИменаПредопределенных.Добавить("ПустаяСсылка"); + ИменаПредопределенных.Добавить("EmptyRef"); + + Для Каждого Предопределенный Из СвойстваТаблицы.Предопределенные Цикл + Для Каждого ИмяПредопределенного Из ИменаПредопределенных Цикл + Если ВРег(ИмяПредопределенного) = Предопределенный.Ключ Тогда + Предопределенный.Значение.ИмяСуществует = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + + +// Для функции СтруктураОграничения. +Процедура ОтметитьНекорректныеИменаТаблицПолейИТиповПолей(ПоляТаблиц, Контекст) + + Для Каждого ТипТаблиц Из ПоляТаблиц Цикл + Для Каждого ОписаниеТаблицы Из ТипТаблиц.Значение Цикл + СвойстваТаблицы = ОписаниеТаблицы.Значение; // см. НовыеСвойстваТаблицы + + Если Не СвойстваТаблицы.ТаблицаСуществует Тогда + Для Каждого Источник Из СвойстваТаблицы.Источники Цикл + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица ""%1""'"), Источник.Символы), , 2); + КонецЦикла; + Если СвойстваТаблицы.Свойство("ПервоеПоле") + И СвойстваТаблицы.ПервоеПоле.ПервыйИсточник <> Неопределено Тогда + + УстановитьОшибкуВСтрокеИмениПоля(Контекст, СвойстваТаблицы.ПервоеПоле.ПервыйИсточник.Ключ, + НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , + СвойстваТаблицы.ПервоеПоле.ПервыйИсточник.Значение); + КонецЕсли; + Для Каждого ОписаниеПредопределенного Из СвойстваТаблицы.Предопределенные Цикл + Для Каждого Источник Из ОписаниеПредопределенного.Значение.Источники Цикл + СоставИмени = СтрРазделить(Источник.Символы, "."); + + УстановитьОшибкуВСтроке(Источник, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Предопределенное значение не существует, так как указана несуществующая таблица ""%1""'"), + СоставИмени[0] + "." + СоставИмени[1]), , 2); + КонецЦикла; + КонецЦикла; + Продолжить; + КонецЕсли; + + Для Каждого ОписаниеПредопределенного Из СвойстваТаблицы.Предопределенные Цикл + СвойстваПредопределенного = ОписаниеПредопределенного.Значение; + Если СвойстваПредопределенного.ИмяСуществует Тогда + Продолжить; + КонецЕсли; + Для Каждого Источник Из СвойстваПредопределенного.Источники Цикл + СоставИмени = СтрРазделить(Источник.Символы, "."); + Источник.ПозицияОшибки = СтрДлина(СоставИмени[0] + "." + СоставИмени[1]) + 1; + Источник.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует предопределенное значение ""%1""'"), СоставИмени[2]); + КонецЦикла; + КонецЦикла; + + Для Каждого ОписаниеПоля Из СвойстваТаблицы.Поля Цикл + ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст); + КонецЦикла; + + Для Каждого ОписаниеРасширения Из СвойстваТаблицы.Расширения Цикл + СвойстваРасширения = ОписаниеРасширения.Значение; + Если Не СвойстваРасширения.ТаблицаСуществует Тогда + Для Каждого Источник Из СвойстваРасширения.Источники Цикл + УстановитьОшибкуВСтроке(Источник, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не существует таблица ""%1""'"), Источник.Символы), , 2); + КонецЦикла; + Если СвойстваРасширения.Свойство("ПервоеПоле") + И СвойстваРасширения.ПервоеПоле.ПервыйИсточник <> Неопределено Тогда + + УстановитьОшибкуВСтрокеИмениПоля(Контекст, СвойстваРасширения.ПервоеПоле.ПервыйИсточник.Ключ, + НСтр("ru = 'Поле не существует, так как указана несуществующая таблица ""%1""'"), 0, , + СвойстваРасширения.ПервоеПоле.ПервыйИсточник.Значение); + КонецЕсли; + Продолжить; + КонецЕсли; + Для Каждого ОписаниеПоля Из СвойстваРасширения.Поля Цикл + ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст); + КонецЦикла; + КонецЦикла; + + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеИменаТаблицПолейИТиповПолей. +Процедура ОтметитьНекорректноеПолеИТипыПоля(ОписаниеПоля, Контекст) + + СвойстваПоля = ОписаниеПоля.Значение; + Если СвойстваПоля.ПолеСОшибкой = 1 Тогда + Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл + ВКонце = Ложь; + Если СвойстваПоля.ВидОшибки = "ТабличнаяЧастьБезПоля" Тогда + ВКонце = Истина; + ШаблонОшибки = НСтр("ru = 'Не указано поле после табличной части ""%1"" таблицы ""%2""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "ТабличнаяЧастьДополнительнойТаблицы" Тогда + ШаблонОшибки = НСтр("ru = 'Табличная часть ""%1"" не поддерживается для дополнительной таблицы ""%2""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Недопустимо" Тогда + ШаблонОшибки = НСтр("ru = 'Недопустимо использовать поле ""%1"" таблицы ""%2""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Запрещено" Тогда + ШаблонОшибки = НСтр("ru = 'Запрещено использовать поле ""%1"" таблицы ""%2""'"); + Иначе + ШаблонОшибки = НСтр("ru = 'Не существует поле ""%1"" таблицы ""%2""'"); + КонецЕсли; + УстановитьОшибкуВСтрокеИмениПоля(Контекст, + ОписаниеИсточника.Ключ, ШаблонОшибки, 1, Истина, ОписаниеИсточника.Значение, ВКонце); + КонецЦикла; + Возврат; + КонецЕсли; + + Если СвойстваПоля.ПолеСОшибкой > 1 Тогда + Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл + Если СвойстваПоля.ВидОшибки = "ТабличнаяЧастьПослеТочки" Тогда + ШаблонОшибки = НСтр("ru = 'Табличная часть ""%1"" не поддерживается ""через точку"" от поля'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Недопустимо" Тогда + ШаблонОшибки = НСтр("ru = 'Недопустимо использовать поле ""%1""'"); + + ИначеЕсли СвойстваПоля.ВидОшибки = "Запрещено" Тогда + ШаблонОшибки = НСтр("ru = 'Запрещено использовать поле ""%1""'"); + Иначе + ШаблонОшибки = НСтр("ru = 'Не существует поле ""%1""'"); + КонецЕсли; + УстановитьОшибкуВСтрокеИмениПоля(Контекст, + ОписаниеИсточника.Ключ, ШаблонОшибки, СвойстваПоля.ПолеСОшибкой, Истина); + КонецЦикла; + Возврат; + КонецЕсли; + + СоставИмени = СтрРазделить(ОписаниеПоля.Ключ, "."); + Если СоставИмени.Количество() > 1 + И ( СоставИмени[1] = ВРег("Ссылка") + Или СоставИмени[1] = ВРег("Ref") ) + И СвойстваПоля.Коллекция <> "ТабличныеЧасти" + И СвойстваПоля.Коллекция <> "СтандартныеТабличныеЧасти" Тогда + + Для Каждого ОписаниеИсточника Из ОписаниеПоля.Значение.Источники Цикл + ШаблонОшибки = НСтр("ru = 'Поле ""%1"" избыточно указывать ""через точку"" от любого поля'"); + УстановитьОшибкуВСтрокеИмениПоля(Контекст, + ОписаниеИсточника.Ключ, ШаблонОшибки, 2, Истина); + КонецЦикла; + Возврат; + КонецЕсли; + + Для Каждого ОписаниеТипа Из СвойстваПоля.СодержитТипы Цикл + СвойстваТипа = ОписаниеТипа.Значение; + Для Каждого ОписаниеИсточника Из ОписаниеТипа.Значение.Источники Цикл + Если ТипЗнч(ОписаниеИсточника.Ключ) = Тип("СтрокаТаблицыЗначений") Тогда + Если Не СвойстваТипа.СодержитТип Тогда + УстановитьОшибкуВСтроке(ОписаниеИсточника.Ключ, + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'У поля ""%1"" не существует тип ""%2""'"), + ОписаниеИсточника.Значение.Символы, + ОписаниеИсточника.Ключ.Символы), + , 2); + КонецЕсли; + КонецЕсли; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОтметитьНекорректныеИменаТаблицПолейИТиповПолей. +Процедура УстановитьОшибкуВСтрокеИмениПоля(Контекст, Строка, ШаблонОшибки, ПолеСОшибкой, + ВставитьИмя = Ложь, Таблица = Null, ВКонце = Ложь) + + Если ЗначениеЗаполнено(Строка.ТекстОшибки) Тогда + Возврат; + КонецЕсли; + + Если ТипЗнч(ВставитьИмя) = Тип("Строка") Тогда + СоставИмени = СтрРазделить(ВставитьИмя, "."); + ВставитьИмя = Истина; + Иначе + СоставИмени = СтрРазделить(Строка.Символы, "."); + КонецЕсли; + + Если СоставИмени.Количество() > 1 + И Контекст.Псевдонимы.Получить(ВРег(СоставИмени[0])) <> Неопределено Тогда + + Строка.ПозицияОшибки = СтрДлина(СоставИмени[0]) + 1; + СоставИмени.Удалить(0); + КонецЕсли; + + Для Номер = 1 По ПолеСОшибкой - 1 Цикл + Строка.ПозицияОшибки = Строка.ПозицияОшибки + СтрДлина(СоставИмени[0]) + 1; + СоставИмени.Удалить(0); + КонецЦикла; + Если ВКонце Тогда + Строка.ПозицияОшибки = Строка.ПозицияОшибки + СтрДлина(СоставИмени[0]); + КонецЕсли; + ИмяПоля = СоставИмени[0]; + + Если ВставитьИмя И Таблица <> Null Тогда + Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + ИмяПоля, ?(ЗначениеЗаполнено(Таблица), Таблица, Контекст.ОсновнаяТаблица)); + + ИначеЕсли ВставитьИмя Тогда + Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, ИмяПоля); + + ИначеЕсли Таблица <> Null Тогда + Строка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки, + ?(ЗначениеЗаполнено(Таблица), Таблица, Контекст.ОсновнаяТаблица)); + Иначе + Строка.ТекстОшибки = ШаблонОшибки; + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область ОбновлениеПрогрессаОбновленияДоступа + +// Возвращаемое значение: +// Структура: +// * СтрокиСписков - Соответствие +// * СвойстваСписков - Соответствие +// * КоличествоКлючей - Число +// * ДатаПоследнегоОбновления - Дата +// +Функция НовыеХранимыеДанныеОбновленияПрогресса() Экспорт + + ХранимыеДанные = Новый Структура; + ХранимыеДанные.Вставить("СтрокиСписков", Новый Соответствие); + ХранимыеДанные.Вставить("СвойстваСписков", Новый Соответствие); + ХранимыеДанные.Вставить("КоличествоКлючей", 0); + ХранимыеДанные.Вставить("ДатаПоследнегоОбновления", '00010101'); + + Возврат ХранимыеДанные; + +КонецФункции + +// Параметры: +// Контекст - Структура: +// * Версия - Число +// * ХранимыеДанные - см. НовыеХранимыеДанныеОбновленияПрогресса +// * РассчитыватьПоКоличествуДанных - Булево +// * ПоказыватьОбработанныеСписки - Булево +// * ЭтоПовторноеОбновлениеПрогресса - Булево +// * ВсегоОбновлено - Число +// * ПериодОбновленияПрогресса - Число +// * АвтообновлениеПрогресса - Булево +// * ДобавленныеСтроки - Массив +// * УдаленныеСтроки - Соответствие +// * ИзмененныеСтроки - Соответствие +// * ОбновлениеДоступаВыполняется - Булево +// +// АдресРезультата - Строка +// +Процедура ОбновитьПрогрессВФоне(Контекст, АдресРезультата) Экспорт + + ТекстОшибки = Неопределено; + + Если Контекст.Свойство("Версия") И Контекст.Версия = 1 Тогда + Попытка + ОбновитьПрогресс(Контекст); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + Если Не СтандартныеПодсистемыСервер.ЭтоОшибкаТребованияПерезапускаСеанса(ИнформацияОбОшибке) Тогда + ВызватьИсключение; + КонецЕсли; + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); + КонецПопытки; + Иначе + ТекстОшибки = НСтр("ru = 'Версия приложения обновлена, перезапустите клиентский сеанс.'"); + КонецЕсли; + + Если ТекстОшибки <> Неопределено Тогда + Контекст.Вставить("ИнформацияОбОшибке", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( + НСтр("ru = 'Не удалось обновить прогресс по причине: + |%1'"), ТекстОшибки)); + КонецЕсли; + + ПоместитьВоВременноеХранилище(Контекст, АдресРезультата); + +КонецПроцедуры + +Процедура ОбновитьПрогресс(Контекст) + + ДатаНачалаОбновленияПрогресса = ТекущаяДатаСеанса(); + ДлительныеОперации.СообщитьПрогресс(0); // Обновление прогресса выполняется. + + СтрокиСписков = Контекст.ХранимыеДанные.СтрокиСписков; + СвойстваСписков = Контекст.ХранимыеДанные.СвойстваСписков; + Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = '00010101'; + КонецЕсли; + + ДействующиеПараметры = Неопределено; // См. ДействующиеПараметрыОграниченияДоступа + ИдентификаторыТаблиц = ИдентификаторыСписковСОграничением(ДействующиеПараметры); + + Если Контекст.ПоказыватьОбработанныеСписки Тогда + Для Каждого КлючИЗначение Из ИдентификаторыТаблиц Цикл + Если СтрокиСписков.Получить(КлючИЗначение.Значение) <> Неопределено Тогда + Продолжить; + КонецЕсли; + ДобавитьНовуюСтрокуСписка(Контекст, КлючИЗначение.Значение, КлючИЗначение.Ключ); + КонецЦикла; + КонецЕсли; + + Запрос = Новый Запрос; + Запрос.УстановитьПараметр("МаксимальнаяДата", МаксимальнаяДатаПриПродолжении()); + Запрос.УстановитьПараметр("ДатаПоследнегоОбновления", Контекст.ХранимыеДанные.ДатаПоследнегоОбновления); + Запрос.УстановитьПараметр("ПустойУникальныйИдентификатор", + ОбщегоНазначенияКлиентСервер.ПустойУникальныйИдентификатор()); + + Контекст.ХранимыеДанные.ДатаПоследнегоОбновления = ДатаНачалаОбновленияПрогресса; + + ТекстыЗапросов = Новый Массив; + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ + | ВсеСпискиОбновления.Список КАК Список, + | МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеЭлементов) КАК ОбновлениеЭлементов, + | МАКСИМУМ(ВсеСпискиОбновления.ОбновлениеКлючейДоступа) КАК ОбновлениеКлючейДоступа + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаКДанным.Список КАК Список, + | ИСТИНА КАК ОбновлениеЭлементов, + | ЛОЖЬ КАК ОбновлениеКлючейДоступа + | ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючейДоступаКДанным + | + | ОБЪЕДИНИТЬ ВСЕ + | + | ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючейДоступаПользователей.Список, + | ЛОЖЬ, + | ИСТИНА + | ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаПользователей КАК ОбновлениеКлючейДоступаПользователей) КАК ВсеСпискиОбновления + | + |СГРУППИРОВАТЬ ПО + | ВсеСпискиОбновления.Список"); + + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ РАЗЛИЧНЫЕ + | ОбновлениеКлючей.Список КАК Список + |ПОМЕСТИТЬ ИзмененныеСпискиКлючейДоступаКДанным + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей + |ГДЕ + | ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления + | И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО + | + |ИНДЕКСИРОВАТЬ ПО + | Список + |; + | + |//////////////////////////////////////////////////////////////////////////////// + |ВЫБРАТЬ + | ОбновлениеКлючей.Список КАК Список, + | ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей, + | ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор КАК ЭтоОсновнаяЗапись, + | МАКСИМУМ(ОбновлениеКлючей.РазмерЗадания) КАК РазмерЗадания, + | МАКСИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МаксимальнаяДатаИзменения, + | МИНИМУМ(ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра) КАК МинимальнаяДатаИзменения + |ИЗ + | ИзмененныеСпискиКлючейДоступаКДанным КАК ИзмененныеСписки + | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей + | ПО (ОбновлениеКлючей.Список = ИзмененныеСписки.Список) + | + |СГРУППИРОВАТЬ ПО + | ОбновлениеКлючей.Список, + | ОбновлениеКлючей.ДляВнешнихПользователей, + | ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор + |ИТОГИ ПО + | Список, + | ДляВнешнихПользователей"); + + ТекстыЗапросов.Добавить(СтрЗаменить(СтрЗаменить(ТекстыЗапросов[1], + "ИзмененныеСпискиКлючейДоступаКДанным", + "ИзмененныеСпискиКлючейДоступаПользователей"), + "РегистрСведений.ОбновлениеКлючейДоступаКДанным", + "РегистрСведений.ОбновлениеКлючейДоступаПользователей")); + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ + | ОбновлениеКлючей.Список КАК Список, + | ОбновлениеКлючей.ДляВнешнихПользователей КАК ДляВнешнихПользователей, + | ОбновлениеКлючей.ПараметрыЗадания КАК ПараметрыЗадания + |ИЗ + | РегистрСведений.ОбновлениеКлючейДоступаКДанным КАК ОбновлениеКлючей + |ГДЕ + | ОбновлениеКлючей.ДатаИзмененияЗаписиРегистра >= &ДатаПоследнегоОбновления + | И ОбновлениеКлючей.КлючУникальности = &ПустойУникальныйИдентификатор + | И ОбновлениеКлючей.Список <> НЕОПРЕДЕЛЕНО + |ИТОГИ ПО + | Список"); + + ТекстыЗапросов.Добавить(СтрЗаменить(ТекстыЗапросов[3], + "РегистрСведений.ОбновлениеКлючейДоступаКДанным", + "РегистрСведений.ОбновлениеКлючейДоступаПользователей")); + + ТекстыЗапросов.Добавить( + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа"); + КонецЕсли; + + Запрос.Текст = СтрСоединить(ТекстыЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + + ВсеСпискиОбновления = РезультатыЗапроса[0].Выгрузить(); + НовыеСписки = Новый Массив; + + Для Каждого СписокОбновления Из ВсеСпискиОбновления Цикл + Если Не ЗначениеЗаполнено(СписокОбновления.Список) Тогда + Продолжить; + КонецЕсли; + Строка = СтрокиСписков.Получить(СписокОбновления.Список); + Если Строка = Неопределено Тогда + НовыеСписки.Добавить(СписокОбновления.Список); + КонецЕсли; + КонецЦикла; + + Если НовыеСписки.Количество() > 0 Тогда + ОбъектыМетаданныхПоИдентификаторам = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(НовыеСписки, Ложь); + Для Каждого НовыйСписок Из НовыеСписки Цикл + ОбъектМетаданных = ОбъектыМетаданныхПоИдентификаторам.Получить(НовыйСписок); + Если ОбъектМетаданных = Неопределено Тогда + Продолжить; + ИначеЕсли ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда + ИмяТаблицы = ОбъектМетаданных.ПолноеИмя(); + Иначе + ИмяТаблицы = ""; + КонецЕсли; + ДобавитьНовуюСтрокуСписка(Контекст, НовыйСписок, ИмяТаблицы); + КонецЦикла; + КонецЕсли; + + СтрокиОбновленияКоличестваЭлементов = Новый Массив; + СтрокиОбновленияКоличестваКлючейДоступа = Новый Массив; + УдаляемыеСтроки = Новый Массив; + Для Каждого КлючИЗначение Из СтрокиСписков Цикл + Строка = КлючИЗначение.Значение; + СписокОбновления = ВсеСпискиОбновления.Найти(Строка.Список, "Список"); + Если СписокОбновления = Неопределено И Не Контекст.ПоказыватьОбработанныеСписки Тогда + УдаляемыеСтроки.Добавить(Строка); + Продолжить; + КонецЕсли; + СвойстваСписка = СвойстваСписков.Получить(Строка.Список); + Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеЭлементов Тогда + СвойстваСписка.РазмерЗаданияОбновленияЭлементов = 0; + СвойстваСписка.ПоследнийОбновленныйЭлемент = Null; + СвойстваСписка.РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей = 0; + СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей = Null; + Строка.ДоляОбработанныхЭлементовДляПользователей = 1; + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = 1; + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + Если Строка.ОбработаноЭлементов <> 100 Тогда + СтрокиОбновленияКоличестваЭлементов.Добавить(Строка); + КонецЕсли; + Иначе + ОбнулитьКоличествоЭлементов(Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст); + КонецЕсли; + Если СписокОбновления = Неопределено Или Не СписокОбновления.ОбновлениеКлючейДоступа Тогда + СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступа = 0; + СвойстваСписка.ПоследнийОбновленныйКлючДоступа = Null; + СвойстваСписка.РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей = 0; + СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей = Null; + Строка.ДоляОбработанныхКлючейДоступаДляПользователей = 1; + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = 1; + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + Если Строка.ОбработаноКлючейДоступа <> 100 Тогда + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка); + КонецЕсли; + Иначе + ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст); + КонецЕсли; + Если СписокОбновления = Неопределено Тогда + ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, '00010101', Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, МаксимальнаяДата(), Строка, Контекст); + КонецЕсли; + КонецЦикла; + + Для Каждого УдаляемаяСтрока Из УдаляемыеСтроки Цикл + СтрокиСписков.Удалить(УдаляемаяСтрока.Список); + СвойстваСписков.Удалить(УдаляемаяСтрока.Список); + Индекс = Контекст.ДобавленныеСтроки.Найти(УдаляемаяСтрока); + Если Индекс <> Неопределено Тогда + Контекст.ДобавленныеСтроки.Удалить(Индекс); + Продолжить; + КонецЕсли; + Контекст.УдаленныеСтроки.Вставить(УдаляемаяСтрока.Список, Истина); + КонецЦикла; + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + ВыборкаПоСпискам = РезультатыЗапроса[5].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); + Пока ВыборкаПоСпискам.Следующий() Цикл + СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список); + Если СвойстваСписка = Неопределено Тогда + Продолжить; + КонецЕсли; + ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать(); + Пока ВыборкаПоВидамПользователей.Следующий() Цикл + Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлементДляВнешнихПользователей"; + Иначе + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлемент"; + КонецЕсли; + Если СвойстваСписка[ИмяПоляПараметровЗадания] <> Истина Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = ВыборкаПоВидамПользователей.ПараметрыЗадания; + КонецЕсли; + КонецЦикла; + КонецЦикла; + ВыборкаПоСпискам = РезультатыЗапроса[6].Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); + Пока ВыборкаПоСпискам.Следующий() Цикл + СвойстваСписка = СвойстваСписков.Получить(ВыборкаПоСпискам.Список); + Если СвойстваСписка = Неопределено Тогда + Продолжить; + КонецЕсли; + ВыборкаПоВидамПользователей = ВыборкаПоСпискам.Выбрать(); + Пока ВыборкаПоВидамПользователей.Следующий() Цикл + Если ВыборкаПоВидамПользователей.ДляВнешнихПользователей Тогда + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей"; + Иначе + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступа"; + КонецЕсли; + Если СвойстваСписка[ИмяПоляПараметровЗадания] <> Истина Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = ВыборкаПоВидамПользователей.ПараметрыЗадания; + КонецЕсли; + КонецЦикла; + КонецЦикла; + КонецЕсли; + + СпискиОбновленияЭлементов = РезультатыЗапроса[2].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого ОписаниеОбновления Из СпискиОбновленияЭлементов.Строки Цикл + Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список); + Если Строка = Неопределено Тогда + Продолжить; + КонецЕсли; + СвойстваСписка = СвойстваСписков.Получить(Строка.Список); + ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Истина, Контекст); + Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда + Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхЭлементовДляПользователей, + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры); + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, Обработано, Строка, Контекст); + ОбнулитьКоличествоЭлементов(Строка, Контекст); + + ИначеЕсли Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + СтрокиОбновленияКоличестваЭлементов.Добавить(Строка); + КонецЕсли; + КонецЦикла; + + СпискиОбновленияКлючейДоступа = РезультатыЗапроса[4].Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам); + Для Каждого ОписаниеОбновления Из СпискиОбновленияКлючейДоступа.Строки Цикл + Строка = СтрокиСписков.Получить(ОписаниеОбновления.Список); + Если Строка = Неопределено Тогда + Продолжить; + КонецЕсли; + СвойстваСписка = СвойстваСписков.Получить(Строка.Список); + ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, Ложь, Контекст); + Если Не Контекст.РассчитыватьПоКоличествуДанных Тогда + Обработано = ОбработаноПоДолям(Строка.ДоляОбработанныхКлючейДоступаДляПользователей, + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей, Строка.ИмяТаблицы, ДействующиеПараметры); + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, Обработано, Строка, Контекст); + ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + + ИначеЕсли Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(Строка); + КонецЕсли; + КонецЦикла; + + Индекс = Контекст.ДобавленныеСтроки.Количество() - 1; + Пока Индекс >= 0 Цикл + Если Не ЗначениеЗаполнено(Контекст.ДобавленныеСтроки[Индекс].ИмяТаблицы) Тогда + Контекст.ДобавленныеСтроки.Удалить(Индекс); + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + КоличествоКлючей = РезультатыЗапроса[7].Выгрузить()[0].Количество; + Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса Тогда + Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл + СтрокиОбновленияКоличестваЭлементов.Добавить(ОписаниеСтроки.Значение); + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение); + КонецЦикла; + ИначеЕсли Контекст.ХранимыеДанные.КоличествоКлючей <> КоличествоКлючей Тогда + Для Каждого ОписаниеСтроки Из СтрокиСписков Цикл + Если СтрокиОбновленияКоличестваКлючейДоступа.Найти(ОписаниеСтроки.Значение) = Неопределено Тогда + СтрокиОбновленияКоличестваКлючейДоступа.Добавить(ОписаниеСтроки.Значение); + КонецЕсли; + КонецЦикла; + КонецЕсли; + Контекст.ХранимыеДанные.КоличествоКлючей = КоличествоКлючей; + Иначе + Контекст.ХранимыеДанные.КоличествоКлючей = 0; + КонецЕсли; + + Если Контекст.РассчитыватьПоКоличествуДанных Тогда + ТекущийКонтекст = Новый Структура; + ТекущийКонтекст.Вставить("ДобавленныеСтроки", Контекст.ДобавленныеСтроки); + ТекущийКонтекст.Вставить("ИзмененныеСтроки", Контекст.ИзмененныеСтроки); + ТекущийКонтекст.Вставить("СвойстваСписков", СвойстваСписков); + ТекущийКонтекст.Вставить("СтрокиСписков", СтрокиСписков); + ТекущийКонтекст.Вставить("ДействующиеПараметры", ДействующиеПараметры); + ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваЭлементов", СтрокиОбновленияКоличестваЭлементов); + ТекущийКонтекст.Вставить("СтрокиОбновленияКоличестваКлючейДоступа", СтрокиОбновленияКоличестваКлючейДоступа); + ТекущийКонтекст.Вставить("ИдентификаторыТаблиц", ИдентификаторыТаблиц); + ТекущийКонтекст.Вставить("ХранимыеДанные", Контекст.ХранимыеДанные); + ВсегоОбновлено = 100; + РассчитатьВсегоОбновленоПоКоличествуДанных(ТекущийКонтекст, ВсегоОбновлено); + Иначе + Если Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда + Контекст.ХранимыеДанные.Удалить("КоличествоЭлементовПоСпискам"); + Контекст.ХранимыеДанные.Удалить("КоличествоКлючейДоступаПоСпискам"); + КонецЕсли; + ВсегоКоличество = ИдентификаторыТаблиц.Количество(); + Если СтрокиСписков.Количество() > ВсегоКоличество Тогда + ВсегоКоличество = СтрокиСписков.Количество(); + КонецЕсли; + ВсегоОбновлено = (100 + 100) * (ВсегоКоличество - СтрокиСписков.Количество()); + Для Каждого КлючИЗначение Из СтрокиСписков Цикл + Строка = КлючИЗначение.Значение; + ВсегоОбновлено = ВсегоОбновлено + Строка.ОбработаноЭлементов + Строка.ОбработаноКлючейДоступа; + КонецЦикла; + ВсегоОбновлено = ВсегоОбновлено / 2 / ВсегоКоличество; + КонецЕсли; + Если ВсегоОбновлено > 100 Тогда + ВсегоОбновлено = 100; + КонецЕсли; + Контекст.ВсегоОбновлено = Цел(ВсегоОбновлено); + + ВремяОбновления = ТекущаяДатаСеанса() - ДатаНачалаОбновленияПрогресса; + + Если Контекст.ЭтоПовторноеОбновлениеПрогресса + И ВремяОбновления > Контекст.ПериодОбновленияПрогресса Тогда + + Контекст.ПериодОбновленияПрогресса = ВремяОбновления; + Иначе + Контекст.Удалить("ПериодОбновленияПрогресса"); + КонецЕсли; + + Если Не Контекст.ЭтоПовторноеОбновлениеПрогресса И ВремяОбновления > 60 Тогда + Контекст.АвтообновлениеПрогресса = Ложь; + Иначе + Контекст.Удалить("АвтообновлениеПрогресса"); + КонецЕсли; + +КонецПроцедуры + +Процедура ЗаполнитьДолиОбработанных(Строка, ОписаниеОбновления, СвойстваСписка, ЭтоОбработкаЭлементов, Контекст) + + Для Каждого СвойстваОбновления Из ОписаниеОбновления.Строки Цикл + Если ЭтоОбработкаЭлементов Тогда + Если СвойстваОбновления.ДляВнешнихПользователей Тогда + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлементДляВнешнихПользователей"; + ИмяПоляДоли = "ДоляОбработанныхЭлементовДляВнешнихПользователей"; + Иначе + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияЭлементов"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйЭлемент"; + ИмяПоляДоли = "ДоляОбработанныхЭлементовДляПользователей"; + КонецЕсли; + Иначе + Если СвойстваОбновления.ДляВнешнихПользователей Тогда + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей"; + ИмяПоляДоли = "ДоляОбработанныхКлючейДоступаДляВнешнихПользователей"; + Иначе + ИмяПоляРазмераЗадания = "РазмерЗаданияОбновленияКлючейДоступа"; + ИмяПоляПараметровЗадания = "ПоследнийОбновленныйКлючДоступа"; + ИмяПоляДоли = "ДоляОбработанныхКлючейДоступаДляПользователей"; + КонецЕсли; + КонецЕсли; + РазмерЗаданияОсновнаяЗапись = СвойстваСписка[ИмяПоляРазмераЗадания]; + РазмерЗаданияНовыеЗаписи = 0; + Для Каждого СвойстваЗадания Из СвойстваОбновления.Строки Цикл + Если СвойстваЗадания.ЭтоОсновнаяЗапись Тогда + Если СвойстваЗадания.МаксимальнаяДатаИзменения > Строка.ПоследнееОбновление Тогда + ОбновитьЗначениеВСтроке(Строка.ПоследнееОбновление, + СвойстваЗадания.МаксимальнаяДатаИзменения, Строка, Контекст); + КонецЕсли; + РазмерЗаданияОсновнаяЗапись = СвойстваЗадания.РазмерЗадания; + Иначе + Если СвойстваЗадания.МинимальнаяДатаИзменения < Строка.ПервоеПланированиеОбновления Тогда + ОбновитьЗначениеВСтроке(Строка.ПервоеПланированиеОбновления, + СвойстваЗадания.МинимальнаяДатаИзменения, Строка, Контекст); + КонецЕсли; + РазмерЗаданияНовыеЗаписи = СвойстваЗадания.РазмерЗадания; + КонецЕсли; + КонецЦикла; + СвойстваСписка[ИмяПоляРазмераЗадания] = РазмерЗаданияОсновнаяЗапись; + Если РазмерЗаданияНовыеЗаписи >= РазмерЗаданияОсновнаяЗапись Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = Истина; + ТекущийРазмерЗадания = РазмерЗаданияНовыеЗаписи; + Иначе + ТекущийРазмерЗадания = РазмерЗаданияОсновнаяЗапись; + Если СвойстваСписка[ИмяПоляПараметровЗадания] = Истина Тогда + СвойстваСписка[ИмяПоляПараметровЗадания] = Null; + КонецЕсли; + КонецЕсли; + Если ТекущийРазмерЗадания = 1 Тогда + Строка[ИмяПоляДоли] = 0.99; + ИначеЕсли ТекущийРазмерЗадания = 2 Тогда + Строка[ИмяПоляДоли] = 0.90; + Иначе + Строка[ИмяПоляДоли] = 0.00; + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Функция ОбработаноПоДолям(ДоляОбработанныхДляПользователей, ДоляОбработанныхДляВнешнихПользователей, ИмяТаблицы, ДействующиеПараметры) + + ЕстьКлючиДляПользователей = Ложь; + ЕстьКлючиДляВнешнихПользователей = Ложь; + Версии = ДействующиеПараметры.ВерсииОграниченийСписков.Получить(ИмяТаблицы); + Если ЗначениеЗаполнено(Версии) Тогда + ЕстьКлючиДляПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 1)); + ЕстьКлючиДляВнешнихПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 2)); + КонецЕсли; + + Если ДоляОбработанныхДляПользователей < 1 Тогда + ЕстьКлючиДляПользователей = Истина; + КонецЕсли; + Если ДоляОбработанныхДляВнешнихПользователей < 1 Тогда + ЕстьКлючиДляВнешнихПользователей = Истина; + КонецЕсли; + + Если ЕстьКлючиДляПользователей И ЕстьКлючиДляВнешнихПользователей Тогда + Обработано = Цел((ДоляОбработанныхДляПользователей + + ДоляОбработанныхДляВнешнихПользователей) / 2 * 100); + + ИначеЕсли ЕстьКлючиДляПользователей Тогда + Обработано = Цел(ДоляОбработанныхДляПользователей * 100); + Иначе + Обработано = Цел(ДоляОбработанныхДляВнешнихПользователей * 100); + КонецЕсли; + + Возврат Обработано; + +КонецФункции + +Процедура ОбнулитьКоличествоЭлементов(Строка, Контекст); + + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементов, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементовДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементовДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяЭлементовДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяЭлементовДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей, 0, Строка, Контекст); + +КонецПроцедуры + +Процедура ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступа, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступаДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяКлючейДоступаДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяКлючейДоступаДляПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей, 0, Строка, Контекст); + +КонецПроцедуры + +Процедура ДобавитьНовуюСтрокуСписка(Контекст, Список, ИмяТаблицы) + + Строка = Новый Структура; + Строка.Вставить("Список", Список); + Строка.Вставить("СписокПредставление", Строка(Список)); + Строка.Вставить("ИмяТаблицы", ИмяТаблицы); + Строка.Вставить("ОбработаноЭлементов", 0); + Строка.Вставить("ОбработаноКлючейДоступа", 0); + Строка.Вставить("КоличествоЭлементов", 0); + Строка.Вставить("КоличествоКлючейДоступа", 0); + Строка.Вставить("КоличествоОбработанныхЭлементов", 0); + Строка.Вставить("КоличествоОбработанныхКлючейДоступа", 0); + Строка.Вставить("ПоследнееОбновление", '00010101'); + Строка.Вставить("ПервоеПланированиеОбновления", МаксимальнаяДата()); + + Строка.Вставить("КоличествоЭлементовДляПользователей", 0); + Строка.Вставить("ДоляОбработанныхЭлементовДляПользователей", 1); + Строка.Вставить("КоличествоЭлементовДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОбработанныхЭлементовДляВнешнихПользователей", 1); + Строка.Вставить("КоличествоКлючейДоступаДляПользователей", 0); + Строка.Вставить("ДоляОбработанныхКлючейДоступаДляПользователей", 1); + Строка.Вставить("КоличествоКлючейДоступаДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОбработанныхКлючейДоступаДляВнешнихПользователей", 1); + + Строка.Вставить("КоличествоОставшихсяЭлементовДляПользователей", 0); + Строка.Вставить("ДоляОставшихсяЭлементовДляПользователей", 0); + Строка.Вставить("КоличествоОставшихсяЭлементовДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОставшихсяЭлементовДляВнешнихПользователей", 0); + Строка.Вставить("КоличествоОставшихсяКлючейДоступаДляПользователей", 0); + Строка.Вставить("ДоляОставшихсяКлючейДоступаДляПользователей", 0); + Строка.Вставить("КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей", 0); + Строка.Вставить("ДоляОставшихсяКлючейДоступаДляВнешнихПользователей", 0); + + Контекст.ХранимыеДанные.СтрокиСписков.Вставить(Список, Строка); + ДобавленныеСтроки = Контекст.ДобавленныеСтроки; // Массив + ДобавленныеСтроки.Добавить(Строка); + + Свойства = Новый Структура; + Свойства.Вставить("РазмерЗаданияОбновленияЭлементов", 0); + Свойства.Вставить("ПоследнийОбновленныйЭлемент", Null); + Свойства.Вставить("РазмерЗаданияОбновленияКлючейДоступа", 0); + Свойства.Вставить("ПоследнийОбновленныйКлючДоступа", Null); + + Свойства.Вставить("РазмерЗаданияОбновленияЭлементовДляВнешнихПользователей", 0); + Свойства.Вставить("ПоследнийОбновленныйЭлементДляВнешнихПользователей", Null); + Свойства.Вставить("РазмерЗаданияОбновленияКлючейДоступаДляВнешнихПользователей", 0); + Свойства.Вставить("ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей", Null); + + Контекст.ХранимыеДанные.СвойстваСписков.Вставить(Список, Свойства); + +КонецПроцедуры + +// Параметры: +// Контекст - Структура: +// * ДобавленныеСтроки - Массив +// * ИзмененныеСтроки - Соответствие +// * СвойстваСписков - Соответствие +// * СтрокиСписков - Соответствие +// * ДействующиеПараметры - см. ДействующиеПараметрыОграниченияДоступа +// * СтрокиОбновленияКоличестваЭлементов - Массив +// * СтрокиОбновленияКоличестваКлючейДоступа - Массив +// * ИдентификаторыТаблиц - см. ОбщегоНазначения.ИдентификаторыОбъектовМетаданных +// * ХранимыеДанные - см. НовыеХранимыеДанныеОбновленияПрогресса +// * ТипыТаблицПоИменам - Соответствие +// +// ВсегоОбновлено - Число +// +Процедура РассчитатьВсегоОбновленоПоКоличествуДанных(Контекст, ВсегоОбновлено) + + ТипыТаблицПоИменам = УправлениеДоступомСлужебныйПовтИсп.СинтаксисЯзыка().ТипыТаблиц.ПоИменам; + Контекст.Вставить("ТипыТаблицПоИменам", ТипыТаблицПоИменам); + + Если Не Контекст.ХранимыеДанные.Свойство("КоличествоЭлементовПоСпискам") Тогда + ЗаполнитьКоличествоЭлементовИКлючейДоступаПоСпискам(Контекст); + КонецЕсли; + + ОбновитьКоличествоЭлементовИКлючейДоступа(Контекст); + + КоличествоЭлементовПоСпискам = Контекст.ХранимыеДанные.КоличествоЭлементовПоСпискам; + КоличествоКлючейДоступаПоСпискам = Контекст.ХранимыеДанные.КоличествоКлючейДоступаПоСпискам; + + ОбщееКоличествоЭлементов = 0; + Для Каждого КлючИЗначение Из КоличествоЭлементовПоСпискам Цикл + ОбщееКоличествоЭлементов = ОбщееКоличествоЭлементов + КлючИЗначение.Значение; + КонецЦикла; + ОбщееКоличествоЭлементов = ?(ОбщееКоличествоЭлементов = 0, 100, ОбщееКоличествоЭлементов); + + ОбщееКоличествоКлючейДоступа = 0; + Для Каждого КлючИЗначение Из КоличествоКлючейДоступаПоСпискам Цикл + ОбщееКоличествоКлючейДоступа = ОбщееКоличествоКлючейДоступа + КлючИЗначение.Значение; + КонецЦикла; + ОбщееКоличествоКлючейДоступа = ?(ОбщееКоличествоКлючейДоступа = 0, 100, ОбщееКоличествоКлючейДоступа); + + ВсегоОбновленоЭлементов = 0; + ВсегоОбновленоКлючейДоступа = 0; + + ДобавкаОбщегоКоличестваЭлементов = 0; + ДобавкаОбщегоКоличестваКлючейДоступа = 0; + + ИменаТаблицСОбновлениемЭлементов = Новый Соответствие; + ИменаТаблицСОбновлениемКлючейДоступа = Новый Соответствие; + + Для Каждого КлючИЗначение Из Контекст.СтрокиСписков Цикл + Строка = КлючИЗначение.Значение; + + КоличествоЭлементов = КоличествоЭлементовПоСпискам.Получить(КлючИЗначение.Значение.ИмяТаблицы); + Если КоличествоЭлементов = Неопределено Тогда + Если КоличествоЭлементовПоСпискам.Количество() = 0 Тогда + Добавка = 1; + Иначе + Добавка = Цел(ОбщееКоличествоЭлементов / КоличествоЭлементовПоСпискам.Количество() / 10); + Добавка = ?(Добавка = 0, 1, Добавка); + КонецЕсли; + ДобавкаОбщегоКоличестваЭлементов = ДобавкаОбщегоКоличестваЭлементов + Добавка; + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + 100 * Добавка; + Иначе + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + Строка.ОбработаноЭлементов * КоличествоЭлементов; + ИменаТаблицСОбновлениемЭлементов.Вставить(КлючИЗначение.Значение.ИмяТаблицы, Истина); + КонецЕсли; + + КоличествоКлючейДоступа = КоличествоКлючейДоступаПоСпискам.Получить(КлючИЗначение.Значение.ИмяТаблицы); + Если КоличествоКлючейДоступа = Неопределено Тогда + Если КоличествоКлючейДоступаПоСпискам.Количество() = 0 Тогда + Добавка = 1; + Иначе + Добавка = Цел(ОбщееКоличествоКлючейДоступа / КоличествоКлючейДоступаПоСпискам.Количество() / 10); + Добавка = ?(Добавка = 0, 1, Добавка); + КонецЕсли; + ДобавкаОбщегоКоличестваКлючейДоступа = ДобавкаОбщегоКоличестваКлючейДоступа + Добавка; + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + 100 * Добавка; + Иначе + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + Строка.ОбработаноКлючейДоступа * КоличествоКлючейДоступа; + ИменаТаблицСОбновлениемКлючейДоступа.Вставить(КлючИЗначение.Значение.ИмяТаблицы, Истина); + КонецЕсли; + КонецЦикла; + + КоличествоОбновленныхЭлементов = 0; + Для Каждого КлючИЗначение Из КоличествоЭлементовПоСпискам Цикл + Если ИменаТаблицСОбновлениемЭлементов.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + КоличествоОбновленныхЭлементов = КоличествоОбновленныхЭлементов + КлючИЗначение.Значение; + КонецЕсли; + КонецЦикла; + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + КоличествоОбновленныхЭлементов * 100; + + КоличествоОбновленныхКлючейДоступа = 0; + Для Каждого КлючИЗначение Из КоличествоКлючейДоступаПоСпискам Цикл + Если ИменаТаблицСОбновлениемКлючейДоступа.Получить(КлючИЗначение.Ключ) = Неопределено Тогда + КоличествоОбновленныхКлючейДоступа = КоличествоОбновленныхКлючейДоступа + КлючИЗначение.Значение; + КонецЕсли; + КонецЦикла; + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + КоличествоОбновленныхКлючейДоступа * 100; + + ВсегоОбновленоЭлементов = ВсегоОбновленоЭлементов + / (ОбщееКоличествоЭлементов + ДобавкаОбщегоКоличестваЭлементов); + + ВсегоОбновленоКлючейДоступа = ВсегоОбновленоКлючейДоступа + / (ОбщееКоличествоКлючейДоступа + ДобавкаОбщегоКоличестваКлючейДоступа); + + ВсегоОбновлено = (ВсегоОбновленоЭлементов + ВсегоОбновленоКлючейДоступа) / 2; + +КонецПроцедуры + +Процедура ЗаполнитьКоличествоЭлементовИКлючейДоступаПоСпискам(Контекст) + + КоличествоЭлементовПоСпискам = Новый Соответствие; + КоличествоКлючейДоступаПоСпискам = Новый Соответствие; + Контекст.ХранимыеДанные.Вставить("КоличествоЭлементовПоСпискам", КоличествоЭлементовПоСпискам); + Контекст.ХранимыеДанные.Вставить("КоличествоКлючейДоступаПоСпискам", КоличествоКлючейДоступаПоСпискам); + + ОписаниеЗапроса = Новый Структура("Запрос, ТекстыПакетаЗапросов", Новый Запрос, Новый Массив); + + ОбновляемыеТаблицы = Новый Соответствие; + ИдентификаторыТаблиц = Контекст.ИдентификаторыТаблиц; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл + Если ИдентификаторыТаблиц.Получить(Строка.ИмяТаблицы) = Строка.Список Тогда + ОбновляемыеТаблицы.Вставить(Строка.ИмяТаблицы, Строка.Список); + КонецЕсли; + КонецЦикла; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл + Если ИдентификаторыТаблиц.Получить(Строка.ИмяТаблицы) = Строка.Список Тогда + ОбновляемыеТаблицы.Вставить(Строка.ИмяТаблицы, Строка.Список); + КонецЕсли; + КонецЦикла; + + Индекс = 0; + ИменаТаблиц = Новый Массив; + Для Каждого КлючИЗначение Из Контекст.ИдентификаторыТаблиц Цикл + Если ОбновляемыеТаблицы.Получить(КлючИЗначение.Ключ) = КлючИЗначение.Значение Тогда + Продолжить; + КонецЕсли; + ИменаТаблиц.Добавить(КлючИЗначение.Ключ); + Строка = Новый Структура("Список, ИмяТаблицы", КлючИЗначение.Значение, КлючИЗначение.Ключ); + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Ложь); + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Истина); + КонецЦикла; + + Если ОписаниеЗапроса.ТекстыПакетаЗапросов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + РезультатыЗапроса = ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса); + + Индекс = 0; + Для Каждого ИмяТаблицы Из ИменаТаблиц Цикл + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоЭлементовДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоЭлементовДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоЭлементовПоСпискам[ИмяТаблицы] = КоличествоЭлементовДляПользователей + + КоличествоЭлементовДляВнешнихПользователей; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоКлючейДоступаДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + КоличествоКлючейДоступаДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоКлючейДоступаПоСпискам[ИмяТаблицы] = КоличествоКлючейДоступаДляПользователей + + КоличествоКлючейДоступаДляВнешнихПользователей; + КонецЦикла; + +КонецПроцедуры + +Процедура ОбновитьКоличествоЭлементовИКлючейДоступа(Контекст) + + ОписаниеЗапроса = Новый Структура("Запрос, ТекстыПакетаЗапросов", Новый Запрос, Новый Массив); + Индекс = 0; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + КонецЦикла; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Ложь); + ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Истина); + ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, Ложь); + ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, Истина); + КонецЦикла; + + Если ОписаниеЗапроса.ТекстыПакетаЗапросов.Количество() = 0 Тогда + Возврат; + КонецЕсли; + + РезультатыЗапроса = ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса); + + КоличествоЭлементовПоСпискам = Контекст.ХранимыеДанные.КоличествоЭлементовПоСпискам; + КоличествоКлючейДоступаПоСпискам = Контекст.ХранимыеДанные.КоличествоКлючейДоступаПоСпискам; + ВерсииОграниченийСписков = Контекст.ДействующиеПараметры.ВерсииОграниченийСписков; + ТипыТаблицПоИменам = Контекст.ТипыТаблицПоИменам; + + Индекс = 0; + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваЭлементов Цикл + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоЭлементовДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоЭлементовДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоЭлементов = Строка.КоличествоЭлементовДляПользователей + Строка.КоличествоЭлементовДляВнешнихПользователей; + Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда + КоличествоЭлементовПоСпискам.Вставить(Строка.ИмяТаблицы, КоличествоЭлементов); + КонецЕсли; + + Если КоличествоЭлементов = 0 Тогда + ОбнулитьКоличествоЭлементов(Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, 100, Строка, Контекст); + Индекс = Индекс + 2; + Иначе + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + ЕстьКлючиДляПользователей = Ложь; + ЕстьКлючиДляВнешнихПользователей = Ложь; + Версии = ВерсииОграниченийСписков.Получить(Строка.ИмяТаблицы); + Если ЗначениеЗаполнено(Версии) Тогда + ЕстьКлючиДляПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 1)); + ЕстьКлючиДляВнешнихПользователей = ЗначениеЗаполнено(СтрПолучитьСтроку(Версии, 2)); + КонецЕсли; + СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); + СвойстваТипа = ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйЭлемент, + Строка.КоличествоОставшихсяЭлементовДляПользователей, + Строка.КоличествоЭлементовДляПользователей, + Строка.ДоляОставшихсяЭлементовДляПользователей, + Строка.ДоляОбработанныхЭлементовДляПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхЭлементов = + Строка.КоличествоЭлементовДляПользователей + - Строка.КоличествоОставшихсяЭлементовДляПользователей; + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей, + Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей, + Строка.КоличествоЭлементовДляВнешнихПользователей, + Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей, + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхЭлементов = КоличествоОбработанныхЭлементов + + Строка.КоличествоЭлементовДляВнешнихПользователей + - Строка.КоличествоОставшихсяЭлементовДляВнешнихПользователей; + + КоличествоЭлементов = Строка.КоличествоЭлементовДляПользователей + Строка.КоличествоЭлементовДляВнешнихПользователей; + Если ЕстьКлючиДляПользователей И ЕстьКлючиДляВнешнихПользователей И СвойстваТипа.ЭтоСсылочныйТип Тогда + КоличествоЭлементов = КоличествоЭлементов / 2; + КоличествоОбработанныхЭлементов = КоличествоОбработанныхЭлементов / 2; + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.КоличествоЭлементов, КоличествоЭлементов, Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, + Цел(КоличествоОбработанныхЭлементов), Строка, Контекст); + Если Строка.КоличествоОбработанныхЭлементов > Строка.КоличествоЭлементов Тогда + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхЭлементов, + Строка.КоличествоЭлементов, Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноЭлементов, ?(Строка.КоличествоЭлементов = 0, 100, + Цел(Строка.КоличествоОбработанныхЭлементов / Строка.КоличествоЭлементов * 100)), Строка, Контекст); + КонецЕсли; + КонецЦикла; + + Для Каждого Строка Из Контекст.СтрокиОбновленияКоличестваКлючейДоступа Цикл + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоКлючейДоступаДляПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + Выборка = РезультатыЗапроса[Индекс].Выбрать(); + Строка.КоличествоКлючейДоступаДляВнешнихПользователей = ?(Выборка.Следующий(), Выборка.Количество, 0); + Индекс = Индекс + 1; + + КоличествоКлючейДоступа = Строка.КоличествоКлючейДоступаДляПользователей + + Строка.КоличествоКлючейДоступаДляВнешнихПользователей; + ОбновитьЗначениеВСтроке(Строка.КоличествоКлючейДоступа, КоличествоКлючейДоступа, Строка, Контекст); + Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда + КоличествоКлючейДоступаПоСпискам.Вставить(Строка.ИмяТаблицы, КоличествоКлючейДоступа); + КонецЕсли; + + Если Строка.КоличествоКлючейДоступа = 0 Тогда + ОбнулитьКоличествоКлючейДоступа(Строка, Контекст); + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, 100, Строка, Контекст); + Индекс = Индекс + 2; + Иначе + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйКлючДоступа, + Строка.КоличествоОставшихсяКлючейДоступаДляПользователей, + Строка.КоличествоКлючейДоступаДляПользователей, + Строка.ДоляОставшихсяКлючейДоступаДляПользователей, + Строка.ДоляОбработанныхКлючейДоступаДляПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхКлючейДоступа = + Строка.КоличествоКлючейДоступаДляПользователей + - Строка.КоличествоОставшихсяКлючейДоступаДляПользователей; + + ОбновитьКоличество(РезультатыЗапроса[Индекс], + СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей, + Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей, + Строка.КоличествоКлючейДоступаДляВнешнихПользователей, + Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей, + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей); + Индекс = Индекс + 1; + КоличествоОбработанныхКлючейДоступа = КоличествоОбработанныхКлючейДоступа + + Строка.КоличествоКлючейДоступаДляВнешнихПользователей + - Строка.КоличествоОставшихсяКлючейДоступаДляВнешнихПользователей; + + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, + Цел(КоличествоОбработанныхКлючейДоступа), Строка, Контекст); + Если Строка.КоличествоОбработанныхКлючейДоступа > Строка.КоличествоКлючейДоступа Тогда + ОбновитьЗначениеВСтроке(Строка.КоличествоОбработанныхКлючейДоступа, + Строка.КоличествоКлючейДоступа, Строка, Контекст); + КонецЕсли; + ОбновитьЗначениеВСтроке(Строка.ОбработаноКлючейДоступа, + Цел(Строка.КоличествоОбработанныхКлючейДоступа / Строка.КоличествоКлючейДоступа * 100), Строка, Контекст); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +// Для процедуры ОбновитьКоличествоЭлементовИКлючейДоступа. +Процедура ОбновитьКоличество(РезультатЗапроса, ПоследнийОбновленный, + КоличествоОставшихся, Количество, ДоляОставшихся, ДоляОбработанных) + + Если ПоследнийОбновленный = Null Или ПоследнийОбновленный = Истина Тогда + НовоеКоличествоОставшихся = -1; + Иначе + Выборка = РезультатЗапроса.Выбрать(); + НовоеКоличествоОставшихся = ?(Выборка.Следующий(), Выборка.Количество, 0); + КонецЕсли; + + Если НовоеКоличествоОставшихся = -1 Тогда + ДоляОставшихся = 0; + НовоеКоличествоОставшихся = 0; + КонецЕсли; + + Если ТипЗнч(НовоеКоличествоОставшихся) = Тип("Число") Тогда + КоличествоОставшихся = Цел(Количество * (1 - ДоляОбработанных - ДоляОставшихся) + 0.99) + + Цел(НовоеКоличествоОставшихся * ДоляОставшихся); + КонецЕсли; + +КонецПроцедуры + +// Возвращаемое значение: +// Массив из РезультатЗапроса +// +Функция ВыполнитьПакетЗапросовПоЧастям(ОписаниеЗапроса) + + РезультатыПакетаЗапросов = Новый Массив; + + ТекстыПорцииЗапросов = Новый Массив; + Для Каждого ТекстЗапроса Из ОписаниеЗапроса.ТекстыПакетаЗапросов Цикл + Если ТекстыПорцииЗапросов.Количество() = 200 Тогда + // @skip-check query-in-loop - Порционная обработка данных + ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса); + ТекстыПорцииЗапросов = Новый Массив; + КонецЕсли; + ТекстыПорцииЗапросов.Добавить(ТекстЗапроса); + КонецЦикла; + ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса); + + Возврат РезультатыПакетаЗапросов; + +КонецФункции + +Процедура ДобавитьРезультатыЗапроса(РезультатыПакетаЗапросов, ТекстыПорцииЗапросов, ОписаниеЗапроса) + + Запрос = ОписаниеЗапроса.Запрос; + + Запрос.Текст = СтрСоединить(ТекстыПорцииЗапросов, ОбщегоНазначения.РазделительПакетаЗапросов()); + РезультатыЗапроса = Запрос.ВыполнитьПакет(); + Запрос.Текст = ""; + + Для Каждого РезультатЗапроса Из РезультатыЗапроса Цикл + РезультатыПакетаЗапросов.Добавить(РезультатЗапроса); + КонецЦикла; + +КонецПроцедуры + +Процедура ОбновитьЗначениеВСтроке(СтароеЗначение, НовоеЗначение, Строка, Контекст) + + Если СтароеЗначение = НовоеЗначение Тогда + Возврат; + КонецЕсли; + СтароеЗначение = НовоеЗначение; + + Если Контекст.ДобавленныеСтроки.Найти(Строка) = Неопределено + И Контекст.ИзмененныеСтроки.Получить(Строка) = Неопределено Тогда + + Контекст.ИзмененныеСтроки.Вставить(Строка.Список, Строка); + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьТекстЗапросаКоличестваЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) + + Версии = Контекст.ДействующиеПараметры.ВерсииОграниченийСписков.Получить(Строка.ИмяТаблицы); + + Если ЗначениеЗаполнено(Версии) + И ЗначениеЗаполнено(Строка.ИмяТаблицы) + Или Строка.ИмяТаблицы = "Справочник.НаборыГруппДоступа" Тогда + + СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); + СвойстваТипа = Контекст.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + Если СвойстваТипа.ЭтоСсылочныйТип Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица"; + Иначе + ТекстЗапроса = ТекстЗапросаКоличестваЭлементовРегистра(Контекст, Строка, Индекс, ДляВнешнихПользователей); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", Строка.ИмяТаблицы); + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | 0 КАК Количество"; + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Функция ТекстЗапросаКоличестваЭлементовРегистра(Контекст, Строка, Индекс, ДляВнешнихПользователей) + + Если ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + Свойства = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Строка.ИмяТаблицы); + + Если Свойства = Неопределено + Или Свойства.ОпорныеПоля = Неопределено + Или Свойства.ОпорныеПоля.Используемые.Количество() = 0 Тогда + + Возврат + "ВЫБРАТЬ + | 0 КАК Количество"; + КонецЕсли; + + ПоляВыбора = ""; + Для Каждого ИмяПоля Из Свойства.ОпорныеПоля.Используемые Цикл + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", ", + | ") + "ТекущаяТаблица." + ИмяПоля; + КонецЦикла; + + Если Свойства.ОпорныеПоля.Используемые.Количество() = 1 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ &ПоляВыбора) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ПоляВыбора КАК ПоляВыбора + | ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица) КАК Комбинации"; + ПоляВыбора = ТекстСОтступом(ПоляВыбора, " "); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляВыбора", ПоляВыбора); + + Возврат ТекстЗапроса; + +КонецФункции + +Процедура ДобавитьТекстЗапросаКоличестваОставшихсяЭлементов(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) + + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + СпискиСДатой = Контекст.ДействующиеПараметры.СпискиСДатой; + + Если ЗначениеЗаполнено(Строка.ИмяТаблицы) Тогда + СоставИмени = СтрРазделить(Строка.ИмяТаблицы, ".", Ложь); + СвойстваТипа = Контекст.ТипыТаблицПоИменам.Получить(ВРег(СоставИмени[0])); + Иначе + СвойстваСписка = Неопределено; + КонецЕсли; + + Если СвойстваСписка = Неопределено Тогда + ПараметрыЗадания = Неопределено; + + ИначеЕсли ДляВнешнихПользователей Тогда + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйЭлементДляВнешнихПользователей; + Иначе + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйЭлемент; + КонецЕсли; + + Если ТипЗнч(ПараметрыЗадания) <> Тип("ХранилищеЗначения") Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | НЕОПРЕДЕЛЕНО КАК Количество"; + Иначе + ДолиКоличестваЭлементов = Новый Структура("Обработанных, Оставшихся", 0, 1); + ПараметрыЗадания = ПараметрыЗадания.Получить(); + + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") + И ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") + И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент) = Тип("Структура") + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ВидКлючаДанных") + И ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных) <> Неопределено + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("КлючДанных") + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ОбработатьУстаревшиеЭлементы") + И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ОбработатьУстаревшиеЭлементы) = Тип("Булево") Тогда + + ПоследнийОбновленныйЭлемент = ПараметрыЗадания.ПоследнийОбновленныйЭлемент; + Иначе + ПоследнийОбновленныйЭлемент = Новый Структура; + ПоследнийОбновленныйЭлемент.Вставить("ВидКлючаДанных", "ЭлементыДанныхСУстаревшимиКлючами"); + ПоследнийОбновленныйЭлемент.Вставить("КлючДанных"); + КонецЕсли; + + УсловиеОтбора = ""; + Если СвойстваТипа.ЭтоСсылочныйТип Тогда + КлючДанных = ПоследнийОбновленныйЭлемент.КлючДанных; + Если СпискиСДатой.Получить(Строка.ИмяТаблицы) <> Неопределено Тогда + + Если ПоследнийОбновленныйЭлемент.Свойство("Дата") + И ТипЗнч(ПоследнийОбновленныйЭлемент.Дата) = Тип("Дата") Тогда + + ИмяПараметра = "ПоследняяДата" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "ТекущаяТаблица.Дата <= &" + ИмяПараметра; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийОбновленныйЭлемент.Дата); + КонецЕсли; + + ИначеЕсли ЗначениеЗаполнено(КлючДанных) Тогда + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(КлючДанных)); + Если ОбъектМетаданных <> Неопределено + И ОбъектМетаданных.ПолноеИмя() = Строка.ИмяТаблицы Тогда + + ИмяПараметра = "ПоследняяСсылка" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "ТекущаяТаблица.Ссылка > &" + ИмяПараметра; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, КлючДанных); + КонецЕсли; + КонецЕсли; + Если ЗначениеЗаполнено(УсловиеОтбора) Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + |ГДЕ + | &УсловиеОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | -1 КАК Количество"; + КонецЕсли; + ЗаполнитьДолиКоличествоЭлементовСсылочногоТипа(ДолиКоличестваЭлементов, + ПоследнийОбновленныйЭлемент, Строка.ИмяТаблицы); + Иначе + Если ДляВнешнихПользователей Тогда + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей; + Иначе + ДополнительныйКонтекст = Контекст.ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей; + КонецЕсли; + СвойстваОграничения = ДополнительныйКонтекст.СвойстваОграниченияСписков.Получить(Строка.ИмяТаблицы); + + Если СвойстваОграничения <> Неопределено Тогда + ИспользуемыеВариантыДоступа = ДополнительныйКонтекст.ОсновныеВариантыДоступа.Получить(Строка.ИмяТаблицы); + Если ИспользуемыеВариантыДоступа = Неопределено Тогда + СвойстваОграничения = Неопределено; + Иначе + СвойстваОграничения = Новый Структура(СвойстваОграничения); + СвойстваОграничения.Вставить("ВариантДоступа", ИспользуемыеВариантыДоступа[0].ВариантДоступа); + КонецЕсли; + КонецЕсли; + + ЗаполнитьДолиКоличестваЭлементовРегистра(ДолиКоличестваЭлементов, + ПоследнийОбновленныйЭлемент, СвойстваОграничения); + + ТекстЗапроса = ТекстЗапросаКоличестваОставшихсяЭлементовРегистра(ОписаниеЗапроса, Строка, Индекс, + ДляВнешнихПользователей, ПоследнийОбновленныйЭлемент, СвойстваОграничения, СвойстваТипа); + КонецЕсли; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", Строка.ИмяТаблицы); + + Если ДляВнешнихПользователей Тогда + Строка.ДоляОбработанныхЭлементовДляВнешнихПользователей = ДолиКоличестваЭлементов.Обработанных; + Строка.ДоляОставшихсяЭлементовДляВнешнихПользователей = ДолиКоличестваЭлементов.Оставшихся; + Иначе + Строка.ДоляОбработанныхЭлементовДляПользователей = ДолиКоличестваЭлементов.Обработанных; + Строка.ДоляОставшихсяЭлементовДляПользователей = ДолиКоличестваЭлементов.Оставшихся; + КонецЕсли; + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Процедура ЗаполнитьДолиКоличествоЭлементовСсылочногоТипа(ДолиКоличестваЭлементов, Элемент, ИмяТаблицы) + + Если ИмяТаблицы = "Справочник.НаборыГруппДоступа" Тогда + Если Элемент.ВидКлючаДанных = "НовыеНаборыИзОдногоПользователя" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.0; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппДоступаНазначенныеПользователям" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.1; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппПользователейНазначенныеПользователям" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.2; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НовыеНаборыГруппСУстаревшимиПравами" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.3; + ДолиКоличестваЭлементов.Оставшихся = 0.2; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппРазрешенныеПользователям" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.5; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + + ИначеЕсли Элемент.ВидКлючаДанных = "НаборыГруппСУстаревшимиПравами" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.6; + ДолиКоличестваЭлементов.Оставшихся = 0.3; + + Иначе // УстаревшиеЭлементы. + ДолиКоличестваЭлементов.Обработанных = 0.9; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + КонецЕсли; + Возврат; + КонецЕсли; + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда + ДолиКоличестваЭлементов.Обработанных = 0.0; + ДолиКоличестваЭлементов.Оставшихся = 0.9; + Иначе // УстаревшиеЭлементы. + ДолиКоличестваЭлементов.Обработанных = 0.9; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + КонецЕсли; + +КонецПроцедуры + +Функция ТекстЗапросаКоличестваОставшихсяЭлементовРегистра(ОписаниеЗапроса, Строка, Индекс, + ДляВнешнихПользователей, ПоследнийОбновленныйЭлемент, СвойстваОграничения, СвойстваТипа) + + ВидКлючаДанных = ПоследнийОбновленныйЭлемент.ВидКлючаДанных; + КлючДанных = ПоследнийОбновленныйЭлемент.КлючДанных; + + Если СвойстваОграничения = Неопределено + Или СвойстваОграничения.ОпорныеПоля = Неопределено + Или СвойстваОграничения.ОпорныеПоля.Используемые.Количество() = 0 + Или ТипЗнч(КлючДанных) <> Тип("Структура") + Или ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" + И (Не ПоследнийОбновленныйЭлемент.Свойство("Дата") + Или ТипЗнч(ПоследнийОбновленныйЭлемент.Дата) <> Тип("Дата")) + Или ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" + И СвойстваОграничения.ОпорныеПоля.Используемые.Количество() <> КлючДанных.Количество() + Или ВидКлючаДанных <> "ЭлементыБезКлючейПоПериоду" + И ВидКлючаДанных <> "ЭлементыБезКлючейПоЗначениямПолей" + И СвойстваОграничения.ОпорныеПоля.Используемые.Количество() > КлючДанных.Количество() Тогда + + Возврат + "ВЫБРАТЬ + | -1 КАК Количество"; + КонецЕсли; + + ПоляВыбора = ""; + УсловиеОтбора = ""; + УсловиеСоединения = ""; + + Если ЗначениеЗаполнено(СвойстваОграничения.ИмяОтдельногоРегистраКлючей) Тогда + ИмяРегистраКлючей = СвойстваОграничения.ИмяОтдельногоРегистраКлючей; + Иначе + ИмяРегистраКлючей = "КлючиДоступаКРегистрам"; + ИмяПараметра = "ИдентификаторРегистра" + Формат(Индекс, "ЧГ="); + УсловиеСоединения = "(КлючиДоступаКРегистрам.Регистр = &" + ИмяПараметра + ")"; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); + КонецЕсли; + + ОпорныеПоля = СвойстваОграничения.ОпорныеПоля; + ОтборПоТипуПользователей = XMLСтрока(СвойстваОграничения.ВариантДоступа); + УсловиеСоединения = УсловиеСоединения + ?(УсловиеСоединения = "", "", " + | И ") + "(КлючиДоступаКРегистрам.ВариантДоступа = " + ОтборПоТипуПользователей + ")"; // @query-part-3 + + НомерПоля = 1; + Для Каждого ИмяПоля Из ОпорныеПоля.Используемые Цикл + ИмяПоляВКлючеДанных = СтрШаблон("Поле%1", НомерПоля); + ИмяПараметра = ИмяПоля + Формат(Индекс, "ЧГ="); + + УсловиеСоединения = УсловиеСоединения + ?(УсловиеСоединения = "", "", " + | И ") + СтрШаблон("(КлючиДоступаКРегистрам.Поле%1 = ТекущаяТаблица.%2)", НомерПоля, ИмяПоля); // @query-part-3 + + Отбор = ""; + Для ТекущийИндекс = 0 По НомерПоля - 2 Цикл + ТекущееИмяПоля = ОпорныеПоля.Используемые[ТекущийИндекс]; + ТекущееИмяПараметра = ТекущееИмяПоля + Формат(Индекс, "ЧГ="); + Отбор = Отбор + ?(Отбор = "", "", " + | И ") + "ТекущаяТаблица." + ТекущееИмяПоля + " = &" + ТекущееИмяПараметра; // @query-part-3 + КонецЦикла; + Отбор = Отбор + ?(Отбор = "", "", " + | И ") + "ТекущаяТаблица." + ИмяПоля + " > &" + ИмяПараметра; // @query-part-3 + + УсловиеОтбора = УсловиеОтбора + ?(НомерПоля = 1, ?(ОпорныеПоля.Используемые.Количество() > 1, "(", "") + Отбор, " + | ИЛИ " + ТекстСОтступом(Отбор, " ")); // @query-part-3 + + Если КлючДанных.Свойство(ИмяПоляВКлючеДанных) Тогда + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, КлючДанных[ИмяПоляВКлючеДанных]); + Иначе + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Неопределено); + КонецЕсли; + ПоляВыбора = ПоляВыбора + ?(ПоляВыбора = "", "", ", + | ") + "ТекущаяТаблица." + ИмяПоля; + НомерПоля = НомерПоля + 1; + КонецЦикла; + + Если ОпорныеПоля.Используемые.Количество() > 1 Тогда + УсловиеОтбора = УсловиеОтбора + ")"; + КонецЕсли; + + Если ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + ИмяПоляПериода = ?(СвойстваТипа.ИмяКоллекции = "РегистрыРасчета", "ПериодРегистрации", "Период"); + ИмяПараметра = ИмяПоляПериода + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "(ТекущаяТаблица." + ИмяПоляПериода + " < &" + ИмяПараметра + " + | ИЛИ ТекущаяТаблица." + + ИмяПоляПериода + " = &" + ИмяПараметра + " + | И " + ТекстСОтступом(УсловиеОтбора, " ") + ")"; // @query-part-3, @query-part-5 + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийОбновленныйЭлемент.Дата); + КонецЕсли; + + Если СвойстваОграничения.ОпорныеПоля.Используемые.Количество() = 1 Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ &ПоляВыбора) КАК Количество + |ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО (&УсловиеСоединения) + |ГДЕ + | &УсловиеОтбора + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL"; + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | (ВЫБРАТЬ РАЗЛИЧНЫЕ + | &ПоляВыбора КАК ПоляВыбора + | ИЗ + | &ТекущаяТаблица КАК ТекущаяТаблица + | ЛЕВОЕ СОЕДИНЕНИЕ ТекущийСписок КАК КлючиДоступаКРегистрам + | ПО (&УсловиеСоединения) + | ГДЕ + | &УсловиеОтбора + | И КлючиДоступаКРегистрам.ВариантДоступа ЕСТЬ NULL) КАК Комбинации"; + ПоляВыбора = ТекстСОтступом(ПоляВыбора, " "); + УсловиеОтбора = ТекстСОтступом(УсловиеОтбора, " "); + КонецЕсли; + + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "(&УсловиеСоединения)", УсловиеСоединения); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПоляВыбора", ПоляВыбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ТекущийСписок", "РегистрСведений." + ИмяРегистраКлючей); + + Возврат ТекстЗапроса; + +КонецФункции + +Процедура ЗаполнитьДолиКоличестваЭлементовРегистра(ДолиКоличестваЭлементов, Элемент, СвойстваОграничения) + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиКлючами" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.0; + ДолиКоличестваЭлементов.Оставшихся = 0.5; + + ИначеЕсли Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоЗначениямПолей" + Или Элемент.ВидКлючаДанных = "ЭлементыБезКлючейПоПериоду" Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.5; + ДолиКоличестваЭлементов.Оставшихся = 0.4; + + ИначеЕсли Элемент.ВидКлючаДанных = "УстаревшиеЭлементы" Тогда + + Если СвойстваОграничения <> Неопределено + И ЗначениеЗаполнено(СвойстваОграничения.ИмяОтдельногоРегистраКлючей) Тогда + + ДолиКоличестваЭлементов.Обработанных = 0.90; + ДолиКоличестваЭлементов.Оставшихся = 0.09; + Иначе + ДолиКоличестваЭлементов.Обработанных = 0.9; + ДолиКоличестваЭлементов.Оставшихся = 0.1; + КонецЕсли; + + Иначе // НекорректныеЭлементы или НекорректныеЭлементыОбщегоРегистра. + ДолиКоличестваЭлементов.Обработанных = 0.99; + ДолиКоличестваЭлементов.Оставшихся = 0.01; + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьТекстЗапросаКоличестваКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, ДляВнешнихПользователей) + + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(КлючиДоступа.Ссылка) КАК Количество + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | КлючиДоступа.Список = &Список + | И КлючиДоступа.ДляВнешнихПользователей = ЛОЖЬ"; + + ИмяПараметра = "СписокКлючей" + Формат(Индекс, "ЧГ="); + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Список", "&" + ИмяПараметра); + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); + + Если ДляВнешнихПользователей Тогда + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ЛОЖЬ", "ИСТИНА"); + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Процедура ДобавитьТекстЗапросаКоличестваОставшихсяКлючейДоступа(ОписаниеЗапроса, Строка, Индекс, Контекст, ДляВнешнихПользователей) + + СвойстваСписка = Контекст.СвойстваСписков.Получить(Строка.Список); + + Если СвойстваСписка = Неопределено Тогда + ПараметрыЗадания = Неопределено; + + ИначеЕсли ДляВнешнихПользователей Тогда + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйКлючДоступаДляВнешнихПользователей; + Иначе + ПараметрыЗадания = СвойстваСписка.ПоследнийОбновленныйКлючДоступа; + КонецЕсли; + + Если ТипЗнч(ПараметрыЗадания) <> Тип("ХранилищеЗначения") Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | НЕОПРЕДЕЛЕНО КАК Количество"; + Иначе + ДолиКоличестваКлючейДоступа = Новый Структура("Обработанных, Оставшихся", 0, 1); + ПараметрыЗадания = ПараметрыЗадания.Получить(); + + Если ТипЗнч(ПараметрыЗадания) = Тип("Структура") + И ПараметрыЗадания.Свойство("ПоследнийОбновленныйЭлемент") + И ТипЗнч(ПараметрыЗадания.ПоследнийОбновленныйЭлемент) = Тип("Структура") + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("ВидКлючаДанных") + И ПорядокВидаКлючаДанных(ПараметрыЗадания.ПоследнийОбновленныйЭлемент.ВидКлючаДанных) <> Неопределено + И ПараметрыЗадания.ПоследнийОбновленныйЭлемент.Свойство("КлючДанных") Тогда + + ПоследнийКлючДоступа = ПараметрыЗадания.ПоследнийОбновленныйЭлемент.КлючДанных; + ЗаполнитьДолиКоличестваКлючейДоступа(ДолиКоличестваКлючейДоступа, + ПараметрыЗадания.ПоследнийОбновленныйЭлемент); + КонецЕсли; + УсловиеОтбора = ""; + Если ТипЗнч(ПоследнийКлючДоступа) = Тип("СправочникСсылка.КлючиДоступа") Тогда + ИмяПараметра = "СписокОбработанныхКлючей" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = "КлючиДоступа.Список = &" + ИмяПараметра; + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, Строка.Список); + + УсловиеОтбора = УсловиеОтбора + " + | И КлючиДоступа.ДляВнешнихПользователей = " + ?(ДляВнешнихПользователей, "ИСТИНА", "ЛОЖЬ"); // @query-part-1 + + ИмяПараметра = "ПоследнийКлючДоступа" + Формат(Индекс, "ЧГ="); + УсловиеОтбора = УсловиеОтбора + " + | И КлючиДоступа.Ссылка > &" + ИмяПараметра; // @query-part-1 + ОписаниеЗапроса.Запрос.УстановитьПараметр(ИмяПараметра, ПоследнийКлючДоступа); + КонецЕсли; + + Если ЗначениеЗаполнено(УсловиеОтбора) Тогда + ТекстЗапроса = + "ВЫБРАТЬ + | КОЛИЧЕСТВО(*) КАК Количество + |ИЗ + | Справочник.КлючиДоступа КАК КлючиДоступа + |ГДЕ + | &УсловиеОтбора"; + ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора); + Иначе + ТекстЗапроса = + "ВЫБРАТЬ + | -1 КАК Количество"; + КонецЕсли; + + Если ДляВнешнихПользователей Тогда + Строка.ДоляОбработанныхКлючейДоступаДляВнешнихПользователей = ДолиКоличестваКлючейДоступа.Обработанных; + Строка.ДоляОставшихсяКлючейДоступаДляВнешнихПользователей = ДолиКоличестваКлючейДоступа.Оставшихся; + Иначе + Строка.ДоляОбработанныхКлючейДоступаДляПользователей = ДолиКоличестваКлючейДоступа.Обработанных; + Строка.ДоляОставшихсяКлючейДоступаДляПользователей = ДолиКоличестваКлючейДоступа.Оставшихся; + КонецЕсли; + КонецЕсли; + + ОписаниеЗапроса.ТекстыПакетаЗапросов.Добавить(ТекстЗапроса); + Индекс = Индекс + 1; + +КонецПроцедуры + +Процедура ЗаполнитьДолиКоличестваКлючейДоступа(ДолиКоличестваКлючейДоступа, Элемент) + + Если Элемент.ВидКлючаДанных = "ЭлементыСУстаревшимиПравами" Тогда + ДолиКоличестваКлючейДоступа.Обработанных = 0.0; + ДолиКоличестваКлючейДоступа.Оставшихся = 0.9; + Иначе // УстаревшиеЭлементы. + ДолиКоличестваКлючейДоступа.Обработанных = 0.9; + ДолиКоличестваКлючейДоступа.Оставшихся = 0.1; + КонецЕсли; + +КонецПроцедуры + +// Параметры: +// ДействующиеПараметры - см. ДействующиеПараметрыОграниченияДоступа +// +// Возвращаемое значение: +// см. ОбщегоНазначения.ИдентификаторыОбъектовМетаданных +// +Функция ИдентификаторыСписковСОграничением(ДействующиеПараметры) + + ДействующиеПараметры = ДействующиеПараметрыОграниченияДоступа(Неопределено, Неопределено, Ложь); + + Списки = Новый Массив; + Для Каждого ОписаниеВерсии Из ДействующиеПараметры.ВерсииОграниченийСписков Цикл + Списки.Добавить(ОписаниеВерсии.Ключ); + КонецЦикла; + + Возврат ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(Списки, Ложь); + +КонецФункции + +Функция ТекущаяДатаНаСервере() Экспорт + + // АПК:143-выкл - №643.2.1 Требуется ТекущаяДата сервера, а не ТекущаяДатаСеанса, + // так как именно ТекущаяДата записывается в журнал регистрации. + Возврат ТекущаяДата(); + // АПК:143-вкл. + +КонецФункции + +#КонецОбласти + +#КонецОбласти + #КонецОбласти \ No newline at end of file From 9b295c96abae4f8cf26696032f16f6981caea37c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:49:42 +0000 Subject: [PATCH 7/9] Add JMH benchmark tests for BSLTokenizer with rebuild functionality Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- build.gradle.kts | 4 + .../bsl/parser/JMXBSLLexerTest.java | 10 +- .../bsl/parser/JMXBSLParserTest.java | 9 +- .../bsl/parser/JMXBSLTokenizerTest.java | 136 ++++++++++++++++++ 4 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java diff --git a/build.gradle.kts b/build.gradle.kts index 4e6b11a2..034ed40f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -100,6 +100,10 @@ tasks.processTestResources { duplicatesStrategy = DuplicatesStrategy.INCLUDE } +tasks.named("processJmhResources") { + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + idea { module { // Marks the already(!) added srcDir as "generated" diff --git a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLLexerTest.java b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLLexerTest.java index ed0d9636..2ced5cf0 100644 --- a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLLexerTest.java +++ b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLLexerTest.java @@ -25,8 +25,8 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Parser; -import org.antlr.v4.runtime.UnicodeCharStream; -import org.apache.commons.io.IOUtils; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Tokenizer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Measurement; @@ -67,7 +67,7 @@ public JMXBSLLexerTest() { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try (InputStream inputStream = classLoader.getResourceAsStream("Module.bsl")) { assert inputStream != null; - content = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { e.printStackTrace(); } @@ -87,9 +87,9 @@ public void lexerTest() var tokenizer = new Tokenizer<>(content, lexer, parserClass) { @Override - protected BSLParserRuleContext rootAST() { + protected ParserRuleContext rootAST() { try { - return (BSLParserRuleContext) parserRootASTMethod.invoke(parser); + return (ParserRuleContext) parserRootASTMethod.invoke(parser); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("Error: ", e); } diff --git a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLParserTest.java b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLParserTest.java index 820d8a2e..513c70d5 100644 --- a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLParserTest.java +++ b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLParserTest.java @@ -25,7 +25,8 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Parser; -import org.apache.commons.io.IOUtils; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Tokenizer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Measurement; @@ -66,7 +67,7 @@ public JMXBSLParserTest() { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try (InputStream inputStream = classLoader.getResourceAsStream("Module.bsl")) { assert inputStream != null; - content = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { e.printStackTrace(); } @@ -86,9 +87,9 @@ public void parserTest() var tokenizer = new Tokenizer<>(content, lexer, parserClass) { @Override - protected BSLParserRuleContext rootAST() { + protected ParserRuleContext rootAST() { try { - return (BSLParserRuleContext) parserRootASTMethod.invoke(parser); + return (ParserRuleContext) parserRootASTMethod.invoke(parser); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("Error: ", e); } diff --git a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java new file mode 100644 index 00000000..c8752d7b --- /dev/null +++ b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java @@ -0,0 +1,136 @@ +/* + * This file is a part of BSL Parser. + * + * Copyright (c) 2018-2025 + * Alexey Sosnoviy , Nikita Fedkin , Sergey Batanov + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * BSL Parser is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * BSL Parser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with BSL Parser. + */ +package com.github._1c_syntax.bsl.parser; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +/** + * JMH benchmark tests for BSLTokenizer. + * Tests new tokenizer creation, rebuild, and incremental text modifications. + */ +@BenchmarkMode(Mode.SampleTime) +@Warmup(iterations = 2) +@Measurement(iterations = 2, batchSize = 2) +@State(Scope.Thread) +public class JMXBSLTokenizerTest { + + private static final String MINIMAL_PROCEDURE = "\nПроцедура ТестоваяПроцедура()\n\tВозврат;\nКонецПроцедуры\n"; + + private String content; + private String contentWithProcedureAtBeginning; + private String contentWithProcedureAtMiddle; + private String contentWithProcedureAtEnd; + private BSLTokenizer tokenizerForRebuild; + + public JMXBSLTokenizerTest() { + final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try (InputStream inputStream = classLoader.getResourceAsStream("Module.bsl")) { + assert inputStream != null; + content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } + + // Prepare content with procedure inserted at various positions + contentWithProcedureAtBeginning = MINIMAL_PROCEDURE + content; + contentWithProcedureAtEnd = content + MINIMAL_PROCEDURE; + + // Insert procedure at the middle of the text + int middlePosition = content.length() / 2; + // Find the nearest line break to avoid breaking in the middle of a statement + int lineBreakPos = content.indexOf('\n', middlePosition); + if (lineBreakPos == -1) { + lineBreakPos = middlePosition; + } + contentWithProcedureAtMiddle = content.substring(0, lineBreakPos) + MINIMAL_PROCEDURE + content.substring(lineBreakPos); + } + + @Setup(Level.Invocation) + public void setupRebuildTokenizer() { + tokenizerForRebuild = new BSLTokenizer(content); + // Compute initial tokens and AST to prime the tokenizer + tokenizerForRebuild.getTokens(); + tokenizerForRebuild.getAst(); + } + + /** + * Test 1: Create new BSLTokenizer, call getTokens and getAst. + */ + @Benchmark + public void newTokenizerGetTokensAndAst() { + var tokenizer = new BSLTokenizer(content); + tokenizer.getTokens(); + tokenizer.getAst(); + } + + /** + * Test 2: Use rebuild with the same text (no new tokenizer creation). + */ + @Benchmark + public void rebuildWithSameText() { + tokenizerForRebuild.rebuild(content); + tokenizerForRebuild.getTokens(); + tokenizerForRebuild.getAst(); + } + + /** + * Test 3: Insert minimal procedure at the beginning of the text. + */ + @Benchmark + public void insertProcedureAtBeginning() { + tokenizerForRebuild.rebuild(contentWithProcedureAtBeginning); + tokenizerForRebuild.getTokens(); + tokenizerForRebuild.getAst(); + } + + /** + * Test 4: Insert minimal procedure at the middle of the text. + */ + @Benchmark + public void insertProcedureAtMiddle() { + tokenizerForRebuild.rebuild(contentWithProcedureAtMiddle); + tokenizerForRebuild.getTokens(); + tokenizerForRebuild.getAst(); + } + + /** + * Test 5: Insert minimal procedure at the end of the text. + */ + @Benchmark + public void insertProcedureAtEnd() { + tokenizerForRebuild.rebuild(contentWithProcedureAtEnd); + tokenizerForRebuild.getTokens(); + tokenizerForRebuild.getAst(); + } +} From 7eaf1f9731ce75d4c236f964c0a981e572061c6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 13:51:32 +0000 Subject: [PATCH 8/9] Address code review: fix null check and Setup level for rebuild benchmarks Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java index c8752d7b..69bef601 100644 --- a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java +++ b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java @@ -56,10 +56,12 @@ public class JMXBSLTokenizerTest { public JMXBSLTokenizerTest() { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try (InputStream inputStream = classLoader.getResourceAsStream("Module.bsl")) { - assert inputStream != null; + if (inputStream == null) { + throw new IllegalStateException("Module.bsl resource not found"); + } content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { - e.printStackTrace(); + throw new IllegalStateException("Failed to read Module.bsl resource", e); } // Prepare content with procedure inserted at various positions @@ -76,7 +78,7 @@ public JMXBSLTokenizerTest() { contentWithProcedureAtMiddle = content.substring(0, lineBreakPos) + MINIMAL_PROCEDURE + content.substring(lineBreakPos); } - @Setup(Level.Invocation) + @Setup(Level.Iteration) public void setupRebuildTokenizer() { tokenizerForRebuild = new BSLTokenizer(content); // Compute initial tokens and AST to prime the tokenizer From 536c97c8013db204b5bc7b44cc17fd5e60aad866 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 14:48:16 +0000 Subject: [PATCH 9/9] Update JMH plugin to 0.7.2 and tune benchmark parameters for ~10 min execution Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- build.gradle.kts | 10 +++++----- .../_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 034ed40f..10586f0d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ plugins { id("ru.vyarus.pom") version "3.0.0" id("org.jreleaser") version "1.21.0" id("org.sonarqube") version "7.0.1.6134" - id("me.champeau.gradle.jmh") version "0.5.3" + id("me.champeau.jmh") version "0.7.2" } repositories { @@ -112,10 +112,10 @@ idea { } jmh { - jvmArgsAppend = listOf("-XX:+UseParallelGC") - isIncludeTests = true - duplicateClassesStrategy = DuplicatesStrategy.WARN - timeUnit = "s" + jvmArgsAppend.add("-XX:+UseParallelGC") + includeTests.set(true) + duplicateClassesStrategy.set(DuplicatesStrategy.WARN) + timeUnit.set("s") } tasks.generateGrammarSource { diff --git a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java index 69bef601..858b351e 100644 --- a/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java +++ b/src/jmh/java/com/github/_1c_syntax/bsl/parser/JMXBSLTokenizerTest.java @@ -23,6 +23,7 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; @@ -40,8 +41,9 @@ * Tests new tokenizer creation, rebuild, and incremental text modifications. */ @BenchmarkMode(Mode.SampleTime) -@Warmup(iterations = 2) -@Measurement(iterations = 2, batchSize = 2) +@Warmup(iterations = 1, time = 10) +@Measurement(iterations = 2, time = 10) +@Fork(1) @State(Scope.Thread) public class JMXBSLTokenizerTest {