///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2025, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////
#Область ПрограммныйИнтерфейс
#Область ОповещениеПользователя
// Формирует и выводит сообщение, которое может быть связано с элементом управления формы.
//
// В фоновом задании длительной операции, если вызов выполнен вне транзакции,
// сообщение записывается в служебный регистр и отправляется сразу на клиент,
// если подключена система взаимодействия.
// В конце фонового задания длительной операции, а также при отправке прогресса,
// все сообщения извлекаются из очереди сообщений фонового задания,
// записываются в служебный регистр и отправляются сразу на клиент,
// если подключена система взаимодействия.
//
// АПК:142-выкл 4 необязательных параметра для совместимости
// с устаревшей процедурой ОбщегоНазначенияКлиентСервер.СообщитьПользователю.
//
// Параметры:
// ТекстСообщенияПользователю - Строка - текст сообщения.
// КлючДанных - Произвольный - объект, ссылка или ключ записи информационной базы, к которому это сообщение относится.
// Поле - Строка - наименование реквизита формы.
// ПутьКДанным - Строка - путь к данным (путь к реквизиту формы).
// Отказ - Булево - выходной параметр, всегда устанавливается в значение Истина.
//
// Пример:
//
// 1. Для вывода сообщения у поля управляемой формы, связанного с реквизитом объекта:
// ОбщегоНазначения.СообщитьПользователю(
// НСтр("ru = 'Сообщение об ошибке.'"), ,
// "ПолеВРеквизитеФормыОбъект",
// "Объект");
//
// Альтернативный вариант использования в форме объекта:
// ОбщегоНазначения.СообщитьПользователю(
// НСтр("ru = 'Сообщение об ошибке.'"), ,
// "Объект.ПолеВРеквизитеФормыОбъект");
//
// 2. Для вывода сообщения рядом с полем управляемой формы, связанным с реквизитом формы:
// ОбщегоНазначения.СообщитьПользователю(
// НСтр("ru = 'Сообщение об ошибке.'"), ,
// "ИмяРеквизитаФормы");
//
// 3. Для вывода сообщения связанного с объектом информационной базы:
// ОбщегоНазначения.СообщитьПользователю(
// НСтр("ru = 'Сообщение об ошибке.'"), ОбъектИнформационнойБазы, "Ответственный",,Отказ);
//
// 4. Для вывода сообщения по ссылке на объект информационной базы:
// ОбщегоНазначения.СообщитьПользователю(
// НСтр("ru = 'Сообщение об ошибке.'"), Ссылка, , , Отказ);
//
// Случаи некорректного использования:
// 1. Передача одновременно параметров КлючДанных и ПутьКДанным.
// 2. Передача в параметре КлючДанных значения типа отличного от допустимого.
// 3. Установка ссылки без установки поля (и/или пути к данным).
//
Процедура СообщитьПользователю(Знач ТекстСообщенияПользователю, Знач КлючДанных = Неопределено, Знач Поле = "",
Знач ПутьКДанным = "", Отказ = Ложь) Экспорт
ЭтоОбъект = Ложь;
Если КлючДанных <> Неопределено
И XMLТипЗнч(КлючДанных) <> Неопределено Тогда
ТипЗначенияСтрокой = XMLТипЗнч(КлючДанных).ИмяТипа;
ЭтоОбъект = СтрНайти(ТипЗначенияСтрокой, "Object.") > 0;
КонецЕсли;
Сообщение = ОбщегоНазначенияСлужебныйКлиентСервер.СообщениеПользователю(ТекстСообщенияПользователю,
КлючДанных, Поле, ПутьКДанным, Отказ, ЭтоОбъект);
#Если НЕ МобильныйАвтономныйСервер Тогда
Если СтандартныеПодсистемыПовтИсп.ЭтоСеансДлительнойОперации()
И Не ТранзакцияАктивна() Тогда
ДлительныеОперации.ОтправитьОповещениеКлиенту("СообщениеПользователю", Сообщение);
Иначе
Сообщение.Сообщить();
КонецЕсли;
#Иначе
Сообщение.Сообщить();
#КонецЕсли
КонецПроцедуры
// АПК:142-вкл
#КонецОбласти
#Если НЕ МобильныйАвтономныйСервер Тогда
#Область ДанныеВБазе
////////////////////////////////////////////////////////////////////////////////
// Общие процедуры и функции для работы с данными в базе.
// Возвращает структуру, содержащую значения реквизитов, прочитанные из информационной базы по ссылке на объект.
// Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект
// для быстрого чтения отдельных реквизитов объекта из базы данных.
//
// Если необходимо зачитать реквизит независимо от прав текущего пользователя,
// то следует использовать предварительный переход в привилегированный режим.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, значения реквизитов которого необходимо получить.
// - Строка - полное имя предопределенного элемента, значения реквизитов которого необходимо получить.
// Реквизиты - Строка - имена реквизитов, перечисленные через запятую, в формате
// требований к свойствам структуры.
// Например, "Код, Наименование, Родитель".
// - Структура
// - ФиксированнаяСтруктура - в качестве ключа передается
// псевдоним поля для возвращаемой структуры с результатом, а в качестве
// значения (опционально) фактическое имя поля в таблице.
// Если ключ задан, а значение не определено, то имя поля берется из ключа.
// Допускается указание имени поля через точку, но при этом параметр КодЯзыка для такого поля
// учитываться не будет.
// - Массив из Строка
// - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры.
// ВыбратьРазрешенные - Булево - если Истина, то запрос к объекту выполняется с учетом прав пользователя;
// если есть ограничение на уровне записей, то все реквизиты вернутся со
// значением Неопределено; если нет прав для работы с таблицей, то возникнет исключение;
// если Ложь, то возникнет исключение при отсутствии прав на таблицу
// или любой из реквизитов.
// КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации.
//
// Возвращаемое значение:
// Структура - содержит имена (ключи) и значения затребованных реквизитов.
// Если в параметр Реквизиты передана пустая строка, то возвращается пустая структура.
// Если в параметр Ссылка передана пустая ссылка, то возвращается структура,
// соответствующая именам реквизитов со значениями Неопределено.
// Если в параметр Ссылка передана ссылка несуществующего объекта (битая ссылка),
// то все реквизиты вернутся со значением Неопределено.
//
Функция ЗначенияРеквизитовОбъекта(Ссылка, Знач Реквизиты, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт
// Если передано имя предопределенного.
Если ТипЗнч(Ссылка) = Тип("Строка") Тогда
ПолноеИмяПредопределенногоЭлемента = Ссылка;
// Вычисление ссылки по имени предопределенного.
// - дополнительно выполняет проверку метаданных предопределенного, выполняется предварительно.
Попытка
Ссылка = ПредопределенныйЭлемент(ПолноеИмяПредопределенногоЭлемента);
Исключение
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный первый параметр %1 в функции %2:
|%3'"), "Ссылка", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта",
ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецПопытки;
// Разбор полного имени предопределенного.
ЧастиПолногоИмени = СтрРазделить(ПолноеИмяПредопределенногоЭлемента, ".");
ПолноеИмяОбъектаМетаданных = ЧастиПолногоИмени[0] + "." + ЧастиПолногоИмени[1];
// Если предопределенный не создан в ИБ, то требуется выполнить проверку доступа к объекту.
// В других сценариях проверка доступа выполняется в момент исполнения запроса.
Если Ссылка = Неопределено Тогда
МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
Если Не ПравоДоступа("Чтение", МетаданныеОбъекта) Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недостаточно прав для работы с таблицей ""%1""'"), ПолноеИмяОбъектаМетаданных),
КатегорияОшибки.НарушениеПравДоступа);
КонецЕсли;
КонецЕсли;
Иначе // Если передана ссылка.
Попытка
ПолноеИмяОбъектаМетаданных = Ссылка.Метаданные().ПолноеИмя();
Исключение
ВызватьИсключение (СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный первый параметр %1 в функции %2:
|Значение должно быть ссылкой или именем предопределенного элемента.'"),
"Ссылка", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецПопытки;
КонецЕсли;
// Разбор реквизитов, если второй параметр Строка.
Если ТипЗнч(Реквизиты) = Тип("Строка") Тогда
Если ПустаяСтрока(Реквизиты) Тогда
Возврат Новый Структура;
КонецЕсли;
Реквизиты = СтрРазделить(Реквизиты, ",", Ложь);
Для Индекс = 0 По Реквизиты.ВГраница() Цикл
Реквизиты[Индекс] = СокрЛП(Реквизиты[Индекс]);
КонецЦикла;
КонецЕсли;
МультиязычныеРеквизиты = Новый Соответствие;
СуффиксЯзыка = "";
Если ЗначениеЗаполнено(КодЯзыка) Тогда
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка);
Если ЗначениеЗаполнено(СуффиксЯзыка) Тогда
МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(Ссылка);
КонецЕсли;
КонецЕсли;
КонецЕсли;
// Приведение реквизитов к единому формату.
СтруктураПолей = Новый Структура;
Если ТипЗнч(Реквизиты) = Тип("Структура")
Или ТипЗнч(Реквизиты) = Тип("ФиксированнаяСтруктура") Тогда
Для Каждого КлючИЗначение Из Реквизиты Цикл
СтруктураПолей.Вставить(КлючИЗначение.Ключ, СокрЛП(КлючИЗначение.Значение));
КонецЦикла;
ИначеЕсли ТипЗнч(Реквизиты) = Тип("Массив")
Или ТипЗнч(Реквизиты) = Тип("ФиксированныйМассив") Тогда
Для Каждого Реквизит Из Реквизиты Цикл
Реквизит = СокрЛП(Реквизит);
Попытка
ПсевдонимПоля = СтрЗаменить(Реквизит, ".", "");
СтруктураПолей.Вставить(ПсевдонимПоля, Реквизит);
Исключение
// Если псевдоним не является ключом.
// Поиск ошибки доступности полей.
Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты);
Если Результат.Ошибка Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2: %3'"),
"Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Результат.ОписаниеОшибки),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
// Не удалось распознать ошибку, проброс первичной ошибки.
ВызватьИсключение;
КонецПопытки;
КонецЦикла;
Иначе
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный тип второго параметра %1 в функции %2: %3.'"),
"Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Строка(ТипЗнч(Реквизиты))),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
// Подготовка результата (после выполнения запроса переопределится).
Результат = Новый Структура;
// Формирование текста запроса к выбираемым полям.
ТекстЗапросаПолей = "";
Для каждого КлючИЗначение Из СтруктураПолей Цикл
ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение),
КлючИЗначение.Значение,
КлючИЗначение.Ключ);
ПсевдонимПоля = КлючИЗначение.Ключ;
Если МультиязычныеРеквизиты[ИмяПоля] = Ложь Тогда
ИмяПоля = ИмяПоля + СуффиксЯзыка;
КонецЕсли;
ТекстЗапросаПолей =
ТекстЗапросаПолей + ?(ПустаяСтрока(ТекстЗапросаПолей), "", ",") + "
| " + ИмяПоля + " КАК " + ПсевдонимПоля;
// Предварительное добавление поля по псевдониму в возвращаемый результат.
Результат.Вставить(ПсевдонимПоля);
КонецЦикла;
// Если предопределенного нет в ИБ.
// - приведение результата к отсутствию объекта в ИБ или передаче пустой ссылки.
Если Ссылка = Неопределено Тогда
Возврат Результат;
КонецЕсли;
Если Тип("Структура") = ТипЗнч(Реквизиты)
Или Тип("ФиксированнаяСтруктура") = ТипЗнч(Реквизиты) Тогда
Реквизиты = Новый Массив;
Для Каждого КлючИЗначение Из СтруктураПолей Цикл
ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение),
КлючИЗначение.Значение,
КлючИЗначение.Ключ);
Реквизиты.Добавить(ИмяПоля);
КонецЦикла;
КонецЕсли;
РеквизитыЧерезТочку = Новый Массив;
Для Индекс = -Реквизиты.ВГраница() По 0 Цикл
ИмяПоля = Реквизиты[-Индекс];
Если СтрНайти(ИмяПоля, ".") Тогда
РеквизитыЧерезТочку.Добавить(ИмяПоля);
Реквизиты.Удалить(-Индекс);
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(Реквизиты) Тогда
ЗначенияРеквизитовОбъекта = ЗначенияРеквизитовОбъектов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Ссылка), Реквизиты, ВыбратьРазрешенные, КодЯзыка)[Ссылка];
Если ЗначенияРеквизитовОбъекта <> Неопределено Тогда
Для Каждого КлючИЗначение Из СтруктураПолей Цикл
ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение),
КлючИЗначение.Значение,
КлючИЗначение.Ключ);
Если СтрНайти(ИмяПоля, ".") = 0 И ЗначенияРеквизитовОбъекта.Свойство(ИмяПоля) Тогда
Результат[КлючИЗначение.Ключ] = ЗначенияРеквизитовОбъекта[ИмяПоля];
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если Не ЗначениеЗаполнено(РеквизитыЧерезТочку) Тогда
Возврат Результат;
КонецЕсли;
Реквизиты = РеквизитыЧерезТочку;
ТекстЗапроса =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
|&ТекстЗапросаПолей
|ИЗ
| &ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы
|ГДЕ
| ПсевдонимЗаданнойТаблицы.Ссылка = &Ссылка";
Если Не ВыбратьРазрешенные Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @Query-part-1
КонецЕсли;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекстЗапросаПолей", ТекстЗапросаПолей);
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных);
// Выполнение запроса.
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Запрос.Текст = ТекстЗапроса;
Попытка
Выборка = Запрос.Выполнить().Выбрать();
Исключение
// Если реквизиты были переданы строкой, то они уже конвертированы в массив.
// Если реквизиты - массив, оставляем без изменений.
// Если реквизиты - структура - конвертируем в массив.
// В остальных случаях уже было бы выброшено исключение.
Если Тип("Структура") = ТипЗнч(Реквизиты)
Или Тип("ФиксированнаяСтруктура") = ТипЗнч(Реквизиты) Тогда
Реквизиты = Новый Массив;
Для каждого КлючИЗначение Из СтруктураПолей Цикл
ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение),
КлючИЗначение.Значение,
КлючИЗначение.Ключ);
Реквизиты.Добавить(ИмяПоля);
КонецЦикла;
КонецЕсли;
// Поиск ошибки доступности полей.
Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты);
Если Результат.Ошибка Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2: %3'"),
"Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Результат.ОписаниеОшибки),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
// Заполнение реквизитов.
Если Выборка.Следующий() Тогда
ЗаполнитьЗначенияСвойств(Результат, Выборка);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает значения реквизита, прочитанного из информационной базы по ссылке на объект.
// Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект
// для быстрого чтения отдельных реквизитов объекта из базы данных.
//
// Если необходимо зачитать реквизит независимо от прав текущего пользователя,
// то следует использовать предварительный переход в привилегированный режим.
//
// Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует".
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, значения реквизитов которого необходимо получить.
// - Строка - полное имя предопределенного элемента, значения реквизитов которого необходимо получить.
// ИмяРеквизита - Строка - имя получаемого реквизита.
// Допускается указание имени реквизита через точку, но при этом параметр КодЯзыка для
// такого реквизита учитываться не будет.
// ВыбратьРазрешенные - Булево - если Истина, то запрос к объекту выполняется с учетом прав пользователя;
// если есть ограничение на уровне записей, то возвращается Неопределено;
// если нет прав для работы с таблицей, то возникнет исключение;
// если Ложь, то возникнет исключение при отсутствии прав на таблицу
// или любой из реквизитов.
// КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации.
//
// Возвращаемое значение:
// Произвольный - если в параметр Ссылка передана пустая ссылка, то возвращается Неопределено.
// Если в параметр Ссылка передана ссылка несуществующего объекта (битая ссылка),
// то возвращается Неопределено.
//
Функция ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт
Если ПустаяСтрока(ИмяРеквизита) Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2:
|Имя реквизита должно быть заполнено.'"),
"ИмяРеквизита", "ОбщегоНазначения.ЗначениеРеквизитаОбъекта"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
Результат = ЗначенияРеквизитовОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные, КодЯзыка);
Возврат Результат[СтрЗаменить(ИмяРеквизита, ".", "")];
КонецФункции
// Возвращает значения реквизитов, прочитанные из информационной базы для нескольких объектов.
// Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект
// для быстрого чтения отдельных реквизитов объекта из базы данных.
//
// Если необходимо зачитать реквизит независимо от прав текущего пользователя,
// то следует использовать предварительный переход в привилегированный режим.
//
// Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует".
//
// Параметры:
// Ссылки - Массив из ЛюбаяСсылка
// - ФиксированныйМассив из ЛюбаяСсылка - ссылки на объекты.
// Если массив пуст, то результатом будет пустое соответствие.
// Реквизиты - Строка - имена реквизитов перечисленные через запятую, в формате требований к свойствам
// структуры. Например, "Код, Наименование, Родитель".
// - Массив из Строка
// - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры.
// ВыбратьРазрешенные - Булево - если Истина, то запрос к объектам выполняется с учетом прав пользователя;
// если какой-либо объект будет исключен из выборки по правам, то этот объект
// будет исключен и из результата;
// если Ложь, то возникнет исключение при отсутствии прав на таблицу
// или любой из реквизитов.
// КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение - список объектов и значений их реквизитов:
// * Ключ - ЛюбаяСсылка - ссылка на объект;
// * Значение - Структура:
// ** Ключ - Строка - имя реквизита;
// ** Значение - Произвольный - значение реквизита.
//
Функция ЗначенияРеквизитовОбъектов(Ссылки, Знач Реквизиты, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт
Если ТипЗнч(Реквизиты) = Тип("Массив") Или ТипЗнч(Реквизиты) = Тип("ФиксированныйМассив") Тогда
Реквизиты = СтрСоединить(Реквизиты, ",");
КонецЕсли;
Если ПустаяСтрока(Реквизиты) Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2:
|Поле объекта должно быть указано.'"),
"Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
Если СтрНайти(Реквизиты, ".") <> 0 Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2:
|Обращение через точку не поддерживается.'"),
"Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ЗначенияРеквизитов = Новый Соответствие;
Если Ссылки.Количество() = 0 Тогда
Возврат ЗначенияРеквизитов;
КонецЕсли;
Если ЗначениеЗаполнено(КодЯзыка) Тогда
КодЯзыка = СтрРазделить(КодЯзыка, "_", Истина)[0];
КонецЕсли;
РеквизитыТекстЗапроса = Реквизиты;
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
Если ЗначениеЗаполнено(КодЯзыка) Тогда
СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка);
Если ЗначениеЗаполнено(СуффиксЯзыка) Тогда
МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(Ссылки[0]);
НаборРеквизитов = СтрРазделить(Реквизиты, ",");
Для Позиция = 0 По НаборРеквизитов.ВГраница() Цикл
ИмяРеквизита = СокрЛП(НаборРеквизитов[Позиция]);
Если МультиязычныеРеквизиты[ИмяРеквизита] = Ложь Тогда
ИмяССуффиксом = ИмяРеквизита + СуффиксЯзыка;
НаборРеквизитов[Позиция] = ИмяССуффиксом + " КАК " + ИмяРеквизита;
КонецЕсли;
КонецЦикла;
РеквизитыТекстЗапроса = СтрСоединить(НаборРеквизитов, ",");
КонецЕсли;
КонецЕсли;
КонецЕсли;
СсылкиПоТипам = Новый Соответствие;
Для Каждого Ссылка Из Ссылки Цикл
Тип = ТипЗнч(Ссылка);
Если СсылкиПоТипам[Тип] = Неопределено Тогда
СсылкиПоТипам[Тип] = Новый Массив;
КонецЕсли;
ЭлементПоТипу = СсылкиПоТипам[Тип]; // Массив
ЭлементПоТипу.Добавить(Ссылка);
КонецЦикла;
ТекстыЗапросов = Новый Массив;
ПараметрыЗапроса = Новый Структура;
ИменаОбъектовМетаданных = Новый Массив;
Для Каждого СсылкиПоТипу Из СсылкиПоТипам Цикл
Тип = СсылкиПоТипу.Ключ;
ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
Если ОбъектМетаданных = Неопределено Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный первый параметр %1 в функции %2:
|Значения массива должны быть ссылками.'"),
"Ссылки", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ПолноеИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя();
ИменаОбъектовМетаданных.Добавить(ПолноеИмяОбъектаМетаданных);
ТекстЗапроса =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Ссылка,
| &Реквизиты
|ИЗ
| &ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы
|ГДЕ
| ПсевдонимЗаданнойТаблицы.Ссылка В (&Ссылки)";
Если Не ВыбратьРазрешенные Или ТекстыЗапросов.Количество() > 0 Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @Query-part-1
КонецЕсли;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Реквизиты", РеквизитыТекстЗапроса);
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных);
ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", "");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра); // @Query-part-1
ПараметрыЗапроса.Вставить(ИмяПараметра, СсылкиПоТипу.Значение);
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
Если ЗначениеЗаполнено(КодЯзыка) И КодЯзыка <> КодОсновногоЯзыка()
И МодульМультиязычностьСервер.ОбъектСодержитТЧПредставления(ПолноеИмяОбъектаМетаданных) Тогда
МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(ОбъектМетаданных);
ПоляТаблиц = Новый Массив;
ПоляТаблиц.Добавить("ПсевдонимЗаданнойТаблицы.Ссылка");
Для Каждого Реквизит Из СтрРазделить(Реквизиты, ",") Цикл
Если МультиязычныеРеквизиты[Реквизит] <> Неопределено Тогда
Если МультиязычныеРеквизиты[Реквизит] = Истина Тогда
ПолеРеквизита = "ЕСТЬNULL(ТаблицаПредставления." + Реквизит + ", """")";
Иначе
СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка);
ПолеРеквизита = ?(ЗначениеЗаполнено(СуффиксЯзыка), Реквизит + СуффиксЯзыка, Реквизит);
КонецЕсли;
ПоляТаблиц.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 КАК %2",
ПолеРеквизита, Реквизит));
Иначе
ПоляТаблиц.Добавить(Реквизит);
КонецЕсли;
КонецЦикла;
ПоляТаблиц = СтрСоединить(ПоляТаблиц, "," + Символы.ПС);
Таблицы = ПолноеИмяОбъектаМетаданных + " " + "КАК ПсевдонимЗаданнойТаблицы" + Символы.ПС
+ "ЛЕВОЕ СОЕДИНЕНИЕ" + " " + ПолноеИмяОбъектаМетаданных + ".Представления КАК ТаблицаПредставления" + Символы.ПС
+ "ПО ТаблицаПредставления.Ссылка = ПсевдонимЗаданнойТаблицы.Ссылка И ТаблицаПредставления.КодЯзыка = &КодЯзыка";
ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", "");
Условия = "ПсевдонимЗаданнойТаблицы.Ссылка В (&" + ИмяПараметра + ")";
СтрокиЗапроса = Новый Массив;
СтрокиЗапроса.Добавить("ВЫБРАТЬ" + ?(ВыбратьРазрешенные И Не ЗначениеЗаполнено(ТекстыЗапросов), " " + "РАЗРЕШЕННЫЕ", "")); // @Query-part-1, @Query-part-3
СтрокиЗапроса.Добавить(ПоляТаблиц);
СтрокиЗапроса.Добавить("ИЗ"); // @Query-part-1
СтрокиЗапроса.Добавить(Таблицы);
СтрокиЗапроса.Добавить("ГДЕ"); // @Query-part-1
СтрокиЗапроса.Добавить(Условия);
ТекстЗапроса = СтрСоединить(СтрокиЗапроса, Символы.ПС);
КонецЕсли;
КонецЕсли;
ТекстыЗапросов.Добавить(ТекстЗапроса);
КонецЦикла;
ТекстЗапроса = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС);
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("КодЯзыка", КодЯзыка);
Для Каждого Параметр Из ПараметрыЗапроса Цикл
Запрос.УстановитьПараметр(Параметр.Ключ, Параметр.Значение);
КонецЦикла;
Попытка
Выборка = Запрос.Выполнить().Выбрать();
Исключение
// Удаление пробелов.
Реквизиты = СтрЗаменить(Реквизиты, " ", "");
// Преобразование параметра в массив полей.
Реквизиты = СтрРазделить(Реквизиты, ",");
// Поиск ошибки доступности полей.
СписокОшибок = Новый Массив;
Для Каждого ПолноеИмяОбъектаМетаданных Из ИменаОбъектовМетаданных Цикл
Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты);
Если Результат.Ошибка Тогда
СписокОшибок.Добавить(Результат.ОписаниеОшибки);
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(СписокОшибок) Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2: %3'"),
"Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов",
СтрСоединить(СписокОшибок, Символы.ПС)),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
Пока Выборка.Следующий() Цикл
Результат = Новый Структура(Реквизиты);
ЗаполнитьЗначенияСвойств(Результат, Выборка);
ЗначенияРеквизитов[Выборка.Ссылка] = Результат;
КонецЦикла;
Возврат ЗначенияРеквизитов;
КонецФункции
// Возвращает значения реквизита, прочитанного из информационной базы для нескольких объектов.
// Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект
// для быстрого чтения отдельных реквизитов объекта из базы данных.
//
// Если необходимо зачитать реквизит независимо от прав текущего пользователя,
// то следует использовать предварительный переход в привилегированный режим.
//
// Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует".
//
// Параметры:
// МассивСсылок - Массив из ЛюбаяСсылка
// - ФиксированныйМассив из ЛюбаяСсылка
// ИмяРеквизита - Строка - например, "Код".
// ВыбратьРазрешенные - Булево - если Истина, то запрос к объектам выполняется с учетом прав пользователя;
// если какой-либо объект будет исключен из выборки по правам, то этот объект
// будет исключен и из результата;
// если Ложь, то возникнет исключение при отсутствии прав на таблицу
// или любой из реквизитов.
// КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - ЛюбаяСсылка - ссылка на объект,
// * Значение - Произвольный - значение прочитанного реквизита.
//
Функция ЗначениеРеквизитаОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт
Если ПустаяСтрока(ИмяРеквизита) Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверный второй параметр %1 в функции %2:
|Имя реквизита должно быть заполнено.'"),
"ИмяРеквизита", "ОбщегоНазначения.ЗначениеРеквизитаОбъектов"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ЗначенияРеквизитов = ЗначенияРеквизитовОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные, КодЯзыка);
Для каждого Элемент Из ЗначенияРеквизитов Цикл
ЗначенияРеквизитов[Элемент.Ключ] = Элемент.Значение[ИмяРеквизита];
КонецЦикла;
Возврат ЗначенияРеквизитов;
КонецФункции
// Добавляет или изменяет значение реквизита в объекте.
//
// Если передано имя несуществующего реквизита, то вызывается исключение.
//
// Параметры:
// Объект - СправочникОбъект
// - ДокументОбъект
// - ПланВидовХарактеристикОбъект
// - РегистрСведенийЗапись - заполняемый объект.
// ИмяРеквизита - Строка - имя заполняемого реквизита. Например, "Комментарий"
// Значение - Строка - значение помещаемое в реквизит.
// КодЯзыка - Строка - код языка реквизита. Например, "ru".
//
Процедура УстановитьЗначениеРеквизита(Объект, ИмяРеквизита, Значение, КодЯзыка = Неопределено) Экспорт
УстановитьЗначенияРеквизитов(Объект, Новый Структура(ИмяРеквизита, Значение), КодЯзыка);
КонецПроцедуры
// Добавляет или изменяет значения реквизитов в объекте.
//
// Если передано имя несуществующего реквизита, то вызывается исключение.
//
// Параметры:
// Объект - СправочникОбъект
// - ДокументОбъект
// - ПланВидовХарактеристикОбъект
// - РегистрСведенийЗапись - заполняемый объект.
// Значения - Структура - где ключ это имя реквизита, а значение содержит строку помещаемую в реквизит.
// КодЯзыка - Строка - код языка реквизита. Например, "ru".
//
Процедура УстановитьЗначенияРеквизитов(Объект, Значения, КодЯзыка = Неопределено) Экспорт
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
МодульМультиязычностьСервер.УстановитьЗначенияРеквизитов(Объект, Значения, КодЯзыка);
Возврат;
КонецЕсли;
Для Каждого ЗначениеРеквизита Из Значения Цикл
Значение = ЗначениеРеквизита.Значение;
Если ТипЗнч(Значение) = Тип("Строка") И СтрокаВВидеНСтр(Значение) Тогда
Значение = НСтр(ЗначениеРеквизита.Значение);
КонецЕсли;
Объект[ЗначениеРеквизита.Ключ] = Значение;
КонецЦикла;
КонецПроцедуры
// Возвращает код основного языка информационной базы, например "ru".
// На котором программно записываются автогенерируемые строки в информационную базу.
// Например, при начальном заполнении информационной базы данными из макета, автогенерации комментария
// к проводке или определении значения параметра ИмяСобытия метода ЗаписьЖурналаРегистрации.
//
// Возвращаемое значение:
// Строка
//
Функция КодОсновногоЯзыка() Экспорт
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
Возврат МодульМультиязычностьСервер.КодОсновногоЯзыка();
КонецЕсли;
Возврат Метаданные.ОсновнойЯзык.КодЯзыка;
КонецФункции
// Возвращает признак того, что для пользователя установлен язык интерфейса
// соответствующий основному языку информационной базы.
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоОсновнойЯзык() Экспорт
Возврат СтрСравнить(КодОсновногоЯзыка(), ТекущийЯзык().КодЯзыка) = 0;
КонецФункции
// Возвращает ссылку предопределенного элемента по его полному имени в следующих объектах:
// - справочники;
// - планы видов характеристик;
// - планы счетов;
// - планы видов расчета.
// См. также функцию ОбщегоНазначенияКлиент.ПредопределенныйЭлемент.
//
// Для корректной работы этой функции после изменения состава предопределенных следует вызывать
// метод ОбновитьПовторноИспользуемыеЗначения.
//
// Параметры:
// ПолноеИмяПредопределенного - Строка - полное имя предопределенного элемента.
// Формат аналогичен функции глобального контекста ПредопределенноеЗначение, например:
// "Справочник.ВидыКонтактнойИнформации.EmailПользователя"
// "ПланСчетов.Хозрасчетный.Материалы"
// "ПланВидовРасчета.Начисления.ОплатаПоОкладу".
//
// Возвращаемое значение:
// - ЛюбаяСсылка - ссылка на предопределенный элемент.
// - Неопределено - если предопределенного элемента нет в метаданных или не создан в информационной базе.
//
Функция ПредопределенныйЭлемент(ПолноеИмяПредопределенного) Экспорт
СтандартнаяОбработка = ОбщегоНазначенияСлужебныйКлиентСервер.ИспользоватьСтандартнуюФункциюПолученияПредопределенного(
ПолноеИмяПредопределенного);
Если СтандартнаяОбработка Тогда
Возврат ПредопределенноеЗначение(ПолноеИмяПредопределенного);
КонецЕсли;
ПоляПредопределенного = ОбщегоНазначенияСлужебныйКлиентСервер.ИмяПредопределенногоПоПолям(ПолноеИмяПредопределенного);
ПредопределенныеЗначения = СтандартныеПодсистемыПовтИсп.СсылкиПоИменамПредопределенных(
ПоляПредопределенного.ПолноеИмяОбъектаМетаданных);
Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредопределенныйЭлемент(
ПолноеИмяПредопределенного, ПоляПредопределенного, ПредопределенныеЗначения);
КонецФункции
// Возвращает информацию о том, являются ли переданные элементы предопределенными.
// Если нет прав доступа на уровне записей, то элемент не включается в результат.
// Если нет прав доступа к таблице, то вызывается исключение.
//
// Параметры:
// Элементы - Массив из ЛюбаяСсылка
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение - список объектов и значений их реквизитов:
// * Ключ - ЛюбаяСсылка - ссылка на объект.
// * Значение - Булево - Истина, если это ссылка на предопределенный элемент.
//
Функция ЭтоПредопределенныеЭлементы(Знач Элементы) Экспорт
ИменаРеквизитов = Новый Массив;
Для каждого ИмяРеквизита Из СтандартныеПодсистемыСервер.РеквизитыПредопределенныхДанных() Цикл
ИменаРеквизитов.Добавить(ИмяРеквизита.Ключ);
КонецЦикла;
ЗначенияРеквизитов = СтандартныеПодсистемыСервер.ЗначенияРеквизитовОбъектовЕслиСуществуют(Элементы, ИменаРеквизитов);
Результат = Новый Соответствие;
Для каждого Элемент Из ЗначенияРеквизитов Цикл
ЭтоПредопределенныйЭлемент = Ложь;
Для каждого Значение Из Элемент.Значение Цикл
Если ЗначениеЗаполнено(Значение.Значение) Тогда
ЭтоПредопределенныйЭлемент = Истина;
КонецЕсли;
КонецЦикла;
Результат[Элемент.Ключ] = ЭтоПредопределенныйЭлемент;
КонецЦикла;
Возврат Результат;
КонецФункции
// Проверяет статус проведения переданных документов и возвращает
// те из них, которые не проведены.
//
// Параметры:
// Документы - Массив из ДокументСсылка - документы, статус проведения которых необходимо проверить.
//
// Возвращаемое значение:
// Массив из ДокументСсылка - непроведенные документы.
//
Функция ПроверитьПроведенностьДокументов(Знач Документы) Экспорт
Результат = Новый Массив;
ШаблонЗапроса =
"ВЫБРАТЬ
| ПсевдонимЗаданнойТаблицы.Ссылка КАК Ссылка
|ИЗ
| &ИмяДокумента КАК ПсевдонимЗаданнойТаблицы
|ГДЕ
| ПсевдонимЗаданнойТаблицы.Ссылка В(&МассивДокументов)
| И НЕ ПсевдонимЗаданнойТаблицы.Проведен";
ТекстОбъединитьВсе = ТекстОбъединитьВсе();
ИменаДокументов = Новый Массив;
Для Каждого Документ Из Документы Цикл
МетаданныеДокумента = Документ.Метаданные();
Если ИменаДокументов.Найти(МетаданныеДокумента.ПолноеИмя()) = Неопределено
И Метаданные.Документы.Содержит(МетаданныеДокумента)
И МетаданныеДокумента.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
ИменаДокументов.Добавить(МетаданныеДокумента.ПолноеИмя());
КонецЕсли;
КонецЦикла;
ТекстЗапроса = "";
Для Каждого ИмяДокумента Из ИменаДокументов Цикл
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
ТекстЗапроса = ТекстЗапроса + ТекстОбъединитьВсе;
КонецЕсли;
ТекстПодзапроса = СтрЗаменить(ШаблонЗапроса, "&ИмяДокумента", ИмяДокумента);
ТекстЗапроса = ТекстЗапроса + ТекстПодзапроса;
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("МассивДокументов", Документы);
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
Результат = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецЕсли;
Возврат Результат;
КонецФункции
// Выполняет попытку проведения документов и возвращает информацию о документах, которые не удалось провести.
//
// Параметры:
// Документы - Массив из ДокументСсылка - документы, которые необходимо провести.
//
// Возвращаемое значение:
// Массив из Структура:
// * Ссылка - ДокументСсылка - документ, который не удалось провести,
// * ОписаниеОшибки - Строка - текст описания ошибки при проведении.
//
Функция ПровестиДокументы(Документы) Экспорт
НепроведенныеДокументы = Новый Массив;
Для Каждого ДокументСсылка Из Документы Цикл
ВыполненоУспешно = Ложь;
ПредставлениеОшибки = "";
Блокировка = Новый БлокировкаДанных();
ЭлементБлокировки = Блокировка.Добавить(ДокументСсылка.Метаданные().ПолноеИмя());
ЭлементБлокировки.УстановитьЗначение("Ссылка", ДокументСсылка);
НачатьТранзакцию();
Попытка
Блокировка.Заблокировать();
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
Если ДокументОбъект.ПроверитьЗаполнение() Тогда
РежимПроведения = РежимПроведенияДокумента.Неоперативный;
Если ДокументОбъект.Дата >= НачалоДня(ТекущаяДатаСеанса())
И ДокументСсылка.Метаданные().ОперативноеПроведение = Метаданные.СвойстваОбъектов.ОперативноеПроведение.Разрешить Тогда
РежимПроведения = РежимПроведенияДокумента.Оперативный;
КонецЕсли;
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведения);
ВыполненоУспешно = Истина;
Иначе
ПредставлениеОшибки = НСтр("ru = 'Поля документа не заполнены.'");
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Если Не ВыполненоУспешно Тогда
НепроведенныеДокументы.Добавить(Новый Структура("Ссылка,ОписаниеОшибки",
ДокументСсылка, ПредставлениеОшибки));
КонецЕсли;
КонецЦикла;
Возврат НепроведенныеДокументы;
КонецФункции
// Проверяет наличие ссылок на объект в базе данных.
// При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях.
//
// Параметры:
// СсылкаИлиМассивСсылок - ЛюбаяСсылка
// - Массив из ЛюбаяСсылка - объект или список объектов.
// ИскатьСредиСлужебныхОбъектов - Булево - если Истина, то не будут учитываться
// исключения поиска ссылок, заданные при разработке конфигурации.
// Про исключение поиска ссылок см. подробнее
// ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.
//
// Возвращаемое значение:
// Булево - Истина, если есть ссылки на объект.
//
Функция ЕстьСсылкиНаОбъект(Знач СсылкаИлиМассивСсылок, Знач ИскатьСредиСлужебныхОбъектов = Ложь) Экспорт
Если ТипЗнч(СсылкаИлиМассивСсылок) = Тип("Массив") Тогда
МассивСсылок = СсылкаИлиМассивСсылок;
Иначе
МассивСсылок = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СсылкаИлиМассивСсылок);
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
МестаИспользования = НайтиПоСсылкам(МассивСсылок);
УстановитьПривилегированныйРежим(Ложь);
Если Не ИскатьСредиСлужебныхОбъектов Тогда
Для каждого Элемент Из СлужебныеСвязиДанных(МестаИспользования) Цикл
МестаИспользования.Удалить(Элемент.Ключ);
КонецЦикла;
КонецЕсли;
Возврат МестаИспользования.Количество() > 0;
КонецФункции
// Определяет, указаны ли места использования в исключениях поиска ссылок.
//
// Параметры:
// МестаИспользования - ТаблицаЗначений - результат функции НайтиПоСсылкам:
// * Ссылка - ЛюбаяСсылка - проверяемая ссылка.
// * Данные - ЛюбаяСсылка - место использования.
// * Метаданные - ОбъектМетаданных - метаданные места использования.
// ИсключенияПоискаСсылок - см. ИсключенияПоискаСсылок
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - СтрокаТаблицыЗначений
// * Значение - Булево - всегда Истина. Если это не служебная связь данных, то в соответствии нет элемента.
//
Функция СлужебныеСвязиДанных(Знач МестаИспользования, Знач ИсключенияПоискаСсылок = Неопределено) Экспорт
Если ИсключенияПоискаСсылок = Неопределено Тогда
ИсключенияПоискаСсылок = ИсключенияПоискаСсылок();
КонецЕсли;
Результат = Новый Соответствие;
МестоИспользованияПоМетаданным = Новый Соответствие;
Для каждого МестоИспользования Из МестаИспользования Цикл
ИсключениеПоиска = ИсключенияПоискаСсылок[МестоИспользования.Метаданные];
// Данные могут быть как ссылкой, так и ключом записи регистра.
Если ИсключениеПоиска = Неопределено Тогда
Если МестоИспользования.Ссылка = МестоИспользования.Данные Тогда
Результат[МестоИспользования] = Истина; // Ссылку саму на себя исключаем.
КонецЕсли;
Продолжить;
ИначеЕсли ИсключениеПоиска = "*" Тогда
Результат[МестоИспользования] = Истина; // Если указано исключить все - считаем все исключением.
Продолжить;
КонецЕсли;
ЭтоСсылка = ЭтоСсылка(ТипЗнч(МестоИспользования.Данные));
Если Не ЭтоСсылка Тогда
Для Каждого ПутьКРеквизиту Из ИсключениеПоиска Цикл
ЗначениеРеквизита = Новый Структура(ПутьКРеквизиту);
ЗаполнитьЗначенияСвойств(ЗначениеРеквизита, МестоИспользования.Данные);
Если ЗначениеРеквизита[ПутьКРеквизиту] = МестоИспользования.Ссылка Тогда
Результат[МестоИспользования] = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Продолжить;
КонецЕсли;
Если ИсключениеПоиска.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
ИмяТаблицы = МестоИспользования.Метаданные.ПолноеИмя();
Значение = МестоИспользованияПоМетаданным[ИмяТаблицы];
Если Значение = Неопределено Тогда
Значение = Новый ТаблицаЗначений;
Значение.Колонки.Добавить("Ссылка", ОписаниеТипаВсеСсылки());
Значение.Колонки.Добавить("Данные", ОписаниеТипаВсеСсылки());
Значение.Колонки.Добавить("Метаданные");
МестоИспользованияПоМетаданным[ИмяТаблицы] = Значение;
КонецЕсли;
ЗаполнитьЗначенияСвойств(Значение.Добавить(), МестоИспользования);
КонецЦикла;
Индекс = 1;
Запрос = Новый Запрос;
ТекстыЗапроса = Новый Массив;
ВременныеТаблицы = Новый Массив;
Для каждого МестоИспользования Из МестоИспользованияПоМетаданным Цикл
ИмяТаблицы = МестоИспользования.Ключ; // Строка
МестоИспользования = МестоИспользования.Значение; // ТаблицаЗначений
// Проверка, есть ли по исключаемому пути в указанных данных проверяемая ссылка.
Если МестоИспользования.Количество() > 1 Тогда
ШаблонЗапроса =
"ВЫБРАТЬ
| Ссылки.Данные КАК Ссылка,
| Ссылки.Ссылка КАК ПроверяемаяСсылка
|ПОМЕСТИТЬ ВТТаблицаСсылок
|ИЗ
| &Ссылки КАК Ссылки
|;
|
|ВЫБРАТЬ
| ТаблицаСсылок.Ссылка КАК Ссылка,
| ТаблицаСсылок.ПроверяемаяСсылка КАК ПроверяемаяСсылка
|ИЗ
| ВТТаблицаСсылок КАК ТаблицаСсылок
| ЛЕВОЕ СОЕДИНЕНИЕ #ПолноеИмяОбъектаМетаданных КАК Таблица
| ПО ТаблицаСсылок.Ссылка = Таблица.Ссылка
|ГДЕ
| &Условие";
ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "#ПолноеИмяОбъектаМетаданных", ИмяТаблицы);
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВТТаблицаСсылок", "ВТТаблицаСсылок" + Формат(Индекс, "ЧГ=;ЧН="));
ИмяПараметра = "Ссылки" + Формат(Индекс, "ЧГ=;ЧН=");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра);
Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования);
ЧастиЗапроса = СтрРазделить(ТекстЗапроса, ";");
ВременныеТаблицы.Добавить(ЧастиЗапроса[0]);
ТекстЗапроса = ЧастиЗапроса[1];
Иначе
ШаблонЗапроса =
"ВЫБРАТЬ
| &СсылкаНаВладельца КАК Ссылка,
| &ПроверяемаяСсылка КАК ПроверяемаяСсылка
|ИЗ
| #ПолноеИмяОбъектаМетаданных КАК Таблица
|ГДЕ
| Таблица.Ссылка = &СсылкаНаВладельца
| И (&Условие)";
ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "#ПолноеИмяОбъектаМетаданных", ИмяТаблицы);
ИмяПараметра = "СсылкаНаВладельца" + Формат(Индекс, "ЧГ=;ЧН=");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СсылкаНаВладельца", "&" + ИмяПараметра);
Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования[0].Данные);
ИмяПараметра = "ПроверяемаяСсылка" + Формат(Индекс, "ЧГ=;ЧН=");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверяемаяСсылка", "&" + ИмяПараметра);
Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования[0].Ссылка);
КонецЕсли;
ТекстУсловия = Новый Массив;
// Относительный путь к реквизиту: "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]".
Для Каждого ПутьКРеквизиту Из ИсключенияПоискаСсылок[МестоИспользования[0].Метаданные] Цикл
ТекстУсловия.Добавить(ПутьКРеквизиту + " = "
+ ?(МестоИспользования.Количество() > 1, "ТаблицаСсылок.ПроверяемаяСсылка", "&" + ИмяПараметра));
КонецЦикла;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Условие", СтрСоединить(ТекстУсловия, " ИЛИ "));
ТекстыЗапроса.Добавить(ТекстЗапроса);
Индекс = Индекс + 1;
КонецЦикла;
Если ТекстыЗапроса.Количество() = 0 Тогда
Возврат Результат;
КонецЕсли;
Запрос.Текст = СтрСоединить(ВременныеТаблицы, ";" + Символы.ПС)
+ ?(ВременныеТаблицы.Количество() > 0, ";" + Символы.ПС, "")
+ СтрСоединить(ТекстыЗапроса, Символы.ПС + "ОБЪЕДИНИТЬ" + Символы.ПС);
УстановитьПривилегированныйРежим(Истина);
ВыборкаЗапроса = Запрос.Выполнить().Выбрать();
УстановитьПривилегированныйРежим(Ложь);
МестаИспользования.Индексы.Добавить("Ссылка,Данные");
Пока ВыборкаЗапроса.Следующий() Цикл
СлужебныеСвязиДанных = МестаИспользования.НайтиСтроки(Новый Структура("Ссылка,Данные",
ВыборкаЗапроса.ПроверяемаяСсылка, ВыборкаЗапроса.Ссылка));
Для каждого СлужебнаяСвязьДанных Из СлужебныеСвязиДанных Цикл
Результат[СлужебнаяСвязьДанных] = Истина;
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
// Определяет, указано ли место использования в исключениях поиска ссылок.
//
// Параметры:
// МестоИспользования - Структура:
// * Ссылка - ЛюбаяСсылка - проверяемая ссылка.
// * Данные - ЛюбаяСсылка - место использования.
// * Метаданные - ОбъектМетаданных - метаданные места использования.
// ИсключенияПоискаСсылок - см. ИсключенияПоискаСсылок
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоСлужебнаяСвязьДанных(Знач МестоИспользования, Знач ИсключенияПоискаСсылок = Неопределено) Экспорт
Если ИсключенияПоискаСсылок = Неопределено Тогда
ИсключенияПоискаСсылок = ИсключенияПоискаСсылок();
КонецЕсли;
Значение = Новый ТаблицаЗначений;
Значение.Колонки.Добавить("Ссылка", ОписаниеТипаВсеСсылки());
Значение.Колонки.Добавить("Данные", ОписаниеТипаВсеСсылки());
Значение.Колонки.Добавить("Метаданные");
МестоИспользованияСтрока = Значение.Добавить();
ЗаполнитьЗначенияСвойств(МестоИспользованияСтрока, МестоИспользования);
Результат = СлужебныеСвязиДанных(Значение, ИсключенияПоискаСсылок);
Возврат Результат[МестоИспользованияСтрока] <> Неопределено;
КонецФункции
// Производит замену ссылок во всех данных. После замены неиспользуемые ссылки опционально удаляются.
// Замена ссылок происходит с транзакциями по изменяемому объекту и его связям, не по анализируемой ссылке.
// При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях.
// Если описаны связи подчиненных и основных объектов (см. СвязиПодчиненныхОбъектов), то:
// * при замене основных объектов будет выполнен поиск замен подчиненных объектов;
// * если ВыполнятьАвтоматическийПоискЗамен = Истина, то будет выполнена попытка поиска замен для подчиненных объектов
// по значениям полей связи. В случае, если объект не существует, будет выполнена процедура ПриПоискеЗаменыСсылок;
// * если МетодПоиска в описании связей задан, то если автоматический поиск не нашел замен
// или не выполнялся, будет вызван МетодПоиска для подбора замен.
//
// Параметры:
// ПарыЗамен - Соответствие из КлючИЗначение:
// * Ключ - ЛюбаяСсылка - что ищем (дубль).
// * Значение - ЛюбаяСсылка - на что заменяем (оригинал).
// Ссылки сами на себя и пустые ссылки для поиска будут проигнорированы.
//
// ПараметрыЗамены - см. ОбщегоНазначения.ПараметрыЗаменыСсылок
//
// Возвращаемое значение:
// ТаблицаЗначений - неуспешные замены (ошибки):
// * Ссылка - ЛюбаяСсылка - ссылка, которую заменяли.
// * ДубльРодитель - ЛюбаяСсылка - ссылка на дубль для группировки ошибок подчиненных объектов.
// Если нет связанных подчиненных, заполняется значением из колонки Ссылка.
// * ОбъектОшибки - Произвольный - объект-причина ошибки.
// * ПредставлениеОбъектаОшибки - Строка - строковое представление объекта ошибки.
// * ТипОшибки - Строка - тип ошибки:
// "ОшибкаБлокировки" - при замене в объекте данные были заблокированы другим сеансом.
// "ДанныеИзменены" - в процессе замены данные были изменены другим пользователем.
// "ОшибкаЗаписи" - не удалось записать объект, или метод ВозможностьЗаменыЭлементов вернул отказ.
// "ОшибкаУдаления" - не удалось удалить объект.
// "НеизвестныеДанные" - при обработке были найдены данные, которые не планировались к замене.
// * ИнформацияОбОшибке - ИнформацияОбОшибке
// * ТекстОшибки - Строка - если свойство ИнформацияОбОшибке содержит Неопределено, то описание причины.
//
Функция ЗаменитьСсылки(Знач ПарыЗамен, Знач ПараметрыЗамены = Неопределено) Экспорт
Статистика = Новый Соответствие;
ТипСтрока = Новый ОписаниеТипов("Строка");
ОшибкиЗамены = Новый ТаблицаЗначений;
ОшибкиЗамены.Колонки.Добавить("Ссылка");
ОшибкиЗамены.Колонки.Добавить("ДубльРодитель");
ОшибкиЗамены.Колонки.Добавить("ОбъектОшибки");
ОшибкиЗамены.Колонки.Добавить("ПредставлениеОбъектаОшибки", ТипСтрока);
ОшибкиЗамены.Колонки.Добавить("ТипОшибки", ТипСтрока);
ОшибкиЗамены.Колонки.Добавить("ТекстОшибки", ТипСтрока);
ОшибкиЗамены.Колонки.Добавить("ИнформацияОбОшибке");
ОшибкиЗамены.Индексы.Добавить("Ссылка");
ОшибкиЗамены.Индексы.Добавить("Ссылка, ОбъектОшибки, ТипОшибки");
Результат = РезультатЗаменыСсылок(ОшибкиЗамены);
ПараметрыВыполнения = НовыйПараметрыВыполненияЗаменыСсылок(ПараметрыЗамены);
ПараметрыПоискаМестИспользования = ПараметрыПоискаМестИспользования();
ДополнитьИсключенияПоискаСсылокПодчиненнымиОбъектами(ПараметрыПоискаМестИспользования.ДополнительныеИсключенияПоискаСсылок);
ПараметрыВыполнения.Вставить("ПараметрыПоискаМестИспользования", ПараметрыПоискаМестИспользования);
ПараметрыВыполнения.Вставить("ПодчиненныеКДублям", Новый Соответствие());
ИнтеграцияПодсистемБСП.ПередПоискомМестИспользования(ПарыЗамен, ПараметрыВыполнения);
Если ПарыЗамен.Количество() = 0 Тогда
Возврат Результат.Ошибки;
КонецЕсли;
Дубли = СформироватьДубли(ПараметрыВыполнения, ПараметрыЗамены, ПарыЗамен, Результат);
ТаблицаПоиска = МестаИспользования(Дубли,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования);
// Для каждой ссылки объекта будем производить замены в порядке "Константа", "Объект", "Набор".
// Одновременно пустая строка в этой колонке - флаг того, что эта замена не нужна или уже была произведена.
ТаблицаПоиска.Колонки.Добавить("КлючЗамены", ТипСтрока);
ТаблицаПоиска.Индексы.Добавить("Ссылка, КлючЗамены");
ТаблицаПоиска.Индексы.Добавить("Данные, КлючЗамены");
// Вспомогательные данные
ТаблицаПоиска.Колонки.Добавить("ЦелеваяСсылка");
ТаблицаПоиска.Колонки.Добавить("Обработано", Новый ОписаниеТипов("Булево"));
// Определяем порядок обработки и проверяем то, что можно обработать.
ОшибкиРазметки = Новый Массив;
ОбъектыСОшибками = Новый Массив;
Количество = Дубли.Количество();
Для Номер = 1 По Количество Цикл
ОбратныйИндекс = Количество - Номер;
Дубль = Дубли[ОбратныйИндекс];
РезультатРазметки = РазметитьМестаИспользования(ПараметрыВыполнения, Дубль, ПарыЗамен[Дубль], ТаблицаПоиска);
Если Не РезультатРазметки.Успех Тогда
Дубли.Удалить(ОбратныйИндекс);
Для Каждого Ошибка Из РезультатРазметки.ОшибкиРазметки Цикл
Ошибка.Вставить("Дубль", Дубль);
ОбъектыСОшибками.Добавить(Ошибка.Объект);
КонецЦикла;
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОшибкиРазметки, РезультатРазметки.ОшибкиРазметки);
КонецЕсли;
КонецЦикла;
Если ОшибкиРазметки.Количество() > 0 Тогда
ПредставленияОбъектов = ПредметыСтрокой(ОбъектыСОшибками);
Для Каждого Ошибка Из ОшибкиРазметки Цикл
ЗарегистрироватьОшибкуЗамены(
Результат,
Ошибка.Дубль,
ОписаниеОшибкиЗамены("НеизвестныеДанные", Ошибка.Объект, ПредставленияОбъектов[Ошибка.Объект],
Ошибка.Текст),
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЦикла;
КонецЕсли;
// Замена и удаление найденных дублей.
ПараметрыВыполнения.Вставить("ПарыЗамен", ПарыЗамен);
ПараметрыВыполнения.Вставить("УспешныеЗамены", Новый Соответствие);
ОтключитьОбновлениеКлючейДоступа(Истина);
Попытка
ТекстПрогресса = НСтр("ru = 'Замена дублей...'");
ДополнительныеПараметрыПрогресса = Новый Структура;
ДополнительныеПараметрыПрогресса.Вставить("КоличествоОбработанных", 0);
Для Каждого Дубль Из Дубли Цикл
БылиОшибки = Результат.ЕстьОшибки;
Результат.ЕстьОшибки = Ложь;
// @skip-check query-in-loop - Порционная обработка большого объема данных.
ЗаменитьСсылкиКороткимиТранзакциями(Результат, ПараметрыВыполнения, Дубль, ТаблицаПоиска);
Если НЕ Результат.ЕстьОшибки Тогда
ПараметрыВыполнения.УспешныеЗамены.Вставить(Дубль, ПараметрыВыполнения.ПарыЗамен[Дубль]);
КонецЕсли;
Результат.ЕстьОшибки = Результат.ЕстьОшибки ИЛИ БылиОшибки;
ДополнительныеПараметрыПрогресса.КоличествоОбработанных =
ДополнительныеПараметрыПрогресса.КоличествоОбработанных + 1;
ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, Результат.ЕстьОшибки);
Если ДополнительныеПараметрыПрогресса.КоличествоОбработанных >9 Тогда
ДлительныеОперации.СообщитьПрогресс(ДополнительныеПараметрыПрогресса.КоличествоОбработанных,
ТекстПрогресса, ДополнительныеПараметрыПрогресса);
ДополнительныеПараметрыПрогресса.КоличествоОбработанных = 0;
КонецЕсли;
КонецЦикла;
Если ДополнительныеПараметрыПрогресса.КоличествоОбработанных > 0 Тогда
ДлительныеОперации.СообщитьПрогресс(ДополнительныеПараметрыПрогресса.КоличествоОбработанных,
ТекстПрогресса, ДополнительныеПараметрыПрогресса);
КонецЕсли;
ОбщегоНазначенияПереопределяемый.ПослеЗаменыСсылок(Результат, ПараметрыВыполнения, ТаблицаПоиска);
ОтключитьОбновлениеКлючейДоступа(Ложь);
Исключение
ОтключитьОбновлениеКлючейДоступа(Ложь);
ВызватьИсключение;
КонецПопытки;
Если ПодсистемаСуществует("СтандартныеПодсистемы.УдалениеПомеченныхОбъектов")
И ПараметрыВыполнения.УдалятьНепосредственно Тогда
МодульУдалениеПомеченныхОбъектов = ОбщийМодуль("УдалениеПомеченныхОбъектов");
ДополнительныеПараметрыПрогресса = Новый Структура;
ДлительныеОперации.СообщитьПрогресс(0, НСтр("ru = 'Удаление дублей...'"), ДополнительныеПараметрыПрогресса);
РезультатУдаления = МодульУдалениеПомеченныхОбъектов.УдалитьПомеченныеОбъекты(Результат.ОчередьКНепосредственномуУдалению);
ЗарегистрироватьОшибкиУдаления(Результат, РезультатУдаления.ПрепятствующиеУдалению, ПараметрыВыполнения);
КонецЕсли;
ОтправитьСтатистикуЗаменыСсылок(Статистика);
Возврат Результат.Ошибки;
КонецФункции
// Конструктор структуры для параметра ПараметрыЗамены функции ОбщегоНазначения.ЗаменитьСсылки.
//
// Возвращаемое значение:
// Структура:
// * СпособУдаления - Строка - указывает, что делать с дублем после успешной замены:
// "" - не предпринимать никаких действий (по умолчанию);
// "Пометка" - помечать на удаление;
// "Непосредственно" - удалять непосредственно.
// * УчитыватьПрикладныеПравила - Булево - если Истина, то для каждой пары "дубль-оригинал"
// вызывается функция ВозможностьЗаменыЭлементов модуля менеджера
// (требуется подсистема "Поиск и удаление дублей"). По умолчанию, Ложь.
// * ВключатьБизнесЛогику - Булево - режим записи объектов при замене в них ссылок дублей на оригиналы.
// Если Истина (по умолчанию), то места использования дублей записываются в обычном режиме,
// иначе запись ведется в режиме ОбменДанными.Загрузка = Истина.
// * ЗаменаПарыВТранзакции - Булево - устарел. определяет размер транзакции при замене дублей.
// Если Истина (по умолчанию), то все места использования одного дубля заменяются в одной транзакции.
// Это может быть очень ресурсоемко в случае большого количества мест использований.
// Если Ложь, то замена в каждом месте использования выполняется в отдельной транзакции.
// * ПривилегированнаяЗапись - Булево - если Истина, то устанавливать привилегированный режим перед запись
// объектов при замене в них ссылок дублей на оригиналы. По умолчанию Ложь.
//
Функция ПараметрыЗаменыСсылок() Экспорт
Результат = Новый Структура;
Результат.Вставить("СпособУдаления", "");
Результат.Вставить("УчитыватьПрикладныеПравила", Ложь);
Результат.Вставить("ВключатьБизнесЛогику", Истина);
Результат.Вставить("ЗаменаПарыВТранзакции", Ложь);
Результат.Вставить("ПривилегированнаяЗапись", Ложь);
Возврат Результат;
КонецФункции
// Получает все места использования ссылок.
// Если какая-либо ссылка нигде не используется, то строк для нее в результирующей таблице не будет.
// При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях.
//
// Параметры:
// НаборСсылок - Массив из ЛюбаяСсылка - ссылки, для которых ищем места использования.
// АдресРезультата - Строка - адрес во временном хранилище, куда будет помещен копия результата замены.
// ДополнительныеПараметры - см. ОбщегоНазначения.ПараметрыПоискаМестИспользования
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * Ссылка - ЛюбаяСсылка - ссылка, которая анализируется.
// * Данные - Произвольный - данные, содержащие анализируемую ссылку.
// * Метаданные - ОбъектМетаданных - метаданные найденных данных.
// * ПредставлениеДанных - Строка - представление данных, содержащих анализируемую ссылку.
// * ТипСсылки - Тип - тип анализируемой ссылки.
// * ВспомогательныеДанные - Булево - Истина, если данные используются анализируемой ссылкой как
// вспомогательные данные (ведущее измерение или попали в исключение ПриДобавленииИсключенийПоискаСсылок).
// * ЭтоСлужебныеДанные - Булево - данные попали в исключение ПриДобавленииИсключенийПоискаСсылок
//
Функция МестаИспользования(Знач НаборСсылок, Знач АдресРезультата = "", ДополнительныеПараметры = Неопределено) Экспорт
МестаИспользования = Новый ТаблицаЗначений;
ИсключенияПоискаРегистровПодчиненныхРегистратору = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
ДополнительныеПараметры, "ИсключенияПоискаРегистровПодчиненныхРегистратору", Неопределено);
УстановитьПривилегированныйРежим(Истина);
МестаИспользования = НайтиПоСсылкам(НаборСсылок, , , ИсключенияПоискаРегистровПодчиненныхРегистратору); // см. МестаИспользования.
УстановитьПривилегированныйРежим(Ложь);
// МестаИспользования - ТаблицаЗначений - где:
// * Ссылка - ЛюбаяСсылка - Ссылка, которая анализируется.
// * Данные - Произвольный - Данные, содержащие анализируемую ссылку.
// * Метаданные - ОбъектМетаданных - Метаданные найденных данных.
МестаИспользования.Колонки.Добавить("ПредставлениеДанных", Новый ОписаниеТипов("Строка"));
МестаИспользования.Колонки.Добавить("ТипСсылки");
МестаИспользования.Колонки.Добавить("ИнформацияОМестеИспользования");
МестаИспользования.Колонки.Добавить("ВспомогательныеДанные", Новый ОписаниеТипов("Булево"));
МестаИспользования.Колонки.Добавить("ЭтоСлужебныеДанные", Новый ОписаниеТипов("Булево"));
МестаИспользования.Индексы.Добавить("Ссылка");
МестаИспользования.Индексы.Добавить("Данные");
МестаИспользования.Индексы.Добавить("ВспомогательныеДанные");
МестаИспользования.Индексы.Добавить("Ссылка, ВспомогательныеДанные");
ТипКлючиЗаписей = ОписаниеТипаКлючиЗаписей();
ТипВсеСсылки = ОписаниеТипаВсеСсылки();
МетаданныеПоследовательностей = Метаданные.Последовательности;
МетаданныеКонстант = Метаданные.Константы;
МетаданныеДокументов = Метаданные.Документы;
ИсключенияПоискаСсылок = ИсключенияПоискаСсылок();
ДополнительныеИсключенияПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
ДополнительныеПараметры, "ДополнительныеИсключенияПоискаСсылок", Новый Соответствие);
Для каждого МетаданныеРеквизитыИсключения Из ДополнительныеИсключенияПоискаСсылок Цикл
ЗначениеИсключения = ИсключенияПоискаСсылок[МетаданныеРеквизитыИсключения.Ключ];
Если ЗначениеИсключения = Неопределено Тогда
ИсключенияПоискаСсылок.Вставить(МетаданныеРеквизитыИсключения.Ключ, МетаданныеРеквизитыИсключения.Значение);
ИначеЕсли ТипЗнч(ЗначениеИсключения) = Тип("Массив") Тогда
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ЗначениеИсключения, МетаданныеРеквизитыИсключения.Значение);
КонецЕсли;
КонецЦикла;
ОтменаИсключенийПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеПараметры,
"ОтменаИсключенийПоискаСсылок", Новый Массив);
Для каждого ОтменаИсключения Из ОтменаИсключенийПоискаСсылок Цикл
ИсключенияПоискаСсылок.Удалить(ОтменаИсключения);
КонецЦикла;
СлужебныеСвязиДанных = СлужебныеСвязиДанных(МестаИспользования, ИсключенияПоискаСсылок);
КэшИзмеренийРегистров = Новый Соответствие;
Для Каждого МестоИспользования Из МестаИспользования Цикл
ТипДанных = ТипЗнч(МестоИспользования.Данные);
ЭтоСлужебныеДанные = СлужебныеСвязиДанных[МестоИспользования] <> Неопределено;
ЭтоВспомогательныеДанные = ЭтоСлужебныеДанные;
Если ТипДанных = Неопределено Или МетаданныеДокументов.Содержит(МестоИспользования.Метаданные) Тогда
Представление = Строка(МестоИспользования.Данные);
ИначеЕсли МетаданныеКонстант.Содержит(МестоИспользования.Метаданные) Тогда
Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = 'константа'") + ")";
ИначеЕсли МетаданныеПоследовательностей.Содержит(МестоИспользования.Метаданные) Тогда
Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = 'последовательность'") + ")";
ИначеЕсли ТипВсеСсылки.СодержитТип(ТипДанных) Тогда
МетаПредставлениеОбъекта = Новый Структура("ПредставлениеОбъекта");
ЗаполнитьЗначенияСвойств(МетаПредставлениеОбъекта, МестоИспользования.Метаданные);
Если ПустаяСтрока(МетаПредставлениеОбъекта.ПредставлениеОбъекта) Тогда
МетаПредставление = МестоИспользования.Метаданные.Представление();
Иначе
МетаПредставление = МетаПредставлениеОбъекта.ПредставлениеОбъекта;
КонецЕсли;
Представление = Строка(МестоИспользования.Данные);
Если Не ПустаяСтрока(МетаПредставление) Тогда
Представление = Представление + " (" + МетаПредставление + ")";
КонецЕсли;
ИначеЕсли ТипКлючиЗаписей.СодержитТип(ТипДанных) Тогда
Представление = МестоИспользования.Метаданные.ПредставлениеЗаписи;
Если ПустаяСтрока(Представление) Тогда
Представление = МестоИспользования.Метаданные.Представление();
КонецЕсли;
ОписаниеИзмерений = Новый Массив;
Для Каждого МетаданныеРеквизитыИсключения Из ОписаниеИзмеренийНабора(МестоИспользования.Метаданные, КэшИзмеренийРегистров) Цикл
Значение = МестоИспользования.Данные[МетаданныеРеквизитыИсключения.Ключ];
Описание = МетаданныеРеквизитыИсключения.Значение;
Если МестоИспользования.Ссылка = Значение Тогда
Если Описание.Ведущее Тогда
ЭтоВспомогательныеДанные = Истина;
КонецЕсли;
КонецЕсли;
Если Не ЭтоСлужебныеДанные Тогда // для оптимизации
ФорматЗначения = Описание.Формат;
ОписаниеИзмерений.Добавить(Описание.Представление + " """
+ ?(ФорматЗначения = Неопределено, Строка(Значение), Формат(Значение, ФорматЗначения)) + """");
КонецЕсли;
КонецЦикла;
Если ОписаниеИзмерений.Количество() > 0 Тогда
Представление = Представление + " (" + СтрСоединить(ОписаниеИзмерений, ", ") + ")";
КонецЕсли;
Иначе
Представление = Строка(МестоИспользования.Данные);
КонецЕсли;
МестоИспользования.ПредставлениеДанных = Представление;
МестоИспользования.ВспомогательныеДанные = ЭтоВспомогательныеДанные;
МестоИспользования.ЭтоСлужебныеДанные = ЭтоСлужебныеДанные;
МестоИспользования.ТипСсылки = ТипЗнч(МестоИспользования.Ссылка);
КонецЦикла;
Если Не ПустаяСтрока(АдресРезультата) Тогда
ПоместитьВоВременноеХранилище(МестаИспользования, АдресРезультата);
КонецЕсли;
Возврат МестаИспользования;
КонецФункции
// Возвращает структуру для параметра ДополнительныеПараметры функции ОбщегоНазначения.МестаИспользования.
//
// Возвращаемое значение:
// Структура:
// * ДополнительныеИсключенияПоискаСсылок - Соответствие - позволяет расширить исключения поиска ссылок
// см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.
// * ОтменаИсключенийПоискаСсылок - Массив из ОбъектМетаданных - полностью отменяет исключения поиска ссылок для
// объектов метаданных.
// * ИсключенияПоискаРегистровПодчиненныхРегистратору - Массив из ОбъектМетаданных - если в см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок
// указаны регистры подчиненные регистратору, то их необходимо добавить.
//
Функция ПараметрыПоискаМестИспользования() Экспорт
ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("ДополнительныеИсключенияПоискаСсылок", Новый Соответствие);
ПараметрыПоиска.Вставить("ОтменаИсключенийПоискаСсылок", Новый Соответствие);
ПараметрыПоиска.Вставить("ИсключенияПоискаРегистровПодчиненныхРегистратору", Новый Массив);
Возврат ПараметрыПоиска;
КонецФункции
// Возвращает исключения при поиске мест использования объектов.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение - исключения поиска ссылок в разрезе объектов метаданных:
// * Ключ - ОбъектМетаданных - объект метаданных, для которого применяются исключения.
// * Значение - Строка
// - Массив из Строка - описание исключенных реквизитов.
// Если "*", то исключены все реквизиты объекта метаданных.
// Если массив строк, то содержит относительные имена исключенных реквизитов.
//
Функция ИсключенияПоискаСсылок() Экспорт
ИсключенияПоискаИнтеграция = Новый Массив;
ИнтеграцияПодсистемБСП.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаИнтеграция);
ИсключенияПоиска = Новый Массив;
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ИсключенияПоиска, ИсключенияПоискаИнтеграция);
ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоиска);
Результат = Новый Соответствие;
Для Каждого ИсключениеПоиска Из ИсключенияПоиска Цикл
// Определение полного имени реквизита и объекта метаданных - носителя реквизита.
Если ТипЗнч(ИсключениеПоиска) = Тип("Строка") Тогда
ПолноеИмя = ИсключениеПоиска;
МассивПодстрок = СтрРазделить(ПолноеИмя, ".");
КоличествоПодстрок = МассивПодстрок.Количество();
ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(МассивПодстрок[0] + "." + МассивПодстрок[1]);
Иначе
ОбъектМетаданных = ИсключениеПоиска;
ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
МассивПодстрок = СтрРазделить(ПолноеИмя, ".");
КоличествоПодстрок = МассивПодстрок.Количество();
Если КоличествоПодстрок > 2 Тогда
Пока Истина Цикл
Родитель = ОбъектМетаданных.Родитель();
Если ТипЗнч(Родитель) = Тип("ОбъектМетаданныхКонфигурация") Тогда
Прервать;
Иначе
ОбъектМетаданных = Родитель;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
// Регистрация.
Если КоличествоПодстрок < 4 Тогда
Результат.Вставить(ОбъектМетаданных, "*");
Иначе
ПутиКРеквизитам = Результат.Получить(ОбъектМетаданных);
Если ПутиКРеквизитам = "*" Тогда
Продолжить; // Весь объект метаданных уже исключен.
ИначеЕсли ПутиКРеквизитам = Неопределено Тогда
ПутиКРеквизитам = Новый Массив;
Результат.Вставить(ОбъектМетаданных, ПутиКРеквизитам);
КонецЕсли;
// Формат реквизита:
// "<ВидОМ>.<ИмяОМ>.<ТипРеквизитаИлиТЧ>.<ИмяРеквизитаИлиТЧ>[.<ТипРеквизита>.<ИмяРеквизитаТЧ>]".
// Примеры:
// "РегистрСведений.ВерсииОбъектов.Реквизит.АвторВерсии",
// "Документ.ЗаказПокупателя.ТабличнаяЧасть.СчетаНаОплату.Реквизит.Счет",
// "ПланВидовРасчета.ОсновныеНачисления.СтандартнаяТабличнаяЧасть.БазовыеВидыРасчета.СтандартныйРеквизит.ВидРасчета".
// Относительный путь к реквизиту должен получиться таким, чтобы его можно было использовать в условиях запроса:
// "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]".
Если КоличествоПодстрок = 4 Тогда
ОтносительныйПутьКРеквизиту = МассивПодстрок[3];
Иначе
ОтносительныйПутьКРеквизиту = МассивПодстрок[3] + "." + МассивПодстрок[5];
КонецЕсли;
ПутиКРеквизитам.Добавить(ОтносительныйПутьКРеквизиту);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает связи подчиненных объектов и перечень реквизитов, по которым осуществляется связь.
//
// Есть возможность переопределить процедуру поиска подчиненных объектов.
// Для этого в общем модуле или модуле менеджера необходимо реализовать процедуру
// ПриПоискеЗаменыСсылок с параметрами:
// ПарыЗамен - Соответствие - содержит пары значение оригинал/дубль.
// НеобработанныеЗначенияОригиналов - Массив из Структура - дополнительная информация об обрабатываемых объектах:
// * ЗаменяемоеЗначение - ПроизвольнаяСсылка - оригинальное значение заменяемого объекта.
// * ИспользуемыеСвязи - см. ОбщегоНазначения.СвязиПодчиненныхОбъектовПоТипам
// * ЗначениеКлючевыхРеквизитов - Структура - где Ключ - имя реквизита, значение - значение реквизита.
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * ПодчиненныйОбъект - ОбъектМетаданных - объект метаданных подчиненного объекта.
// * ПоляСвязей - Строка - имена реквизитов, определяющих связь между основными и подчиненными объектами.
// * ПриПоискеЗаменыСсылок - Строка - опционально. Имя общего модуля или модуля менеджера, в котором определена
// процедура ПриПоискеЗаменыСсылок.
// * ВыполнятьАвтоматическийПоискЗаменСсылок - Булево - если указать Истина, то будет выполнена попытка поиска замен
// для подчиненных объектов по значениям полей связи. В случае, если объект не существует,
// будет выполнена процедура ПриПоискеЗаменыСсылок. См. также ЗаменитьСсылки.
//
Функция ПодчиненныеОбъекты() Экспорт
ОписаниеСвязей = Новый ТаблицаЗначений;
ОписаниеСвязей.Колонки.Добавить("ПодчиненныйОбъект", Новый ОписаниеТипов("ОбъектМетаданных"));
ОписаниеСвязей.Колонки.Добавить("ПоляСвязей");
ОписаниеСвязей.Колонки.Добавить("ПриПоискеЗаменыСсылок", ОписаниеТипаСтрока(0));
ОписаниеСвязей.Колонки.Добавить("ВыполнятьАвтоматическийПоискЗаменСсылок", Новый ОписаниеТипов("Булево"));
ИнтеграцияПодсистемБСП.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей);
ОбщегоНазначенияПереопределяемый.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей);
// Если передали соответствие или структуру преобразуем к необходимому типу.
Для каждого СтрокаСвязи Из ОписаниеСвязей Цикл
ТипОписанияПолейСвязи = ТипЗнч(СтрокаСвязи.ПоляСвязей);
Если ТипОписанияПолейСвязи = Тип("Структура")
ИЛИ ТипОписанияПолейСвязи = Тип("Соответствие") Тогда
ПоляСвязейСтрокой = "";
Для каждого КлючЗначение Из СтрокаСвязи.ПоляСвязей Цикл
ПоляСвязейСтрокой = ПоляСвязейСтрокой + КлючЗначение.Ключ + ",";
КонецЦикла;
СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(ПоляСвязейСтрокой,1);
СтрокаСвязи.ПоляСвязей = ПоляСвязейСтрокой;
КонецЕсли;
Если ТипОписанияПолейСвязи = Тип("Массив") Тогда
СтрокаСвязи.ПоляСвязей = СтрСоединить(СтрокаСвязи.ПоляСвязей, ",");
КонецЕсли;
КонецЦикла;
Возврат ОписаниеСвязей;
КонецФункции
// Возвращает связи подчиненных объектов с указанием типа поля связи.
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * Ключ - Строка
// * ТипРеквизита - Тип
// * ИмяРеквизита - Строка
// * Используется - Булево
// * Метаданные - ОбъектМетаданных
//
Функция СвязиПодчиненныхОбъектовПоТипам() Экспорт
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("ТипРеквизита", Новый ОписаниеТипов("Тип"));
Результат.Колонки.Добавить("ИмяРеквизита", ОписаниеТипаСтрока(0));
Результат.Колонки.Добавить("Ключ", ОписаниеТипаСтрока(0));
Результат.Колонки.Добавить("Используется", Новый ОписаниеТипов("Булево"));
Результат.Колонки.Добавить("Метаданные");
Возврат Результат;
КонецФункции
#КонецОбласти
#Область УсловныеВызовы
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для вызова необязательных подсистем.
// Возвращает Истина, если функциональная подсистема существует в конфигурации.
// Предназначена для вызова необязательной подсистемы (условного вызова) совместно с ОбщегоНазначения.ОбщийМодуль.
//
// У функциональной подсистемы снят флажок "Включать в командный интерфейс".
// См. также ОбщегоНазначенияПереопределяемый.ПриОпределенииОтключенныхПодсистем
// и ОбщегоНазначенияКлиент.ПодсистемаСуществует для вызова из клиентского кода.
//
// Параметры:
// ПолноеИмяПодсистемы - Строка - полное имя объекта метаданных подсистема
// без слов "Подсистема." и с учетом регистра символов.
// Например: "СтандартныеПодсистемы.ВариантыОтчетов".
//
// Пример:
// Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВариантыОтчетов") Тогда
// МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов");
// МодульВариантыОтчетов.<Имя процедуры>();
// КонецЕсли;
//
// Возвращаемое значение:
// Булево
//
Функция ПодсистемаСуществует(ПолноеИмяПодсистемы) Экспорт
ИменаПодсистем = СтандартныеПодсистемыПовтИсп.ИменаПодсистем();
Возврат ИменаПодсистем.Получить(ПолноеИмяПодсистемы) <> Неопределено;
КонецФункции
// Возвращает ссылку на общий модуль или модуль менеджера по имени.
// Применяется для условного вызова процедуры или функции совместно с ОбщегоНазначения.ПодсистемаСуществует.
// См. также ОбщегоНазначенияКлиент.ОбщийМодуль для вызова клиентского кода.
//
// Параметры:
// Имя - Строка - имя общего модуля или модуля менеджера, например "ОбновлениеКонфигурации",
// "Обработки.ПолнотекстовыйПоиск".
//
// Возвращаемое значение:
// - ОбщийМодуль
// - ПланОбменаМенеджер
// - КритерийОтбораМенеджер
// - ХранилищеНастроекМенеджер
// - КонстантаМенеджер
// - СправочникМенеджер
// - ДокументМенеджер
// - ЖурналДокументовМенеджер
// - ПеречислениеМенеджер
// - ОтчетМенеджер
// - ОбработкаМенеджер
// - ПланВидовХарактеристикМенеджер
// - ПланСчетовМенеджер
// - ПланВидовРасчетаМенеджер
// - РегистрСведенийМенеджер
// - РегистрНакопленияМенеджер
// - РегистрБухгалтерииМенеджер
// - РегистрРасчетаМенеджер
// - БизнесПроцессМенеджер
// - ЗадачаМенеджер
// - ВнешнийИсточникДанныхТаблицаМенеджер
// - ВнешнийИсточникДанныхКубМенеджер
// - ВнешнийИсточникДанныхКубТаблицаИзмеренияМенеджер
//
// Пример:
// Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда
// МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации");
// МодульОбновлениеКонфигурации.<Имя процедуры>();
// КонецЕсли;
//
// Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолнотекстовыйПоиск") Тогда
// МодульОбработкаПолнотекстовыйПоиск = ОбщегоНазначения.ОбщийМодуль("Обработки.ПолнотекстовыйПоиск");
// МодульОбработкаПолнотекстовыйПоиск.<Имя процедуры>();
// КонецЕсли;
//
Функция ОбщийМодуль(Имя) Экспорт
Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда
// АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно.
УстановитьБезопасныйРежим(Истина);
Модуль = Вычислить(Имя); // Не нарушает безопасность информации, так как вычисляется ссылка на общий модуль по проверенному имени.
// АПК:488-вкл
ИначеЕсли СтрЧислоВхождений(Имя, ".") > 0 Тогда
Возврат МенеджерОбъектаПоИмени(Имя, Истина, Истина, Истина, "ОбщегоНазначения.ОбщийМодуль", "Имя");
Иначе
Модуль = Неопределено;
КонецЕсли;
Если ТипЗнч(Модуль) <> Тип("ОбщийМодуль") Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение параметра %1 в %2. Общий модуль ""%3"" не существует.'"),
"Имя", "ОбщегоНазначения.ОбщийМодуль", Имя),
КатегорияОшибки.ОшибкаКонфигурации,
"СтандартныеПодсистемы.БазоваяФункциональность.ЭтоОшибкаПолученияОбщегоМодуляПоИмени");
КонецЕсли;
Возврат Модуль;
КонецФункции
#КонецОбласти
#Область ТекущееОкружение
////////////////////////////////////////////////////////////////////////////////
// Функции описания текущего окружения клиентского приложения и операционной системы.
// Возвращает Истина, если клиентское приложение запущено под управлением ОС Windows.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоWindowsКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоWindowsКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоWindowsКлиент");
Если ЭтоWindowsКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоWindowsКлиент;
КонецФункции
// Возвращает Истина, если текущий сеанс выполняется на сервере, работающем под управлением ОС Windows.
//
// Возвращаемое значение:
// Булево - Истина, если сервер работает под управлением ОС Windows.
//
Функция ЭтоWindowsСервер() Экспорт
СистемнаяИнформация = Новый СистемнаяИнформация;
Возврат СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86
Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64;
КонецФункции
// Возвращает Истина, если клиентское приложение запущено под управлением ОС Linux.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоLinuxКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоLinuxКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоLinuxКлиент");
Если ЭтоLinuxКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоLinuxКлиент;
КонецФункции
// Возвращает Истина, если текущий сеанс выполняется на сервере, работающем под управлением ОС Linux.
//
// Возвращаемое значение:
// Булево - Истина, если сервер работает под управлением ОС Linux.
//
Функция ЭтоLinuxСервер() Экспорт
СистемнаяИнформация = Новый СистемнаяИнформация;
Возврат СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86
Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64
Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы["Linux_ARM64"]
Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы["Linux_E2K"];
КонецФункции
// Возвращает Истина, если клиентское приложение запущено под управлением macОС.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоMacOSКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент");
Если ЭтоMacOSКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоMacOSКлиент;
КонецФункции
// Возвращает Истина, если клиентское приложение является Веб-клиентом.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоВебКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоВебКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоВебКлиент");
Если ЭтоВебКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоВебКлиент;
КонецФункции
// Возвращает Истина, если клиентское приложение является мобильным клиентом.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоМобильныйКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоМобильныйКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоМобильныйКлиент");
Если ЭтоМобильныйКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоМобильныйКлиент;
КонецФункции
// Возвращает Истина, если клиентское приложение подключено к базе через веб-сервер.
//
// Возвращаемое значение:
// Булево - Истина, если подключен.
//
Функция КлиентПодключенЧерезВебСервер() Экспорт
УстановитьПривилегированныйРежим(Истина);
СтрокаСоединенияИнформационнойБазы = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("СтрокаСоединенияИнформационнойБазы");
Если СтрокаСоединенияИнформационнойБазы = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат СтрНайти(ВРег(СтрокаСоединенияИнформационнойБазы), "WS=") = 1;
КонецФункции
// Возвращает системную информацию клиента, если есть клиентское приложение.
// До первого серверного вызова с клиента вернет Неопределено.
//
// Возвращаемое значение:
// - ФиксированнаяСтруктура:
// * ВерсияОС - Строка
// * ВерсияПриложения - Строка
// * ИдентификаторКлиента - УникальныйИдентификатор
// * ИнформацияПрограммыПросмотра - Строка
// * ОперативнаяПамять - Число
// * Процессор - Строка
// * ТипПлатформы - см. ОбщегоНазначенияКлиентСервер.ИмяТипаПлатформы
// - Неопределено - если нет клиентского приложения или информация запрашивается
// до первого серверного вызова, например, при первом вызове события
// платформы УстановкаПараметровСеанса в модуле сеанса.
//
Функция СистемнаяИнформацияКлиента() Экспорт
УстановитьПривилегированныйРежим(Истина);
Возврат СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("СистемнаяИнформация");
КонецФункции
// Возвращает имя используемого клиента, а для веб-браузера название и версию, если есть.
// До первого серверного вызова с клиента вернет Неопределено.
//
// Возвращаемое значение:
// - Строка - варианты строк "ВебКлиент.<Название>[.<Версия>]", "ТонкийКлиент",
// "ТолстыйКлиентУправляемоеПриложение", "ТолстыйКлиентОбычноеПриложение",
// где <Название> - варианты строк "Chrome", "Firefox", "Safari", "IE", "Opera"
// или "Другой", когда не определен (ни один из указанных), например "ВебКлиент.Chrome.109".
// - Неопределено - если нет клиентского приложения или информация запрашивается
// до первого серверного вызова, например, при первом вызове события
// платформы УстановкаПараметровСеанса в модуле сеанса.
//
Функция ИспользуемыйКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
Возврат СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИспользуемыйКлиент");
КонецФункции
// Возвращает Истина, если включен режим отладки.
//
// Возвращаемое значение:
// Булево - Истина, если включен режим отладки.
//
Функция РежимОтладки() Экспорт
ПараметрЗапускаПриложения = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере(Ложь).Получить("ПараметрЗапуска");
Возврат СтрНайти(ПараметрЗапускаПриложения, "РежимОтладки") > 0;
КонецФункции
// Возвращает объем оперативной памяти, доступной клиентскому приложению.
//
// Возвращаемое значение:
// Число - количество гигабайтов оперативной памяти с точностью до десятых долей.
// Неопределено - нет клиентского приложения, то есть ТекущийРежимЗапуска() = Неопределено.
//
Функция ОперативнаяПамятьДоступнаяКлиентскомуПриложению() Экспорт
ДоступныйОбъем = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ОперативнаяПамять");
Возврат ДоступныйОбъем;
КонецФункции
// Определяет режим эксплуатации информационной базы файловый (Истина) или серверный (Ложь).
// При проверке используется СтрокаСоединенияИнформационнойБазы, которую можно указать явно.
//
// Параметры:
// СтрокаСоединенияИнформационнойБазы - Строка - параметр используется, если
// нужно проверить строку соединения не текущей информационной базы.
//
// Возвращаемое значение:
// Булево - Истина, если файловая.
//
Функция ИнформационнаяБазаФайловая(Знач СтрокаСоединенияИнформационнойБазы = "") Экспорт
Если ПустаяСтрока(СтрокаСоединенияИнформационнойБазы) Тогда
Возврат СтандартныеПодсистемыПовтИсп.ИнформационнаяБазаФайловая();
КонецЕсли;
Возврат СтрНайти(ВРег(СтрокаСоединенияИнформационнойБазы), "FILE=") = 1;
КонецФункции
// Возвращает Истина, если эта информационная база подключена к 1С:Fresh.
//
// Возвращаемое значение:
// Булево - признак автономного рабочего места.
//
Функция ЭтоАвтономноеРабочееМесто() Экспорт
Если ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщийМодуль("ОбменДаннымиСервер");
Возврат МодульОбменДаннымиСервер.ЭтоАвтономноеРабочееМесто();
КонецЕсли;
Возврат Ложь;
КонецФункции
// Возвращает признак того, что информационная база является распределенной (РИБ).
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоРаспределеннаяИнформационнаяБаза() Экспорт
УстановитьПривилегированныйРежим(Истина);
Возврат СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ();
КонецФункции
// Определяет, что эта информационная база является подчиненным узлом
// распределенной информационной базы (РИБ).
//
// Возвращаемое значение:
// Булево - Истина, если эта информационная база является подчиненным узлом РИБ.
//
Функция ЭтоПодчиненныйУзелРИБ() Экспорт
УстановитьПривилегированныйРежим(Истина);
Возврат ПланыОбмена.ГлавныйУзел() <> Неопределено;
КонецФункции
// Определяет, что эта информационная база является подчиненным узлом
// распределенной информационной базы (РИБ) с фильтром.
//
// Возвращаемое значение:
// Булево - Истина, если эта информационная база является подчиненным узлом РИБ с фильтром.
//
Функция ЭтоПодчиненныйУзелРИБСФильтром() Экспорт
УстановитьПривилегированныйРежим(Истина);
Если ПланыОбмена.ГлавныйУзел() <> Неопределено
И ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщийМодуль("ОбменДаннымиСервер");
Если МодульОбменДаннымиСервер.НазначениеПланаОбмена(ПланыОбмена.ГлавныйУзел().Метаданные().Имя) = "РИБСФильтром" Тогда
Возврат Истина;
КонецЕсли;
КонецЕсли;
Возврат Ложь;
КонецФункции
// Возвращает Истина при необходимости обновления конфигурации информационной базы подчиненного узла РИБ.
// В главном узле всегда Ложь.
//
// Возвращаемое значение:
// Булево - Истина, если требуется.
//
Функция ТребуетсяОбновлениеКонфигурацииПодчиненногоУзлаРИБ() Экспорт
Возврат ЭтоПодчиненныйУзелРИБ() И КонфигурацияИзменена();
КонецФункции
// Возвращает признак работы в режиме разделения данных по областям
// (технически это признак условного разделения).
//
// Возвращает Ложь, если конфигурация не может работать в режиме разделения данных
// (не содержит общих реквизитов, предназначенных для разделения данных).
//
// Возвращаемое значение:
// Булево - Истина, если разделение включено,
// Ложь, если разделение выключено или не поддерживается.
//
Функция РазделениеВключено() Экспорт
Возврат СтандартныеПодсистемыПовтИсп.РазделениеВключено();
КонецФункции
// Возвращает признак возможности обращения к разделенным данным (которые входят в состав разделителей).
// Признак относится к сеансу, но может меняться во время работы сеанса, если разделение было включено
// в самом сеансе, поэтому проверку следует делать непосредственно перед обращением к разделенным данным.
//
// Возвращает Истина, если конфигурация не может работать в режиме разделения данных
// (не содержит общих реквизитов, предназначенных для разделения данных).
//
// Возвращаемое значение:
// Булево - Истина, если разделение не поддерживается, либо разделение выключено,
// либо разделение включено и разделители установлены.
// Ложь, если разделение включено и разделители не установлены.
//
Функция ДоступноИспользованиеРазделенныхДанных() Экспорт
Возврат СтандартныеПодсистемыПовтИсп.ДоступноИспользованиеРазделенныхДанных();
КонецФункции
// Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ
// для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию в сети Интернет.
// Например, если такой адрес включить в электронное письмо, то из письма одним нажатием
// можно перейти к форме объекта в самой программе.
//
// Возвращаемое значение:
// Строка - адрес информационной базы, как он задан в настройке "Адрес в Интернете" в панели администрирования
// (хранится в константе АдресПубликацииИнформационнойБазыВИнтернете).
// Например, "http://1c.com/database".
//
// Пример:
// ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта";
// возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта.
//
Функция АдресПубликацииИнформационнойБазыВИнтернете() Экспорт
УстановитьПривилегированныйРежим(Истина);
Результат = Константы.АдресПубликацииИнформационнойБазыВИнтернете.Получить();
Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда
Если ПустаяСтрока(Результат)
И ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность")
И ПодсистемаСуществует("ТехнологияСервиса.ВнешнийПрограммныйИнтерфейс") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
МодульПрограммныйИнтерфейсСервиса = ОбщийМодуль("ПрограммныйИнтерфейсСервиса");
РазделительСеанса = МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса();
Попытка
Результат = МодульПрограммныйИнтерфейсСервиса.СвойстваПриложения(РазделительСеанса).АдресПриложения;
Исключение
ЗаписьЖурналаРегистрации(НСтр("ru = 'Адрес публикации приложения'", КодОсновногоЯзыка()), // АПК:154 Не считаем ошибкой проблемы недоступности Менеджера сервиса.
УровеньЖурналаРегистрации.Предупреждение,,,
ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат "";
КонецПопытки;
Константы.АдресПубликацииИнформационнойБазыВИнтернете.Установить(Результат);
КонецЕсли;
Возврат Результат;
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ
// для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию локальной сети.
// Например, если такой адрес включить в электронное письмо, то из письма за одно нажатие
// можно перейти к форме объекта в самой программе.
//
// При работе в приложении в Интернете возвращает значение функции АдресПубликацииИнформационнойБазыВИнтернете.
//
// Возвращаемое значение:
// Строка - адрес информационной базы, как он задан в настройке "Локальный адрес" в панели администрирования
// (хранится в константе АдресПубликацииИнформационнойБазыВЛокальнойСети).
// Например, "http://localserver/base".
//
// Пример:
// ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта";
// возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта.
//
Функция АдресПубликацииИнформационнойБазыВЛокальнойСети() Экспорт
Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат АдресПубликацииИнформационнойБазыВИнтернете();
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
Возврат Константы.АдресПубликацииИнформационнойБазыВЛокальнойСети.Получить();
КонецФункции
// Формирует ссылку для входа в программу для указанного пользователя.
//
// Параметры:
// Пользователь - Строка - логин пользователя для входа в программу;
// Пароль - Строка - пароль пользователя для входа в программу;
// ВидПубликацииИБ - Строка - через какую публикацию пользователь входит в программу:
// "ВИнтернете" или "ВЛокальнойСети".
//
// Возвращаемое значение:
// Строка, Неопределено - адрес входа в программу или Неопределено, если адрес не настроен.
//
Функция АдресВходаВПрограмму(Пользователь, Пароль, ВидПубликацииИБ) Экспорт
Результат = "";
Если НРег(ВидПубликацииИБ) = НРег("ВИнтернете") Тогда
Результат = АдресПубликацииИнформационнойБазыВИнтернете();
ИначеЕсли НРег(ВидПубликацииИБ) = НРег("ВЛокальнойСети") Тогда
Результат = АдресПубликацииИнформационнойБазыВЛокальнойСети();
КонецЕсли;
Если ПустаяСтрока(Результат) Тогда
Возврат Неопределено;
КонецЕсли;
Если Не СтрЗаканчиваетсяНа(Результат, "/") Тогда
Результат = Результат + "/";
КонецЕсли;
Результат = Результат + "?n=" + КодироватьСтроку(Пользователь, СпособКодированияСтроки.КодировкаURL);
Если ЗначениеЗаполнено(Пароль) Тогда
Результат = Результат + "&p=" + КодироватьСтроку(Пароль, СпособКодированияСтроки.КодировкаURL);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает редакцию конфигурации.
// Редакцией принято называть две первые группы цифр полной версии конфигурации.
// Например, у версии "1.2.3.4" редакция "1.2".
//
// Возвращаемое значение:
// Строка - номер редакции конфигурации.
//
Функция РедакцияКонфигурации() Экспорт
Результат = "";
ВерсияКонфигурации = Метаданные.Версия;
Позиция = СтрНайти(ВерсияКонфигурации, ".");
Если Позиция > 0 Тогда
Результат = Лев(ВерсияКонфигурации, Позиция);
ВерсияКонфигурации = Сред(ВерсияКонфигурации, Позиция + 1);
Позиция = СтрНайти(ВерсияКонфигурации, ".");
Если Позиция > 0 Тогда
Результат = Результат + Лев(ВерсияКонфигурации, Позиция - 1);
Иначе
Результат = "";
КонецЕсли;
КонецЕсли;
Если ПустаяСтрока(Результат) Тогда
Результат = Метаданные.Версия;
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает общие параметры работы.
//
// Параметры:
// ВернутьЗакешированноеЗначение - Булево - служебный параметр.
//
// Возвращаемое значение:
// см. ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности.ОбщиеПараметры
//
Функция ОбщиеПараметрыБазовойФункциональности(ВернутьЗакешированноеЗначение = Истина) Экспорт
Если ВернутьЗакешированноеЗначение Тогда
Возврат СтандартныеПодсистемыПовтИсп.ОбщиеПараметрыБазовойФункциональности();
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("ИмяФормыПерсональныхНастроек", "");
Результат.Вставить("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", Истина);
Результат.Вставить("РекомендуемыйОбъемОперативнойПамяти", 4);
Результат.Вставить("МинимальнаяВерсияПлатформы", МинимальнаяВерсияПлатформы());
Результат.Вставить("РекомендуемаяВерсияПлатформы", Результат.МинимальнаяВерсияПлатформы);
Результат.Вставить("ВыводитьПолныйСтекПриОшибкеДлительнойОперации", Ложь);
Результат.Вставить("ОтключитьИдентификаторыОбъектовМетаданных", Ложь);
Результат.Вставить("ГруппироватьСтатусыИВажныеСообщенияГоризонтально", Ложь);
ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности(Результат);
Результат.МинимальнаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(Результат.МинимальнаяВерсияПлатформы);
Результат.РекомендуемаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(Результат.РекомендуемаяВерсияПлатформы);
УточнитьМинимальнуюВерсиюПлатформыИзСервиса(Результат);
СистемнаяИнформация = Новый СистемнаяИнформация;
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, Результат.МинимальнаяВерсияПлатформы) < 0
И ЭтоВерсияЗащищенногоПрограммногоКомплекса(СистемнаяИнформация.ВерсияПриложения) Тогда
Результат.МинимальнаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения;
Результат.РекомендуемаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения;
КонецЕсли;
Минимальная = Результат.МинимальнаяВерсияПлатформы;
Рекомендуемая = Результат.РекомендуемаяВерсияПлатформы;
Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда
ТекстСообщения = НСтр("ru = 'Указанные в %1 минимальная и рекомендуемая версии платформы не соответствуют следующим требованиям:
| - минимальная версия должна быть заполнена;
| - минимальная версия не должна быть меньше минимальной версии БСП (см. %2);
| - минимальная версия не должна быть меньше рекомендуемой версии.
|Минимальная версия: %3
|Минимальная версия БСП: %4
|Рекомендуемая версия: %5'",
КодОсновногоЯзыка());
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения,
"ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности",
"ОбщегоНазначения.МинимальнаяВерсияПлатформы",
Минимальная, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), Рекомендуемая);
ЗаписьЖурналаРегистрации(НСтр("ru = 'Базовая функциональность'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,,
ТекстСообщения);
КонецЕсли;
УточнитьВерсиюПлатформы(Результат);
// Обратная совместимость.
ИмяУстаревшегоСвойства = "МинимальноНеобходимаяВерсияПлатформы";
Результат.Вставить(ИмяУстаревшегоСвойства, Результат.МинимальнаяВерсияПлатформы);
ИмяУстаревшегоСвойства = "РаботаВПрограммеЗапрещена";
Результат.Вставить(ИмяУстаревшегоСвойства, Ложь);
Возврат Результат;
КонецФункции
// Возвращает описания всех библиотек конфигурации, включая
// описание самой конфигурации.
//
// Возвращаемое значение:
// Массив - структур со свойствами:
// * Имя - Строка - имя подсистемы, например, "СтандартныеПодсистемы".
// * ИдентификаторИнтернетПоддержки - Строка - уникальное имя программы в сервисах интернет-поддержки.
// * Версия - Строка - версия в формате из четырех цифр, например "2.3.3.1".
// * ЭтоКонфигурация - Булево - признак того, что данная подсистема является основной конфигурацией.
//
Функция ОписанияПодсистем() Экспорт
Результат = Новый Массив;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл
Параметры = Новый Структура;
Параметры.Вставить("Имя");
Параметры.Вставить("ИдентификаторИнтернетПоддержки");
Параметры.Вставить("Версия");
Параметры.Вставить("ЭтоКонфигурация");
ЗаполнитьЗначенияСвойств(Параметры, ОписаниеПодсистемы.Значение);
Результат.Добавить(Параметры);
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает идентификатор Интернет-поддержки основной конфигурации.
//
// Возвращаемое значение:
// Строка - уникальное имя программы в сервисах Интернет-поддержки.
//
Функция ИдентификаторИнтернетПоддержкиКонфигурации() Экспорт
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл
Если ОписаниеПодсистемы.Значение.ЭтоКонфигурация Тогда
Возврат ОписаниеПодсистемы.Значение.ИдентификаторИнтернетПоддержки;
КонецЕсли;
КонецЦикла;
Возврат "";
КонецФункции
#КонецОбласти
#Область Даты
#Область ФункцииДляРаботыСДатамиСУчетомЧасовогоПоясаСеанса
// Преобразует локальную дату к формату "YYYY-MM-DDThh:mm:ssTZD" согласно ISO 8601.
//
// Параметры:
// ЛокальнаяДата - Дата - дата в часовом поясе сеанса.
//
// Возвращаемое значение:
// Строка - представление даты.
//
Функция ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата) Экспорт
Смещение = СмещениеСтандартногоВремени(ЧасовойПоясСеанса());
Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата, Смещение);
КонецФункции
// Возвращает строковое представление интервала между переданными датами или
// относительно переданной даты и текущей даты сеанса.
//
// Параметры:
// ВремяНачала - Дата - начальная точка интервала.
// ВремяОкончания - Дата - конечная точка интервала. Если не задана, берется текущая дата сеанса.
//
// Возвращаемое значение:
// Строка - представление интервала времени. Пустая строка, если ВремяНачала больше ВремяОкончания.
//
Функция ИнтервалВремениСтрокой(Знач ВремяНачала, Знач ВремяОкончания = Неопределено) Экспорт
Если ВремяОкончания = Неопределено Тогда
ВремяОкончания = ТекущаяДатаСеанса();
КонецЕсли;
Если ВремяНачала > ВремяОкончания Тогда
Возврат "";
КонецЕсли;
ВеличинаИнтервала = ВремяОкончания - ВремяНачала;
ВеличинаИнтервалаВДнях = Цел(ВеличинаИнтервала/60/60/24);
Если ВеличинаИнтервалаВДнях > 365 Тогда
ОписаниеИнтервала = НСтр("ru = 'более года'");
ИначеЕсли ВеличинаИнтервалаВДнях > 31 Тогда
ОписаниеИнтервала = НСтр("ru = 'более месяца'");
ИначеЕсли ВеличинаИнтервалаВДнях >= 1 Тогда
ОписаниеИнтервала = Формат(ВеличинаИнтервалаВДнях, "ЧДЦ=0") + " "
+ ПользователиСлужебныйКлиентСервер.ПредметЦелогоЧисла(ВеличинаИнтервалаВДнях, "",
НСтр("ru = 'день,дня,дней,,,,,,0'"));
Иначе
ОписаниеИнтервала = НСтр("ru = 'менее одного дня'");
КонецЕсли;
Возврат ОписаниеИнтервала;
КонецФункции
#КонецОбласти
#Область ФункцииДляРаботыСНастройкойРабочейДаты
// Сохраняет настройку рабочей даты пользователя.
//
// Параметры:
// НоваяРабочаяДата - Дата - дата, которую необходимо установить в качестве рабочей даты пользователя.
// ИмяПользователя - Строка - имя пользователя, для которого устанавливается рабочая дата.
// Если не задано, то устанавливается для текущего пользователя.
//
Процедура УстановитьРабочуюДатуПользователя(НоваяРабочаяДата, ИмяПользователя = Неопределено) Экспорт
КлючОбъекта = ВРег("РабочаяДата");
ХранилищеОбщихНастроекСохранить(КлючОбъекта, "", НоваяРабочаяДата, , ИмяПользователя);
КонецПроцедуры
// Возвращает значение настройки рабочей даты для пользователя.
//
// Параметры:
// ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата.
// Если не задано, то устанавливается для текущего пользователя.
//
// Возвращаемое значение:
// Дата - значение настройки рабочей даты пользователя или пустая дата, если настройка не задана.
//
Функция РабочаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт
КлючОбъекта = ВРег("РабочаяДата");
Результат = ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, "", '0001-01-01', , ИмяПользователя);
Если ТипЗнч(Результат) <> Тип("Дата") Тогда
Результат = '0001-01-01';
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает значение настройки рабочей даты для пользователя или текущей даты сеанса,
// если рабочая дата пользователя не задана.
//
// Параметры:
// ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата.
// Если не задано, то устанавливается для текущего пользователя.
//
// Возвращаемое значение:
// Дата - значение настройки рабочей даты пользователя или текущая дата сеанса, если настройка не задана.
//
Функция ТекущаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт
Результат = РабочаяДатаПользователя(ИмяПользователя);
Если НЕ ЗначениеЗаполнено(Результат) Тогда
Результат = ТекущаяДатаСеанса();
КонецЕсли;
Возврат НачалоДня(Результат);
КонецФункции
#КонецОбласти
#КонецОбласти
#Область Данные
////////////////////////////////////////////////////////////////////////////////
// Общие процедуры и функции для работы с прикладными типами и коллекциями значений.
// Возвращает строковое имя значения перечисления по его ссылке.
// Вызывает исключение, если передано несуществующее значение перечисления
// (например, удаленное в конфигурации или от отключенного расширения конфигурации).
//
// Параметры:
// Значение - ПеречислениеСсылка - значение, для которого необходимо получить имя перечисления.
//
// Возвращаемое значение:
// Строка
//
// Пример:
// В результат будет помещено строковое значение "ФизическоеЛицо":
// Результат = ОбщегоНазначения.ИмяЗначенияПеречисления(Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо);
//
Функция ИмяЗначенияПеречисления(Значение) Экспорт
ОбъектМетаданных = Значение.Метаданные();
ИндексЗначения = Перечисления[ОбъектМетаданных.Имя].Индекс(Значение);
Возврат ОбъектМетаданных.ЗначенияПеречисления[ИндексЗначения].Имя;
КонецФункции
// Процедура удаляет из массива МассивРеквизитов элементы, соответствующие именам
// реквизитов объекта из массива МассивНепроверяемыхРеквизитов.
// Для использования в обработчиках события ОбработкаПроверкиЗаполнения.
//
// Параметры:
// МассивРеквизитов - Массив - коллекция имен реквизитов объекта.
// МассивНепроверяемыхРеквизитов - Массив - коллекция имен реквизитов объекта, не требующих проверки.
//
Процедура УдалитьНепроверяемыеРеквизитыИзМассива(МассивРеквизитов, МассивНепроверяемыхРеквизитов) Экспорт
Для Каждого ЭлементМассива Из МассивНепроверяемыхРеквизитов Цикл
ПорядковыйНомер = МассивРеквизитов.Найти(ЭлементМассива);
Если ПорядковыйНомер <> Неопределено Тогда
МассивРеквизитов.Удалить(ПорядковыйНомер);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Преобразует таблицу значений в массив структур.
// Может использоваться для передачи на клиент данных в том случае, если таблица
// значений содержит только такие значения, которые могут
// быть переданы с сервера на клиент.
//
// Полученный массив содержит структуры, каждая из которых повторяет
// структуру колонок таблицы значений.
//
// Не рекомендуется использовать для преобразования таблиц значений
// с большим количеством строк.
//
// Параметры:
// ТаблицаЗначений - ТаблицаЗначений - исходная таблица значений.
//
// Возвращаемое значение:
// Массив - коллекция строк таблицы в виде структур.
//
Функция ТаблицаЗначенийВМассив(ТаблицаЗначений) Экспорт
Массив = Новый Массив();
СтруктураСтрокой = "";
НужнаЗапятая = Ложь;
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
Если НужнаЗапятая Тогда
СтруктураСтрокой = СтруктураСтрокой + ",";
КонецЕсли;
СтруктураСтрокой = СтруктураСтрокой + Колонка.Имя;
НужнаЗапятая = Истина;
КонецЦикла;
Для Каждого СтрокаТаблицы Из ТаблицаЗначений Цикл
НоваяСтрока = Новый Структура(СтруктураСтрокой);
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТаблицы);
Массив.Добавить(НоваяСтрока);
КонецЦикла;
Возврат Массив;
КонецФункции
// Преобразует строку таблицы значений в структуру.
// Свойства структуры и их значения совпадают с колонками переданной строки.
//
// Параметры:
// СтрокаТаблицыЗначений - СтрокаТаблицыЗначений
//
// Возвращаемое значение:
// Структура - преобразованная строка таблицы значений.
//
Функция СтрокаТаблицыЗначенийВСтруктуру(СтрокаТаблицыЗначений) Экспорт
Структура = Новый Структура;
Для каждого Колонка Из СтрокаТаблицыЗначений.Владелец().Колонки Цикл
Структура.Вставить(Колонка.Имя, СтрокаТаблицыЗначений[Колонка.Имя]);
КонецЦикла;
Возврат Структура;
КонецФункции
// Создает структуру, содержащую имена и значения измерений, ресурсов и реквизитов
// переданного менеджера записи регистра сведений.
//
// Параметры:
// МенеджерЗаписи - РегистрСведенийМенеджерЗаписиИмяРегистраСведений - менеджер записи, из которого надо получить структуру.
// МетаданныеРегистра - ОбъектМетаданныхРегистрСведений - метаданные регистра сведений.
//
// Возвращаемое значение:
// Структура - коллекция измерений ресурсов и реквизитов, переданного менеджеру записи.
//
Функция СтруктураПоМенеджеруЗаписи(МенеджерЗаписи, МетаданныеРегистра) Экспорт
ЗаписьКакСтруктура = Новый Структура;
Если МетаданныеРегистра.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда
ЗаписьКакСтруктура.Вставить("Период", МенеджерЗаписи.Период);
КонецЕсли;
Для Каждого Поле Из МетаданныеРегистра.Измерения Цикл
ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]);
КонецЦикла;
Для Каждого Поле Из МетаданныеРегистра.Ресурсы Цикл
ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]);
КонецЦикла;
Для Каждого Поле Из МетаданныеРегистра.Реквизиты Цикл
ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]);
КонецЦикла;
Возврат ЗаписьКакСтруктура;
КонецФункции
// Создает массив и копирует в него значения, содержащиеся в колонке объекта, для
// которого доступен обход посредством оператора Для каждого … Из.
//
// Параметры:
// КоллекцияСтрок - ТаблицаЗначений
// - ДеревоЗначений
// - СписокЗначений
// - ТабличнаяЧасть
// - Соответствие
// - Структура - коллекция, колонку которой нужно выгрузить в массив.
// А так же другие объекты, для которых доступен обход
// посредством оператора Для каждого … Из … Цикл.
// ИмяКолонки - Строка - имя поля коллекции, значения которого нужно выгрузить.
// ТолькоУникальныеЗначения - Булево - если Истина, то в массив будут включены
// только различающиеся значения.
//
// Возвращаемое значение:
// Массив - значения колонки.
//
Функция ВыгрузитьКолонку(КоллекцияСтрок, ИмяКолонки, ТолькоУникальныеЗначения = Ложь) Экспорт
МассивЗначений = Новый Массив;
УникальныеЗначения = Новый Соответствие;
Для каждого СтрокаКоллекции Из КоллекцияСтрок Цикл
Значение = СтрокаКоллекции[ИмяКолонки];
Если ТолькоУникальныеЗначения И УникальныеЗначения[Значение] <> Неопределено Тогда
Продолжить;
КонецЕсли;
МассивЗначений.Добавить(Значение);
УникальныеЗначения.Вставить(Значение, Истина);
КонецЦикла;
Возврат МассивЗначений;
КонецФункции
// Преобразует текст указанного формата XML в таблицу значений,
// при этом колонки таблицы формируются на основе описания в XML.
//
// Схема XML:
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
// Параметры:
// XML - Строка
// - ЧтениеXML - текст в формате XML или ЧтениеXML.
//
// Возвращаемое значение:
// Структура:
// * ИмяТаблицы - Строка - имя таблицы.
// * Данные - ТаблицаЗначений - преобразованная из XML таблица.
//
// Пример:
// КлассификаторТаблица = ОбщегоНазначения.ПрочитатьXMLВТаблицу(
// Обработки.ЗагрузкаКурсовВалют.ПолучитьМакет("ОбщероссийскийКлассификаторВалют").ПолучитьТекст()).Данные;
//
Функция ПрочитатьXMLВТаблицу(Знач XML) Экспорт
Если ТипЗнч(XML) <> Тип("ЧтениеXML") Тогда
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(XML);
Иначе
Чтение = XML;
КонецЕсли;
// Прочитаем первый узел и проверим его.
Если Не Чтение.Прочитать() Тогда
ВызватьИсключение НСтр("ru = 'Не удалось загрузить данные из XML-файла, т.к. он пустой.'");
ИначеЕсли Чтение.Имя <> "Items" Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось загрузить данные из XML-файла: отсутствует обязательный тег %1.'"),
"Items");
КонецЕсли;
// Получим описание таблицы и создадим ее.
ИмяТаблицы = Чтение.ПолучитьАтрибут("Description");
ИменаКолонок = СтрЗаменить(Чтение.ПолучитьАтрибут("Columns"), ",", Символы.ПС);
Колонок = СтрЧислоСтрок(ИменаКолонок);
ТаблицаЗначений = Новый ТаблицаЗначений;
Для Сч = 1 По Колонок Цикл
ТаблицаЗначений.Колонки.Добавить(СтрПолучитьСтроку(ИменаКолонок, Сч), Новый ОписаниеТипов("Строка"));
КонецЦикла;
// Заполним значения в таблице.
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И Чтение.Имя = "Items" Тогда
Прервать;
ИначеЕсли Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
Продолжить;
ИначеЕсли Чтение.Имя <> "Item" Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось загрузить данные из XML-файла: в теге %1 отсутствует обязательный тег %2.'"),
"Items", "Item");
КонецЕсли;
новСтр = ТаблицаЗначений.Добавить();
Для Сч = 1 По Колонок Цикл
ИмяКолонки = СтрПолучитьСтроку(ИменаКолонок, Сч);
новСтр[Сч-1] = Чтение.ПолучитьАтрибут(ИмяКолонки);
КонецЦикла;
КонецЦикла;
// Заполним результат
Результат = Новый Структура;
Результат.Вставить("ИмяТаблицы", ИмяТаблицы);
Результат.Вставить("Данные", ТаблицаЗначений);
Возврат Результат;
КонецФункции
// Сравнивает две коллекции строк (ТаблицаЗначений, ДеревоЗначений и т.д.),
// для которых доступен обход посредством оператора Для каждого … Из … Цикл.
// Сравниваемые коллекции должны отвечать следующим требованиям:
// - доступен обход посредством оператора Для каждого … Из … Цикл,
// - наличие в обеих коллекциях всех колонок, перечисленных в параметре ИменаКолонок
// (если ИменаКолонок не заполнен - все колонки первой коллекции должны существовать во второй коллекции).
// Также позволяет сравнивать массивы.
// Для сравнения других коллекций, а также для сравнения коллекций с учетом вложенности см. функцию ДанныеСовпадают.
//
// Параметры:
// КоллекцияСтрок1 - ТаблицаЗначений
// - ДеревоЗначений
// - СписокЗначений
// - ТабличнаяЧасть
// - Соответствие
// - Массив
// - ФиксированныйМассив
// - Структура - коллекция, отвечающая вышеописанным требованиям. А также другие
// объекты, для которых доступен обход посредством оператора Для каждого … Из … Цикл.
// КоллекцияСтрок2 - ТаблицаЗначений
// - ДеревоЗначений
// - СписокЗначений
// - ТабличнаяЧасть
// - Соответствие
// - Массив
// - ФиксированныйМассив
// - Структура - коллекция, отвечающая вышеописанным требованиям. А также другие
// объекты, для которых доступен обход посредством оператора Для каждого … Из … Цикл.
// ИменаКолонок - Строка - имена колонок через запятую, по которым производится сравнение.
// Не обязательно для коллекций, состав колонок которых можно определить автоматически:
// ТаблицаЗначений, СписокЗначений, Соответствие, Структура.
// Если не указан, то сравнение производится по колонкам первой коллекции.
// Для коллекций других типов является обязательным.
// Следует также учитывать, что при сравнении коллекций, содержащих вместо строк другие типы
// элементов, в качестве имен колонок можно указывать только имена свойств этих элементов.
// Для соответствий и структур это "Ключ" и "Значение", но не значения ключей.
// Для списков значений это "Значение" и "Представление", но не сами значения.
//
// ИсключаяКолонки - Строка - имена колонок, которые игнорируются при сравнении.
// УчитыватьПоследовательностьСтрок - Булево - если Истина, то коллекции признаются
// идентичными, только если одинаковые строки размещены в коллекциях на одинаковых местах.
//
// Возвращаемое значение:
// Булево - Истина, если идентичны.
//
Функция КоллекцииИдентичны(КоллекцияСтрок1, КоллекцияСтрок2, Знач ИменаКолонок = "", Знач ИсключаяКолонки = "",
УчитыватьПоследовательностьСтрок = Ложь) Экспорт
ТипКоллекции = ТипЗнч(КоллекцияСтрок1);
СравниваютсяМассивы = (ТипКоллекции = Тип("Массив") Или ТипКоллекции = Тип("ФиксированныйМассив"));
СравниваемыеКолонки = Неопределено;
Если Не СравниваютсяМассивы Тогда
СравниваемыеКолонки = СравниваемыеКолонки(КоллекцияСтрок1, ИменаКолонок, ИсключаяКолонки);
КонецЕсли;
Если УчитыватьПоследовательностьСтрок Тогда
Возврат СравнитьСУчетомПоследовательности(КоллекцияСтрок1, КоллекцияСтрок2, СравниваемыеКолонки);
ИначеЕсли СравниваютсяМассивы Тогда // Для массивов используется более простой алгоритм.
Возврат СравнитьМассивы(КоллекцияСтрок1, КоллекцияСтрок2);
Иначе
Возврат СравнитьБезУчетаПоследовательности(КоллекцияСтрок1, КоллекцияСтрок2, СравниваемыеКолонки);
КонецЕсли;
КонецФункции
// Сравнивает данные сложной структуры с учетом вложенности.
//
// Параметры:
// Данные1 - Структура
// - ФиксированнаяСтруктура
// - Соответствие
// - ФиксированноеСоответствие
// - Массив
// - ФиксированныйМассив
// - ХранилищеЗначения
// - ТаблицаЗначений
// - Строка
// - Число
// - Булево - сравниваемые данные.
// Данные2 - Произвольный - те же типы, что и для параметра Данные1.
//
// Возвращаемое значение:
// Булево - Истина, если совпадают.
//
Функция ДанныеСовпадают(Данные1, Данные2) Экспорт
Если ТипЗнч(Данные1) <> ТипЗнч(Данные2) Тогда
Возврат Ложь;
КонецЕсли;
Если ТипЗнч(Данные1) = Тип("Структура")
ИЛИ ТипЗнч(Данные1) = Тип("ФиксированнаяСтруктура") Тогда
Если Данные1.Количество() <> Данные2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для каждого КлючИЗначение Из Данные1 Цикл
СтароеЗначение = Неопределено;
Если НЕ Данные2.Свойство(КлючИЗначение.Ключ, СтароеЗначение)
ИЛИ НЕ ДанныеСовпадают(КлючИЗначение.Значение, СтароеЗначение) Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
ИначеЕсли ТипЗнч(Данные1) = Тип("Соответствие")
ИЛИ ТипЗнч(Данные1) = Тип("ФиксированноеСоответствие") Тогда
Если Данные1.Количество() <> Данные2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
КлючиНовогоСоответствия = Новый Соответствие;
Для каждого КлючИЗначение Из Данные1 Цикл
КлючиНовогоСоответствия.Вставить(КлючИЗначение.Ключ, Истина);
СтароеЗначение = Данные2.Получить(КлючИЗначение.Ключ);
Если НЕ ДанныеСовпадают(КлючИЗначение.Значение, СтароеЗначение) Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Для каждого КлючИЗначение Из Данные2 Цикл
Если КлючиНовогоСоответствия[КлючИЗначение.Ключ] = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
ИначеЕсли ТипЗнч(Данные1) = Тип("Массив")
ИЛИ ТипЗнч(Данные1) = Тип("ФиксированныйМассив") Тогда
Если Данные1.Количество() <> Данные2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Индекс = Данные1.Количество()-1;
Пока Индекс >= 0 Цикл
Если НЕ ДанныеСовпадают(Данные1.Получить(Индекс), Данные2.Получить(Индекс)) Тогда
Возврат Ложь;
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
Возврат Истина;
ИначеЕсли ТипЗнч(Данные1) = Тип("ТаблицаЗначений") Тогда
Если Данные1.Количество() <> Данные2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Если Данные1.Колонки.Количество() <> Данные2.Колонки.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для каждого Колонка Из Данные1.Колонки Цикл
Если Данные2.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Индекс = Данные1.Количество()-1;
Пока Индекс >= 0 Цикл
Если НЕ ДанныеСовпадают(Данные1[Индекс][Колонка.Имя], Данные2[Индекс][Колонка.Имя]) Тогда
Возврат Ложь;
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
КонецЦикла;
Возврат Истина;
ИначеЕсли ТипЗнч(Данные1) = Тип("ХранилищеЗначения") Тогда
Если НЕ ДанныеСовпадают(Данные1.Получить(), Данные2.Получить()) Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецЕсли;
Возврат Данные1 = Данные2;
КонецФункции
// Фиксирует данные типов Структура, Соответствие, Массив с учетом вложенности.
//
// Параметры:
// Данные - Структура
// - Соответствие
// - Массив - коллекции, значения которых являются примитивными типами,
// хранилищем значения или не могут быть изменены. Поддерживаются типы значений:
// Булево, Строка, Число, Дата, Неопределено, УникальныйИдентификатор, Null, Тип,
// ХранилищеЗначения, ОбщийМодуль, ОбъектМетаданных, ТипЗначенияXDTO, ТипОбъектаXDTO,
// ЛюбаяСсылка.
//
// ВызыватьИсключение - Булево - начальное значение Истина. Когда установлено Ложь, тогда в случае наличия
// нефиксируемых данных исключение не будет вызвано, при этом данные будут
// зафиксированы на сколько возможно.
//
// Возвращаемое значение:
// ФиксированнаяСтруктура, ФиксированноеСоответствие, ФиксированныйМассив - фиксированные данные, аналогичные
// переданным в параметре Данные.
//
Функция ФиксированныеДанные(Данные, ВызыватьИсключение = Истина) Экспорт
Если ТипЗнч(Данные) = Тип("Массив") Тогда
Массив = Новый Массив;
Для каждого Значение Из Данные Цикл
Если ТипЗнч(Значение) = Тип("Структура")
ИЛИ ТипЗнч(Значение) = Тип("Соответствие")
ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда
Массив.Добавить(ФиксированныеДанные(Значение, ВызыватьИсключение));
Иначе
Если ВызыватьИсключение Тогда
ПроверкаФиксированностиДанных(Значение, Истина);
КонецЕсли;
Массив.Добавить(Значение);
КонецЕсли;
КонецЦикла;
Возврат Новый ФиксированныйМассив(Массив);
ИначеЕсли ТипЗнч(Данные) = Тип("Структура")
ИЛИ ТипЗнч(Данные) = Тип("Соответствие") Тогда
Если ТипЗнч(Данные) = Тип("Структура") Тогда
Коллекция = Новый Структура;
Иначе
Коллекция = Новый Соответствие;
КонецЕсли;
Для каждого КлючИЗначение Из Данные Цикл
Значение = КлючИЗначение.Значение;
Если ТипЗнч(Значение) = Тип("Структура")
ИЛИ ТипЗнч(Значение) = Тип("Соответствие")
ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда
Коллекция.Вставить(
КлючИЗначение.Ключ, ФиксированныеДанные(Значение, ВызыватьИсключение));
Иначе
Если ВызыватьИсключение Тогда
ПроверкаФиксированностиДанных(Значение, Истина);
КонецЕсли;
Коллекция.Вставить(КлючИЗначение.Ключ, Значение);
КонецЕсли;
КонецЦикла;
Если ТипЗнч(Данные) = Тип("Структура") Тогда
Возврат Новый ФиксированнаяСтруктура(Коллекция);
Иначе
Возврат Новый ФиксированноеСоответствие(Коллекция);
КонецЕсли;
ИначеЕсли ВызыватьИсключение Тогда
ПроверкаФиксированностиДанных(Данные);
КонецЕсли;
Возврат Данные;
КонецФункции
// Вычисляет контрольную сумму для произвольных данных по указанному алгоритму.
//
// Параметры:
// Данные - Произвольный - любое сериализуемое значение.
// Алгоритм - ХешФункция - алгоритм расчета контрольной суммы. По умолчанию, MD5.
//
// Возвращаемое значение:
// Строка - контрольная сумма строкой без пробелов (например 32 символа).
//
Функция КонтрольнаяСуммаСтрокой(Знач Данные, Знач Алгоритм = Неопределено) Экспорт
Если Алгоритм = Неопределено Тогда
Алгоритм = ХешФункция.MD5;
КонецЕсли;
ХешированиеДанных = Новый ХешированиеДанных(Алгоритм);
Если ТипЗнч(Данные) <> Тип("Строка") И ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Тогда
Данные = ЗначениеВСтрокуXML(Данные);
КонецЕсли;
ХешированиеДанных.Добавить(Данные);
Если ТипЗнч(ХешированиеДанных.ХешСумма) = Тип("ДвоичныеДанные") Тогда
Результат = СтрЗаменить(ХешированиеДанных.ХешСумма, " ", "");
ИначеЕсли ТипЗнч(ХешированиеДанных.ХешСумма) = Тип("Число") Тогда
Результат = Формат(ХешированиеДанных.ХешСумма, "ЧГ=");
КонецЕсли;
Возврат Результат;
КонецФункции
// Сокращает строку до нужной длины, при этом обрезанная часть хешируется,
// обеспечивая уникальность строки. Проверяет длину строки на входе и, в случае
// превышения максимальной длины, преобразует ее конец по алгоритму MD5 в
// уникальную строку из 32 символов.
//
// Параметры:
// Строка - Строка - исходная строка произвольной длины.
// МаксимальнаяДлина - Число - требуемое максимальное количество символов в строке,
// минимальное значение: 32.
//
// Возвращаемое значение:
// Строка - строка, не превышающая максимальную длину.
//
Функция СократитьСтрокуКонтрольнойСуммой(Строка, МаксимальнаяДлина) Экспорт
Если МаксимальнаяДлина < 32 Тогда
ОбщегоНазначенияКлиентСервер.Проверить(Ложь,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Параметр %1 не может быть меньше 32.'"),
"МаксимальнаяДлина"), "ОбщегоНазначения.СократитьСтрокуКонтрольнойСуммой");
КонецЕсли;
Результат = Строка;
Если СтрДлина(Строка) > МаксимальнаяДлина Тогда
Результат = Лев(Строка, МаксимальнаяДлина - 32);
ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5);
ХешированиеДанных.Добавить(Сред(Строка, МаксимальнаяДлина - 32 + 1));
Результат = Результат + СтрЗаменить(ХешированиеДанных.ХешСумма, " ", "");
КонецЕсли;
Возврат Результат;
КонецФункции
// Создает полную копию структуры, соответствия, массива, списка или таблицы значений, рекурсивно,
// с учетом типов дочерних элементов. При этом содержимое значений объектных типов
// (СправочникОбъект, ДокументОбъект и т.п.) не копируются, а возвращаются ссылки на исходный объект.
//
// Параметры:
// Источник - Структура
// - ФиксированнаяСтруктура
// - Соответствие
// - ФиксированноеСоответствие
// - Массив
// - ФиксированныйМассив
// - СписокЗначений - объект, который необходимо скопировать.
// ФиксироватьДанные - Булево - если Истина - фиксировать, если Ложь - снять фиксацию.
// - Неопределено - не изменять.
//
// Возвращаемое значение:
// - Структура
// - ФиксированнаяСтруктура
// - Соответствие
// - ФиксированноеСоответствие
// - Массив
// - ФиксированныйМассив
// - СписокЗначений - копия объекта, переданного в параметре Источник.
//
Функция СкопироватьРекурсивно(Источник, ФиксироватьДанные = Неопределено) Экспорт
Перем Приемник;
ТипИсточника = ТипЗнч(Источник);
Если ТипИсточника = Тип("ТаблицаЗначений") Тогда
Приемник = Источник.Скопировать();
СкопироватьЗначенияТаблицыЗначений(Приемник, ФиксироватьДанные);
ИначеЕсли ТипИсточника = Тип("ДеревоЗначений") Тогда
Приемник = Источник.Скопировать();
СкопироватьЗначенияСтрокиДереваЗначений(Приемник.Строки, ФиксироватьДанные);
ИначеЕсли ТипИсточника = Тип("Структура")
Или ТипИсточника = Тип("ФиксированнаяСтруктура") Тогда
Приемник = СкопироватьСтруктуру(Источник, ФиксироватьДанные);
ИначеЕсли ТипИсточника = Тип("Соответствие")
Или ТипИсточника = Тип("ФиксированноеСоответствие") Тогда
Приемник = СкопироватьСоответствие(Источник, ФиксироватьДанные);
ИначеЕсли ТипИсточника = Тип("Массив")
Или ТипИсточника = Тип("ФиксированныйМассив") Тогда
Приемник = СкопироватьМассив(Источник, ФиксироватьДанные);
ИначеЕсли ТипИсточника = Тип("СписокЗначений") Тогда
Приемник = СкопироватьСписокЗначений(Источник, ФиксироватьДанные);
Иначе
Приемник = Источник;
КонецЕсли;
Возврат Приемник;
КонецФункции
// Возвращает описание предмета в виде текстовой строки.
// Для документов возвращается представление, для остальных ссылочных типов возвращается
// представление и тип в скобках, например, "Ножницы (Номенклатура)".
// Для пустых ссылок, Неопределено или незаполненных значений примитивных типов возвращается "не задан".
//
// Параметры:
// СсылкаНаПредмет - Произвольный.
//
// Возвращаемое значение:
// Строка - например, "Ножницы (Номенклатура)", "Заказ клиента № 0001 от 01.01.2001" или "не задан".
//
Функция ПредметСтрокой(СсылкаНаПредмет) Экспорт
Если СсылкаНаПредмет <> Неопределено Тогда
Возврат ПредметыСтрокой(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СсылкаНаПредмет))[СсылкаНаПредмет];
Иначе
Возврат НСтр("ru = 'не задан'");
КонецЕсли;
КонецФункции
// Возвращает описания предметов СсылкиНаПредметы.
// Для документов возвращается представление, для остальных ссылочных типов возвращается
// представление и тип в скобках, например, "Ножницы (Номенклатура)".
// Для пустых ссылок или незаполненных значений примитивных типов возвращается "не задан".
// Значение "удален", если объект не существует в информационной базе.
// Значения Неопределено пропускаются.
//
// Параметры:
// СсылкиНаПредметы - Массив из ЛюбаяСсылка
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - ЛюбаяСсылка
// * Значение - Строка - например, "Ножницы (Номенклатура)", "Заказ клиента № 0001 от 01.01.2001" или "не задан".
//
Функция ПредметыСтрокой(Знач СсылкиНаПредметы) Экспорт
ПроверяемыеСсылки = Новый Массив;
Результат = Новый Соответствие;
Для каждого СсылкаНаПредмет Из СсылкиНаПредметы Цикл
Если СсылкаНаПредмет = Неопределено Тогда
Результат[СсылкаНаПредмет] = НСтр("ru = 'не задан'");
ИначеЕсли Не ЭтоСсылка(ТипЗнч(СсылкаНаПредмет)) Тогда
Результат[СсылкаНаПредмет] = Строка(СсылкаНаПредмет);
ИначеЕсли СсылкаНаПредмет.Пустая() Тогда
Результат[СсылкаНаПредмет] = НСтр("ru = 'не задан'");
ИначеЕсли Метаданные.Перечисления.Содержит(СсылкаНаПредмет.Метаданные()) Тогда
Результат[СсылкаНаПредмет] = Строка(СсылкаНаПредмет);
Иначе
ПроверяемыеСсылки.Добавить(СсылкаНаПредмет);
КонецЕсли;
КонецЦикла;
Для каждого СуществующаяСсылка Из ПредставленияСсылок(ПроверяемыеСсылки) Цикл
СсылкаНаПредмет = СуществующаяСсылка.Ключ;
Результат[СсылкаНаПредмет] = СуществующаяСсылка.Значение;
Если Не Метаданные.Документы.Содержит(СсылкаНаПредмет.Метаданные()) Тогда
ПредставлениеОбъекта = СсылкаНаПредмет.Метаданные().ПредставлениеОбъекта;
Если ПустаяСтрока(ПредставлениеОбъекта) Тогда
ПредставлениеОбъекта = СсылкаНаПредмет.Метаданные().Представление();
КонецЕсли;
Результат[СсылкаНаПредмет] = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 (%2)",
Результат[СсылкаНаПредмет], ПредставлениеОбъекта);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает представления переданных ссылок.
//
// Параметры:
// ПроверяемыеСсылки - Массив из ЛюбаяСсылка, ЛюбаяСсылка
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - ЛюбаяСсылка
// * Значение - Строка - представление ссылки или "удален", если ссылка не существует в информационной базе.
//
Функция ПредставленияСсылок(ПроверяемыеСсылки) Экспорт
ОбъектыПоТипу = Новый Соответствие;
Если ТипЗнч(ПроверяемыеСсылки) = Тип("Массив") Тогда
Для каждого ПроверяемаяСсылка Из ПроверяемыеСсылки Цикл
Объекты = ОбъектыПоТипу[ПроверяемаяСсылка.Метаданные()];
Если Объекты = Неопределено Тогда
Объекты = Новый Массив;
ОбъектыПоТипу[ПроверяемаяСсылка.Метаданные()] = Объекты;
КонецЕсли;
Объекты.Добавить(ПроверяемаяСсылка);
КонецЦикла;
Иначе
ОбъектыПоТипу[ПроверяемыеСсылки.Метаданные()] = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПроверяемыеСсылки);
КонецЕсли;
Результат = Новый Соответствие;
Если ОбъектыПоТипу.Количество() = 0 Тогда
Возврат Результат;
КонецЕсли;
Запрос = Новый Запрос;
ТекстыЗапросов = Новый Массив;
Индекс = 0;
Для каждого ТипОбъекта Из ОбъектыПоТипу Цикл
ТекстЗапроса =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Представление КАК Представление,
| Таблица.Ссылка КАК Ссылка
|ИЗ
| &ИмяТаблицы КАК Таблица
|ГДЕ
| Таблица.Ссылка В (&Ссылка)";
Если ТекстыЗапросов.Количество() > 0 Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВЫБРАТЬ РАЗРЕШЕННЫЕ", "ВЫБРАТЬ"); // @query-part-1, @query-part-2
КонецЕсли;
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ТипОбъекта.Ключ.ПолноеИмя());
ИмяПараметра = "Ссылка" + Формат(Индекс, "ЧГ=;ЧН=");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылка", "&" + ИмяПараметра);
ТекстыЗапросов.Добавить(ТекстЗапроса);
Запрос.УстановитьПараметр(ИмяПараметра, ТипОбъекта.Значение);
Индекс = Индекс + 1;
КонецЦикла;
Запрос.Текст = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); // @query-part;
УстановитьПривилегированныйРежим(Истина);
ФактическиеСсылки = Запрос.Выполнить().Выгрузить();
УстановитьПривилегированныйРежим(Ложь);
ПредставленияСсылок = Запрос.Выполнить().Выгрузить();
ПредставленияСсылок.Индексы.Добавить("Ссылка");
Для каждого Ссылка Из ФактическиеСсылки Цикл
Если ЗначениеЗаполнено(Ссылка.Ссылка) Тогда
ПредставлениеСсылки = ПредставленияСсылок.Найти(Ссылка.Ссылка, "Ссылка");
Результат[Ссылка.Ссылка] = ?(ПредставлениеСсылки <> Неопределено,
ПредставлениеСсылки.Представление, Строка(Ссылка.Ссылка));
КонецЕсли;
КонецЦикла;
Для каждого Ссылка Из ПроверяемыеСсылки Цикл
Если Результат[Ссылка] = Неопределено Тогда
Результат[Ссылка] = НСтр("ru = 'удален'");
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область ДинамическийСписок
// Создает структуру для второго параметра СвойстваСписка процедуры УстановитьСвойстваДинамическогоСписка.
//
// Возвращаемое значение:
// Структура - любое поле может иметь значение Неопределено, если оно не устанавливается:
// * ТекстЗапроса - Строка - новый текст запроса.
// * ОсновнаяТаблица - Строка - имя основной таблицы.
// * ДинамическоеСчитываниеДанных - Булево - признак использования динамического считывания.
//
Функция СтруктураСвойствДинамическогоСписка() Экспорт
Возврат Новый Структура("ТекстЗапроса, ОсновнаяТаблица, ДинамическоеСчитываниеДанных");
КонецФункции
// Установить текст запроса, основную таблицу или динамическое считывание в динамическом списке.
// Устанавливать эти свойства следует за один вызов этой процедуры, чтобы не снижалась производительность.
//
// Параметры:
// Список - ТаблицаФормы - элемент формы динамического списка, для которого устанавливаются свойства.
// СвойстваСписка - см. СтруктураСвойствДинамическогоСписка
//
Процедура УстановитьСвойстваДинамическогоСписка(Список, СвойстваСписка) Экспорт
Форма = Список.Родитель;
ТипФормаКлиентскогоПриложения = Тип("ФормаКлиентскогоПриложения");
Пока ТипЗнч(Форма) <> ТипФормаКлиентскогоПриложения Цикл
Форма = Форма.Родитель;
КонецЦикла;
ДинамическийСписок = Форма[Список.ПутьКДанным];
ТекстЗапроса = СвойстваСписка.ТекстЗапроса;
Если Не ПустаяСтрока(ТекстЗапроса) Тогда
ДинамическийСписок.ТекстЗапроса = ТекстЗапроса;
КонецЕсли;
ОсновнаяТаблица = СвойстваСписка.ОсновнаяТаблица;
Если ОсновнаяТаблица <> Неопределено Тогда
ДинамическийСписок.ОсновнаяТаблица = ОсновнаяТаблица;
КонецЕсли;
ДинамическоеСчитываниеДанных = СвойстваСписка.ДинамическоеСчитываниеДанных;
Если ТипЗнч(ДинамическоеСчитываниеДанных) = Тип("Булево") Тогда
ДинамическийСписок.ДинамическоеСчитываниеДанных = ДинамическоеСчитываниеДанных;
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область ВнешнееСоединение
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с внешним соединением.
// Возвращает CLSID COM-класса для работы с "1С:Предприятием 8" через COM-соединение.
//
// Параметры:
// ИмяCOMСоединителя - Строка - имя COM-класса для работы с "1С:Предприятием 8" через COM-соединение.
//
// Возвращаемое значение:
// Строка - строковое представление CLSID.
//
Функция ИдентификаторCOMСоединителя(Знач ИмяCOMСоединителя) Экспорт
Если ИмяCOMСоединителя = "v83.COMConnector" Тогда
Возврат "181E893D-73A4-4722-B61D-D604B3D67D47";
ИначеЕсли ИмяCOMСоединителя = "v85.COMConnector" Тогда
Возврат "BBAB44B3-6C80-43B1-AFEC-3094B12122BE";
КонецЕсли;
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение параметра %1 функции %2. Не задан CLSID для класса %3.'"),
"ИмяCOMСоединителя", "ОбщегоНазначения.ИдентификаторCOMСоединителя", ИмяCOMСоединителя),
КатегорияОшибки.ОшибкаКонфигурации);
КонецФункции
// Устанавливает внешнее соединение с информационной базой по переданным параметрам подключения и возвращает указатель
// на это соединение.
//
// Параметры:
// Параметры - см. ОбщегоНазначенияКлиентСервер.СтруктураПараметровДляУстановкиВнешнегоСоединения
//
// Возвращаемое значение:
// Структура:
// * Соединение - COMОбъект
// - Неопределено - COM-объект соединения или Неопределено в случае ошибки;
// * КраткоеОписаниеОшибки - Строка - краткое описание ошибки;
// * ПодробноеОписаниеОшибки - Строка - подробное описание ошибки;
// * ОшибкаПодключенияКомпоненты - Булево - флаг ошибки подключения COM.
//
Функция УстановитьВнешнееСоединениеСБазой(Параметры) Экспорт
ПодключениеНедоступно = ЭтоLinuxСервер();
КраткоеОписаниеОшибки = НСтр("ru = 'Прямое подключение к информационной базе недоступно на сервере под управлением ОС Linux.'");
Возврат ОбщегоНазначенияСлужебныйКлиентСервер.УстановитьВнешнееСоединениеСБазой(Параметры, ПодключениеНедоступно, КраткоеОписаниеОшибки);
КонецФункции
#КонецОбласти
#Область Метаданные
#Область ФункцииОпределенияТиповОбъектовМетаданных
// Ссылочные типы данных
// Определяет принадлежность объекта метаданных к общему типу "Документ".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к документам.
//
// Возвращаемое значение:
// Булево - Истина, если объект является документом.
//
Функция ЭтоДокумент(ОбъектМетаданных) Экспорт
Возврат Метаданные.Документы.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Справочник".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является справочником.
//
Функция ЭтоСправочник(ОбъектМетаданных) Экспорт
Возврат Метаданные.Справочники.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Перечисление".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является перечислением.
//
Функция ЭтоПеречисление(ОбъектМетаданных) Экспорт
Возврат Метаданные.Перечисления.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План обмена".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом обмена.
//
Функция ЭтоПланОбмена(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыОбмена.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План видов характеристик".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом видов характеристик.
//
Функция ЭтоПланВидовХарактеристик(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Бизнес-процесс".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является бизнес-процессом.
//
Функция ЭтоБизнесПроцесс(ОбъектМетаданных) Экспорт
Возврат Метаданные.БизнесПроцессы.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Задача".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является задачей.
//
Функция ЭтоЗадача(ОбъектМетаданных) Экспорт
Возврат Метаданные.Задачи.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План счетов".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом счетов.
//
Функция ЭтоПланСчетов(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План видов расчета".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом видов расчета.
//
Функция ЭтоПланВидовРасчета(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных);
КонецФункции
// Регистры
// Определяет принадлежность объекта метаданных к общему типу "Регистр сведений".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром сведений.
//
Функция ЭтоРегистрСведений(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Регистр накопления".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром накопления.
//
Функция ЭтоРегистрНакопления(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Регистр бухгалтерии".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром бухгалтерии.
//
Функция ЭтоРегистрБухгалтерии(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Регистр расчета".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром расчета.
//
Функция ЭтоРегистрРасчета(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных);
КонецФункции
// Константы
// Определяет принадлежность объекта метаданных к общему типу "Константа".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является константой.
//
Функция ЭтоКонстанта(ОбъектМетаданных) Экспорт
Возврат Метаданные.Константы.Содержит(ОбъектМетаданных);
КонецФункции
// Журналы документов
// Определяет принадлежность объекта метаданных к общему типу "Журнал документов".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является журналом документов.
//
Функция ЭтоЖурналДокументов(ОбъектМетаданных) Экспорт
Возврат Метаданные.ЖурналыДокументов.Содержит(ОбъектМетаданных);
КонецФункции
// Последовательности
// Определяет принадлежность объекта метаданных к общему типу "Последовательности".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является последовательностью.
//
Функция ЭтоПоследовательность(ОбъектМетаданных) Экспорт
Возврат Метаданные.Последовательности.Содержит(ОбъектМетаданных);
КонецФункции
// РегламентныеЗадания
// Определяет принадлежность объекта метаданных к общему типу "Регламентные задания".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регламентным заданием.
//
Функция ЭтоРегламентноеЗадание(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегламентныеЗадания.Содержит(ОбъектМетаданных);
КонецФункции
// Общие
// Определяет принадлежность объекта метаданных к типу регистр.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является каким-либо регистром.
//
Функция ЭтоРегистр(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных)
Или Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных)
Или Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных)
Или Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к ссылочному типу.
// Принадлежность определяется по базовому типу, то есть для формы справочника будет Истина,
// для формы регистра будет Ложь. Если объект метаданных не найден по типу, тогда будет Ложь.
//
// Параметры:
// ОписаниеОбъекта - ОбъектМетаданных, Тип
//
// Возвращаемое значение:
// Булево - Истина, если базовый тип объекта ссылочного типа.
//
Функция ЭтоОбъектСсылочногоТипа(ОписаниеОбъекта) Экспорт
Если ТипЗнч(ОписаниеОбъекта) = Тип("Тип") Тогда
ОбъектМетаданных = Метаданные.НайтиПоТипу(ОписаниеОбъекта);
Если ОбъектМетаданных = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Иначе
ОбъектМетаданных = ОписаниеОбъекта;
КонецЕсли;
ИмяВидаОбъектов = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".")[0];
ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов;
Свойства = ПоВидамОбъектов.Получить(ВРег(ИмяВидаОбъектов));
Если Свойства.ИмяКоллекции = "Перечисления" Тогда // Обратная совместимость.
Возврат Ложь;
КонецЕсли;
Возврат Свойства <> Неопределено И Свойства.ЕстьСсылка;
КонецФункции
#КонецОбласти
#Область ПроцедурыИФункцииДляРаботыСТипамиОбъектамиМетаданныхИИхСтроковымиПредставлениями
// Возвращает имена реквизитов объекта заданного типа.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - ссылка на элемент базы данных, для которого требуется получить результат функции;
// Тип - Тип - тип значения реквизита.
//
// Возвращаемое значение:
// Строка - строка реквизитов объекта метаданных конфигурации, разделенных символом ",".
//
// Пример:
// РеквизитыОрганизации = ОбщегоНазначения.ИменаРеквизитовПоТипу(Документ.Ссылка, Тип("СправочникСсылка.Организации"));
//
Функция ИменаРеквизитовПоТипу(Ссылка, Тип) Экспорт
Результат = "";
МетаданныеОбъекта = Ссылка.Метаданные();
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Если Реквизит.Тип.СодержитТип(Тип) Тогда
Результат = Результат + ?(ПустаяСтрока(Результат), "", ", ") + Реквизит.Имя;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает имя базового типа по началу полного имени объекта метаданных.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект метаданных, для которого необходимо определить базовый тип.
//
// Возвращаемое значение:
// Строка - имя базового типа указанного объекта метаданных, например,
// "ОбщиеМодули", ..., "Языки", ..., "Документы", ..., "РегистрыСведений", ...
// Для перерасчетов регистров расчета возвращается "Перерасчеты".
//
// Пример:
// ИмяБазовогоТипа = ОбщегоНазначения.ИмяБазовогоТипаПоОбъектуМетаданных(Метаданные.Справочники.Номенклатура);
//
Функция ИмяБазовогоТипаПоОбъектуМетаданных(ОбъектМетаданных) Экспорт
ЧастиИмени = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".");
ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов;
Свойства = ПоВидамОбъектов.Получить(ВРег(ЧастиИмени[0]));
Если Свойства = Неопределено Тогда
Возврат "";
КонецЕсли;
Если Свойства.ИмяВидаОбъекта = "РегистрРасчета"
И ЧастиИмени.Количество() = 4
И ВРег(ЧастиИмени[2]) = "ПЕРЕРАСЧЕТ" Тогда
Возврат "Перерасчеты";
КонецЕсли;
Возврат Свойства.ИмяКоллекции;
КонецФункции
// Возвращает менеджер объекта по началу полному имени объекта метаданных.
// Вызывает исключение при неверном начале полного имени или
// отсутствии объектов в конфигурации из начала полного имени,
// определяющего менеджер объекта.
// Например, для реквизитов или форм справочника используется только
// имя справочника и возвращается менеджер справочника,
// а для перерасчета используется имя регистра расчета, имя перерасчета и
// возвращается менеджер перерасчета.
//
// Параметры:
// ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Справочник.Организации".
//
// Возвращаемое значение:
// - ПланОбменаМенеджер
// - КритерийОтбораМенеджер
// - ХранилищеНастроекМенеджер
// - WSСсылкаМенеджер
// - СервисИнтеграцииМенеджер
// - КонстантаМенеджер
// - СправочникМенеджер
// - ДокументМенеджер
// - ПоследовательностьМенеджер
// - ЖурналДокументовМенеджер
// - ПеречислениеМенеджер
// - ОтчетМенеджер
// - ОбработкаМенеджер
// - ПланВидовХарактеристикМенеджер
// - ПланСчетовМенеджер
// - ПланВидовРасчетаМенеджер
// - РегистрСведенийМенеджер
// - РегистрНакопленияМенеджер
// - РегистрБухгалтерииМенеджер
// - РегистрРасчетаМенеджер
// - ПерерасчетМенеджер
// - БизнесПроцессМенеджер
// - ЗадачаМенеджер
// - ВнешнийИсточникДанныхМенеджер
// - ВнешнийИсточникДанныхТаблицаМенеджер
// - ВнешнийИсточникДанныхКубМенеджер
// - ВнешнийИсточникДанныхКубТаблицаИзмеренияМенеджер
//
// Пример:
// МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени("Справочник.Организации");
// ПустаяСсылка = МенеджерСправочника.ПустаяСсылка();
//
Функция МенеджерОбъектаПоПолномуИмени(ПолноеИмя) Экспорт
Возврат МенеджерОбъектаПоИмени(ПолноеИмя, Истина, Ложь, Ложь,
"ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени", "ПолноеИмя", Ложь);
КонецФункции
// Возвращает менеджер объекта по ссылке на объект.
// См. МенеджерОбъектаПоПолномуИмени.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - ссылка на объект, менеджер которого требуется получить.
//
// Возвращаемое значение:
// - ПланОбменаМенеджер
// - СправочникМенеджер
// - ДокументМенеджер
// - ПеречислениеМенеджер
// - ПланВидовХарактеристикМенеджер
// - ПланСчетовМенеджер
// - ПланВидовРасчетаМенеджер
// - БизнесПроцессМенеджер
// - ЗадачаМенеджер
//
// Пример:
// МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОрганизацию);
// ПустаяСсылка = МенеджерСправочника.ПустаяСсылка();
//
Функция МенеджерОбъектаПоСсылке(Ссылка) Экспорт
ЧастиИмени = СтрРазделить(Ссылка.Метаданные().ПолноеИмя(), ".");
ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов;
Свойства = ПоВидамОбъектов.Получить(ВРег(ЧастиИмени[0]));
Если Свойства <> Неопределено И Свойства.ЕстьСсылка Тогда
Возврат Свойства.Менеджер[ЧастиИмени[1]];
КонецЕсли;
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4.'"),
Ссылка, ТипЗнч(Ссылка), "Ссылка", "ОбщегоНазначения.МенеджерОбъектаПоСсылке");
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецФункции
// Проверка того, что переданный тип является ссылочным типом данных.
// Для типа Неопределено возвращается Ложь.
//
// Параметры:
// ПроверяемыйТип - Тип - для проверки на ссылочный тип данных.
//
// Возвращаемое значение:
// Булево - Истина, если это ссылка.
//
Функция ЭтоСсылка(ПроверяемыйТип) Экспорт
Возврат ПроверяемыйТип <> Тип("Неопределено") И ОписаниеТипаВсеСсылки().СодержитТип(ПроверяемыйТип);
КонецФункции
// Проверяет физическое наличие записи в информационной базе данных о переданном значении ссылки.
//
// Параметры:
// ПроверяемаяСсылка - ЛюбаяСсылка - значение любой ссылки информационной базы данных.
//
// Возвращаемое значение:
// Булево - Истина, если существует.
//
Функция СсылкаСуществует(ПроверяемаяСсылка) Экспорт
ТекстЗапроса =
"ВЫБРАТЬ ПЕРВЫЕ 1
| 1 КАК Поле1
|ИЗ
| &ИмяТаблицы КАК Таблица
|ГДЕ
| Таблица.Ссылка = &Ссылка";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИмяТаблицыПоСсылке(ПроверяемаяСсылка));
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Ссылка", ПроверяемаяСсылка);
УстановитьПривилегированныйРежим(Истина);
Возврат НЕ Запрос.Выполнить().Пустой();
КонецФункции
// Возвращает имя вида объектов метаданных по ссылке на объект.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
// См. так же ВидОбъектаПоТипу.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, вид которого требуется получить.
//
// Возвращаемое значение:
// Строка - имя вида объектов метаданных. Например: "Справочник", "Документ".
//
Функция ВидОбъектаПоСсылке(Ссылка) Экспорт
Возврат ВидОбъектаПоТипу(ТипЗнч(Ссылка));
КонецФункции
// Возвращает имя вида объектов метаданных по типу объекта.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
// См. так же ВидОбъектаПоСсылке.
//
// Параметры:
// ТипОбъекта - Тип - тип прикладного объекта, определенный в конфигурации.
//
// Возвращаемое значение:
// Строка - имя вида объектов метаданных. Например: "Справочник", "Документ".
//
Функция ВидОбъектаПоТипу(ТипОбъекта) Экспорт
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипОбъекта);
Если ОбъектМетаданных = Неопределено Тогда
ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ОбщегоНазначения.ВидОбъектаПоТипу",
"ТипОбъекта", ТипОбъекта, Тип("Тип"));
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объекта метаданных для указанного типа.'"),
ТипОбъекта, ТипЗнч(ТипОбъекта), "ТипОбъекта", "ОбщегоНазначения.ВидОбъектаПоТипу");
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ИмяВидаОбъектов = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".")[0];
ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов;
Свойства = ПоВидамОбъектов.Получить(ВРег(ИмяВидаОбъектов));
Если Свойства = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не определен вид объектов метаданных для указанного типа.'"),
ТипОбъекта, ТипЗнч(ТипОбъекта), "ТипОбъекта", "ОбщегоНазначения.ВидОбъектаПоТипу");
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
Возврат Свойства.ИмяВидаОбъекта;
КонецФункции
// Возвращает полное имя объекта метаданных по переданному значению ссылки.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, для которого необходимо получить имя таблицы ИБ.
//
// Возвращаемое значение:
// Строка - полное имя объекта метаданных для указанного объекта. Например: "Справочник.Номенклатура".
//
Функция ИмяТаблицыПоСсылке(Ссылка) Экспорт
Возврат Ссылка.Метаданные().ПолноеИмя();
КонецФункции
// Проверяет, что переданное значение имеет ссылочный тип данных.
//
// Параметры:
// Значение - Произвольный - проверяемое значение.
//
// Возвращаемое значение:
// Булево - Истина, если тип значения ссылочный.
//
Функция ЗначениеСсылочногоТипа(Значение) Экспорт
Возврат ЭтоСсылка(ТипЗнч(Значение));
КонецФункции
// Проверяет, является ли элемент справочника или плана видов характеристик группой элементов.
//
// Параметры:
// Объект - СправочникСсылка
// - ПланВидовХарактеристикСсылка
// - СправочникОбъект
// - ПланВидовХарактеристикОбъект - проверяемый объект.
//
// Возвращаемое значение:
// Булево
//
Функция ОбъектЯвляетсяГруппой(Объект) Экспорт
Если ЗначениеСсылочногоТипа(Объект) Тогда
Ссылка = Объект;
Иначе
Ссылка = Объект.Ссылка;
КонецЕсли;
МетаданныеОбъекта = Ссылка.Метаданные();
Если ЭтоСправочник(МетаданныеОбъекта) Тогда
Если Не МетаданныеОбъекта.Иерархический
Или МетаданныеОбъекта.ВидИерархии <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда
Возврат Ложь;
КонецЕсли;
ИначеЕсли Не ЭтоПланВидовХарактеристик(МетаданныеОбъекта) Или Не МетаданныеОбъекта.Иерархический Тогда
Возврат Ложь;
КонецЕсли;
Если Ссылка <> Объект Тогда
Возврат Объект.ЭтоГруппа;
КонецЕсли;
Возврат ЗначениеРеквизитаОбъекта(Ссылка, "ЭтоГруппа") = Истина;
КонецФункции
// Возвращает ссылку, соответствующую объекту метаданных, для использования в базе данных.
// См. также ОбщегоНазначения.ИдентификаторыОбъектовМетаданных.
//
// Ссылки возвращаются для следующих объектов метаданных:
// - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - ПланыОбмена;
// - Константы;
// - Справочники;
// - Документы;
// - ЖурналыДокументов;
// - Отчеты;
// - Обработки;
// - ПланыВидовХарактеристик;
// - ПланыСчетов;
// - ПланыВидовРасчета;
// - РегистрыСведений;
// - РегистрыНакопления;
// - РегистрыБухгалтерии;
// - РегистрыРасчета;
// - БизнесПроцессы;
// - Задачи.
//
// Параметры:
// ОписаниеОбъектаМетаданных - ОбъектМетаданных - объект метаданных конфигурации;
// - Тип - тип, который можно использовать в функции Метаданные.НайтиПоТипу;
// - Строка - полное имя объекта метаданных, которое можно
// использовать в функции Метаданные.НайтиПоПолномуИмени.
//
// ВызыватьИсключение - Булево - если Ложь, то вместо вызова исключения возвращается Null для несуществующего
// или неподдерживаемого объекта метаданных.
//
// Возвращаемое значение:
// - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений
// - Null
//
// Пример:
// Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ТипЗнч(Ссылка));
// Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных);
// Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.Организации");
//
Функция ИдентификаторОбъектаМетаданных(ОписаниеОбъектаМетаданных, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторОбъектаМетаданных(
ОписаниеОбъектаМетаданных, ВызыватьИсключение);
КонецФункции
// Возвращает ссылки, соответствующие объектам метаданных, для использования в базе данных.
// См. также ОбщегоНазначения.ИдентификаторОбъектаМетаданных.
//
// Ссылки возвращаются для следующих объектов метаданных:
// - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - ПланыОбмена.
// - Константы.
// - Справочники.
// - Документы.
// - ЖурналыДокументов.
// - Отчеты.
// - Обработки.
// - ПланыВидовХарактеристик.
// - ПланыСчетов.
// - ПланыВидовРасчета.
// - РегистрыСведений.
// - РегистрыНакопления.
// - РегистрыБухгалтерии.
// - РегистрыРасчета.
// - БизнесПроцессы.
// - Задачи.
//
// Параметры:
// ОписаниеОбъектовМетаданных - Массив из ОбъектМетаданных - объекты метаданных конфигурации;
// - Массив из Строка - полные имена объектов метаданных, которые можно использовать
// в функции Метаданные.НайтиПоПолномуИмени;
// - Массив из Тип - типы, которые можно использовать в функции Метаданные.НайтиПоТипу.
// ВызыватьИсключение - Булево - если Ложь, то несуществующие и неподдерживаемые объекты метаданных
// будут пропущены в возвращаемом значении.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - Строка - полное имя указанного объекта метаданных.
// * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - найденный идентификатор.
//
// Пример:
// ПолныеИмена = Новый Массив;
// ПолныеИмена.Добавить(Метаданные.Справочники.Валюты.ПолноеИмя());
// ПолныеИмена.Добавить(Метаданные.РегистрыСведений.КурсыВалют.ПолноеИмя());
// Идентификаторы = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена);
//
Функция ИдентификаторыОбъектовМетаданных(ОписаниеОбъектовМетаданных, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторыОбъектовМетаданных(
ОписаниеОбъектовМетаданных, ВызыватьИсключение);
КонецФункции
// Возвращает объект метаданных по переданному идентификатору.
//
// Параметры:
// Идентификатор - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор
// объекта метаданных конфигурации или расширения конфигурации.
//
// ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных
// не существует или недоступен, возвращает соответственно
// Null или Неопределено вместо вызова исключения.
//
// Возвращаемое значение:
// - ОбъектМетаданных - объект метаданных, соответствующий идентификатору.
//
// - Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что
// для указанного идентификатора объект метаданных не существует (идентификатор устарел).
//
// - Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает,
// что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен.
// Для расширений конфигурации это значит, что расширение установлено, но не подключено,
// либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка.
// Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект
// метаданных имеется, а в текущем (старом) сеансе нет.
//
Функция ОбъектМетаданныхПоИдентификатору(Идентификатор, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектМетаданныхПоИдентификатору(
Идентификатор, ВызыватьИсключение);
КонецФункции
// Возвращает объекты метаданных по переданным идентификаторам.
//
// Параметры:
// Идентификаторы - Массив - со значениями:
// * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификаторы
// объектов метаданных конфигурации или расширений конфигурации.
//
// ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных
// не существует или недоступен, возвращает соответственно
// Null или Неопределено вместо вызова исключения.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - переданный идентификатор.
// * Значение - ОбъектМетаданных - объект метаданных, соответствующий идентификатору.
// - Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что
// для указанного идентификатора объект метаданных не существует (идентификатор устарел).
// - Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает,
// что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен.
// Для расширений конфигурации это значит, что расширение установлено, но не подключено,
// либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка.
// Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект
// метаданных имеется, а в текущем (старом) сеансе нет.
//
Функция ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектыМетаданныхПоИдентификаторам(
Идентификаторы, ВызыватьИсключение);
КонецФункции
// Возвращает ОбъектМетаданных, быстро найденный по полному имени.
// Более производительный аналог метода платформы Метаданные.НайтиПоПолномуИмени
// для корневых объектов метаданных.
//
// Параметры:
// ПолноеИмя - Строка - полное имя объекта метаданных, например, Справочник.Организации
//
// Возвращаемое значение:
// - ОбъектМетаданных - когда найден
// - Неопределено - когда не найден
//
Функция ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) Экспорт
ПозицияТочки = СтрНайти(ПолноеИмя, ".");
ИмяВидаОбъектов = Лев(ПолноеИмя, ПозицияТочки - 1);
ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов;
Свойства = ПоВидамОбъектов.Получить(ВРег(ИмяВидаОбъектов));
Если Свойства <> Неопределено Тогда
Если Свойства.ИмяКоллекции <> "Подсистемы" Тогда
ИмяОбъекта = Сред(ПолноеИмя, ПозицияТочки + 1);
ОбъектМетаданных = Метаданные[Свойства.ИмяКоллекции].Найти(ИмяОбъекта);
Иначе
ИменаПодсистем = СтрРазделить(ВРег(ПолноеИмя), ".");
Количество = ИменаПодсистем.Количество();
Подсистема = Метаданные;
ОбъектМетаданных = Неопределено;
Индекс = 0;
Пока Истина Цикл
Индекс = Индекс + 1;
Если Индекс >= Количество Тогда
Прервать;
КонецЕсли;
ИмяПодсистемы = ИменаПодсистем[Индекс];
Подсистема = Подсистема.Подсистемы.Найти(ИмяПодсистемы);
Если Подсистема = Неопределено Тогда
Прервать;
КонецЕсли;
Индекс = Индекс + 1;
Если Индекс = Количество Тогда
ОбъектМетаданных = Подсистема;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если ОбъектМетаданных = Неопределено Тогда
ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмя);
КонецЕсли;
Возврат ОбъектМетаданных;
КонецФункции
// Определяет доступность объекта метаданных по функциональным опциям.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных
// - Строка - проверяемый объект метаданных.
//
// Возвращаемое значение:
// Булево - Истина, если объект доступен.
//
Функция ОбъектМетаданныхДоступенПоФункциональнымОпциям(Знач ОбъектМетаданных) Экспорт
Если ОбъектМетаданных = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Если ТипЗнч(ОбъектМетаданных) <> Тип("Строка") Тогда
ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
Иначе
ПолноеИмя = ОбъектМетаданных;
КонецЕсли;
Возврат СтандартныеПодсистемыПовтИсп.ДоступностьОбъектовПоОпциям().Получить(ПолноеИмя) <> Ложь;
КонецФункции
// Позволяет отразить переименование объекта метаданных при переходе на новую версию конфигурации.
// Для вызова в процедуре ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.
//
// Параметры:
// Переименования - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.Переименования
// ВерсияИБ - Строка - версия конечной конфигурации, при переходе на которую нужно
// выполнить переименование, например, "2.1.2.14".
// СтароеПолноеИмя - Строка - старое полное имя объекта метаданных, которое нужно переименовать,
// например "Подсистема.СлужебныеПодсистемы".
// НовоеПолноеИмя - Строка - новое полное имя объекта метаданных, на которое нужно переименовать,
// например "Подсистема.СервисныеПодсистемы".
// ИдентификаторБиблиотеки - Строка - внутренний идентификатор библиотеки, к которой относится ВерсияИБ.
// Для основной конфигурации не требуется.
// Например, "СтандартныеПодсистемы" - как указано
// в ОбновлениеИнформационнойБазыБСП.ПриДобавленииПодсистемы.
// Пример:
// ОбщегоНазначения.ДобавитьПереименование(Переименования, "2.1.2.14",
// "Подсистема.СлужебныеПодсистемы",
// "Подсистема.СервисныеПодсистемы");
//
Процедура ДобавитьПереименование(Переименования, ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя,
ИдентификаторБиблиотеки = "") Экспорт
Справочники.ИдентификаторыОбъектовМетаданных.ДобавитьПереименование(Переименования,
ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки);
КонецПроцедуры
// Возвращает строковое представление типа, например, "СправочникСсылка.ИмяОбъекта", "Форма клиентского приложения".
// Тип приводится к строке напрямую, кроме простых типов, ссылочных типов,
// типов ключа записи регистров, типов объекта и типов набора записей.
//
// Параметры:
// Тип - Тип - для которого надо получить представление.
//
// Возвращаемое значение:
// Строка - "СправочникСсылка.ИмяОбъекта", "РегистрСведенийКлючЗаписи.ИмяОбъекта",
// "СправочникОбъект.ИмяОбъекта", "РегистрСведенийНаборЗаписей.ИмяОбъекта", ...
//
Функция СтроковоеПредставлениеТипа(Тип) Экспорт
ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
Если ОбъектМетаданных <> Неопределено Тогда
ЧастиИмени = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".");
ПоВидамОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных().ПоВидамОбъектов;
Свойства = ПоВидамОбъектов.Получить(ВРег(ЧастиИмени[0]));
Если Свойства <> Неопределено Тогда
Если Свойства.ИмяВидаОбъекта = "БизнесПроцесс"
И БизнесПроцессы.ТипВсеСсылкиТочекМаршрутаБизнесПроцессов().СодержитТип(Тип) Тогда
ИмяТипа = "ТочкаМаршрутаБизнесПроцессаСсылка";
ИначеЕсли Свойства.ЕстьСсылка Тогда
ИмяТипа = Свойства.ИмяТипаСсылки;
ИначеЕсли Свойства.ЕстьКлючЗаписи Тогда
ИмяТипа = Свойства.ИмяТипаКлючаЗаписи;
КонецЕсли;
Если ЗначениеЗаполнено(ИмяТипа) Тогда
Результат = ИмяТипа + "." + ЧастиИмени[1];
Если Тип(Результат) = Тип Тогда
Возврат Результат;
КонецЕсли;
КонецЕсли;
ИмяТипа = Неопределено;
Если ЗначениеЗаполнено(Свойства.ИмяТипаОбъекта) Тогда
ИмяТипа = Свойства.ИмяТипаОбъекта;
ИначеЕсли ЗначениеЗаполнено(Свойства.ИмяТипаНабораЗаписей) Тогда
ИмяТипа = Свойства.ИмяТипаНабораЗаписей;
КонецЕсли;
Если ЗначениеЗаполнено(ИмяТипа) Тогда
Результат = ИмяТипа + "." + ЧастиИмени[1];
Если Тип(Результат) = Тип Тогда
Возврат Результат;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если Тип = Тип("Неопределено") Тогда
Результат = "Неопределено";
ИначеЕсли Тип = Тип("Строка") Тогда
Результат = "Строка";
ИначеЕсли Тип = Тип("Число") Тогда
Результат = "Число";
ИначеЕсли Тип = Тип("Булево") Тогда
Результат = "Булево";
ИначеЕсли Тип = Тип("Дата") Тогда
Результат = "Дата";
Иначе
Результат = Строка(Тип);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает таблицу значений с описанием требуемых свойств всех реквизитов объекта метаданных.
// Получает значения свойств стандартных реквизитов и пользовательских реквизитов (созданных в режиме конфигуратора).
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо получить значение свойств реквизитов.
// Например: Метаданные.Документ.РеализацияТоваровИУслуг
// Свойства - Строка - свойства реквизитов, перечисленные через запятую, значение которых необходимо получить.
// Например: "Имя, Тип, Синоним, Подсказка".
//
// Возвращаемое значение:
// ТаблицаЗначений - описание требуемых свойств всех реквизитов объекта метаданных.
//
Функция ОписаниеСвойствОбъекта(ОбъектМетаданных, Свойства) Экспорт
МассивСвойств = СтрРазделить(Свойства, ",");
// Возвращаемое значение функции.
ТаблицаОписанияСвойствОбъекта = Новый ТаблицаЗначений;
// Добавляем в таблицу поля согласно именам переданных свойств.
Для Каждого ИмяСвойства Из МассивСвойств Цикл
ТаблицаОписанияСвойствОбъекта.Колонки.Добавить(СокрЛП(ИмяСвойства));
КонецЦикла;
// Заполняем строку таблицы свойствами реквизитов объекта метаданных.
Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл
ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит);
КонецЦикла;
// Заполняем строку таблицы свойствами стандартных реквизитов объекта метаданных.
Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит);
КонецЦикла;
Возврат ТаблицаОписанияСвойствОбъекта;
КонецФункции
// Возвращает признак того, что реквизит входит в подмножество стандартных реквизитов.
//
// Параметры:
// СтандартныеРеквизиты - ОписанияСтандартныхРеквизитов - тип и значение, описывающие коллекцию настроек различных
// стандартных реквизитов;
// ИмяРеквизита - Строка - реквизит, который необходимо проверить на принадлежность множеству стандартных
// реквизитов.
//
// Возвращаемое значение:
// Булево - Истина, если реквизит входит в подмножество стандартных реквизитов.
//
Функция ЭтоСтандартныйРеквизит(СтандартныеРеквизиты, ИмяРеквизита) Экспорт
Для Каждого Реквизит Из СтандартныеРеквизиты Цикл
Если Реквизит.Имя = ИмяРеквизита Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Позволяет определить, есть ли среди реквизитов объекта реквизит с переданным именем.
//
// Параметры:
// ИмяРеквизита - Строка - имя реквизита;
// МетаданныеОбъекта - ОбъектМетаданных - объект, в котором требуется проверить наличие реквизита.
//
// Возвращаемое значение:
// Булево - Истина, если есть.
//
Функция ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта) Экспорт
Реквизиты = МетаданныеОбъекта.Реквизиты; // КоллекцияОбъектовМетаданных
Возврат НЕ (Реквизиты.Найти(ИмяРеквизита) = Неопределено);
КонецФункции
// Проверить, что описание типа состоит из единственного типа значения и
// совпадает с нужным типом.
//
// Параметры:
// ОписаниеТипа - ОписаниеТипов - проверяемая коллекция типов;
// ТипЗначения - Тип - проверяемый тип.
//
// Возвращаемое значение:
// Булево - Истина, если совпадает.
//
// Пример:
// Если ОбщегоНазначения.ОписаниеТипаСостоитИзТипа(ТипЗначенияСвойства, Тип("Булево") Тогда
// // Выводим поле в виде флажка.
// КонецЕсли;
//
Функция ОписаниеТипаСостоитИзТипа(ОписаниеТипа, ТипЗначения) Экспорт
Если ОписаниеТипа.Типы().Количество() = 1
И ОписаниеТипа.Типы().Получить(0) = ТипЗначения Тогда
Возврат Истина;
КонецЕсли;
Возврат Ложь;
КонецФункции
// Создает объект ОписаниеТипов, содержащий тип Строка.
//
// Параметры:
// ДлинаСтроки - Число - длина строки.
//
// Возвращаемое значение:
// ОписаниеТипов - описание типа Строка.
//
Функция ОписаниеТипаСтрока(ДлинаСтроки) Экспорт
Возврат Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(ДлинаСтроки));
КонецФункции
// Создает объект ОписаниеТипов, содержащий тип Число.
//
// Параметры:
// Разрядность - Число - общее количество разрядов числа (количество разрядов
// целой части плюс количество разрядов дробной части).
// РазрядностьДробнойЧасти - Число - число разрядов дробной части.
// ЗнакЧисла - ДопустимыйЗнак - допустимый знак числа.
//
// Возвращаемое значение:
// ОписаниеТипов - описание типа Число.
//
Функция ОписаниеТипаЧисло(Разрядность, РазрядностьДробнойЧасти = 0, Знач ЗнакЧисла = Неопределено) Экспорт
Если ЗнакЧисла = Неопределено Тогда
ЗнакЧисла = ДопустимыйЗнак.Любой;
КонецЕсли;
Возврат Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(Разрядность, РазрядностьДробнойЧасти, ЗнакЧисла));
КонецФункции
// Создает объект ОписаниеТипов, содержащий тип Дата.
//
// Параметры:
// ЧастиДаты - ЧастиДаты - набор вариантов использования значений типа Дата.
//
// Возвращаемое значение:
// ОписаниеТипов - описание типа Дата.
//
Функция ОписаниеТипаДата(ЧастиДаты) Экспорт
Возврат Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты));
КонецФункции
// Возвращает описание типа, включающего в себя все возможные ссылочные типы конфигурации.
//
// Возвращаемое значение:
// ОписаниеТипов - все ссылочные типы конфигурации.
//
Функция ОписаниеТипаВсеСсылки() Экспорт
Возврат СтандартныеПодсистемыПовтИсп.ОписаниеТипаВсеСсылки();
КонецФункции
// Возвращает строковое представление списка, заданное в свойствах объекта метаданных.
// В зависимости от того, какие свойства объекта метаданных заполнены, функция возвращают одно из них в указанном
// порядке: Расширенное представление списка, Представление списка, Синоним или Имя.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - произвольный объект.
//
// Возвращаемое значение:
// Строка - представление списка.
//
Функция ПредставлениеСписка(ОбъектМетаданных) Экспорт
СвойстваОбъекта = Новый Структура("РасширенноеПредставлениеСписка,ПредставлениеСписка");
ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных);
Если ЗначениеЗаполнено(СвойстваОбъекта.РасширенноеПредставлениеСписка) Тогда
Результат = СвойстваОбъекта.РасширенноеПредставлениеСписка;
ИначеЕсли ЗначениеЗаполнено(СвойстваОбъекта.ПредставлениеСписка) Тогда
Результат = СвойстваОбъекта.ПредставлениеСписка;
Иначе
Результат = ОбъектМетаданных.Представление();
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает строковое представление объекта, заданное в свойствах объекта метаданных.
// В зависимости от того, какие свойства объекта метаданных заполнены, функция возвращают одно из них в указанном
// порядке: Расширенное представление объекта, Представление объекта, Синоним или Имя.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - произвольный объект.
//
// Возвращаемое значение:
// Строка - представление объекта.
//
Функция ПредставлениеОбъекта(ОбъектМетаданных) Экспорт
СвойстваОбъекта = Новый Структура("РасширенноеПредставлениеОбъекта,ПредставлениеОбъекта");
ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных);
Если ЗначениеЗаполнено(СвойстваОбъекта.РасширенноеПредставлениеОбъекта) Тогда
Результат = СвойстваОбъекта.РасширенноеПредставлениеОбъекта;
ИначеЕсли ЗначениеЗаполнено(СвойстваОбъекта.ПредставлениеОбъекта) Тогда
Результат = СвойстваОбъекта.ПредставлениеОбъекта;
Иначе
Результат = ОбъектМетаданных.Представление();
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает условие отбора и параметры запроса для выбора записей из базы данных
// по указанному набору записей с учетом режима замещения.
//
// Если Замещение равно Истина или РежимЗамещения.Замещение, тогда
// записи будут извлекаться из базы данных по настройке свойства Отбор,
// в противном случае по ключам строк записей в наборе записей.
//
// Параметры:
// НаборЗаписей - РегистрСведенийНаборЗаписей
// - РегистрНакопленияНаборЗаписей
// - РегистрБухгалтерииНаборЗаписей
// - РегистрРасчетаНаборЗаписей - набор записей, который используется
// для подготовки условия и параметров для запроса.
// - Отбор - отбор набора записей (в этом случае Замещение считается Истина).
//
// Замещение - РежимЗамещения, Булево - как передается в подписку на событие ПередЗаписью.
// - Неопределено - получить и установить в этот параметр значение из свойства
// Замещение структуры ДополнительныеСвойства указанного набора записей
// (если свойства нет, тогда устанавливается Истина).
//
// Запрос - Запрос - установить параметры в указанный запрос и заменить на возвращаемое
// УсловиеЗапроса строку "&УсловиеОтбора" в тексте запроса, если есть.
// - Неопределено
//
// ДополнительныеПараметры - см. НовыеПараметрыОтбораЗаписейНабораИзБазыДанных
//
// Возвращаемое значение:
// Структура:
// * УсловиеЗапроса - Строка - условие для подстановки в текст запроса.
// * ПараметрыЗапроса - Структура из КлючИЗначение:
// ** Ключ - Строка - имя поля отбора или ЗначенияПолейОтбораСтрок с указанным префиксом.
// ** Значение - Произвольный - значение поля отбора или таблица значений.
//
// Пример:
// Запрос = Новый Запрос;
// Запрос.Текст =
// "ВЫБРАТЬ РАЗЛИЧНЫЕ
// | ТекущаяТаблица.Пользователь КАК Пользователь,
// | ТекущаяТаблица.ПотребоватьСменуПароляПриВходе КАК ПотребоватьСменуПароляПриВходе,
// | ТекущаяТаблица.СрокДействияНеОграничен КАК СрокДействияНеОграничен,
// | ТекущаяТаблица.СрокДействия КАК СрокДействия,
// | ТекущаяТаблица.ПросрочкаРаботыВПрограммеДоЗапрещенияВхода КАК ПросрочкаРаботыВПрограммеДоЗапрещенияВхода
// |ИЗ
// | РегистрСведений.СведенияОПользователях КАК ТекущаяТаблица
// |ГДЕ
// | &УсловиеОтбора";
// ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение, Запрос);
// СуществующиеЗаписи = Запрос.Выполнить().Выгрузить();
//
Функция ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение = Неопределено, Запрос = Неопределено,
ДополнительныеПараметры = Неопределено) Экспорт
Параметры = ?(ДополнительныеПараметры <> Неопределено, ДополнительныеПараметры,
НовыеПараметрыОтбораЗаписейНабораИзБазыДанных());
Режим = Новый Структура("Замещение", Истина);
Если ТипЗнч(НаборЗаписей) = Тип("Отбор") Или ТипЗнч(НаборЗаписей) = Тип("Массив") Тогда
Отбор = НаборЗаписей;
Иначе
Отбор = НаборЗаписей.Отбор;
Если Замещение = Неопределено Тогда
ЗаполнитьЗначенияСвойств(Режим, НаборЗаписей.ДополнительныеСвойства);
ИмяПараметра = "НаборЗаписей.ДополнительныеСвойства.Замещение";
Иначе
Режим.Замещение = Замещение;
ИмяПараметра = "Замещение";
КонецЕсли;
Если ТипЗнч(Режим.Замещение) <> Тип("Булево")
И Не ЭтоДобавлениеНабораЗаписей(Режим.Замещение)
И Не ЭтоЗамещениеНабораЗаписей(Режим.Замещение)
И Не ЭтоОбновлениеНабораЗаписей(Режим.Замещение)
И Не ЭтоСлияниеНабораЗаписей(Режим.Замещение)
И Не ЭтоУдалениеНабораЗаписей(Режим.Замещение) Тогда
ОжидаемыеТипы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Тип("Булево"));
Если СтандартныеПодсистемыПовтИсп.РежимДобавленияНабораЗаписей() <> Неопределено Тогда
ОжидаемыеТипы.Добавить(СтандартныеПодсистемыПовтИсп.ТипРежимЗамещения());
КонецЕсли;
ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ОбщегоНазначения.ОтборЗаписейНабораИзБазыДанных",
ИмяПараметра, Режим.Замещение, ОжидаемыеТипы);
КонецЕсли;
КонецЕсли;
Если Замещение = Неопределено Тогда
Замещение = Режим.Замещение;
КонецЕсли;
ПараметрыЗапроса = Новый Структура;
Условие = "ЛОЖЬ";
Псевдоним = Параметры.ПсевдонимТаблицы;
Если ЭтоОбновлениеНабораЗаписей(Режим.Замещение)
Или ЭтоСлияниеНабораЗаписей(Режим.Замещение)
Или ЭтоУдалениеНабораЗаписей(Режим.Замещение) Тогда
ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(
НаборЗаписей.Метаданные().ПолноеИмя());
СписокПолей = ОписаниеКлючаЗаписи.СписокПолейОбновления;
Если ЗначениеЗаполнено(СписокПолей) Тогда
ИмяПараметраТаблицы = Параметры.ИмяПараметраТаблицыКлючевыхПолей;
Выгрузка = НаборЗаписей.Выгрузить(, СписокПолей);
ПараметрыЗапроса.Вставить(ИмяПараметраТаблицы, Выгрузка);
Если Запрос <> Неопределено Тогда
Запрос.УстановитьПараметр(ИмяПараметраТаблицы, Выгрузка);
КонецЕсли;
Условие = СтрШаблон("(%1) В (&" + ИмяПараметраТаблицы + ")",
Псевдоним + СтрЗаменить(СписокПолей, ",", ", " + Псевдоним)); // @query-part-1
Иначе
Условие = "ИСТИНА";
КонецЕсли;
ИначеЕсли Режим.Замещение = Истина
Или ЭтоЗамещениеНабораЗаписей(Режим.Замещение) Тогда
ЧастиУсловия = Новый Массив;
Префикс = Параметры.ПрефиксИменПолейВПараметрах;
Шаблон = Псевдоним + "%1 = &" + Префикс + "%1"; // @query-part-1
Для Каждого ЭлементОтбора Из Отбор Цикл
Если Не ЭлементОтбора.Использование Тогда
Продолжить;
КонецЕсли;
ЧастиУсловия.Добавить(СтрШаблон(Шаблон, ЭлементОтбора.Имя));
ПараметрыЗапроса.Вставить(Префикс + ЭлементОтбора.Имя, ЭлементОтбора.Значение);
Если Запрос <> Неопределено Тогда
Запрос.УстановитьПараметр(Префикс + ЭлементОтбора.Имя, ЭлементОтбора.Значение);
КонецЕсли;
КонецЦикла;
Условие = ?(Не ЗначениеЗаполнено(ЧастиУсловия), "ИСТИНА",
СтрСоединить(ЧастиУсловия, Символы.ПС + " И "));
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("УсловиеЗапроса", Условие);
Результат.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
Если Запрос <> Неопределено Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеОтбора", Условие);
КонецЕсли;
Возврат Результат;
КонецФункции
// Дополнительные параметры для функции ОтборЗаписейНабораИзБазыДанных.
//
// Возвращаемое значение:
// Структура:
// * ПсевдонимТаблицы - Строка - префикс, добавляемый к именам полей
// (начальное значение "ТекущаяТаблица.").
//
// * ПрефиксИменПолейВПараметрах - Строка - префикс, добавляемый к именам
// полей отбора в условии и параметрах запроса (начальное значение без префикса).
//
// * ИмяПараметраТаблицыКлючевыхПолей - Строка - начальное значение ЗначенияПолейОтбораСтрок.
//
Функция НовыеПараметрыОтбораЗаписейНабораИзБазыДанных() Экспорт
Результат = Новый Структура;
Результат.Вставить("ПсевдонимТаблицы", "ТекущаяТаблица.");
Результат.Вставить("ПрефиксИменПолейВПараметрах", "");
Результат.Вставить("ИмяПараметраТаблицыКлючевыхПолей", "ЗначенияПолейОтбораСтрок");
Возврат Результат;
КонецФункции
// Возвращает указанные поля строк регистра из базы данных, которые будут
// записаны при записи указанного набора записей с учетом режима замещения.
//
// Параметры:
// НаборЗаписей - РегистрСведенийНаборЗаписей
// - РегистрНакопленияНаборЗаписей
// - РегистрБухгалтерииНаборЗаписей
// - РегистрРасчетаНаборЗаписей - набор записей,
// который используется вычисления изменений.
//
// Замещение - РежимЗамещения, Булево - как передается в подписку на событие ПередЗаписью.
// - Неопределено - получить и установить в этот параметр значение из свойства
// Замещение структуры ДополнительныеСвойства указанного набора записей
// (если свойства нет, тогда устанавливается Истина).
//
// СписокПолей - Строка - список полей набора записей через запятую.
// Если не указан, значит все поля набора записей.
//
// Возвращаемое значение:
// ТаблицаЗначений - поля из параметра СписокПолей,
// строки без повторений для указанного списка полей.
//
Функция ЗаписиНабораИзБазыДанных(НаборЗаписей, Замещение = Неопределено, СписокПолей = "") Экспорт
ПолноеИмяРегистра = НаборЗаписей.Метаданные().ПолноеИмя();
СвернутьРезультат = Ложь;
Если ЗначениеЗаполнено(СписокПолей) Тогда
ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(ПолноеИмяРегистра);
Поля = СтрРазделить(ВРег(СписокПолей), ",");
Для Каждого Поле Из ОписаниеКлючаЗаписи.ОписаниеПолей Цикл
Если Поля.Найти(ВРег(Поле.Имя)) = Неопределено Тогда
СвернутьРезультат = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Иначе
Таблица = НаборЗаписей.Выгрузить(Новый Массив);
Поля = Новый Массив;
Для Каждого Колонка Из Таблица.Колонки Цикл
Поля.Добавить(Колонка.Имя);
КонецЦикла;
СписокПолей = СтрСоединить(Поля, ",");
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| &ВыбираемыеПоля
|ИЗ
| &Таблица КАК ТекущаяТаблица
|ГДЕ
| &УсловиеОтбора";
ОтборЗаписейНабораИзБазыДанных(НаборЗаписей, Замещение, Запрос);
Если Замещение = Ложь Или ЭтоДобавлениеНабораЗаписей(Замещение) Тогда
Возврат НаборЗаписей.Выгрузить(Новый Массив,
?(ЗначениеЗаполнено(СписокПолей), СписокПолей, Неопределено));
КонецЕсли;
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&Таблица", ПолноеИмяРегистра);
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ВыбираемыеПоля", СписокПолей);
Результат = Запрос.Выполнить().Выгрузить();
Если СвернутьРезультат Тогда
Результат.Свернуть(СписокПолей);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает удаленные и добавленные строки регистра
// для указанного набора записей с учетом режима замещения.
//
// Параметры:
// ЗаписиИзБазыДанных - см. ЗаписиНабораИзБазыДанных
//
// НаборЗаписей - РегистрСведенийНаборЗаписей
// - РегистрНакопленияНаборЗаписей
// - РегистрБухгалтерииНаборЗаписей
// - РегистрРасчетаНаборЗаписей - набор записей,
// который используется вычисления изменений.
//
// Замещение - РежимЗамещения, Булево - как передается в подписку на событие ПередЗаписью.
//
// ТолькоИзменения - Булево - если установить Истина, тогда в результате
// не будет строк без изменений (ВидИзмененияСтроки = 0).
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * ВидИзмененияСтроки - Число - если 1, то строка добавлена,
// если -1, то удалена, если 0, то не изменилась.
// Далее поля из таблицы ЗаписиИзБазыДанных.
//
Функция ИзменениеЗаписейНабора(ЗаписиИзБазыДанных, НаборЗаписей, Замещение, ТолькоИзменения = Ложь) Экспорт
ОписаниеКлючаЗаписи = СтандартныеПодсистемыСервер.ОписаниеКлючаЗаписи(
НаборЗаписей.Метаданные().ПолноеИмя());
СписокПолейКлючаЗаписи = ВРег("," + ОписаниеКлючаЗаписи.СписокПолей + ",");
ПоляКлючаЗаписи = Новый Массив;
Поля = Новый Массив;
Для Каждого Колонка Из ЗаписиИзБазыДанных.Колонки Цикл
Поля.Добавить(Колонка.Имя);
Если СтрНайти(СписокПолейКлючаЗаписи, "," + ВРег(Колонка.Имя) + ",") > 0 Тогда
ПоляКлючаЗаписи.Добавить(Колонка.Имя);
КонецЕсли;
КонецЦикла;
СписокПолей = СтрСоединить(Поля, ",");
НовыеСтроки = ?(ЭтоУдалениеНабораЗаписей(Замещение), Новый Массив, Неопределено);
Таблица = НаборЗаписей.Выгрузить(НовыеСтроки, СписокПолей);
Если ОписаниеКлючаЗаписи.ОписаниеПолей.Количество() <> ПоляКлючаЗаписи.Количество() Тогда
Таблица.Свернуть(СписокПолей);
КонецЕсли;
Таблица.Колонки.Добавить("ВидИзмененияСтроки", Новый ОписаниеТипов("Число"));
Таблица.ЗаполнитьЗначения(1, "ВидИзмененияСтроки");
Для Каждого СтараяЗапись Из ЗаписиИзБазыДанных Цикл
НоваяСтрока = Таблица.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтараяЗапись);
НоваяСтрока.ВидИзмененияСтроки = -1;
КонецЦикла;
Таблица.Свернуть(СписокПолей, "ВидИзмененияСтроки");
Если ТолькоИзменения Тогда
СтрокиБезИзменений = Таблица.НайтиСтроки(Новый Структура("ВидИзмененияСтроки", 0));
Для Каждого СтрокаТаблицы Из СтрокиБезИзменений Цикл
Таблица.Удалить(СтрокаТаблицы);
КонецЦикла;
КонецЕсли;
Возврат Таблица;
КонецФункции
#КонецОбласти
#КонецОбласти
#Область ХранилищеНастроек
////////////////////////////////////////////////////////////////////////////////
// Сохранение, чтение и удаление настроек из хранилищ.
// Сохраняет настройку в хранилище общих настроек, как метод платформы Сохранить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки.
//
// Параметры:
// КлючОбъекта - Строка - см. синтакс-помощник платформы.
// КлючНастроек - Строка - см. синтакс-помощник платформы.
// Настройки - Произвольный - см. синтакс-помощник платформы.
// ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы.
// ИмяПользователя - Строка - см. синтакс-помощник платформы.
// ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы.
//
Процедура ХранилищеОбщихНастроекСохранить(КлючОбъекта, КлючНастроек, Настройки,
ОписаниеНастроек = Неопределено,
ИмяПользователя = Неопределено,
ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт
ХранилищеСохранить(ХранилищеОбщихНастроек,
КлючОбъекта,
КлючНастроек,
Настройки,
ОписаниеНастроек,
ИмяПользователя,
ОбновитьПовторноИспользуемыеЗначения);
КонецПроцедуры
// Сохраняет несколько настроек в хранилище общих настроек, как метод платформы Сохранить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки.
//
// Параметры:
// НесколькоНастроек - Массив - со значениями:
// * Значение - Структура:
// * Объект - Строка - см. параметр КлючОбъекта в синтакс-помощнике платформы.
// * Настройка - Строка - см. параметр КлючНастроек в синтакс-помощнике платформы.
// * Значение - Произвольный - см. параметр Настройки в синтакс-помощнике платформы.
//
// ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы.
//
Процедура ХранилищеОбщихНастроекСохранитьМассив(НесколькоНастроек,
ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт
Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
Возврат;
КонецЕсли;
Для Каждого Элемент Из НесколькоНастроек Цикл
ХранилищеОбщихНастроек.Сохранить(Элемент.Объект, КлючНастроек(Элемент.Настройка), Элемент.Значение);
КонецЦикла;
Если ОбновитьПовторноИспользуемыеЗначения Тогда
ОбновитьПовторноИспользуемыеЗначения();
КонецЕсли;
КонецПроцедуры
// Загружает настройку из хранилища общих настроек, как метод платформы Загрузить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют.
// Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки.
//
// В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно
// - возвращаемая ссылка заменяется на указанное значение по умолчанию;
// - из данных типа Массив ссылки удаляются;
// - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено;
// - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно.
//
// Параметры:
// КлючОбъекта - Строка - см. синтакс-помощник платформы.
// КлючНастроек - Строка - см. синтакс-помощник платформы.
// ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют.
// Если не указано, возвращается значение Неопределено.
// ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы.
// ИмяПользователя - Строка - см. синтакс-помощник платформы.
//
// Возвращаемое значение:
// Произвольный - см. синтакс-помощник платформы.
//
Функция ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено,
ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт
Возврат ХранилищеЗагрузить(ХранилищеОбщихНастроек,
КлючОбъекта,
КлючНастроек,
ЗначениеПоУмолчанию,
ОписаниеНастроек,
ИмяПользователя);
КонецФункции
// Удаляет настройку из хранилища общих настроек, как метод платформы Удалить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки.
//
// Параметры:
// КлючОбъекта - Строка
// - Неопределено - см. синтакс-помощник платформы.
// КлючНастроек - Строка
// - Неопределено - см. синтакс-помощник платформы.
// ИмяПользователя - Строка
// - Неопределено - см. синтакс-помощник платформы.
//
Процедура ХранилищеОбщихНастроекУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт
ХранилищеУдалить(ХранилищеОбщихНастроек,
КлючОбъекта,
КлючНастроек,
ИмяПользователя);
КонецПроцедуры
// Сохраняет настройку в хранилище системных настроек, как метод платформы Сохранить
// объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек
// более 128 символов путем хеширования части, которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки.
//
// Параметры:
// КлючОбъекта - Строка - см. синтакс-помощник платформы.
// КлючНастроек - Строка - см. синтакс-помощник платформы.
// Настройки - Произвольный - см. синтакс-помощник платформы.
// ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы.
// ИмяПользователя - Строка - см. синтакс-помощник платформы.
// ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы.
//
Процедура ХранилищеСистемныхНастроекСохранить(КлючОбъекта, КлючНастроек, Настройки,
ОписаниеНастроек = Неопределено,
ИмяПользователя = Неопределено,
ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт
ХранилищеСохранить(ХранилищеСистемныхНастроек,
КлючОбъекта,
КлючНастроек,
Настройки,
ОписаниеНастроек,
ИмяПользователя,
ОбновитьПовторноИспользуемыеЗначения);
КонецПроцедуры
// Загружает настройку из хранилища системных настроек, как метод платформы Загрузить,
// объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек
// более 128 символов путем хеширования части, которая превышает 96 символов.
// Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют.
// Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки.
//
// В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно:
// - возвращаемая ссылка заменяется на указанное значение по умолчанию;
// - из данных типа Массив ссылки удаляются;
// - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено;
// - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно.
//
// Параметры:
// КлючОбъекта - Строка - см. синтакс-помощник платформы.
// КлючНастроек - Строка - см. синтакс-помощник платформы.
// ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют.
// Если не указано, возвращается значение Неопределено.
// ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы.
// ИмяПользователя - Строка - см. синтакс-помощник платформы.
//
// Возвращаемое значение:
// Произвольный - см. синтакс-помощник платформы.
//
Функция ХранилищеСистемныхНастроекЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено,
ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт
Возврат ХранилищеЗагрузить(ХранилищеСистемныхНастроек,
КлючОбъекта,
КлючНастроек,
ЗначениеПоУмолчанию,
ОписаниеНастроек,
ИмяПользователя);
КонецФункции
// Удаляет настройку из хранилища системных настроек, как метод платформы Удалить,
// объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек
// более 128 символов путем хеширования части, которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки.
//
// Параметры:
// КлючОбъекта - Строка
// - Неопределено - см. синтакс-помощник платформы.
// КлючНастроек - Строка
// - Неопределено - см. синтакс-помощник платформы.
// ИмяПользователя - Строка
// - Неопределено - см. синтакс-помощник платформы.
//
Процедура ХранилищеСистемныхНастроекУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт
ХранилищеУдалить(ХранилищеСистемныхНастроек,
КлючОбъекта,
КлючНастроек,
ИмяПользователя);
КонецПроцедуры
// Сохраняет настройку в хранилище настроек данных форм, как метод платформы Сохранить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки.
//
// Параметры:
// КлючОбъекта - Строка - см. синтакс-помощник платформы.
// КлючНастроек - Строка - см. синтакс-помощник платформы.
// Настройки - Произвольный - см. синтакс-помощник платформы.
// ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы.
// ИмяПользователя - Строка - см. синтакс-помощник платформы.
// ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы.
//
Процедура ХранилищеНастроекДанныхФормСохранить(КлючОбъекта, КлючНастроек, Настройки,
ОписаниеНастроек = Неопределено,
ИмяПользователя = Неопределено,
ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт
ХранилищеСохранить(ХранилищеНастроекДанныхФорм,
КлючОбъекта,
КлючНастроек,
Настройки,
ОписаниеНастроек,
ИмяПользователя,
ОбновитьПовторноИспользуемыеЗначения);
КонецПроцедуры
// Загружает настройку из хранилища настроек данных форм, как метод платформы Загрузить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют.
// Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки.
//
// В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно
// - возвращаемая ссылка заменяется на указанное значение по умолчанию;
// - из данных типа Массив ссылки удаляются;
// - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено;
// - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно.
//
// Параметры:
// КлючОбъекта - Строка - см. синтакс-помощник платформы.
// КлючНастроек - Строка - см. синтакс-помощник платформы.
// ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют.
// Если не указано, возвращается значение Неопределено.
// ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы.
// ИмяПользователя - Строка - см. синтакс-помощник платформы.
//
// Возвращаемое значение:
// Произвольный - см. синтакс-помощник платформы.
//
Функция ХранилищеНастроекДанныхФормЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено,
ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт
Возврат ХранилищеЗагрузить(ХранилищеНастроекДанныхФорм,
КлючОбъекта,
КлючНастроек,
ЗначениеПоУмолчанию,
ОписаниеНастроек,
ИмяПользователя);
КонецФункции
// Удаляет настройку из хранилища настроек данных форм, как метод платформы Удалить,
// объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>,
// но с поддержкой длины ключа настроек более 128 символов путем хеширования части,
// которая превышает 96 символов.
// Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки.
//
// Параметры:
// КлючОбъекта - Строка
// - Неопределено - см. синтакс-помощник платформы.
// КлючНастроек - Строка
// - Неопределено - см. синтакс-помощник платформы.
// ИмяПользователя - Строка
// - Неопределено - см. синтакс-помощник платформы.
//
Процедура ХранилищеНастроекДанныхФормУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт
ХранилищеУдалить(ХранилищеНастроекДанныхФорм,
КлючОбъекта,
КлючНастроек,
ИмяПользователя);
КонецПроцедуры
#КонецОбласти
#Область СериализацияXML
// Преобразует (сериализует) любое значение в XML-строку.
// Преобразованы в могут быть только те объекты, для которых в синтакс-помощнике указано, что они сериализуются.
// См. также ЗначениеИзСтрокиXML.
//
// Параметры:
// Значение - Произвольный - значение, которое необходимо сериализовать в XML-строку.
//
// Возвращаемое значение:
// Строка - XML-строка.
//
Функция ЗначениеВСтрокуXML(Значение) Экспорт
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение, НазначениеТипаXML.Явное);
Возврат ЗаписьXML.Закрыть();
КонецФункции
// Выполняет преобразование (десериализацию) XML-строки в значение.
// См. также ЗначениеВСтрокуXML.
//
// Параметры:
// СтрокаXML - Строка - XML-строка, с сериализованным объектом..
//
// Возвращаемое значение:
// Произвольный - значение, полученное из переданной XML-строки.
//
Функция ЗначениеИзСтрокиXML(СтрокаXML) Экспорт
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXML);
Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
КонецФункции
// Возвращает XML-представление XDTO-объекта.
//
// Параметры:
// ОбъектXDTO - ОбъектXDTO - объект, для которого требуется сформировать XML-представление.
// Фабрика - ФабрикаXDTO - фабрика, с использованием которой требуется формировать XML-представление.
// Если параметр не указан - будет использоваться глобальная фабрика XDTO.
//
// Возвращаемое значение:
// Строка - XML-представление XDTO-объекта.
//
Функция ОбъектXDTOВСтрокуXML(Знач ОбъектXDTO, Знач Фабрика = Неопределено) Экспорт
ОбъектXDTO.Проверить();
Если Фабрика = Неопределено Тогда
Фабрика = ФабрикаXDTO;
КонецЕсли;
Запись = Новый ЗаписьXML();
Запись.УстановитьСтроку();
Фабрика.ЗаписатьXML(Запись, ОбъектXDTO, , , , НазначениеТипаXML.Явное);
Возврат Запись.Закрыть();
КонецФункции
// Формирует XDTO-объект по XML-представлению.
//
// Параметры:
// СтрокаXML - Строка - XML-представление XDTO-объекта,
// Фабрика - ФабрикаXDTO - фабрика, с использованием которой требуется формировать XDTO-объект.
// Если параметр не указан - будет использоваться глобальная фабрика XDTO.
//
// Возвращаемое значение:
// ОбъектXDTO - XDTO-объект.
//
Функция ОбъектXDTOИзСтрокиXML(Знач СтрокаXML, Знач Фабрика = Неопределено) Экспорт
Если Фабрика = Неопределено Тогда
Фабрика = ФабрикаXDTO;
КонецЕсли;
Чтение = Новый ЧтениеXML();
Чтение.УстановитьСтроку(СтрокаXML);
Возврат Фабрика.ПрочитатьXML(Чтение);
КонецФункции
#КонецОбласти
#Область СериализацияJSON
// Преобразует значение в строку JSON при помощи метода глобального контекста ЗаписатьJSON.
// Допускаются не все типы значений, подробности см. в синтакс-помощнике.
// Даты преобразуются в формат ISO (YYYY-MM-DDThh:mm:ssZ).
//
// Параметры:
// Значение - Произвольный
//
// Возвращаемое значение:
// Строка
//
Функция ЗначениеВJSON(Знач Значение) Экспорт
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Значение);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
// Преобразует строку в формате JSON в значение при помощи метода глобального контекста ПрочитатьJSON.
// См. ограничения в синтакс-помощнике.
// Объекты JSON по умолчанию преобразует в значения типа Соответствие.
// Имена свойств со значением типа Дата необходимо явно указывать, чтобы было выполнено преобразование.
// Ожидаемый формат дат - ISO (YYYY-MM-DDThh:mm:ssZ).
//
// Параметры:
// Строка - Строка - значение в формате JSON.
// ИменаСвойствСоЗначениямиДата - Строка - имя свойства, содержащее значение типа Дата. Допустимо указывать несколько
// свойств через запятую.
// - Массив из Строка
// ПрочитатьВСоответствие - Булево - если Ложь, то объекты JSON будут преобразованы в значение типа Структура.
//
// Возвращаемое значение:
// Произвольный
//
Функция JSONВЗначение(Знач Строка, Знач ИменаСвойствСоЗначениямиДата = Неопределено, Знач ПрочитатьВСоответствие = Истина) Экспорт
Если ТипЗнч(ИменаСвойствСоЗначениямиДата) = Тип("Строка") Тогда
ИменаСвойствСоЗначениямиДата = СтрРазделить(ИменаСвойствСоЗначениямиДата, ", " + Символы.ПС, Ложь);
КонецЕсли;
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Строка);
Возврат ПрочитатьJSON(ЧтениеJSON, ПрочитатьВСоответствие, ИменаСвойствСоЗначениямиДата);
КонецФункции
#КонецОбласти
#Область РаботаСИнтернетом
// Проверяет, что разрешена работа с Интернет-сервисами из приложения.
// Параметры:
// ПоказатьОшибку - Булево - вызвать исключение.
//
// Возвращаемое значение:
// Булево
//
Функция РазрешенДоступКИнтернетСервисам(ПоказатьОшибку = Ложь) Экспорт
Если РазделениеВключено() Тогда
Возврат Истина;
КонецЕсли;
ДоступРазрешен = ПолучитьФункциональнуюОпцию("РазрешитьДоступКИнтернетСервисам");
Если Не ДоступРазрешен Тогда
ВерсияМетаданных = Метаданные.Версия;
Если Не ПустаяСтрока(ВерсияМетаданных) И ВерсияМетаданных <> ОбновлениеИнформационнойБазыСлужебный.ВерсияИБ(
Метаданные.Имя) Тогда
Возврат Истина;
КонецЕсли;
КонецЕсли;
Если Не ДоступРазрешен И ПоказатьОшибку Тогда
ВызватьИсключение ЗапрещенДоступКИнтернетСервисамТекстСообщения();
КонецЕсли;
Возврат ДоступРазрешен;
КонецФункции
// Текст ошибки при отключенном доступе к сервисам интернета.
//
// Возвращаемое значение:
// Строка
//
Функция ЗапрещенДоступКИнтернетСервисамТекстСообщения() Экспорт
Возврат НСтр("ru = 'Доступ к Интернет-сервисам в приложении запрещен администратором (""Интернет-поддержка и сервисы"" - ""Доступ к Интернет-сервисам"").'");
КонецФункции
// Устанавливает признак разрешения работа с Интернет-сервисами из приложения. После вызова на клиенте рекомендуется
// вызвать оповещение о записи константы.
//
// Параметры:
// Разрешить - Булево
//
Процедура НастроитьРаботуСИнтернетСервисами(Разрешить) Экспорт
Если Не Разрешить И РазделениеВключено() Тогда
Возврат;
КонецЕсли;
Константы.РазрешитьДоступКИнтернетСервисам.Установить(Разрешить);
Если Разрешить И ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
МодульБлокировкаРаботыСВнешнимиРесурсами.ПриВключенииДоступаКИнтернетСервисам();
КонецЕсли;
КонецПроцедуры
// Возвращает структуру параметров для функции СоздатьWSПрокси.
//
// Возвращаемое значение:
// см. СоздатьWSПрокси.ПараметрыПодключенияWSПрокси
//
Функция ПараметрыПодключенияWSПрокси() Экспорт
Результат = Новый Структура;
Результат.Вставить("АдресWSDL");
Результат.Вставить("URIПространстваИмен");
Результат.Вставить("ИмяСервиса");
Результат.Вставить("ИмяТочкиПодключения", "");
Результат.Вставить("ИмяПользователя");
Результат.Вставить("Пароль");
Результат.Вставить("Таймаут", 0);
Результат.Вставить("Местоположение");
Результат.Вставить("ИспользоватьАутентификациюОС", Ложь);
Результат.Вставить("ДелатьКонтрольныйВызов", Ложь);
Результат.Вставить("ЗащищенноеСоединение", Неопределено);
Результат.Вставить("ПроверятьДоставкуПакетовПриОшибке", Истина);
Результат.Вставить("ПроверятьДоступКИнтернетСервисам", Истина);
Возврат Результат;
КонецФункции
// Конструктор объекта WSПрокси с дополнительными возможностями по сравнению с конструктором Новый WSПрокси:
// - создает WSОпределения;
// - кэширует файл WSDL для ускорения работы с веб-сервисом;
// - не требуется указание ИнтернетПрокси (используется автоматически, если настроен);
// - позволяет делать быструю проверку доступности сервиса с помощью операции Ping.
//
// Параметры:
// ПараметрыПодключенияWSПрокси - Структура:
// * АдресWSDL - Строка - месторасположение wsdl, например, "http://webservice.net/webservice.asmx?wsdl".
// * URIПространстваИмен - Строка - URI пространства имен web-сервиса, например, "http://www.webservice.net/WebService/1.0.0.1".
// * ИмяСервиса - Строка - имя сервиса, например, "WebService_1_0_0_1".
// * ИмяТочкиПодключения - Строка - необязательный параметр. Если не задано, образуется как "<ИмяСервиса>Soap".
// * ИмяПользователя - Строка - необязательный параметр. Имя пользователя для входа на сервер.
// * Пароль - Строка - необязательный параметр. Пароль пользователя.
// * Таймаут - Число - необязательный параметр. Таймаут на операции веб-сервиса, выполняемые
// через прокси. В секундах.
// * Местоположение - Строка - необязательный параметр. Фактический адрес сервиса. Используется, если
// адрес реального расположения сервиса отличается от адреса, который указан
// в WSDL-файле.
// * ИспользоватьАутентификациюОС - Булево - необязательный параметр. Включает использование авторизации NTLM или
// Negotiate на сервере.
// * ДелатьКонтрольныйВызов - Булево - необязательный параметр. Выполнять проверку доступности сервиса (требуется
// поддержка команды Ping в веб-сервисе). По умолчанию, Ложь.
// * ЗащищенноеСоединение - ЗащищенноеСоединениеOpenSSL
// - Неопределено - необязательные параметры защищенного соединения.
// * ПроверятьДоставкуПакетовПриОшибке - см. ПолучениеФайловИзИнтернета.ДиагностикаСоединения.ПроверятьДоставкуПакетов.
// * ПроверятьДоступКИнтернетСервисам - Булево - необязательный параметр, по умолчанию Истина - выполняется проверка
// разрешения доступа к Интернет-сервисам из приложения.
//
// Возвращаемое значение:
// WSПрокси
//
// Пример:
// ПараметрыПодключения = ОбщегоНазначения.ПараметрыПодключенияWSПрокси();
// ПараметрыПодключения.АдресWSDL = "http://webservice.net/webservice.asmx?wsdl";
// ПараметрыПодключения.URIПространстваИмен = "http://www.webservice.net/WebService/1.0.0.1";
// ПараметрыПодключения.ИмяСервиса = "WebService_1_0_0_1";
// ПараметрыПодключения.Таймаут = 20;
// Прокси = ОбщегоНазначения.СоздатьWSПрокси(ПараметрыПодключения);
//
Функция СоздатьWSПрокси(Знач ПараметрыПодключенияWSПрокси) Экспорт
ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("СоздатьWSПрокси", "Параметры", ПараметрыПодключенияWSПрокси, Тип("Структура"),
Новый Структура("АдресWSDL,URIПространстваИмен,ИмяСервиса", Тип("Строка"), Тип("Строка"), Тип("Строка")));
ПараметрыПодключения = ПараметрыПодключенияWSПрокси();
ЗаполнитьЗначенияСвойств(ПараметрыПодключения, ПараметрыПодключенияWSПрокси);
Если ПараметрыПодключения.ПроверятьДоступКИнтернетСервисам Тогда
РазрешенДоступКИнтернетСервисам(Истина);
КонецЕсли;
ДелатьКонтрольныйВызов = ПараметрыПодключения.ДелатьКонтрольныйВызов;
Таймаут = ПараметрыПодключения.Таймаут;
Если ДелатьКонтрольныйВызов И Таймаут <> Неопределено И Таймаут > 20 Тогда
ПараметрыПодключения.Таймаут = 7;
WSПроксиPing = РегистрыСведений.КэшПрограммныхИнтерфейсов.ВнутренняяWSПрокси(ПараметрыПодключения);
Попытка
WSПроксиPing.Ping();
Исключение
АдресТочкиПодключения = WSПроксиPing.ТочкаПодключения.Местоположение;
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось проверить доступность web-сервиса
|%1
|по причине:
|%2'"),
ПараметрыПодключения.АдресWSDL,
ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Если ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
МодульПолучениеФайловИзИнтернета = ОбщийМодуль("ПолучениеФайловИзИнтернета");
РезультатДиагностики = МодульПолучениеФайловИзИнтернета.ДиагностикаСоединения(АдресТочкиПодключения,,
ПараметрыПодключения.ПроверятьДоставкуПакетовПриОшибке);
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = '%1
|Результат диагностики:
|%2'"),
ТекстОшибки,
РезультатДиагностики.ОписаниеОшибки);
КонецЕсли;
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаСети);
КонецПопытки;
ПараметрыПодключения.Таймаут = Таймаут;
КонецЕсли;
Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ВнутренняяWSПрокси(ПараметрыПодключения);
КонецФункции
#Область ВерсионированиеПрограммныхИнтерфейсов
// Возвращает номера версий программных интерфейсов удаленной системы, доступной через веб-сервис.
// Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах
// с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии,
// то только в этом случае допустимо вызывать у него новую функцию.
//
// В целях экономии трафика при интенсивном взаимодействии между вызывающей и вызываемой сторонами
// сведения о версиях кэшируются на одни сутки. Если для целей отладки требуется сбросить кэш раньше этого времени,
// следует удалить соответствующие записи из регистра сведений КэшПрограммныхИнтерфейсов.
//
// Параметры:
// Адрес - Строка - адрес веб-сервиса версионирования интерфейсов InterfaceVersion;
// Пользователь - Строка - имя пользователя веб-сервиса;
// Пароль - Строка - пароль пользователя веб-сервиса;
// Интерфейс - Строка - имя запрашиваемого программного интерфейса, например, "СервисПередачиФайлов";
// ПроверятьДоставкуПакетовПриОшибке - см. ПолучениеФайловИзИнтернета.ДиагностикаСоединения.ПроверятьДоставкуПакетов
//
// Возвращаемое значение:
// ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса.
// Например, "1.0.2.1".
//
// Пример:
// Версии = ПолучитьВерсииИнтерфейса("http://vsrvx/sm", "ivanov",, "СервисПередачиФайлов");
//
// Также для обратной совместимости поддерживается устаревший вариант вызова:
// ПараметрыПодключения = Новый Структура;
// ПараметрыПодключения.Вставить("URL", "http://vsrvx/sm");
// ПараметрыПодключения.Вставить("UserName", "ivanov");
// ПараметрыПодключения.Вставить("Password", "");
// Версии = ПолучитьВерсииИнтерфейса(ПараметрыПодключения, "СервисПередачиФайлов");
//
Функция ПолучитьВерсииИнтерфейса(Знач Адрес, Знач Пользователь, Знач Пароль = Неопределено,
Знач Интерфейс = Неопределено, Знач ПроверятьДоставкуПакетовПриОшибке = Истина) Экспорт
Если ТипЗнч(Адрес) = Тип("Структура") Тогда // для обратной совместимости
ПараметрыПодключения = Адрес;
ИмяИнтерфейса = Пользователь;
Иначе
ПараметрыПодключения = Новый Структура;
ПараметрыПодключения.Вставить("URL", Адрес);
ПараметрыПодключения.Вставить("UserName", Пользователь);
ПараметрыПодключения.Вставить("Password", Пароль);
ИмяИнтерфейса = Интерфейс;
КонецЕсли;
ПараметрыПодключения.Вставить("ПроверятьДоставкуПакетовПриОшибке", ПроверятьДоставкуПакетовПриОшибке);
Если Не ПараметрыПодключения.Свойство("URL")
Или Не ЗначениеЗаполнено(ПараметрыПодключения.URL) Тогда
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение параметра %1 функции %2. Не задан URL сервиса.'"),
"ПараметрыПодключения", "ОбщегоНазначения.ПолучитьВерсииИнтерфейса"), КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ПараметрыПолучения = Новый Массив;
ПараметрыПолучения.Добавить(ПараметрыПодключения);
ПараметрыПолучения.Добавить(ИмяИнтерфейса);
Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ДанныеКэшаВерсий(
РегистрыСведений.КэшПрограммныхИнтерфейсов.ИдентификаторЗаписиКэшаВерсий(ПараметрыПодключения.URL, ИмяИнтерфейса),
Перечисления.ТипыДанныхКэшаПрограммныхИнтерфейсов.ВерсииИнтерфейса,
ПараметрыПолучения,
Истина);
КонецФункции
// Возвращает номера версий программных интерфейсов удаленной системы, подключенной через внешнее соединение.
// Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах
// с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии,
// то только в этом случае допустимо вызывать у него новую функцию.
//
// Параметры:
// ВнешнееСоединение - COMОбъект - внешнее соединение, которое используется для работы с удаленной системой.
// ИмяИнтерфейса - Строка - имя запрашиваемого программного интерфейса, например "СервисПередачиФайлов".
//
// Возвращаемое значение:
// ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса.
// Например "1.0.2.1".
//
// Пример:
// Версии = ОбщегоНазначения.ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, "СервисПередачиФайлов");
//
Функция ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, Знач ИмяИнтерфейса) Экспорт
Попытка
ВерсииИнтерфейсаXML = ВнешнееСоединение.СтандартныеПодсистемыСервер.ПоддерживаемыеВерсии(ИмяИнтерфейса);
Исключение
СтрокаСообщения = НСтр("ru = 'Корреспондент не поддерживает версионирование программных интерфейсов.
|Описание ошибки: %1'");
СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ЗаписьЖурналаРегистрации(НСтр("ru = 'Получение версий интерфейса'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка, , , СтрокаСообщения);
Возврат Новый ФиксированныйМассив(Новый Массив);
КонецПопытки;
Возврат Новый ФиксированныйМассив(ЗначениеИзСтрокиXML(ВерсииИнтерфейсаXML));
КонецФункции
// Удаляет записи кэша версий программных интерфейсов, содержащих в идентификаторе указанную подстроку.
// В качестве подстроки может использоваться, например, имя интерфейса, более не используемого в конфигурации.
//
// Параметры:
// ПодстрокаПоискаИдентификаторов - Строка - подстрока поиска идентификаторов.
// Не может содержать символов %, _ и [.
//
Процедура УдалитьЗаписиКэшаВерсий(Знач ПодстрокаПоискаИдентификаторов) Экспорт
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
Блокировка.Заблокировать();
ТекстЗапроса =
"ВЫБРАТЬ
| ТаблицаКэша.Идентификатор КАК Идентификатор,
| ТаблицаКэша.ТипДанных КАК ТипДанных
|ИЗ
| РегистрСведений.КэшПрограммныхИнтерфейсов КАК ТаблицаКэша
|ГДЕ
| ТаблицаКэша.Идентификатор ПОДОБНО ""%ПодстрокаПоиска%"" СПЕЦСИМВОЛ ""~""";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПодстрокаПоиска",
СформироватьСтрокуДляПоискаВЗапросе(ПодстрокаПоискаИдентификаторов));
Запрос = Новый Запрос(ТекстЗапроса);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Запись = РегистрыСведений.КэшПрограммныхИнтерфейсов.СоздатьМенеджерЗаписи();
Запись.Идентификатор = Выборка.Идентификатор;
Запись.ТипДанных = Выборка.ТипДанных;
Запись.Удалить();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
// Список версий программных интерфейсов, доступных через web-сервис InterfaceVersions.
//
// Возвращаемое значение:
// Структура:
// * Ключ - Строка - имя программного интерфейса
// * Значение - Массив из Строка - поддерживаемые версии интерфейса.
//
Функция ВерсииИнтерфейсов() Экспорт
Результат = Новый Структура;
ИнтеграцияПодсистемБСП.ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(Результат);
ОбщегоНазначенияПереопределяемый.ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(Результат);
Возврат Результат;
КонецФункции
#КонецОбласти
#КонецОбласти
#Область БезопасноеХранилище
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с хранилищем паролей.
// Записывает конфиденциальные данные в безопасное хранилище.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владелец - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы,
// представляющий объект-владелец сохраняемого пароля или строка до 128 символов.
// Для объектов других типов в качестве владельца рекомендуется использовать ссылку на
// элемент метаданных этого типа в справочнике ИдентификаторыОбъектовМетаданных
// или ключ в виде строки с учетом имен подсистем.
// Например, для БСП:
// Владелец = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("РегистрСведений.АдресныеОбъекты");
// если нужно 1 хранилище на подсистему БСП:
// Владелец = "СтандартныеПодсистемы.УправлениеДоступом";
// если нужно более 1 хранилища на подсистему БСП:
// Владелец = "СтандартныеПодсистемы.УправлениеДоступом.<Уточнение>";
// Данные - Произвольный - данные помещаемые в безопасное хранилище. Неопределенно - удаляет все данные.
// Для удаления данных по ключу следует использовать процедуру УдалитьДанныеИзБезопасногоХранилища.
// - Структура - если параметр Ключ содержит Неопределено. Подробнее см. описание параметра Ключ
// Ключ - Строка - ключ сохраняемых настроек, по умолчанию "Пароль".
// Ключ должен соответствовать правилам имен идентификаторов:
// 1. Первым символом ключа должна быть буква или символ подчеркивания (_).
// 2. Каждый из последующих символов может быть буквой, цифрой или символом подчеркивания (_).
// Неопределено - для добавления набора данных структурой, где ключ структуры - это имя ключа данных,
// а значение - сохраняемые данные. Пример использования см. ниже.
//
// Пример:
//
// Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Если ТекущийПользовательМожетИзменятьПароль Тогда
// УстановитьПривилегированныйРежим(Истина);
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Логин, "Логин");
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Пароль);
// УстановитьПривилегированныйРежим(Ложь);
// КонецЕсли;
// КонецПроцедуры
//
// Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Если ТекущийПользовательМожетИзменятьПароль Тогда
// ЛогинИПароль = Новый Структура;
// ЛогинИПароль.Вставить("Логин", Логин);
// ЛогинИПароль.Вставить("Пароль", Пароль);
// УстановитьПривилегированныйРежим(Истина);
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, ЛогинИПароль, Неопределено);
// УстановитьПривилегированныйРежим(Ложь);
// КонецЕсли;
// КонецПроцедуры
//
Процедура ЗаписатьДанныеВБезопасноеХранилище(Владелец, Данные, Ключ = "Пароль") Экспорт
ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать ссылку; передано значение: %3 (тип %4).'"),
"Владелец", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Владелец, ТипЗнч(Владелец)));
Если ЗначениеЗаполнено(Ключ) Тогда
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Ключ) = Тип("Строка"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать строку; передано значение: %3 (тип %4).'"),
"Ключ", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Ключ, ТипЗнч(Ключ)));
Иначе
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Данные) = Тип("Структура"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|Если Ключ = Неопределено, то параметр должен содержать структуру; передано значение: %3 (тип %4).'"),
"Данные", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Данные, ТипЗнч(Данные)));
КонецЕсли;
Блокировка = Новый БлокировкаДанных();
ЭтоОбластьДанных = РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных();
Если ЭтоОбластьДанных Тогда
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных");
Иначе
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанных");
КонецЕсли;
БезопасноеХранилищеДанных.Владелец = Владелец;
ЭлементБлокировки.УстановитьЗначение("Владелец", Владелец);
НачатьТранзакцию();
Попытка
Блокировка.Заблокировать();
Если Данные <> Неопределено Тогда
БезопасноеХранилищеДанных.Прочитать();
Если БезопасноеХранилищеДанных.Выбран() Тогда
ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить();
Если ТипЗнч(ДанныеДляСохранения) <> Тип("Структура") Тогда
ДанныеДляСохранения = Новый Структура();
КонецЕсли;
Если ЗначениеЗаполнено(Ключ) Тогда
ДанныеДляСохранения.Вставить(Ключ, Данные);
Иначе
ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ДанныеДляСохранения, Данные, Истина);
КонецЕсли;
Иначе
ДанныеДляСохранения = ?(ЗначениеЗаполнено(Ключ), Новый Структура(Ключ, Данные), Данные);
БезопасноеХранилищеДанных.Владелец = Владелец;
КонецЕсли;
ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(9));
БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения;
БезопасноеХранилищеДанных.Записать();
Иначе
БезопасноеХранилищеДанных.Удалить();
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
// Возвращает данные из безопасного хранилища.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владельцы - Массив из ПланОбменаСсылка
// - Массив из СправочникСсылка
// - Массив из Строка - ссылки на объекты информационной базы,
// представляющих объекты-владельцы или уникальные строки(до 128 символов) владельцев данных.
// Ключи - Строка - содержит имя ключа данных или список имен ключей, указанных через запятую.
// - Неопределено - будут возвращены все сохраненные данные переданных владельцев.
// ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме.
// ОбластьДанных - Число - содержит номер области данных для которой необходимо выполнить получение данных из
// безопасного хранилища области данных. Параметр следует передавать только в случае получения
// данных из неразделенного сеанса для области данных. Во всех остальных случаях параметр
// игнорируется.
// Неопределено - режим получения данных из безопасного хранилища определяется автоматический
// по доступности использования разделенных данных.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы
// или строка до 128 символов идентифицирующая владельца данных.
// * Значение - Произвольный - если в параметре Ключи указан один ключ,
// то возвращается его значение произвольного типа.
// - Структура - если в параметре Ключи указано несколько ключей или Неопределено,
// где ключ структуры - это имя ключа сохраненных данных,
// а значение - данные произвольного типа. Когда для ключа отсутствуют данные,
// то значение содержит Неопределено.
// - Неопределено - если данные по ключу отсутствуют.
//
// Пример:
// Процедура РассылкаПриглашений(Пользователи)
//
// УстановитьПривилегированныйРежим(Истина);
// ДанныеАвторизации = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(Пользователи, "Логин, Пароль");
// УстановитьПривилегированныйРежим(Ложь);
//
// Для каждого Пользователь Из Пользователи Цикл
// ОтправитьПриглашение(Пользователь, ДанныеАвторизации[Пользователь]);
// КонецЦикла;
//
// КонецПроцедуры
//
Функция ПрочитатьДанныеВладельцевИзБезопасногоХранилища(
Владельцы,
Ключи = "Пароль",
ОбщиеДанные = Неопределено,
ОбластьДанных = Неопределено) Экспорт
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Владельцы) = Тип("Массив"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать массив; передано значение: %3 (тип %4).'"),
"Владельцы", "ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища", Владельцы, ТипЗнч(Владельцы)));
Если ЗначениеЗаполнено(ОбластьДанных) Тогда
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(ОбластьДанных) = Тип("Число"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать строку; передано значение: %3 (тип %4).'"),
"ОбластьДанных", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище",
ОбластьДанных,
ТипЗнч(ОбластьДанных)));
КонецЕсли;
Возврат ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные, ОбластьДанных);
КонецФункции
// Возвращает данные из безопасного хранилища.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владелец - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы,
// представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов).
// Ключи - Строка - содержит список имен сохраненных данных, указанных через запятую.
// - Неопределено - будут возвращены все сохраненные данные владельца.
// ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме.
// ОбластьДанных - Число - содержит номер области данных для которой необходимо выполнить получение данных из
// безопасного хранилища области данных. Параметр следует передавать только в случае получения
// данных из неразделенного сеанса для области данных. Во всех остальных случаях параметр
// игнорируется.
// Неопределено - режим получения данных из безопасного хранилища определяется автоматический
// по доступности использования разделенных данных.
//
// Возвращаемое значение:
// Произвольный, Структура, Неопределено - данные из безопасного хранилища. Если указан один ключ,
// то возвращается его значение, иначе структура.
// Если данные отсутствуют - Неопределенно.
//
// Пример:
// Если ТекущийПользовательМожетИзменятьПароль Тогда
// УстановитьПривилегированныйРежим(Истина);
// Логин = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, "Логин");
// Пароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка);
// УстановитьПривилегированныйРежим(Ложь);
// Иначе
// Элементы.ГруппаЛогинИПароль.Видимость = Ложь;
// КонецЕсли;
//
// УстановитьПривилегированныйРежим(Истина);
// ЛогинИПароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, Неопределено);
//
Функция ПрочитатьДанныеИзБезопасногоХранилища(
Владелец,
Ключи = "Пароль",
ОбщиеДанные = Неопределено,
ОбластьДанных = Неопределено) Экспорт
Владельцы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец);
ДанныеВладельца = ПрочитатьДанныеВладельцевИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные, ОбластьДанных);
Возврат ДанныеВладельца[Владелец];
КонецФункции
// Удаляет конфиденциальные данные в безопасное хранилище.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владелец - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы,
// представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов).
// - Массив - ссылки на объекты информационной базы для удаления данным по нескольким владельцам.
// Ключи - Строка - содержит список имен удаляемых данных, указанных через запятую.
// Неопределено - удаляет все данные.
//
// Пример:
// Процедура ПередУдалением(Отказ)
//
// // Проверка значения свойства ОбменДанными.Загрузка отсутствует, так как удалять данные
// // из безопасного хранилища нужно даже при удалении объекта при обмене данными.
//
// УстановитьПривилегированныйРежим(Истина);
// ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища(Ссылка);
// УстановитьПривилегированныйРежим(Ложь);
//
// КонецПроцедуры
//
Процедура УдалитьДанныеИзБезопасногоХранилища(Знач Владелец, Знач Ключи = Неопределено) Экспорт
ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать ссылку; передано значение: %3 (тип %4).'"),
"Владелец", "ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища", Владелец, ТипЗнч(Владелец)));
Блокировка = Новый БлокировкаДанных();
Владельцы = ?(ТипЗнч(Владелец) = Тип("Массив"), Владелец, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец));
Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных");
Иначе
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи();
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.БезопасноеХранилищеДанных");
КонецЕсли;
Для каждого ВладелецДанных Из Владельцы Цикл
ЭлементБлокировки.УстановитьЗначение("Владелец", ВладелецДанных);
КонецЦикла;
НачатьТранзакцию();
Попытка
Блокировка.Заблокировать();
Для Каждого ВладелецДанных Из Владельцы Цикл
БезопасноеХранилищеДанных.Владелец = ВладелецДанных;
БезопасноеХранилищеДанных.Прочитать();
Если ТипЗнч(БезопасноеХранилищеДанных.Данные) = Тип("ХранилищеЗначения") Тогда
ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить();
Если Ключи <> Неопределено И ТипЗнч(ДанныеДляСохранения) = Тип("Структура") Тогда
СписокКлючей = СтрРазделить(Ключи, ",", Ложь);
Если БезопасноеХранилищеДанных.Выбран() И СписокКлючей.Количество() > 0 Тогда
Для каждого КлючДляУдаления Из СписокКлючей Цикл
Если ДанныеДляСохранения.Свойство(КлючДляУдаления) Тогда
ДанныеДляСохранения.Удалить(КлючДляУдаления);
КонецЕсли;
КонецЦикла;
БезопасноеХранилищеДанных.Данные = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(9));
БезопасноеХранилищеДанных.Записать();
Продолжить;
КонецЕсли;
КонецЕсли;
КонецЕсли;
БезопасноеХранилищеДанных.Удалить();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
#КонецОбласти
#Область БуферОбмена
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с внутренним буфером обмена.
// Помещает выделенные строки табличной части во внутренний буфер обмена
// откуда их можно получить с помощью СтрокиИзБуфераОбмена.
//
// Параметры:
// ТабличнаяЧасть - ДанныеФормыКоллекция - табличная часть, строки которой
// необходимо поместить во внутренний буфер обмена.
// ВыделенныеСтроки - Массив - массив идентификаторов выделенных строк.
// Источник - Строка - произвольный строковый идентификатор, например, имя объекта,
// строки табличной части которого помещаются во внутренний буфер обмена.
//
Процедура СкопироватьСтрокиВБуферОбмена(ТабличнаяЧасть, ВыделенныеСтроки, Источник = Неопределено) Экспорт
Если ВыделенныеСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
ТаблицаЗначений = ТабличнаяЧасть.Выгрузить();
ТаблицаЗначений.Очистить();
УдаляемыеКолонки = Новый Массив;
УдаляемыеКолонки.Добавить("ИсходныйНомерСтроки");
УдаляемыеКолонки.Добавить("НомерСтроки");
Для Каждого ИмяКолонки Из УдаляемыеКолонки Цикл
Колонка = ТаблицаЗначений.Колонки.Найти(ИмяКолонки);
Если Колонка = Неопределено Тогда
Продолжить;
КонецЕсли;
ТаблицаЗначений.Колонки.Удалить(Колонка);
КонецЦикла;
Для Каждого ИдентификаторСтроки Из ВыделенныеСтроки Цикл
КопируемаяСтрока = ТабличнаяЧасть.НайтиПоИдентификатору(ИдентификаторСтроки);
ЗаполнитьЗначенияСвойств(ТаблицаЗначений.Добавить(), КопируемаяСтрока);
КонецЦикла;
СкопироватьВБуферОбмена(ТаблицаЗначений, Источник);
КонецПроцедуры
// Помещает произвольные данные во внутренний буфер обмена, откуда их можно получить с помощью СтрокиИзБуфераОбмена.
//
// Параметры:
// Данные - Произвольный - данные, которые необходимо поместить в внутренний буфер обмена.
// Источник - Строка - произвольный строковый идентификатор, например, имя объекта,
// строки табличной части которого помещаются во внутренний буфер обмена.
//
Процедура СкопироватьВБуферОбмена(Данные, Источник = Неопределено) Экспорт
ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена;
Если ЗначениеЗаполнено(ТекущийБуферОбмена.Данные) Тогда
Адрес = ТекущийБуферОбмена.Данные;
Иначе
Адрес = Новый УникальныйИдентификатор;
КонецЕсли;
ДанныеВХранилище = ПоместитьВоВременноеХранилище(Данные, Адрес);
СтруктураБуфераОбмена = Новый Структура;
СтруктураБуфераОбмена.Вставить("Источник", Источник);
СтруктураБуфераОбмена.Вставить("Данные", ДанныеВХранилище);
ПараметрыСеанса.БуферОбмена = Новый ФиксированнаяСтруктура(СтруктураБуфераОбмена);
КонецПроцедуры
// Получает строки табличной части, помещенные во внутренний буфер обмена с помощью СкопироватьСтрокиВБуферОбмена.
//
// Возвращаемое значение:
// Структура:
// * Данные - Произвольный - данные из внутреннего буфера обмена.
// Например, ТаблицаЗначений при вызове СкопироватьСтрокиВБуферОбмена.
// * Источник - Строка - объект, к которому относятся данные.
// Если при помещении во внутренний буфер не был указан, то Неопределено.
//
Функция СтрокиИзБуфераОбмена() Экспорт
Результат = Новый Структура;
Результат.Вставить("Источник", Неопределено);
Результат.Вставить("Данные", Неопределено);
Если ПустойБуферОбмена() Тогда
Возврат Результат;
КонецЕсли;
ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена
Результат.Источник = ТекущийБуферОбмена.Источник;
Результат.Данные = ПолучитьИзВременногоХранилища(ТекущийБуферОбмена.Данные);
Возврат Результат;
КонецФункции
// Проверяет наличие сохраненных данных во внутренний буфере обмена.
//
// Параметры:
// Источник - Строка - если передан, то проверяется наличие данных
// в внутреннем буфере обмена с этим ключом.
// По умолчанию - Неопределено.
// Возвращаемое значение:
// Булево - Истина, если пустой.
//
Функция ПустойБуферОбмена(Источник = Неопределено) Экспорт
ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена
ИсточникСовпадает = Истина;
Если Источник <> Неопределено Тогда
ИсточникСовпадает = (Источник = ТекущийБуферОбмена.Источник);
КонецЕсли;
Возврат (Не ИсточникСовпадает Или Не ЗначениеЗаполнено(ТекущийБуферОбмена.Данные));
КонецФункции
#КонецОбласти
#Область БезопасноеВыполнениеВнешнегоКода
// Запускает фоновое задание с проверкой вызываемой процедуры.
//
// Параметры:
// ИмяМетода - Строка - также как у метода платформы ФоновыеЗадания.Выполнить.
// ПараметрыВыполнения - см. НовыеПараметрыВыполненияФоновогоЗадания
// - Неопределено - использовать значения по умолчанию.
//
// Возвращаемое значение:
// ФоновоеЗадание - также как у метода платформы ФоновыеЗадания.Выполнить.
//
Функция ВыполнитьФоновоеЗадание(Знач ИмяМетода, Знач ПараметрыВыполнения = Неопределено) Экспорт
Если ПараметрыВыполнения = Неопределено Тогда
ПараметрыВыполнения = НовыеПараметрыВыполненияФоновогоЗадания();
КонецЕсли;
Попытка
СтандартныеПодсистемыСервер.ПроверитьМетодДляВызоваКакПроизвольныйКод(ИмяМетода, Истина);
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильное значение параметра %1 (передано значение: ""%2"") в %3:'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.ВыполнитьФоновоеЗадание");
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, ЗаголовокОшибки);
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
Если ПараметрыВыполнения.СРасширениямиБазыДанных = Истина Тогда
ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных(ИмяМетода,
ПараметрыВыполнения.Параметры, ПараметрыВыполнения.Ключ, ПараметрыВыполнения.Наименование);
ИначеЕсли ПараметрыВыполнения.СРасширениямиБазыДанных = Ложь Тогда
ФоновоеЗадание = РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеБезРасширений(ИмяМетода,
ПараметрыВыполнения.Параметры, ПараметрыВыполнения.Ключ, ПараметрыВыполнения.Наименование);
Иначе
ФоновоеЗадание = ФоновыеЗадания.Выполнить(ИмяМетода,
ПараметрыВыполнения.Параметры, ПараметрыВыполнения.Ключ, ПараметрыВыполнения.Наименование);
КонецЕсли;
Возврат ФоновоеЗадание;
КонецФункции
// Конструктор параметров для функции ВыполнитьФоновоеЗадание.
//
// Возвращаемое значение:
// Структура:
// * Параметры - Неопределено - значение по умолчанию.
// - Массив - также как у метода платформы ФоновыеЗадания.Выполнить.
//
// * Ключ - Неопределено - значение по умолчанию.
// - Строка - также как у метода платформы ФоновыеЗадания.Выполнить.
//
// * Наименование - Неопределено - значение по умолчанию.
// - Строка - также как у метода платформы ФоновыеЗадания.Выполнить.
//
// * СРасширениямиБазыДанных - Неопределено - ФоновыеЗадания.Выполнить
// - Булево - Истина - РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеСРасширениямиБазыДанных
// Ложь - РасширенияКонфигурации.ВыполнитьФоновоеЗаданиеБезРасширений
//
Функция НовыеПараметрыВыполненияФоновогоЗадания() Экспорт
Результат = Новый Структура;
Результат.Вставить("Параметры");
Результат.Вставить("Ключ");
Результат.Вставить("Наименование");
Результат.Вставить("СРасширениямиБазыДанных");
Возврат Результат;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Функции для поддержки работы конфигурации с профилем безопасности, в котором
// запрещено подключение внешних модулей без установки безопасного режима.
//
// Выполнить экспортную процедуру или функцию по имени с уровнем привилегий конфигурации.
// При включении профилей безопасности для вызова оператора Выполнить() используется
// переход в безопасный режим с профилем безопасности, используемым для информационной базы
// (если выше по стеку не был установлен другой безопасный режим).
//
// Параметры:
// ИмяМетода - Строка - имя экспортной процедуры или функции в формате
// <имя объекта>.<имя процедуры или функции>, где <имя объекта> - это
// общий модуль или модуль менеджера объекта.
// Параметры - Массив - параметры передаются в процедуру или функцию <ИмяМетода>
// в порядке расположения элементов массива.
// ЭтоФункция - Булево - указать Истина, если вызывается функция.
//
// Возвращаемое значение:
// Произвольный - если это функция, иначе Неопределено.
//
// Пример:
// Параметры = Новый Массив();
// Параметры.Добавить("1");
// ОбщегоНазначения.ВыполнитьМетодКонфигурации("МойОбщийМодуль.МояПроцедура", Параметры);
//
Функция ВыполнитьМетодКонфигурации(Знач ИмяМетода, Знач Параметры = Неопределено, ЭтоФункция = Ложь) Экспорт
ПрофильБезопасностиИБ = СтандартныеПодсистемыСервер.ПрофильБезопасностиДляВыполнитьВычислить();
Если ЗначениеЗаполнено(ПрофильБезопасностиИБ) Тогда
УстановитьБезопасныйРежим(ПрофильБезопасностиИБ);
КонецЕсли;
СтрокаВызова = СтрокаВызоваМетодаКакПроизвольногоКода(ИмяМетода, Параметры);
Если ЭтоФункция Тогда
Возврат Вычислить(СтрокаВызова); // АПК:488 Исполняемый код безопасен.
КонецЕсли;
Выполнить(СтрокаВызова); // АПК:487 Исполняемый код безопасен.
КонецФункции
// Выполнить экспортную процедуру или функцию объекта по имени.
// При включении профилей безопасности для вызова оператора Выполнить() используется
// переход в безопасный режим с профилем безопасности, используемым для информационной базы
// (если выше по стеку не был установлен другой безопасный режим).
//
// Параметры:
// ОбъектМетода - ПланОбменаОбъект
// - КонстантаМенеджерЗначения
// - СправочникОбъект
// - ДокументОбъект
// - ПоследовательностьНаборЗаписей
// - ОтчетОбъект
// - ОбработкаОбъект
// - ПланВидовХарактеристикОбъект
// - ПланСчетовОбъект
// - ПланВидовРасчетаОбъект
// - РегистрСведенийНаборЗаписей
// - РегистрНакопленияНаборЗаписей
// - РегистрБухгалтерииНаборЗаписей
// - РегистрРасчетаНаборЗаписей
// - ПерерасчетНаборЗаписей
// - БизнесПроцессОбъект
// - ЗадачаОбъект
// - ВнешнийИсточникДанныхТаблицаОбъект
// - ВнешнийИсточникДанныхТаблицаНаборЗаписей
// - ВнешнийИсточникДанныхКубНаборЗаписей
// - ВнешнийИсточникДанныхКубТаблицаИзмеренияОбъект
//
// ИмяМетода - Строка - имя экспортной процедуры модуля объекта обработки.
// Параметры - Массив - параметры передаются в процедуру <ИмяПроцедуры>
// в порядке расположения элементов массива.
// ЭтоФункция - Булево - указать Истина, если вызывается функция.
//
// Возвращаемое значение:
// Произвольный - если это функция, иначе Неопределено.
//
Функция ВыполнитьМетодОбъекта(Знач ОбъектМетода, Знач ИмяМетода, Знач Параметры = Неопределено, ЭтоФункция = Ложь) Экспорт
ПрофильБезопасностиИБ = СтандартныеПодсистемыСервер.ПрофильБезопасностиДляВыполнитьВычислить();
Если ЗначениеЗаполнено(ПрофильБезопасностиИБ) Тогда
УстановитьБезопасныйРежим(ПрофильБезопасностиИБ);
КонецЕсли;
СтрокаВызова = СтрокаВызоваМетодаКакПроизвольногоКода(ИмяМетода, Параметры, ОбъектМетода);
Если ЭтоФункция Тогда
Возврат Вычислить(СтрокаВызова); // АПК:488 Исполняемый код безопасен.
КонецЕсли;
Выполнить(СтрокаВызова); // АПК:487 Исполняемый код безопасен.
КонецФункции
// Выполняет произвольный алгоритм на встроенном языке 1С:Предприятия, предварительно устанавливая
// безопасный режим выполнения кода и безопасный режим разделения данных для всех разделителей,
// присутствующих в составе конфигурации.
//
// Для выполняемого кода так же применяются дополнительные ограничения, запрещается:
//
// 1) Вызов методов платформы:
// - Выполнить
// - Вычислить
// - Подключить (для внешних обработок)
// - НачатьТранзакцию
// - ОтменитьТранзакцию
// - ЗафиксироватьТранзакцию
// - СократитьЖурналРегистрации
// - УстановитьИспользованиеСобытияЖурналаРегистрации
// - ЗапуститьПриложение
// - Base64Значение
// - ЗначениеИзСтрокиВнутр
// - XMLЗначение
//
// 2) Вызов общих модулей и свойств глобального контекста:
// - ДлительныеОперации
// - ПользователиИнформационнойБазы
//
// 3) Вызов процедур и функций БСП:
// - ВыполнитьМетодОбъекта
// - ВыполнитьМетодКонфигурации
// - ВыполнитьФоновоеЗадание
// - ОбщийМодуль
// - ЗначениеИзСтрокиXML
//
// Помимо этого рекомендуется вызывать метод вне транзакции, тогда выполняемый код будет
// автоматически выполнен в транзакции с ее отменой по завершении, что позволит более
// надежно защититься от изменения данных выполняемым кодом.
//
// Параметры:
// Алгоритм - Строка - алгоритм на встроенном языке "1С:Предприятия".
// Параметры - Произвольный - контекст, который требуется для выполнения алгоритма.
// В тексте алгоритма обращение к контексту должно происходить по имени "Параметры".
// Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям
// "Значение1" и "Значение2", переданным в Параметры, как свойства.
// ПараметрыПроверкиАлгоритма - см. ОбщегоНазначения.ПараметрыПроверкиАлгоритма
// Позволяет указать список методов, модулей и свойств глобального контекста, использование
// которых не допускается при выполнении алгоритма. Дополняет базовую проверку.
//
// Пример:
//
// // Пример 1
// Параметры = Новый Структура;
// Параметры.Вставить("Значение1", 1);
// Параметры.Вставить("Значение2", 10);
// ОбщегоНазначения.ВыполнитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры);
//
// // Пример 2
// Параметры = Новый Структура;
// Параметры.Вставить("Источник", Источник);
// Параметры.Вставить("Результат", Неопределено);
// ПараметрыПроверкиАлгоритма = ОбщегоНазначения.ПараметрыПроверкиАлгоритма();
// ПараметрыПроверкиАлгоритма.НедопустимыеМетоды.Добавить("Записать");
// ПараметрыПроверкиАлгоритма.НедопустимыеМетоды.Добавить("Base64Значение");
// ОбщегоНазначения.ВыполнитьВБезопасномРежиме(ВычисляемоеВыражение, Параметры, ПараметрыПроверкиАлгоритма);
//
Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено,
Знач ПараметрыПроверкиАлгоритма = Неопределено) Экспорт
ПроверитьАлгоритм(Алгоритм, ПараметрыПроверкиАлгоритма);
УстановитьБезопасныйРежим(Истина);
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации();
Иначе
МассивРазделителей = Новый Массив;
КонецЕсли;
Для Каждого ИмяРазделителя Из МассивРазделителей Цикл
УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина);
КонецЦикла;
Попытка
Если ТранзакцияАктивна() Тогда
Выполнить Алгоритм; // АПК:487 Код выполняется в безопасном режиме.
Иначе
НачатьТранзакцию(); // АПК:326 принудительная отмена транзакции
Попытка
Выполнить Алгоритм; // АПК:487 Код выполняется в безопасном режиме.
ОтменитьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецЕсли;
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке);
ВызватьИсключение(Уточнение.Текст, КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных ,,, ИнформацияОбОшибке);
КонецПопытки;
КонецПроцедуры
// Вычисляет переданное выражение, предварительно устанавливая безопасный режим выполнения кода
// и безопасный режим разделения данных для всех разделителей, присутствующих в составе конфигурации.
//
// Для выполняемого кода так же применяются дополнительные ограничения, запрещается:
//
// 1) Вызов методов платформы:
// - Выполнить
// - Вычислить
// - Подключить (для внешних обработок)
// - НачатьТранзакцию
// - ОтменитьТранзакцию
// - ЗафиксироватьТранзакцию
// - СократитьЖурналРегистрации
// - УстановитьИспользованиеСобытияЖурналаРегистрации
// - ЗапуститьПриложение
// - Base64Значение
// - ЗначениеИзСтрокиВнутр
// - XMLЗначение
//
// 2) Вызов общих модулей и свойств глобального контекста:
// - ДлительныеОперации
// - ПользователиИнформационнойБазы
//
// 3) Вызов процедур и функций БСП:
// - ВыполнитьМетодОбъекта
// - ВыполнитьМетодКонфигурации
// - ВыполнитьФоновоеЗадание
// - ОбщийМодуль
// - ЗначениеИзСтрокиXML
//
// Помимо этого рекомендуется вызывать метод вне транзакции, тогда выполняемый код будет
// автоматически выполнен в транзакции с ее отменой по завершении, что позволит более
// надежно защититься от изменения данных выполняемым кодом.
//
// Параметры:
// Выражение - Строка - выражение на встроенном языке 1С:Предприятия.
// Параметры - Произвольный - контекст, который требуется для вычисления выражения.
// В тексте выражения обращение к контексту должно происходить по имени "Параметры".
// Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям
// "Значение1" и "Значение2" переданные в Параметры, как свойства.
// ПараметрыПроверкиАлгоритма - см. ОбщегоНазначения.ПараметрыПроверкиАлгоритма
// Позволяет указать список методов, модулей и свойств глобального контекста, использование
// которых не допускается при выполнении алгоритма. Дополняет базовую проверку.
//
// Возвращаемое значение:
// Произвольный - результат вычисления выражения.
//
// Пример:
//
// // Пример 1
// Параметры = Новый Структура;
// Параметры.Вставить("Значение1", 1);
// Параметры.Вставить("Значение2", 10);
// Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры);
//
// // Пример 2
// Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("СтандартныеПодсистемыСервер.ВерсияБиблиотеки()");
//
Функция ВычислитьВБезопасномРежиме(Знач Выражение, Знач Параметры = Неопределено,
Знач ПараметрыПроверкиАлгоритма = Неопределено) Экспорт
ПроверитьАлгоритм(Выражение, ПараметрыПроверкиАлгоритма);
УстановитьБезопасныйРежим(Истина);
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации();
Иначе
МассивРазделителей = Новый Массив;
КонецЕсли;
Для Каждого ИмяРазделителя Из МассивРазделителей Цикл
УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина);
КонецЦикла;
Попытка
Если ТранзакцияАктивна() Тогда
Результат = Вычислить(Выражение); // АПК:488 Код выполняется в безопасном режиме.
Иначе
НачатьТранзакцию(); // АПК:326 принудительная отмена транзакции
Попытка
Результат = Вычислить(Выражение); // АПК:488 Код выполняется в безопасном режиме.
ОтменитьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецЕсли;
Возврат Результат;
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке);
ВызватьИсключение(Уточнение.Текст, КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных ,,, ИнформацияОбОшибке);
КонецПопытки;
КонецФункции
// Возвращает строку для вызова указанного метода с параметрами с помощью Выполнить/Вычислить.
// См. ВыполнитьМетодКонфигурации и см. ВыполнитьМетодОбъекта.
//
// Проверяет, что переданное имя метода является именем экспортной процедуры или функции
// конфигурации или объекта и не содержит произвольного алгоритма на встроенном языке 1С:Предприятия.
// В случае если переданная строка не соответствует требованиям, вызывается исключение.
//
// Параметры:
// ИмяМетода - см. ВыполнитьМетодОбъекта.ИмяМетода
// - см. ВыполнитьМетодКонфигурации.ИмяМетода
// Параметры - см. ВыполнитьМетодОбъекта.Параметры
// - см. ВыполнитьМетодКонфигурации.Параметры
// ОбъектМетода - см. ВыполнитьМетодОбъекта.ОбъектМетода
// - Неопределено - строка для вызова метода конфигурации.
//
// Возвращаемое значение:
// Строка - если параметр Объект указан, тогда строка в формате
// "ОбъектМетода.ИмяМетода(Параметры[0],...)",
// если параметр Объект не указан, тогда строка в формате
// "ИмяМетода(Параметры[0],...)".
//
Функция СтрокаВызоваМетодаКакПроизвольногоКода(Знач ИмяМетода, Знач Параметры = Неопределено,
Знач ОбъектМетода = Неопределено) Экспорт
Если ОбъектМетода = Неопределено Тогда
ЧастиИмени = СтрРазделить(ИмяМетода, ".");
Если ЧастиИмени.Количество() <> 2 И ЧастиИмени.Количество() <> 3 Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3.'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода");
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
ИмяОбъекта = ЧастиИмени[0];
Если ЧастиИмени.Количество() = 2 И Метаданные.ОбщиеМодули.Найти(ИмяОбъекта) = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3:
|Не существует общий модуль ""%4"".'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", ИмяОбъекта);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
Если ЧастиИмени.Количество() = 3 Тогда
ПолноеИмяОбъекта = ЧастиИмени[0] + "." + ЧастиИмени[1];
Попытка
Менеджер = МенеджерОбъектаПоИмени(ПолноеИмяОбъекта, Истина, Истина, Истина,
"ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", "ИмяМетода");
Исключение
Менеджер = Неопределено;
КонецПопытки;
Если Менеджер = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3:
|Не существует менеджер объекта ""%4"".'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", ПолноеИмяОбъекта);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
КонецЕсли;
ИмяМетодаОбъекта = ЧастиИмени[ЧастиИмени.ВГраница()];
Иначе
ИмяМетодаОбъекта = ИмяМетода;
СериализованныйТипОбъекта = ЗначениеВСтрокуВнутр(ТипЗнч(ОбъектМетода));
Если Не СтандартныеПодсистемыПовтИсп.ЭтоОбъектСМодулем(СериализованныйТипОбъекта)
И Не ЭтоВнешнийОтчетИлиВнешняяОбработка(ОбъектМетода) Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение типа: ""%2"") в %3:
|Указан недопустимый тип объекта для выполнения метода.'"),
"ОбъектМетода",
СтроковоеПредставлениеТипа(ТипЗнч(ОбъектМетода)),
"ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода");
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
КонецЕсли;
ВременнаяСтруктура = Новый Структура;
Попытка
ВременнаяСтруктура.Вставить(ИмяМетодаОбъекта);
Исключение
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3:
|Имя ""%4"" не соответствует требованиям образования имен процедур и функций.'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода", ИмяМетодаОбъекта);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации);
КонецПопытки;
Попытка
СтандартныеПодсистемыСервер.ПроверитьМетодДляВызоваКакПроизвольныйКод(ИмяМетода,, ОбъектМетода);
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильное значение параметра %1 (передано значение: ""%2"") в %3:'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода");
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, ЗаголовокОшибки);
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
ПараметрыСтрока = "";
Если Параметры <> Неопределено Тогда
Если ТипЗнч(Параметры) <> Тип("Массив") Тогда
ДопустимыеТипы = Новый Массив;
ДопустимыеТипы.Добавить(Тип("Неопределено"));
ДопустимыеТипы.Добавить(Тип("Массив"));
ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ОбщегоНазначения.СтрокаВызоваМетодаКакПроизвольногоКода",
"Параметры", Параметры, ДопустимыеТипы);
КонецЕсли;
Если Параметры.Количество() > 0 Тогда
Для Индекс = 0 По Параметры.ВГраница() Цикл
ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],";
КонецЦикла;
ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1);
КонецЕсли;
КонецЕсли;
Если ОбъектМетода = Неопределено Тогда
Возврат ИмяМетода + "(" + ПараметрыСтрока + ")";
КонецЕсли;
Возврат "ОбъектМетода." + ИмяМетода + "(" + ПараметрыСтрока + ")";
КонецФункции
// Возвращает описание защиты от опасных действий с отключенными предупреждениями.
//
// Возвращаемое значение:
// ОписаниеЗащитыОтОпасныхДействий - со свойством ПредупреждатьОбОпасныхДействиях = Ложь.
//
Функция ОписаниеЗащитыБезПредупреждений() Экспорт
ОписаниеЗащиты = Новый ОписаниеЗащитыОтОпасныхДействий;
ОписаниеЗащиты.ПредупреждатьОбОпасныхДействиях = Ложь;
Возврат ОписаниеЗащиты;
КонецФункции
// Конструктор структуры для параметра ПараметрыПроверкиАлгоритма функций
// ОбщегоНазначения.ВыполнитьВБезопасномРежиме и ОбщегоНазначения.ВычислитьВБезопасномРежиме.
//
// Возвращаемое значение:
// Структура:
// * НедопустимыеМетоды - Массив из Строка - список методов, вызов которых не допускается при
// выполнении алгоритма.
// * ЗапрещенныеСвойстваГлобальногоКонтекста - Массив из Строка - список свойств глобального контекста,
// обращение к которым не допускается при выполнении алгоритма.
// * ЗапрещенныеМодули - Массив из Строка - список модулей, использование которых не допускается при
// выполнении алгоритма.
//
Функция ПараметрыПроверкиАлгоритма() Экспорт
ПараметрыПроверки = Новый Структура;
ПараметрыПроверки.Вставить("НедопустимыеМетоды", Новый Массив);
ПараметрыПроверки.Вставить("ЗапрещенныеСвойстваГлобальногоКонтекста", Новый Массив);
ПараметрыПроверки.Вставить("ЗапрещенныеМодули", Новый Массив);
Возврат ПараметрыПроверки;
КонецФункции
#КонецОбласти
#Область Запросы
// Подготавливает строку для использования в качестве шаблона поиска в запросе с оператором ПОДОБНО.
// Экранирует служебные символы, если они есть в строке.
//
// Параметры:
// СтрокаПоиска - Строка - произвольная строка.
//
// Возвращаемое значение:
// Строка
//
// Пример:
// ВЫБРАТЬ
// Номенклатура.Ссылка КАК Ссылка
// ИЗ
// Справочник.Номенклатура КАК Номенклатура
// ГДЕ
// Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~"
//
// Запрос.УстановитьПараметр("Шаблон", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИскомыйТекст));
//
Функция СформироватьСтрокуДляПоискаВЗапросе(Знач СтрокаПоиска) Экспорт
Результат = СтрокаПоиска;
Результат = СтрЗаменить(Результат, "~", "~~");
Результат = СтрЗаменить(Результат, "%", "~%");
Результат = СтрЗаменить(Результат, "_", "~_");
Результат = СтрЗаменить(Результат, "[", "~[");
Результат = СтрЗаменить(Результат, "]", "~]");
Результат = СтрЗаменить(Результат, "^", "~^");
Возврат Результат;
КонецФункции
// Возвращает фрагмент текста запроса, отделяющего один запрос от другого.
//
// Возвращаемое значение:
// Строка - разделитель запросов.
//
Функция РазделительПакетаЗапросов() Экспорт
Возврат "
|;
|
|////////////////////////////////////////////////////////////////////////////////
|";
КонецФункции
// Возвращает фрагмент текста запроса, объединяющего результаты запросов в один запрос.
//
// Возвращаемое значение:
// Строка
//
Функция ТекстОбъединитьВсе() Экспорт
Возврат
"
|
|ОБЪЕДИНИТЬ ВСЕ
|
|";
КонецФункции
#КонецОбласти
#Область Прочее
// Выполняет проверки перед выполнением обработчика регламентного задания и прерывает выполнение,
// если его запуск в данный момент невозможен, например:
// - еще не завершено обновление программы;
// - запуск через консоль или другим способом, минуя включение функциональной опции
// (если регламентное задание зависит от функциональных опций);
// - попытка выполнения задания, работающего с внешними ресурсами в копии информационной базы.
//
// Параметры:
// РегламентноеЗадание - ОбъектМетаданныхРегламентноеЗадание - регламентное задание,
// из которого вызывается данная процедура.
//
// Пример:
// ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.<ИмяРегламентногоЗадания>);
//
Процедура ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание = Неопределено) Экспорт
УстановитьПривилегированныйРежим(Истина);
Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда
Текст = НСтр("ru = 'Вход в приложение временно невозможен в связи с обновлением на новую версию.
|Рекомендуется запрещать выполнение регламентных заданий на время обновления.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
Если Не РазделениеВключено()
И ПланыОбмена.ГлавныйУзел() = Неопределено
И ЗначениеЗаполнено(Константы.ГлавныйУзел.Получить()) Тогда
Текст = НСтр("ru = 'Вход в приложение временно невозможен до восстановления связи с главным узлом.
|Рекомендуется запрещать выполнение регламентных заданий на время восстановления.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
Если РегламентноеЗадание <> Неопределено
И ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
МодульБлокировкаРаботыСВнешнимиРесурсами.ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание);
МодульРегламентныеЗаданияСлужебный = ОбщийМодуль("РегламентныеЗаданияСлужебный");
Доступно = МодульРегламентныеЗаданияСлужебный.РегламентноеЗаданиеДоступноПоФункциональнымОпциям(РегламентноеЗадание);
Если Не Доступно Тогда
Задания = РегламентныеЗаданияСервер.НайтиЗадания(Новый Структура("Метаданные", РегламентноеЗадание));
Для Каждого Задание Из Задания Цикл
РегламентныеЗаданияСервер.ИзменитьЗадание(Задание.УникальныйИдентификатор,
Новый Структура("Использование", Ложь));
КонецЦикла;
Текст = НСтр("ru = 'Регламентное задание недоступно по функциональным опциям или
|не поддерживает работу в текущем режиме работы.
|Выполнение прервано. Задание отключено.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
КонецЕсли;
Если СтандартныеПодсистемыСервер.ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы() Тогда
Текст = НСтр("ru = 'Регламентное задание недоступно до установки начальных региональных настроек приложения.
|Выполнение прервано.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
Справочники.ВерсииРасширений.ЗарегистрироватьИспользованиеВерсииРасширений();
РегистрыСведений.ПараметрыРаботыВерсийРасширений.ПриУспешномНачалеВыполненияРегламентногоЗадания();
КонецПроцедуры
// Переводит параметры сеанса в состояние "Не установлено".
//
// Параметры:
// ПараметрыДляОчистки - Строка - имена параметров сеанса для очистки, разделенные ",".
// Исключения - Строка - имена параметров сеанса не предназначенные для очистки, разделенные ",".
//
Процедура ОчиститьПараметрыСеанса(ПараметрыДляОчистки = "", Исключения = "") Экспорт
МассивИсключений = СтрРазделить(Исключения, ",");
МассивПараметровДляОчистки = СтрРазделить(ПараметрыДляОчистки, ",", Ложь);
Если МассивПараметровДляОчистки.Количество() = 0 Тогда
Для Каждого ПараметрСеанса Из Метаданные.ПараметрыСеанса Цикл
Если МассивИсключений.Найти(ПараметрСеанса.Имя) = Неопределено Тогда
МассивПараметровДляОчистки.Добавить(ПараметрСеанса.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Индекс = МассивПараметровДляОчистки.Найти("ПараметрыКлиентаНаСервере");
Если Индекс <> Неопределено Тогда
МассивПараметровДляОчистки.Удалить(Индекс);
КонецЕсли;
Индекс = МассивПараметровДляОчистки.Найти("ОсновнойЯзык");
Если Индекс <> Неопределено Тогда
МассивПараметровДляОчистки.Удалить(Индекс);
КонецЕсли;
Индекс = МассивПараметровДляОчистки.Найти("УстановленныеРасширения");
Если Индекс <> Неопределено Тогда
МассивПараметровДляОчистки.Удалить(Индекс);
КонецЕсли;
ПараметрыСеанса.Очистить(МассивПараметровДляОчистки);
КонецПроцедуры
// Проверяет, умещаются ли переданные табличные документы на страницу при печати.
//
// Параметры:
// ТабДокумент - ТабличныйДокумент - табличный документ.
// ВыводимыеОбласти - Массив
// - ТабличныйДокумент - массив из проверяемых таблиц или табличный документ.
// РезультатПриОшибке - Булево - какой возвращать результат при возникновении ошибки.
//
// Возвращаемое значение:
// Булево - умещаются или нет переданные документы.
//
Функция ПроверитьВыводТабличногоДокумента(ТабДокумент, ВыводимыеОбласти, РезультатПриОшибке = Истина) Экспорт
Попытка
Возврат ТабДокумент.ПроверитьВывод(ВыводимыеОбласти);
Исключение
Возврат РезультатПриОшибке;
КонецПопытки;
КонецФункции
// Сохраняет персональные настройки пользователя, относящиеся к подсистеме БазоваяФункциональность.
// Для получения настроек предусмотрены следующие функции:
// - СтандартныеПодсистемыСервер.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы,
// - СтандартныеПодсистемыСервер.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы,
// - ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботы1СПредприятия.
//
// Параметры:
// Настройки - Структура:
// * НапоминатьОбУстановкеРасширенияРаботыСФайлами - Булево - если Истина, то напоминать об установке
// расширения для работы с 1С:Предприятием в веб-клиенте.
// * ЗапрашиватьПодтверждениеПриЗавершенииПрограммы - Булево - запрашивать подтверждение по завершении работы.
// * ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы - Булево - показывать оповещение при
// динамическом обновлении приложения.
//
Процедура СохранитьПерсональныеНастройки(Настройки) Экспорт
Если Настройки.Свойство("НапоминатьОбУстановкеРасширенияРаботыСФайлами") Тогда
Если ЭтоВебКлиент() Тогда
ИдентификаторКлиента = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИдентификаторКлиента");
Если ИдентификаторКлиента = Неопределено Тогда
СистемнаяИнформация = Новый СистемнаяИнформация;
ИдентификаторКлиента = СистемнаяИнформация.ИдентификаторКлиента;
КонецЕсли;
ХранилищеОбщихНастроекСохранить(
"НастройкиПрограммы/ПредлагатьУстановкуРасширенияРаботыСФайлами",
ИдентификаторКлиента, Настройки.НапоминатьОбУстановкеРасширенияРаботыСФайлами);
КонецЕсли;
КонецЕсли;
Если Настройки.Свойство("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы") Тогда
ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя",
"ЗапрашиватьПодтверждениеПриЗавершенииПрограммы",
Настройки.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы);
КонецЕсли;
Если Настройки.Свойство("ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы") Тогда
ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя",
"ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы",
Настройки.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы);
КонецЕсли;
КонецПроцедуры
// Выполняет пропорциональное распределение суммы в соответствии
// с заданными коэффициентами распределения.
//
// Параметры:
// РаспределяемаяСумма - Число - сумма, которую надо распределить, если сумма равна 0 - то возвращается Неопределено;
// Если передана отрицательная - расчет по модулю и после инверсия знаков результата.
// Коэффициенты - Массив из Число - коэффициенты распределения, должны быть положительны или отрицательными
// одновременно.
// Точность - Число - точность округления при распределении.
//
// Возвращаемое значение:
// Массив из Число - массив размерностью равный массиву коэффициентов, содержит
// суммы в соответствии с весом коэффициента (из массива коэффициентов).
// В случае, если распределить невозможно (кол-во коэффициентов = 0
// есть коэффициенты с отрицательным значением или суммарный вес коэффициентов = 0),
// тогда будет возвращено Неопределено.
//
// Пример:
//
// Коэффициенты = Новый Массив;
// Коэффициенты.Добавить(1);
// Коэффициенты.Добавить(2);
// Результат = ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам(1, Коэффициенты);
// // Результат = [0.33, 0.67]
//
Функция РаспределитьСуммуПропорциональноКоэффициентам(
Знач РаспределяемаяСумма, Коэффициенты, Знач Точность = 2) Экспорт
Возврат ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам(
РаспределяемаяСумма, Коэффициенты, Точность);
КонецФункции
// Процедура предназначена для заполнения реквизита формы типа ДанныеФормыДерево.
//
// Параметры:
// КоллекцияЭлементовДерева - ДанныеФормыКоллекцияЭлементовДерева - реквизит, который нужно заполнить.
// ДеревоЗначений - ДеревоЗначений - данные для заполнения.
//
Процедура ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(КоллекцияЭлементовДерева, ДеревоЗначений) Экспорт
Для Каждого СтрокаТаблицы Из ДеревоЗначений.Строки Цикл
ЭлементДерева = КоллекцияЭлементовДерева.Добавить();
ЗаполнитьЗначенияСвойств(ЭлементДерева, СтрокаТаблицы);
Если СтрокаТаблицы.Строки.Количество() > 0 Тогда
ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(ЭлементДерева.ПолучитьЭлементы(), СтрокаТаблицы);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Подключает внешнюю компоненту, выполненную по технологии Native API или COM,
// из макета конфигурации (хранится в виде ZIP-архива).
//
// Параметры:
// Идентификатор - Строка - идентификатор объекта внешней компоненты.
// ПолноеИмяМакета - Строка - полное имя макета конфигурации с ZIP-архивом.
// Изолированно - Булево - если Истина, компонента должна подключаться изолированно,
// в этом случае она загружается в отдельный процесс операционной системы.
// Если Ложь, то в этом случае компонента будет выполняться в том же процессе
// операционной системы, который выполняет код встроенного языка.
// - Неопределено - (по умолчанию Неопределено) соответствует поведению платформы:
// не изолированно - если компонентой поддерживается только этот режим,
// изолированно - в остальных случаях.
// См. https://its.1c.eu/db/v83doc#bookmark:dev:TI000001866
//
// Возвращаемое значение:
// - ОбъектВнешнейКомпоненты - экземпляр объекта внешней компоненты.
// - Неопределено - если не удалось создать.
//
// Пример:
//
// ПодключаемыйМодуль = ОбщегоНазначения.ПодключитьКомпонентуИзМакета(
// "QRCodeExtension",
// "ОбщийМакет.КомпонентаПечатиQRКода");
//
// Если ПодключаемыйМодуль <> Неопределено Тогда
// // ПодключаемыйМодуль содержит созданный экземпляр подключенной компоненты.
// КонецЕсли;
//
// ПодключаемыйМодуль = Неопределено;
//
Функция ПодключитьКомпонентуИзМакета(Знач Идентификатор, Знач ПолноеИмяМакета, Знач Изолированно = Неопределено) Экспорт
РезультатПроверкиВнешнейКомпоненты = Неопределено;
Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда
МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный");
РезультатПроверкиВнешнейКомпоненты = МодульВнешниеКомпонентыСлужебный.ПроверитьПодключениеКомпоненты(Идентификатор);
РезультатПроверкиВнешнейКомпоненты.Вставить("Доступна",
Не ЗначениеЗаполнено(РезультатПроверкиВнешнейКомпоненты.ОписаниеОшибки));
КонецЕсли;
КомпонентаПоследнейВерсии = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии(
Идентификатор, ПолноеИмяМакета, РезультатПроверкиВнешнейКомпоненты);
Результат = ПодключитьКомпонентуПоИдентификатору(Идентификатор,
КомпонентаПоследнейВерсии.Местоположение, Изолированно);
Возврат Результат.ПодключаемыйМодуль;
КонецФункции
#КонецОбласти
#Область ПереходныеПроцедурыИФункции
// Проверяет, что указанный режим соответствует добавлению набора записей.
//
// Параметры:
// Режим - Булево, РежимЗамещения
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоДобавлениеНабораЗаписей(Режим) Экспорт
Значение = СтандартныеПодсистемыПовтИсп.РежимДобавленияНабораЗаписей();
Возврат Значение <> Неопределено И Режим = Значение;
КонецФункции
// Проверяет, что указанный режим соответствует замещению набора записей.
//
// Параметры:
// Режим - Булево, РежимЗамещения
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоЗамещениеНабораЗаписей(Режим) Экспорт
Значение = СтандартныеПодсистемыПовтИсп.РежимЗамещенияНабораЗаписей();
Возврат Значение <> Неопределено И Режим = Значение;
КонецФункции
// Проверяет, что указанный режим соответствует обновлению набора записей.
//
// Параметры:
// Режим - Булево, РежимЗамещения
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоОбновлениеНабораЗаписей(Режим) Экспорт
Значение = СтандартныеПодсистемыПовтИсп.РежимОбновленияНабораЗаписей();
Возврат Значение <> Неопределено И Режим = Значение;
КонецФункции
// Проверяет, что указанный режим соответствует слиянию набора записей.
//
// Параметры:
// Режим - Булево, РежимЗамещения
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоСлияниеНабораЗаписей(Режим) Экспорт
Значение = СтандартныеПодсистемыПовтИсп.РежимСлиянияНабораЗаписей();
Возврат Значение <> Неопределено И Режим = Значение;
КонецФункции
// Проверяет, что указанный режим соответствует удалению набора записей.
//
// Параметры:
// Режим - Булево, РежимЗамещения
//
// Возвращаемое значение:
// Булево
//
Функция ЭтоУдалениеНабораЗаписей(Режим) Экспорт
Значение = СтандартныеПодсистемыПовтИсп.РежимУдаленияНабораЗаписей();
Возврат Значение <> Неопределено И Режим = Значение;
КонецФункции
// Возвращает РежимЗамещения.Обновление или Неопределено,
// если не поддерживается в текущей версии 1С:Предприятия.
//
// Возвращаемое значение:
// Неопределено, РежимЗамещения
//
Функция РежимОбновленияНабораЗаписей() Экспорт
Возврат СтандартныеПодсистемыПовтИсп.РежимОбновленияНабораЗаписей();
КонецФункции
// Возвращает РежимЗамещения.Слияние или Неопределено,
// если не поддерживается в текущей версии 1С:Предприятия.
//
// Возвращаемое значение:
// - Неопределено
// - РежимЗамещения
//
Функция РежимСлиянияНабораЗаписей() Экспорт
Возврат СтандартныеПодсистемыПовтИсп.РежимСлиянияНабораЗаписей();
КонецФункции
// Возвращает РежимЗамещения.Удаление или Неопределено,
// если не поддерживается в текущей версии 1С:Предприятия.
//
// Возвращаемое значение:
// - Неопределено
// - РежимЗамещения
//
Функция РежимУдаленияНабораЗаписей() Экспорт
Возврат СтандартныеПодсистемыПовтИсп.РежимУдаленияНабораЗаписей();
КонецФункции
#КонецОбласти
#Область РаботаСоСтатусамиИВажнымиСообщениями
// Добавляет важное сообщение для привлечения внимания пользователя с размещением в шапке формы.
// Данная процедура только дополняет список сообщений, которые необходимо показать
// пользователю и не выводит его непосредственно на форму.
//
// При повторном добавлении сообщения с уже существующим идентификатором предыдущее будет удалено.
//
// Вывод важных сообщений на форму осуществляется при помощи процедуры ОбщегоНазначения.ВывестиСтатусыИВажныеСообщенияНаФорму,
// подробнее про использование см. в описании к ней.
//
// Параметры:
// Форма - ФормаКлиентскогоПриложения
// Параметры - см. ОбщегоНазначения.ПараметрыВажногоСообщения
//
Процедура ДобавитьВажноеСообщение(Форма, Параметры) Экспорт
НезаполненныеПараметры = Новый Массив;
Если Не ЗначениеЗаполнено(Параметры.ТипСообщения) Тогда
НезаполненныеПараметры.Добавить("ТипСообщения");
КонецЕсли;
Если Не ЗначениеЗаполнено(Параметры.Сообщение) Тогда
НезаполненныеПараметры.Добавить("Сообщение");
КонецЕсли;
Если Не ЗначениеЗаполнено(Параметры.КраткоеПредставление)
И Не ЗначениеЗаполнено(Параметры.Родитель) Тогда
НезаполненныеПараметры.Добавить("КраткоеПредставление");
КонецЕсли;
Если НезаполненныеПараметры.Количество() > 0 Тогда
ТекстОшибки = НСтр("ru = 'Некорректный вызов процедуры добавления важного сообщения. Не заполнены обязательные параметры:
|%1'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НезаполненныеПараметры, ", "));
КонецЕсли;
Проверка = Новый Структура("БФ_ДобавляемыеВажныеСообщения, БФ_КонтрольнаяСумма", "Проверка", "Проверка");
ЗаполнитьЗначенияСвойств(Проверка, Форма);
Если Проверка.БФ_ДобавляемыеВажныеСообщения = "Проверка" Тогда
Реквизиты = Новый Массив;
Реквизиты.Добавить(Новый РеквизитФормы("БФ_ДобавляемыеВажныеСообщения", Новый ОписаниеТипов("СписокЗначений")));
Реквизиты.Добавить(Новый РеквизитФормы("БФ_ОбработчикиКомандВажногоСообщения", Новый ОписаниеТипов()));
Реквизиты.Добавить(Новый РеквизитФормы("БФ_ВсегоВажныхСообщений", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный))));
Если Проверка.БФ_КонтрольнаяСумма = "Проверка" Тогда
Реквизиты.Добавить(Новый РеквизитФормы("БФ_КонтрольнаяСумма", Новый ОписаниеТипов("Строка")));
КонецЕсли;
Форма.ИзменитьРеквизиты(Реквизиты);
Форма.БФ_ОбработчикиКомандВажногоСообщения = Новый Структура;
КонецЕсли;
Если ТипЗнч(Параметры.Сообщение) = Тип("ФорматированнаяСтрока") И ЗначениеЗаполнено(Параметры.Обработчик) Тогда
ИмяОбработчикаЧастями = СтрРазделить(Параметры.Обработчик, ".");
// Если в качестве обработчика передана процедура формы, то сохранять параметры не требуется,
// т.к. процедура будет обработчиком элемента формы и ссылка будет передана штатно платформой.
Если ИмяОбработчикаЧастями.Количество() > 1 Тогда
Строка = ЗначениеВСтрокуВнутр(Параметры.Сообщение);
РегулярноеВыражение = "]+)>";
РезультатыПоиска = СтрНайтиВсеПоРегулярномуВыражению(Строка, РегулярноеВыражение);
Для Каждого РезультатПоиска Из РезультатыПоиска Цикл
Ссылка = СокрЛП(СтрЗаменить(СтрЗаменить(РезультатПоиска.Значение, "", ""));
Ссылка = СтандартныеПодсистемыСервер.ПреобразоватьСтрокуВДопустимоеНаименованиеКолонки(Ссылка);
Форма.БФ_ОбработчикиКомандВажногоСообщения.Вставить(Ссылка, Параметры.Обработчик);
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если Параметры.ПараметрыДействия <> Неопределено Тогда
Если ТипЗнч(Параметры.ПараметрыДействия) <> Тип("Массив") Тогда
ПараметрыДействияВажногоСообщения = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Параметры.ПараметрыДействия);
Иначе
ПараметрыДействияВажногоСообщения = Параметры.ПараметрыДействия;
КонецЕсли;
Для Каждого ОписаниеДействия Из ПараметрыДействияВажногоСообщения Цикл
Форма.БФ_ОбработчикиКомандВажногоСообщения.Вставить(ОписаниеДействия.ИмяКоманды, ОписаниеДействия.Обработчик);
КонецЦикла;
КонецЕсли;
Если ЗначениеЗаполнено(Параметры.Идентификатор) Тогда
Для Каждого Элемент Из Форма.БФ_ДобавляемыеВажныеСообщения Цикл
Если Элемент.Значение.Идентификатор = Параметры.Идентификатор Тогда
Элемент.Значение = Параметры;
Возврат;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Форма.БФ_ДобавляемыеВажныеСообщения.Добавить(Параметры);
КонецПроцедуры
// Добавляет контекстное важное сообщение для привлечения внимания пользователя с размещением в указанном месте на форме.
// Важно: Контекстно в группу можно вставить только одно сообщение.
//
// Данная процедура только дополняет список сообщений, которые необходимо показать
// пользователю и не выводит его непосредственно на форму.
//
// При повторном добавлении сообщения с уже существующим идентификатором предыдущее будет удалено.
//
// Вывод важных сообщений на форму осуществляется при помощи процедуры ОбщегоНазначения.ВывестиСтатусыИВажныеСообщенияНаФорму,
// подробнее про использование см. в описании к ней.
//
// Параметры:
// Форма - ФормаКлиентскогоПриложения
// Параметры - см. ОбщегоНазначения.ПараметрыВажногоСообщения
// Родитель - Строка
// - ГруппаФормы - имя группы, в которой разместить сообщение.
// Элемент - Строка
// - ДекорацияФормы
// - ГруппаФормы
// - КнопкаФормы
// - ТаблицаФормы
// - ПолеФормы - элемент, перед которым должно быть вставлено важное сообщение.
//
Процедура ВставитьВажноеСообщение(Форма, Параметры, Родитель, Элемент = Неопределено) Экспорт
Если ТипЗнч(Родитель) = Тип("Строка") Тогда
Параметры.Родитель = Родитель;
ИначеЕсли Родитель <> Неопределено Тогда
Параметры.Родитель = Родитель.Имя;
КонецЕсли;
Если ТипЗнч(Элемент) = Тип("Строка") Тогда
Параметры.Элемент = Элемент;
ИначеЕсли Элемент <> Неопределено Тогда
Параметры.Элемент = Элемент.Имя;
КонецЕсли;
ДобавитьВажноеСообщение(Форма, Параметры);
КонецПроцедуры
// Коллекция параметров для настройки важного сообщения.
//
// Возвращаемое значение:
// Структура:
// * ТипСообщения - Строка - возможны значения Ошибка, Предупреждение, Информация, Успех. Заполнять обязательно.
// * Идентификатор - Строка - идентификатор сообщения, который будет использоваться для
// обновления информации или удаления сообщения при перечитывании данных формы.
// Необходимо заполнять, если требуется обновлять или удалять важное сообщение при работе пользователя
// или если добавление сообщения может выполняться не только в событии ПриСозданииНаСервере, в остальных
// случаях необязательно.
// * Заголовок - Строка - заголовок важного сообщения.
// * Сообщение - Строка, ФорматированнаяСтрока - содержимое сообщения, заполнять обязательно.
// * КраткоеПредставление - Строка - краткое и понятное описание сути проблемы.
// Использование обобщающих формулировок вида "Найдены проблемы" не допускается, вместо
// этого правильно будет написать, например, "Проблемы проверки учета".
// Рекомендуемая длина до 30 символов, максимум - 38.
// Обязательно заполнять для сообщений, выводимых в шапке формы процедурой ДобавитьВажноеСообщение.
// * Обработчик - Строка - нужно указывать, если передана форматированная строка. Варианты:
// 1) Процедура модуля формы, состав параметров как у события ОбработкаНавигационнойСсылки.
// 2) Процедура клиентского общего модуля с параметрами:
// # Форма - ФормаКлиентскогоПриложения
// # Ссылка - Строка - ссылка из форматированной строки.
// * ОбработчикЗакрытия - обработчик нажатия на кнопку закрытия сообщения. Для работы требуется заполнить свойство Идентификатор.
// Важно: Закрытие сообщения в необходимо делать самостоятельно вызовом процедуры ОбщегоНазначенияКлиентСервер.УдалитьСтатусИлиВажноеСообщение.
// Возможные варианты:
// 1) Процедура модуля формы, состав параметров как у обработчика команды.
// 2) Процедура клиентского общего модуля с параметрами:
// # Форма - ФормаКлиентскогоПриложения
// # Идентификатор - Строка - идентификатор важного сообщения.
// * Скрываемый - Булево - можно ли скрыть важное сообщение нажатием на "х". По умолчанию - Истина.
// * ПараметрыДействия - см. ОбщегоНазначения.ПараметрыДействияВажногоСообщения
// - Массив из см. ОбщегоНазначения.ПараметрыДействияВажногоСообщения
//
Функция ПараметрыВажногоСообщения() Экспорт
Параметры = Новый Структура;
Параметры.Вставить("ТипСообщения", "Предупреждение");
Параметры.Вставить("Скрываемый", Истина);
Параметры.Вставить("Идентификатор", "");
Параметры.Вставить("Заголовок", "");
Параметры.Вставить("Сообщение", "");
Параметры.Вставить("КраткоеПредставление", "");
Параметры.Вставить("Обработчик", "");
Параметры.Вставить("ОбработчикЗакрытия", "");
Параметры.Вставить("ПараметрыДействия", Неопределено);
Параметры.Вставить("Родитель", Неопределено); // Для внутреннего использования.
Параметры.Вставить("Элемент", Неопределено); // Для внутреннего использования.
Возврат Параметры;
КонецФункции
// Коллекция параметров для настройки команд, выводимых в важном сообщении.
//
// Возвращаемое значение:
// Структура:
// * ИмяКоманды - Строка - имя команды. Рекомендуется подбирать уникальное имя, которое не пересечется с другими командами.
// * Обработчик - Строка - процедура-обработчик команды формы, возможные варианты:
// 1) Процедура модуля формы, состав параметров как у обработчика команды.
// 2) Процедура клиентского общего модуля с параметрами:
// # Форма - ФормаКлиентскогоПриложения
// # Ссылка - Строка - значение из свойства ИмяКоманды.
// * Заголовок - Строка
//
Функция ПараметрыДействияВажногоСообщения() Экспорт
ПараметрыДействия = Новый Структура;
ПараметрыДействия.Вставить("ИмяКоманды", "");
ПараметрыДействия.Вставить("Обработчик", "");
ПараметрыДействия.Вставить("Заголовок", "");
Возврат ПараметрыДействия;
КонецФункции
// Добавляет статус на форму.
// Например, для отображения текущего статуса заказа покупателя.
//
// При повторном добавлении статуса с уже существующим идентификатором предыдущий будет удален.
//
// Вывод статуса на форму осуществляется при помощи процедуры ОбщегоНазначения.ВывестиСтатусыИВажныеСообщенияНаФорму,
// подробнее про использование см. в описании к ней.
//
// Параметры:
// Форма - ФормаКлиентскогоПриложения
// Параметры - см. ОбщегоНазначения.ПараметрыСтатуса
//
Процедура ДобавитьСтатус(Форма, Параметры) Экспорт
НезаполненныеПараметры = Новый Массив;
Если Не ЗначениеЗаполнено(Параметры.Наименование) Тогда
НезаполненныеПараметры.Добавить("Наименование");
КонецЕсли;
Если Не ЗначениеЗаполнено(Параметры.Идентификатор) Тогда
НезаполненныеПараметры.Добавить("Идентификатор");
КонецЕсли;
Если НезаполненныеПараметры.Количество() > 0 Тогда
ТекстОшибки = НСтр("ru = 'Некорректный вызов процедуры добавления статуса. Не заполнены обязательные параметры:
|%1'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НезаполненныеПараметры, ", "));
КонецЕсли;
Проверка = Новый Структура("БФ_ДобавляемыеСтатусы, БФ_КонтрольнаяСумма", "Проверка", "Проверка");
ЗаполнитьЗначенияСвойств(Проверка, Форма);
Если Проверка.БФ_ДобавляемыеСтатусы = "Проверка" Тогда
Реквизиты = Новый Массив;
Реквизиты.Добавить(Новый РеквизитФормы("БФ_ДобавляемыеСтатусы", Новый ОписаниеТипов("СписокЗначений")));
Реквизиты.Добавить(Новый РеквизитФормы("БФ_ОбработчикиСтатусов", Новый ОписаниеТипов()));
Реквизиты.Добавить(Новый РеквизитФормы("БФ_ВсегоСтатусов", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный))));
Если Проверка.БФ_КонтрольнаяСумма = "Проверка" Тогда
Реквизиты.Добавить(Новый РеквизитФормы("БФ_КонтрольнаяСумма", Новый ОписаниеТипов("Строка")));
КонецЕсли;
Форма.ИзменитьРеквизиты(Реквизиты);
Форма.БФ_ОбработчикиСтатусов = Новый Структура;
КонецЕсли;
Для Каждого Элемент Из Форма.БФ_ДобавляемыеСтатусы Цикл
Если Элемент.Значение.Идентификатор = Параметры.Идентификатор Тогда
Элемент.Значение = Параметры;
Возврат;
КонецЕсли;
КонецЦикла;
Форма.БФ_ДобавляемыеСтатусы.Добавить(Параметры);
КонецПроцедуры
// Коллекция параметров для настройки выводимого на форму статуса.
//
// Возвращаемое значение:
// Структура:
// * Наименование - Строка, ФорматированнаяСтрока - представление статуса. Рекомендуемая длина до 15 символов.
// Заполнять обязательно. Форматированную строку допустимо использовать только для
// оформления цвета статуса, добавление гиперссылок не поддерживается. Пример
// использования: СтроковыеФункции.ФорматированнаяСтрока(
// НСтр("ru = 'Состояние: зарегистрирован'"));
// * Идентификатор - Строка - идентификатор статуса, должен удовлетворять требованиям, предъявляемым
// к именованию переменных встроенного языка. Заполнять обязательно.
// * Картинка - Картинка - картинка статуса.
// * Порядок - Число, Неопределено - порядок вывода статуса на форме. Статусы будут выводиться по
// возрастанию значения. По умолчанию - Неопределено, в порядке добавления
// на форму.
// * Обработчик - Строка - обработчик нажатия на гиперссылку статуса.
// Если не заполнен, то статус выводится обычной надписью. Варианты:
// 1) Процедура модуля формы, состав параметров как у события Нажатие у элемента ДекорацияФормы.
// 2) Процедура клиентского общего модуля с параметрами:
// # Форма - ФормаКлиентскогоПриложения
// # Параметры - Структура:
// * Идентификатор - Строка - идентификатор статуса.
// * Родитель - ГруппаФормы - элемент формы, к которому привязывается
// расшифровка статуса.
//
Функция ПараметрыСтатуса() Экспорт
Параметры = Новый Структура;
Параметры.Вставить("Наименование", "");
Параметры.Вставить("Идентификатор", Неопределено);
Параметры.Вставить("Картинка", Неопределено);
Параметры.Вставить("Порядок", Неопределено);
Параметры.Вставить("Обработчик", "");
Возврат Параметры;
КонецФункции
// Выводит на форму статусы и важные сообщения для привлечения внимания пользователя.
//
// Внешний вид важных сообщений зависит от их количества:
// - Если было добавлено только одно сообщение, то оно отображается целиком и
// дополнительно выделяется цветом в зависимости от значения свойства ТипСообщения.
// - Если сообщений добавлено больше одного, то они выводятся одной строкой в виде
// кратких представлений с отображением подробностей по нажатии на них.
//
// Для удаления ранее выведенного на форму статуса или сообщения можно воспользоваться процедурой
// см. ОбщегоНазначенияКлиентСервер.УдалитьСтатусИлиВажноеСообщение.
//
// Использование:
// 1) Вызывать необходимо разово, в конце события ПриСозданииНаСервере, при необходимости можно
// добавить дополнительные вызовы для обновления состояния статусов и важных сообщений после некоторых действий пользователя.
//
// 2)Для корректной работы так же необходимо добавить подключаемый обработчик события формы:
//
// &НаКлиенте
// Процедура Подключаемый_ОбработатьДействиеИнформационногоСообщения(ЭлементИлиКоманда, НавигационнаяСсылка = Неопределено, СтандартнаяОбработка = Неопределено)
// ОбщегоНазначенияКлиент.ОбработатьДействиеИнформационногоСообщения(ЭтотОбъект, ЭлементИлиКоманда, НавигационнаяСсылка, СтандартнаяОбработка);
// КонецПроцедуры
//
// Параметры:
// Форма - ФормаКлиентскогоПриложения
//
Процедура ВывестиСтатусыИВажныеСообщенияНаФорму(Форма) Экспорт
Проверка = Новый Массив;
ПроверкаВажныеСообщения = Новый Структура;
ПроверкаВажныеСообщения.Вставить("БФ_ДобавляемыеВажныеСообщения");
ЗаполнитьЗначенияСвойств(ПроверкаВажныеСообщения, Форма);
ЕстьВажныеСообщения = (ПроверкаВажныеСообщения.БФ_ДобавляемыеВажныеСообщения <> Неопределено
И Форма.БФ_ДобавляемыеВажныеСообщения.Количество() <> 0);
Если ЕстьВажныеСообщения Тогда
Проверка.Добавить(Форма.БФ_ДобавляемыеВажныеСообщения);
КонецЕсли;
ПроверкаСтатусы = Новый Структура;
ПроверкаСтатусы.Вставить("БФ_ДобавляемыеСтатусы");
ЗаполнитьЗначенияСвойств(ПроверкаСтатусы, Форма);
ЕстьСтатусы = (ПроверкаСтатусы.БФ_ДобавляемыеСтатусы <> Неопределено
И Форма.БФ_ДобавляемыеСтатусы.Количество() <> 0);
Если ЕстьСтатусы Тогда
Проверка.Добавить(Форма.БФ_ДобавляемыеСтатусы);
КонецЕсли;
Если Не ЕстьВажныеСообщения И Не ЕстьСтатусы Тогда
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(Форма.БФ_КонтрольнаяСумма)
Или Форма.БФ_КонтрольнаяСумма <> КонтрольнаяСуммаСтрокой(Проверка) Тогда
Форма.БФ_КонтрольнаяСумма = КонтрольнаяСуммаСтрокой(Проверка);
ИначеЕсли Форма.БФ_КонтрольнаяСумма = КонтрольнаяСуммаСтрокой(Проверка) Тогда
Возврат;
КонецЕсли;
РодительскаяГруппа = Форма.Элементы.Найти("БФ_ГруппаВажныеСообщенияИСтатусы");
Если РодительскаяГруппа <> Неопределено Тогда
Форма.Элементы.Удалить(РодительскаяГруппа);
КонецЕсли;
ПодчиненныеЭлементы = Форма.ПодчиненныеЭлементы;
Если ПодчиненныеЭлементы.Количество() = 0 Тогда
ПервыйЭлемент = Неопределено;
Иначе
ПервыйЭлемент = ПодчиненныеЭлементы[0];
КонецЕсли;
ОбщиеПараметры = ОбщиеПараметрыБазовойФункциональности();
РодительскаяГруппа = Форма.Элементы.Вставить("БФ_ГруппаВажныеСообщенияИСтатусы", Тип("ГруппаФормы"), Форма, ПервыйЭлемент);
РодительскаяГруппа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
РодительскаяГруппа.ОтображатьЗаголовок = Ложь;
РодительскаяГруппа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
Если Не ОбщегоНазначенияКлиентСервер.ЭтоВариантИнтерфейса85()
И Не ОбщиеПараметры.ГруппироватьСтатусыИВажныеСообщенияГоризонтально Тогда
РодительскаяГруппа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
КонецЕсли;
// Вывод статусов.
Если ЕстьСтатусы Тогда
ВывестиСтатусыНаФорму(Форма, РодительскаяГруппа);
КонецЕсли;
Если Не ЕстьВажныеСообщения Тогда
Возврат;
КонецЕсли;
// Группа для важных сообщений.
ГруппаРазмещенияВажныхСообщений = Форма.Элементы.Найти("БФ_ГруппаСообщенияШапки");
Если ГруппаРазмещенияВажныхСообщений <> Неопределено Тогда
// Повторный вывод сообщения.
Форма.Элементы.Удалить(ГруппаРазмещенияВажныхСообщений);
КонецЕсли;
ГруппаРазмещенияВажныхСообщений = НоваяГруппаВажногоСообщения(Форма, "БФ_ГруппаСообщенияШапки", РодительскаяГруппа);
ГруппаРазмещенияВажныхСообщений.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ВсегоВажныхСообщений = Форма.БФ_ДобавляемыеВажныеСообщения.Количество();
// Вывод контекстных важных сообщений.
ВывестиКонтекстноеВажноеСообщение(Форма, ВсегоВажныхСообщений);
Если ВсегоВажныхСообщений = 0 Тогда
Возврат;
КонецЕсли;
// Вывод одиночного сообщения.
Если ВсегоВажныхСообщений = 1 Тогда
ВывестиОдиночноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений);
Возврат;
КонецЕсли;
СгруппированныеСообщения = НоваяТаблицаСгруппированныхСообщений();
СгруппироватьСообщения(СгруппированныеСообщения, Форма.БФ_ДобавляемыеВажныеСообщения);
ГруппаРазмещенияВажныхСообщений.Группировка = ГруппировкаПодчиненныхЭлементовФормы.АвтоматическиУчитыватьВидЭкрана;
ГруппаРазмещенияВажныхСообщений.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Авто;
ГруппаРазмещенияВажныхСообщений.РастягиватьПоГоризонтали = Истина;
ГруппаРазмещенияВажныхСообщений.ОтображатьКакКарточку = Истина;
// Вывод агрегированного сообщения, когда важных сообщений больше одного.
ВывестиАгрегированноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений, СгруппированныеСообщения, ЕстьСтатусы);
// Добавление группы со списком всех важных сообщений.
ВывестиГруппуПоказатьВсеВажныеСообщения(Форма, СгруппированныеСообщения, ГруппаРазмещенияВажныхСообщений);
Форма.БФ_ВсегоВажныхСообщений = СгруппированныеСообщения.Количество();
КонецПроцедуры
#КонецОбласти
#Область УстаревшиеПроцедурыИФункции
// Устарела. Следует использовать ОбщегоНазначения.ЭтоMacOSКлиент
// Возвращает Истина, если клиентское приложение запущено под управлением ОС X.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоOSXКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент");
Если ЭтоMacOSКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоMacOSКлиент;
КонецФункции
#КонецОбласти
#КонецЕсли
#КонецОбласти
#Если НЕ МобильныйАвтономныйСервер Тогда
#Область СлужебныйПрограммныйИнтерфейс
// Выгружает запрос в строку XML, которую можно вставить в Консоль запросов.
// Для переноса запроса и всех его параметров в Консоль запросов, необходимо вызвать функцию в окне.
// "Вычислить выражение" (Shift + F9), скопировать полученный XML в поле "Текст запроса"
// консоли запросов и выполнить команду "Заполнить из XML" из меню "Еще".
// Подробнее об использование функции смотрите в справке к консоли запросов.
//
// Параметры:
// Запрос - Запрос - запрос, который необходимо выгрузить в формат строки XML.
//
// Возвращаемое значение:
// Строка - строка в формате XML, которую можно извлечь при помощи метода "ОбщегоНазначения.ЗначениеИзСтрокиXML".
// После извлечения получится объект типа "Структура" с полями:
// * Текст - Строка - текст запроса.
// * Параметры - Структура - параметры запроса.
//
Функция ЗапросВСтрокуXML(Запрос) Экспорт // АПК:299 - используется при отладке запросов, см. описание функции.
Структура = Новый Структура("Текст, Параметры");
ЗаполнитьЗначенияСвойств(Структура, Запрос);
Возврат ЗначениеВСтрокуXML(Структура);
КонецФункции
Функция ПодключитьКомпонентуПоИдентификатору(Знач Идентификатор, Знач Местоположение, Знач Изолированно = Неопределено) Экспорт
ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение);
Результат = Новый Структура;
Результат.Вставить("Подключено", Ложь);
Результат.Вставить("ПодключаемыйМодуль", Неопределено);
Результат.Вставить("ОписаниеОшибки", "");
Попытка
#Если МобильноеПриложениеСервер Тогда
РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName");
#Иначе
РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName",,
ОбщегоНазначенияСлужебныйКлиентСервер.ТипПодключенияКомпоненты(Изолированно));
#КонецЕсли
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине:'"),
Идентификатор);
Результат.ОписаниеОшибки = ЗаголовокОшибки + Символы.ПС
+ ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
КомментарийДляЖурнала = ЗаголовокОшибки + Символы.ПС
+ ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)
+ СистемнаяИнформацияДляЖурналаРегистрации();
ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка,,, КомментарийДляЖурнала);
Возврат Результат;
КонецПопытки;
Если Не РезультатПодключения Тогда
ОшибкаСовместимостиКомпонентыИзМакета = ОшибкаСовместимостиКомпонентыИзМакета(Местоположение);
Если ЗначениеЗаполнено(ОшибкаСовместимостиКомпонентыИзМакета) Тогда
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине:
|%2.
|Техническая информация:
|%3
|Метод %4 вернул Ложь.'"), Идентификатор, ОшибкаСовместимостиКомпонентыИзМакета, Местоположение,
"ПодключитьВнешнююКомпоненту");
Иначе
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере.
|Техническая информация:
|%2
|Метод %3 вернул Ложь.'"), Идентификатор, Местоположение, "ПодключитьВнешнююКомпоненту");
КонецЕсли;
Попытка
ВызватьИсключение НСтр("ru = 'Стек вызовов:'")
Исключение
КомментарийДляЖурнала = Результат.ОписаниеОшибки + Символы.ПС + Символы.ПС
+ ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())
+ СистемнаяИнформацияДляЖурналаРегистрации();
КонецПопытки;
ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка,,, КомментарийДляЖурнала);
Возврат Результат;
КонецЕсли;
ПодключаемыйМодуль = Неопределено;
Попытка
ПодключаемыйМодуль = Новый("AddIn." + Идентификатор + "SymbolicName" + "." + Идентификатор);
Если ПодключаемыйМодуль = Неопределено Тогда
ВызватьИсключение НСтр("ru = 'Оператор Новый вернул Неопределено'");
КонецЕсли;
Исключение
ПодключаемыйМодуль = Неопределено;
ИнформацияОбОшибке = ИнформацияОбОшибке();
КонецПопытки;
Если ПодключаемыйМодуль = Неопределено Тогда
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось создать объект внешней компоненты ""%1"", подключенной на сервере, по причине:
|%2'"),
Идентификатор, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
КомментарийДляЖурнала = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось создать объект внешней компоненты ""%1"", подключенной на сервере, по причине:
|%2'"),
Идентификатор, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)
+ СистемнаяИнформацияДляЖурналаРегистрации());
ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка,,, КомментарийДляЖурнала);
Возврат Результат;
КонецЕсли;
Результат.Подключено = Истина;
Результат.ПодключаемыйМодуль = ПодключаемыйМодуль;
ОтправитьСтатистикуПодключенияКомпоненты(Идентификатор, Местоположение);
Возврат Результат;
КонецФункции
Функция СтрокаВВидеНСтр(Знач ПроверяемаяСтрока) Экспорт
ПроверяемаяСтрока = СтрЗаменить(ПроверяемаяСтрока, " ", "");
ВариантыСовпадений = Новый Массив;
Для каждого Язык Из Метаданные.Языки Цикл
ВариантыСовпадений.Добавить(Язык.КодЯзыка + "=");
КонецЦикла;
Для каждого ВариантСовпадения Из ВариантыСовпадений Цикл
Если СтрНайти(ПроверяемаяСтрока, ВариантСовпадения) > 0 Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Устанавливает условное оформление списка выбора
//
// Параметры:
// Форма - ФормаКлиентскогоПриложения - форма, для которой устанавливается оформление.
// ИмяЭлемента - Строка - имя элемента, для которого устанавливается оформление.
// ИмяПоляКомпоновкиДанных - Строка - имя поля компоновки данных.
//
Процедура УстановитьУсловноеОформлениеСпискаВыбора(Форма, ИмяЭлемента, ИмяПоляКомпоновкиДанных) Экспорт
Элементы = Форма.Элементы;
УсловноеОформление = Форма.УсловноеОформление;
Для каждого ЭлементВыбора Из Элементы[ИмяЭлемента].СписокВыбора Цикл
Элемент = УсловноеОформление.Элементы.Добавить();
ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
ЭлементФормы = Элементы[ИмяЭлемента]; // ПолеФормы
ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(ЭлементФормы.Имя);
ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоляКомпоновкиДанных);
ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборЭлемента.ПравоеЗначение = ЭлементВыбора.Значение;
Элемент.Оформление.УстановитьЗначениеПараметра("Текст", ЭлементВыбора.Представление);
КонецЦикла;
КонецПроцедуры
// Возвращает суффикс текущего языка для мультиязычных реквизитов.
//
// Возвращаемое значение:
// - Строка - "Язык1" или "Язык2", если язык пользователя является дополнительным
// Пустая строка, если язык пользователя является основным.
// - Неопределено - мультиязычное хранение данных не используется.
//
Функция СуффиксЯзыкаТекущегоПользователя() Экспорт
Результат = Новый Структура();
Результат.Вставить("СуффиксТекущегоЯзыка", "");
Результат.Вставить("ЭтоОсновнойЯзык", "");
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
СуффиксТекущегоЯзыка = МодульМультиязычностьСервер.СуффиксТекущегоЯзыка();
Если ЗначениеЗаполнено(СуффиксТекущегоЯзыка) Тогда
Возврат СуффиксТекущегоЯзыка;
КонецЕсли;
Иначе
СуффиксТекущегоЯзыка = "";
КонецЕсли;
Если ЭтоОсновнойЯзык() Тогда
Возврат СуффиксТекущегоЯзыка;
КонецЕсли;
Возврат Неопределено;
КонецФункции
// Сокращает имя файла с расширением, если оно превышает размер в 255 байт.
// При этом сокращается часть имени файла без расширения, в конец которой добавляется уникальное значение,
// вычисленное по алгоритму MD5.
//
// Параметры:
// ИмяФайла - Строка - имя файла с расширением
//
Процедура СократитьИмяФайла(ИмяФайла) Экспорт
ОграничениеВБайтах = 127;
Файл = Новый Файл(ИмяФайла);
Если РазмерСтрокиВБайтах(Файл.Имя) <= ОграничениеВБайтах Тогда
Возврат;
КонецЕсли;
Строка = "";
ОстатокСтроки = "";
РазмерСтроки = 0;
МаксимальныйРазмерСтроки = ОграничениеВБайтах - 32;
РазмерРасширения = РазмерСтрокиВБайтах(Файл.Расширение);
СокращатьВместеСРасширением = РазмерРасширения > 32;
Если СокращатьВместеСРасширением Тогда
СокращаемоеИмя = Файл.Имя;
Иначе
СокращаемоеИмя = Файл.ИмяБезРасширения;
РазмерСтроки = РазмерРасширения;
КонецЕсли;
Для НомерСимвола = 1 По СтрДлина(СокращаемоеИмя) Цикл
Символ = Сред(СокращаемоеИмя, НомерСимвола, 1);
РазмерСимвола = РазмерСтрокиВБайтах(Символ);
Если РазмерСтроки + РазмерСимвола > МаксимальныйРазмерСтроки Тогда
ОстатокСтроки = Сред(СокращаемоеИмя, НомерСимвола);
Прервать;
КонецЕсли;
Строка = Строка + Символ;
РазмерСтроки = РазмерСтроки + РазмерСимвола;
КонецЦикла;
ИмяФайла = Строка;
ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5);
ХешированиеДанных.Добавить(ОстатокСтроки);
ХешСумма = СтрЗаменить(ХешированиеДанных.ХешСумма, " ", "");
ИмяФайла = Файл.Путь + ИмяФайла + ХешСумма + ?(СокращатьВместеСРасширением, "", Файл.Расширение);
КонецПроцедуры
// Служебные объекты и объекты при загрузке из резервной копии,
// должны записываться без какой-либо прикладной логики.
//
// Запись служебных объектов без отключения прикладной логики,
// может привести к зацикливанию, снижению производительности,
// а также избыточным изменениях, которые в некоторых случаях
// могут неожиданно повлиять на логику работы.
//
// Служебными являются объекты, которые обычно не участвуют
// в обмене данными, не зависят от других объектов, например:
// - кэши;
// - даты обновления кэшей и аналогичные признаки;
// - промежуточные данные для передачи параметров в фоновые задания;
// - вспомогательные служебные данные (например, ключи доступа,
// идентификаторы объектов метаданных).
//
// При использовании подсистемы Управление доступом, требуется
// отдельно вызывать процедуру ОтключитьОбновлениеКлючейДоступа
// общего модуля УправлениеДоступом.
//
// Процедура включает режим загрузки данных,
// отключает регистрацию объектов на планах обмена,
// отключает контроль механизма удаления помеченных объектов.
//
// Параметры:
// Объект - ПланОбменаОбъект
// - КонстантаМенеджерЗначения
// - СправочникОбъект
// - ДокументОбъект
// - ПоследовательностьНаборЗаписей
// - ПланВидовХарактеристикОбъект
// - ПланСчетовОбъект
// - ПланВидовРасчетаОбъект
// - БизнесПроцессОбъект
// - ЗадачаОбъект
// - УдалениеОбъекта
// - РегистрСведенийНаборЗаписей
// - РегистрНакопленияНаборЗаписей
// - РегистрБухгалтерииНаборЗаписей
// - РегистрРасчетаНаборЗаписей
// - ПерерасчетНаборЗаписей
//
// ЭтоУзелПланаОбмена - Булево
//
Процедура ОтключитьКонтрольЗаписи(Объект, ЭтоУзелПланаОбмена = Ложь) Экспорт
Объект.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых");
Объект.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
Объект.ОбменДанными.Загрузка = Истина;
Если Не ЭтоУзелПланаОбмена Тогда
Объект.ОбменДанными.Получатели.АвтоЗаполнение = Ложь;
КонецЕсли;
КонецПроцедуры
Функция МакетСуществует(ПолноеИмяМакета) Экспорт
Макет = Метаданные.НайтиПоПолномуИмени(ПолноеИмяМакета);
Если ТипЗнч(Макет) = Тип("ОбъектМетаданных") Тогда
Шаблон = Новый Структура("ТипМакета");
ЗаполнитьЗначенияСвойств(Шаблон, Макет);
ТипМакета = Неопределено;
Если Шаблон.Свойство("ТипМакета", ТипМакета) Тогда
Возврат ТипМакета <> Неопределено;
КонецЕсли;
КонецЕсли;
Возврат Ложь;
КонецФункции
Функция ДоменноеИмяКорректное(ДоменноеИмя) Экспорт
Если СтрДлина(ДоменноеИмя) > 255 Тогда
Возврат Ложь;
КонецЕсли;
Выражение = "(?:xn--[a-z0-9-]{1,59})(?:\.xn--[a-z0-9-]{1,59})*"
+ "|(?!^\d+$)(?:(?!-)[a-z0-9-]{1,63}(? 0 Тогда
ТекстОшибки = НСтр("ru = 'Вызовы недопустимых методов:
|%1'");
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НайденныеВызовы, Символы.ПС));
ТекстыОшибок.Добавить(ТекстОшибки);
КонецЕсли;
// Проверка обращений к общим модулям и свойствам глобального контекста.
ЗапрещенныеСвойстваГлобальногоКонтекста = ЗапрещенныеСвойстваГлобальногоКонтекста();
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(
ЗапрещенныеСвойстваГлобальногоКонтекста, ПараметрыПроверки.ЗапрещенныеСвойстваГлобальногоКонтекста, Истина);
НайденныеВызовы = НайденныеВызовы(Алгоритм, ЗапрещенныеСвойстваГлобальногоКонтекста, ".");
НайденныеВызовыАльтернативные = НайденныеВызовы(Алгоритм, ЗапрещенныеСвойстваГлобальногоКонтекста, "[");
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(НайденныеВызовы, НайденныеВызовыАльтернативные, Истина);
Если НайденныеВызовы.Количество() > 0 Тогда
ТекстОшибки = НСтр("ru = 'Вызовы недопустимых свойств глобального контекста:
|%1'");
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НайденныеВызовы, Символы.ПС));
ТекстыОшибок.Добавить(ТекстОшибки);
КонецЕсли;
ЗапрещенныеМодули = ЗапрещенныеМодули();
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ЗапрещенныеМодули, ПараметрыПроверки.ЗапрещенныеМодули, Истина);
НайденныеВызовы = НайденныеВызовы(Алгоритм, ЗапрещенныеМодули, ".");
Если НайденныеВызовы.Количество() > 0 Тогда
ТекстОшибки = НСтр("ru = 'Вызовы недопустимых модулей:
|%1'");
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, СтрСоединить(НайденныеВызовы, Символы.ПС));
ТекстыОшибок.Добавить(ТекстОшибки);
КонецЕсли;
Если ТекстыОшибок.Количество() > 0 Тогда
ВызватьИсключение (СтрСоединить(ТекстыОшибок, Символы.ПС + Символы.ПС), КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
#Область ДанныеВБазе
#Область ЗначенияРеквизитов
// Проверяет существование указанных реквизитов у объекта метаданных.
//
// Параметры:
// ПолноеИмяОбъектаМетаданных - Строка - полное имя проверяемого объекта.
// ПроверяемыеВыражения - Массив - имена полей или проверяемые выражения объекта метаданных.
//
// Возвращаемое значение:
// Структура:
// * Ошибка - Булево - найдена ошибка.
// * ОписаниеОшибки - Строка - описание найденных ошибок.
//
// Пример:
//
// Реквизиты = Новый Массив;
// Реквизиты.Добавить("Номер");
// Реквизиты.Добавить("Валюта.НаименованиеПолное");
//
// Результат = ОбщегоНазначения.ПроверитьСуществованиеРеквизитовОбъекта("Документ.ЗаказПокупателя", Реквизиты);
//
// Если Результат.Ошибка Тогда
// ВызватьИсключение Результат.ОписаниеОшибки;
// КонецЕсли;
//
Функция ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, ПроверяемыеВыражения)
МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
Если МетаданныеОбъекта = Неопределено Тогда
Возврат Новый Структура("Ошибка, ОписаниеОшибки", Истина,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Несуществующий объект метаданных ""%1"".'"), ПолноеИмяОбъектаМетаданных));
КонецЕсли;
// Разрешение вызова из безопасного режима внешней обработки или расширения.
// Информация о доступности полей источника схемы при проверке метаданных не является секретной.
УстановитьОтключениеБезопасногоРежима(Истина);
УстановитьПривилегированныйРежим(Истина);
Схема = Новый СхемаЗапроса;
Пакет = Схема.ПакетЗапросов.Добавить(Тип("ЗапросВыбораСхемыЗапроса"));
Оператор = Пакет.Операторы.Получить(0);
Источник = Оператор.Источники.Добавить(ПолноеИмяОбъектаМетаданных, "Таблица");
ТекстОшибки = "";
Для Каждого ТекущееВыражение Из ПроверяемыеВыражения Цикл
Если Не ПолеИсточникаСхемыЗапросаДоступно(Источник, ТекущееВыражение) Тогда
ТекстОшибки = ТекстОшибки + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Поле объекта ""%1"" не существует.'"), ТекущееВыражение);
КонецЕсли;
КонецЦикла;
Возврат Новый Структура("Ошибка, ОписаниеОшибки", Не ПустаяСтрока(ТекстОшибки), ТекстОшибки);
КонецФункции
// Используется в ПроверитьСуществованиеРеквизитовОбъекта.
// Выполняет проверку доступности поля проверяемого выражения в источнике оператора схемы запроса.
//
Функция ПолеИсточникаСхемыЗапросаДоступно(ИсточникОператора, ПроверяемоеВыражение)
ЧастиИмениПоля = СтрРазделить(ПроверяемоеВыражение, ".");
ДоступныеПоля = ИсточникОператора.Источник.ДоступныеПоля;
ТекущаяЧастьИмениПоля = 0;
Пока ТекущаяЧастьИмениПоля < ЧастиИмениПоля.Количество() Цикл
ТекущееПоле = ДоступныеПоля.Найти(ЧастиИмениПоля.Получить(ТекущаяЧастьИмениПоля));
Если ТекущееПоле = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
// Инкрементация следующей части имени поля и соответствующего списка доступности полей.
ТекущаяЧастьИмениПоля = ТекущаяЧастьИмениПоля + 1;
ДоступныеПоля = ТекущееПоле.Поля;
КонецЦикла;
Возврат Истина;
КонецФункции
#КонецОбласти
#Область ЗаменитьСсылки
Функция РазметитьМестаИспользования(Знач ПараметрыВыполнения, Знач Ссылка, Знач ЦелеваяСсылка, Знач ТаблицаПоиска)
УстановитьПривилегированныйРежим(Истина);
// Устанавливаем порядок известных и проверяем наличие неопознанных объектов.
Результат = Новый Структура;
Результат.Вставить("МестаИспользования", ТаблицаПоиска.НайтиСтроки(Новый Структура("Ссылка", Ссылка)));
Результат.Вставить("ОшибкиРазметки", Новый Массив);
Результат.Вставить("Успех", Истина);
Для Каждого МестоИспользования Из Результат.МестаИспользования Цикл
Если МестоИспользования.ЭтоСлужебныеДанные Тогда
Продолжить; // Зависимые данные не обрабатываются.
КонецЕсли;
Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения);
Если Информация.Вид = "КОНСТАНТА" Тогда
МестоИспользования.КлючЗамены = "Константа";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Вид = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Тогда
МестоИспользования.КлючЗамены = "Последовательность";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Вид = "РЕГИСТРСВЕДЕНИЙ" Тогда
МестоИспользования.КлючЗамены = "РегистрСведений";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Вид = "РЕГИСТРБУХГАЛТЕРИИ"
Или Информация.Вид = "РЕГИСТРНАКОПЛЕНИЯ"
Или Информация.Вид = "РЕГИСТРРАСЧЕТА" Тогда
МестоИспользования.КлючЗамены = "КлючЗаписи";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Ссылочный Тогда
МестоИспользования.КлючЗамены = "Объект";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
Иначе
// Неизвестный объект для замены ссылок.
Результат.Успех = Ложь;
Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Замена ссылок в ""%1"" недоступна.'"), Информация.ПолноеИмя);
ОписаниеОшибки = Новый Структура("Объект, Текст", МестоИспользования.Данные, Текст);
Результат.ОшибкиРазметки.Добавить(ОписаниеОшибки);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Параметры:
// ТаблицаПоиска - см. МестаИспользования
//
Процедура ЗаменитьСсылкиКороткимиТранзакциями(Результат, Знач ПараметрыВыполнения, Знач Дубль, Знач ТаблицаПоиска)
// Основной цикл обработки
ФильтрСсылок = Новый Структура("Ссылка, КлючЗамены");
Результат.ЕстьОшибки = Ложь;
ФильтрСсылок.Ссылка = Дубль;
ФильтрСсылок.КлючЗамены = "Константа";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВКонстанте(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "Объект";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВОбъекте(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "КлючЗаписи";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "Последовательность";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "РегистрСведений";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВРегистреСведений(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ПроизводимыеЗамены = Новый Массив;
ПроизводимыеЗамены.Добавить(Дубль);
Если ПараметрыВыполнения.УдалятьНепосредственно
ИЛИ ПараметрыВыполнения.ПомечатьНаУдаление Тогда
УстановитьПометкуУдаленияДляОбъектов(Результат, ПроизводимыеЗамены, ПараметрыВыполнения);
Иначе
ТаблицаПовторногоПоиска = МестаИспользования(ПроизводимыеЗамены,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования);
ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска, ПараметрыВыполнения);
КонецЕсли;
КонецПроцедуры
Процедура ПроизвестиЗаменуВКонстанте(Результат, Знач МестоИспользования, Знач ПараметрыЗаписи)
УстановитьПривилегированныйРежим(Истина);
Данные = МестоИспользования.Данные;
МетаданныеКонстанты = МестоИспользования.Метаданные;
ПредставлениеДанных = Строка(Данные);
Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Константа");
ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
СтрокаТаблицы.КлючЗамены = "";
КонецЦикла;
СостояниеОперации = "";
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
Блокировка.Добавить(МетаданныеКонстанты.ПолноеИмя());
Попытка
Блокировка.Заблокировать();
Исключение
СостояниеОперации = "ОшибкаБлокировки";
УточнениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось заменить в константе ""%1"", т.к. данные редактируются в другом сеансе работы с приложением.
|Повторите попытку замены.'"),
ПредставлениеДанных);
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, УточнениеОшибки);
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
МенеджерКонстанты = Константы[МетаданныеКонстанты.Имя].СоздатьМенеджерЗначения();
МенеджерКонстанты.Прочитать();
ЗаменаПроизведена = Ложь;
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
Если МенеджерКонстанты.Значение = СтрокаТаблицы.Ссылка Тогда
МенеджерКонстанты.Значение = СтрокаТаблицы.ЦелеваяСсылка;
ЗаменаПроизведена = Истина;
КонецЕсли;
КонецЦикла;
Если Не ЗаменаПроизведена Тогда
ОтменитьТранзакцию();
Возврат;
КонецЕсли;
// Пытаемся сохранить
Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Попытка
ЗаписатьОбъект(МенеджерКонстанты, ПараметрыЗаписи);
Исключение
СостояниеОперации = "ОшибкаЗаписи";
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке,
НСтр("ru = 'Не удалось заменить по причине:'"));
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,
МетаданныеКонстанты,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Если СостояниеОперации = "ОшибкаЗаписи" Тогда
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка,
ОписаниеОшибкиЗамены("ОшибкаЗаписи", Данные, ПредставлениеДанных, ИнформацияОбОшибке()),
ПараметрыЗаписи.ПодчиненныеКДублям);
КонецЦикла;
Иначе
ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка,
ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ИнформацияОбОшибке()),
ПараметрыЗаписи.ПодчиненныеКДублям);
КонецЕсли;
КонецПопытки;
КонецПроцедуры
Процедура ПроизвестиЗаменуВОбъекте(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения)
УстановитьПривилегированныйРежим(Истина);
Данные = МестоИспользования.Данные;
// Будем производить сразу все замены для этих данных.
Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Объект");
ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
ПредставлениеДанных = ПредметСтрокой(Данные);
СостояниеОперации = "";
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования);
Попытка
Блокировка.Заблокировать();
Исключение
СостояниеОперации = "ОшибкаБлокировки";
УточнениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось заменить в ""%1"", т.к. данные редактируются в другом сеансе работы с приложением.
|Повторите попытку замены.'"),
ПредставлениеДанных);
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, УточнениеОшибки);
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
ОбъектыЗаписи = ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки);
// Пытаемся сохранить, сам объект идет последним.
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Попытка
Если ПараметрыВыполнения.ВключатьБизнесЛогику Тогда
// Первая запись без контроля, чтобы устранить циклические ссылки.
НовыеПараметрыВыполнения = СкопироватьРекурсивно(ПараметрыВыполнения);
НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Ложь;
Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл
ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения);
КонецЦикла;
// Вторая запись c контролем.
НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Истина;
Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл
ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения);
КонецЦикла;
Иначе
// Запись без контроля бизнес-логики.
Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл
ЗаписатьОбъект(КлючЗначение.Ключ, ПараметрыВыполнения);
КонецЦикла;
КонецЕсли;
Исключение
СостояниеОперации = "ОшибкаЗаписи";
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке,
НСтр("ru = 'Не удалось заменить по причине:'"));
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Информация = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,
МестоИспользования.Метаданные,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ИнформацияОбОшибке());
Если СостояниеОперации = "ОшибкаЗаписи" Тогда
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, Ошибка,
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЦикла;
Иначе
ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка,
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЕсли;
КонецПопытки;
// Помечаем как обработанные
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
СтрокаТаблицы.КлючЗамены = "";
КонецЦикла;
КонецПроцедуры
Процедура ПроизвестиЗаменуВНаборе(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения)
УстановитьПривилегированныйРежим(Истина);
Данные = МестоИспользования.Данные;
МетаданныеРегистра = МестоИспользования.Метаданные;
ПредставлениеДанных = Строка(Данные);
// Будем производить сразу все замены для этих данных.
Фильтр = Новый Структура("Данные, КлючЗамены");
ЗаполнитьЗначенияСвойств(Фильтр, МестоИспользования);
ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
ОписаниеНабора = ОписаниеНабораЗаписей(МетаданныеРегистра);
НаборЗаписей = ОписаниеНабора.НаборЗаписей; // РегистрСведенийНаборЗаписей
ПарыЗамен = Новый Соответствие;
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
ПарыЗамен.Вставить(СтрокаТаблицы.Ссылка, СтрокаТаблицы.ЦелеваяСсылка);
КонецЦикла;
// Помечаем как обработанные
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
СтрокаТаблицы.КлючЗамены = "";
КонецЦикла;
СостояниеОперации = "";
НачатьТранзакцию();
Попытка
// Блокировка и подготовка набора.
Блокировка = Новый БлокировкаДанных;
Для Каждого КлючЗначение Из ОписаниеНабора.СписокИзмерений Цикл
ТипИзмерения = КлючЗначение.Значение;
Имя = КлючЗначение.Ключ;
Значение = Данные[Имя];
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
ТекущаяСсылка = СтрокаТаблицы.Ссылка;
Если ТипИзмерения.СодержитТип(ТипЗнч(ТекущаяСсылка)) Тогда
Блокировка.Добавить(ОписаниеНабора.ПространствоБлокировки).УстановитьЗначение(Имя, ТекущаяСсылка);
КонецЕсли;
КонецЦикла;
НаборЗаписей.Отбор[Имя].Установить(Значение);
КонецЦикла;
Попытка
Блокировка.Заблокировать();
Исключение
СостояниеОперации = "ОшибкаБлокировки";
УточнениеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось заменить в регистре ""%1"", т.к. данные редактируются в другом сеансе работы с приложением.
|Повторите попытку замены.'"),
ПредставлениеДанных);
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке, УточнениеОшибки);
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
НаборЗаписей.Прочитать();
ЗаменитьВКоллекцииСтрок("НаборЗаписей", "НаборЗаписей", НаборЗаписей, НаборЗаписей, ОписаниеНабора.СписокПолей, ПарыЗамен);
Если НаборЗаписей.Модифицированность() Тогда
ОтменитьТранзакцию();
Возврат;
КонецЕсли;
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Попытка
ЗаписатьОбъект(НаборЗаписей, ПараметрыВыполнения);
Исключение
СостояниеОперации = "ОшибкаЗаписи";
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке,
НСтр("ru = 'Не удалось заменить по причине:'"));
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Информация = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,
МетаданныеРегистра,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ИнформацияОбОшибке());
Если СостояниеОперации = "ОшибкаЗаписи" Тогда
Для Каждого СтрокаТаблицы Из ОбрабатываемыеСтроки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка, Ошибка,
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЦикла;
Иначе
ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка,
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЕсли;
КонецПопытки;
КонецПроцедуры
Процедура ПроизвестиЗаменуВРегистреСведений(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения)
Если МестоИспользования.Обработано Тогда
Возврат;
КонецЕсли;
МестоИспользования.Обработано = Истина;
// В случае, если дубль указан в измерениях набора, тогда используется 2 набора записей:
// НаборЗаписейДубля - чтение старых значений (по старым измерениям) и удаление старых значений.
// НаборЗаписейОригинала - чтение актуальных значений (по новым измерениям) и запись новых значений.
// Данные дублей и оригиналов объединяются по правилам:
// Приоритет у данных оригинала.
// Если в оригинале нет данных, то берутся данные из дубля.
// Набор оригинала записывается, а набор дубля удаляется.
//
// В случае, если дубль не указан в измерениях набора, тогда используется 1 набор записей:
// НаборЗаписейДубля - чтение старых значений и запись новых значений.
//
// Замена ссылок в ресурсах и реквизитах производится в обоих случаях.
УстановитьПривилегированныйРежим(Истина);
Дубль = МестоИспользования.Ссылка;
Оригинал = МестоИспользования.ЦелеваяСсылка;
МетаданныеРегистра = МестоИспользования.Метаданные;
КлючЗаписиРегистра = МестоИспользования.Данные;
Информация = ИнформацияОТипе(МетаданныеРегистра, ПараметрыВыполнения);
ТребуетсяДваНабора = Ложь;
Для Каждого КлючЗначение Из Информация.Измерения Цикл
ЗначениеИзмеренияДубля = КлючЗаписиРегистра[КлючЗначение.Ключ];
Если ЗначениеИзмеренияДубля = Дубль
Или ПараметрыВыполнения.УспешныеЗамены[ЗначениеИзмеренияДубля] = Дубль Тогда
ТребуетсяДваНабора = Истина; // Дубль указан в измерениях.
Прервать;
КонецЕсли;
КонецЦикла;
Менеджер = МенеджерОбъектаПоПолномуИмени(Информация.ПолноеИмя);
НаборЗаписейДубля = Менеджер.СоздатьНаборЗаписей();
Если ТребуетсяДваНабора Тогда
ЗначенияИзмеренийОригинала = Новый Структура;
НаборЗаписейОригинала = Менеджер.СоздатьНаборЗаписей();
КонецЕсли;
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
БлокировкаДубля = Блокировка.Добавить(Информация.ПолноеИмя);
Если ТребуетсяДваНабора Тогда
БлокировкаОригинала = Блокировка.Добавить(Информация.ПолноеИмя);
КонецЕсли;
Для Каждого КлючЗначение Из Информация.Измерения Цикл
ЗначениеИзмеренияДубля = КлючЗаписиРегистра[КлючЗначение.Ключ];
// Для решения проблемы уникальности
// выполняется замена старых значений измерений ключа записи на актуальные.
// Соответствие старых и актуальных обеспечивает соответствием УспешныеЗамены.
// Данные соответствия актуальны на текущий момент времени,
// т.к. пополняются только после успешной обработки очередной пары и фиксации транзакции.
НовоеЗначениеИзмеренияДубля = ПараметрыВыполнения.УспешныеЗамены[ЗначениеИзмеренияДубля];
Если НовоеЗначениеИзмеренияДубля <> Неопределено Тогда
ЗначениеИзмеренияДубля = НовоеЗначениеИзмеренияДубля;
КонецЕсли;
НаборЗаписейДубля.Отбор[КлючЗначение.Ключ].Установить(ЗначениеИзмеренияДубля);
// Замена в конкретной паре и блокировка на конкретную замену.
БлокировкаДубля.УстановитьЗначение(КлючЗначение.Ключ, ЗначениеИзмеренияДубля);
Если ТребуетсяДваНабора Тогда
Если ЗначениеИзмеренияДубля = Дубль Тогда
ЗначениеИзмеренияОригинала = Оригинал;
Иначе
ЗначениеИзмеренияОригинала = ЗначениеИзмеренияДубля;
КонецЕсли;
НаборЗаписейОригинала.Отбор[КлючЗначение.Ключ].Установить(ЗначениеИзмеренияОригинала);
ЗначенияИзмеренийОригинала.Вставить(КлючЗначение.Ключ, ЗначениеИзмеренияОригинала);
// Замена в конкретной паре и блокировка на конкретную замену.
БлокировкаОригинала.УстановитьЗначение(КлючЗначение.Ключ, ЗначениеИзмеренияОригинала);
КонецЕсли;
КонецЦикла;
Блокировка.Заблокировать();
НаборЗаписейДубля.Прочитать();
Если НаборЗаписейДубля.Количество() = 0 Тогда
ОтменитьТранзакцию();
Возврат;
КонецЕсли;
ЗаписьДубля = НаборЗаписейДубля[0];
Если ТребуетсяДваНабора Тогда
// Пишем в набор с другими измерениями.
НаборЗаписейОригинала.Прочитать();
Если НаборЗаписейОригинала.Количество() = 0 Тогда
ЗаписьОригинала = НаборЗаписейОригинала.Добавить();
ЗаполнитьЗначенияСвойств(ЗаписьОригинала, ЗаписьДубля);
ЗаполнитьЗначенияСвойств(ЗаписьОригинала, ЗначенияИзмеренийОригинала);
Иначе
ЗаписьОригинала = НаборЗаписейОригинала[0];
КонецЕсли;
Иначе
// Пишем туда же, откуда и читаем.
НаборЗаписейОригинала = НаборЗаписейДубля;
ЗаписьОригинала = ЗаписьДубля; // Ситуация с нулевым количеством записей в наборе обработана выше.
КонецЕсли;
// Замена дубля на оригинал в ресурсах и реквизитах.
Для Каждого КлючЗначение Из Информация.Ресурсы Цикл
ЗначениеРеквизитаВОригинале = ЗаписьОригинала[КлючЗначение.Ключ];
Если ЗначениеРеквизитаВОригинале = Дубль Тогда
ЗаписьОригинала[КлючЗначение.Ключ] = Оригинал;
КонецЕсли;
КонецЦикла;
Для Каждого КлючЗначение Из Информация.Реквизиты Цикл
ЗначениеРеквизитаВОригинале = ЗаписьОригинала[КлючЗначение.Ключ];
Если ЗначениеРеквизитаВОригинале = Дубль Тогда
ЗаписьОригинала[КлючЗначение.Ключ] = Оригинал;
КонецЕсли;
КонецЦикла;
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
// Удаление данных дубля.
Если ТребуетсяДваНабора Тогда
НаборЗаписейДубля.Очистить();
ЗаписатьОбъект(НаборЗаписейДубля, ПараметрыВыполнения);
КонецЕсли;
// Запись данных оригинала.
Если НаборЗаписейОригинала.Модифицированность() Тогда
ЗаписатьОбъект(НаборЗаписейОригинала, ПараметрыВыполнения);
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗарегистрироватьОшибкуВТаблицу(Результат, Дубль, Оригинал, КлючЗаписиРегистра, Информация,
"БлокировкаДляРегистра", ИнформацияОбОшибке());
КонецПопытки
КонецПроцедуры
Функция ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки)
Данные = МестоИспользования.Данные;
ОписаниеПоследовательностей = ОписаниеПоследовательностей(МестоИспользования.Метаданные);
ОписаниеДвижений = ОписаниеДвижений(МестоИспользования.Метаданные, ПараметрыВыполнения);
ОписаниеЗадач = ОписаниеЗадач(МестоИспользования.Метаданные);
УстановитьПривилегированныйРежим(Истина);
// Возвращаем измененные обработанные объекты.
Измененные = Новый Соответствие;
// Считываем
Описание = ОписаниеОбъекта(Данные.Метаданные());
Попытка
Объект = Данные.ПолучитьОбъект();
Исключение
// Был уже обработан с ошибками.
Объект = Неопределено;
КонецПопытки;
Если Объект = Неопределено Тогда
Возврат Измененные;
КонецЕсли;
Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл
ОписаниеДвижения.НаборЗаписей.Отбор.Регистратор.Установить(Данные);
ОписаниеДвижения.НаборЗаписей.Прочитать();
КонецЦикла;
Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл
ОписаниеПоследовательности.НаборЗаписей.Отбор.Регистратор.Установить(Данные);
ОписаниеПоследовательности.НаборЗаписей.Прочитать();
КонецЦикла;
// Заменяем сразу все варианты.
ПарыЗамен = Новый Соответствие;
Для Каждого МестоИспользования Из ОбрабатываемыеСтроки Цикл
ПарыЗамен.Вставить(МестоИспользования.Ссылка, МестоИспользования.ЦелеваяСсылка);
КонецЦикла;
ВыполнитьЗаменуВРеквизитахОбъекта(Объект, Описание, ПарыЗамен);
// Движения
Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл
ЗаменитьВКоллекцииСтрок(
"Движения",
ОписаниеДвижения.ПространствоБлокировки,
ОписаниеДвижения.НаборЗаписей,
ОписаниеДвижения.НаборЗаписей,
ОписаниеДвижения.СписокПолей,
ПарыЗамен);
КонецЦикла;
// Последовательности
Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл
ЗаменитьВКоллекцииСтрок(
"Последовательности",
ОписаниеПоследовательности.ПространствоБлокировки,
ОписаниеПоследовательности.НаборЗаписей,
ОписаниеПоследовательности.НаборЗаписей,
ОписаниеПоследовательности.СписокПолей,
ПарыЗамен);
КонецЦикла;
Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл
Если ОписаниеДвижения.НаборЗаписей.Модифицированность() Тогда
Измененные.Вставить(ОписаниеДвижения.НаборЗаписей, Ложь);
КонецЕсли;
КонецЦикла;
Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл
Если ОписаниеПоследовательности.НаборЗаписей.Модифицированность() Тогда
Измененные.Вставить(ОписаниеПоследовательности.НаборЗаписей, Ложь);
КонецЕсли;
КонецЦикла;
Если ОписаниеЗадач <> Неопределено Тогда
ЗадачаПроцесса = ЗадачиПроцесса(Данные, ОписаниеЗадач.ПространствоБлокировки);
Пока ЗадачаПроцесса.Следующий() Цикл
ЗадачаОбъект = ЗадачаПроцесса.Ссылка.ПолучитьОбъект();
Фильтр = Новый Структура("Данные, КлючЗамены", ЗадачаПроцесса.Ссылка, "Объект");
ОбрабатываемыеСтрокиЗадачи = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
Для каждого МестоИспользованияЗадачи Из ОбрабатываемыеСтрокиЗадачи Цикл
ПарыЗамен.Вставить(МестоИспользованияЗадачи.Ссылка, МестоИспользованияЗадачи.ЦелеваяСсылка);
КонецЦикла;
ВыполнитьЗаменуВРеквизитахОбъекта(ЗадачаОбъект, ОписаниеЗадач, ПарыЗамен);
Если ЗадачаОбъект.Модифицированность() Тогда
Измененные.Вставить(ЗадачаОбъект, Ложь);
КонецЕсли;
КонецЦикла;
КонецЕсли;
// Сам объект последний - для возможного перепроведения.
Если Объект.Модифицированность() Тогда
Измененные.Вставить(Объект, Описание.МожетБытьПроведен);
КонецЕсли;
Возврат Измененные;
КонецФункции
Функция ЗадачиПроцесса(БизнесПроцесс, ТипЗадач)
ТекстЗапроса = "ВЫБРАТЬ
| ИмяТаблицы.Ссылка
|ИЗ
| &ИмяТаблицы КАК ИмяТаблицы
|ГДЕ
| ИмяТаблицы.БизнесПроцесс = &БизнесПроцесс";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ТипЗадач);
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("БизнесПроцесс", БизнесПроцесс);
Возврат Запрос.Выполнить().Выбрать();
КонецФункции
Процедура ВыполнитьЗаменуВРеквизитахОбъекта(Объект, Описание, ПарыЗамен)
// Реквизиты
Для Каждого КлючЗначение Из Описание.Реквизиты Цикл
Имя = КлючЗначение.Ключ;
ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ];
Если ЦелеваяСсылка <> Неопределено Тогда
ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "Реквизиты", Имя);
Объект[Имя] = ЦелеваяСсылка;
КонецЕсли;
КонецЦикла;
// Стандартные реквизиты
Для Каждого КлючЗначение Из Описание.СтандартныеРеквизиты Цикл
Имя = КлючЗначение.Ключ;
ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ];
Если ЦелеваяСсылка <> Неопределено Тогда
ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "СтандартныеРеквизиты", Имя);
Объект[Имя] = ЦелеваяСсылка;
КонецЕсли;
КонецЦикла;
// Табличные части
Для Каждого Элемент Из Описание.ТабличныеЧасти Цикл
ЗаменитьВКоллекцииСтрок(
"ТабличныеЧасти",
Элемент.Имя,
Объект,
Объект[Элемент.Имя],
Элемент.СписокПолей,
ПарыЗамен);
КонецЦикла;
// Стандартные табличные части.
Для Каждого Элемент Из Описание.СтандартныеТабличныеЧасти Цикл
ЗаменитьВКоллекцииСтрок(
"СтандартныеТабличныеЧасти",
Элемент.Имя,
Объект,
Объект[Элемент.Имя],
Элемент.СписокПолей,
ПарыЗамен);
КонецЦикла;
Для Каждого Реквизит Из Описание.РеквизитыАдресации Цикл
Имя = Реквизит.Ключ;
ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ];
Если ЦелеваяСсылка <> Неопределено Тогда
ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "РеквизитыАдресации", Имя);
Объект[Имя] = ЦелеваяСсылка;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ЗарегистрироватьФактЗамены(Объект, СсылкаДубля, СсылкаОригинала, ВидРеквизита, ИмяРеквизита,
Индекс = Неопределено, ИмяКолонки = Неопределено)
ЕстьДополнительныеСвойства = Новый Структура("ДополнительныеСвойства");
ЗаполнитьЗначенияСвойств(ЕстьДополнительныеСвойства, Объект);
Если ТипЗнч(ЕстьДополнительныеСвойства.ДополнительныеСвойства) <> Тип("Структура") Тогда
Возврат;
КонецЕсли;
ДополнительныеСвойства = Объект.ДополнительныеСвойства;
ДополнительныеСвойства.Вставить("ЗаменаСсылок", Истина);
ВыполненныеЗамены = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеСвойства, "ВыполненныеЗамены");
Если ВыполненныеЗамены = Неопределено Тогда
ВыполненныеЗамены = Новый Массив;
ДополнительныеСвойства.Вставить("ВыполненныеЗамены", ВыполненныеЗамены);
КонецЕсли;
ОписаниеЗамены = Новый Структура;
ОписаниеЗамены.Вставить("СсылкаДубля", СсылкаДубля);
ОписаниеЗамены.Вставить("СсылкаОригинала", СсылкаОригинала);
ОписаниеЗамены.Вставить("ВидРеквизита", ВидРеквизита);
ОписаниеЗамены.Вставить("ИмяРеквизита", ИмяРеквизита);
ОписаниеЗамены.Вставить("Индекс", Индекс);
ОписаниеЗамены.Вставить("ИмяКолонки", ИмяКолонки);
ВыполненныеЗамены.Добавить(ОписаниеЗамены);
КонецПроцедуры
Процедура УстановитьПометкуУдаленияДляОбъектов(Результат, Знач УдаляемыеСсылки, Знач ПараметрыВыполнения)
УстановитьПривилегированныйРежим(Истина);
ЕстьВнешняяТранзакция = ТранзакцияАктивна();
ВсеМестаИспользования = МестаИспользования(УдаляемыеСсылки,,ПараметрыВыполнения.ПараметрыПоискаМестИспользования);
Для Каждого УдаляемаяСсылка Из УдаляемыеСсылки Цикл
Информация = ИнформацияОТипе(ТипЗнч(УдаляемаяСсылка), ПараметрыВыполнения);
Блокировка = Новый БлокировкаДанных;
Блокировка.Добавить(Информация.ПолноеИмя).УстановитьЗначение("Ссылка", УдаляемаяСсылка);
НачатьТранзакцию();
Попытка
ЭтоОшибкаБлокировки = Истина;
Блокировка.Заблокировать();
ЭтоОшибкаБлокировки = Ложь;
Успешно = УстановитьПометкуУдаления(Результат, УдаляемаяСсылка, ВсеМестаИспользования,
ПараметрыВыполнения, ЕстьВнешняяТранзакция);
Если Не Успешно Тогда
ОтменитьТранзакцию();
Продолжить;
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Если ЭтоОшибкаБлокировки Тогда
ЗарегистрироватьОшибкуВТаблицу(Результат, УдаляемаяСсылка, Неопределено, УдаляемаяСсылка, Информация,
"БлокировкаДляУдаленияДубля", ИнформацияОбОшибке());
КонецЕсли;
Если ЕстьВнешняяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Функция УстановитьПометкуУдаления(Результат, Знач УдаляемаяСсылка, Знач ВсеМестаИспользования, Знач ПараметрыВыполнения,
ЕстьВнешняяТранзакция)
УстановитьПривилегированныйРежим(Истина);
ПредставлениеСсылки = ПредметСтрокой(УдаляемаяСсылка);
Фильтр = Новый Структура("Ссылка");
Фильтр.Ссылка = УдаляемаяСсылка;
МестаИспользования = ВсеМестаИспользования.НайтиСтроки(Фильтр);
Индекс = МестаИспользования.ВГраница();
Пока Индекс >= 0 Цикл
Если МестаИспользования[Индекс].ВспомогательныеДанные Тогда
МестаИспользования.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
Если МестаИспользования.Количество() > 0 Тогда
ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, МестаИспользования, ПараметрыВыполнения);
Возврат Ложь; // Остались места использования, нельзя удалять.
КонецЕсли;
Объект = УдаляемаяСсылка.ПолучитьОбъект(); // ДокументОбъект, СправочникОбъект
Если Объект = Неопределено Тогда
Возврат Ложь; // Уже удален.
КонецЕсли;
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Успешно = Истина;
Попытка
ЗаписатьОбъектСПерехватомСообщений(Объект, "ПометкаУдаления", Неопределено, ПараметрыВыполнения);
Результат.ОчередьКНепосредственномуУдалению.Добавить(Объект.Ссылка);
Исключение
Успешно = Ложь;
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке,
НСтр("ru = 'Элемент не был помечен на удаление по причине:'"));
Попытка
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
Исключение
ОписаниеОшибки = ОписаниеОшибкиЗамены("ОшибкаУдаления", УдаляемаяСсылка, ПредставлениеСсылки, ИнформацияОбОшибке());
ЗарегистрироватьОшибкуЗамены(Результат, УдаляемаяСсылка, ОписаниеОшибки, ПараметрыВыполнения.ПодчиненныеКДублям);
Если ЕстьВнешняяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
КонецПопытки;
КонецПопытки;
Возврат Успешно;
КонецФункции
Процедура ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска, ПараметрыВыполнения)
Фильтр = Новый Структура("Ссылка, ОбъектОшибки");
Для Каждого СтрокаТаблицы Из ТаблицаПовторногоПоиска Цикл
Тест = Новый Структура("ВспомогательныеДанные", Ложь);
ЗаполнитьЗначенияСвойств(Тест, СтрокаТаблицы);
Если Тест.ВспомогательныеДанные Тогда
Продолжить;
КонецЕсли;
Фильтр.ОбъектОшибки = СтрокаТаблицы.Данные;
Фильтр.Ссылка = СтрокаТаблицы.Ссылка;
Если Результат.Ошибки.НайтиСтроки(Фильтр).Количество() > 0 Тогда
Продолжить; // По данной проблеме уже записана ошибка.
КонецЕсли;
ЗарегистрироватьОшибкуЗамены(Результат, СтрокаТаблицы.Ссылка,
ОписаниеОшибкиЗамены("ДанныеИзменены", СтрокаТаблицы.Данные, ПредметСтрокой(СтрокаТаблицы.Данные),
НСтр("ru = 'Заменены не все места использования. Возможно места использования были добавлены или изменены другим пользователем.'")),
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЦикла;
КонецПроцедуры
Процедура ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования)
Если МестоИспользования.КлючЗамены = "Константа" Тогда
Блокировка.Добавить(МестоИспользования.Метаданные.ПолноеИмя());
ИначеЕсли МестоИспользования.КлючЗамены = "Объект" Тогда
СсылкаОбъекта = МестоИспользования.Данные;
МетаданныеОбъекта = МестоИспользования.Метаданные;
// Сам объект.
Блокировка.Добавить(МетаданныеОбъекта.ПолноеИмя()).УстановитьЗначение("Ссылка", СсылкаОбъекта);
// Движения по регистратору.
ОписаниеДвижений = ОписаниеДвижений(МетаданныеОбъекта);
Для Каждого Элемент Из ОписаниеДвижений Цикл
Блокировка.Добавить(Элемент.ПространствоБлокировки + ".НаборЗаписей").УстановитьЗначение("Регистратор", СсылкаОбъекта);
КонецЦикла;
// Последовательности.
ОписаниеПоследовательностей = ОписаниеПоследовательностей(МетаданныеОбъекта);
Для Каждого Элемент Из ОписаниеПоследовательностей Цикл
Блокировка.Добавить(Элемент.ПространствоБлокировки).УстановитьЗначение("Регистратор", СсылкаОбъекта);
КонецЦикла;
// Задачи (для бизнес-процессов)
ОписаниеЗадач = ОписаниеЗадач(МетаданныеОбъекта);
Если ОписаниеЗадач <> Неопределено Тогда
Блокировка.Добавить(ОписаниеЗадач.ПространствоБлокировки).УстановитьЗначение("БизнесПроцесс", СсылкаОбъекта);
КонецЕсли;
ИначеЕсли МестоИспользования.КлючЗамены = "Последовательность" Тогда
СсылкаОбъекта = МестоИспользования.Данные;
МетаданныеОбъекта = МестоИспользования.Метаданные;
ОписаниеПоследовательностей = ОписаниеПоследовательностей(МетаданныеОбъекта);
Для Каждого Элемент Из ОписаниеПоследовательностей Цикл
Блокировка.Добавить(Элемент.ПространствоБлокировки).УстановитьЗначение("Регистратор", СсылкаОбъекта);
КонецЦикла;
ИначеЕсли МестоИспользования.КлючЗамены = "КлючЗаписи"
Или МестоИспользования.КлючЗамены = "РегистрСведений" Тогда
Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения);
ТипДубля = МестоИспользования.ТипСсылки;
ТипОригинала = ТипЗнч(МестоИспользования.ЦелеваяСсылка);
Для Каждого КлючЗначение Из Информация.Измерения Цикл
ТипИзмерения = КлючЗначение.Значение.Тип;
Если ТипИзмерения.СодержитТип(ТипДубля) Тогда
БлокировкаПоИзмерению = Блокировка.Добавить(Информация.ПолноеИмя);
БлокировкаПоИзмерению.УстановитьЗначение(КлючЗначение.Ключ, МестоИспользования.Ссылка);
КонецЕсли;
Если ТипИзмерения.СодержитТип(ТипОригинала) Тогда
БлокировкаПоИзмерению = Блокировка.Добавить(Информация.ПолноеИмя);
БлокировкаПоИзмерению.УстановитьЗначение(КлючЗначение.Ключ, МестоИспользования.ЦелеваяСсылка);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Процедура ОтключитьОбновлениеКлючейДоступа(Значение)
Если ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
УстановитьПривилегированныйРежим(Истина);
МодульУправлениеДоступом = ОбщийМодуль("УправлениеДоступом");
МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Значение);
КонецЕсли;
КонецПроцедуры
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных
// ПараметрыВыполнения - см. ПараметрыПоискаМестИспользования
//
// Возвращаемое значение:
// Массив из Структура:
// * СписокПолей - Структура
// * СтруктураИзмерений - Структура
// * СписокВедущих - Структура
// * НаборЗаписей - РегистрСведенийНаборЗаписей
// * ПространствоБлокировки - Строка
//
Функция ОписаниеДвижений(Знач ОбъектМетаданных, ПараметрыВыполнения = Неопределено)
ОписаниеДвижений = Новый Массив;
Если Не Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда
Возврат ОписаниеДвижений;
КонецЕсли;
Исключения = ИсключенияПоискаСсылок();
Для Каждого Движение Из ОбъектМетаданных.Движения Цикл
Если Исключения[Движение] = "*" Тогда
Если ПараметрыВыполнения <> Неопределено И ПараметрыВыполнения.УдалятьНепосредственно Тогда
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(
ПараметрыВыполнения.ПараметрыПоискаМестИспользования.ИсключенияПоискаРегистровПодчиненныхРегистратору,
ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Движение), Истина);
КонецЕсли;
Продолжить;
КонецЕсли;
Если Метаданные.РегистрыНакопления.Содержит(Движение) Тогда
НаборЗаписей = РегистрыНакопления[Движение.Имя].СоздатьНаборЗаписей();
ИсключатьПоля = "Активность, НомерСтроки, Период, Регистратор";
ИначеЕсли Метаданные.РегистрыСведений.Содержит(Движение) Тогда
НаборЗаписей = РегистрыСведений[Движение.Имя].СоздатьНаборЗаписей();
ИсключатьПоля = "Активность, ВидДвижения, НомерСтроки, Период, Регистратор";
ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(Движение) Тогда
НаборЗаписей = РегистрыБухгалтерии[Движение.Имя].СоздатьНаборЗаписей();
ИсключатьПоля = "Активность, ВидДвижения, НомерСтроки, Период, Регистратор";
ИначеЕсли Метаданные.РегистрыРасчета.Содержит(Движение) Тогда
НаборЗаписей = РегистрыРасчета[Движение.Имя].СоздатьНаборЗаписей();
ИсключатьПоля = "Активность, БазовыйПериодКонец, БазовыйПериодНачало, НомерСтроки, ПериодДействия,
|ПериодДействияКонец, ПериодДействияНачало, ПериодРегистрации, Регистратор, Сторно,
|ФактическийПериодДействия";
Иначе
// Неизвестный тип
Продолжить;
КонецЕсли;
// Поля ссылочного типа и измерения - кандидаты.
// @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы.
Описание = СпискиПолейОбъекта(НаборЗаписей, Движение.Измерения, ИсключатьПоля);
Если Описание.СписокПолей.Количество() = 0 Тогда
// Незачем обрабатывать
Продолжить;
КонецЕсли;
Описание.Вставить("НаборЗаписей", НаборЗаписей);
Описание.Вставить("ПространствоБлокировки", Движение.ПолноеИмя() );
ОписаниеДвижений.Добавить(Описание);
КонецЦикла;
Возврат ОписаниеДвижений;
КонецФункции
// Параметры:
// Мета - ОбъектМетаданных
//
// Возвращаемое значение:
// Массив из Структура:
// * НаборЗаписей - ПоследовательностьНаборЗаписей
// * ПространствоБлокировки - Строка
// * Измерения - Структура
//
Функция ОписаниеПоследовательностей(Знач Мета)
ОписаниеПоследовательностей = Новый Массив;
Если Не Метаданные.Документы.Содержит(Мета) Тогда
Возврат ОписаниеПоследовательностей;
КонецЕсли;
Для Каждого Последовательность Из Метаданные.Последовательности Цикл
Если Не Последовательность.Документы.Содержит(Мета) Тогда
Продолжить;
КонецЕсли;
ИмяТаблицы = Последовательность.ПолноеИмя();
// @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы.
Описание = СпискиПолейОбъекта(ИмяТаблицы, Последовательность.Измерения, "Регистратор");
Если Описание.СписокПолей.Количество() > 0 Тогда
Описание.Вставить("НаборЗаписей", Последовательности[Последовательность.Имя].СоздатьНаборЗаписей());
Описание.Вставить("ПространствоБлокировки", ИмяТаблицы + ".Записи");
Описание.Вставить("Измерения", Новый Структура);
ОписаниеПоследовательностей.Добавить(Описание);
КонецЕсли;
КонецЦикла;
Возврат ОписаниеПоследовательностей;
КонецФункции
// Возвращаемое значение:
// Структура:
// * СтандартныеРеквизиты - Структура
// * РеквизитыАдресации - Структура
// * Реквизиты - Структура
// * СтандартныеТабличныеЧасти - Массив из Структура:
// ** Имя - Строка
// ** СписокПолей - Структура
// * ТабличныеЧасти - Массив из Структура:
// ** Имя - Строка
// ** СписокПолей - Структура
// * МожетБытьПроведен - Булево
//
Функция ОписаниеОбъекта(Знач ОбъектМетаданных)
ТипВсеСсылки = ОписаниеТипаВсеСсылки();
Кандидаты = Новый Структура("Реквизиты, СтандартныеРеквизиты, ТабличныеЧасти, СтандартныеТабличныеЧасти, РеквизитыАдресации");
ЗаполнитьЗначенияСвойств(Кандидаты, ОбъектМетаданных);
ОписаниеОбъекта = Новый Структура;
ОписаниеОбъекта.Вставить("Реквизиты", Новый Структура);
Если Кандидаты.Реквизиты <> Неопределено Тогда
Для Каждого МетаРеквизит Из Кандидаты.Реквизиты Цикл
Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда
ОписаниеОбъекта.Реквизиты.Вставить(МетаРеквизит.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
ОписаниеОбъекта.Вставить("СтандартныеРеквизиты", Новый Структура);
Если Кандидаты.СтандартныеРеквизиты <> Неопределено Тогда
Исключаемые = Новый Структура("Ссылка");
Для Каждого МетаРеквизит Из Кандидаты.СтандартныеРеквизиты Цикл
Имя = МетаРеквизит.Имя;
Если Не Исключаемые.Свойство(Имя) И ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда
ОписаниеОбъекта.Реквизиты.Вставить(МетаРеквизит.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
ОписаниеОбъекта.Вставить("ТабличныеЧасти", Новый Массив);
Если Кандидаты.ТабличныеЧасти <> Неопределено Тогда
Для Каждого МетаТаблица Из Кандидаты.ТабличныеЧасти Цикл
СписокПолей = Новый Структура;
Для Каждого МетаРеквизит Из МетаТаблица.Реквизиты Цикл
Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда
СписокПолей.Вставить(МетаРеквизит.Имя);
КонецЕсли;
КонецЦикла;
Если СписокПолей.Количество() > 0 Тогда
ОписаниеОбъекта.ТабличныеЧасти.Добавить(Новый Структура("Имя, СписокПолей", МетаТаблица.Имя, СписокПолей));
КонецЕсли;
КонецЦикла;
КонецЕсли;
ОписаниеОбъекта.Вставить("СтандартныеТабличныеЧасти", Новый Массив);
Если Кандидаты.СтандартныеТабличныеЧасти <> Неопределено Тогда
Для Каждого МетаТаблица Из Кандидаты.СтандартныеТабличныеЧасти Цикл
СписокПолей = Новый Структура;
Для Каждого МетаРеквизит Из МетаТаблица.СтандартныеРеквизиты Цикл
Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда
СписокПолей.Вставить(МетаРеквизит.Имя);
КонецЕсли;
КонецЦикла;
Если СписокПолей.Количество() > 0 Тогда
ОписаниеОбъекта.СтандартныеТабличныеЧасти.Добавить(Новый Структура("Имя, СписокПолей", МетаТаблица.Имя, СписокПолей));
КонецЕсли;
КонецЦикла;
КонецЕсли;
ОписаниеОбъекта.Вставить("РеквизитыАдресации", Новый Структура);
Если Кандидаты.РеквизитыАдресации <> Неопределено Тогда
Для Каждого Реквизит Из Кандидаты.РеквизитыАдресации Цикл
Если ОписанияТиповПересекаются(Реквизит.Тип, ТипВсеСсылки) Тогда
ОписаниеОбъекта.РеквизитыАдресации.Вставить(Реквизит.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
ОписаниеОбъекта.Вставить("МожетБытьПроведен", Метаданные.Документы.Содержит(ОбъектМетаданных));
Возврат ОписаниеОбъекта;
КонецФункции
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных
//
// Возвращаемое значение:
// Массив из Структура:
// * СписокПолей - Структура
// * СтруктураИзмерений - Структура
// * СписокВедущих - Структура
// * НаборЗаписей - РегистрСведенийНаборЗаписей
// * ПространствоБлокировки - Строка
//
Функция ОписаниеЗадач(Знач Мета)
ОписаниеЗадач = Неопределено;
Если НЕ Метаданные.БизнесПроцессы.Содержит(Мета) Тогда
Возврат ОписаниеЗадач;
КонецЕсли;
ОписаниеЗадач = ОписаниеОбъекта(Мета.Задача);
ОписаниеЗадач.Вставить("ПространствоБлокировки", Мета.Задача.ПолноеИмя());
Возврат ОписаниеЗадач;
КонецФункции
Функция ОписаниеНабораЗаписей(Знач МетаданныеТаблицы)
ИмяТаблицы = МетаданныеТаблицы.ПолноеИмя();
// Поля ссылочного типа - кандидаты и набор измерений.
// @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы.
ОписаниеКлюча = СпискиПолейОбъекта(ИмяТаблицы, МетаданныеТаблицы.Измерения, "Период, Регистратор");
Если Метаданные.РегистрыСведений.Содержит(МетаданныеТаблицы) Тогда
НаборЗаписей = РегистрыСведений[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей();
ИначеЕсли Метаданные.РегистрыНакопления.Содержит(МетаданныеТаблицы) Тогда
НаборЗаписей = РегистрыНакопления[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей();
ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(МетаданныеТаблицы) Тогда
НаборЗаписей = РегистрыБухгалтерии[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей();
ИначеЕсли Метаданные.РегистрыРасчета.Содержит(МетаданныеТаблицы) Тогда
НаборЗаписей = РегистрыРасчета[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей();
ИначеЕсли Метаданные.Последовательности.Содержит(МетаданныеТаблицы) Тогда
НаборЗаписей = Последовательности[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей();
Иначе
НаборЗаписей = Неопределено;
КонецЕсли;
ОписаниеКлюча.Вставить("НаборЗаписей", НаборЗаписей);
ОписаниеКлюча.Вставить("ПространствоБлокировки", ИмяТаблицы);
Возврат ОписаниеКлюча;
КонецФункции
Функция ОписанияТиповПересекаются(Знач Описание1, Знач Описание2)
Для Каждого Тип Из Описание1.Типы() Цикл
Если Описание2.СодержитТип(Тип) Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Возвращает описание по имени таблицы или по набору записей.
Функция СпискиПолейОбъекта(Знач ИсточникДанных, Знач МетаданныеИзмеренийРегистра, Знач ИсключатьПоля)
Описание = Новый Структура;
Описание.Вставить("СписокПолей", Новый Структура);
Описание.Вставить("СтруктураИзмерений", Новый Структура);
Описание.Вставить("СписокВедущих", Новый Структура);
ТипКонтроля = ОписаниеТипаВсеСсылки();
Исключаемые = Новый Структура(ИсключатьПоля);
ТипИсточникаДанных = ТипЗнч(ИсточникДанных);
Если ТипИсточникаДанных = Тип("Строка") Тогда
// Источник - имя таблицы, получаем поля запросом.
ТекстЗапроса = "ВЫБРАТЬ * ИЗ &ИмяТаблицы ГДЕ ЛОЖЬ";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИсточникДанных);
Запрос = Новый Запрос(ТекстЗапроса);
ИсточникПолей = Запрос.Выполнить();
Иначе
// Источник - набор записей
ИсточникПолей = ИсточникДанных.ВыгрузитьКолонки();
КонецЕсли;
Для Каждого Колонка Из ИсточникПолей.Колонки Цикл
Имя = Колонка.Имя;
Если Не Исключаемые.Свойство(Имя) И ОписанияТиповПересекаются(Колонка.ТипЗначения, ТипКонтроля) Тогда
Описание.СписокПолей.Вставить(Имя);
// И проверка на ведущее измерение.
Мета = МетаданныеИзмеренийРегистра.Найти(Имя);
Если Мета <> Неопределено Тогда
Описание.СтруктураИзмерений.Вставить(Имя, Мета.Тип);
Тест = Новый Структура("Ведущее", Ложь);
ЗаполнитьЗначенияСвойств(Тест, Мета);
Если Тест.Ведущее Тогда
Описание.СписокВедущих.Вставить(Имя, Мета.Тип);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Описание;
КонецФункции
Процедура ЗаменитьВКоллекцииСтрок(ВидКоллекции, ИмяКоллекции, Объект, Коллекция, Знач СписокПолей, Знач ПарыЗамен)
ИзмененнаяКоллекция = Коллекция.Выгрузить();
Модифицировано = Ложь;
ИменаИзмененныхРеквизитов = Новый Массив;
Для Каждого СтрокаТаблицы Из ИзмененнаяКоллекция Цикл
Для Каждого КлючЗначение Из СписокПолей Цикл
ИмяРеквизита = КлючЗначение.Ключ;
ЦелеваяСсылка = ПарыЗамен[ СтрокаТаблицы[ИмяРеквизита] ];
Если ЦелеваяСсылка <> Неопределено Тогда
ЗарегистрироватьФактЗамены(Объект, СтрокаТаблицы[ИмяРеквизита], ЦелеваяСсылка, ВидКоллекции, ИмяКоллекции,
ИзмененнаяКоллекция.Индекс(СтрокаТаблицы), ИмяРеквизита);
СтрокаТаблицы[ИмяРеквизита] = ЦелеваяСсылка;
Модифицировано = Истина;
ИменаИзмененныхРеквизитов.Добавить(ИмяРеквизита);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если Модифицировано Тогда
ЭтоРегистрБухгалтерии = ВидКоллекции = "Движения" И ЭтоРегистрБухгалтерии(Коллекция.Метаданные());
Если ЭтоРегистрБухгалтерии Тогда
ЗагрузитьИзмененныйНаборВРегистрБухгалтерии(Коллекция, ИзмененнаяКоллекция, ИменаИзмененныхРеквизитов);
Иначе
Коллекция.Загрузить(ИзмененнаяКоллекция);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ЗагрузитьИзмененныйНаборВРегистрБухгалтерии(НаборЗаписей, ИзмененнаяКоллекция, ИменаИзмененныхРеквизитов)
НеизмененныеИзмерения = Новый Соответствие;
ИзмененныеИзмерения = Новый Соответствие;
НеизмененныеРесурсы = Новый Соответствие;
ИзмененныеРесурсы = Новый Соответствие;
МетаданныеРегистра = НаборЗаписей.Метаданные();
Для Каждого Измерение Из МетаданныеРегистра.Измерения Цикл
ИменаИзмерений = Новый Массив;
Если Измерение.Балансовый Или Не МетаданныеРегистра.Корреспонденция Тогда
ИменаИзмерений.Добавить(Измерение.Имя);
Иначе
ИменаИзмерений.Добавить(Измерение.Имя + "Дт");
ИменаИзмерений.Добавить(Измерение.Имя + "Кт");
КонецЕсли;
Для Каждого ИмяИзмерения Из ИменаИзмерений Цикл
Если ИменаИзмененныхРеквизитов.Найти(ИмяИзмерения) = Неопределено Тогда
НеизмененныеИзмерения.Вставить(ИмяИзмерения, НаборЗаписей.ВыгрузитьКолонку(ИмяИзмерения));
Иначе
ИзмененныеИзмерения.Вставить(ИмяИзмерения, НаборЗаписей.ВыгрузитьКолонку(ИмяИзмерения));
КонецЕсли;
КонецЦикла;
КонецЦикла;
Для Каждого Ресурс Из МетаданныеРегистра.Ресурсы Цикл
ИменаРесурсов = Новый Массив;
Если Ресурс.Балансовый Или Не МетаданныеРегистра.Корреспонденция Тогда
ИменаРесурсов.Добавить(Ресурс.Имя);
Иначе
ИменаРесурсов.Добавить(Ресурс.Имя + "Дт");
ИменаРесурсов.Добавить(Ресурс.Имя + "Кт");
КонецЕсли;
Для Каждого ИмяРесурса Из ИменаРесурсов Цикл
Если ИменаИзмененныхРеквизитов.Найти(ИмяРесурса) = Неопределено Тогда
НеизмененныеРесурсы.Вставить(ИмяРесурса, НаборЗаписей.ВыгрузитьКолонку(ИмяРесурса));
Иначе
ИзмененныеРесурсы.Вставить(ИмяРесурса, НаборЗаписей.ВыгрузитьКолонку(ИмяРесурса));
КонецЕсли;
КонецЦикла;
КонецЦикла;
Для Сч = 0 По НаборЗаписей.Количество() - 1 Цикл
Для Каждого ИмяИзмеренияЗначения Из ИзмененныеИзмерения Цикл
Если НаборЗаписей[Сч][ИмяИзмеренияЗначения.Ключ] = NULL Тогда
ИмяИзмеренияЗначения.Значение[Сч] = NULL;
Иначе
ИмяИзмеренияЗначения.Значение[Сч] = ИзмененнаяКоллекция[Сч][ИмяИзмеренияЗначения.Ключ];
КонецЕсли;
КонецЦикла;
Для Каждого ИмяРесурсаЗначения Из ИзмененныеРесурсы Цикл
Если НаборЗаписей[Сч][ИмяРесурсаЗначения.Ключ] = NULL Тогда
ИмяРесурсаЗначения.Значение[Сч] = NULL;
Иначе
ИмяРесурсаЗначения.Значение[Сч] = ИзмененнаяКоллекция[Сч][ИмяРесурсаЗначения.Ключ];
КонецЕсли;
КонецЦикла;
КонецЦикла;
НаборЗаписей.Загрузить(ИзмененнаяКоллекция);
Для Каждого ИзмеренияЗначенияВКолонке Из НеизмененныеИзмерения Цикл
НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ);
КонецЦикла;
Для Каждого ИзмеренияЗначенияВКолонке Из ИзмененныеИзмерения Цикл
НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ);
КонецЦикла;
Для Каждого ИзмеренияЗначенияВКолонке Из НеизмененныеРесурсы Цикл
НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ);
КонецЦикла;
Для Каждого ИзмеренияЗначенияВКолонке Из ИзмененныеРесурсы Цикл
НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ);
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьОбъектСПерехватомСообщений(Знач Объект, Знач Действие, Знач РежимЗаписи, Знач ПараметрыЗаписи)
// Текущие сообщения до исключения запоминаем.
ПредыдущиеСообщения = ПолучитьСообщенияПользователю(Истина);
СообщатьПовторно = ТекущийРежимЗапуска() <> Неопределено;
Попытка
Если Действие = "Запись" Тогда
Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику;
Если РежимЗаписи = Неопределено Тогда
Объект.Записать();
Иначе
Объект.Записать(РежимЗаписи);
КонецЕсли;
ИначеЕсли Действие = "ПометкаУдаления" Тогда
МетаданныеОбъекта = Объект.Метаданные();
Если ЭтоСправочник(МетаданныеОбъекта)
Или ЭтоПланВидовХарактеристик(МетаданныеОбъекта)
Или ЭтоПланСчетов(МетаданныеОбъекта) Тогда
Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику;
Объект.УстановитьПометкуУдаления(Истина, Ложь);
ИначеЕсли ЭтоДокумент(МетаданныеОбъекта)
И МетаданныеОбъекта.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
Объект.УстановитьПометкуУдаления(Истина);
Иначе
Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику;
Объект.УстановитьПометкуУдаления(Истина);
КонецЕсли;
КонецЕсли;
Исключение
ТекстСообщений = "";
Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Ложь) Цикл
ТекстСообщений = ТекстСообщений + Символы.ПС + Сообщение.Текст;
КонецЦикла;
Если СообщатьПовторно Тогда
СообщитьОтложенныеСообщения(ПредыдущиеСообщения);
КонецЕсли;
Если ТекстСообщений = "" Тогда
ВызватьИсключение;
КонецЕсли;
ИнформацияОбОшибке = ИнформацияОбОшибке();
Уточнение = ОбщегоНазначенияКлиентСервер.УточнениеИсключения(ИнформацияОбОшибке);
Уточнение.Текст = Уточнение.Текст + Символы.ПС + СокрЛП(ТекстСообщений);
ВызватьИсключение(Уточнение.Текст, Уточнение.Категория,,, ИнформацияОбОшибке);
КонецПопытки;
Если СообщатьПовторно Тогда
СообщитьОтложенныеСообщения(ПредыдущиеСообщения);
КонецЕсли;
КонецПроцедуры
Процедура СообщитьОтложенныеСообщения(Знач Сообщения)
Для Каждого Сообщение Из Сообщения Цикл
Сообщение.Сообщить();
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьОбъект(Знач Объект, Знач ПараметрыЗаписи)
МетаданныеОбъекта = Объект.Метаданные();
Если ЭтоДокумент(МетаданныеОбъекта) Тогда
ЗаписатьОбъектСПерехватомСообщений(Объект, "Запись", РежимЗаписиДокумента.Запись, ПараметрыЗаписи);
Возврат;
КонецЕсли;
// Проверка на возможные циклические ссылки.
СвойстваОбъекта = Новый Структура("Иерархический, ВидыСубконто, Владельцы", Ложь, Неопределено, Новый Массив);
ЗаполнитьЗначенияСвойств(СвойстваОбъекта, МетаданныеОбъекта);
// По родителю
Если СвойстваОбъекта.Иерархический Или СвойстваОбъекта.ВидыСубконто <> Неопределено Тогда
Если Объект.Родитель = Объект.Ссылка Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Невозможно записать ""%1"", т.к. его родительским элементом не может быть он сам.'"),
ПредметСтрокой(Объект));
КонецЕсли;
КонецЕсли;
// По владельцу
Если СвойстваОбъекта.Владельцы.Количество() > 1 И Объект.Владелец = Объект.Ссылка Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Невозможно записать ""%1"", т.к. его владельцем не может быть он сам.'"),
ПредметСтрокой(Объект));
КонецЕсли;
// Для последовательностей право "Изменение" может отсутствовать даже у роли "АдминистраторСистемы".
Если ЭтоПоследовательность(МетаданныеОбъекта)
И Не ПравоДоступа("Изменение", МетаданныеОбъекта)
И Пользователи.ЭтоПолноправныйПользователь(,, Ложь) Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
ЗаписатьОбъектСПерехватомСообщений(Объект, "Запись", Неопределено, ПараметрыЗаписи);
КонецПроцедуры
Функция СобытиеЖурналаРегистрацииЗаменыСсылок()
Возврат НСтр("ru = 'Поиск и удаление ссылок'", КодОсновногоЯзыка());
КонецФункции
// Параметры:
// Результат - см. РезультатЗаменыСсылок
// Ссылка - ЛюбаяСсылка
// ОписаниеОшибки - см. ОписаниеОшибкиЗамены
// ПодчиненныеКДублям - Соответствие, Неопределено
//
Процедура ЗарегистрироватьОшибкуЗамены(Результат, Знач Ссылка, Знач ОписаниеОшибки, ПодчиненныеКДублям = Неопределено)
Результат.ЕстьОшибки = Истина;
Строка = Результат.Ошибки.Добавить();
Строка.Ссылка = Ссылка;
Строка.ПредставлениеОбъектаОшибки = ОписаниеОшибки.ПредставлениеОбъектаОшибки;
Строка.ОбъектОшибки = ОписаниеОшибки.ОбъектОшибки;
Строка.ИнформацияОбОшибке = ?(ТипЗнч(ОписаниеОшибки.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке"),
ОписаниеОшибки.ИнформацияОбОшибке, Неопределено);
Строка.ТекстОшибки = ?(ТипЗнч(ОписаниеОшибки.ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке"),
ОбработкаОшибок.КраткоеПредставлениеОшибки(ОписаниеОшибки.ИнформацияОбОшибке), ОписаниеОшибки.ИнформацияОбОшибке);
Строка.ТипОшибки = ОписаниеОшибки.ТипОшибки;
ДубльРодитель = Ссылка;
Если ПодчиненныеКДублям <> Неопределено И ПодчиненныеКДублям[Ссылка] <> Неопределено Тогда
ДубльРодитель = ПодчиненныеКДублям[Ссылка];
КонецЕсли;
Строка.ДубльРодитель = ДубльРодитель;
КонецПроцедуры
// Возвращаемое значение:
// Структура:
// * ТипОшибки - Строка
// * ОбъектОшибки - ЛюбаяСсылка
// * ПредставлениеОбъектаОшибки - Строка
// * ИнформацияОбОшибке - ИнформацияОбОшибке, Строка
//
Функция ОписаниеОшибкиЗамены(Знач ТипОшибки, Знач ОбъектОшибки, Знач ПредставлениеОбъектаОшибки, Знач ИнформацияОбОшибке)
Результат = Новый Структура;
Результат.Вставить("ТипОшибки", ТипОшибки);
Результат.Вставить("ОбъектОшибки", ОбъектОшибки);
Результат.Вставить("ПредставлениеОбъектаОшибки", ПредставлениеОбъектаОшибки);
Результат.Вставить("ИнформацияОбОшибке", ИнформацияОбОшибке);
Возврат Результат;
КонецФункции
// Возвращаемое значение:
// Структура:
// * ЕстьОшибки - Булево
// * ОчередьКНепосредственномуУдалению - Массив
// * Ошибки - см. ОбщегоНазначения.ЗаменитьСсылки
//
Функция РезультатЗаменыСсылок(Знач ОшибкиЗамены)
Результат = Новый Структура;
Результат.Вставить("ЕстьОшибки", Ложь);
Результат.Вставить("ОчередьКНепосредственномуУдалению", Новый Массив);
Результат.Вставить("Ошибки", ОшибкиЗамены);
Возврат Результат
КонецФункции
Процедура ЗарегистрироватьОшибкуВТаблицу(Результат, Дубль, Оригинал, Данные, Информация, ТипОшибки, ИнформацияОбОшибке)
Результат.ЕстьОшибки = Истина;
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(),
УровеньЖурналаРегистрации.Ошибка,,,
ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
ПолноеПредставлениеДанных = Строка(Данные) + " (" + Информация.ПредставлениеЭлемента + ")";
Ошибка = Результат.Ошибки.Добавить();
Ошибка.Ссылка = Дубль;
Ошибка.ОбъектОшибки = Данные;
Ошибка.ПредставлениеОбъектаОшибки = ПолноеПредставлениеДанных;
Если ТипОшибки = "БлокировкаДляРегистра" Тогда
НовыйШаблон = НСтр("ru = 'Не удалось начать редактирование %1: %2'");
Ошибка.ТипОшибки = "ОшибкаБлокировки";
ИначеЕсли ТипОшибки = "БлокировкаДляУдаленияДубля" Тогда
НовыйШаблон = НСтр("ru = 'Не удалось начать удаление: %2'");
Ошибка.ТипОшибки = "ОшибкаБлокировки";
ИначеЕсли ТипОшибки = "УдалитьНаборДубля" Тогда
НовыйШаблон = НСтр("ru = 'Не удалось очистить сведения о дубле в %1: %2'");
Ошибка.ТипОшибки = "ОшибкаЗаписи";
ИначеЕсли ТипОшибки = "ЗаписатьНаборОригинала" Тогда
НовыйШаблон = НСтр("ru = 'Не удалось обновить сведения в %1: %2'");
Ошибка.ТипОшибки = "ОшибкаЗаписи";
Иначе
НовыйШаблон = ТипОшибки + " (%1): %2";
Ошибка.ТипОшибки = ТипОшибки;
КонецЕсли;
НовыйШаблон = НовыйШаблон + Символы.ПС + Символы.ПС + НСтр("ru = 'Подробности в журнале регистрации.'");
КраткоеПредставление = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
Ошибка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НовыйШаблон, ПолноеПредставлениеДанных, КраткоеПредставление);
КонецПроцедуры
// Формирует информацию о типе объекта метаданных: полное имя, представления, вид и т.п.
Функция ИнформацияОТипе(ПолноеИмяИлиМетаданныеИлиТип, Кэш)
ТипПервогоПараметра = ТипЗнч(ПолноеИмяИлиМетаданныеИлиТип);
Если ТипПервогоПараметра = Тип("Строка") Тогда
ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяИлиМетаданныеИлиТип);
Иначе
Если ТипПервогоПараметра = Тип("Тип") Тогда // Поиск объекта метаданных.
ОбъектМетаданных = Метаданные.НайтиПоТипу(ПолноеИмяИлиМетаданныеИлиТип);
Иначе
ОбъектМетаданных = ПолноеИмяИлиМетаданныеИлиТип;
КонецЕсли;
КонецЕсли;
ПолноеИмя = ВРег(ОбъектМетаданных.ПолноеИмя());
ИнформацияОТипах = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Кэш, "ИнформацияОТипах");
Если ИнформацияОТипах = Неопределено Тогда
ИнформацияОТипах = Новый Соответствие;
Кэш.Вставить("ИнформацияОТипах", ИнформацияОТипах);
Иначе
Информация = ИнформацияОТипах.Получить(ПолноеИмя);
Если Информация <> Неопределено Тогда
Возврат Информация;
КонецЕсли;
КонецЕсли;
Информация = Новый Структура("ПолноеИмя, ПредставлениеЭлемента,
|Вид, Ссылочный, Технический, Разделенный,
|Иерархический,
|ЕстьПодчиненные, ИменаПодчиненных,
|Измерения, Реквизиты, Ресурсы");
ИнформацияОТипах.Вставить(ПолноеИмя, Информация);
// Заполнение базовой информации.
Информация.ПолноеИмя = ПолноеИмя;
// Представление элемента.
Информация.ПредставлениеЭлемента = ПредставлениеОбъекта(ОбъектМетаданных);
// Вид и его свойства.
Информация.Вид = Лев(Информация.ПолноеИмя, СтрНайти(Информация.ПолноеИмя, ".")-1);
Если Информация.Вид = "СПРАВОЧНИК"
Или Информация.Вид = "ДОКУМЕНТ"
Или Информация.Вид = "ПЕРЕЧИСЛЕНИЕ"
Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК"
Или Информация.Вид = "ПЛАНСЧЕТОВ"
Или Информация.Вид = "ПЛАНВИДОВРАСЧЕТА"
Или Информация.Вид = "БИЗНЕСПРОЦЕСС"
Или Информация.Вид = "ЗАДАЧА"
Или Информация.Вид = "ПЛАНОБМЕНА" Тогда
Информация.Ссылочный = Истина;
Иначе
Информация.Ссылочный = Ложь;
КонецЕсли;
Если Информация.Вид = "СПРАВОЧНИК"
Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Тогда
Информация.Иерархический = ОбъектМетаданных.Иерархический;
ИначеЕсли Информация.Вид = "ПЛАНСЧЕТОВ" Тогда
Информация.Иерархический = Истина;
Иначе
Информация.Иерархический = Ложь;
КонецЕсли;
Информация.ЕстьПодчиненные = Ложь;
Если Информация.Вид = "СПРАВОЧНИК"
Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК"
Или Информация.Вид = "ПЛАНОБМЕНА"
Или Информация.Вид = "ПЛАНСЧЕТОВ"
Или Информация.Вид = "ПЛАНВИДОВРАСЧЕТА" Тогда
Для Каждого Справочник Из Метаданные.Справочники Цикл
Если Справочник.Владельцы.Содержит(ОбъектМетаданных) Тогда
Если Информация.ЕстьПодчиненные = Ложь Тогда
Информация.ЕстьПодчиненные = Истина;
Информация.ИменаПодчиненных = Новый Массив;
КонецЕсли;
ИменаПодчиненных = Информация.ИменаПодчиненных; // Массив -
ИменаПодчиненных.Добавить(Справочник.ПолноеИмя());
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если Информация.ПолноеИмя = "СПРАВОЧНИК.ИДЕНТИФИКАТОРЫОБЪЕКТОВМЕТАДАННЫХ"
Или Информация.ПолноеИмя = "СПРАВОЧНИК.ПРЕДОПРЕДЕЛЕННЫЕВАРИАНТЫОТЧЕТОВ" Тогда
Информация.Технический = Истина;
Информация.Разделенный = Ложь;
Иначе
Информация.Технический = Ложь;
Если Не Кэш.Свойство("МодельСервиса") Тогда
Кэш.Вставить("МодельСервиса", РазделениеВключено());
Если Кэш.МодельСервиса Тогда
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
РазделительОсновныхДанных = МодульРаботаВМоделиСервиса.РазделительОсновныхДанных();
РазделительВспомогательныхДанных = МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных();
Иначе
РазделительОсновныхДанных = Неопределено;
РазделительВспомогательныхДанных = Неопределено;
КонецЕсли;
Кэш.Вставить("ВОбластиДанных", РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных());
Кэш.Вставить("РазделительОсновныхДанных", РазделительОсновныхДанных);
Кэш.Вставить("РазделительВспомогательныхДанных", РазделительВспомогательныхДанных);
КонецЕсли;
КонецЕсли;
Если Кэш.МодельСервиса Тогда
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ОбъектМетаданных);
Иначе
ЭтоРазделенныйОбъектМетаданных = Истина;
КонецЕсли;
Информация.Разделенный = ЭтоРазделенныйОбъектМетаданных;
КонецЕсли;
КонецЕсли;
Информация.Измерения = Новый Структура;
Информация.Реквизиты = Новый Структура;
Информация.Ресурсы = Новый Структура;
ВидыРеквизитов = Новый Структура("СтандартныеРеквизиты, Реквизиты, Измерения, Ресурсы");
ЗаполнитьЗначенияСвойств(ВидыРеквизитов, ОбъектМетаданных);
Для Каждого КлючИЗначение Из ВидыРеквизитов Цикл
Коллекция = КлючИЗначение.Значение; // КоллекцияОбъектовМетаданных
Если ТипЗнч(Коллекция) = Тип("КоллекцияОбъектовМетаданных") Тогда
КудаПишем = ?(Информация.Свойство(КлючИЗначение.Ключ), Информация[КлючИЗначение.Ключ], Информация.Реквизиты);
Для Каждого Реквизит Из Коллекция Цикл
КудаПишем.Вставить(Реквизит.Имя, ИнформацияПоРеквизиту(Реквизит));
КонецЦикла;
КонецЕсли;
КонецЦикла;
Если Информация.Вид = "РЕГИСТРСВЕДЕНИЙ"
И ОбъектМетаданных.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда
ИнформацияПоРеквизиту = Новый Структура("Ведущее, Представление, Формат, Тип, ЗначениеПоУмолчанию, ЗаполнятьИзДанныхЗаполнения");
ИнформацияПоРеквизиту.Ведущее = Ложь;
ИнформацияПоРеквизиту.ЗаполнятьИзДанныхЗаполнения = Ложь;
Если ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.ПозицияРегистратора Тогда
ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("МоментВремени");
ИначеЕсли ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Секунда Тогда
ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя));
Иначе
ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата));
КонецЕсли;
Информация.Измерения.Вставить("Период", ИнформацияПоРеквизиту);
КонецЕсли;
Возврат Информация;
КонецФункции
// Параметры:
// МетаданныеРеквизита - ОбъектМетаданныхРеквизит
//
Функция ИнформацияПоРеквизиту(МетаданныеРеквизита)
// ОписаниеСтандартногоРеквизита
// ОбъектМетаданных: Измерение
// ОбъектМетаданных: Ресурс
// ОбъектМетаданных: Реквизит
Информация = Новый Структура("Ведущее, Представление, Формат, Тип, ЗначениеПоУмолчанию, ЗаполнятьИзДанныхЗаполнения");
ЗаполнитьЗначенияСвойств(Информация, МетаданныеРеквизита);
Информация.Представление = МетаданныеРеквизита.Представление();
Если Информация.ЗаполнятьИзДанныхЗаполнения = Истина Тогда
Информация.ЗначениеПоУмолчанию = МетаданныеРеквизита.ЗначениеЗаполнения;
Иначе
Информация.ЗначениеПоУмолчанию = МетаданныеРеквизита.Тип.ПривестиЗначение();
КонецЕсли;
Возврат Информация;
КонецФункции
Процедура ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, ЕстьОшибки)
КлючДубля = Дубль.Метаданные().ПолноеИмя();
ЭлементСтатистики = Статистика[КлючДубля];
Если ЭлементСтатистики = Неопределено Тогда
ЭлементСтатистики = Новый Структура("КоличествоЭлементов, КоличествоОшибок",0,0);
Статистика.Вставить(КлючДубля, ЭлементСтатистики);
КонецЕсли;
ЭлементСтатистики.КоличествоЭлементов = ЭлементСтатистики.КоличествоЭлементов + 1;
ЭлементСтатистики.КоличествоОшибок = ЭлементСтатистики.КоличествоОшибок + ?(ЕстьОшибки, 1,0);
КонецПроцедуры
Процедура ОтправитьСтатистикуЗаменыСсылок(Статистика)
Если НЕ ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда
Возврат;
КонецЕсли;
МодульЦентрМониторинга = ОбщийМодуль("ЦентрМониторинга");
Для каждого ЭлементСтатистики Из Статистика Цикл
МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики(
"БазоваяФункциональность.ЗаменаСсылок." + ЭлементСтатистики.Ключ, ЭлементСтатистики.Значение.КоличествоЭлементов);
МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики(
"БазоваяФункциональность.ЗаменаСсылокКоличествоОшибок." + ЭлементСтатистики.Ключ, ЭлементСтатистики.Значение.КоличествоОшибок);
КонецЦикла;
КонецПроцедуры
Процедура ДополнитьИсключенияПоискаСсылокПодчиненнымиОбъектами(Знач ИсключенияПоискаСсылок)
Для каждого ОписаниеПодчиненногоОбъекта Из ПодчиненныеОбъекты() Цикл
ПоляСвязи = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(
ОписаниеПодчиненногоОбъекта.ПоляСвязей, ",",, Истина);
ЗначениеИсключенияПоискаСсылок = Новый Массив;
Для каждого ПолеСвязи Из ПоляСвязи Цикл
ЗначениеИсключенияПоискаСсылок.Добавить(ПолеСвязи);
КонецЦикла;
ИсключенияПоискаСсылок.Вставить(ОписаниеПодчиненногоОбъекта.ПодчиненныйОбъект, ЗначениеИсключенияПоискаСсылок);
КонецЦикла;
КонецПроцедуры
Процедура ЗарегистрироватьОшибкиУдаления(Результат, ПрепятствующиеУдалению, ПараметрыВыполнения)
ПредставленияСсылок = ПредметыСтрокой(ПрепятствующиеУдалению.ВыгрузитьКолонку("МестоИспользования"));
Для каждого ПрепятствующийУдалению Из ПрепятствующиеУдалению Цикл
ТекстОшибки = НСтр("ru = 'Элемент не удален, т.к. на него есть ссылки.'");
ОписаниеОшибки = ОписаниеОшибкиЗамены("ОшибкаУдаления", ПрепятствующийУдалению.МестоИспользования,
ПредставленияСсылок[ПрепятствующийУдалению.МестоИспользования], ТекстОшибки);
ЗарегистрироватьОшибкуЗамены(Результат, ПрепятствующийУдалению.УдаляемыйСсылка, ОписаниеОшибки,
ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЦикла;
КонецПроцедуры
Функция СформироватьДубли(ПараметрыВыполнения, ПараметрыЗамены, ПарыЗамен, Результат)
Дубли = Новый Массив;
Для Каждого КлючЗначение Из ПарыЗамен Цикл
Дубль = КлючЗначение.Ключ;
Оригинал = КлючЗначение.Значение;
Если Дубль = Оригинал Или Дубль.Пустая() Тогда
Продолжить; // Самого на себя и пустые ссылки не заменяем.
КонецЕсли;
Дубли.Добавить(Дубль);
// Пропускаем промежуточные замены, чтобы не строить граф (если A->B и B->C то вместо A->B производится замена A->C).
ОригиналОригинала = ПарыЗамен[Оригинал];
ЕстьОригиналОригинала = (ОригиналОригинала <> Неопределено И ОригиналОригинала <> Дубль И ОригиналОригинала <> Оригинал);
Если ЕстьОригиналОригинала Тогда
Пока ЕстьОригиналОригинала Цикл
Оригинал = ОригиналОригинала;
ОригиналОригинала = ПарыЗамен[Оригинал];
ЕстьОригиналОригинала = (ОригиналОригинала <> Неопределено И ОригиналОригинала <> Дубль И ОригиналОригинала <> Оригинал);
КонецЦикла;
ПарыЗамен.Вставить(Дубль, Оригинал);
КонецЕсли;
КонецЦикла;
Если ПараметрыВыполнения.УчитыватьПрикладныеПравила И ПодсистемаСуществует("СтандартныеПодсистемы.ПоискИУдалениеДублей") Тогда
МодульПоискИУдалениеДублей = ОбщийМодуль("ПоискИУдалениеДублей");
Ошибки = МодульПоискИУдалениеДублей.ПроверитьВозможностьЗаменыЭлементов(ПарыЗамен, ПараметрыЗамены);
ОригиналыОбъектов = Новый Массив;
Для Каждого КлючЗначение Из Ошибки Цикл
Дубль = КлючЗначение.Ключ;
ОригиналыОбъектов.Добавить(ПарыЗамен[Дубль]);
Индекс = Дубли.Найти(Дубль);
Если Индекс <> Неопределено Тогда
Дубли.Удалить(Индекс); // пропускаем проблемный элемент.
КонецЕсли;
КонецЦикла;
ПредставленияОбъектов = ПредметыСтрокой(ОригиналыОбъектов);
Для Каждого КлючЗначение Из Ошибки Цикл
Дубль = КлючЗначение.Ключ;
Оригинал = ПарыЗамен[Дубль];
ТекстОшибки = КлючЗначение.Значение;
Причина = ОписаниеОшибкиЗамены("ОшибкаЗаписи", Оригинал, ПредставленияОбъектов[Оригинал], ТекстОшибки);
ЗарегистрироватьОшибкуЗамены(Результат, Дубль, Причина, ПараметрыВыполнения.ПодчиненныеКДублям);
КонецЦикла;
КонецЕсли;
Возврат Дубли;
КонецФункции
Функция НовыйПараметрыВыполненияЗаменыСсылок(Знач ПараметрыЗамены)
ПараметрыПоУмолчанию = ПараметрыЗаменыСсылок();
ПараметрыВыполнения = Новый Структура;
ПараметрыВыполнения.Вставить("УдалятьНепосредственно", ПараметрыПоУмолчанию.СпособУдаления = "Непосредственно");
ПараметрыВыполнения.Вставить("ПомечатьНаУдаление", ПараметрыПоУмолчанию.СпособУдаления = "Пометка");
ПараметрыВыполнения.Вставить("ВключатьБизнесЛогику", ПараметрыПоУмолчанию.ВключатьБизнесЛогику);
ПараметрыВыполнения.Вставить("ПривилегированнаяЗапись", ПараметрыПоУмолчанию.ПривилегированнаяЗапись);
ПараметрыВыполнения.Вставить("УчитыватьПрикладныеПравила", ПараметрыПоУмолчанию.УчитыватьПрикладныеПравила);
ПараметрыВыполнения.Вставить("МестаЗамены", Новый Массив);
// Переданные параметры обрабатываются условно для обратной совместимости.
ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "СпособУдаления");
Если ЗначениеПараметра = "Непосредственно" Тогда
ПараметрыВыполнения.УдалятьНепосредственно = Истина;
ПараметрыВыполнения.ПомечатьНаУдаление = Ложь;
ИначеЕсли ЗначениеПараметра = "Пометка" Тогда
ПараметрыВыполнения.УдалятьНепосредственно = Ложь;
ПараметрыВыполнения.ПомечатьНаУдаление = Истина;
КонецЕсли;
ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "ВключатьБизнесЛогику");
Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда
ПараметрыВыполнения.ВключатьБизнесЛогику = ЗначениеПараметра;
КонецЕсли;
ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "ПривилегированнаяЗапись");
Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда
ПараметрыВыполнения.ПривилегированнаяЗапись = ЗначениеПараметра;
КонецЕсли;
ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "УчитыватьПрикладныеПравила");
Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда
ПараметрыВыполнения.УчитыватьПрикладныеПравила = ЗначениеПараметра;
КонецЕсли;
ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "МестаЗамены", Новый Массив);
Если (ЗначениеПараметра.Количество() > 0) Тогда
ПараметрыВыполнения.МестаЗамены = Новый Массив(Новый ФиксированныйМассив(ЗначениеПараметра));
КонецЕсли;
Возврат ПараметрыВыполнения;
КонецФункции
#КонецОбласти
#Область МестаИспользования
Функция ОписаниеТипаКлючиЗаписей()
ДобавляемыеТипы = Новый Массив;
Для Каждого Мета Из Метаданные.РегистрыСведений Цикл
ДобавляемыеТипы.Добавить(Тип("РегистрСведенийКлючЗаписи." + Мета.Имя));
КонецЦикла;
Для Каждого Мета Из Метаданные.РегистрыНакопления Цикл
ДобавляемыеТипы.Добавить(Тип("РегистрНакопленияКлючЗаписи." + Мета.Имя));
КонецЦикла;
Для Каждого Мета Из Метаданные.РегистрыБухгалтерии Цикл
ДобавляемыеТипы.Добавить(Тип("РегистрБухгалтерииКлючЗаписи." + Мета.Имя));
КонецЦикла;
Для Каждого Мета Из Метаданные.РегистрыРасчета Цикл
ДобавляемыеТипы.Добавить(Тип("РегистрРасчетаКлючЗаписи." + Мета.Имя));
КонецЦикла;
Возврат Новый ОписаниеТипов(ДобавляемыеТипы);
КонецФункции
Функция ОписаниеИзмеренийНабора(Знач МетаданныеРегистра, КэшИзмеренийРегистров)
ОписаниеИзмерений = КэшИзмеренийРегистров[МетаданныеРегистра];
Если ОписаниеИзмерений <> Неопределено Тогда
Возврат ОписаниеИзмерений;
КонецЕсли;
// Период и регистратор, если есть.
ОписаниеИзмерений = Новый Структура;
ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип", Ложь);
Если Метаданные.РегистрыСведений.Содержит(МетаданныеРегистра) Тогда
// Возможно есть период
МетаПериод = МетаданныеРегистра.ПериодичностьРегистраСведений;
Периодичность = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений;
Если МетаПериод = Периодичность.ПозицияРегистратора Тогда
ДанныеИзмерения.Тип = Документы.ТипВсеСсылки();
ДанныеИзмерения.Представление = НСтр("ru = 'Регистратор'");
ДанныеИзмерения.Ведущее = Истина;
ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения);
ИначеЕсли МетаПериод = Периодичность.Год Тогда
ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата");
ДанныеИзмерения.Представление = НСтр("ru = 'Период'");
ДанныеИзмерения.Формат = НСтр("ru = 'ДФ=''yyyy ""г.""''; ДП=''Дата не задана'''");
ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения);
ИначеЕсли МетаПериод = Периодичность.День Тогда
ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата");
ДанныеИзмерения.Представление = НСтр("ru = 'Период'");
ДанныеИзмерения.Формат = НСтр("ru = 'ДЛФ=D; ДП=''Дата не задана'''");
ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения);
ИначеЕсли МетаПериод = Периодичность.Квартал Тогда
ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата");
ДанныеИзмерения.Представление = НСтр("ru = 'Период'");
ДанныеИзмерения.Формат = НСтр("ru = 'ДФ=''к """"квартал """"yyyy """"г.""""''; ДП=''Дата не задана'''");
ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения);
ИначеЕсли МетаПериод = Периодичность.Месяц Тогда
ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата");
ДанныеИзмерения.Представление = НСтр("ru = 'Период'");
ДанныеИзмерения.Формат = НСтр("ru = 'ДФ=''ММММ yyyy """"г.""""''; ДП=''Дата не задана'''");
ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения);
ИначеЕсли МетаПериод = Периодичность.Секунда Тогда
ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата");
ДанныеИзмерения.Представление = НСтр("ru = 'Период'");
ДанныеИзмерения.Формат = НСтр("ru = 'ДЛФ=DT; ДП=''Дата не задана'''");
ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения);
КонецЕсли;
Иначе
ДанныеИзмерения.Тип = Документы.ТипВсеСсылки();
ДанныеИзмерения.Представление = НСтр("ru = 'Регистратор'");
ДанныеИзмерения.Ведущее = Истина;
ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения);
КонецЕсли;
// Все измерения
Для Каждого МетаИзмерение Из МетаданныеРегистра.Измерения Цикл
ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип");
ДанныеИзмерения.Тип = МетаИзмерение.Тип;
ДанныеИзмерения.Представление = МетаИзмерение.Представление();
ДанныеИзмерения.Ведущее = МетаИзмерение.Ведущее;
ОписаниеИзмерений.Вставить(МетаИзмерение.Имя, ДанныеИзмерения);
КонецЦикла;
КэшИзмеренийРегистров[МетаданныеРегистра] = ОписаниеИзмерений;
Возврат ОписаниеИзмерений;
КонецФункции
#КонецОбласти
#КонецОбласти
#Область Данные
Функция СравниваемыеКолонки(Знач КоллекцияСтрок, Знач ИменаКолонок, Знач ИсключаяКолонки)
Если ПустаяСтрока(ИменаКолонок) Тогда
ТипКоллекции = ТипЗнч(КоллекцияСтрок);
ЭтоСписокЗначений = (ТипКоллекции = Тип("СписокЗначений"));
ЭтоТаблицаЗначений = (ТипКоллекции = Тип("ТаблицаЗначений"));
ЭтоКоллекцияКлючИЗначение = (ТипКоллекции = Тип("Соответствие"))
Или (ТипКоллекции = Тип("Структура"))
Или (ТипКоллекции = Тип("ФиксированноеСоответствие"))
Или (ТипКоллекции = Тип("ФиксированнаяСтруктура"));
СравниваемыеКолонки = Новый Массив;
Если ЭтоТаблицаЗначений Тогда
Для Каждого Колонка Из КоллекцияСтрок.Колонки Цикл
СравниваемыеКолонки.Добавить(Колонка.Имя);
КонецЦикла;
ИначеЕсли ЭтоСписокЗначений Тогда
СравниваемыеКолонки.Добавить("Значение");
СравниваемыеКолонки.Добавить("Картинка");
СравниваемыеКолонки.Добавить("Пометка");
СравниваемыеКолонки.Добавить("Представление");
ИначеЕсли ЭтоКоллекцияКлючИЗначение Тогда
СравниваемыеКолонки.Добавить("Ключ");
СравниваемыеКолонки.Добавить("Значение");
Иначе
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение параметра %1 (тип %2) в %3. Укажите имена полей, по которым производится сравнение.'"),
"КоллекцияСтрок1", ТипКоллекции, "ОбщегоНазначения.КоллекцииИдентичны"),
КатегорияОшибки.ОшибкаКонфигурации);
КонецЕсли;
Иначе
СравниваемыеКолонки = СтрРазделить(СтрЗаменить(ИменаКолонок, " ", ""), ",");
КонецЕсли;
// Вычитаем исключаемые поля
Если Не ПустаяСтрока(ИсключаяКолонки) Тогда
ИсключаяКолонки = СтрРазделить(СтрЗаменить(ИсключаяКолонки, " ", ""), ",");
СравниваемыеКолонки = ОбщегоНазначенияКлиентСервер.РазностьМассивов(СравниваемыеКолонки, ИсключаяКолонки);
КонецЕсли;
Возврат СравниваемыеКолонки;
КонецФункции
Функция СравнитьСУчетомПоследовательности(Знач КоллекцияСтрок1, Знач КоллекцияСтрок2, Знач СравниваемыеКолонки)
ТипКоллекции = ТипЗнч(КоллекцияСтрок1);
СравниваютсяМассивы = (ТипКоллекции = Тип("Массив") Или ТипКоллекции = Тип("ФиксированныйМассив"));
// Параллельный обход обеих коллекций.
НомерСтрокиКоллекции1 = 0;
Для Каждого СтрокаКоллекции1 Из КоллекцияСтрок1 Цикл
// Спозиционируемся на аналогичную строку второй коллекции.
НомерСтрокиКоллекции2 = 0;
ЕстьСтрокиКоллекции2 = Ложь;
Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл
ЕстьСтрокиКоллекции2 = Истина;
Если НомерСтрокиКоллекции2 = НомерСтрокиКоллекции1 Тогда
Прервать;
КонецЕсли;
НомерСтрокиКоллекции2 = НомерСтрокиКоллекции2 + 1;
КонецЦикла;
Если Не ЕстьСтрокиКоллекции2 Тогда
// Во второй коллекции вообще нет строк.
Возврат Ложь;
КонецЕсли;
// Сравниваем значения полей двух строк.
Если СравниваютсяМассивы Тогда
Если СтрокаКоллекции1 <> СтрокаКоллекции2 Тогда
Возврат Ложь;
КонецЕсли;
Иначе
Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл
Если СтрокаКоллекции1[ИмяКолонки] <> СтрокаКоллекции2[ИмяКолонки] Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
КонецЕсли;
НомерСтрокиКоллекции1 = НомерСтрокиКоллекции1 + 1;
КонецЦикла;
КоличествоСтрокКоллекции1 = НомерСтрокиКоллекции1;
// Отдельно подсчитаем количество строк второй коллекции.
КоличествоСтрокКоллекции2 = 0;
Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл
КоличествоСтрокКоллекции2 = КоличествоСтрокКоллекции2 + 1;
КонецЦикла;
// Если в первой коллекции не оказалось строк,
// то их не должно быть и во второй.
Если КоличествоСтрокКоллекции1 = 0 Тогда
Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл
Возврат Ложь;
КонецЦикла;
КоличествоСтрокКоллекции2 = 0;
КонецЕсли;
// Количество строк не должно отличаться.
Если КоличествоСтрокКоллекции1 <> КоличествоСтрокКоллекции2 Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
Функция СравнитьБезУчетаПоследовательности(Знач КоллекцияСтрок1, Знач КоллекцияСтрок2, Знач СравниваемыеКолонки)
// Строки отбора накапливаем по первой коллекции для того, чтобы:
// - повторно не искать одинаковые строки,
// - убедиться, что во второй коллекции ни одной такой строки, которой нет в накопленных.
СтрокиОтбора = Новый ТаблицаЗначений;
ПараметрыОтбора = Новый Структура;
Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл
СтрокиОтбора.Колонки.Добавить(ИмяКолонки);
ПараметрыОтбора.Вставить(ИмяКолонки);
КонецЦикла;
ЕстьСтрокиКоллекции1 = Ложь;
Для Каждого СтрокаОтбора Из КоллекцияСтрок1 Цикл
ЗаполнитьЗначенияСвойств(ПараметрыОтбора, СтрокаОтбора);
Если СтрокиОтбора.НайтиСтроки(ПараметрыОтбора).Количество() > 0 Тогда
// Строку с такими полями уже искали.
Продолжить;
КонецЕсли;
ЗаполнитьЗначенияСвойств(СтрокиОтбора.Добавить(), СтрокаОтбора);
// Подсчитаем количество таких строк в первой коллекции.
НайденоСтрокКоллекции1 = 0;
Для Каждого СтрокаКоллекции1 Из КоллекцияСтрок1 Цикл
СтрокаПодходит = Истина;
Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл
Если СтрокаКоллекции1[ИмяКолонки] <> СтрокаОтбора[ИмяКолонки] Тогда
СтрокаПодходит = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
Если СтрокаПодходит Тогда
НайденоСтрокКоллекции1 = НайденоСтрокКоллекции1 + 1;
КонецЕсли;
КонецЦикла;
// Подсчитаем количество таких строк во второй коллекции.
НайденоСтрокКоллекции2 = 0;
Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл
СтрокаПодходит = Истина;
Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл
Если СтрокаКоллекции2[ИмяКолонки] <> СтрокаОтбора[ИмяКолонки] Тогда
СтрокаПодходит = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
Если СтрокаПодходит Тогда
НайденоСтрокКоллекции2 = НайденоСтрокКоллекции2 + 1;
// Если количество таких строк во второй коллекции превысило количество в первой,
// то уже можно сделать вывод, что коллекции не идентичны.
Если НайденоСтрокКоллекции2 > НайденоСтрокКоллекции1 Тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Количество таких строк не должно отличаться.
Если НайденоСтрокКоллекции1 <> НайденоСтрокКоллекции2 Тогда
Возврат Ложь;
КонецЕсли;
ЕстьСтрокиКоллекции1 = Истина;
КонецЦикла;
// Если в первой коллекции не оказалось строк,
// то их не должно быть и во второй.
Если Не ЕстьСтрокиКоллекции1 Тогда
Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл
Возврат Ложь;
КонецЦикла;
КонецЕсли;
// Проверим, что во второй коллекции нет ни одной такой строки, которой нет в накопленных.
Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл
ЗаполнитьЗначенияСвойств(ПараметрыОтбора, СтрокаКоллекции2);
Если СтрокиОтбора.НайтиСтроки(ПараметрыОтбора).Количество() = 0 Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Функция СравнитьМассивы(Знач Массив1, Знач Массив2)
Если Массив1.Количество() <> Массив2.Количество() Тогда
Возврат Ложь;
КонецЕсли;
Для Каждого Элемент Из Массив1 Цикл
Если Массив2.Найти(Элемент) = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Процедура ПроверкаФиксированностиДанных(Данные, ДанныеВЗначенииФиксированныхТипов = Ложь)
ТипДанных = ТипЗнч(Данные);
СоставТипов = Новый ОписаниеТипов(
"ХранилищеЗначения,
|ФиксированныйМассив,
|ФиксированнаяСтруктура,
|ФиксированноеСоответствие");
Если СоставТипов.СодержитТип(ТипДанных) Тогда
Возврат;
КонецЕсли;
Если ДанныеВЗначенииФиксированныхТипов Тогда
СоставТипов = Новый ОписаниеТипов(
"Булево,Строка,Число,Дата,
|Неопределено,УникальныйИдентификатор,Null,Тип,
|РежимОтправкиИнформацииОбОшибке,
|ХранилищеЗначения,ОбщийМодуль,ОбъектМетаданных,
|ТипЗначенияXDTO,ТипОбъектаXDTO,
|ИдентификаторОбсужденияСистемыВзаимодействия");
Если СоставТипов.СодержитТип(ТипДанных)
Или ЭтоСсылка(ТипДанных) Тогда
Возврат;
КонецЕсли;
КонецЕсли;
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение параметра %1 в функции %2. Данные типа %3 не могут быть зафиксированы.'"),
"Данные", "ОбщегоНазначения.ФиксированныеДанные", Строка(ТипДанных)),
КатегорияОшибки.ОшибкаКонфигурации);
КонецПроцедуры
Функция РазмерСтрокиВБайтах(Знач Строка)
Возврат ПолучитьДвоичныеДанныеИзСтроки(Строка, "UTF-8").Размер();
КонецФункции
#Область СкопироватьРекурсивно
Функция СкопироватьСтруктуру(СтруктураИсточник, ФиксироватьДанные)
СтруктураРезультат = Новый Структура;
Для Каждого КлючИЗначение Из СтруктураИсточник Цикл
СтруктураРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные));
КонецЦикла;
Если ФиксироватьДанные = Истина
Или ФиксироватьДанные = Неопределено
И ТипЗнч(СтруктураИсточник) = Тип("ФиксированнаяСтруктура") Тогда
Возврат Новый ФиксированнаяСтруктура(СтруктураРезультат);
КонецЕсли;
Возврат СтруктураРезультат;
КонецФункции
Функция СкопироватьСоответствие(СоответствиеИсточник, ФиксироватьДанные)
СоответствиеРезультат = Новый Соответствие;
Для Каждого КлючИЗначение Из СоответствиеИсточник Цикл
СоответствиеРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные));
КонецЦикла;
Если ФиксироватьДанные = Истина
Или ФиксироватьДанные = Неопределено
И ТипЗнч(СоответствиеИсточник) = Тип("ФиксированноеСоответствие") Тогда
Возврат Новый ФиксированноеСоответствие(СоответствиеРезультат);
КонецЕсли;
Возврат СоответствиеРезультат;
КонецФункции
Функция СкопироватьМассив(МассивИсточник, ФиксироватьДанные)
МассивРезультат = Новый Массив;
Для Каждого Элемент Из МассивИсточник Цикл
МассивРезультат.Добавить(СкопироватьРекурсивно(Элемент, ФиксироватьДанные));
КонецЦикла;
Если ФиксироватьДанные = Истина
Или ФиксироватьДанные = Неопределено
И ТипЗнч(МассивИсточник) = Тип("ФиксированныйМассив") Тогда
Возврат Новый ФиксированныйМассив(МассивРезультат);
КонецЕсли;
Возврат МассивРезультат;
КонецФункции
Функция СкопироватьСписокЗначений(СписокИсточник, ФиксироватьДанные)
СписокРезультат = Новый СписокЗначений;
Для Каждого ЭлементСписка Из СписокИсточник Цикл
СписокРезультат.Добавить(
СкопироватьРекурсивно(ЭлементСписка.Значение, ФиксироватьДанные),
ЭлементСписка.Представление,
ЭлементСписка.Пометка,
ЭлементСписка.Картинка);
КонецЦикла;
Возврат СписокРезультат;
КонецФункции
Процедура СкопироватьЗначенияТаблицыЗначений(ТаблицаЗначений, ФиксироватьДанные)
Для Каждого СтрокаТаблицыЗначений Из ТаблицаЗначений Цикл
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
СтрокаТаблицыЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаТаблицыЗначений[Колонка.Имя], ФиксироватьДанные);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура СкопироватьЗначенияСтрокиДереваЗначений(СтрокиДереваЗначений, ФиксироватьДанные);
Для Каждого СтрокаДереваЗначений Из СтрокиДереваЗначений Цикл
Для Каждого Колонка Из СтрокаДереваЗначений.Владелец().Колонки Цикл
СтрокаДереваЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаДереваЗначений[Колонка.Имя], ФиксироватьДанные);
КонецЦикла;
СкопироватьЗначенияСтрокиДереваЗначений(СтрокаДереваЗначений.Строки, ФиксироватьДанные);
КонецЦикла;
КонецПроцедуры
Функция ЭтоВнешнийОтчетИлиВнешняяОбработка(ОбъектМетода)
Попытка
ПолноеИмя = ОбъектМетода.Метаданные().ПолноеИмя();
Исключение
Возврат Ложь;
КонецПопытки;
ЧастиИмени = СтрРазделить(ПолноеИмя, ".");
Если ЧастиИмени.Количество() <> 2 Тогда
Возврат Ложь;
КонецЕсли;
ИмяВидаОбъекта = ЧастиИмени[0];
Возврат ИмяВидаОбъекта = "ВнешнийОтчет" // @Non-NLS
Или ИмяВидаОбъекта = "ВнешняяОбработка" // @Non-NLS
Или ИмяВидаОбъекта = "ExternalReport"
Или ИмяВидаОбъекта = "ExternalDataProcessor";
КонецФункции
#КонецОбласти
#КонецОбласти
#Область ХранилищеНастроек
Процедура ХранилищеСохранить(МенеджерХранилища, КлючОбъекта, КлючНастроек, Настройки,
ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения)
Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
Возврат;
КонецЕсли;
МенеджерХранилища.Сохранить(КлючОбъекта, КлючНастроек(КлючНастроек), Настройки,
ОписаниеНастроек, ИмяПользователя);
Если ОбновитьПовторноИспользуемыеЗначения Тогда
ОбновитьПовторноИспользуемыеЗначения();
КонецЕсли;
КонецПроцедуры
Функция ХранилищеЗагрузить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию,
ОписаниеНастроек, ИмяПользователя)
Результат = Неопределено;
Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
Результат = МенеджерХранилища.Загрузить(КлючОбъекта, КлючНастроек(КлючНастроек),
ОписаниеНастроек, ИмяПользователя);
КонецЕсли;
Если Результат = Неопределено Тогда
Результат = ЗначениеПоУмолчанию;
Иначе
УстановитьПривилегированныйРежим(Истина);
Если ОчиститьНесуществующиеСсылки(Результат) Тогда
Результат = ЗначениеПоУмолчанию;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
// Удаляет из переданной коллекции ссылки, ссылающиеся на несуществующие данные в информационной базе.
// Не очищает переданное значение, если в нем передана несуществующая ссылка, а возвращает Ложь.
//
// Параметры:
// Значение - ЛюбаяСсылка
// - Произвольный - проверяемое значение или коллекция.
//
// Возвращаемое значение:
// Булево - Истина, если Значение ссылочного типа и объект не существует в информационной базе.
// Ложь, если Значение не ссылочного типа или объект существует.
//
Функция ОчиститьНесуществующиеСсылки(Значение)
Тип = ТипЗнч(Значение);
Если Тип = Тип("Неопределено")
Или Тип = Тип("Булево")
Или Тип = Тип("Строка")
Или Тип = Тип("Число")
Или Тип = Тип("Дата") Тогда // Оптимизация - часто используемые примитивные типы.
Возврат Ложь; // Не ссылка.
ИначеЕсли Тип = Тип("Массив") Тогда
Количество = Значение.Количество();
Для Номер = 1 По Количество Цикл
ОбратныйИндекс = Количество - Номер;
// @skip-check query-in-loop - выборка ссылок из разных таблиц.
Если ОчиститьНесуществующиеСсылки(Значение[ОбратныйИндекс]) Тогда
Значение.Удалить(ОбратныйИндекс);
КонецЕсли;
КонецЦикла;
Возврат Ложь; // Не ссылка.
ИначеЕсли Тип = Тип("Структура")
Или Тип = Тип("Соответствие") Тогда
Для Каждого КлючИЗначение Из Значение Цикл
// @skip-check query-in-loop - выборка ссылок из разных таблиц.
Если ОчиститьНесуществующиеСсылки(КлючИЗначение.Значение) Тогда
Значение.Вставить(КлючИЗначение.Ключ, Неопределено);
КонецЕсли;
КонецЦикла;
Возврат Ложь; // Не ссылка.
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(Тип)
Или Справочники.ТипВсеСсылки().СодержитТип(Тип)
Или Перечисления.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыСчетов.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыОбмена.ТипВсеСсылки().СодержитТип(Тип)
Или БизнесПроцессы.ТипВсеСсылки().СодержитТип(Тип)
Или Задачи.ТипВсеСсылки().СодержитТип(Тип) Тогда
// Ссылочный тип, исключая ТочкаМаршрутаБизнесПроцессаСсылка.
Если Значение.Пустая() Тогда
Возврат Ложь; // Ссылка пустая.
КонецЕсли;
Возврат ЗначениеРеквизитаОбъекта(Значение, "Ссылка") = Неопределено;
Иначе
Возврат Ложь; // Не ссылка.
КонецЕсли;
КонецФункции
Процедура ХранилищеУдалить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ИмяПользователя)
Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
МенеджерХранилища.Удалить(КлючОбъекта, КлючНастроек(КлючНастроек), ИмяПользователя);
КонецЕсли;
КонецПроцедуры
// Возвращает строку ключа настроек, не превышающую допустимую длину 128 символов.
// Если указанная строка превышает 128, тогда вместо символов сверх 96 символов
// добавляется их хеш-сумма по алгоритму MD5 размером 32 символа.
//
// Параметры:
// Строка - Строка - строка произвольной длины.
//
// Возвращаемое значение:
// Строка - не более 128 символов.
//
Функция КлючНастроек(Знач Строка)
Возврат СократитьСтрокуКонтрольнойСуммой(Строка, 128);
КонецФункции
#КонецОбласти
#Область БезопасноеХранилище
Функция ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные, ОбластьДанных)
ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанных";
ЗапросОбласти = (РазделениеВключено()
И ОбщиеДанные <> Истина
И (ДоступноИспользованиеРазделенныхДанных()
Или ЗначениеЗаполнено(ОбластьДанных)));
Если ЗапросОбласти Тогда
ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных";
КонецЕсли;
ТекстЗапроса =
"ВЫБРАТЬ
| БезопасноеХранилищеДанных.Владелец КАК ВладелецДанных,
| БезопасноеХранилищеДанных.Данные КАК Данные
|ИЗ
| #ИмяБезопасногоХранилищаДанных КАК БезопасноеХранилищеДанных
|ГДЕ
| &Условие";
ТекстЗапроса = СтрЗаменить(
ТекстЗапроса,
"#ИмяБезопасногоХранилищаДанных",
ИмяБезопасногоХранилищаДанных);
ТекстЗапроса = ?((ЗначениеЗаполнено(ОбластьДанных) И ЗапросОбласти),
СтрЗаменить(
ТекстЗапроса,
"&Условие",
"БезопасноеХранилищеДанных.Владелец В (&Владельцы)
|И БезопасноеХранилищеДанных.ОбластьДанныхВспомогательныеДанные = &ОбластьДанных"),
СтрЗаменить(
ТекстЗапроса,
"&Условие",
"БезопасноеХранилищеДанных.Владелец В (&Владельцы)"));
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Владельцы", Владельцы);
Запрос.УстановитьПараметр("ОбластьДанных", ОбластьДанных);
РезультатЗапроса = Запрос.Выполнить().Выбрать();
Результат = Новый Соответствие();
НаборДанныхКлюча = ?(ЗначениеЗаполнено(Ключи) И СтрНайти(Ключи, ","), Новый Структура(Ключи), Неопределено);
Для Каждого ВладелецДанных Из Владельцы Цикл
Результат.Вставить(ВладелецДанных, НаборДанныхКлюча);
КонецЦикла;
Пока РезультатЗапроса.Следующий() Цикл
ДанныеВладельца = Новый Структура(Ключи);
Если ЗначениеЗаполнено(РезультатЗапроса.Данные) Тогда
СохраненныеДанные = РезультатЗапроса.Данные.Получить();
Если ЗначениеЗаполнено(СохраненныеДанные) Тогда
Если ЗначениеЗаполнено(Ключи) Тогда
ВладелецДанных = Результат[РезультатЗапроса.ВладелецДанных];
ЗаполнитьЗначенияСвойств(ДанныеВладельца, СохраненныеДанные);
Иначе
ДанныеВладельца = СохраненныеДанные;
КонецЕсли;
Если Ключи <> Неопределено
И ДанныеВладельца <> Неопределено
И ДанныеВладельца.Количество() = 1 Тогда
ЗначениеПоКлючу = ?(ДанныеВладельца.Свойство(Ключи), ДанныеВладельца[Ключи], Неопределено);
Результат.Вставить(РезультатЗапроса.ВладелецДанных, ЗначениеПоКлючу);
Иначе
Результат.Вставить(РезультатЗапроса.ВладелецДанных, ДанныеВладельца);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область БезопасноеВыполнениеВнешнегоКода
// Возвращает менеджер объекта по имени.
//
// Параметры:
// Имя - Строка - имя например, "Справочники.Организации", "Справочник.Организации", "Справочники", "Справочник".
// ЭтоПолноеИмя - Неопределено, Булево
// ЭтоИмяМенеджера - Неопределено, Булево
// ТребуетсяМодульМенеджера - Булево
// ИмяВызывающейПроцедуры - Строка
// ИмяПараметра - Строка
// МенеджерПоТочномуИмени - Булево - если Ложь,
// тогда для вложенных объектов (форм, реквизитов, ...)
// возвращается менеджер основного объекта (по первым двум частям имени через точку),
// при этом для перерасчетов возвращается менеджер перерасчета (по первым четырем частям имени через точку).
//
// Возвращаемое значение:
// - см. МенеджерОбъектаПоПолномуИмени
// - ПланыОбменаМенеджер
// - КритерииОтбораМенеджер
// - ХранилищаНастроекМенеджер
// - WSСсылкиМенеджер
// - СервисыИнтеграцииМенеджер
// - КонстантыМенеджер
// - СправочникиМенеджер
// - ДокументыМенеджер
// - ПоследовательностиМенеджер
// - ЖурналыДокументовМенеджер
// - ПеречисленияМенеджер
// - ОтчетыМенеджер
// - ОбработкиМенеджер
// - ПланыВидовХарактеристикМенеджер
// - ПланыСчетовМенеджер
// - ПланыВидовРасчетаМенеджер
// - РегистрыСведенийМенеджер
// - РегистрыНакопленияМенеджер
// - РегистрыБухгалтерииМенеджер
// - РегистрыРасчетаМенеджер
// - ПерерасчетыМенеджер
// - БизнесПроцессыМенеджер
// - ЗадачиМенеджер
// - ВнешниеИсточникиДанныхМенеджер
// - ВнешнийИсточникДанныхТаблицыМенеджер
// - ВнешнийИсточникДанныхКубыМенеджер
// - ВнешнийИсточникДанныхКубТаблицыИзмеренийМенеджер
//
Функция МенеджерОбъектаПоИмени(Имя, ЭтоПолноеИмя, ЭтоИмяМенеджера, ТребуетсяМодульМенеджера,
ИмяВызывающейПроцедуры, ИмяПараметра, МенеджерПоТочномуИмени = Истина)
ЧастиИмени = СтрРазделить(Имя, ".");
ПерваяЧастьИмени = ЧастиИмени[0];
СвойстваВидовОбъектов = СтандартныеПодсистемыПовтИсп.СвойстваВидовОбъектовМетаданных();
Свойства = СвойстваВидовОбъектов.ПоКоллекциям.Получить(ВРег(ПерваяЧастьИмени));
НайденоПоКоллекциям = Истина;
Если Свойства = Неопределено Тогда
Свойства = СвойстваВидовОбъектов.ПоВидамОбъектов.Получить(ВРег(ПерваяЧастьИмени));
НайденоПоКоллекциям = Ложь;
КонецЕсли;
КодОшибки = "СтандартныеПодсистемы.БазоваяФункциональность.ЭтоОшибкаПолученияМодуляМенеджераПоИмени";
Если Свойства = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объектов ""%5"".'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
Если ЭтоИмяМенеджера = Истина И Не НайденоПоКоллекциям Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - начало имени объекта метаданных, а ожидается начало имени менеджера объекта.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
ИначеЕсли ЭтоИмяМенеджера = Ложь И НайденоПоКоллекциям Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - начало имени менеджера объекта, а ожидается начало имени объекта метаданных.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
Менеджер = Свойства.Менеджер;
Если Менеджер = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. У объектов ""%5"" нет менеджера.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьИмени);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
ЕстьМодульМенеджера = Свойства.ЕстьМодульМенеджера;
КоллекцияМетаданных = Метаданные[Свойства.ИмяКоллекции];
Индекс = 0;
Если ЧастиИмени.Количество() > 2
И ( Свойства.ИмяВидаОбъекта = "РегистрРасчета"
Или Свойства.ИмяВидаОбъекта = "ВнешнийИсточникДанных") Тогда
Если Свойства.ИмяВидаОбъекта = "РегистрРасчета" Тогда
УстановитьМенеджерВложенногоОбъекта("ПЕРЕРАСЧЕТЫ", "ПЕРЕРАСЧЕТ", Ложь,
Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени,
НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки);
Иначе
УстановитьМенеджерВложенногоОбъекта("КУБЫ", "КУБ", Истина,
Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени,
НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки);
Если Индекс = 0 Тогда
УстановитьМенеджерВложенногоОбъекта("ТАБЛИЦЫ", "ТАБЛИЦА", Истина,
Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени,
НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки);
ИначеЕсли ЧастиИмени.Количество() > 4 Тогда
УстановитьМенеджерВложенногоОбъекта("ТАБЛИЦЫИЗМЕРЕНИЙ", "ТАБЛИЦАИЗМЕРЕНИЯ", Истина,
Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени,
НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ЧастиИмени.Количество() = Индекс + 1 Тогда
Если Не ЭтоПолноеИмя Тогда
Возврат Менеджер;
КонецЕсли;
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Ожидается полное имя объекта.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
Если ТребуетсяМодульМенеджера И Не ЕстьМодульМенеджера Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. У объектов ""%5"" нет модулей менеджера.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ЧастиИмени[Индекс]);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
ИмяОбъекта = ЧастиИмени[Индекс + 1];
Попытка
Возврат Менеджер[ИмяОбъекта];
Исключение
Если КоллекцияМетаданных.Найти(ИмяОбъекта) = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объект ""%5"".'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ИмяОбъекта);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
КонецФункции
// АПК:134-выкл - Количество параметров более 7 для компактного описания и производительности (0-2 вызовов за раз).
// Для функции МенеджерОбъектаПоИмени.
Процедура УстановитьМенеджерВложенногоОбъекта(ИмяКоллекции, ИмяВидаОбъекта, ЕстьМодуль,
Индекс, Менеджер, ЕстьМодульМенеджера, КоллекцияМетаданных, Имя, ЧастиИмени,
НайденоПоКоллекциям, ИмяВызывающейПроцедуры, ИмяПараметра, КодОшибки)
ПерваяЧастьВложенногоИмени = ЧастиИмени[Индекс + 2];
Если ВРег(ПерваяЧастьВложенногоИмени) <> ИмяВидаОбъекта
И ВРег(ПерваяЧастьВложенногоИмени) <> ИмяКоллекции Тогда
Возврат;
КонецЕсли;
Если ВРег(ПерваяЧастьВложенногоИмени) = ИмяВидаОбъекта И НайденоПоКоллекциям Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - часть имени объекта метаданных, а ожидается часть имени менеджера объекта.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьВложенногоИмени);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
ИначеЕсли ВРег(ПерваяЧастьВложенногоИмени) = ИмяКоллекции И Не НайденоПоКоллекциям Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Указано ""%5"" - часть имени менеджера объекта, а ожидается часть имени объекта метаданных.'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ПерваяЧастьВложенногоИмени);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
ИмяОбъекта = ЧастиИмени[Индекс + 1];
Попытка
Менеджер = Менеджер[ИмяОбъекта][ИмяКоллекции];
Исключение
Если КоллекцияМетаданных.Найти(ИмяОбъекта) = Неопределено Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неверное значение ""%1"" (тип %2) параметра %3 в %4. Не существует объект ""%5"".'"),
Имя, ТипЗнч(Имя), ИмяПараметра, ИмяВызывающейПроцедуры, ИмяОбъекта);
ВызватьИсключение(ТекстОшибки, КатегорияОшибки.ОшибкаКонфигурации, КодОшибки);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
ЕстьМодульМенеджера = ЕстьМодуль;
КоллекцияМетаданных = КоллекцияМетаданных[ИмяОбъекта][ИмяКоллекции];
Индекс = Индекс + 2;
КонецПроцедуры
// АПК:134-вкл
#КонецОбласти
#Область ВнешниеКомпоненты
Процедура ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение)
Если МакетСуществует(Местоположение) Тогда
Возврат;
КонецЕсли;
Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда
МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный");
МодульВнешниеКомпонентыСлужебный.ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение);
Возврат;
КонецЕсли;
ВызватьИсключение(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Указан несуществующий макет ""%1"" при подключении внешней компоненты ""%2"".'"),
Местоположение, Идентификатор),
КатегорияОшибки.ОшибкаКонфигурации);
КонецПроцедуры
Функция ОшибкаСовместимостиКомпонентыИзМакета(Местоположение)
Если Не ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда
Возврат "";
КонецЕсли;
МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный");
Возврат МодульВнешниеКомпонентыСлужебный.ОшибкаСовместимостиКомпонентыИзМакета(
Местоположение);
КонецФункции
Функция СистемнаяИнформацияДляЖурналаРегистрации()
Возврат СтандартныеПодсистемыСервер.ИнформацияДляПоддержки();
КонецФункции
Процедура ОтправитьСтатистикуПодключенияКомпоненты(Идентификатор, Местоположение)
Если Не ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда
Возврат;
КонецЕсли;
МодульЦентрМониторинга = ОбщийМодуль("ЦентрМониторинга");
МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики(
"СтандартныеПодсистемы.ВнешниеКомпоненты." + Идентификатор + ".НаСервере." + ?(СтрНачинаетсяС(Местоположение, "e1cib"), "Справочник", "Макет"), 1);
КонецПроцедуры
#КонецОбласти
#Область ТекущееОкружение
Функция НомерСборкиПоТекущейВерсииПлатформы(НомераСборокСтрокой)
НомераСборок = СтрРазделить(НомераСборокСтрокой, ";", Истина);
СборкиПоВерсиям = Новый Соответствие;
Для Каждого НомерСборки Из НомераСборок Цикл
НомерВерсии = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(НомерСборки);
СборкиПоВерсиям.Вставить(СокрЛП(НомерВерсии), СокрЛП(НомерСборки));
КонецЦикла;
СистемнаяИнформация = Новый СистемнаяИнформация;
ТекущаяВерсия = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения);
Результат = СборкиПоВерсиям[ТекущаяВерсия];
Если Не ЗначениеЗаполнено(Результат) Тогда
Результат = НомераСборок[0];
КонецЕсли;
Возврат Результат;
КонецФункции
// Ниже этой версии платформы конфигурация может запуститься и показать окно с требованием обновить платформу,
// если она выше, чем в СтандартныеПодсистемыСервер.МинимальнаяВерсияПлатформыДляЗапуска.
// Конкретные номера версий указаны в СтандартныеПодсистемыСервер.МинимальнаяВерсияПлатформыДляИспользования.
// Версии могут быть переопределены в ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности.
//
Функция МинимальнаяВерсияПлатформы() Экспорт // АПК:581 - экспортная, так как используется при тестировании.
ВерсияРежимаСовместимости = ВерсияРежимаСовместимости();
МинимальныеВерсииПлатформы = СтандартныеПодсистемыСервер.МинимальнаяВерсияПлатформыДляИспользования();
НайденнаяВерсия = МинимальныеВерсииПлатформы.НайтиПоЗначению(ВерсияРежимаСовместимости);
Если НайденнаяВерсия = Неопределено Тогда
НайденнаяВерсия = МинимальныеВерсииПлатформы[МинимальныеВерсииПлатформы.Количество() - 1];
КонецЕсли;
Возврат НайденнаяВерсия.Представление;
КонецФункции
Функция ВерсияРежимаСовместимости() Экспорт
СистемнаяИнформация = Новый СистемнаяИнформация();
РежимСовместимости = Метаданные.РежимСовместимости;
Если РежимСовместимости = Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда
ВерсияРежимаСовместимости = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения);
Иначе
ВерсияРежимаСовместимости = СтрСоединить(СтрРазделить(РежимСовместимости,
СтрСоединить(СтрРазделить(РежимСовместимости, "1234567890", Ложь), ""), Ложь), ".");
КонецЕсли;
Возврат ВерсияРежимаСовместимости;
КонецФункции
// Выполняет проверку правильности заполнения минимальной и рекомендуемой версии платформы.
//
// Параметры:
// Минимальная - Строка - номер версия платформы.
// Рекомендуемая - Строка - номер версия платформы.
//
// Возвращаемое значение:
// Булево - Истина, если минимальная и рекомендуемая версия платформы заполнена неправильно.
//
Функция МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая)
// Минимальная версия платформы должна быть заполнена.
Если ПустаяСтрока(Минимальная) Тогда
Возврат Истина;
КонецЕсли;
// Минимальная версия платформы, заданная в конфигурации, не должна быть меньше минимальной версии платформы,
// заданной в библиотеке.
МинимальнаяБСП = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы());
Если Не ЭтоВерсияЗащищенногоПрограммногоКомплекса(Минимальная)
И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(МинимальнаяБСП, Минимальная) > 0 Тогда
Возврат Истина;
КонецЕсли;
// Минимальная версия платформы не должны быть больше рекомендуемой.
Возврат Не ПустаяСтрока(Минимальная)
И Не ПустаяСтрока(Рекомендуемая)
И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Минимальная, Рекомендуемая) > 0;
КонецФункции
Функция НедопустимыеВерсииПлатформы() Экспорт
Возврат "";
КонецФункции
Функция ЭтоВерсияЗащищенногоПрограммногоКомплекса(Версия)
СистемнаяИнформация = Новый СистемнаяИнформация();
Возврат ЗначениеЗаполнено(СистемнаяИнформация.ВариантПриложения);
КонецФункции
// Для функции ОбщиеПараметрыБазовойФункциональности.
Процедура УточнитьВерсиюПлатформы(ОбщиеПараметры)
СистемнаяИнформация = Новый СистемнаяИнформация;
НоваяСборка = СтандартныеПодсистемыСервер.НомерВерсииПлатформыВместоОтозванной(СистемнаяИнформация.ВерсияПриложения);
Если Не ЗначениеЗаполнено(НоваяСборка) Тогда
НоваяРекомендуемаяСборка = СтандартныеПодсистемыСервер.НомерВерсииПлатформыВместоОтозванной(ОбщиеПараметры.МинимальнаяВерсияПлатформы);
Если ЗначениеЗаполнено(НоваяРекомендуемаяСборка) Тогда
МинимальнаяСборка = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы());
ОбщиеПараметры.МинимальнаяВерсияПлатформы = МинимальнаяСборка;
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.РекомендуемаяВерсияПлатформы, НоваяРекомендуемаяСборка) < 0 Тогда
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяРекомендуемаяСборка;
КонецЕсли;
КонецЕсли;
ИначеЕсли ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.МинимальнаяВерсияПлатформы, НоваяСборка) < 0 Тогда
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяСборка;
ОбщиеПараметры.МинимальнаяВерсияПлатформы = НоваяСборка;
КонецЕсли;
КонецПроцедуры
// Параметры:
// ОбщиеПараметры - см. ОбщиеПараметрыБазовойФункциональности
//
Процедура УточнитьМинимальнуюВерсиюПлатформыИзСервиса(ОбщиеПараметры)
МинимальнаяИзСервиса = "";
РекомендуемаяИзСервиса = "";
СтандартныеПодсистемыСерверЛокализация.ПриОпределенииМинимальнойИРекомендуемойВерсийПлатформы(
МинимальнаяИзСервиса, РекомендуемаяИзСервиса);
Если Не ЗначениеЗаполнено(МинимальнаяИзСервиса) И Не ЗначениеЗаполнено(РекомендуемаяИзСервиса) Тогда
Возврат;
КонецЕсли;
Минимальная = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяИзСервиса);
Рекомендуемая = НомерСборкиПоТекущейВерсииПлатформы(РекомендуемаяИзСервиса);
Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда
СтандартныеПодсистемыСерверЛокализация.ПриНеверномЗаполненииМинимальнойИРекомендуемойВерсийПлатформы(
Минимальная, Рекомендуемая, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), ОбщиеПараметры);
Возврат;
КонецЕсли;
ОбщиеПараметры.МинимальнаяВерсияПлатформы = Минимальная;
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = Рекомендуемая;
КонецПроцедуры
#КонецОбласти
#Область ПроверкаАлгоритмов
Функция НайденныеВызовы(Алгоритм, СтрокиПоиска, Окончание = Неопределено)
НайденныеВызовы = Новый Массив;
ПоискОбращенияЧерезТочку = Ложь;
ПоискТаблицы = Ложь;
Для Каждого Элемент Из СтрокиПоиска Цикл
Если ТипЗнч(Элемент) = Тип("Структура") Тогда
ПоискОбращенияЧерезТочку = Истина;
СтрокаПоиска = Элемент.Коллекция;
Иначе
СтрокаПоиска = Элемент;
КонецЕсли;
ПозицияВызова = СтрНайти(Алгоритм, ВРег(СтрокаПоиска));
НомерВхождения = 1;
Пока ПозицияВызова > 0 Цикл
Если ПоискОбращенияЧерезТочку Тогда
Окончание = ".";
ПоискТаблицы = Ложь;
КонецЕсли;
ЧислоСимволов = СтрДлина(Окончание);
ПозицияСимвола = ПозицияВызова + СтрДлина(СтрокаПоиска);
Пока ПозицияСимвола + ЧислоСимволов < СтрДлина(Алгоритм) Цикл
ЗначениеСимвола = СокрЛП(Сред(Алгоритм, ПозицияСимвола, ЧислоСимволов));
Если ВРег(СтрокаПоиска) = ВРег("Выполнить")
Или ВРег(СтрокаПоиска) = ВРег("Execute") Тогда
Если Не ЗначениеЗаполнено(ЗначениеСимвола) Тогда
НайденныеВызовы.Добавить(СтрокаПоиска);
Прервать;
КонецЕсли;
КонецЕсли;
Если СтрДлина(ЗначениеСимвола) < СтрДлина(Окончание) Тогда
ЧислоСимволов = ЧислоСимволов + 1;
ИначеЕсли ПоискОбращенияЧерезТочку
И ЗначениеСимвола = Окончание
И Не ПоискТаблицы Тогда
ПозицияСимвола = ПозицияСимвола + ЧислоСимволов;
Окончание = ВРег(Элемент.Таблица);
ЧислоСимволов = СтрДлина(Окончание);
ПоискТаблицы = Истина;
ИначеЕсли ЗначениеСимвола = Окончание Тогда
Если ПоискОбращенияЧерезТочку Тогда
НайденныеВызовы.Добавить(Элемент.Коллекция + "." + Элемент.Таблица);
Иначе
НайденныеВызовы.Добавить(СтрокаПоиска);
КонецЕсли;
Прервать;
ИначеЕсли ЗначениеСимвола = "/" Тогда
НайденныеВызовы.Добавить(СтрокаПоиска);
Прервать;
ИначеЕсли ЗначениеЗаполнено(СокрЛП(ЗначениеСимвола)) Тогда
Прервать;
КонецЕсли;
КонецЦикла;
НомерВхождения = НомерВхождения + 1;
ПозицияВызова = СтрНайти(Алгоритм, ВРег(СтрокаПоиска), , , НомерВхождения);
КонецЦикла;
КонецЦикла;
Возврат НайденныеВызовы;
КонецФункции
Функция НедопустимыеМетоды()
Массив = Новый Массив;
Массив.Добавить("Выполнить"); // @Non-NLS
Массив.Добавить("Вычислить"); // @Non-NLS
Массив.Добавить("Подключить"); // @Non-NLS
Массив.Добавить("ЗафиксироватьТранзакцию"); // @Non-NLS
Массив.Добавить("ОтменитьТранзакцию"); // @Non-NLS
Массив.Добавить("НачатьТранзакцию"); // @Non-NLS
Массив.Добавить("СократитьЖурналРегистрации"); // @Non-NLS
Массив.Добавить("УстановитьИспользованиеСобытияЖурналаРегистрации"); // @Non-NLS
Массив.Добавить("ЗапуститьПриложение"); // @Non-NLS
Массив.Добавить("УстановитьМаксимальныйСрокДействияПаролейПользователей"); // @Non-NLS
Массив.Добавить("УстановитьМинимальнуюДлинуПаролейПользователей"); // @Non-NLS
Массив.Добавить("УстановитьМинимальныйСрокДействияПаролейПользователей"); // @Non-NLS
Массив.Добавить("УстановитьОграничениеПовторенияПаролейПользователейСредиПоследних"); // @Non-NLS
Массив.Добавить("УстановитьПроверкуСложностиПаролейПользователей"); // @Non-NLS
Массив.Добавить("УстановитьНастройкиВосстановленияПароля"); // @Non-NLS
Массив.Добавить("Base64Значение"); // @Non-NLS
Массив.Добавить("ЗначениеИзСтрокиВнутр"); // @Non-NLS
Массив.Добавить("XMLЗначение"); // @Non-NLS
Массив.Добавить("Execute");
Массив.Добавить("Eval");
Массив.Добавить("Connect");
Массив.Добавить("CommitTransaction");
Массив.Добавить("RollbackTransaction");
Массив.Добавить("BeginTransaction");
Массив.Добавить("TruncateEventLog");
Массив.Добавить("SetEventLogEventUse");
Массив.Добавить("RunApp");
Массив.Добавить("SetUserPasswordMaxEffectivePeriod");
Массив.Добавить("SetUserPasswordMinLength");
Массив.Добавить("SetUserPasswordMinEffectivePeriod");
Массив.Добавить("SetUserPasswordReuseLimit");
Массив.Добавить("SetUserPasswordStrengthCheck");
Массив.Добавить("SetPasswordRecoverySettings");
Массив.Добавить("Base64Value");
Массив.Добавить("ValueFromStringInternal");
Массив.Добавить("XMLValue");
// Процедуры и функции БСП
Массив.Добавить("ВыполнитьМетодОбъекта");
Массив.Добавить("ВыполнитьМетодКонфигурации");
Массив.Добавить("ВыполнитьФоновоеЗадание");
Массив.Добавить("ОбщийМодуль");
Массив.Добавить("ЗначениеИзСтрокиXML");
Возврат Массив;
КонецФункции
Функция ЗапрещенныеСвойстваГлобальногоКонтекста()
Массив = Новый Массив;
Массив.Добавить("ПользователиИнформационнойБазы"); // @Non-NLS
Массив.Добавить("ДополнительныеНастройкиАутентификации"); // @Non-NLS
Массив.Добавить("ПараметрыСеанса"); // @Non-NLS
Массив.Добавить("ФоновыеЗадания"); // @Non-NLS
Массив.Добавить("РасширенияКонфигурации"); // @Non-NLS
Массив.Добавить("InfoBaseUsers");
Массив.Добавить("AdditionalAuthenticationSettings");
Массив.Добавить("SessionParameters");
Массив.Добавить("BackgroundJobs");
Массив.Добавить("ConfigurationExtensions");
Возврат Массив;
КонецФункции
Функция ЗапрещенныеМодули()
Массив = Новый Массив;
Массив.Добавить("ДлительныеОперации");
Возврат Массив;
КонецФункции
#КонецОбласти
#Область ВспомогательныеПроцедурыВажныхСообщений
Процедура ВывестиКонтекстноеВажноеСообщение(Форма, ВсегоВажныхСообщений)
Для Каждого ЭлементСписка Из Форма.БФ_ДобавляемыеВажныеСообщения Цикл
ПараметрыСообщения = ЭлементСписка.Значение;
Если Не ЗначениеЗаполнено(ПараметрыСообщения.Родитель) Тогда
Продолжить;
КонецЕсли;
ВсегоВажныхСообщений = ВсегоВажныхСообщений - 1;
РодительскаяГруппа = Форма.Элементы[ПараметрыСообщения.Родитель];
Если ЗначениеЗаполнено(ПараметрыСообщения.Идентификатор) Тогда
ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + ПараметрыСообщения.Идентификатор;
Иначе
ИмяГруппы = ПараметрыСообщения.Родитель + "_" + "БФ_ГруппаКонтекстноеСообщение";
КонецЕсли;
Группа = Форма.Элементы.Найти(ИмяГруппы);
Если Группа <> Неопределено Тогда
// Повторный вывод сообщения.
Форма.Элементы.Удалить(Группа);
КонецЕсли;
Элемент = Неопределено;
Если ЗначениеЗаполнено(ПараметрыСообщения.Элемент) Тогда
Элемент = Форма.Элементы[ПараметрыСообщения.Элемент];
КонецЕсли;
ГруппаРазмещенияКонтекстногоСообщения = Форма.Элементы.Вставить(ИмяГруппы, Тип("ГруппаФормы"), РодительскаяГруппа, Элемент);
ГруппаРазмещенияКонтекстногоСообщения.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ГруппаРазмещенияКонтекстногоСообщения.ОтображатьЗаголовок = Ложь;
ГруппаРазмещенияКонтекстногоСообщения.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
ГруппаРазмещенияКонтекстногоСообщения.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ВывестиПростоеВажноеСообщение(Форма, ПараметрыСообщения, ГруппаРазмещенияКонтекстногоСообщения);
КонецЦикла;
КонецПроцедуры
Процедура ВывестиОдиночноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений)
Для Каждого ЭлементСписка Из Форма.БФ_ДобавляемыеВажныеСообщения Цикл
Если ЗначениеЗаполнено(ЭлементСписка.Значение.Родитель) Тогда
// Пропускаем контекстные сообщения.
Продолжить;
КонецЕсли;
ПараметрыСообщения = ЭлементСписка.Значение;
Прервать;
КонецЦикла;
Если ЗначениеЗаполнено(ПараметрыСообщения.Идентификатор) Тогда
ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + ПараметрыСообщения.Идентификатор;
Иначе
ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + ГруппаРазмещенияВажныхСообщений.Имя + "_" + ПараметрыСообщения.ТипСообщения;
КонецЕсли;
ГруппаРазмещенияСообщения = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияВажныхСообщений);
ВывестиПростоеВажноеСообщение(Форма, ПараметрыСообщения, ГруппаРазмещенияСообщения);
КонецПроцедуры
Процедура ВывестиАгрегированноеВажноеСообщение(Форма, ГруппаРазмещенияВажныхСообщений, СгруппированныеСообщения, ЕстьСтатусы)
ЦветаВажныхСообщений = ЦветаВажныхСообщений();
КартинкиВажныхСообщений = КартинкиВажныхСообщений();
ВыведеноСообщений = 0;
ЛимитСообщений = 5;
Если ЕстьСтатусы Тогда
ВсегоСтатусов = Форма.БФ_ДобавляемыеСтатусы.Количество();
Если ВсегоСтатусов >= 3 Тогда
ЛимитСообщений = 2;
Иначе
ЛимитСообщений = ЛимитСообщений - ВсегоСтатусов;
КонецЕсли;
КонецЕсли;
Для Каждого СтрокаСообщение Из СгруппированныеСообщения Цикл
Если ЗначениеЗаполнено(СтрокаСообщение.ПараметрыСообщения.Идентификатор) Тогда
ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + СтрокаСообщение.ПараметрыСообщения.Идентификатор;
Иначе
ИмяГруппы = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения() + СгруппированныеСообщения.Индекс(СтрокаСообщение) + "_" + СтрокаСообщение.ТипСообщения;
КонецЕсли;
ГруппаВажноеСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияВажныхСообщений);
ГруппаВажноеСообщение.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ДекорацияКартинка = Форма.Элементы.Добавить(ИмяГруппы + "_" + "КартинкаСообщения", Тип("ДекорацияФормы"), ГруппаВажноеСообщение);
ДекорацияКартинка.Вид = ВидДекорацииФормы.Картинка;
ДекорацияКартинка.Картинка = КартинкиВажныхСообщений[СтрокаСообщение.ТипСообщения];
ДекорацияКартинка.ЦветКартинки = ЦветаВажныхСообщений[СтрокаСообщение.ТипСообщения];
ДекорацияКартинка.Шрифт = ШрифтВажныхСообщений();
ДекорацияКартинка.РазмерКартинки = РазмерКартинки.ПоРазмеруШрифта;
ИмяГруппы = ИмяГруппы + "_" + "Заголовок";
ГруппаЗаголовок = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаВажноеСообщение);
ГруппаЗаголовок.Поведение = ПоведениеОбычнойГруппы.Всплывающая;
ГруппаЗаголовок.Отображение = ОтображениеОбычнойГруппы.Нет;
ГруппаЗаголовок.ОтображатьЗаголовок = Истина;
КраткоеПредставление = СтрокаСообщение.ПараметрыСообщения.КраткоеПредставление;
Если СтрДлина(КраткоеПредставление) > 38 Тогда
КраткоеПредставление = Лев(КраткоеПредставление, 35) + "...";
КонецЕсли;
ГруппаЗаголовок.Заголовок = КраткоеПредставление;
Если Не ОбщегоНазначенияКлиентСервер.ЭтоВариантИнтерфейса85() Тогда
ГруппаЗаголовок.ЦветТекстаЗаголовка = ЦветаПалитры.Синий;
КонецЕсли;
ИмяГруппы = ИмяГруппы + "_" + "Сообщение";
ГруппаСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаЗаголовок);
ГруппаСообщение.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ГруппаСообщение.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ГруппаСообщение.Ширина = 40;
ГруппаСообщение.ОтображатьКакКарточку = Истина;
ГруппаСообщение.РастягиватьПоГоризонтали = Ложь;
ГруппаСообщение.ЦветФона = ЦветаВажныхСообщений[СтрокаСообщение.ТипСообщения];
ИмяГруппы = ИмяГруппы + "_" + "КонтентСообщения";
ГруппаКонтентСообщения = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаСообщение);
ГруппаКонтентСообщения.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаКонтентСообщения.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ГруппаКонтентСообщения.РастягиватьПоГоризонтали = Истина;
ВывестиКонтентСообщения(Форма, ГруппаКонтентСообщения, СтрокаСообщение.ПараметрыСообщения);
ДобавитьКнопкуСкрытияСообщения(Форма, ГруппаСообщение, ГруппаВажноеСообщение, СтрокаСообщение.ПараметрыСообщения);
ВыведеноСообщений = ВыведеноСообщений + 1;
Если ВыведеноСообщений = ЛимитСообщений Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ВывестиГруппуПоказатьВсеВажныеСообщения(Форма, СгруппированныеСообщения, ГруппаРазмещенияВажныхСообщений)
ЦветаВажныхСообщений = ЦветаВажныхСообщений();
ИмяГруппы = ГруппаРазмещенияВажныхСообщений.Имя + "_" + "ПоказатьВсе";
ГруппаПоказатьВсе = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияВажныхСообщений);
ГруппаПоказатьВсе.Заголовок = НСтр("ru = 'Показать все'");
ГруппаПоказатьВсе.ОтображатьЗаголовок = Истина;
ГруппаПоказатьВсе.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаПоказатьВсе.Поведение = ПоведениеОбычнойГруппы.Всплывающая;
ГруппаПоказатьВсе.Отображение = ОтображениеОбычнойГруппы.Нет;
ГруппаПоказатьВсе.ГоризонтальноеПоложениеВГруппе = ГоризонтальноеПоложениеЭлемента.Право;
ГруппаПоказатьВсе.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ГруппаПоказатьВсе.ПутьКДаннымЗаголовка = "БФ_ВсегоВажныхСообщений";
Для Каждого СтрокаСообщение Из СгруппированныеСообщения Цикл
Если ЗначениеЗаполнено(СтрокаСообщение.ПараметрыСообщения.Идентификатор) Тогда
ИмяГруппыСообщения = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе()
+ ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения()
+ СтрокаСообщение.ПараметрыСообщения.Идентификатор;
Иначе
ИмяГруппыСообщения = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе()
+ ОбщегоНазначенияКлиентСервер.ПрефиксГруппыВажногоСообщения()
+ СгруппированныеСообщения.Индекс(СтрокаСообщение)
+ "_" + СтрокаСообщение.ТипСообщения;
КонецЕсли;
ГруппаСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппыСообщения, ГруппаПоказатьВсе);
ГруппаСообщение.Вид = ВидГруппыФормы.ОбычнаяГруппа;
ГруппаСообщение.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ГруппаСообщение.Ширина = 40;
ГруппаСообщение.ОтображатьКакКарточку = Истина;
ГруппаСообщение.РастягиватьПоГоризонтали = Ложь;
ГруппаСообщение.ЦветФона = ЦветаВажныхСообщений[СтрокаСообщение.ТипСообщения];
ИмяГруппыКонтент = ИмяГруппыСообщения + "_" + "КонтентСообщения";
ГруппаКонтентСообщения = НоваяГруппаВажногоСообщения(Форма, ИмяГруппыКонтент, ГруппаСообщение);
ГруппаКонтентСообщения.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаКонтентСообщения.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ГруппаКонтентСообщения.РастягиватьПоГоризонтали = Истина;
ВывестиКонтентСообщения(Форма, ГруппаКонтентСообщения, СтрокаСообщение.ПараметрыСообщения, Истина);
ДобавитьКнопкуСкрытияСообщения(Форма, ГруппаСообщение, ГруппаСообщение, СтрокаСообщение.ПараметрыСообщения);
КонецЦикла;
КонецПроцедуры
Процедура ВывестиСтатусыНаФорму(Форма, РодительскаяГруппа)
// Упорядочивание статусов.
ТаблицаСтатусов = Новый ТаблицаЗначений;
ТаблицаСтатусов.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
ТаблицаСтатусов.Колонки.Добавить("ОписаниеСтатуса");
Для Каждого ЭлементСписка Из Форма.БФ_ДобавляемыеСтатусы Цикл
ПараметрыСтатуса = ЭлементСписка.Значение;
Строка = ТаблицаСтатусов.Добавить();
Если ПараметрыСтатуса.Порядок = Неопределено Тогда
Строка.Порядок = 9999;
Иначе
Строка.Порядок = ПараметрыСтатуса.Порядок;
КонецЕсли;
Строка.ОписаниеСтатуса = ПараметрыСтатуса;
КонецЦикла;
ТаблицаСтатусов.Сортировать("Порядок Возр");
Форма.БФ_ВсегоСтатусов = Форма.БФ_ДобавляемыеСтатусы.Количество();
// Группа для статусов.
ГруппаРазмещенияСтатусов = Форма.Элементы.Найти("БФ_ГруппаСтатусы");
Если ГруппаРазмещенияСтатусов <> Неопределено Тогда
// Повторный вывод сообщения.
Форма.Элементы.Удалить(ГруппаРазмещенияСтатусов);
КонецЕсли;
ГруппаРазмещенияСтатусов = НоваяГруппаВажногоСообщения(Форма, "БФ_ГруппаСтатусы", РодительскаяГруппа);
ГруппаРазмещенияСтатусов.ОтображатьКакКарточку = Истина;
ВыводитьПоказатьВсе = Форма.БФ_ВсегоСтатусов > 6;
Если ВыводитьПоказатьВсе Тогда
ИмяГруппы = ГруппаРазмещенияСтатусов.Имя + "_" + "ПоказатьВсе";
ГруппаПоказатьВсе = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияСтатусов);
ГруппаПоказатьВсе.Заголовок = НСтр("ru = 'Показать все'");
ГруппаПоказатьВсе.ОтображатьЗаголовок = Истина;
ГруппаПоказатьВсе.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаПоказатьВсе.Поведение = ПоведениеОбычнойГруппы.Всплывающая;
ГруппаПоказатьВсе.Отображение = ОтображениеОбычнойГруппы.Нет;
ГруппаПоказатьВсе.ГоризонтальноеПоложениеВГруппе = ГоризонтальноеПоложениеЭлемента.Право;
ГруппаПоказатьВсе.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ГруппаПоказатьВсе.ПутьКДаннымЗаголовка = "БФ_ВсегоСтатусов";
КонецЕсли;
Для Каждого Строка Из ТаблицаСтатусов Цикл
ВывестиСтатус(Форма, Строка.ОписаниеСтатуса, ГруппаРазмещенияСтатусов);
Если ВыводитьПоказатьВсе Тогда
ПрефиксВсе = ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе();
ВывестиСтатус(Форма, Строка.ОписаниеСтатуса, ГруппаПоказатьВсе, ПрефиксВсе);
КонецЕсли;
КонецЦикла;
Если ВыводитьПоказатьВсе Тогда
Форма.Элементы.Переместить(ГруппаПоказатьВсе, ГруппаРазмещенияСтатусов);
КонецЕсли;
КонецПроцедуры
Процедура ВывестиСтатус(Форма, ПараметрыСтатуса, ГруппаРазмещенияСтатусов, ПрефиксВсе = "")
ИмяГруппы = ПрефиксВсе + ОбщегоНазначенияКлиентСервер.ПрефиксГруппыСтатуса() + ПараметрыСтатуса.Идентификатор;
ГруппаСтатус = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаРазмещенияСтатусов);
ГруппаСтатус.ГоризонтальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
Если ЗначениеЗаполнено(ПрефиксВсе) Тогда
ГруппаСтатус.Ширина = 30;
ГруппаСтатус.РастягиватьПоГоризонтали = Ложь;
ГруппаСтатус.ОтображатьКакКарточку = Истина;
КонецЕсли;
Если ЗначениеЗаполнено(ПараметрыСтатуса.Картинка) Тогда
ДекорацияКартинка = Форма.Элементы.Добавить(ГруппаСтатус.Имя + "_" + "КартинкаСтатуса", Тип("ДекорацияФормы"), ГруппаСтатус);
ДекорацияКартинка.Вид = ВидДекорацииФормы.Картинка;
ДекорацияКартинка.Картинка = ПараметрыСтатуса.Картинка;
ДекорацияКартинка.Шрифт = ШрифтВажныхСообщений();
ДекорацияКартинка.РазмерКартинки = РазмерКартинки.ПоРазмеруШрифта;
КонецЕсли;
ДекорацияНадпись = Форма.Элементы.Добавить(ОбщегоНазначенияКлиентСервер.ПрефиксСтатуса() + ПрефиксВсе + ПараметрыСтатуса.Идентификатор, Тип("ДекорацияФормы"), ГруппаСтатус);
ДекорацияНадпись.Вид = ВидДекорацииФормы.Надпись;
ДекорацияНадпись.Заголовок = ПараметрыСтатуса.Наименование;
ДекорацияНадпись.Шрифт = ШрифтВажныхСообщений();
Если ЗначениеЗаполнено(ПараметрыСтатуса.Обработчик) Тогда
ДекорацияНадпись.Гиперссылка = Истина;
Если СтрРазделить(ПараметрыСтатуса.Обработчик, ".").Количество() = 1 Тогда
ДекорацияНадпись.УстановитьДействие("Нажатие", ПараметрыСтатуса.Обработчик);
Иначе
ДекорацияНадпись.УстановитьДействие("Нажатие", "Подключаемый_ОбработатьДействиеИнформационногоСообщения");
КонецЕсли;
Форма.БФ_ОбработчикиСтатусов.Вставить(ПараметрыСтатуса.Идентификатор, ПараметрыСтатуса.Обработчик);
КонецЕсли;
КонецПроцедуры
Процедура ВывестиКонтентСообщения(Форма, ГруппаКонтент, ПараметрыСообщения, ПоказатьВсе = Ложь)
ЕстьЗаголовок = ЗначениеЗаполнено(ПараметрыСообщения.Заголовок);
ЕстьДействие = (ПараметрыСообщения.ПараметрыДействия <> Неопределено);
Если ЕстьЗаголовок Тогда
ДекорацияЗаголовок = Форма.Элементы.Добавить(ГруппаКонтент.Имя + "_" + "ЗаголовокВажногоСообщения", Тип("ДекорацияФормы"), ГруппаКонтент);
ДекорацияЗаголовок.Вид = ВидДекорацииФормы.Надпись;
ДекорацияЗаголовок.Заголовок = ПараметрыСообщения.Заголовок;
ДекорацияЗаголовок.АвтоМаксимальнаяШирина = Ложь;
УстановитьШрифтЗаголовкаВажныхСообщений(ДекорацияЗаголовок.Шрифт);
КонецЕсли;
ДекорацияНадпись = Форма.Элементы.Добавить(ГруппаКонтент.Имя + "_" + "НадписьВажногоСообщения", Тип("ДекорацияФормы"), ГруппаКонтент);
ДекорацияНадпись.Вид = ВидДекорацииФормы.Надпись;
ДекорацияНадпись.Заголовок = ПараметрыСообщения.Сообщение;
ДекорацияНадпись.Шрифт = ШрифтВажныхСообщений();
ДекорацияНадпись.АвтоМаксимальнаяШирина = Ложь;
Если ТипЗнч(ПараметрыСообщения.Сообщение) = Тип("ФорматированнаяСтрока") Тогда
Если ЗначениеЗаполнено(ПараметрыСообщения.Обработчик) И СтрРазделить(ПараметрыСообщения.Обработчик, ".").Количество() = 1 Тогда
ДекорацияНадпись.УстановитьДействие("ОбработкаНавигационнойСсылки", ПараметрыСообщения.Обработчик);
Иначе
ДекорацияНадпись.УстановитьДействие("ОбработкаНавигационнойСсылки", "Подключаемый_ОбработатьДействиеИнформационногоСообщения");
КонецЕсли;
КонецЕсли;
Если ЕстьДействие Тогда
ПараметрыДействия = ПараметрыСообщения.ПараметрыДействия;
Если ТипЗнч(ПараметрыДействия) <> Тип("Массив") Тогда
ПараметрыДействия = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПараметрыДействия);
КонецЕсли;
ИмяГруппы = ГруппаКонтент.Имя + "_" + "КомандыДействия";
ГруппаКомандыДействия = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, ГруппаКонтент);
Для Каждого ОписаниеДействия Из ПараметрыДействия Цикл
ИмяКоманды = ?(ПоказатьВсе, ОбщегоНазначенияКлиентСервер.ПрефиксГруппыПоказатьВсе(), "") + ОписаниеДействия.ИмяКоманды;
КомандаДействие = Форма.Команды.Найти(ИмяКоманды);
Если КомандаДействие = Неопределено Тогда
КомандаДействие = Форма.Команды.Добавить(ИмяКоманды);
КонецЕсли;
КомандаДействие.Заголовок = ОписаниеДействия.Заголовок;
Если СтрРазделить(ОписаниеДействия.Обработчик, ".").Количество() = 1 Тогда
КомандаДействие.Действие = ОписаниеДействия.Обработчик;
Иначе
КомандаДействие.Действие = "Подключаемый_ОбработатьДействиеИнформационногоСообщения";
КонецЕсли;
ИмяКнопки = ГруппаКомандыДействия.Имя + "_" + ОписаниеДействия.ИмяКоманды;
КнопкаДействие = Форма.Элементы.Добавить(ИмяКнопки, Тип("КнопкаФормы"), ГруппаКомандыДействия);
КнопкаДействие.Вид = ВидКнопкиФормы.Гиперссылка;
КнопкаДействие.Заголовок = ОписаниеДействия.Заголовок;
КнопкаДействие.ИмяКоманды = КомандаДействие.Имя;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Процедура ДобавитьКнопкуСкрытияСообщения(Форма, ГруппаРазмещения, СкрываемаяГруппа, Параметры)
Если Не Параметры.Скрываемый Тогда
Возврат;
КонецЕсли;
Если ЗначениеЗаполнено(Параметры.ОбработчикЗакрытия)
И Не ЗначениеЗаполнено(Параметры.Идентификатор) Тогда
ТекстИсключения = НСтр("ru = 'Для важного сообщения с заполненным свойством ""ОбработчикЗакрытия""
|должно быть заполнено свойство ""Идентификатор"".
|
|Текст проблемного сообщения:
|%1'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстИсключения, Параметры.Сообщение);
КонецЕсли;
ИмяКоманды = ОбщегоНазначенияКлиентСервер.ПрефиксКомандСкрытияВажногоСообщения() + СкрываемаяГруппа.Имя;
КомандаЗакрытия = Форма.Команды.Найти(ИмяКоманды);
Если КомандаЗакрытия = Неопределено Тогда
КомандаЗакрытия = Форма.Команды.Добавить(ИмяКоманды);
КонецЕсли;
КомандаЗакрытия.Заголовок = НСтр("ru = 'Скрыть сообщение'");
КомандаЗакрытия.Подсказка = НСтр("ru = 'Скрыть сообщение'");
КомандаЗакрытия.Картинка = БиблиотекаКартинок.ВажноеСообщениеЗакрыть;
Если ЗначениеЗаполнено(Параметры.ОбработчикЗакрытия) И СтрРазделить(Параметры.ОбработчикЗакрытия, ".").Количество() = 1 Тогда
КомандаЗакрытия.Действие = Параметры.ОбработчикЗакрытия;
Иначе
КомандаЗакрытия.Действие = "Подключаемый_ОбработатьДействиеИнформационногоСообщения";
КонецЕсли;
КнопкаЗакрытие = Форма.Элементы.Добавить(СкрываемаяГруппа.Имя + "_" + "КнопкаЗакрыть", Тип("КнопкаФормы"), ГруппаРазмещения);
КнопкаЗакрытие.Вид = ВидКнопкиФормы.Гиперссылка;
КнопкаЗакрытие.ИмяКоманды = КомандаЗакрытия.Имя;
КнопкаЗакрытие.Отображение = ОтображениеКнопки.Картинка;
Если ЗначениеЗаполнено(Параметры.ОбработчикЗакрытия) Тогда
ПараметрыКоманды = Новый Структура();
ПараметрыКоманды.Вставить("Обработчик", Параметры.ОбработчикЗакрытия);
ПараметрыКоманды.Вставить("Идентификатор", Параметры.Идентификатор);
Форма.БФ_ОбработчикиКомандВажногоСообщения.Вставить(ИмяКоманды, ПараметрыКоманды);
КонецЕсли;
КонецПроцедуры
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - Строка
// * Значение - Цвет - цвет из палитры.
//
Функция ЦветаВажныхСообщений()
Соответствие = Новый Соответствие;
Соответствие.Вставить("Успех", ЦветаПалитры.Зеленый);
Соответствие.Вставить("Информация", ЦветаПалитры.Голубой);
Соответствие.Вставить("Предупреждение", ЦветаПалитры.Желтый);
Соответствие.Вставить("Ошибка", ЦветаПалитры.Красный);
Возврат Соответствие;
КонецФункции
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - Строка
// * Значение - Картинка
//
Функция КартинкиВажныхСообщений()
Соответствие = Новый Соответствие;
Соответствие.Вставить("Успех", БиблиотекаКартинок.ВажноеСообщениеУспешно);
Соответствие.Вставить("Информация", БиблиотекаКартинок.ВажноеСообщениеИнформация);
Соответствие.Вставить("Предупреждение", БиблиотекаКартинок.ВажноеСообщениеПредупреждение);
Соответствие.Вставить("Ошибка", БиблиотекаКартинок.ВажноеСообщениеОшибка);
Возврат Соответствие;
КонецФункции
Процедура УстановитьШрифтЗаголовкаВажныхСообщений(Шрифт)
Шрифт = ШрифтыСтиля.ТекстВторогоУровня;
КонецПроцедуры
// Возвращаемое значение:
// Шрифт
//
Функция ШрифтВажныхСообщений()
Возврат ШрифтыСтиля.ТекстТретьегоУровня;
КонецФункции
// Возвращаемое значение:
// ГруппаФормы
//
Функция НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, Родитель)
Группа = Форма.Элементы.Добавить(ИмяГруппы, Тип("ГруппаФормы"), Родитель);
Группа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
Группа.ОтображатьЗаголовок = Ложь;
Группа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
Возврат Группа;
КонецФункции
// Возвращаемое значение:
// ТаблицаЗначений:
// * ТипСообщения - Строка
// * Количество - Число
// * ПараметрыСообщения - Массив из см. ОбщегоНазначения.ПараметрыВажногоСообщения
//
Функция НоваяТаблицаСгруппированныхСообщений()
СгруппированныеСообщения = Новый ТаблицаЗначений;
СгруппированныеСообщения.Колонки.Добавить("ТипСообщения", Новый ОписаниеТипов("Строка"));
СгруппированныеСообщения.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число"));
СгруппированныеСообщения.Колонки.Добавить("ПараметрыСообщения", Новый ОписаниеТипов("Структура"));
Возврат СгруппированныеСообщения;
КонецФункции
// Параметры:
// СгруппированныеСообщения - см. ОбщегоНазначения.НоваяТаблицаСгруппированныхСообщений
// ДобавляемыеСообщения - см. ОбщегоНазначения.ПараметрыВажногоСообщения
//
Процедура СгруппироватьСообщения(СгруппированныеСообщения, ДобавляемыеСообщения)
Для Каждого ДобавляемоеСообщение Из ДобавляемыеСообщения.ВыгрузитьЗначения() Цикл
Если ЗначениеЗаполнено(ДобавляемоеСообщение.Родитель) Тогда
Продолжить;
КонецЕсли;
Строка = СгруппированныеСообщения.Добавить();
Строка.ТипСообщения = ДобавляемоеСообщение.ТипСообщения;
Если ДобавляемоеСообщение.ТипСообщения = "Ошибка" Тогда
Строка.Уровень = 0;
ИначеЕсли ДобавляемоеСообщение.ТипСообщения = "Предупреждение" Тогда
Строка.Уровень = 1;
ИначеЕсли ДобавляемоеСообщение.ТипСообщения = "Информация" Тогда
Строка.Уровень = 2;
Иначе
Строка.Уровень = 3;
КонецЕсли;
Строка.ПараметрыСообщения = ДобавляемоеСообщение;
КонецЦикла;
СгруппированныеСообщения.Сортировать("Уровень Возр");
КонецПроцедуры
Процедура ВывестиПростоеВажноеСообщение(Форма, ПараметрыСообщения, Родитель)
ЦветаВажныхСообщений = ЦветаВажныхСообщений();
КартинкиВажныхСообщений = КартинкиВажныхСообщений();
Родитель.ЦветФона = ЦветаВажныхСообщений[ПараметрыСообщения.ТипСообщения];
ДекорацияКартинка = Форма.Элементы.Добавить(Родитель.Имя + "_" + "КартинкаСообщения", Тип("ДекорацияФормы"), Родитель);
ДекорацияКартинка.Вид = ВидДекорацииФормы.Картинка;
ДекорацияКартинка.Картинка = КартинкиВажныхСообщений[ПараметрыСообщения.ТипСообщения];
ДекорацияКартинка.ЦветКартинки = ЦветаВажныхСообщений[ПараметрыСообщения.ТипСообщения];
Если ЗначениеЗаполнено(ПараметрыСообщения.Заголовок) Тогда
УстановитьШрифтЗаголовкаВажныхСообщений(ДекорацияКартинка.Шрифт);
Иначе
ДекорацияКартинка.Шрифт = ШрифтВажныхСообщений();
ДекорацияКартинка.РазмерКартинки = РазмерКартинки.ПоРазмеруШрифта;
КонецЕсли;
ИмяГруппы = Родитель.Имя + "_" + "БФ_ГруппаВажноеСообщение";
ГруппаВажноеСообщение = НоваяГруппаВажногоСообщения(Форма, ИмяГруппы, Родитель);
ГруппаВажноеСообщение.РастягиватьПоГоризонтали = Истина;
ГруппаВажноеСообщение.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
ГруппаВажноеСообщение.ВертикальныйИнтервал = ИнтервалМеждуЭлементамиФормы.Половинный;
ВывестиКонтентСообщения(Форма, ГруппаВажноеСообщение, ПараметрыСообщения);
ДобавитьКнопкуСкрытияСообщения(Форма, Родитель, Родитель, ПараметрыСообщения);
КонецПроцедуры
#КонецОбласти
// См. СтандартныеПодсистемыСервер.ПриОпределенииМетодовРазрешенныхДляВызоваКакПроизвольныйКод
Процедура ПриОпределенииМетодовРазрешенныхДляВызоваКакПроизвольныйКод(Методы) Экспорт
Методы.Вставить("ЕстьСсылкиНаОбъект", Истина);
КонецПроцедуры
#КонецОбласти
#КонецЕсли