const regex = new RegExp('(?<=(?:\\/\\/){1}[ [ruА-Яа-яёЁ])((?:[ruА-Яа-яёЁ\\s\\d \\,\\.\\:\\-\\"\\&\\d\\*\\;\\(\\)\\.\\,\\\\'\\=\\<\\>\\!-\\?\\@^#])*?)$(?:[\\b\\t\\s]+((?:Функция|Процедура)\\s+(?:[\\w\\d]|[А-Яа-я])+\\([\\w\\W]*?\\)\\s*(?:Экспорт)?))', 'gmi')
const str = `///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 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 Тогда
ПредставленияОбъектов = ПредметыСтрокой(ОбъектыСОшибками);
Для Каждого Ошибка Из ОшибкиРазметки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, Ошибка.Дубль,
ОписаниеОшибкиЗамены("НеизвестныеДанные", Ошибка.Объект, ПредставленияОбъектов[Ошибка.Объект],
Ошибка.Текст));
КонецЦикла;
КонецЕсли;
// Замена и удаление найденных дублей.
ПараметрыВыполнения.Вставить("ПарыЗамен", ПарыЗамен);
ПараметрыВыполнения.Вставить("УспешныеЗамены", Новый Соответствие);
ОтключитьОбновлениеКлючейДоступа(Истина);
Попытка
КоличествоДублей = Дубли.Количество();
Номер = 1;
Для Каждого Дубль Из Дубли Цикл
БылиОшибки = Результат.ЕстьОшибки;
Результат.ЕстьОшибки = Ложь;
// @skip-check query-in-loop - Порционная обработка большого объема данных.
ЗаменитьСсылкиКороткимиТранзакциями(Результат, ПараметрыВыполнения, Дубль, ТаблицаПоиска);
Если НЕ Результат.ЕстьОшибки Тогда
ПараметрыВыполнения.УспешныеЗамены.Вставить(Дубль, ПараметрыВыполнения.ПарыЗамен[Дубль]);
КонецЕсли;
Результат.ЕстьОшибки = Результат.ЕстьОшибки ИЛИ БылиОшибки;
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("НомерСеанса", НомерСеансаИнформационнойБазы());
ДополнительныеПараметры.Вставить("КоличествоОбработанных", Номер);
ДлительныеОперации.СообщитьПрогресс(Номер,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Замена дублей... обработано (%1 из %2)'"),
Номер, КоличествоДублей), ДополнительныеПараметры);
Номер = Номер + 1;
ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, Результат.ЕстьОшибки);
КонецЦикла;
ОбщегоНазначенияПереопределяемый.ПослеЗаменыСсылок(Результат, ПараметрыВыполнения, ТаблицаПоиска);
ОтключитьОбновлениеКлючейДоступа(Ложь);
Исключение
ОтключитьОбновлениеКлючейДоступа(Ложь);
ВызватьИсключение;
КонецПопытки;
Если ПодсистемаСуществует("СтандартныеПодсистемы.УдалениеПомеченныхОбъектов")
И ПараметрыВыполнения.УдалятьНепосредственно Тогда
МодульУдалениеПомеченныхОбъектов = ОбщийМодуль("УдалениеПомеченныхОбъектов");
ДлительныеОперации.СообщитьПрогресс(0, НСтр("ru = 'Удаление дублей...'"));
РезультатУдаления = МодульУдалениеПомеченныхОбъектов.УдалитьПомеченныеОбъекты(Результат.ОчередьКНепосредственномуУдалению);
ЗарегистрироватьОшибкиУдаления(Результат, РезультатУдаления.ПрепятствующиеУдалению);
КонецЕсли;
ОтправитьСтатистикуЗаменыСсылок(Статистика);
Возврат Результат.Ошибки;
КонецФункции
// Конструктор структуры для параметра ПараметрыЗамены функции ОбщегоНазначения.ЗаменитьСсылки.
//
// Возвращаемое значение:
// Структура:
// * СпособУдаления - Строка - указывает, что делать с дублем после успешной замены:
// "" - не предпринимать никаких действий (по умолчанию);
// "Пометка" - помечать на удаление;
// "Непосредственно" - удалять непосредственно.
// * УчитыватьПрикладныеПравила - Булево - если Истина, то для каждой пары "дубль-оригинал"
// вызывается функция ВозможностьЗаменыЭлементов модуля менеджера
// (требуется подсистема "Поиск и удаление дублей"). По умолчанию, Ложь.
// * ВключатьБизнесЛогику - Булево - режим записи объектов при замене в них ссылок дублей на оригиналы.
// Если Истина (по умолчанию), то места использования дублей записываются в обычном режиме,
// иначе запись ведется в режиме ОбменДанными.Загрузка = Истина.
// * ЗаменаПарыВТранзакции - Булево - устарел. определяет размер транзакции при замене дублей.
// Если Истина (по умолчанию), то все места использования одного дубля заменяются в одной транзакции.
// Это может быть очень ресурсоемко в случае большого количества мест использований.
// Если Ложь, то замена в каждом месте использования выполняется в отдельной транзакции.
// * ПривилегированнаяЗапись - Булево - если Истина, то устанавливать привилегированный режим перед запись
// объектов при замене в них ссылок дублей на оригиналы. По умолчанию Ложь.
//
Функция ПараметрыЗаменыСсылок() Экспорт
Результат = Новый Структура;
Результат.Вставить("СпособУдаления", "");
Результат.Вставить("УчитыватьПрикладныеПравила", Ложь);
Результат.Вставить("ВключатьБизнесЛогику", Истина);
Результат.Вставить("ЗаменаПарыВТранзакции", Ложь);
Результат.Вставить("ПривилегированнаяЗапись", Ложь);
Возврат Результат;
КонецФункции
// Получает все места использования ссылок.
// Если какая-либо ссылка нигде не используется, то строк для нее в результирующей таблице не будет.
// При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях.
//
// Параметры:
// НаборСсылок - Массив из ЛюбаяСсылка - ссылки, для которых ищем места использования.
// АдресРезультата - Строка - адрес во временном хранилище, куда будет помещен копия результата замены.
// ДополнительныеПараметры - см. ОбщегоНазначения.ПараметрыПоискаМестИспользования
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * Ссылка - ЛюбаяСсылка - ссылка, которая анализируется.
// * Данные - Произвольный - данные, содержащие анализируемую ссылку.
// * Метаданные - ОбъектМетаданных - метаданные найденных данных.
// * ПредставлениеДанных - Строка - представление данных, содержащих анализируемую ссылку.
// * ТипСсылки - Тип - тип анализируемой ссылки.
// * ВспомогательныеДанные - Булево - Истина, если данные используются анализируемой ссылкой как
// вспомогательные данные (ведущее измерение или попали в исключение ПриДобавленииИсключенийПоискаСсылок).
// * ЭтоСлужебныеДанные - Булево - данные попали в исключение ПриДобавленииИсключенийПоискаСсылок
//
Функция МестаИспользования(Знач НаборСсылок, Знач АдресРезультата = "", ДополнительныеПараметры = Неопределено) Экспорт
МестаИспользования = Новый ТаблицаЗначений;
УстановитьПривилегированныйРежим(Истина);
МестаИспользования = НайтиПоСсылкам(НаборСсылок); // см. МестаИспользования.
УстановитьПривилегированныйРежим(Ложь);
// МестаИспользования - ТаблицаЗначений - где:
// * Ссылка - ЛюбаяСсылка - Ссылка, которая анализируется.
// * Данные - Произвольный - Данные, содержащие анализируемую ссылку.
// * Метаданные - ОбъектМетаданных - Метаданные найденных данных.
МестаИспользования.Колонки.Добавить("ПредставлениеДанных", Новый ОписаниеТипов("Строка"));
МестаИспользования.Колонки.Добавить("ТипСсылки");
МестаИспользования.Колонки.Добавить("ИнформацияОМестеИспользования");
МестаИспользования.Колонки.Добавить("ВспомогательныеДанные", Новый ОписаниеТипов("Булево"));
МестаИспользования.Колонки.Добавить("ЭтоСлужебныеДанные", Новый ОписаниеТипов("Булево"));
МестаИспользования.Индексы.Добавить("Ссылка");
МестаИспользования.Индексы.Добавить("Данные");
МестаИспользования.Индексы.Добавить("ВспомогательныеДанные");
МестаИспользования.Индексы.Добавить("Ссылка, ВспомогательныеДанные");
ТипКлючиЗаписей = ОписаниеТипаКлючиЗаписей();
ТипВсеСсылки = ОписаниеТипаВсеСсылки();
МетаданныеПоследовательностей = Метаданные.Последовательности;
МетаданныеКонстант = Метаданные.Константы;
МетаданныеДокументов = Метаданные.Документы;
ИсключенияПоискаСсылок = ИсключенияПоискаСсылок();
ДополнительныеИсключенияПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
ДополнительныеПараметры,
"ДополнительныеИсключенияПоискаСсылок",
Новый Соответствие);
Для каждого МетаданныеРеквизитыИсключения Из ДополнительныеИсключенияПоискаСсылок Цикл
ЗначениеИсключения = ИсключенияПоискаСсылок[МетаданныеРеквизитыИсключения.Ключ];
Если ЗначениеИсключения = Неопределено Тогда
ИсключенияПоискаСсылок.Вставить(МетаданныеРеквизитыИсключения.Ключ,
МетаданныеРеквизитыИсключения.Значение);
Иначе
Если ТипЗнч(ЗначениеИсключения) = Тип("Массив") Тогда
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ЗначениеИсключения,
МетаданныеРеквизитыИсключения.Значение);
КонецЕсли;
КонецЕсли;
КонецЦикла;
ОтменаИсключенийПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеПараметры,
"ОтменаИсключенийПоискаСсылок", Новый Массив);
Для каждого ОтменаИсключения Из ОтменаИсключенийПоискаСсылок Цикл
ИсключенияПоискаСсылок.Удалить(ОтменаИсключения);
КонецЦикла;
СлужебныеСвязиДанных = СлужебныеСвязиДанных(МестаИспользования, ИсключенияПоискаСсылок);
КэшИзмеренийРегистров = Новый Соответствие;
Для Каждого МестоИспользования Из МестаИспользования Цикл
ТипДанных = ТипЗнч(МестоИспользования.Данные);
ЭтоСлужебныеДанные = СлужебныеСвязиДанных[МестоИспользования] <> Неопределено;
ЭтоВспомогательныеДанные = ЭтоСлужебныеДанные;
Если ТипДанных = Неопределено Или МетаданныеДокументов.Содержит(МестоИспользования.Метаданные) Тогда
Представление = Строка(МестоИспользования.Данные);
ИначеЕсли МетаданныеКонстант.Содержит(МестоИспользования.Метаданные) Тогда
Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = 'константа'") + ")";
ИначеЕсли МетаданныеПоследовательностей.Содержит(МестоИспользования.Метаданные) Тогда
Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = 'последовательность'") + ")";
ИначеЕсли ТипВсеСсылки.СодержитТип(ТипДанных) Тогда
МетаПредставлениеОбъекта = Новый Структура("ПредставлениеОбъекта");
ЗаполнитьЗначенияСвойств(МетаПредставлениеОбъекта, МестоИспользования.Метаданные);
Если ПустаяСтрока(МетаПредставлениеОбъекта.ПредставлениеОбъекта) Тогда
МетаПредставление = МестоИспользования.Метаданные.Представление();
Иначе
МетаПредставление = МетаПредставлениеОбъекта.ПредставлениеОбъекта;
КонецЕсли;
Представление = Строка(МестоИспользования.Данные);
Если Не ПустаяСтрока(МетаПредставление) Тогда
Представление = Представление + " (" + МетаПредставление + ")";
КонецЕсли;
ИначеЕсли ТипКлючиЗаписей.СодержитТип(ТипДанных) Тогда
Представление = МестоИспользования.Метаданные.ПредставлениеЗаписи;
Если ПустаяСтрока(Представление) Тогда
Представление = МестоИспользования.Метаданные.Представление();
КонецЕсли;
ОписаниеИзмерений = Новый Массив;
Для Каждого МетаданныеРеквизитыИсключения Из ОписаниеИзмеренийНабора(МестоИспользования.Метаданные, КэшИзмеренийРегистров) Цикл
Значение = МестоИспользования.Данные[МетаданныеРеквизитыИсключения.Ключ];
Описание = МетаданныеРеквизитыИсключения.Значение;
Если МестоИспользования.Ссылка = Значение Тогда
Если Описание.Ведущее Тогда
ЭтоВспомогательныеДанные = Истина;
КонецЕсли;
КонецЕсли;
Если Не ЭтоСлужебныеДанные Тогда // для оптимизации
ФорматЗначения = Описание.Формат;
ОписаниеИзмерений.Добавить(Описание.Представление + " """
+ ?(ФорматЗначения = Неопределено, Строка(Значение), Формат(Значение, ФорматЗначения)) + """");
КонецЕсли;
КонецЦикла;
Если ОписаниеИзмерений.Количество() > 0 Тогда
Представление = Представление + " (" + СтрСоединить(ОписаниеИзмерений, ", ") + ")";
КонецЕсли;
Иначе
Представление = Строка(МестоИспользования.Данные);
КонецЕсли;
МестоИспользования.ПредставлениеДанных = Представление;
МестоИспользования.ВспомогательныеДанные = ЭтоВспомогательныеДанные;
МестоИспользования.ЭтоСлужебныеДанные = ЭтоСлужебныеДанные;
МестоИспользования.ТипСсылки = ТипЗнч(МестоИспользования.Ссылка);
КонецЦикла;
Если Не ПустаяСтрока(АдресРезультата) Тогда
ПоместитьВоВременноеХранилище(МестаИспользования, АдресРезультата);
КонецЕсли;
Возврат МестаИспользования;
КонецФункции
// Возвращает структуру для параметра ДополнительныеПараметры функции ОбщегоНазначения.МестаИспользования.
//
// Возвращаемое значение:
// Структура:
// * ДополнительныеИсключенияПоискаСсылок - Соответствие - позволяет расширить исключения поиска ссылок
// см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок
// * ОтменаИсключенийПоискаСсылок - Массив из ОбъектМетаданных - полностью отменяет исключения поиска ссылок для
// объектов метаданных.
//
Функция ПараметрыПоискаМестИспользования() Экспорт
ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("ДополнительныеИсключенияПоискаСсылок", Новый Соответствие);
ПараметрыПоиска.Вставить("ОтменаИсключенийПоискаСсылок", Новый Соответствие);
Возврат ПараметрыПоиска;
КонецФункции
// Возвращает исключения при поиске мест использования объектов.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение - исключения поиска ссылок в разрезе объектов метаданных:
// * Ключ - ОбъектМетаданных - объект метаданных, для которого применяются исключения.
// * Значение - Строка
// - Массив из Строка - описание исключенных реквизитов.
// Если "*", то исключены все реквизиты объекта метаданных.
// Если массив строк, то содержит относительные имена исключенных реквизитов.
//
Функция ИсключенияПоискаСсылок() Экспорт
ИсключенияПоискаИнтеграция = Новый Массив;
ИнтеграцияПодсистемБСП.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаИнтеграция);
ИсключенияПоиска = Новый Массив;
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ИсключенияПоиска, ИсключенияПоискаИнтеграция);
ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоиска);
Результат = Новый Соответствие;
Для Каждого ИсключениеПоиска Из ИсключенияПоиска Цикл
// Определение полного имени реквизита и объекта метаданных - носителя реквизита.
Если ТипЗнч(ИсключениеПоиска) = Тип("Строка") Тогда
ПолноеИмя = ИсключениеПоиска;
МассивПодстрок = СтрРазделить(ПолноеИмя, ".");
КоличествоПодстрок = МассивПодстрок.Количество();
ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(МассивПодстрок[0] + "." + МассивПодстрок[1]);
Иначе
ОбъектМетаданных = ИсключениеПоиска;
ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
МассивПодстрок = СтрРазделить(ПолноеИмя, ".");
КоличествоПодстрок = МассивПодстрок.Количество();
Если КоличествоПодстрок > 2 Тогда
Пока Истина Цикл
Родитель = ОбъектМетаданных.Родитель();
Если ТипЗнч(Родитель) = Тип("ОбъектМетаданныхКонфигурация") Тогда
Прервать;
Иначе
ОбъектМетаданных = Родитель;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
// Регистрация.
Если КоличествоПодстрок < 4 Тогда
Результат.Вставить(ОбъектМетаданных, "*");
Иначе
ПутиКРеквизитам = Результат.Получить(ОбъектМетаданных);
Если ПутиКРеквизитам = "*" Тогда
Продолжить; // Весь объект метаданных уже исключен.
ИначеЕсли ПутиКРеквизитам = Неопределено Тогда
ПутиКРеквизитам = Новый Массив;
Результат.Вставить(ОбъектМетаданных, ПутиКРеквизитам);
КонецЕсли;
// Формат реквизита:
// "<ВидОМ>.<ИмяОМ>.<ТипРеквизитаИлиТЧ>.<ИмяРеквизитаИлиТЧ>[.<ТипРеквизита>.<ИмяРеквизитаТЧ>]".
// Примеры:
// "РегистрСведений.ВерсииОбъектов.Реквизит.АвторВерсии",
// "Документ._ДемоЗаказПокупателя.ТабличнаяЧасть.СчетаНаОплату.Реквизит.Счет",
// "ПланВидовРасчета._ДемоОсновныеНачисления.СтандартнаяТабличнаяЧасть.БазовыеВидыРасчета.СтандартныйРеквизит.ВидРасчета".
// Относительный путь к реквизиту должен получиться таким, чтобы его можно было использовать в условиях запроса:
// "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]".
Если КоличествоПодстрок = 4 Тогда
ОтносительныйПутьКРеквизиту = МассивПодстрок[3];
Иначе
ОтносительныйПутьКРеквизиту = МассивПодстрок[3] + "." + МассивПодстрок[5];
КонецЕсли;
ПутиКРеквизитам.Добавить(ОтносительныйПутьКРеквизиту);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает связи подчиненных объектов и перечень реквизитов, по которым осуществляется связь.
//
// Есть возможность переопределить процедуру поиска подчиненных объектов.
// Для этого в общем модуле или модуле менеджера необходимо реализовать процедуру
// ПриПоискеЗаменыСсылок с параметрами:
// ПарыЗамен - Соответствие - содержит пары значение оригинал/дубль.
// НеобработанныеЗначенияОригиналов - Массив из Структура - дополнительная информация об обрабатываемых объектах:
// * ЗаменяемоеЗначение - ПроизвольнаяСсылка - оригинальное значение заменяемого объекта.
// * ИспользуемыеСвязи - см. ОбщегоНазначения.СвязиПодчиненныхОбъектовПоТипам
// * ЗначениеКлючевыхРеквизитов - Структура - где Ключ - имя реквизита, значение - значение реквизита.
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * ПодчиненныйОбъект - ОбъектМетаданных - объект метаданных подчиненного объекта.
// * ПоляСвязей - Строка - имена реквизитов, определяющих связь между основными и подчиненными объектами.
// * ПриПоискеЗаменыСсылок - Строка - опционально. Имя общего модуля или модуля менеджера, в котором определена
// процедура ПриПоискеЗаменыСсылок.
// * ВыполнятьАвтоматическийПоискЗаменСсылок - Булево - если указать Истина, то будет выполнена попытка поиска замен
// для подчиненных объектов по значениям полей связи. В случае, если объект не существует,
// будет выполнена процедура ПриПоискеЗаменыСсылок. См. также ЗаменитьСсылки.
//
Функция ПодчиненныеОбъекты() Экспорт
ОписаниеСвязей = Новый ТаблицаЗначений;
ОписаниеСвязей.Колонки.Добавить("ПодчиненныйОбъект", Новый ОписаниеТипов("ОбъектМетаданных"));
ОписаниеСвязей.Колонки.Добавить("ПоляСвязей");
ОписаниеСвязей.Колонки.Добавить("ПриПоискеЗаменыСсылок", ОписаниеТипаСтрока(0));
ОписаниеСвязей.Колонки.Добавить("ВыполнятьАвтоматическийПоискЗаменСсылок", Новый ОписаниеТипов("Булево"));
ИнтеграцияПодсистемБСП.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей);
ОбщегоНазначенияПереопределяемый.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей);
// Если передали соответствие или структуру преобразуем к необходимому типу.
Для каждого СтрокаСвязи Из ОписаниеСвязей Цикл
ТипОписанияПолейСвязи = ТипЗнч(СтрокаСвязи.ПоляСвязей);
Если ТипОписанияПолейСвязи = Тип("Структура")
ИЛИ ТипОписанияПолейСвязи = Тип("Соответствие") Тогда
ПоляСвязейСтрокой = "";
Для каждого КлючЗначение Из СтрокаСвязи.ПоляСвязей Цикл
ПоляСвязейСтрокой = ПоляСвязейСтрокой + КлючЗначение.Ключ + ",";
КонецЦикла;
СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(ПоляСвязейСтрокой,1);
СтрокаСвязи.ПоляСвязей = ПоляСвязейСтрокой;
КонецЕсли;
Если ТипОписанияПолейСвязи = Тип("Массив") Тогда
СтрокаСвязи.ПоляСвязей = СтрСоединить(СтрокаСвязи.ПоляСвязей, ",");
КонецЕсли;
КонецЦикла;
Возврат ОписаниеСвязей;
КонецФункции
// Возвращает связи подчиненных объектов с указанием типа поля связи.
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * Ключ - Строка
// * ТипРеквизита - Тип
// * ИмяРеквизита - Строка
// * Используется - Булево
// * Метаданные - ОбъектМетаданных
//
Функция СвязиПодчиненныхОбъектовПоТипам() Экспорт
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("ТипРеквизита", Новый ОписаниеТипов("Тип"));
Результат.Колонки.Добавить("ИмяРеквизита", ОписаниеТипаСтрока(0));
Результат.Колонки.Добавить("Ключ", ОписаниеТипаСтрока(0));
Результат.Колонки.Добавить("Используется", Новый ОписаниеТипов("Булево"));
Результат.Колонки.Добавить("Метаданные");
Возврат Результат;
КонецФункции
#КонецОбласти
#Область УсловныеВызовы
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для вызова необязательных подсистем.
// Возвращает Истина, если функциональная подсистема существует в конфигурации.
// Предназначена для реализации вызова необязательной подсистемы (условного вызова).
// У функциональной подсистемы снят флажок "Включать в командный интерфейс".
// См. также ОбщегоНазначенияПереопределяемый.ПриОпределенииОтключенныхПодсистем
// и ОбщегоНазначенияКлиент.ПодсистемаСуществует для вызова из клиентского кода.
//
// Параметры:
// ПолноеИмяПодсистемы - Строка - полное имя объекта метаданных подсистема
// без слов "Подсистема." и с учетом регистра символов.
// Например: "СтандартныеПодсистемы.ВариантыОтчетов".
//
// Пример:
// Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВариантыОтчетов") Тогда
// МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов");
// МодульВариантыОтчетов.<Имя метода>();
// КонецЕсли;
//
// Возвращаемое значение:
// Булево - Истина, если подсистема существует.
//
Функция ПодсистемаСуществует(ПолноеИмяПодсистемы) Экспорт
ИменаПодсистем = СтандартныеПодсистемыПовтИсп.ИменаПодсистем();
Возврат ИменаПодсистем.Получить(ПолноеИмяПодсистемы) <> Неопределено;
КонецФункции
// Возвращает ссылку на общий модуль или модуль менеджера по имени.
//
// Параметры:
// Имя - Строка - имя общего модуля.
//
// Возвращаемое значение:
// ОбщийМодуль
// МодульМенеджераОбъекта
//
// Пример:
// Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда
// МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации");
// МодульОбновлениеКонфигурации.<Имя метода>();
// КонецЕсли;
//
// Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолнотекстовыйПоиск") Тогда
// МодульПолнотекстовыйПоискСервер = ОбщегоНазначения.ОбщийМодуль("ПолнотекстовыйПоискСервер");
// МодульПолнотекстовыйПоискСервер.<Имя метода>();
// КонецЕсли;
//
Функция ОбщийМодуль(Имя) Экспорт
Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда
// АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно.
УстановитьБезопасныйРежим(Истина);
Модуль = Вычислить(Имя);
// АПК:488-вкл
ИначеЕсли СтрЧислоВхождений(Имя, ".") = 1 Тогда
Возврат СерверныйМодульМенеджера(Имя);
Иначе
Модуль = Неопределено;
КонецЕсли;
Если ТипЗнч(Модуль) <> Тип("ОбщийМодуль") Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Общий модуль ""%1"" не существует.'"),
Имя);
КонецЕсли;
Возврат Модуль;
КонецФункции
#КонецОбласти
#Область ТекущееОкружение
////////////////////////////////////////////////////////////////////////////////
// Функции описания текущего окружения клиентского приложения и операционной системы.
// Возвращает Истина, если клиентское приложение запущено под управлением ОС 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
Или ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, "8.3.22.1923") >= 0
И (СистемнаяИнформация.ТипПлатформы = ТипПлатформы["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/Обработка.ВыгрузкаДанныхПроекта";
// возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта.
//
Функция АдресПубликацииИнформационнойБазыВИнтернете() Экспорт
УстановитьПривилегированныйРежим(Истина);
Возврат Константы.АдресПубликацииИнформационнойБазыВИнтернете.Получить();
КонецФункции
// Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ
// для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию локальной сети.
// Например, если такой адрес включить в электронное письмо, то из письма за одно нажатие
// можно перейти к форме объекта в самой программе.
//
// Возвращаемое значение:
// Строка - адрес информационной базы, как он задан в настройке "Локальный адрес" в панели администрирования
// (хранится в константе АдресПубликацииИнформационнойБазыВЛокальнойСети).
// Например, "http://localserver/base".
//
// Пример:
// ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта";
// возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта.
//
Функция АдресПубликацииИнформационнойБазыВЛокальнойСети() Экспорт
УстановитьПривилегированныйРежим(Истина);
Возврат Константы.АдресПубликацииИнформационнойБазыВЛокальнойСети.Получить();
КонецФункции
// Формирует ссылку для входа в программу для указанного пользователя.
//
// Параметры:
// Пользователь - Строка - логин пользователя для входа в программу;
// Пароль - Строка - пароль пользователя для входа в программу;
// ВидПубликацииИБ - Строка - через какую публикацию пользователь входит в программу:
// "ВИнтернете" или "ВЛокальнойСети".
//
// Возвращаемое значение:
// Строка, Неопределено - адрес входа в программу или Неопределено, если адрес не настроен.
//
Функция АдресВходаВПрограмму(Пользователь, Пароль, ВидПубликацииИБ) Экспорт
Результат = "";
Если НРег(ВидПубликацииИБ) = НРег("ВИнтернете") Тогда
Результат = АдресПубликацииИнформационнойБазыВИнтернете();
ИначеЕсли НРег(ВидПубликацииИБ) = НРег("ВЛокальнойСети") Тогда
Результат = АдресПубликацииИнформационнойБазыВЛокальнойСети();
КонецЕсли;
Если ПустаяСтрока(Результат) Тогда
Возврат Неопределено;
КонецЕсли;
Если Не СтрЗаканчиваетсяНа(Результат, "/") Тогда
Результат = Результат + "/";
КонецЕсли;
Результат = Результат + "?n=" + КодироватьСтроку(Пользователь, СпособКодированияСтроки.КодировкаURL);
Если ЗначениеЗаполнено(Пароль) Тогда
Результат = Результат + "&p=" + КодироватьСтроку(Пароль, СпособКодированияСтроки.КодировкаURL);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает редакцию конфигурации.
// Редакцией принято называть две первые группы цифр полной версии конфигурации.
// Например, у версии "1.2.3.4" редакция "1.2".
//
// Возвращаемое значение:
// Строка - номер редакции конфигурации.
//
Функция РедакцияКонфигурации() Экспорт
Результат = "";
ВерсияКонфигурации = Метаданные.Версия;
Позиция = СтрНайти(ВерсияКонфигурации, ".");
Если Позиция > 0 Тогда
Результат = Лев(ВерсияКонфигурации, Позиция);
ВерсияКонфигурации = Сред(ВерсияКонфигурации, Позиция + 1);
Позиция = СтрНайти(ВерсияКонфигурации, ".");
Если Позиция > 0 Тогда
Результат = Результат + Лев(ВерсияКонфигурации, Позиция - 1);
Иначе
Результат = "";
КонецЕсли;
КонецЕсли;
Если ПустаяСтрока(Результат) Тогда
Результат = Метаданные.Версия;
КонецЕсли;
Возврат Результат;
КонецФункции
// Общие параметры подсистемы.
//
// См. ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности
//
// Возвращаемое значение:
// Структура:
// * ИмяФормыПерсональныхНастроек - Строка - имя формы для редактирования персональных настроек.
// * ЗапрашиватьПодтверждениеПриЗавершенииПрограммы - Булево - по умолчанию Истина. Если установить в Ложь, то
// подтверждение при завершении работы программы не
// будет запрашиваться, если явно не разрешить в
// персональных настройках программы.
// * МинимальнаяВерсияПлатформы - Строка - минимальная версии платформы, требуемая для запуска программы.
// Запуск программы на версии платформы ниже указанной будет невозможен.
// Например, "8.3.6.1650".
// * РекомендуемаяВерсияПлатформы - Строка - рекомендуемая версия платформы для запуска программы.
// Например, "8.3.8.2137".
// * ОтключитьИдентификаторыОбъектовМетаданных - Булево - отключает заполнение справочников ИдентификаторыОбъектовМетаданных
// и ИдентификаторыОбъектовРасширений, процедуру выгрузки и загрузки в узлах РИБ.
// Для частичного встраивания отдельных функций библиотеки в конфигурации без постановки на поддержку.
// * РекомендуемыйОбъемОперативнойПамяти - Число - объем памяти в гигабайтах, рекомендуемый для комфортной работы в
// программе.
// Устарели, следует использовать свойства МинимальнаяВерсияПлатформы и РекомендуемаяВерсияПлатформы:
// * МинимальноНеобходимаяВерсияПлатформы - Строка - полный номер версии платформы для запуска программы.
// Например, "8.3.4.365".
// * РаботаВПрограммеЗапрещена - Булево - начальное значение Ложь.
//
Функция ОбщиеПараметрыБазовойФункциональности() Экспорт
ОбщиеПараметры = Новый Структура;
ОбщиеПараметры.Вставить("ИмяФормыПерсональныхНастроек", "");
ОбщиеПараметры.Вставить("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", Истина);
ОбщиеПараметры.Вставить("ОтключитьИдентификаторыОбъектовМетаданных", Ложь);
ОбщиеПараметры.Вставить("РекомендуемыйОбъемОперативнойПамяти", 4);
ОбщиеПараметры.Вставить("МинимальнаяВерсияПлатформы", МинимальнаяВерсияПлатформы());
ОбщиеПараметры.Вставить("РекомендуемаяВерсияПлатформы", ОбщиеПараметры.МинимальнаяВерсияПлатформы);
// Устарело, следует использовать свойства МинимальнаяВерсияПлатформы и РекомендуемаяВерсияПлатформы:
ОбщиеПараметры.Вставить("МинимальноНеобходимаяВерсияПлатформы", "");
ОбщиеПараметры.Вставить("РаботаВПрограммеЗапрещена", Ложь); // Блокировать запуск, если версия ниже минимальной.
ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности(ОбщиеПараметры);
ОбщиеПараметры.МинимальнаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(ОбщиеПараметры.МинимальнаяВерсияПлатформы);
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(ОбщиеПараметры.РекомендуемаяВерсияПлатформы);
// Локализация
УточнитьМинимальнуюВерсиюПлатформыИзСервиса(ОбщиеПараметры);
// Конец Локализация
СистемнаяИнформация = Новый СистемнаяИнформация;
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, ОбщиеПараметры.МинимальнаяВерсияПлатформы) < 0
И ЭтоВерсияЗащищенногоПрограммногоКомплекса(СистемнаяИнформация.ВерсияПриложения) Тогда
ОбщиеПараметры.МинимальнаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения;
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения;
КонецЕсли;
Минимальная = ОбщиеПараметры.МинимальнаяВерсияПлатформы;
Рекомендуемая = ОбщиеПараметры.РекомендуемаяВерсияПлатформы;
Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда
ТекстСообщения = НСтр("ru = 'Указанные в %1 минимальная и рекомендуемая версии платформы не соответствуют следующим требованиям:
| - минимальная версия должна быть заполнена;
| - минимальная версия не должна быть меньше минимальной версии БСП (см. %2);
| - минимальная версия не должна быть меньше рекомендуемой версии.
|Минимальная версия: %3
|Минимальная версия БСП: %4
|Рекомендуемая версия: %5'",
КодОсновногоЯзыка());
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения,
"ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности",
"ОбщегоНазначения.МинимальнаяВерсияПлатформы",
Минимальная, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), Рекомендуемая);
ЗаписьЖурналаРегистрации(НСтр("ru = 'Базовая функциональность'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,,
ТекстСообщения);
КонецЕсли;
// Обратная совместимость.
МинимальноНеобходимаяВерсияПлатформы = ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы;
Если ЗначениеЗаполнено(МинимальноНеобходимаяВерсияПлатформы) Тогда
Если ОбщиеПараметры.РаботаВПрограммеЗапрещена Тогда
ОбщиеПараметры.МинимальнаяВерсияПлатформы = МинимальноНеобходимаяВерсияПлатформы;
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = "";
Иначе
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = МинимальноНеобходимаяВерсияПлатформы;
ОбщиеПараметры.МинимальнаяВерсияПлатформы = "";
КонецЕсли;
Иначе
Текущая = СистемнаяИнформация.ВерсияПриложения;
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Минимальная, Текущая) > 0 Тогда
ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = Минимальная;
ОбщиеПараметры.РаботаВПрограммеЗапрещена = Истина;
Иначе
ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = Рекомендуемая;
ОбщиеПараметры.РаботаВПрограммеЗапрещена = Ложь;
КонецЕсли;
КонецЕсли;
УточнитьВерсиюПлатформы(ОбщиеПараметры);
Возврат ОбщиеПараметры;
КонецФункции
// Возвращает описания всех библиотек конфигурации, включая
// описание самой конфигурации.
//
// Возвращаемое значение:
// Массив - структур со свойствами:
// * Имя - Строка - имя подсистемы, например, "СтандартныеПодсистемы".
// * ИдентификаторИнтернетПоддержки - Строка - уникальное имя программы в сервисах интернет-поддержки.
// * Версия - Строка - версия в формате из четырех цифр, например "2.3.3.1".
// * ЭтоКонфигурация - Булево - признак того, что данная подсистема является основной конфигурацией.
//
Функция ОписанияПодсистем() Экспорт
Результат = Новый Массив;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл
Параметры = Новый Структура;
Параметры.Вставить("Имя");
Параметры.Вставить("ИдентификаторИнтернетПоддержки");
Параметры.Вставить("Версия");
Параметры.Вставить("ЭтоКонфигурация");
ЗаполнитьЗначенияСвойств(Параметры, ОписаниеПодсистемы.Значение);
Результат.Добавить(Параметры);
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает идентификатор Интернет-поддержки основной конфигурации.
//
// Возвращаемое значение:
// Строка - уникальное имя программы в сервисах Интернет-поддержки.
//
Функция ИдентификаторИнтернетПоддержкиКонфигурации() Экспорт
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл
Если ОписаниеПодсистемы.Значение.ЭтоКонфигурация Тогда
Возврат ОписаниеПодсистемы.Значение.ИдентификаторИнтернетПоддержки;
КонецЕсли;
КонецЦикла;
Возврат "";
КонецФункции
#КонецОбласти
#Область Даты
////////////////////////////////////////////////////////////////////////////////
// Функции для работы с датами с учетом часового пояса сеанса
// Преобразует локальную дату к формату "YYYY-MM-DDThh:mm:ssTZD" согласно ISO 8601.
//
// Параметры:
// ЛокальнаяДата - Дата - дата в часовом поясе сеанса.
//
// Возвращаемое значение:
// Строка - представление даты.
//
Функция ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата) Экспорт
Смещение = СмещениеСтандартногоВремени(ЧасовойПоясСеанса());
Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата, Смещение);
КонецФункции
// Возвращает строковое представление интервала между переданными датами или
// относительно переданной даты и текущей даты сеанса.
//
// Параметры:
// ВремяНачала - Дата - начальная точка интервала.
// ВремяОкончания - Дата - конечная точка интервала, если не задана - берется текущая дата сеанса.
//
// Возвращаемое значение:
// Строка - представление интервала времени.
//
Функция ИнтервалВремениСтрокой(ВремяНачала, ВремяОкончания = Неопределено) Экспорт
Если ВремяОкончания = Неопределено Тогда
ВремяОкончания = ТекущаяДатаСеанса();
ИначеЕсли ВремяНачала > ВремяОкончания Тогда
ВызватьИсключение НСтр("ru = 'Дата окончания интервала не может быть меньше даты начала.'");
КонецЕсли;
ВеличинаИнтервала = ВремяОкончания - ВремяНачала;
ВеличинаИнтервалаВДнях = Цел(ВеличинаИнтервала/60/60/24);
Если ВеличинаИнтервалаВДнях > 365 Тогда
ОписаниеИнтервала = НСтр("ru = 'более года'");
ИначеЕсли ВеличинаИнтервалаВДнях > 31 Тогда
ОписаниеИнтервала = НСтр("ru = 'более месяца'");
ИначеЕсли ВеличинаИнтервалаВДнях >= 1 Тогда
ОписаниеИнтервала = Формат(ВеличинаИнтервалаВДнях, "ЧДЦ=0") + " "
+ ПользователиСлужебныйКлиентСервер.ПредметЦелогоЧисла(ВеличинаИнтервалаВДнях,
"", НСтр("ru = 'день,дня,дней,,,,,,0'"));
Иначе
ОписаниеИнтервала = НСтр("ru = 'менее одного дня'");
КонецЕсли;
Возврат ОписаниеИнтервала;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Функции для работы с настройкой рабочей даты.
// Сохраняет настройку рабочей даты пользователя.
//
// Параметры:
// НоваяРабочаяДата - Дата - дата, которую необходимо установить в качестве рабочей даты пользователя.
// ИмяПользователя - Строка - имя пользователя, для которого устанавливается рабочая дата.
// Если не задано, то устанавливается для текущего пользователя.
//
Процедура УстановитьРабочуюДатуПользователя(НоваяРабочаяДата, ИмяПользователя = Неопределено) Экспорт
КлючОбъекта = ВРег("РабочаяДата");
ХранилищеОбщихНастроекСохранить(КлючОбъекта, "", НоваяРабочаяДата, , ИмяПользователя);
КонецПроцедуры
// Возвращает значение настройки рабочей даты для пользователя.
//
// Параметры:
// ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата.
// Если не задано, то устанавливается для текущего пользователя.
//
// Возвращаемое значение:
// Дата - значение настройки рабочей даты пользователя или пустая дата, если настройка не задана.
//
Функция РабочаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт
КлючОбъекта = ВРег("РабочаяДата");
Результат = ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, "", '0001-01-01', , ИмяПользователя);
Если ТипЗнч(Результат) <> Тип("Дата") Тогда
Результат = '0001-01-01';
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает значение настройки рабочей даты для пользователя или текущей даты сеанса,
// если рабочая дата пользователя не задана.
//
// Параметры:
// ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата.
// Если не задано, то устанавливается для текущего пользователя.
//
// Возвращаемое значение:
// Дата - значение настройки рабочей даты пользователя или текущая дата сеанса, если настройка не задана.
//
Функция ТекущаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт
Результат = РабочаяДатаПользователя(ИмяПользователя);
Если НЕ ЗначениеЗаполнено(Результат) Тогда
Результат = ТекущаяДатаСеанса();
КонецЕсли;
Возврат НачалоДня(Результат);
КонецФункции
#КонецОбласти
#Область Данные
////////////////////////////////////////////////////////////////////////////////
// Общие процедуры и функции для работы с прикладными типами и коллекциями значений.
// Возвращает строковое имя значения перечисления по его ссылке.
// Вызывает исключение, если передано несуществующее значение перечисления
// (например, удаленное в конфигурации или от отключенного расширения конфигурации).
//
// Параметры:
// Значение - ПеречислениеСсылка - значение, для которого необходимо получить имя перечисления.
//
// Возвращаемое значение:
// Строка
//
// Пример:
// В результат будет помещено строковое значение "ФизическоеЛицо":
// Результат = ОбщегоНазначения.ИмяЗначенияПеречисления(Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо);
//
Функция ИмяЗначенияПеречисления(Значение) Экспорт
ОбъектМетаданных = Значение.Метаданные();
ИндексЗначения = Перечисления[ОбъектМетаданных.Имя].Индекс(Значение);
Возврат ОбъектМетаданных.ЗначенияПеречисления[ИндексЗначения].Имя;
КонецФункции
// Процедура удаляет из массива МассивРеквизитов элементы, соответствующие именам
// реквизитов объекта из массива МассивНепроверяемыхРеквизитов.
// Для использования в обработчиках события ОбработкаПроверкиЗаполнения.
//
// Параметры:
// МассивРеквизитов - Массив - коллекция имен реквизитов объекта.
// МассивНепроверяемыхРеквизитов - Массив - коллекция имен реквизитов объекта, не требующих проверки.
//
Процедура УдалитьНепроверяемыеРеквизитыИзМассива(МассивРеквизитов, МассивНепроверяемыхРеквизитов) Экспорт
Для Каждого ЭлементМассива Из МассивНепроверяемыхРеквизитов Цикл
ПорядковыйНомер = МассивРеквизитов.Найти(ЭлементМассива);
Если ПорядковыйНомер <> Неопределено Тогда
МассивРеквизитов.Удалить(ПорядковыйНомер);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Преобразует таблицу значений в массив структур.
// Может использоваться для передачи на клиент данных в том случае, если таблица
// значений содержит только такие значения, которые могут
// быть переданы с сервера на клиент.
//
// Полученный массив содержит структуры, каждая из которых повторяет
// структуру колонок таблицы значений.
//
// Не рекомендуется использовать для преобразования таблиц значений
// с большим количеством строк.
//
// Параметры:
// ТаблицаЗначений - ТаблицаЗначений - исходная таблица значений.
//
// Возвращаемое значение:
// Массив - коллекция строк таблицы в виде структур.
//
Функция ТаблицаЗначенийВМассив(ТаблицаЗначений) Экспорт
Массив = Новый Массив();
СтруктураСтрокой = "";
НужнаЗапятая = Ложь;
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
Если НужнаЗапятая Тогда
СтруктураСтрокой = СтруктураСтрокой + ",";
КонецЕсли;
СтруктураСтрокой = СтруктураСтрокой + Колонка.Имя;
НужнаЗапятая = Истина;
КонецЦикла;
Для Каждого Строка Из ТаблицаЗначений Цикл
НоваяСтрока = Новый Структура(СтруктураСтрокой);
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
Массив.Добавить(НоваяСтрока);
КонецЦикла;
Возврат Массив;
КонецФункции
// Преобразует строку таблицы значений в структуру.
// Свойства структуры и их значения совпадают с колонками переданной строки.
//
// Параметры:
// СтрокаТаблицыЗначений - СтрокаТаблицыЗначений
//
// Возвращаемое значение:
// Структура - преобразованная строка таблицы значений.
//
Функция СтрокаТаблицыЗначенийВСтруктуру(СтрокаТаблицыЗначений) Экспорт
Структура = Новый Структура;
Для каждого Колонка Из СтрокаТаблицыЗначений.Владелец().Колонки Цикл
Структура.Вставить(Колонка.Имя, СтрокаТаблицыЗначений[Колонка.Имя]);
КонецЦикла;
Возврат Структура;
КонецФункции
// Создает структуру, содержащую имена и значения измерений, ресурсов и реквизитов
// переданного менеджера записи регистра сведений.
//
// Параметры:
// МенеджерЗаписи - РегистрСведенийМенеджерЗаписиИмяРегистраСведений - менеджер записи, из которого надо получить структуру.
// МетаданныеРегистра - ОбъектМетаданныхРегистрСведений - метаданные регистра сведений.
//
// Возвращаемое значение:
// Структура - коллекция измерений ресурсов и реквизитов, переданного менеджеру записи.
//
Функция СтруктураПоМенеджеруЗаписи(МенеджерЗаписи, МетаданныеРегистра) Экспорт
ЗаписьКакСтруктура = Новый Структура;
Если МетаданныеРегистра.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда
ЗаписьКакСтруктура.Вставить("Период", МенеджерЗаписи.Период);
КонецЕсли;
Для Каждого Поле Из МетаданныеРегистра.Измерения Цикл
ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]);
КонецЦикла;
Для Каждого Поле Из МетаданныеРегистра.Ресурсы Цикл
ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]);
КонецЦикла;
Для Каждого Поле Из МетаданныеРегистра.Реквизиты Цикл
ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]);
КонецЦикла;
Возврат ЗаписьКакСтруктура;
КонецФункции
// Создает массив и копирует в него значения, содержащиеся в колонке объекта, для
// которого доступен обход посредством оператора Для каждого … Из.
//
// Параметры:
// КоллекцияСтрок - ТаблицаЗначений
// - ДеревоЗначений
// - СписокЗначений
// - ТабличнаяЧасть
// - Соответствие
// - Структура - коллекция, колонку которой нужно выгрузить в массив.
// А так же другие объекты, для которых доступен обход
// посредством оператора Для каждого … Из … Цикл.
// ИмяКолонки - Строка - имя поля коллекции, значения которого нужно выгрузить.
// ТолькоУникальныеЗначения - Булево - если Истина, то в массив будут включены
// только различающиеся значения.
//
// Возвращаемое значение:
// Массив - значения колонки.
//
Функция ВыгрузитьКолонку(КоллекцияСтрок, ИмяКолонки, ТолькоУникальныеЗначения = Ложь) Экспорт
МассивЗначений = Новый Массив;
УникальныеЗначения = Новый Соответствие;
Для каждого СтрокаКоллекции Из КоллекцияСтрок Цикл
Значение = СтрокаКоллекции[ИмяКолонки];
Если ТолькоУникальныеЗначения И УникальныеЗначения[Значение] <> Неопределено Тогда
Продолжить;
КонецЕсли;
МассивЗначений.Добавить(Значение);
УникальныеЗначения.Вставить(Значение, Истина);
КонецЦикла;
Возврат МассивЗначений;
КонецФункции
// Преобразует текст указанного формата XML в таблицу значений,
// при этом колонки таблицы формируются на основе описания в XML.
//
// Схема XML:
// <?xml version="1.0" encoding="utf-8"?>
// <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
// <xs:element name="Items">
// <xs:complexType>
// <xs:sequence>
// <xs:element maxOccurs="unbounded" name="Item">
// <xs:complexType>
// <xs:attribute name="Code" type="xs:integer" use="required" />
// <xs:attribute name="Name" type="xs:string" use="required" />
// <xs:attribute name="Socr" type="xs:string" use="required" />
// <xs:attribute name="Index" type="xs:string" use="required" />
// </xs:complexType>
// </xs:element>
// </xs:sequence>
// <xs:attribute name="Description" type="xs:string" use="required" />
// <xs:attribute name="Columns" type="xs:string" use="required" />
// </xs:complexType>
// </xs:element>
// </xs:schema>
//
// Параметры:
// XML - Строка
// - ЧтениеXML - текст в формате XML или ЧтениеXML.
//
// Возвращаемое значение:
// Структура:
// * ИмяТаблицы - Строка - имя таблицы.
// * Данные - ТаблицаЗначений - преобразованная из XML таблица.
//
// Пример:
// КлассификаторТаблица = ОбщегоНазначения.ПрочитатьXMLВТаблицу(
// Обработки.ЗагрузкаКурсовВалют.ПолучитьМакет("ОбщероссийскийКлассификаторВалют").ПолучитьТекст()).Данные;
//
Функция ПрочитатьXMLВТаблицу(Знач XML) Экспорт
Если ТипЗнч(XML) <> Тип("ЧтениеXML") Тогда
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(XML);
Иначе
Чтение = XML;
КонецЕсли;
// Прочитаем первый узел и проверим его.
Если Не Чтение.Прочитать() Тогда
ВызватьИсключение НСтр("ru = 'Пустой XML'");
ИначеЕсли Чтение.Имя <> "Items" Тогда
ВызватьИсключение НСтр("ru = 'Ошибка в структуре XML'");
КонецЕсли;
// Получим описание таблицы и создадим ее.
ИмяТаблицы = Чтение.ПолучитьАтрибут("Description");
ИменаКолонок = СтрЗаменить(Чтение.ПолучитьАтрибут("Columns"), ",", Символы.ПС);
Колонок = СтрЧислоСтрок(ИменаКолонок);
ТаблицаЗначений = Новый ТаблицаЗначений;
Для Сч = 1 По Колонок Цикл
ТаблицаЗначений.Колонки.Добавить(СтрПолучитьСтроку(ИменаКолонок, Сч), Новый ОписаниеТипов("Строка"));
КонецЦикла;
// Заполним значения в таблице.
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И Чтение.Имя = "Items" Тогда
Прервать;
ИначеЕсли Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда
Продолжить;
ИначеЕсли Чтение.Имя <> "Item" Тогда
ВызватьИсключение НСтр("ru = 'Ошибка в структуре XML'");
КонецЕсли;
новСтр = ТаблицаЗначений.Добавить();
Для Сч = 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";
КонецЕсли;
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'На задан CLSID для класса %1.'"),
ИмяCOMСоединителя);
КонецФункции
// Устанавливает внешнее соединение с информационной базой по переданным параметрам подключения и возвращает указатель
// на это соединение.
//
// Параметры:
// Параметры - см. ОбщегоНазначенияКлиентСервер.СтруктураПараметровДляУстановкиВнешнегоСоединения
//
// Возвращаемое значение:
// Структура:
// * Соединение - COMОбъект
// - Неопределено - COM-объект соединения или Неопределено в случае ошибки;
// * КраткоеОписаниеОшибки - Строка - краткое описание ошибки;
// * ПодробноеОписаниеОшибки - Строка - подробное описание ошибки;
// * ОшибкаПодключенияКомпоненты - Булево - флаг ошибки подключения COM.
//
Функция УстановитьВнешнееСоединениеСБазой(Параметры) Экспорт
ПодключениеНедоступно = ЭтоLinuxСервер();
КраткоеОписаниеОшибки = НСтр("ru = 'Прямое подключение к информационной базе недоступно на сервере под управлением ОС Linux.'");
Возврат ОбщегоНазначенияСлужебныйКлиентСервер.УстановитьВнешнееСоединениеСБазой(Параметры, ПодключениеНедоступно, КраткоеОписаниеОшибки);
КонецФункции
#КонецОбласти
#Область Метаданные
////////////////////////////////////////////////////////////////////////////////
// Функции определения типов объектов метаданных.
// Ссылочные типы данных
// Определяет принадлежность объекта метаданных к общему типу "Документ".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к документам.
//
// Возвращаемое значение:
// Булево - Истина, если объект является документом.
//
Функция ЭтоДокумент(ОбъектМетаданных) Экспорт
Возврат Метаданные.Документы.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Справочник".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является справочником.
//
Функция ЭтоСправочник(ОбъектМетаданных) Экспорт
Возврат Метаданные.Справочники.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Перечисление".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является перечислением.
//
Функция ЭтоПеречисление(ОбъектМетаданных) Экспорт
Возврат Метаданные.Перечисления.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План обмена".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом обмена.
//
Функция ЭтоПланОбмена(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыОбмена.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План видов характеристик".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом видов характеристик.
//
Функция ЭтоПланВидовХарактеристик(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Бизнес-процесс".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является бизнес-процессом.
//
Функция ЭтоБизнесПроцесс(ОбъектМетаданных) Экспорт
Возврат Метаданные.БизнесПроцессы.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Задача".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является задачей.
//
Функция ЭтоЗадача(ОбъектМетаданных) Экспорт
Возврат Метаданные.Задачи.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План счетов".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом счетов.
//
Функция ЭтоПланСчетов(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "План видов расчета".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является планом видов расчета.
//
Функция ЭтоПланВидовРасчета(ОбъектМетаданных) Экспорт
Возврат Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных);
КонецФункции
// Регистры
// Определяет принадлежность объекта метаданных к общему типу "Регистр сведений".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром сведений.
//
Функция ЭтоРегистрСведений(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Регистр накопления".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром накопления.
//
Функция ЭтоРегистрНакопления(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Регистр бухгалтерии".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром бухгалтерии.
//
Функция ЭтоРегистрБухгалтерии(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к общему типу "Регистр расчета".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регистром расчета.
//
Функция ЭтоРегистрРасчета(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных);
КонецФункции
// Константы
// Определяет принадлежность объекта метаданных к общему типу "Константа".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является константой.
//
Функция ЭтоКонстанта(ОбъектМетаданных) Экспорт
Возврат Метаданные.Константы.Содержит(ОбъектМетаданных);
КонецФункции
// Журналы документов
// Определяет принадлежность объекта метаданных к общему типу "Журнал документов".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является журналом документов.
//
Функция ЭтоЖурналДокументов(ОбъектМетаданных) Экспорт
Возврат Метаданные.ЖурналыДокументов.Содержит(ОбъектМетаданных);
КонецФункции
// Последовательности
// Определяет принадлежность объекта метаданных к общему типу "Последовательности".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является последовательностью.
//
Функция ЭтоПоследовательность(ОбъектМетаданных) Экспорт
Возврат Метаданные.Последовательности.Содержит(ОбъектМетаданных);
КонецФункции
// РегламентныеЗадания
// Определяет принадлежность объекта метаданных к общему типу "Регламентные задания".
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является регламентным заданием.
//
Функция ЭтоРегламентноеЗадание(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегламентныеЗадания.Содержит(ОбъектМетаданных);
КонецФункции
// Общие
// Определяет принадлежность объекта метаданных к типу регистр.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект является каким-либо регистром.
//
Функция ЭтоРегистр(ОбъектМетаданных) Экспорт
Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных)
Или Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных)
Или Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных)
Или Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных);
КонецФункции
// Определяет принадлежность объекта метаданных к ссылочному типу.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу.
//
// Возвращаемое значение:
// Булево - Истина, если объект ссылочного типа.
//
Функция ЭтоОбъектСсылочногоТипа(ОбъектМетаданных) Экспорт
ИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя();
Позиция = СтрНайти(ИмяОбъектаМетаданных, ".");
Если Позиция > 0 Тогда
ИмяБазовогоТипа = Лев(ИмяОбъектаМетаданных, Позиция - 1);
Возврат ИмяБазовогоТипа = "Справочник"
Или ИмяБазовогоТипа = "Документ"
Или ИмяБазовогоТипа = "БизнесПроцесс"
Или ИмяБазовогоТипа = "Задача"
Или ИмяБазовогоТипа = "ПланСчетов"
Или ИмяБазовогоТипа = "ПланОбмена"
Или ИмяБазовогоТипа = "ПланВидовХарактеристик"
Или ИмяБазовогоТипа = "ПланВидовРасчета";
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с типами, объектами метаданных и их строковыми представлениями.
// Возвращает имена реквизитов объекта заданного типа.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - ссылка на элемент базы данных, для которого требуется получить результат функции;
// Тип - Тип - тип значения реквизита.
//
// Возвращаемое значение:
// Строка - строка реквизитов объекта метаданных конфигурации, разделенных символом ",".
//
// Пример:
// РеквизитыОрганизации = ОбщегоНазначения.ИменаРеквизитовПоТипу(Документ.Ссылка, Тип("СправочникСсылка.Организации"));
//
Функция ИменаРеквизитовПоТипу(Ссылка, Тип) Экспорт
Результат = "";
МетаданныеОбъекта = Ссылка.Метаданные();
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Если Реквизит.Тип.СодержитТип(Тип) Тогда
Результат = Результат + ?(ПустаяСтрока(Результат), "", ", ") + Реквизит.Имя;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Возвращает имя базового типа по переданному значению объекта метаданных.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект метаданных, по которому необходимо определить базовый тип.
//
// Возвращаемое значение:
// Строка - имя базового типа по переданному значению объекта метаданных.
//
// Пример:
// ИмяБазовогоТипа = ОбщегоНазначения.ИмяБазовогоТипаПоОбъектуМетаданных(Метаданные.Справочники.Номенклатура); = "Справочники".
//
Функция ИмяБазовогоТипаПоОбъектуМетаданных(ОбъектМетаданных) Экспорт
Если Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда
Возврат "Документы";
ИначеЕсли Метаданные.Справочники.Содержит(ОбъектМетаданных) Тогда
Возврат "Справочники";
ИначеЕсли Метаданные.Перечисления.Содержит(ОбъектМетаданных) Тогда
Возврат "Перечисления";
ИначеЕсли Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных) Тогда
Возврат "РегистрыСведений";
ИначеЕсли Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных) Тогда
Возврат "РегистрыНакопления";
ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных) Тогда
Возврат "РегистрыБухгалтерии";
ИначеЕсли Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных) Тогда
Возврат "РегистрыРасчета";
ИначеЕсли Метаданные.ПланыОбмена.Содержит(ОбъектМетаданных) Тогда
Возврат "ПланыОбмена";
ИначеЕсли Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных) Тогда
Возврат "ПланыВидовХарактеристик";
ИначеЕсли Метаданные.БизнесПроцессы.Содержит(ОбъектМетаданных) Тогда
Возврат "БизнесПроцессы";
ИначеЕсли Метаданные.Задачи.Содержит(ОбъектМетаданных) Тогда
Возврат "Задачи";
ИначеЕсли Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных) Тогда
Возврат "ПланыСчетов";
ИначеЕсли Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных) Тогда
Возврат "ПланыВидовРасчета";
ИначеЕсли Метаданные.Константы.Содержит(ОбъектМетаданных) Тогда
Возврат "Константы";
ИначеЕсли Метаданные.ЖурналыДокументов.Содержит(ОбъектМетаданных) Тогда
Возврат "ЖурналыДокументов";
ИначеЕсли Метаданные.Последовательности.Содержит(ОбъектМетаданных) Тогда
Возврат "Последовательности";
ИначеЕсли Метаданные.РегламентныеЗадания.Содержит(ОбъектМетаданных) Тогда
Возврат "РегламентныеЗадания";
ИначеЕсли Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных.Родитель())
И ОбъектМетаданных.Родитель().Перерасчеты.Найти(ОбъектМетаданных.Имя) = ОбъектМетаданных Тогда
Возврат "Перерасчеты";
ИначеЕсли Метаданные.Обработки.Содержит(ОбъектМетаданных) Тогда
Возврат "Обработки";
ИначеЕсли Метаданные.Отчеты.Содержит(ОбъектМетаданных) Тогда
Возврат "Отчеты";
ИначеЕсли Метаданные.Подсистемы.Содержит(ОбъектМетаданных) Тогда
Возврат "Подсистемы";
ИначеЕсли Метаданные.ОбщиеМодули.Содержит(ОбъектМетаданных) Тогда
Возврат "ОбщиеМодули";
ИначеЕсли Метаданные.ПараметрыСеанса.Содержит(ОбъектМетаданных) Тогда
Возврат "ПараметрыСеанса";
ИначеЕсли Метаданные.Роли.Содержит(ОбъектМетаданных) Тогда
Возврат "Роли";
ИначеЕсли Метаданные.ОбщиеРеквизиты.Содержит(ОбъектМетаданных) Тогда
Возврат "ОбщиеРеквизиты";
ИначеЕсли Метаданные.КритерииОтбора.Содержит(ОбъектМетаданных) Тогда
Возврат "КритерииОтбора";
ИначеЕсли Метаданные.ПодпискиНаСобытия.Содержит(ОбъектМетаданных) Тогда
Возврат "ПодпискиНаСобытия";
ИначеЕсли Метаданные.ФункциональныеОпции.Содержит(ОбъектМетаданных) Тогда
Возврат "ФункциональныеОпции";
ИначеЕсли Метаданные.ПараметрыФункциональныхОпций.Содержит(ОбъектМетаданных) Тогда
Возврат "ПараметрыФункциональныхОпций";
ИначеЕсли Метаданные.ХранилищаНастроек.Содержит(ОбъектМетаданных) Тогда
Возврат "ХранилищаНастроек";
ИначеЕсли Метаданные.ОбщиеФормы.Содержит(ОбъектМетаданных) Тогда
Возврат "ОбщиеФормы";
ИначеЕсли Метаданные.ОбщиеКоманды.Содержит(ОбъектМетаданных) Тогда
Возврат "ОбщиеКоманды";
ИначеЕсли Метаданные.ГруппыКоманд.Содержит(ОбъектМетаданных) Тогда
Возврат "ГруппыКоманд";
ИначеЕсли Метаданные.ОбщиеМакеты.Содержит(ОбъектМетаданных) Тогда
Возврат "ОбщиеМакеты";
ИначеЕсли Метаданные.ОбщиеКартинки.Содержит(ОбъектМетаданных) Тогда
Возврат "ОбщиеКартинки";
ИначеЕсли Метаданные.ПакетыXDTO.Содержит(ОбъектМетаданных) Тогда
Возврат "ПакетыXDTO";
ИначеЕсли Метаданные.WebСервисы.Содержит(ОбъектМетаданных) Тогда
Возврат "WebСервисы";
ИначеЕсли Метаданные.WSСсылки.Содержит(ОбъектМетаданных) Тогда
Возврат "WSСсылки";
ИначеЕсли Метаданные.Стили.Содержит(ОбъектМетаданных) Тогда
Возврат "Стили";
ИначеЕсли Метаданные.Языки.Содержит(ОбъектМетаданных) Тогда
Возврат "Языки";
ИначеЕсли Метаданные.ВнешниеИсточникиДанных.Содержит(ОбъектМетаданных) Тогда
Возврат "ВнешниеИсточникиДанных";
Иначе
Возврат "";
КонецЕсли;
КонецФункции
// Возвращает менеджер объекта по полному имени объекта метаданных.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
//
// Параметры:
// ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Справочник.Организации".
//
// Возвращаемое значение:
// СправочникМенеджер, ДокументМенеджер, ОбработкаМенеджер, РегистрСведенийМенеджер - менеджер объекта.
//
// Пример:
// МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени("Справочник.Организации");
// ПустаяСсылка = МенеджерСправочника.ПустаяСсылка();
//
Функция МенеджерОбъектаПоПолномуИмени(ПолноеИмя) Экспорт
Перем КлассОМ, ИмяОМ, Менеджер;
ЧастиИмени = СтрРазделить(ПолноеИмя, ".");
Если ЧастиИмени.Количество() >= 2 Тогда
КлассОМ = ЧастиИмени[0];
ИмяОМ = ЧастиИмени[1];
Иначе
Менеджер = Неопределено;
КонецЕсли;
Если ВРег(КлассОМ) = "ПЛАНОБМЕНА" Тогда
Менеджер = ПланыОбмена;
ИначеЕсли ВРег(КлассОМ) = "СПРАВОЧНИК" Тогда
Менеджер = Справочники;
ИначеЕсли ВРег(КлассОМ) = "ДОКУМЕНТ" Тогда
Менеджер = Документы;
ИначеЕсли ВРег(КлассОМ) = "ЖУРНАЛДОКУМЕНТОВ" Тогда
Менеджер = ЖурналыДокументов;
ИначеЕсли ВРег(КлассОМ) = "ПЕРЕЧИСЛЕНИЕ" Тогда
Менеджер = Перечисления;
ИначеЕсли ВРег(КлассОМ) = "ОТЧЕТ" Тогда
Менеджер = Отчеты;
ИначеЕсли ВРег(КлассОМ) = "ОБРАБОТКА" Тогда
Менеджер = Обработки;
ИначеЕсли ВРег(КлассОМ) = "ПЛАНВИДОВХАРАКТЕРИСТИК" Тогда
Менеджер = ПланыВидовХарактеристик;
ИначеЕсли ВРег(КлассОМ) = "ПЛАНСЧЕТОВ" Тогда
Менеджер = ПланыСчетов;
ИначеЕсли ВРег(КлассОМ) = "ПЛАНВИДОВРАСЧЕТА" Тогда
Менеджер = ПланыВидовРасчета;
ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРСВЕДЕНИЙ" Тогда
Менеджер = РегистрыСведений;
ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРНАКОПЛЕНИЯ" Тогда
Менеджер = РегистрыНакопления;
ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРБУХГАЛТЕРИИ" Тогда
Менеджер = РегистрыБухгалтерии;
ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРРАСЧЕТА" Тогда
Если ЧастиИмени.Количество() = 2 Тогда
Менеджер = РегистрыРасчета;
ИначеЕсли ЧастиИмени.Количество() = 4 Тогда
КлассПодчиненногоОМ = ЧастиИмени[2];
ИмяПодчиненногоОМ = ЧастиИмени[3];
Если ВРег(КлассПодчиненногоОМ) = "ПЕРЕРАСЧЕТ" Тогда
Менеджер = РегистрыРасчета[ИмяОМ].Перерасчеты;
ИмяОм = ИмяПодчиненногоОМ;
Иначе
Менеджер = Неопределено;
КонецЕсли;
Иначе
Менеджер = Неопределено;
КонецЕсли;
ИначеЕсли ВРег(КлассОМ) = "БИЗНЕСПРОЦЕСС" Тогда
Менеджер = БизнесПроцессы;
ИначеЕсли ВРег(КлассОМ) = "ЗАДАЧА" Тогда
Менеджер = Задачи;
ИначеЕсли ВРег(КлассОМ) = "КОНСТАНТА" Тогда
Менеджер = Константы;
ИначеЕсли ВРег(КлассОМ) = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Тогда
Менеджер = Последовательности;
Иначе
Менеджер = Неопределено;
КонецЕсли;
Если Менеджер = Неопределено Тогда
ПроверитьОбъектМетаданныхСуществует(ПолноеИмя);
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Объект метаданных ""%1"" не имеет менеджера объекта.'"), ПолноеИмя);
КонецЕсли;
Попытка
Возврат Менеджер[ИмяОМ];
Исключение
ПроверитьОбъектМетаданныхСуществует(ПолноеИмя);
ВызватьИсключение;
КонецПопытки;
КонецФункции
// Возвращает менеджер объекта по ссылке на объект.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
// См. также ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, менеджер которого требуется получить.
//
// Возвращаемое значение:
// СправочникМенеджер, ДокументМенеджер, ОбработкаМенеджер, РегистрСведенийМенеджер - менеджер объекта.
//
// Пример:
// МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОрганизацию);
// ПустаяСсылка = МенеджерСправочника.ПустаяСсылка();
//
Функция МенеджерОбъектаПоСсылке(Ссылка) Экспорт
ИмяОбъекта = Ссылка.Метаданные().Имя;
ТипСсылки = ТипЗнч(Ссылка);
Если Справочники.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат Справочники[ИмяОбъекта];
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат Документы[ИмяОбъекта];
ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат БизнесПроцессы[ИмяОбъекта];
ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат ПланыВидовХарактеристик[ИмяОбъекта];
ИначеЕсли ПланыСчетов.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат ПланыСчетов[ИмяОбъекта];
ИначеЕсли ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат ПланыВидовРасчета[ИмяОбъекта];
ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат Задачи[ИмяОбъекта];
ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат ПланыОбмена[ИмяОбъекта];
ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда
Возврат Перечисления[ИмяОбъекта];
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
// Проверка того, что переданный тип является ссылочным типом данных.
// Для типа Неопределено возвращается Ложь.
//
// Параметры:
// ПроверяемыйТип - Тип - для проверки на ссылочный тип данных.
//
// Возвращаемое значение:
// Булево - Истина, если это ссылка.
//
Функция ЭтоСсылка(ПроверяемыйТип) Экспорт
Возврат ПроверяемыйТип <> Тип("Неопределено") И ОписаниеТипаВсеСсылки().СодержитТип(ПроверяемыйТип);
КонецФункции
// Проверяет физическое наличие записи в информационной базе данных о переданном значении ссылки.
//
// Параметры:
// ПроверяемаяСсылка - ЛюбаяСсылка - значение любой ссылки информационной базы данных.
//
// Возвращаемое значение:
// Булево - Истина, если существует.
//
Функция СсылкаСуществует(ПроверяемаяСсылка) Экспорт
ТекстЗапроса =
"ВЫБРАТЬ ПЕРВЫЕ 1
| 1 КАК Поле1
|ИЗ
| &ИмяТаблицы КАК Таблица
|ГДЕ
| Таблица.Ссылка = &Ссылка";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИмяТаблицыПоСсылке(ПроверяемаяСсылка));
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("Ссылка", ПроверяемаяСсылка);
УстановитьПривилегированныйРежим(Истина);
Возврат НЕ Запрос.Выполнить().Пустой();
КонецФункции
// Возвращает имя вида объектов метаданных по ссылке на объект.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
// См. так же ВидОбъектаПоТипу.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, вид которого требуется получить.
//
// Возвращаемое значение:
// Строка - имя вида объектов метаданных. Например: "Справочник", "Документ".
//
Функция ВидОбъектаПоСсылке(Ссылка) Экспорт
Возврат ВидОбъектаПоТипу(ТипЗнч(Ссылка));
КонецФункции
// Возвращает имя вида объектов метаданных по типу объекта.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
// См. так же ВидОбъектаПоСсылке.
//
// Параметры:
// ТипОбъекта - Тип - тип прикладного объекта, определенный в конфигурации.
//
// Возвращаемое значение:
// Строка - имя вида объектов метаданных. Например: "Справочник", "Документ".
//
Функция ВидОбъектаПоТипу(ТипОбъекта) Экспорт
Если Справочники.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "Справочник";
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "Документ";
ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "БизнесПроцесс";
ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "ПланВидовХарактеристик";
ИначеЕсли ПланыСчетов.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "ПланСчетов";
ИначеЕсли ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "ПланВидовРасчета";
ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "Задача";
ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "ПланОбмена";
ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда
Возврат "Перечисление";
Иначе
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Неверный тип значения параметра (%1)'"), Строка(ТипОбъекта));
КонецЕсли;
КонецФункции
// Возвращает полное имя объекта метаданных по переданному значению ссылки.
//
// Параметры:
// Ссылка - ЛюбаяСсылка - объект, для которого необходимо получить имя таблицы ИБ.
//
// Возвращаемое значение:
// Строка - полное имя объекта метаданных для указанного объекта. Например: "Справочник.Номенклатура".
//
Функция ИмяТаблицыПоСсылке(Ссылка) Экспорт
Возврат Ссылка.Метаданные().ПолноеИмя();
КонецФункции
// Проверяет, что переданное значение имеет ссылочный тип данных.
//
// Параметры:
// Значение - Произвольный - проверяемое значение.
//
// Возвращаемое значение:
// Булево - Истина, если тип значения ссылочный.
//
Функция ЗначениеСсылочногоТипа(Значение) Экспорт
Возврат ЭтоСсылка(ТипЗнч(Значение));
КонецФункции
// Проверяет, является ли элемент справочника или плана видов характеристик группой элементов.
//
// Параметры:
// Объект - СправочникСсылка
// - ПланВидовХарактеристикСсылка
// - СправочникОбъект
// - ПланВидовХарактеристикОбъект - проверяемый объект.
//
// Возвращаемое значение:
// Булево
//
Функция ОбъектЯвляетсяГруппой(Объект) Экспорт
Если ЗначениеСсылочногоТипа(Объект) Тогда
Ссылка = Объект;
Иначе
Ссылка = Объект.Ссылка;
КонецЕсли;
МетаданныеОбъекта = Ссылка.Метаданные();
Если ЭтоСправочник(МетаданныеОбъекта) Тогда
Если Не МетаданныеОбъекта.Иерархический
Или МетаданныеОбъекта.ВидИерархии <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда
Возврат Ложь;
КонецЕсли;
ИначеЕсли Не ЭтоПланВидовХарактеристик(МетаданныеОбъекта) Или Не МетаданныеОбъекта.Иерархический Тогда
Возврат Ложь;
КонецЕсли;
Если Ссылка <> Объект Тогда
Возврат Объект.ЭтоГруппа;
КонецЕсли;
Возврат ЗначениеРеквизитаОбъекта(Ссылка, "ЭтоГруппа") = Истина;
КонецФункции
// Возвращает ссылку, соответствующую объекту метаданных, для использования в базе данных.
// См. также ОбщегоНазначения.ИдентификаторыОбъектовМетаданных.
//
// Ссылки возвращаются для следующих объектов метаданных:
// - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - ПланыОбмена;
// - Константы;
// - Справочники;
// - Документы;
// - ЖурналыДокументов;
// - Отчеты;
// - Обработки;
// - ПланыВидовХарактеристик;
// - ПланыСчетов;
// - ПланыВидовРасчета;
// - РегистрыСведений;
// - РегистрыНакопления;
// - РегистрыБухгалтерии;
// - РегистрыРасчета;
// - БизнесПроцессы;
// - Задачи.
//
// Параметры:
// ОписаниеОбъектаМетаданных - ОбъектМетаданных - объект метаданных конфигурации;
// - Тип - тип, который можно использовать в функции Метаданные.НайтиПоТипу;
// - Строка - полное имя объекта метаданных, которое можно
// использовать в функции Метаданные.НайтиПоПолномуИмени.
//
// ВызыватьИсключение - Булево - если Ложь, то вместо вызова исключения возвращается Null для несуществующего
// или неподдерживаемого объекта метаданных.
//
// Возвращаемое значение:
// СправочникСсылка.ИдентификаторыОбъектовМетаданных
// СправочникСсылка.ИдентификаторыОбъектовРасширений
// Null
//
// Пример:
// Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ТипЗнч(Ссылка));
// Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных);
// Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.Организации");
//
Функция ИдентификаторОбъектаМетаданных(ОписаниеОбъектаМетаданных, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторОбъектаМетаданных(
ОписаниеОбъектаМетаданных, ВызыватьИсключение);
КонецФункции
// Возвращает ссылки, соответствующие объектам метаданных, для использования в базе данных.
// См. также ОбщегоНазначения.ИдентификаторОбъектаМетаданных.
//
// Ссылки возвращаются для следующих объектов метаданных:
// - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных);
// - ПланыОбмена.
// - Константы.
// - Справочники.
// - Документы.
// - ЖурналыДокументов.
// - Отчеты.
// - Обработки.
// - ПланыВидовХарактеристик.
// - ПланыСчетов.
// - ПланыВидовРасчета.
// - РегистрыСведений.
// - РегистрыНакопления.
// - РегистрыБухгалтерии.
// - РегистрыРасчета.
// - БизнесПроцессы.
// - Задачи.
//
// Параметры:
// ОписаниеОбъектовМетаданных - Массив из ОбъектМетаданных - объекты метаданных конфигурации;
// - Массив из Строка - полные имена объектов метаданных, которые можно использовать
// в функции Метаданные.НайтиПоПолномуИмени;
// - Массив из Тип - типы, которые можно использовать в функции Метаданные.НайтиПоТипу.
// ВызыватьИсключение - Булево - если Ложь, то несуществующие и неподдерживаемые объекты метаданных
// будут пропущены в возвращаемом значении.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - Строка - полное имя указанного объекта метаданных.
// * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - найденный идентификатор.
//
// Пример:
// ПолныеИмена = Новый Массив;
// ПолныеИмена.Добавить(Метаданные.Справочники.Валюты.ПолноеИмя());
// ПолныеИмена.Добавить(Метаданные.РегистрыСведений.КурсыВалют.ПолноеИмя());
// Идентификаторы = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена);
//
Функция ИдентификаторыОбъектовМетаданных(ОписаниеОбъектовМетаданных, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторыОбъектовМетаданных(
ОписаниеОбъектовМетаданных, ВызыватьИсключение);
КонецФункции
// Возвращает объект метаданных по переданному идентификатору.
//
// Параметры:
// Идентификатор - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор
// объекта метаданных конфигурации или расширения конфигурации.
//
// ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных
// не существует или недоступен, возвращает соответственно
// Null или Неопределено вместо вызова исключения.
//
// Возвращаемое значение:
// ОбъектМетаданных - объект метаданных, соответствующий идентификатору.
//
// Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что
// для указанного идентификатора объект метаданных не существует (идентификатор устарел).
//
// Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает,
// что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен.
// Для расширений конфигурации это значит, что расширение установлено, но не подключено,
// либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка.
// Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект
// метаданных имеется, а в текущем (старом) сеансе нет.
//
Функция ОбъектМетаданныхПоИдентификатору(Идентификатор, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектМетаданныхПоИдентификатору(
Идентификатор, ВызыватьИсключение);
КонецФункции
// Возвращает объекты метаданных по переданным идентификаторам.
//
// Параметры:
// Идентификаторы - Массив - со значениями:
// * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификаторы
// объектов метаданных конфигурации или расширений конфигурации.
//
// ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных
// не существует или недоступен, возвращает соответственно
// Null или Неопределено вместо вызова исключения.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// - СправочникСсылка.ИдентификаторыОбъектовРасширений - переданный идентификатор.
// * Значение - ОбъектМетаданных - объект метаданных, соответствующий идентификатору.
// - Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что
// для указанного идентификатора объект метаданных не существует (идентификатор устарел).
// - Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает,
// что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен.
// Для расширений конфигурации это значит, что расширение установлено, но не подключено,
// либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка.
// Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект
// метаданных имеется, а в текущем (старом) сеансе нет.
//
Функция ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, ВызыватьИсключение = Истина) Экспорт
Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектыМетаданныхПоИдентификаторам(
Идентификаторы, ВызыватьИсключение);
КонецФункции
// Возвращает ОбъектМетаданных, быстро найденный по полному имени.
// Более производительный аналог метода платформы Метаданные.НайтиПоПолномуИмени
// для корневых объектов метаданных.
//
// Параметры:
// ПолноеИмя - Строка - полное имя объекта метаданных, например, Справочник.Организации
//
// Возвращаемое значение:
// ОбъектМетаданных - когда найден
// Неопределено - когда не найден
//
Функция ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) Экспорт
ПозицияТочки = СтрНайти(ПолноеИмя, ".");
ИмяБазовогоТипа = Лев(ПолноеИмя, ПозицияТочки - 1);
ИменаКоллекций = СтандартныеПодсистемыПовтИсп.ИменаКоллекцийПоИменамБазовыхТипов();
Коллекция = ИменаКоллекций.Получить(ВРег(ИмяБазовогоТипа));
Если Коллекция <> Неопределено Тогда
Если Коллекция <> "Подсистемы" Тогда
ИмяОбъекта = Сред(ПолноеИмя, ПозицияТочки + 1);
ОбъектМетаданных = Метаданные[Коллекция].Найти(ИмяОбъекта);
Иначе
ИменаПодсистем = СтрРазделить(ВРег(ПолноеИмя), ".");
Количество = ИменаПодсистем.Количество();
Подсистема = Метаданные;
ОбъектМетаданных = Неопределено;
Индекс = 0;
Пока Истина Цикл
Индекс = Индекс + 1;
Если Индекс >= Количество Тогда
Прервать;
КонецЕсли;
ИмяПодсистемы = ИменаПодсистем[Индекс];
Подсистема = Подсистема.Подсистемы.Найти(ИмяПодсистемы);
Если Подсистема = Неопределено Тогда
Прервать;
КонецЕсли;
Индекс = Индекс + 1;
Если Индекс = Количество Тогда
ОбъектМетаданных = Подсистема;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если ОбъектМетаданных = Неопределено Тогда
ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмя);
КонецЕсли;
Возврат ОбъектМетаданных;
КонецФункции
// Определяет доступность объекта метаданных по функциональным опциям.
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных
// - Строка - проверяемый объект метаданных.
//
// Возвращаемое значение:
// Булево - Истина, если объект доступен.
//
Функция ОбъектМетаданныхДоступенПоФункциональнымОпциям(Знач ОбъектМетаданных) Экспорт
Если ОбъектМетаданных = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Если ТипЗнч(ОбъектМетаданных) <> Тип("Строка") Тогда
ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
Иначе
ПолноеИмя = ОбъектМетаданных;
КонецЕсли;
Возврат СтандартныеПодсистемыПовтИсп.ДоступностьОбъектовПоОпциям().Получить(ПолноеИмя) <> Ложь;
КонецФункции
// Добавляет описание переименования объекта метаданных при переходе на указанную версию конфигурации.
// Добавление выполняется в структуру Итог, которая передается в
// процедуру ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.
//
// Параметры:
// Итог - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.Итог
// ВерсияИБ - Строка - версия конечной конфигурации, при переходе на которую нужно
// выполнить переименование, например, "2.1.2.14".
// СтароеПолноеИмя - Строка - старое полное имя объекта метаданных, которое нужно переименовать,
// например "Подсистема._ДемоПодсистемы".
// НовоеПолноеИмя - Строка - новое полное имя объекта метаданных, на которое нужно переименовать,
// например "Подсистема._ДемоСервисныеПодсистемы".
// ИдентификаторБиблиотеки - Строка - внутренний идентификатор библиотеки, к которой относится ВерсияИБ.
// Для основной конфигурации не требуется.
// Например, "СтандартныеПодсистемы" - как указано
// в ОбновлениеИнформационнойБазыБСП.ПриДобавленииПодсистемы.
// Пример:
// ОбщегоНазначения.ДобавитьПереименование(Итог, "2.1.2.14",
// "Подсистема._ДемоПодсистемы",
// "Подсистема._ДемоСервисныеПодсистемы");
//
Процедура ДобавитьПереименование(Итог, ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки = "") Экспорт
Справочники.ИдентификаторыОбъектовМетаданных.ДобавитьПереименование(Итог,
ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки);
КонецПроцедуры
// Возвращает строковое представление типа, например, "СправочникСсылка.ИмяОбъекта", "ДокументСсылка.ИмяОбъекта".
// Для остальных типов приводит тип к строке, например "Число".
//
// Параметры:
// Тип - Тип - для которого надо получить представление.
//
// Возвращаемое значение:
// Строка
//
Функция СтроковоеПредставлениеТипа(Тип) Экспорт
Представление = "";
Если ЭтоСсылка(Тип) Тогда
ПолноеИмя = Метаданные.НайтиПоТипу(Тип).ПолноеИмя();
ИмяОбъекта = СтрРазделить(ПолноеИмя, ".")[1];
Если Справочники.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "СправочникСсылка";
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ДокументСсылка";
ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "БизнесПроцессСсылка";
ИначеЕсли БизнесПроцессы.ТипВсеСсылкиТочекМаршрутаБизнесПроцессов().СодержитТип(Тип) Тогда
Представление = "ТочкаМаршрутаБизнесПроцессаСсылка";
ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ПланВидовХарактеристикСсылка";
ИначеЕсли ПланыСчетов.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ПланСчетовСсылка";
ИначеЕсли ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ПланВидовРасчетаСсылка";
ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ЗадачаСсылка";
ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ПланОбменаСсылка";
ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(Тип) Тогда
Представление = "ПеречислениеСсылка";
КонецЕсли;
Результат = ?(Представление = "", Представление, Представление + "." + ИмяОбъекта);
ИначеЕсли Тип = Тип("Неопределено") Тогда
Результат = "Неопределено";
ИначеЕсли Тип = Тип("Строка") Тогда
Результат = "Строка";
ИначеЕсли Тип = Тип("Число") Тогда
Результат = "Число";
ИначеЕсли Тип = Тип("Булево") Тогда
Результат = "Булево";
ИначеЕсли Тип = Тип("Дата") Тогда
Результат = "Дата";
Иначе
Результат = Строка(Тип);
КонецЕсли;
Возврат Результат;
КонецФункции
// Возвращает таблицу значений с описанием требуемых свойств всех реквизитов объекта метаданных.
// Получает значения свойств стандартных реквизитов и пользовательских реквизитов (созданных в режиме конфигуратора).
//
// Параметры:
// ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо получить значение свойств реквизитов.
// Например: Метаданные.Документ.РеализацияТоваровИУслуг
// Свойства - Строка - свойства реквизитов, перечисленные через запятую, значение которых необходимо получить.
// Например: "Имя, Тип, Синоним, Подсказка".
//
// Возвращаемое значение:
// ТаблицаЗначений - описание требуемых свойств всех реквизитов объекта метаданных.
//
Функция ОписаниеСвойствОбъекта(ОбъектМетаданных, Свойства) Экспорт
МассивСвойств = СтрРазделить(Свойства, ",");
// Возвращаемое значение функции.
ТаблицаОписанияСвойствОбъекта = Новый ТаблицаЗначений;
// Добавляем в таблицу поля согласно именам переданных свойств.
Для Каждого ИмяСвойства Из МассивСвойств Цикл
ТаблицаОписанияСвойствОбъекта.Колонки.Добавить(СокрЛП(ИмяСвойства));
КонецЦикла;
// Заполняем строку таблицы свойствами реквизитов объекта метаданных.
Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл
ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит);
КонецЦикла;
// Заполняем строку таблицы свойствами стандартных реквизитов объекта метаданных.
Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит);
КонецЦикла;
Возврат ТаблицаОписанияСвойствОбъекта;
КонецФункции
// Возвращает признак того, что реквизит входит в подмножество стандартных реквизитов.
//
// Параметры:
// СтандартныеРеквизиты - ОписанияСтандартныхРеквизитов - тип и значение, описывающие коллекцию настроек различных
// стандартных реквизитов;
// ИмяРеквизита - Строка - реквизит, который необходимо проверить на принадлежность множеству стандартных
// реквизитов.
//
// Возвращаемое значение:
// Булево - Истина, если реквизит входит в подмножество стандартных реквизитов.
//
Функция ЭтоСтандартныйРеквизит(СтандартныеРеквизиты, ИмяРеквизита) Экспорт
Для Каждого Реквизит Из СтандартныеРеквизиты Цикл
Если Реквизит.Имя = ИмяРеквизита Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Позволяет определить, есть ли среди реквизитов объекта реквизит с переданным именем.
//
// Параметры:
// ИмяРеквизита - Строка - имя реквизита;
// МетаданныеОбъекта - ОбъектМетаданных - объект, в котором требуется проверить наличие реквизита.
//
// Возвращаемое значение:
// Булево - Истина, если есть.
//
Функция ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта) Экспорт
Реквизиты = МетаданныеОбъекта.Реквизиты; // КоллекцияОбъектовМетаданных
Возврат НЕ (Реквизиты.Найти(ИмяРеквизита) = Неопределено);
КонецФункции
// Проверить, что описание типа состоит из единственного типа значения и
// совпадает с нужным типом.
//
// Параметры:
// ОписаниеТипа - ОписаниеТипов - проверяемая коллекция типов;
// ТипЗначения - Тип - проверяемый тип.
//
// Возвращаемое значение:
// Булево - Истина, если совпадает.
//
// Пример:
// Если ОбщегоНазначения.ОписаниеТипаСостоитИзТипа(ТипЗначенияСвойства, Тип("Булево") Тогда
// // Выводим поле в виде флажка.
// КонецЕсли;
//
Функция ОписаниеТипаСостоитИзТипа(ОписаниеТипа, ТипЗначения) Экспорт
Если ОписаниеТипа.Типы().Количество() = 1
И ОписаниеТипа.Типы().Получить(0) = ТипЗначения Тогда
Возврат Истина;
КонецЕсли;
Возврат Ложь;
КонецФункции
// Создает объект ОписаниеТипов, содержащий тип Строка.
//
// Параметры:
// ДлинаСтроки - Число - длина строки.
//
// Возвращаемое значение:
// ОписаниеТипов - описание типа Строка.
//
Функция ОписаниеТипаСтрока(ДлинаСтроки) Экспорт
Возврат Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(ДлинаСтроки));
КонецФункции
// Создает объект ОписаниеТипов, содержащий тип Число.
//
// Параметры:
// Разрядность - Число - общее количество разрядов числа (количество разрядов
// целой части плюс количество разрядов дробной части).
// РазрядностьДробнойЧасти - Число - число разрядов дробной части.
// ЗнакЧисла - ДопустимыйЗнак - допустимый знак числа.
//
// Возвращаемое значение:
// ОписаниеТипов - описание типа Число.
//
Функция ОписаниеТипаЧисло(Разрядность, РазрядностьДробнойЧасти = 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, ПрочитатьВСоответствие, ИменаСвойствСоЗначениямиДата);
КонецФункции
#КонецОбласти
#Область ВебСервисы
// Возвращает структуру параметров для функции Создать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 = 'Не задан URL сервиса.'"));
КонецЕсли;
ПараметрыПолучения = Новый Массив;
ПараметрыПолучения.Добавить(ПараметрыПодключения);
ПараметрыПолучения.Добавить(ИмяИнтерфейса);
Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ДанныеКэшаВерсий(
РегистрыСведений.КэшПрограммныхИнтерфейсов.ИдентификаторЗаписиКэшаВерсий(ПараметрыПодключения.URL, ИмяИнтерфейса),
Перечисления.ТипыДанныхКэшаПрограммныхИнтерфейсов.ВерсииИнтерфейса,
ПараметрыПолучения,
Истина);
КонецФункции
// Возвращает номера версий программных интерфейсов удаленной системы, подключенной через внешнее соединение.
// Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах
// с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии,
// то только в этом случае допустимо вызывать у него новую функцию.
//
// Параметры:
// ВнешнееСоединение - COMОбъект - внешнее соединение, которое используется для работы с удаленной системой.
// ИмяИнтерфейса - Строка - имя запрашиваемого программного интерфейса, например "СервисПередачиФайлов".
//
// Возвращаемое значение:
// ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса.
// Например "1.0.2.1".
//
// Пример:
// Версии = ОбщегоНазначения.ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, "СервисПередачиФайлов");
//
Функция ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, Знач ИмяИнтерфейса) Экспорт
Попытка
ВерсииИнтерфейсаXML = ВнешнееСоединение.СтандартныеПодсистемыСервер.ПоддерживаемыеВерсии(ИмяИнтерфейса);
Исключение
СтрокаСообщения = НСтр("ru = 'Корреспондент не поддерживает версионирование программных интерфейсов.
|Описание ошибки: %1'");
СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ЗаписьЖурналаРегистрации(НСтр("ru = 'Получение версий интерфейса'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка, , , СтрокаСообщения);
Возврат Новый ФиксированныйМассив(Новый Массив);
КонецПопытки;
Возврат Новый ФиксированныйМассив(ЗначениеИзСтрокиXML(ВерсииИнтерфейсаXML));
КонецФункции
// Удаляет записи кэша версий программных интерфейсов, содержащих в идентификаторе указанную подстроку.
// В качестве подстроки может использоваться, например, имя интерфейса, более не используемого в конфигурации.
//
// Параметры:
// ПодстрокаПоискаИдентификаторов - Строка - подстрока поиска идентификаторов.
// Не может содержать символов %, _ и [.
//
Процедура УдалитьЗаписиКэшаВерсий(Знач ПодстрокаПоискаИдентификаторов) Экспорт
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов");
Блокировка.Заблокировать();
ТекстЗапроса =
"ВЫБРАТЬ
| ТаблицаКэша.Идентификатор КАК Идентификатор,
| ТаблицаКэша.ТипДанных КАК ТипДанных
|ИЗ
| РегистрСведений.КэшПрограммныхИнтерфейсов КАК ТаблицаКэша
|ГДЕ
| ТаблицаКэша.Идентификатор ПОДОБНО ""%ПодстрокаПоиска%"" СПЕЦСИМВОЛ ""~""";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПодстрокаПоиска",
СформироватьСтрокуДляПоискаВЗапросе(ПодстрокаПоискаИдентификаторов));
Запрос = Новый Запрос(ТекстЗапроса);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Запись = РегистрыСведений.КэшПрограммныхИнтерфейсов.СоздатьМенеджерЗаписи();
Запись.Идентификатор = Выборка.Идентификатор;
Запись.ТипДанных = Выборка.ТипДанных;
Запись.Удалить();
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
#КонецОбласти
#Область БезопасноеХранилище
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с хранилищем паролей.
// Записывает конфиденциальные данные в безопасное хранилище.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владелец - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы,
// представляющий объект-владелец сохраняемого пароля или строка до 128 символов.
// Для объектов других типов в качестве владельца рекомендуется использовать ссылку на
// элемент метаданных этого типа в справочнике ИдентификаторыОбъектовМетаданных
// или ключ в виде строки с учетом имен подсистем.
// Например, для БСП:
// Владелец = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("РегистрСведений.АдресныеОбъекты");
// если нужно 1 хранилище на подсистему БСП:
// Владелец = "СтандартныеПодсистемы.УправлениеДоступом";
// если нужно более 1 хранилища на подсистему БСП:
// Владелец = "СтандартныеПодсистемы.УправлениеДоступом.<Уточнение>";
// Данные - Произвольный - данные помещаемые в безопасное хранилище. Неопределенно - удаляет все данные.
// Для удаления данных по ключу следует использовать процедуру УдалитьДанныеИзБезопасногоХранилища.
// - Структура - если параметр Ключ содержит Неопределено. Подробнее см. описание параметра Ключ
// Ключ - Строка - ключ сохраняемых настроек, по умолчанию "Пароль".
// Ключ должен соответствовать правилам имен идентификаторов:
// 1. Первым символом ключа должна быть буква или символ подчеркивания (_).
// 2. Каждый из последующих символов может быть буквой, цифрой или символом подчеркивания (_).
// Неопределено - для добавления набора данных структурой, где ключ структуры - это имя ключа данных,
// а значение - сохраняемые данные. Пример использования см. ниже.
//
// Пример:
//
// Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Если ТекущийПользовательМожетИзменятьПароль Тогда
// УстановитьПривилегированныйРежим(Истина);
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Логин, "Логин");
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Пароль);
// УстановитьПривилегированныйРежим(Ложь);
// КонецЕсли;
// КонецПроцедуры
//
// Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Если ТекущийПользовательМожетИзменятьПароль Тогда
// ЛогинИПароль = Новый Структура;
// ЛогинИПароль.Вставить("Логин", Логин);
// ЛогинИПароль.Вставить("Пароль", Пароль);
// УстановитьПривилегированныйРежим(Истина);
// ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, ЛогинИПароль, Неопределено);
// УстановитьПривилегированныйРежим(Ложь);
// КонецЕсли;
// КонецПроцедуры
//
Процедура ЗаписатьДанныеВБезопасноеХранилище(Владелец, Данные, Ключ = "Пароль") Экспорт
ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать ссылку; передано значение: %3 (тип %4).'"),
"Владелец", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Владелец, ТипЗнч(Владелец)));
Если ЗначениеЗаполнено(Ключ) Тогда
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Ключ) = Тип("Строка"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать строку; передано значение: %3 (тип %4).'"),
"Ключ", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Ключ, ТипЗнч(Ключ)));
Иначе
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Данные) = Тип("Структура"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|Если Ключ = Неопределено, то параметр должен содержать структуру; передано значение: %3 (тип %4).'"),
"Данные", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Данные, ТипЗнч(Данные)));
КонецЕсли;
ЭтоОбластьДанных = РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных();
Если ЭтоОбластьДанных Тогда
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи();
Иначе
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи();
КонецЕсли;
БезопасноеХранилищеДанных.Владелец = Владелец;
БезопасноеХранилищеДанных.Прочитать();
Если Данные <> Неопределено Тогда
Если БезопасноеХранилищеДанных.Выбран() Тогда
ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить();
Если ТипЗнч(ДанныеДляСохранения) <> Тип("Структура") Тогда
ДанныеДляСохранения = Новый Структура();
КонецЕсли;
Если ЗначениеЗаполнено(Ключ) Тогда
ДанныеДляСохранения.Вставить(Ключ, Данные);
Иначе
ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ДанныеДляСохранения, Данные, Истина);
КонецЕсли;
ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(6));
БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения;
БезопасноеХранилищеДанных.Записать();
Иначе
ДанныеДляСохранения = ?(ЗначениеЗаполнено(Ключ), Новый Структура(Ключ, Данные), Данные);
ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(6));
БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения;
БезопасноеХранилищеДанных.Владелец = Владелец;
БезопасноеХранилищеДанных.Записать();
КонецЕсли;
Иначе
БезопасноеХранилищеДанных.Удалить();
КонецЕсли;
КонецПроцедуры
// Возвращает данные из безопасного хранилища.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владельцы - Массив из ПланОбменаСсылка
// - Массив из СправочникСсылка
// - Массив из Строка - ссылки на объекты информационной базы,
// представляющих объекты-владельцы или уникальные строки(до 128 символов) владельцев данных.
// Ключи - Строка - содержит имя ключа данных или список имен ключей, указанных через запятую.
// - Неопределено - будут возвращены все сохраненные данные переданных владельцев.
// ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме.
//
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы
// или строка до 128 символов идентифицирующая владельца данных.
// * Значение - Произвольный - если в параметре Ключи указан один ключ,
// то возвращается его значение произвольного типа.
// - Структура - если в параметре Ключи указано несколько ключей или Неопределено,
// где ключ структуры - это имя ключа сохраненных данных,
// а значение - данные произвольного типа. Когда для ключа отсутствуют данные,
// то значение содержит Неопределено.
// - Неопределено - если данные по ключу отсутствуют.
//
// Пример:
// Процедура РассылкаПриглашений(Пользователи)
//
// УстановитьПривилегированныйРежим(Истина);
// ДанныеАвторизации = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(Пользователи, "Логин, Пароль");
// УстановитьПривилегированныйРежим(Ложь);
//
// Для каждого Пользователь Из Пользователи Цикл
// ОтправитьПриглашение(Пользователь, ДанныеАвторизации[Пользователь]);
// КонецЦикла;
//
// КонецПроцедуры
//
Функция ПрочитатьДанныеВладельцевИзБезопасногоХранилища(Владельцы, Ключи = "Пароль", ОбщиеДанные = Неопределено) Экспорт
ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Владельцы) = Тип("Массив"),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать массив; передано значение: %3 (тип %4).'"),
"Владельцы", "ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища", Владельцы, ТипЗнч(Владельцы)));
Результат = ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные);
Возврат Результат;
КонецФункции
// Возвращает данные из безопасного хранилища.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владелец - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы,
// представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов).
// Ключи - Строка - содержит список имен сохраненных данных, указанных через запятую.
// - Неопределено - будут возвращены все сохраненные данные владельца.
// ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме.
//
// Возвращаемое значение:
// Произвольный, Структура, Неопределено - данные из безопасного хранилища. Если указан один ключ,
// то возвращается его значение, иначе структура.
// Если данные отсутствуют - Неопределенно.
//
// Пример:
// Если ТекущийПользовательМожетИзменятьПароль Тогда
// УстановитьПривилегированныйРежим(Истина);
// Логин = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, "Логин");
// Пароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка);
// УстановитьПривилегированныйРежим(Ложь);
// Иначе
// Элементы.ГруппаЛогинИПароль.Видимость = Ложь;
// КонецЕсли;
//
// УстановитьПривилегированныйРежим(Истина);
// ЛогинИПароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, Неопределено);
//
Функция ПрочитатьДанныеИзБезопасногоХранилища(Владелец, Ключи = "Пароль", ОбщиеДанные = Неопределено) Экспорт
Владельцы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец);
ДанныеВладельца = ПрочитатьДанныеВладельцевИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные);
Результат = ДанныеВладельца[Владелец];
Возврат Результат;
КонецФункции
// Удаляет конфиденциальные данные в безопасное хранилище.
// Вызывающий код должен самостоятельно устанавливать привилегированный режим.
//
// Безопасное хранилище недоступно для чтения пользователям (кроме администраторов),
// а доступно только коду, который делает обращения только к своей части данных и
// в том контексте, который предполагает чтение или запись конфиденциальных данных.
//
// Параметры:
// Владелец - ПланОбменаСсылка
// - СправочникСсылка
// - Строка - ссылка на объект информационной базы,
// представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов).
// - Массив - ссылки на объекты информационной базы для удаления данным по нескольким владельцам.
// Ключи - Строка - содержит список имен удаляемых данных, указанных через запятую.
// Неопределено - удаляет все данные.
//
// Пример:
// Процедура ПередУдалением(Отказ)
//
// // Проверка значения свойства ОбменДанными.Загрузка отсутствует, так как удалять данные
// // из безопасного хранилища нужно даже при удалении объекта при обмене данными.
//
// УстановитьПривилегированныйРежим(Истина);
// ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища(Ссылка);
// УстановитьПривилегированныйРежим(Ложь);
//
// КонецПроцедуры
//
Процедура УдалитьДанныеИзБезопасногоХранилища(Владелец, Ключи = Неопределено) Экспорт
ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец),
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|параметр должен содержать ссылку; передано значение: %3 (тип %4).'"),
"Владелец", "ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища", Владелец, ТипЗнч(Владелец)));
Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи();
Иначе
БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи();
КонецЕсли;
Владельцы = ?(ТипЗнч(Владелец) = Тип("Массив"), Владелец, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец));
Для Каждого ВладелецДанных Из Владельцы Цикл
БезопасноеХранилищеДанных.Владелец = ВладелецДанных;
БезопасноеХранилищеДанных.Прочитать();
Если ТипЗнч(БезопасноеХранилищеДанных.Данные) = Тип("ХранилищеЗначения") Тогда
ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить();
Если Ключи <> Неопределено И ТипЗнч(ДанныеДляСохранения) = Тип("Структура") Тогда
СписокКлючей = СтрРазделить(Ключи, ",", Ложь);
Если БезопасноеХранилищеДанных.Выбран() И СписокКлючей.Количество() > 0 Тогда
Для каждого КлючДляУдаления Из СписокКлючей Цикл
Если ДанныеДляСохранения.Свойство(КлючДляУдаления) Тогда
ДанныеДляСохранения.Удалить(КлючДляУдаления);
КонецЕсли;
КонецЦикла;
ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(6));
БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения;
БезопасноеХранилищеДанных.Записать();
Возврат;
КонецЕсли;
КонецЕсли;
КонецЕсли;
БезопасноеХранилищеДанных.Удалить();
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#Область БуферОбмена
////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с внутренним буфером обмена.
// Помещает выделенные строки табличной части во внутренний буфер обмена
// откуда их можно получить с помощью СтрокиИзБуфераОбмена.
//
// Параметры:
// ТабличнаяЧасть - ДанныеФормыКоллекция - табличная часть, строки которой
// необходимо поместить во внутренний буфер обмена.
// ВыделенныеСтроки - Массив - массив идентификаторов выделенных строк.
// Источник - Строка - произвольный строковый идентификатор, например, имя объекта,
// строки табличной части которого помещаются во внутренний буфер обмена.
//
Процедура СкопироватьСтрокиВБуферОбмена(ТабличнаяЧасть, ВыделенныеСтроки, Источник = Неопределено) Экспорт
Если ВыделенныеСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
ТаблицаЗначений = ТабличнаяЧасть.Выгрузить();
ТаблицаЗначений.Очистить();
УдаляемыеКолонки = Новый Массив;
УдаляемыеКолонки.Добавить("ИсходныйНомерСтроки");
УдаляемыеКолонки.Добавить("НомерСтроки");
Для Каждого ИмяКолонки Из УдаляемыеКолонки Цикл
Колонка = ТаблицаЗначений.Колонки.Найти(ИмяКолонки);
Если Колонка = Неопределено Тогда
Продолжить;
КонецЕсли;
ТаблицаЗначений.Колонки.Удалить(Колонка);
КонецЦикла;
Для Каждого ИдентификаторСтроки Из ВыделенныеСтроки Цикл
КопируемаяСтрока = ТабличнаяЧасть.НайтиПоИдентификатору(ИдентификаторСтроки);
ЗаполнитьЗначенияСвойств(ТаблицаЗначений.Добавить(), КопируемаяСтрока);
КонецЦикла;
СкопироватьВБуферОбмена(ТаблицаЗначений, Источник);
КонецПроцедуры
// Помещает произвольные данные во внутренний буфер обмена, откуда их можно получить с помощью СтрокиИзБуфераОбмена.
//
// Параметры:
// Данные - Произвольный - данные, которые необходимо поместить в внутренний буфер обмена.
// Источник - Строка - произвольный строковый идентификатор, например, имя объекта,
// строки табличной части которого помещаются во внутренний буфер обмена.
//
Процедура СкопироватьВБуферОбмена(Данные, Источник = Неопределено) Экспорт
ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена;
Если ЗначениеЗаполнено(ТекущийБуферОбмена.Данные) Тогда
Адрес = ТекущийБуферОбмена.Данные;
Иначе
Адрес = Новый УникальныйИдентификатор;
КонецЕсли;
ДанныеВХранилище = ПоместитьВоВременноеХранилище(Данные, Адрес);
СтруктураБуфераОбмена = Новый Структура;
СтруктураБуфераОбмена.Вставить("Источник", Источник);
СтруктураБуфераОбмена.Вставить("Данные", ДанныеВХранилище);
ПараметрыСеанса.БуферОбмена = Новый ФиксированнаяСтруктура(СтруктураБуфераОбмена);
КонецПроцедуры
// Получает строки табличной части, помещенные во внутренний буфер обмена с помощью СкопироватьСтрокиВБуферОбмена.
//
// Возвращаемое значение:
// Структура:
// * Данные - Произвольный - данные из внутреннего буфера обмена.
// Например, ТаблицаЗначений при вызове СкопироватьСтрокиВБуферОбмена.
// * Источник - Строка - объект, к которому относятся данные.
// Если при помещении во внутренний буфер не был указан, то Неопределено.
//
Функция СтрокиИзБуфераОбмена() Экспорт
Результат = Новый Структура;
Результат.Вставить("Источник", Неопределено);
Результат.Вставить("Данные", Неопределено);
Если ПустойБуферОбмена() Тогда
Возврат Результат;
КонецЕсли;
ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена
Результат.Источник = ТекущийБуферОбмена.Источник;
Результат.Данные = ПолучитьИзВременногоХранилища(ТекущийБуферОбмена.Данные);
Возврат Результат;
КонецФункции
// Проверяет наличие сохраненных данных во внутренний буфере обмена.
//
// Параметры:
// Источник - Строка - если передан, то проверяется наличие данных
// в внутреннем буфере обмена с этим ключом.
// По умолчанию - Неопределено.
// Возвращаемое значение:
// Булево - Истина, если пустой.
//
Функция ПустойБуферОбмена(Источник = Неопределено) Экспорт
ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена
ИсточникСовпадает = Истина;
Если Источник <> Неопределено Тогда
ИсточникСовпадает = (Источник = ТекущийБуферОбмена.Источник);
КонецЕсли;
Возврат (Не ИсточникСовпадает Или Не ЗначениеЗаполнено(ТекущийБуферОбмена.Данные));
КонецФункции
#КонецОбласти
#Область БезопасноеВыполнениеВнешнегоКода
////////////////////////////////////////////////////////////////////////////////
// Функции для поддержки работы конфигурации с профилем безопасности, в котором
// запрещено подключение внешних модулей без установки безопасного режима.
//
// Выполнить экспортную процедуру по имени с уровнем привилегий конфигурации.
// При включении профилей безопасности для вызова оператора Выполнить() используется
// переход в безопасный режим с профилем безопасности, используемым для информационной базы
// (если выше по стеку не был установлен другой безопасный режим).
//
// Параметры:
// ИмяМетода - Строка - имя экспортной процедуры в формате
// <имя объекта>.<имя процедуры>, где <имя объекта> - это
// общий модуль или модуль менеджера объекта.
// Параметры - Массив - параметры передаются в процедуру <ИмяЭкспортнойПроцедуры>
// в порядке расположения элементов массива.
//
// Пример:
// Параметры = Новый Массив();
// Параметры.Добавить("1");
// ОбщегоНазначения.ВыполнитьМетодКонфигурации("МойОбщийМодуль.МояПроцедура", Параметры);
//
Процедура ВыполнитьМетодКонфигурации(Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт
ПроверитьИмяПроцедурыКонфигурации(ИмяМетода);
Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме");
Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности()
И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда
ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы();
Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда
УстановитьБезопасныйРежим(ПрофильИнформационнойБазы);
Если БезопасныйРежим() = Истина Тогда
УстановитьБезопасныйРежим(Ложь);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ПараметрыСтрока = "";
Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда
Для Индекс = 0 По Параметры.ВГраница() Цикл
ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],";
КонецЦикла;
ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1);
КонецЕсли;
Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")";
КонецПроцедуры
// Выполнить экспортную процедуру объекта встроенного языка по имени.
// При включении профилей безопасности для вызова оператора Выполнить() используется
// переход в безопасный режим с профилем безопасности, используемым для информационной базы
// (если выше по стеку не был установлен другой безопасный режим).
//
// Параметры:
// Объект - Произвольный - объект встроенного языка 1С:Предприятия, содержащий методы (например, ОбработкаОбъект).
// ИмяМетода - Строка - имя экспортной процедуры модуля объекта обработки.
// Параметры - Массив - параметры передаются в процедуру <ИмяПроцедуры>
// в порядке расположения элементов массива.
//
Процедура ВыполнитьМетодОбъекта(Знач Объект, Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт
// Проверка имени метода на корректность.
Попытка
Тест = Новый Структура(ИмяМетода, ИмяМетода);
Если Тест = Неопределено Тогда
ВызватьИсключение НСтр("ru = 'Синтетический тест'");
КонецЕсли;
Исключение
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Некорректное значение параметра %1 (%2) в %3.'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.ВыполнитьМетодОбъекта");
КонецПопытки;
Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме");
Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности()
И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда
МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме");
ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы();
Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда
УстановитьБезопасныйРежим(ПрофильИнформационнойБазы);
Если БезопасныйРежим() = Истина Тогда
УстановитьБезопасныйРежим(Ложь);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ПараметрыСтрока = "";
Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда
Для Индекс = 0 По Параметры.ВГраница() Цикл
ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],";
КонецЦикла;
ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1);
КонецЕсли;
Выполнить "Объект." + ИмяМетода + "(" + ПараметрыСтрока + ")";
КонецПроцедуры
// Выполняет произвольный алгоритм на встроенном языке 1С:Предприятия, предварительно устанавливая
// безопасный режим выполнения кода и безопасный режим разделения данных для всех разделителей,
// присутствующих в составе конфигурации.
//
// Параметры:
// Алгоритм - Строка - алгоритм на встроенном языке "1С:Предприятия".
// Параметры - Произвольный - контекст, который требуется для выполнения алгоритма.
// В тексте алгоритма обращение к контексту должно происходить по имени "Параметры".
// Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям
// "Значение1" и "Значение2", переданным в Параметры, как свойства.
//
// Пример:
//
// Параметры = Новый Структура;
// Параметры.Вставить("Значение1", 1);
// Параметры.Вставить("Значение2", 10);
// ОбщегоНазначения.ВыполнитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры);
//
Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено) Экспорт
УстановитьБезопасныйРежим(Истина);
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации();
Иначе
МассивРазделителей = Новый Массив;
КонецЕсли;
Для Каждого ИмяРазделителя Из МассивРазделителей Цикл
УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина);
КонецЦикла;
Выполнить Алгоритм;
КонецПроцедуры
// Вычисляет переданное выражение, предварительно устанавливая безопасный режим выполнения кода
// и безопасный режим разделения данных для всех разделителей, присутствующих в составе конфигурации.
//
// Параметры:
// Выражение - Строка - выражение на встроенном языке 1С:Предприятия.
// Параметры - Произвольный - контекст, который требуется для вычисления выражения.
// В тексте выражения обращение к контексту должно происходить по имени "Параметры".
// Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям
// "Значение1" и "Значение2" переданные в Параметры, как свойства.
//
// Возвращаемое значение:
// Произвольный - результат вычисления выражения.
//
// Пример:
//
// // Пример 1
// Параметры = Новый Структура;
// Параметры.Вставить("Значение1", 1);
// Параметры.Вставить("Значение2", 10);
// Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры);
//
// // Пример 2
// Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("СтандартныеПодсистемыСервер.ВерсияБиблиотеки()");
//
Функция ВычислитьВБезопасномРежиме(Знач Выражение, Знач Параметры = Неопределено) Экспорт
УстановитьБезопасныйРежим(Истина);
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации();
Иначе
МассивРазделителей = Новый Массив;
КонецЕсли;
Для Каждого ИмяРазделителя Из МассивРазделителей Цикл
УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина);
КонецЦикла;
Возврат Вычислить(Выражение);
КонецФункции
// Возвращает описание защиты от опасных действий с отключенными предупреждениями.
//
// Возвращаемое значение:
// ОписаниеЗащитыОтОпасныхДействий - со свойством ПредупреждатьОбОпасныхДействиях = Ложь.
//
Функция ОписаниеЗащитыБезПредупреждений() Экспорт
ОписаниеЗащиты = Новый ОписаниеЗащитыОтОпасныхДействий;
ОписаниеЗащиты.ПредупреждатьОбОпасныхДействиях = Ложь;
Возврат ОписаниеЗащиты;
КонецФункции
#КонецОбласти
#Область Запросы
// Подготавливает строку для использования в качестве шаблона поиска в запросе с оператором ПОДОБНО.
// Экранирует служебные символы, если они есть в строке.
//
// Параметры:
// СтрокаПоиска - Строка - произвольная строка.
//
// Возвращаемое значение:
// Строка
//
// Пример:
// ВЫБРАТЬ
// Номенклатура.Ссылка КАК Ссылка
// ИЗ
// Справочник.Номенклатура КАК Номенклатура
// ГДЕ
// Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~"
//
// Запрос.УстановитьПараметр("Шаблон", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИскомыйТекст));
//
Функция СформироватьСтрокуДляПоискаВЗапросе(Знач СтрокаПоиска) Экспорт
Результат = СтрокаПоиска;
Результат = СтрЗаменить(Результат, "~", "~~");
Результат = СтрЗаменить(Результат, "%", "~%");
Результат = СтрЗаменить(Результат, "_", "~_");
Результат = СтрЗаменить(Результат, "[", "~[");
Результат = СтрЗаменить(Результат, "]", "~]");
Результат = СтрЗаменить(Результат, "^", "~^");
Возврат Результат;
КонецФункции
// Возвращает фрагмент текста запроса, отделяющего один запрос от другого.
//
// Возвращаемое значение:
// Строка - разделитель запросов.
//
Функция РазделительПакетаЗапросов() Экспорт
Возврат "
|;
|
|////////////////////////////////////////////////////////////////////////////////
|";
КонецФункции
#КонецОбласти
#Область Прочее
// Выполняет проверки перед выполнением обработчика регламентного задания и прерывает выполнение,
// если его запуск в данный момент невозможен, например:
// - еще не завершено обновление программы;
// - запуск через консоль или другим способом, минуя включение функциональной опции
// (если регламентное задание зависит от функциональных опций);
// - попытка выполнения задания, работающего с внешними ресурсами в копии информационной базы.
//
// Параметры:
// РегламентноеЗадание - ОбъектМетаданныхРегламентноеЗадание - регламентное задание,
// из которого вызывается данная процедура.
//
// Пример:
// ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.<ИмяРегламентногоЗадания>);
//
Процедура ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание = Неопределено) Экспорт
УстановитьПривилегированныйРежим(Истина);
Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда
Текст = НСтр("ru = 'Вход в программу временно невозможен в связи с обновлением на новую версию.
|Рекомендуется запрещать выполнение регламентных заданий на время обновления.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
Если Не РазделениеВключено()
И ПланыОбмена.ГлавныйУзел() = Неопределено
И ЗначениеЗаполнено(Константы.ГлавныйУзел.Получить()) Тогда
Текст = НСтр("ru = 'Вход в программу временно невозможен до восстановления связи с главным узлом.
|Рекомендуется запрещать выполнение регламентных заданий на время восстановления.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
Если РегламентноеЗадание <> Неопределено
И ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда
МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами");
МодульБлокировкаРаботыСВнешнимиРесурсами.ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание);
МодульРегламентныеЗаданияСлужебный = ОбщийМодуль("РегламентныеЗаданияСлужебный");
Доступно = МодульРегламентныеЗаданияСлужебный.РегламентноеЗаданиеДоступноПоФункциональнымОпциям(РегламентноеЗадание);
Если Не Доступно Тогда
Задания = РегламентныеЗаданияСервер.НайтиЗадания(Новый Структура("Метаданные", РегламентноеЗадание));
Для Каждого Задание Из Задания Цикл
РегламентныеЗаданияСервер.ИзменитьЗадание(Задание.УникальныйИдентификатор,
Новый Структура("Использование", Ложь));
КонецЦикла;
Текст = НСтр("ru = 'Регламентное задание недоступно по функциональным опциям или
|не поддерживает работу в текущем режиме работы программы.
|Выполнение прервано. Задание отключено.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
КонецЕсли;
Если СтандартныеПодсистемыСервер.ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы() Тогда
Текст = НСтр("ru = 'Регламентное задание недоступно до установки начальных региональных настроек программы.
|Выполнение прервано.'");
РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст);
ВызватьИсключение Текст;
КонецЕсли;
Справочники.ВерсииРасширений.ЗарегистрироватьИспользованиеВерсииРасширений();
РегистрыСведений.ПараметрыРаботыВерсийРасширений.ПриУспешномНачалеВыполненияРегламентногоЗадания();
КонецПроцедуры
// Переводит параметры сеанса в состояние "Не установлено".
//
// Параметры:
// ПараметрыДляОчистки - Строка - имена параметров сеанса для очистки, разделенные ",".
// Исключения - Строка - имена параметров сеанса не предназначенные для очистки, разделенные ",".
//
Процедура ОчиститьПараметрыСеанса(ПараметрыДляОчистки = "", Исключения = "") Экспорт
МассивИсключений = СтрРазделить(Исключения, ",");
МассивПараметровДляОчистки = СтрРазделить(ПараметрыДляОчистки, ",", Ложь);
Если МассивПараметровДляОчистки.Количество() = 0 Тогда
Для Каждого ПараметрСеанса Из Метаданные.ПараметрыСеанса Цикл
Если МассивИсключений.Найти(ПараметрСеанса.Имя) = Неопределено Тогда
МассивПараметровДляОчистки.Добавить(ПараметрСеанса.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Индекс = МассивПараметровДляОчистки.Найти("ПараметрыКлиентаНаСервере");
Если Индекс <> Неопределено Тогда
МассивПараметровДляОчистки.Удалить(Индекс);
КонецЕсли;
Индекс = МассивПараметровДляОчистки.Найти("ОсновнойЯзык");
Если Индекс <> Неопределено Тогда
МассивПараметровДляОчистки.Удалить(Индекс);
КонецЕсли;
Индекс = МассивПараметровДляОчистки.Найти("УстановленныеРасширения");
Если Индекс <> Неопределено Тогда
МассивПараметровДляОчистки.Удалить(Индекс);
КонецЕсли;
ПараметрыСеанса.Очистить(МассивПараметровДляОчистки);
КонецПроцедуры
// Проверяет, умещаются ли переданные табличные документы на страницу при печати.
//
// Параметры:
// ТабДокумент - ТабличныйДокумент - табличный документ.
// ВыводимыеОбласти - Массив
// - ТабличныйДокумент - массив из проверяемых таблиц или табличный документ.
// РезультатПриОшибке - Булево - какой возвращать результат при возникновении ошибки.
//
// Возвращаемое значение:
// Булево - умещаются или нет переданные документы.
//
Функция ПроверитьВыводТабличногоДокумента(ТабДокумент, ВыводимыеОбласти, РезультатПриОшибке = Истина) Экспорт
Попытка
Возврат ТабДокумент.ПроверитьВывод(ВыводимыеОбласти);
Исключение
Возврат РезультатПриОшибке;
КонецПопытки;
КонецФункции
// Сохраняет персональные настройки пользователя, относящиеся к подсистеме БазоваяФункциональность.
// Для получения настроек предусмотрены следующие функции:
// - ОбщегоНазначенияКлиент.ПредлагатьУстановкуРасширенияРаботыСФайлами(),
// - СтандартныеПодсистемыСервер.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы(),
// - СтандартныеПодсистемыСервер.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы().
//
// Параметры:
// Настройки - Структура:
// * НапоминатьОбУстановкеРасширенияРаботыСФайлами - Булево - признак необходимости
// напоминания об установке расширения.
// * ЗапрашиватьПодтверждениеПриЗавершенииПрограммы - Булево - запрашивать подтверждение по завершении работы.
// * ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы - Булево - показывать оповещение при
// динамическом обновлении программы.
//
Процедура СохранитьПерсональныеНастройки(Настройки) Экспорт
Если Настройки.Свойство("НапоминатьОбУстановкеРасширенияРаботыСФайлами") Тогда
Если ЭтоВебКлиент() Тогда
ИдентификаторКлиента = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИдентификаторКлиента");
Если ИдентификаторКлиента = Неопределено Тогда
СистемнаяИнформация = Новый СистемнаяИнформация;
ИдентификаторКлиента = СистемнаяИнформация.ИдентификаторКлиента;
КонецЕсли;
ХранилищеОбщихНастроекСохранить(
"НастройкиПрограммы/ПредлагатьУстановкуРасширенияРаботыСФайлами",
ИдентификаторКлиента, Настройки.НапоминатьОбУстановкеРасширенияРаботыСФайлами);
КонецЕсли;
КонецЕсли;
Если Настройки.Свойство("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы") Тогда
ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя",
"ЗапрашиватьПодтверждениеПриЗавершенииПрограммы",
Настройки.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы);
КонецЕсли;
Если Настройки.Свойство("ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы") Тогда
ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя",
"ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы",
Настройки.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы);
КонецЕсли;
КонецПроцедуры
// Выполняет пропорциональное распределение суммы в соответствии
// с заданными коэффициентами распределения.
//
// Параметры:
// РаспределяемаяСумма - Число - сумма, которую надо распределить, если сумма равна 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Кода");
//
// Если ПодключаемыйМодуль <> Неопределено Тогда
// // ПодключаемыйМодуль содержит созданный экземпляр подключенной компоненты.
// КонецЕсли;
//
// ПодключаемыйМодуль = Неопределено;
//
Функция ПодключитьКомпонентуИзМакета(Знач Идентификатор, Знач ПолноеИмяМакета, Знач Изолированно = Ложь) Экспорт
РезультатПроверкиВнешнейКомпоненты = Неопределено;
Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда
МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный");
РезультатПроверкиВнешнейКомпоненты = МодульВнешниеКомпонентыСлужебный.ПроверитьПодключениеКомпоненты(Идентификатор);
РезультатПроверкиВнешнейКомпоненты.Вставить("Доступна",
Не ЗначениеЗаполнено(РезультатПроверкиВнешнейКомпоненты.ОписаниеОшибки));
КонецЕсли;
КомпонентаПоследнейВерсии = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии(
Идентификатор, ПолноеИмяМакета, РезультатПроверкиВнешнейКомпоненты);
Результат = ПодключитьКомпонентуПоИдентификатору(Идентификатор,
КомпонентаПоследнейВерсии.Местоположение, Изолированно);
Возврат Результат.ПодключаемыйМодуль;
КонецФункции
#КонецОбласти
#Область УстаревшиеПроцедурыИФункции
// Устарела. Следует использовать
// ОбщегоНазначения.РазделениеВключено И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных.
//
// Возвращаемое значение:
// Булево
//
Функция ИспользованиеРазделителяСеанса() Экспорт
Если Не РазделениеВключено() Тогда
Возврат Ложь;
КонецЕсли;
Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса");
Возврат МодульРаботаВМоделиСервиса.ИспользованиеРазделителяСеанса();
КонецЕсли;
КонецФункции
// Устарела. Следует использовать ФайловаяСистема.СоздатьВременныйКаталог
// Создает временный каталог. После окончания работы с временным каталогом его необходимо удалить
// с помощью ОбщегоНазначения.УдалитьВременныйКаталог.
//
// Параметры:
// Расширение - Строка - расширение каталога, которое идентифицирует назначение временного каталога
// и подсистему, которая его создала.
// Рекомендуется указывать на английском языке.
//
// Возвращаемое значение:
// Строка - полный путь к каталогу с разделителем пути.
//
Функция СоздатьВременныйКаталог(Знач Расширение = "") Экспорт
Возврат ФайловаяСистема.СоздатьВременныйКаталог(Расширение);
КонецФункции
// Устарела. Следует использовать ФайловаяСистема.УдалитьВременныйКаталог
// Удаляет временный каталог вместе с его содержимым, если возможно.
// Если временный каталог не может быть удален (например, он занят каким-то процессом),
// то в журнал регистрации записывается соответствующее предупреждение, а процедура завершается.
//
// Для совместного использования с ОбщегоНазначения.СоздатьВременныйКаталог,
// после окончания работы с временным каталогом.
//
// Параметры:
// ПутьККаталогу - Строка - полный путь к временному каталогу.
//
Процедура УдалитьВременныйКаталог(Знач ПутьККаталогу) Экспорт
ФайловаяСистема.УдалитьВременныйКаталог(ПутьККаталогу);
КонецПроцедуры
// Устарела. Проверяет наличие механизма платформы, предупреждающего об опасных действиях.
//
// Возвращаемое значение:
// Булево - если Истина, тогда работает механизм предупреждений безопасности.
//
Функция ЕстьЗащитаОтОпасныхДействий() Экспорт
Возврат Истина;
КонецФункции
// Устарела. Создает и возвращает экземпляр отчета или обработки по полному имени объекта метаданных.
//
// Параметры:
// ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Отчет.БизнесПроцессы".
//
// Возвращаемое значение:
// ОтчетОбъект
// ОбработкаОбъект - экземпляр отчета или обработки.
//
Функция ОбъектПоПолномуИмени(ПолноеИмя) Экспорт
МассивСтрок = СтрРазделить(ПолноеИмя, ".");
Если МассивСтрок.Количество() >= 2 Тогда
Вид = ВРег(МассивСтрок[0]);
Имя = МассивСтрок[1];
Иначе
ВызватьИсключение СтрЗаменить(НСтр("ru = 'Некорректное полное имя отчета или обработки ""%1"".'"), "%1", ПолноеИмя);
КонецЕсли;
Если Вид = "ОТЧЕТ" Тогда
Возврат Отчеты[Имя].Создать();
ИначеЕсли Вид = "ОБРАБОТКА" Тогда
Возврат Обработки[Имя].Создать();
Иначе
ВызватьИсключение СтрЗаменить(НСтр("ru = '""%1"" не является отчетом или обработкой.'"), "%1", ПолноеИмя);
КонецЕсли;
КонецФункции
// Устарела. Следует использовать ОбщегоНазначения.ЭтоMacOSКлиент
// Возвращает Истина, если клиентское приложение запущено под управлением ОС X.
//
// Возвращаемое значение:
// Булево - если нет клиентского приложения, возвращается Ложь.
//
Функция ЭтоOSXКлиент() Экспорт
УстановитьПривилегированныйРежим(Истина);
ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент");
Если ЭтоMacOSКлиент = Неопределено Тогда
Возврат Ложь; // Нет клиентского приложения.
КонецЕсли;
Возврат ЭтоMacOSКлиент;
КонецФункции
#КонецОбласти
#КонецЕсли
#КонецОбласти
#Если НЕ МобильныйАвтономныйСервер Тогда
#Область СлужебныйПрограммныйИнтерфейс
// Выгружает запрос в строку XML, которую можно вставить в Консоль запросов.
// Для переноса запроса и всех его параметров в Консоль запросов, необходимо вызвать функцию в окне.
// "Вычислить выражение" (Shift + F9), скопировать полученный XML в поле "Текст запроса"
// консоли запросов и выполнить команду "Заполнить из XML" из меню "Еще".
// Подробнее об использование функции смотрите в справке к консоли запросов.
//
// Параметры:
// Запрос - Запрос - запрос, который необходимо выгрузить в формат строки XML.
//
// Возвращаемое значение:
// Строка - строка в формате XML, которую можно извлечь при помощи метода "ОбщегоНазначения.ЗначениеИзСтрокиXML".
// После извлечения получится объект типа "Структура" с полями:
// * Текст - Строка - текст запроса.
// * Параметры - Структура - параметры запроса.
//
Функция ЗапросВСтрокуXML(Запрос) Экспорт // АПК:299 - используется при отладке запросов, см. описание функции.
Структура = Новый Структура("Текст, Параметры");
ЗаполнитьЗначенияСвойств(Структура, Запрос);
Возврат ЗначениеВСтрокуXML(Структура);
КонецФункции
Функция ПодключитьКомпонентуПоИдентификатору(Знач Идентификатор, Знач Местоположение, Знач Изолированно = Ложь) Экспорт
ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение);
Результат = Новый Структура;
Результат.Вставить("Подключено", Ложь);
Результат.Вставить("ПодключаемыйМодуль", Неопределено);
Результат.Вставить("ОписаниеОшибки", "");
Попытка
#Если МобильноеПриложениеСервер Тогда
РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName");
#Иначе
РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName",,
ОбщегоНазначенияСлужебныйКлиентСервер.ТипПодключенияКомпоненты(Изолированно));
#КонецЕсли
Исключение
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине:
|%2.'"),
Идентификатор, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка,,, Результат.ОписаниеОшибки);
Возврат Результат;
КонецПопытки;
Если Не РезультатПодключения Тогда
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине:
|Метод %2 вернул Ложь.'"),
Идентификатор, "ПодключитьВнешнююКомпоненту");
ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка,,, Результат.ОписаниеОшибки);
Возврат Результат;
КонецЕсли;
ПодключаемыйМодуль = Неопределено;
Попытка
ПодключаемыйМодуль = Новый("AddIn." + Идентификатор + "SymbolicName" + "." + Идентификатор);
Если ПодключаемыйМодуль = Неопределено Тогда
ВызватьИсключение НСтр("ru = 'Оператор Новый вернул Неопределено'");
КонецЕсли;
Исключение
ПодключаемыйМодуль = Неопределено;
ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Если ПодключаемыйМодуль = Неопределено Тогда
Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось создать объект внешней компоненты ""%1"", подключенной на сервере, по причине:
|%2'"),
Идентификатор, ТекстОшибки);
ЗаписьЖурналаРегистрации(НСтр("ru = 'Подключение внешней компоненты на сервере'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка,,, Результат.ОписаниеОшибки);
Возврат Результат;
КонецЕсли;
Результат.Подключено = Истина;
Результат.ПодключаемыйМодуль = ПодключаемыйМодуль;
Возврат Результат;
КонецФункции
Функция СтрокаВВидеНСтр(Знач ПроверяемаяСтрока) Экспорт
ПроверяемаяСтрока = СтрЗаменить(ПроверяемаяСтрока, " ", "");
ВариантыСовпадений = Новый Массив;
Для каждого Язык Из Метаданные.Языки Цикл
ВариантыСовпадений.Добавить(Язык.КодЯзыка + "=");
КонецЦикла;
Для каждого ВариантСовпадения Из ВариантыСовпадений Цикл
Если СтрНайти(ПроверяемаяСтрока, ВариантСовпадения) > 0 Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Устанавливает условное оформление списка выбора
//
// Параметры:
// Форма - ФормаКлиентскогоПриложения - форма, для которой устанавливается оформление.
// ИмяЭлемента - Строка - имя элемента, для которого устанавливается оформление.
// ИмяПоляКомпоновкиДанных - Строка - имя поля компоновки данных.
//
Процедура УстановитьУсловноеОформлениеСпискаВыбора(Форма, ИмяЭлемента, ИмяПоляКомпоновкиДанных) Экспорт
Элементы = Форма.Элементы;
УсловноеОформление = Форма.УсловноеОформление;
Для каждого ЭлементВыбора Из Элементы[ИмяЭлемента].СписокВыбора Цикл
Элемент = УсловноеОформление.Элементы.Добавить();
ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
ЭлементФормы = Элементы[ИмяЭлемента]; // ПолеФормы
ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(ЭлементФормы.Имя);
ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоляКомпоновкиДанных);
ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборЭлемента.ПравоеЗначение = ЭлементВыбора.Значение;
Элемент.Оформление.УстановитьЗначениеПараметра("Текст", ЭлементВыбора.Представление);
КонецЦикла;
КонецПроцедуры
// Возвращает суффикс текущего языка для мультиязычных реквизитов.
//
// Возвращаемое значение:
// Строка - "Язык1" или "Язык2", если язык пользователя является дополнительным
// Пустая строка, если язык пользователя является основным.
// Неопределено - мультиязычное хранение данных не используется.
//
Функция СуффиксЯзыкаТекущегоПользователя() Экспорт
Результат = Новый Структура();
Результат.Вставить("СуффиксТекущегоЯзыка", "");
Результат.Вставить("ЭтоОсновнойЯзык", "");
Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер");
СуффиксТекущегоЯзыка = МодульМультиязычностьСервер.СуффиксТекущегоЯзыка();
Если ЗначениеЗаполнено(СуффиксТекущегоЯзыка) Тогда
Возврат СуффиксТекущегоЯзыка;
КонецЕсли;
Иначе
СуффиксТекущегоЯзыка = "";
КонецЕсли;
Если ЭтоОсновнойЯзык() Тогда
Возврат СуффиксТекущегоЯзыка;
КонецЕсли;
Возврат Неопределено;
КонецФункции
// Сокращает имя файла с расширением.
// Сокращение имени, производится, когда имя файла с расширением превышает размер 255 байт.
// Сокращение ими файла достигая за счет сокращения имени файла без расширения и
// добавления значения хеш функции сокращенной строки.
//
// Параметры:
// ИмяФайла - Строка - имя файла с расширением
//
Процедура СократитьИмяФайла(ИмяФайла) Экспорт
ОграничениеВБайтах = 255;
Если РазмерСтрокиВБайтах(ИмяФайла) <= ОграничениеВБайтах Тогда
Возврат;
КонецЕсли;
Файл = Новый Файл(ИмяФайла);
ИмяБезРасширения = Файл.ИмяБезРасширения;
ОграничениеВБайтах = ОграничениеВБайтах - РазмерСтрокиВБайтах(Файл.Расширение);
ДлинаСтроки = СтрДлина(ИмяБезРасширения);
ИспользуемоеКоличествоСимволов = ОграничениеВБайтах - 32;
БольшееКоличествоСимволов = Мин(ДлинаСтроки, ОграничениеВБайтах);
МеньшееКоличествоСимволов = Цел((ОграничениеВБайтах - 32)/4);
Уменьшить = Истина;
Пока Истина Цикл
Если Уменьшить Тогда
ИспользуемоеКоличествоСимволов = МеньшееКоличествоСимволов + Цел((ИспользуемоеКоличествоСимволов-МеньшееКоличествоСимволов)/2);
Иначе
ИспользуемоеКоличествоСимволов = ИспользуемоеКоличествоСимволов + Цел((БольшееКоличествоСимволов - ИспользуемоеКоличествоСимволов)/2);
КонецЕсли;
РазмерСтрокиВБайтах = РазмерСтрокиВБайтах(ИмяБезРасширения)+32;
Если РазмерСтрокиВБайтах = ОграничениеВБайтах Или БольшееКоличествоСимволов - МеньшееКоличествоСимволов = 1 Тогда
Прервать;
КонецЕсли;
Если РазмерСтрокиВБайтах > ОграничениеВБайтах Тогда
Уменьшить = Истина;
БольшееКоличествоСимволов = ИспользуемоеКоличествоСимволов;
Иначе
Уменьшить = Ложь;
МеньшееКоличествоСимволов = ИспользуемоеКоличествоСимволов;
КонецЕсли;
КонецЦикла;
СокращеннаяСтрока = СократитьСтрокуКонтрольнойСуммой(ИмяБезРасширения, ИспользуемоеКоличествоСимволов+32);
ИмяФайла = СокращеннаяСтрока+Файл.Расширение;
КонецПроцедуры
// Служебные объекты и объекты при загрузке из резервной копии,
// должны записываться без какой-либо прикладной логики.
//
// Запись служебных объектов без отключения прикладной логики,
// может привести к зацикливанию, снижению производительности,
// а также избыточным изменениях, которые в некоторых случаях
// могут неожиданно повлиять на логику работы.
//
// Служебными являются объекты, которые обычно не участвуют
// в обмене данными, не зависят от других объектов, например:
// - кэши;
// - даты обновления кэшей и аналогичные признаки;
// - промежуточные данные для передачи параметров в фоновые задания;
// - вспомогательные служебные данные (например, ключи доступа,
// идентификаторы объектов метаданных).
//
// При использовании подсистемы Управление доступом, требуется
// отдельно вызывать процедуру ОтключитьОбновлениеКлючейДоступа
// общего модуля УправлениеДоступом.
//
// Процедура включает режим загрузки данных,
// отключает регистрацию объектов на планах обмена,
// отключает контроль механизма удаления помеченных объектов.
//
// Параметры:
// Объект - ПланОбменаОбъект
// - КонстантаМенеджерЗначения
// - СправочникОбъект
// - ДокументОбъект
// - ПоследовательностьНаборЗаписей
// - ПланВидовХарактеристикОбъект
// - ПланСчетовОбъект
// - ПланВидовРасчетаОбъект
// - БизнесПроцессОбъект
// - ЗадачаОбъект
// - УдалениеОбъекта
// - РегистрСведенийНаборЗаписей
// - РегистрНакопленияНаборЗаписей
// - РегистрБухгалтерииНаборЗаписей
// - РегистрРасчетаНаборЗаписей
// - ПерерасчетНаборЗаписей
//
// ЭтоУзелПланаОбмена - Булево
//
Процедура ОтключитьКонтрольЗаписи(Объект, ЭтоУзелПланаОбмена = Ложь) Экспорт
Объект.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых");
Объект.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов");
Объект.ОбменДанными.Загрузка = Истина;
Если Не ЭтоУзелПланаОбмена Тогда
Объект.ОбменДанными.Получатели.АвтоЗаполнение = Ложь;
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
#Область ДанныеВБазе
#Область ЗначенияРеквизитов
// Проверяет существование указанных реквизитов у объекта метаданных.
//
// Параметры:
// ПолноеИмяОбъектаМетаданных - Строка - полное имя проверяемого объекта.
// ПроверяемыеВыражения - Массив - имена полей или проверяемые выражения объекта метаданных.
//
// Возвращаемое значение:
// Структура:
// * Ошибка - Булево - найдена ошибка.
// * ОписаниеОшибки - Строка - описание найденных ошибок.
//
// Пример:
//
// Реквизиты = Новый Массив;
// Реквизиты.Добавить("Номер");
// Реквизиты.Добавить("Валюта.НаименованиеПолное");
//
// Результат = ОбщегоНазначения.ПроверитьСуществованиеРеквизитовОбъекта("Документ._ДемоЗаказПокупателя", Реквизиты);
//
// Если Результат.Ошибка Тогда
// ВызватьИсключение Результат.ОписаниеОшибки;
// КонецЕсли;
//
Функция ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, ПроверяемыеВыражения)
МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
Если МетаданныеОбъекта = Неопределено Тогда
Возврат Новый Структура("Ошибка, ОписаниеОшибки", Истина,
СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Несуществующий объект метаданных ""%1"".'"), ПолноеИмяОбъектаМетаданных));
КонецЕсли;
// Разрешение вызова из безопасного режима внешней обработки или расширения.
// Информация о доступности полей источника схемы при проверке метаданных не является секретной.
УстановитьОтключениеБезопасногоРежима(Истина);
УстановитьПривилегированныйРежим(Истина);
Схема = Новый СхемаЗапроса;
Пакет = Схема.ПакетЗапросов.Добавить(Тип("ЗапросВыбораСхемыЗапроса"));
Оператор = Пакет.Операторы.Получить(0);
Источник = Оператор.Источники.Добавить(ПолноеИмяОбъектаМетаданных, "Таблица");
ТекстОшибки = "";
Для Каждого ТекущееВыражение Из ПроверяемыеВыражения Цикл
Если Не ПолеИсточникаСхемыЗапросаДоступно(Источник, ТекущееВыражение) Тогда
ТекстОшибки = ТекстОшибки + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Поле объекта ""%1"" не существует.'"), ТекущееВыражение);
КонецЕсли;
КонецЦикла;
Возврат Новый Структура("Ошибка, ОписаниеОшибки", Не ПустаяСтрока(ТекстОшибки), ТекстОшибки);
КонецФункции
// Используется в ПроверитьСуществованиеРеквизитовОбъекта.
// Выполняет проверку доступности поля проверяемого выражения в источнике оператора схемы запроса.
//
Функция ПолеИсточникаСхемыЗапросаДоступно(ИсточникОператора, ПроверяемоеВыражение)
ЧастиИмениПоля = СтрРазделить(ПроверяемоеВыражение, ".");
ДоступныеПоля = ИсточникОператора.Источник.ДоступныеПоля;
ТекущаяЧастьИмениПоля = 0;
Пока ТекущаяЧастьИмениПоля < ЧастиИмениПоля.Количество() Цикл
ТекущееПоле = ДоступныеПоля.Найти(ЧастиИмениПоля.Получить(ТекущаяЧастьИмениПоля));
Если ТекущееПоле = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
// Инкрементация следующей части имени поля и соответствующего списка доступности полей.
ТекущаяЧастьИмениПоля = ТекущаяЧастьИмениПоля + 1;
ДоступныеПоля = ТекущееПоле.Поля;
КонецЦикла;
Возврат Истина;
КонецФункции
#КонецОбласти
#Область ЗаменитьСсылки
Функция РазметитьМестаИспользования(Знач ПараметрыВыполнения, Знач Ссылка, Знач ЦелеваяСсылка, Знач ТаблицаПоиска)
УстановитьПривилегированныйРежим(Истина);
// Устанавливаем порядок известных и проверяем наличие неопознанных объектов.
Результат = Новый Структура;
Результат.Вставить("МестаИспользования", ТаблицаПоиска.НайтиСтроки(Новый Структура("Ссылка", Ссылка)));
Результат.Вставить("ОшибкиРазметки", Новый Массив);
Результат.Вставить("Успех", Истина);
Для Каждого МестоИспользования Из Результат.МестаИспользования Цикл
Если МестоИспользования.ЭтоСлужебныеДанные Тогда
Продолжить; // Зависимые данные не обрабатываются.
КонецЕсли;
Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения);
Если Информация.Вид = "КОНСТАНТА" Тогда
МестоИспользования.КлючЗамены = "Константа";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Вид = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Тогда
МестоИспользования.КлючЗамены = "Последовательность";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Вид = "РЕГИСТРСВЕДЕНИЙ" Тогда
МестоИспользования.КлючЗамены = "РегистрСведений";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Вид = "РЕГИСТРБУХГАЛТЕРИИ"
Или Информация.Вид = "РЕГИСТРНАКОПЛЕНИЯ"
Или Информация.Вид = "РЕГИСТРРАСЧЕТА" Тогда
МестоИспользования.КлючЗамены = "КлючЗаписи";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
ИначеЕсли Информация.Ссылочный Тогда
МестоИспользования.КлючЗамены = "Объект";
МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка;
Иначе
// Неизвестный объект для замены ссылок.
Результат.Успех = Ложь;
Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Замена ссылок в ""%1"" не поддерживается.'"), Информация.ПолноеИмя);
ОписаниеОшибки = Новый Структура("Объект, Текст", МестоИспользования.Данные, Текст);
Результат.ОшибкиРазметки.Добавить(ОписаниеОшибки);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Параметры:
// ТаблицаПоиска - см. МестаИспользования
//
Процедура ЗаменитьСсылкиКороткимиТранзакциями(Результат, Знач ПараметрыВыполнения, Знач Дубль, Знач ТаблицаПоиска)
// Основной цикл обработки
ФильтрСсылок = Новый Структура("Ссылка, КлючЗамены");
Результат.ЕстьОшибки = Ложь;
ФильтрСсылок.Ссылка = Дубль;
ФильтрСсылок.КлючЗамены = "Константа";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВКонстанте(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "Объект";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВОбъекте(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "КлючЗаписи";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "Последовательность";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ФильтрСсылок.КлючЗамены = "РегистрСведений";
МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок);
Для Каждого МестоИспользования Из МестаИспользования Цикл
ПроизвестиЗаменуВРегистреСведений(Результат, МестоИспользования, ПараметрыВыполнения);
КонецЦикла;
ПроизводимыеЗамены = Новый Массив;
ПроизводимыеЗамены.Добавить(Дубль);
Если ПараметрыВыполнения.УдалятьНепосредственно
ИЛИ ПараметрыВыполнения.ПомечатьНаУдаление Тогда
УстановитьПометкуУдаленияДляОбъектов(Результат, ПроизводимыеЗамены, ПараметрыВыполнения);
Иначе
ТаблицаПовторногоПоиска = МестаИспользования(ПроизводимыеЗамены,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования);
ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска);
КонецЕсли;
КонецПроцедуры
Процедура ПроизвестиЗаменуВКонстанте(Результат, Знач МестоИспользования, Знач ПараметрыЗаписи)
УстановитьПривилегированныйРежим(Истина);
Данные = МестоИспользования.Данные;
МетаданныеКонстанты = МестоИспользования.Метаданные;
ПредставлениеДанных = Строка(Данные);
// Будем производить сразу все замены для этих данных.
Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Константа");
ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
// Помечаем как обработанные
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
Строка.КлючЗамены = "";
КонецЦикла;
СостояниеОперации = "";
Ошибка = "";
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
Блокировка.Добавить(МетаданныеКонстанты.ПолноеИмя());
Попытка
Блокировка.Заблокировать();
Исключение
Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось заблокировать константу %1'"),
ПредставлениеДанных);
СостояниеОперации = "ОшибкаБлокировки";
ВызватьИсключение;
КонецПопытки;
МенеджерКонстанты = Константы[МетаданныеКонстанты.Имя].СоздатьМенеджерЗначения();
МенеджерКонстанты.Прочитать();
ЗаменаПроизведена = Ложь;
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
Если МенеджерКонстанты.Значение = Строка.Ссылка Тогда
МенеджерКонстанты.Значение = Строка.ЦелеваяСсылка;
ЗаменаПроизведена = Истина;
КонецЕсли;
КонецЦикла;
Если Не ЗаменаПроизведена Тогда
ОтменитьТранзакцию();
Возврат;
КонецЕсли;
// Пытаемся сохранить
Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Попытка
ЗаписатьОбъект(МенеджерКонстанты, ПараметрыЗаписи);
Исключение
ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось записать %1 по причине: %2'"),
ПредставлениеДанных, ОписаниеОшибки);
СостояниеОперации = "ОшибкаЗаписи";
ВызватьИсключение;
КонецПопытки;
Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,
МетаданныеКонстанты,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Если СостояниеОперации = "ОшибкаЗаписи" Тогда
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка,
ОписаниеОшибкиЗамены("ОшибкаЗаписи", Данные, ПредставлениеДанных, Ошибка));
КонецЦикла;
Иначе
ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка,
ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, Ошибка));
КонецЕсли;
КонецПопытки;
КонецПроцедуры
Процедура ПроизвестиЗаменуВОбъекте(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения)
УстановитьПривилегированныйРежим(Истина);
Данные = МестоИспользования.Данные;
// Будем производить сразу все замены для этих данных.
Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Объект");
ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
ПредставлениеДанных = ПредметСтрокой(Данные);
СостояниеОперации = "";
ТекстОшибки = "";
НачатьТранзакцию();
Попытка
Блокировка = Новый БлокировкаДанных;
ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования);
Попытка
Блокировка.Заблокировать();
Исключение
СостояниеОперации = "ОшибкаБлокировки";
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось заблокировать объект ""%1"":
|%2'"),
ПредставлениеДанных,
ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
ОбъектыЗаписи = ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки);
// Пытаемся сохранить, сам объект идет последним.
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Попытка
Если ПараметрыВыполнения.ВключатьБизнесЛогику Тогда
// Первая запись без контроля, чтобы устранить циклические ссылки.
НовыеПараметрыВыполнения = СкопироватьРекурсивно(ПараметрыВыполнения);
НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Ложь;
Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл
ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения);
КонецЦикла;
// Вторая запись c контролем.
НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Истина;
Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл
ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения);
КонецЦикла;
Иначе
// Запись без контроля бизнес-логики.
Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл
ЗаписатьОбъект(КлючЗначение.Ключ, ПараметрыВыполнения);
КонецЦикла;
КонецЕсли;
Исключение
СостояниеОперации = "ОшибкаЗаписи";
ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось записать %1 по причине: %2'"),
ПредставлениеДанных, ОписаниеОшибки);
ВызватьИсключение;
КонецПопытки;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Информация = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,
МестоИспользования.Метаданные,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ТекстОшибки);
Если СостояниеОперации = "ОшибкаЗаписи" Тогда
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка, Ошибка);
КонецЦикла;
Иначе
ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка);
КонецЕсли;
КонецПопытки;
// Помечаем как обработанные
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
Строка.КлючЗамены = "";
КонецЦикла;
КонецПроцедуры
Процедура ПроизвестиЗаменуВНаборе(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения)
УстановитьПривилегированныйРежим(Истина);
Данные = МестоИспользования.Данные;
Мета = МестоИспользования.Метаданные;
ПредставлениеДанных = Строка(Данные);
// Будем производить сразу все замены для этих данных.
Фильтр = Новый Структура("Данные, КлючЗамены");
ЗаполнитьЗначенияСвойств(Фильтр, МестоИспользования);
ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования
ОписаниеНабора = ОписаниеКлючаЗаписи(Мета);
НаборЗаписей = ОписаниеНабора.НаборЗаписей; // РегистрСведенийНаборЗаписей
ПарыЗамен = Новый Соответствие;
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
ПарыЗамен.Вставить(Строка.Ссылка, Строка.ЦелеваяСсылка);
КонецЦикла;
// Помечаем как обработанные
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
Строка.КлючЗамены = "";
КонецЦикла;
СостояниеОперации = "";
Ошибка = "";
НачатьТранзакцию();
Попытка
// Блокировка и подготовка набора.
Блокировка = Новый БлокировкаДанных;
Для Каждого КлючЗначение Из ОписаниеНабора.СписокИзмерений Цикл
ТипИзмерения = КлючЗначение.Значение;
Имя = КлючЗначение.Ключ;
Значение = Данные[Имя];
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
ТекущаяСсылка = Строка.Ссылка;
Если ТипИзмерения.СодержитТип(ТипЗнч(ТекущаяСсылка)) Тогда
Блокировка.Добавить(ОписаниеНабора.ПространствоБлокировки).УстановитьЗначение(Имя, ТекущаяСсылка);
КонецЕсли;
КонецЦикла;
НаборЗаписей.Отбор[Имя].Установить(Значение);
КонецЦикла;
Попытка
Блокировка.Заблокировать();
Исключение
Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось заблокировать набор %1'"),
ПредставлениеДанных);
СостояниеОперации = "ОшибкаБлокировки";
ВызватьИсключение;
КонецПопытки;
НаборЗаписей.Прочитать();
ЗаменитьВКоллекцииСтрок("НаборЗаписей", "НаборЗаписей", НаборЗаписей, НаборЗаписей, ОписаниеНабора.СписокПолей, ПарыЗамен);
Если НаборЗаписей.Модифицированность() Тогда
ОтменитьТранзакцию();
Возврат;
КонецЕсли;
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Ложь);
КонецЕсли;
Попытка
ЗаписатьОбъект(НаборЗаписей, ПараметрыВыполнения);
Исключение
ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось записать %1 по причине: %2'"),
ПредставлениеДанных, ОписаниеОшибки);
СостояниеОперации = "ОшибкаЗаписи";
ВызватьИсключение;
КонецПопытки;
Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Информация = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка,
Мета,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, Ошибка);
Если СостояниеОперации = "ОшибкаЗаписи" Тогда
Для Каждого Строка Из ОбрабатываемыеСтроки Цикл
ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка, Ошибка);
КонецЦикла;
Иначе
ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка);
КонецЕсли;
КонецПопытки;
КонецПроцедуры
Процедура ПроизвестиЗаменуВРегистреСведений(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения)
Если МестоИспользования.Обработано Тогда
Возврат;
КонецЕсли;
МестоИспользования.Обработано = Истина;
// В случае, если дубль указан в измерениях набора, тогда используется 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;
Иначе
ИмяИзмеренияЗначения.Значение[Сч] = ИзмененнаяКоллекция[Сч][ИмяИзмеренияЗначения.Ключ];
КонецЕсли;
КонецЦикла;
КонецЦикла;
НаборЗаписей.Загрузить(ИзмененнаяКоллекция);
Для каждого ИзмеренияЗначенияВКолонке Из НеизмененныеИзмерения Цикл
НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ);
КонецЦикла;
Для каждого ИзмеренияЗначенияВКолонке Из ИзмененныеИзмерения Цикл
НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ);
КонецЦикла;
КонецПроцедуры
Процедура ОбработатьОбъектСПерехватомСообщений(Знач Объект, Знач Действие, Знач РежимЗаписи, Знач ПараметрыЗаписи)
// Текущие сообщения до исключения запоминаем.
ПредыдущиеСообщения = ПолучитьСообщенияПользователю(Истина);
СообщатьПовторно = ТекущийРежимЗапуска() <> Неопределено;
Попытка
Если Действие = "Запись" Тогда
Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику;
Если РежимЗаписи = Неопределено Тогда
Объект.Записать();
Иначе
Объект.Записать(РежимЗаписи);
КонецЕсли;
ИначеЕсли Действие = "ПометкаУдаления" Тогда
МетаданныеОбъекта = Объект.Метаданные();
Если ЭтоСправочник(МетаданныеОбъекта)
Или ЭтоПланВидовХарактеристик(МетаданныеОбъекта)
Или ЭтоПланСчетов(МетаданныеОбъекта) Тогда
Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику;
Объект.УстановитьПометкуУдаления(Истина, Ложь);
ИначеЕсли ЭтоДокумент(МетаданныеОбъекта)
И МетаданныеОбъекта.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
Объект.УстановитьПометкуУдаления(Истина);
Иначе
Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику;
Объект.УстановитьПометкуУдаления(Истина);
КонецЕсли;
КонецЕсли;
Исключение
// Перехватываем все сообщенное при ошибке и добавляем их в одно исключение.
ТекстИсключения = "";
Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Ложь) Цикл
ТекстИсключения = ТекстИсключения + Символы.ПС + Сообщение.Текст;
КонецЦикла;
// Сообщаем предыдущие
Если СообщатьПовторно Тогда
СообщитьОтложенныеСообщения(ПредыдущиеСообщения);
КонецЕсли;
Если ТекстИсключения = "" Тогда
ВызватьИсключение;
КонецЕсли;
ВызватьИсключение СокрЛП(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()) + Символы.ПС + СокрЛП(ТекстИсключения));
КонецПопытки;
Если СообщатьПовторно Тогда
СообщитьОтложенныеСообщения(ПредыдущиеСообщения);
КонецЕсли;
КонецПроцедуры
Процедура СообщитьОтложенныеСообщения(Знач Сообщения)
Для Каждого Сообщение Из Сообщения Цикл
Сообщение.Сообщить();
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьОбъект(Знач Объект, Знач ПараметрыЗаписи)
МетаданныеОбъекта = Объект.Метаданные();
Если ЭтоДокумент(МетаданныеОбъекта) Тогда
ОбработатьОбъектСПерехватомСообщений(Объект, "Запись", РежимЗаписиДокумента.Запись, ПараметрыЗаписи);
Возврат;
КонецЕсли;
// Проверка на возможные циклические ссылки.
СвойстваОбъекта = Новый Структура("Иерархический, ВидыСубконто, Владельцы", Ложь, Неопределено, Новый Массив);
ЗаполнитьЗначенияСвойств(СвойстваОбъекта, МетаданныеОбъекта);
// По родителю
Если СвойстваОбъекта.Иерархический Или СвойстваОбъекта.ВидыСубконто <> Неопределено Тогда
Если Объект.Родитель = Объект.Ссылка Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("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 = 'Регистратор'");
ДанныеИзмерения.Ведущее = Истина;
ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения);
КонецЕсли;
// Все измерения
Для Каждого МетаИзмерение Из МетаданныеРегистра.Измерения Цикл
ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип");
ДанныеИзмерения.Тип = МетаИзмерение.Тип;
ДанныеИзмерения.Представление = МетаИзмерение.Представление();
ДанныеИзмерения.Ведущее = МетаИзмерение.Ведущее;
ОписаниеИзмерений.Вставить(МетаИзмерение.Имя, ДанныеИзмерения);
КонецЦикла;
КэшИзмеренийРегистров[МетаданныеРегистра] = ОписаниеИзмерений;
Возврат ОписаниеИзмерений;
КонецФункции
#КонецОбласти
#КонецОбласти
#Область УсловныеВызовы
// Возвращает серверный модуль менеджера по имени объекта.
Функция СерверныйМодульМенеджера(Имя)
ОбъектНайден = Ложь;
ЧастиИмени = СтрРазделить(Имя, ".");
Если ЧастиИмени.Количество() = 2 Тогда
ИмяВида = ВРег(ЧастиИмени[0]);
ИмяОбъекта = ЧастиИмени[1];
Если ИмяВида = ВРег("Константы") Тогда
Если Метаданные.Константы.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("РегистрыСведений") Тогда
Если Метаданные.РегистрыСведений.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("РегистрыНакопления") Тогда
Если Метаданные.РегистрыНакопления.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("РегистрыБухгалтерии") Тогда
Если Метаданные.РегистрыБухгалтерии.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("РегистрыРасчета") Тогда
Если Метаданные.РегистрыРасчета.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("Справочники") Тогда
Если Метаданные.Справочники.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("Документы") Тогда
Если Метаданные.Документы.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("Отчеты") Тогда
Если Метаданные.Отчеты.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("Обработки") Тогда
Если Метаданные.Обработки.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("БизнесПроцессы") Тогда
Если Метаданные.БизнесПроцессы.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("ЖурналыДокументов") Тогда
Если Метаданные.ЖурналыДокументов.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("Задачи") Тогда
Если Метаданные.Задачи.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("ПланыСчетов") Тогда
Если Метаданные.ПланыСчетов.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("ПланыОбмена") Тогда
Если Метаданные.ПланыОбмена.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("ПланыВидовХарактеристик") Тогда
Если Метаданные.ПланыВидовХарактеристик.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
ИначеЕсли ИмяВида = ВРег("ПланыВидовРасчета") Тогда
Если Метаданные.ПланыВидовРасчета.Найти(ИмяОбъекта) <> Неопределено Тогда
ОбъектНайден = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если Не ОбъектНайден Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Объект метаданных ""%1"" не существует.'"), Имя);
КонецЕсли;
// АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно.
УстановитьБезопасныйРежим(Истина);
Модуль = Вычислить(Имя);
// АПК:488-вкл
Возврат Модуль;
КонецФункции
#КонецОбласти
#Область Данные
Функция СравниваемыеКолонки(Знач КоллекцияСтрок, Знач ИменаКолонок, Знач ИсключаяКолонки)
Если ПустаяСтрока(ИменаКолонок) Тогда
ТипКоллекции = ТипЗнч(КоллекцияСтрок);
ЭтоСписокЗначений = (ТипКоллекции = Тип("СписокЗначений"));
ЭтоТаблицаЗначений = (ТипКоллекции = Тип("ТаблицаЗначений"));
ЭтоКоллекцияКлючИЗначение = (ТипКоллекции = Тип("Соответствие"))
Или (ТипКоллекции = Тип("Структура"))
Или (ТипКоллекции = Тип("ФиксированноеСоответствие"))
Или (ТипКоллекции = Тип("ФиксированнаяСтруктура"));
СравниваемыеКолонки = Новый Массив;
Если ЭтоТаблицаЗначений Тогда
Для Каждого Колонка Из КоллекцияСтрок.Колонки Цикл
СравниваемыеКолонки.Добавить(Колонка.Имя);
КонецЦикла;
ИначеЕсли ЭтоСписокЗначений Тогда
СравниваемыеКолонки.Добавить("Значение");
СравниваемыеКолонки.Добавить("Картинка");
СравниваемыеКолонки.Добавить("Пометка");
СравниваемыеКолонки.Добавить("Представление");
ИначеЕсли ЭтоКоллекцияКлючИЗначение Тогда
СравниваемыеКолонки.Добавить("Ключ");
СравниваемыеКолонки.Добавить("Значение");
Иначе
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Для коллекции типа %1 укажите имена полей, по которым производится сравнение в %2.'"),
ТипКоллекции, "ОбщегоНазначения.КоллекцииИдентичны");
КонецЕсли;
Иначе
СравниваемыеКолонки = СтрРазделить(СтрЗаменить(ИменаКолонок, " ", ""), ",");
КонецЕсли;
// Вычитаем исключаемые поля
Если Не ПустаяСтрока(ИсключаяКолонки) Тогда
ИсключаяКолонки = СтрРазделить(СтрЗаменить(ИсключаяКолонки, " ", ""), ",");
СравниваемыеКолонки = ОбщегоНазначенияКлиентСервер.РазностьМассивов(СравниваемыеКолонки, ИсключаяКолонки);
КонецЕсли;
Возврат СравниваемыеКолонки;
КонецФункции
Функция СравнитьСУчетомПоследовательности(Знач КоллекцияСтрок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.'"),
Строка(ТипДанных), "ОбщегоНазначения.ФиксированныеДанные");
КонецПроцедуры
Функция РазмерСтрокиВБайтах(Знач Строка)
Возврат ПолучитьДвоичныеДанныеИзСтроки(Строка, "UTF-8").Размер();
КонецФункции
#Область СкопироватьРекурсивно
Функция СкопироватьСтруктуру(СтруктураИсточник, ФиксироватьДанные)
СтруктураРезультат = Новый Структура;
Для Каждого КлючИЗначение Из СтруктураИсточник Цикл
СтруктураРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные));
КонецЦикла;
Если ФиксироватьДанные = Истина
Или ФиксироватьДанные = Неопределено
И ТипЗнч(СтруктураИсточник) = Тип("ФиксированнаяСтруктура") Тогда
Возврат Новый ФиксированнаяСтруктура(СтруктураРезультат);
КонецЕсли;
Возврат СтруктураРезультат;
КонецФункции
Функция СкопироватьСоответствие(СоответствиеИсточник, ФиксироватьДанные)
СоответствиеРезультат = Новый Соответствие;
Для Каждого КлючИЗначение Из СоответствиеИсточник Цикл
СоответствиеРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные));
КонецЦикла;
Если ФиксироватьДанные = Истина
Или ФиксироватьДанные = Неопределено
И ТипЗнч(СоответствиеИсточник) = Тип("ФиксированноеСоответствие") Тогда
Возврат Новый ФиксированноеСоответствие(СоответствиеРезультат);
КонецЕсли;
Возврат СоответствиеРезультат;
КонецФункции
Функция СкопироватьМассив(МассивИсточник, ФиксироватьДанные)
МассивРезультат = Новый Массив;
Для Каждого Элемент Из МассивИсточник Цикл
МассивРезультат.Добавить(СкопироватьРекурсивно(Элемент, ФиксироватьДанные));
КонецЦикла;
Если ФиксироватьДанные = Истина
Или ФиксироватьДанные = Неопределено
И ТипЗнч(МассивИсточник) = Тип("ФиксированныйМассив") Тогда
Возврат Новый ФиксированныйМассив(МассивРезультат);
КонецЕсли;
Возврат МассивРезультат;
КонецФункции
Функция СкопироватьСписокЗначений(СписокИсточник, ФиксироватьДанные)
СписокРезультат = Новый СписокЗначений;
Для Каждого ЭлементСписка Из СписокИсточник Цикл
СписокРезультат.Добавить(
СкопироватьРекурсивно(ЭлементСписка.Значение, ФиксироватьДанные),
ЭлементСписка.Представление,
ЭлементСписка.Пометка,
ЭлементСписка.Картинка);
КонецЦикла;
Возврат СписокРезультат;
КонецФункции
Процедура СкопироватьЗначенияТаблицыЗначений(ТаблицаЗначений, ФиксироватьДанные)
Для Каждого СтрокаТаблицыЗначений Из ТаблицаЗначений Цикл
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
СтрокаТаблицыЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаТаблицыЗначений[Колонка.Имя], ФиксироватьДанные);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура СкопироватьЗначенияСтрокиДереваЗначений(СтрокиДереваЗначений, ФиксироватьДанные);
Для Каждого СтрокаДереваЗначений Из СтрокиДереваЗначений Цикл
Для Каждого Колонка Из СтрокаДереваЗначений.Владелец().Колонки Цикл
СтрокаДереваЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаДереваЗначений[Колонка.Имя], ФиксироватьДанные);
КонецЦикла;
СкопироватьЗначенияСтрокиДереваЗначений(СтрокаДереваЗначений.Строки, ФиксироватьДанные);
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#КонецОбласти
#Область Метаданные
Процедура ПроверитьОбъектМетаданныхСуществует(ПолноеИмя)
Если ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) = Неопределено Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неизвестный тип объекта метаданных ""%1"".'"), ПолноеИмя);
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область ХранилищеНастроек
Процедура ХранилищеСохранить(МенеджерХранилища, КлючОбъекта, КлючНастроек, Настройки,
ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения)
Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
Возврат;
КонецЕсли;
МенеджерХранилища.Сохранить(КлючОбъекта, КлючНастроек(КлючНастроек), Настройки,
ОписаниеНастроек, ИмяПользователя);
Если ОбновитьПовторноИспользуемыеЗначения Тогда
ОбновитьПовторноИспользуемыеЗначения();
КонецЕсли;
КонецПроцедуры
Функция ХранилищеЗагрузить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию,
ОписаниеНастроек, ИмяПользователя)
Результат = Неопределено;
Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
Результат = МенеджерХранилища.Загрузить(КлючОбъекта, КлючНастроек(КлючНастроек),
ОписаниеНастроек, ИмяПользователя);
КонецЕсли;
Если Результат = Неопределено Тогда
Результат = ЗначениеПоУмолчанию;
Иначе
УстановитьПривилегированныйРежим(Истина);
Если ОчиститьНесуществующиеСсылки(Результат) Тогда
Результат = ЗначениеПоУмолчанию;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
// Удаляет из переданной коллекции ссылки, ссылающиеся на несуществующие данные в информационной базе.
// Не очищает переданное значение, если в нем передана несуществующая ссылка, а возвращает Ложь.
//
// Параметры:
// Значение - ЛюбаяСсылка
// - Произвольный - проверяемое значение или коллекция.
//
// Возвращаемое значение:
// Булево - Истина, если Значение ссылочного типа и объект не существует в информационной базе.
// Ложь, если Значение не ссылочного типа или объект существует.
//
Функция ОчиститьНесуществующиеСсылки(Значение)
Тип = ТипЗнч(Значение);
Если Тип = Тип("Неопределено")
Или Тип = Тип("Булево")
Или Тип = Тип("Строка")
Или Тип = Тип("Число")
Или Тип = Тип("Дата") Тогда // Оптимизация - часто используемые примитивные типы.
Возврат Ложь; // Не ссылка.
ИначеЕсли Тип = Тип("Массив") Тогда
Количество = Значение.Количество();
Для Номер = 1 По Количество Цикл
ОбратныйИндекс = Количество - Номер;
// @skip-check query-in-loop - выборка ссылок из разных таблиц.
Если ОчиститьНесуществующиеСсылки(Значение[ОбратныйИндекс]) Тогда
Значение.Удалить(ОбратныйИндекс);
КонецЕсли;
КонецЦикла;
Возврат Ложь; // Не ссылка.
ИначеЕсли Тип = Тип("Структура")
Или Тип = Тип("Соответствие") Тогда
Для Каждого КлючИЗначение Из Значение Цикл
// @skip-check query-in-loop - выборка ссылок из разных таблиц.
Если ОчиститьНесуществующиеСсылки(КлючИЗначение.Значение) Тогда
Значение.Вставить(КлючИЗначение.Ключ, Неопределено);
КонецЕсли;
КонецЦикла;
Возврат Ложь; // Не ссылка.
ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(Тип)
Или Справочники.ТипВсеСсылки().СодержитТип(Тип)
Или Перечисления.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыСчетов.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(Тип)
Или ПланыОбмена.ТипВсеСсылки().СодержитТип(Тип)
Или БизнесПроцессы.ТипВсеСсылки().СодержитТип(Тип)
Или Задачи.ТипВсеСсылки().СодержитТип(Тип) Тогда
// Ссылочный тип, исключая ТочкаМаршрутаБизнесПроцессаСсылка.
Если Значение.Пустая() Тогда
Возврат Ложь; // Ссылка пустая.
КонецЕсли;
Возврат ЗначениеРеквизитаОбъекта(Значение, "Ссылка") = Неопределено;
Иначе
Возврат Ложь; // Не ссылка.
КонецЕсли;
КонецФункции
Процедура ХранилищеУдалить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ИмяПользователя)
Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
МенеджерХранилища.Удалить(КлючОбъекта, КлючНастроек(КлючНастроек), ИмяПользователя);
КонецЕсли;
КонецПроцедуры
// Возвращает строку ключа настроек, не превышающую допустимую длину 128 символов.
// Если указанная строка превышает 128, тогда вместо символов сверх 96 символов
// добавляется их хеш-сумма по алгоритму MD5 размером 32 символа.
//
// Параметры:
// Строка - Строка - строка произвольной длины.
//
// Возвращаемое значение:
// Строка - не более 128 символов.
//
Функция КлючНастроек(Знач Строка)
Возврат СократитьСтрокуКонтрольнойСуммой(Строка, 128);
КонецФункции
#КонецОбласти
#Область БезопасноеХранилище
Функция ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные)
ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанных";
Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() И ОбщиеДанные <> Истина Тогда
ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных";
КонецЕсли;
ТекстЗапроса =
"ВЫБРАТЬ
| БезопасноеХранилищеДанных.Владелец КАК ВладелецДанных,
| БезопасноеХранилищеДанных.Данные КАК Данные
|ИЗ
| #ИмяБезопасногоХранилищаДанных КАК БезопасноеХранилищеДанных
|ГДЕ
| БезопасноеХранилищеДанных.Владелец В (&Владельцы)";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяБезопасногоХранилищаДанных", ИмяБезопасногоХранилищаДанных);
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("Владельцы", Владельцы);
РезультатЗапроса = Запрос.Выполнить().Выбрать();
Результат = Новый Соответствие();
НаборДанныхКлюча = ?(ЗначениеЗаполнено(Ключи) И СтрНайти(Ключи, ","), Новый Структура(Ключи), Неопределено);
Для Каждого ВладелецДанных Из Владельцы Цикл
Результат.Вставить(ВладелецДанных, НаборДанныхКлюча);
КонецЦикла;
Пока РезультатЗапроса.Следующий() Цикл
ДанныеВладельца = Новый Структура(Ключи);
Если ЗначениеЗаполнено(РезультатЗапроса.Данные) Тогда
СохраненныеДанные = РезультатЗапроса.Данные.Получить();
Если ЗначениеЗаполнено(СохраненныеДанные) Тогда
Если ЗначениеЗаполнено(Ключи) Тогда
ВладелецДанных = Результат[РезультатЗапроса.ВладелецДанных];
ЗаполнитьЗначенияСвойств(ДанныеВладельца, СохраненныеДанные);
Иначе
ДанныеВладельца = СохраненныеДанные;
КонецЕсли;
Если Ключи <> Неопределено
И ДанныеВладельца <> Неопределено
И ДанныеВладельца.Количество() = 1 Тогда
ЗначениеПоКлючу = ?(ДанныеВладельца.Свойство(Ключи), ДанныеВладельца[Ключи], Неопределено);
Результат.Вставить(РезультатЗапроса.ВладелецДанных, ЗначениеПоКлючу);
Иначе
Результат.Вставить(РезультатЗапроса.ВладелецДанных, ДанныеВладельца);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область БезопасноеВыполнениеВнешнегоКода
// Проверяет, что переданное имя ИмяПроцедуры является именем экспортной процедуры конфигурации.
// Может использоваться для проверки, что переданная строка не содержит произвольного алгоритма
// на встроенном языке 1С:Предприятия перед использованием его в операторах Выполнить и Вычислить
// при их использовании для динамического вызова методов код конфигурации.
//
// В случае если переданная строка не является именем процедуры конфигурации, генерируется исключение.
//
// Предназначена для вызова из см. процедуру ВыполнитьМетодКонфигурации.
//
// Параметры:
// ИмяПроцедуры - Строка - проверяемое имя экспортной процедуры.
//
Процедура ПроверитьИмяПроцедурыКонфигурации(Знач ИмяПроцедуры)
ЧастиИмени = СтрРазделить(ИмяПроцедуры, ".");
Если ЧастиИмени.Количество() <> 2 И ЧастиИмени.Количество() <> 3 Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3.'"),
"ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации");
КонецЕсли;
ИмяОбъекта = ЧастиИмени[0];
Если ЧастиИмени.Количество() = 2 И Метаданные.ОбщиеМодули.Найти(ИмяОбъекта) = Неопределено Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3:
|Не существует общий модуль ""%4"".'"),
"ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации", ИмяОбъекта);
КонецЕсли;
Если ЧастиИмени.Количество() = 3 Тогда
ПолноеИмяОбъекта = ЧастиИмени[0] + "." + ЧастиИмени[1];
Попытка
Менеджер = МенеджерОбъектаПоИмени(ПолноеИмяОбъекта);
Исключение
Менеджер = Неопределено;
КонецПопытки;
Если Менеджер = Неопределено Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3:
|Не существует менеджер объекта ""%4"".'"),
"ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации", ПолноеИмяОбъекта);
КонецЕсли;
КонецЕсли;
ИмяМетодаОбъекта = ЧастиИмени[ЧастиИмени.ВГраница()];
ВременнаяСтруктура = Новый Структура;
Попытка
// Проверка того, что ИмяПроцедуры является допустимым идентификатором.
// Например: МояПроцедура.
ВременнаяСтруктура.Вставить(ИмяМетодаОбъекта);
Исключение
ЗаписьЖурналаРегистрации(НСтр("ru = 'Безопасное выполнение метода'", КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Неправильный формат параметра %1 (передано значение: ""%2"") в %3:
|Имя метода ""%4"" не соответствует требованиям образования имен процедур и функций.'"),
"ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации", ИмяМетодаОбъекта);
КонецПопытки;
КонецПроцедуры
// Возвращает менеджер объекта по имени.
// Ограничение: не обрабатываются точки маршрутов бизнес-процессов.
//
// Параметры:
// Имя - Строка - имя например, "Справочник", "Справочники", "Справочник.Организации".
//
// Возвращаемое значение:
// СправочникиМенеджер
// СправочникМенеджер
// ДокументыМенеджер
// ДокументМенеджер
// ...
//
Функция МенеджерОбъектаПоИмени(Имя)
Перем КлассОМ, ИмяОМ, Менеджер;
ЧастиИмени = СтрРазделить(Имя, ".");
Если ЧастиИмени.Количество() > 0 Тогда
КлассОМ = ВРег(ЧастиИмени[0]);
КонецЕсли;
Если ЧастиИмени.Количество() > 1 Тогда
ИмяОМ = ЧастиИмени[1];
КонецЕсли;
Если КлассОМ = "ПЛАНОБМЕНА"
Или КлассОМ = "ПЛАНЫОБМЕНА" Тогда
Менеджер = ПланыОбмена;
ИначеЕсли КлассОМ = "СПРАВОЧНИК"
Или КлассОМ = "СПРАВОЧНИКИ" Тогда
Менеджер = Справочники;
ИначеЕсли КлассОМ = "ДОКУМЕНТ"
Или КлассОМ = "ДОКУМЕНТЫ" Тогда
Менеджер = Документы;
ИначеЕсли КлассОМ = "ЖУРНАЛДОКУМЕНТОВ"
Или КлассОМ = "ЖУРНАЛЫДОКУМЕНТОВ" Тогда
Менеджер = ЖурналыДокументов;
ИначеЕсли КлассОМ = "ПЕРЕЧИСЛЕНИЕ"
Или КлассОМ = "ПЕРЕЧИСЛЕНИЯ" Тогда
Менеджер = Перечисления;
ИначеЕсли КлассОМ = "ОБЩИЙМОДУЛЬ"
Или КлассОМ = "ОБЩИЕМОДУЛИ" Тогда
Возврат ОбщийМодуль(ИмяОМ);
ИначеЕсли КлассОМ = "ОТЧЕТ"
Или КлассОМ = "ОТЧЕТЫ" Тогда
Менеджер = Отчеты;
ИначеЕсли КлассОМ = "ОБРАБОТКА"
Или КлассОМ = "ОБРАБОТКИ" Тогда
Менеджер = Обработки;
ИначеЕсли КлассОМ = "ПЛАНВИДОВХАРАКТЕРИСТИК"
Или КлассОМ = "ПЛАНЫВИДОВХАРАКТЕРИСТИК" Тогда
Менеджер = ПланыВидовХарактеристик;
ИначеЕсли КлассОМ = "ПЛАНСЧЕТОВ"
Или КлассОМ = "ПЛАНЫСЧЕТОВ" Тогда
Менеджер = ПланыСчетов;
ИначеЕсли КлассОМ = "ПЛАНВИДОВРАСЧЕТА"
Или КлассОМ = "ПЛАНЫВИДОВРАСЧЕТА" Тогда
Менеджер = ПланыВидовРасчета;
ИначеЕсли КлассОМ = "РЕГИСТРСВЕДЕНИЙ"
Или КлассОМ = "РЕГИСТРЫСВЕДЕНИЙ" Тогда
Менеджер = РегистрыСведений;
ИначеЕсли КлассОМ = "РЕГИСТРНАКОПЛЕНИЯ"
Или КлассОМ = "РЕГИСТРЫНАКОПЛЕНИЯ" Тогда
Менеджер = РегистрыНакопления;
ИначеЕсли КлассОМ = "РЕГИСТРБУХГАЛТЕРИИ"
Или КлассОМ = "РЕГИСТРЫБУХГАЛТЕРИИ" Тогда
Менеджер = РегистрыБухгалтерии;
ИначеЕсли КлассОМ = "РЕГИСТРРАСЧЕТА"
Или КлассОМ = "РЕГИСТРЫРАСЧЕТА" Тогда
Если ЧастиИмени.Количество() < 3 Тогда
// Регистр расчета
Менеджер = РегистрыРасчета;
Иначе
КлассПодчиненногоОМ = ВРег(ЧастиИмени[2]);
Если ЧастиИмени.Количество() > 3 Тогда
ИмяПодчиненногоОМ = ЧастиИмени[3];
КонецЕсли;
Если КлассПодчиненногоОМ = "ПЕРЕРАСЧЕТ"
Или КлассПодчиненногоОМ = "ПЕРЕРАСЧЕТЫ" Тогда
// Перерасчет
Попытка
Менеджер = РегистрыРасчета[ИмяОМ].Перерасчеты;
ИмяОМ = ИмяПодчиненногоОМ;
Исключение
Менеджер = Неопределено;
КонецПопытки;
КонецЕсли;
КонецЕсли;
ИначеЕсли КлассОМ = "БИЗНЕСПРОЦЕСС"
Или КлассОМ = "БИЗНЕСПРОЦЕССЫ" Тогда
Менеджер = БизнесПроцессы;
ИначеЕсли КлассОМ = "ЗАДАЧА"
Или КлассОМ = "ЗАДАЧИ" Тогда
Менеджер = Задачи;
ИначеЕсли КлассОМ = "КОНСТАНТА"
Или КлассОМ = "КОНСТАНТЫ" Тогда
Менеджер = Константы;
ИначеЕсли КлассОМ = "ПОСЛЕДОВАТЕЛЬНОСТЬ"
Или КлассОМ = "ПОСЛЕДОВАТЕЛЬНОСТИ" Тогда
Менеджер = Последовательности;
КонецЕсли;
Если Менеджер <> Неопределено Тогда
Если ЗначениеЗаполнено(ИмяОМ) Тогда
Попытка
Возврат Менеджер[ИмяОМ];
Исключение
Менеджер = Неопределено;
КонецПопытки;
Иначе
Возврат Менеджер;
КонецЕсли;
КонецЕсли;
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не удалось получить менеджер для объекта ""%1""'"), Имя);
КонецФункции
// Вызвать экспортную функцию по имени с уровнем привилегий конфигурации.
// При включении профилей безопасности для вызова оператора Выполнить() используется
// переход в безопасный режим с профилем безопасности, используемом для информационной базы
// (если выше по стеку не был установлен другой безопасный режим).
//
// Параметры:
// ИмяМетода - Строка - имя экспортной функции в формате
// <имя объекта>.<имя процедуры>, где <имя объекта> - это
// общий модуль или модуль менеджера объекта.
// Параметры - Массив - параметры передаются в функцию <ИмяМетода>
// в порядке расположения элементов массива.
//
// Возвращаемое значение:
// Произвольный - результат вызываемой функции.
//
Функция ВызватьФункциюКонфигурации(Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт
ПроверитьИмяПроцедурыКонфигурации(ИмяМетода);
Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме");
Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности()
И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда
ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы();
Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда
УстановитьБезопасныйРежим(ПрофильИнформационнойБазы);
Если БезопасныйРежим() = Истина Тогда
УстановитьБезопасныйРежим(Ложь);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ПараметрыСтрока = "";
Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда
Для Индекс = 0 По Параметры.ВГраница() Цикл
ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],";
КонецЦикла;
ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1);
КонецЕсли;
Возврат Вычислить(ИмяМетода + "(" + ПараметрыСтрока + ")"); // АПК:488 Исполняемый код безопасен.
КонецФункции
// Вызвать экспортную функцию объекта встроенного языка по имени.
// При включении профилей безопасности для вызова оператора Выполнить() используется
// переход в безопасный режим с профилем безопасности, используемом для информационной базы
// (если выше по стеку не был установлен другой безопасный режим).
//
// Параметры:
// Объект - Произвольный - объект встроенного языка 1С:Предприятия, содержащий методы (например, ОбработкаОбъект).
// ИмяМетода - Строка - имя экспортной функции модуля объекта обработки.
// Параметры - Массив - параметры передаются в функцию <ИмяМетода>
// в порядке расположения элементов массива.
//
// Возвращаемое значение:
// Произвольный - результат вызываемой функции.
//
Функция ВызватьФункциюОбъекта(Знач Объект, Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт
// Проверка имени метода на корректность.
Попытка
Тест = Новый Структура;
Тест.Вставить(ИмяМетода, ИмяМетода);
Исключение
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Некорректное значение параметра %1 (%2) в %3.'"),
"ИмяМетода", ИмяМетода, "ОбщегоНазначения.ВыполнитьМетодОбъекта");
КонецПопытки;
Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда
МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме");
Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности()
И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда
МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме");
ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы();
Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда
УстановитьБезопасныйРежим(ПрофильИнформационнойБазы);
Если БезопасныйРежим() = Истина Тогда
УстановитьБезопасныйРежим(Ложь);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
ПараметрыСтрока = "";
Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда
Для Индекс = 0 По Параметры.ВГраница() Цикл
ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],";
КонецЦикла;
ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1);
КонецЕсли;
Возврат Вычислить("Объект." + ИмяМетода + "(" + ПараметрыСтрока + ")"); // АПК:488 Исполняемый код безопасен.
КонецФункции
#КонецОбласти
#Область ВнешниеКомпоненты
Процедура ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение)
Если МакетСуществует(Местоположение) Тогда
Возврат;
КонецЕсли;
Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда
МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный");
МодульВнешниеКомпонентыСлужебный.ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение);
Иначе
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Указан несуществующий макет ""%1"" при подключении внешней компоненты ""%2"".'"),
Местоположение, Идентификатор);
КонецЕсли;
КонецПроцедуры
Функция МакетСуществует(ПолноеИмяМакета)
Макет = Метаданные.НайтиПоПолномуИмени(ПолноеИмяМакета);
Если ТипЗнч(Макет) = Тип("ОбъектМетаданных") Тогда
Шаблон = Новый Структура("ТипМакета");
ЗаполнитьЗначенияСвойств(Шаблон, Макет);
ТипМакета = Неопределено;
Если Шаблон.Свойство("ТипМакета", ТипМакета) Тогда
Возврат ТипМакета <> Неопределено;
КонецЕсли;
КонецЕсли;
Возврат Ложь;
КонецФункции
#КонецОбласти
#Область ТекущееОкружение
Функция НомерСборкиПоТекущейВерсииПлатформы(НомераСборокСтрокой)
НомераСборок = СтрРазделить(НомераСборокСтрокой, ";", Истина);
СборкиПоВерсиям = Новый Соответствие;
Для Каждого НомерСборки Из НомераСборок Цикл
НомерВерсии = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(НомерСборки);
СборкиПоВерсиям.Вставить(СокрЛП(НомерВерсии), СокрЛП(НомерСборки));
КонецЦикла;
СистемнаяИнформация = Новый СистемнаяИнформация;
ТекущаяВерсия = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения);
Результат = СборкиПоВерсиям[ТекущаяВерсия];
Если Не ЗначениеЗаполнено(Результат) Тогда
Результат = НомераСборок[0];
КонецЕсли;
Возврат Результат;
КонецФункции
// Ниже этой версии БСП может запуститься и показать окно с рекомендациями, если она выше чем в МинимальнаяВерсияПлатформыДляЗапуска.
Функция МинимальнаяВерсияПлатформы() Экспорт // АПК:581 - экспортная, так как используется при тестировании.
ВерсияРежимаСовместимости = ВерсияРежимаСовместимости();
ПоддерживаемыеВерсииПлатформы = ПоддерживаемыеВерсииПлатформы();
НайденнаяВерсия = ПоддерживаемыеВерсииПлатформы.НайтиПоЗначению(ВерсияРежимаСовместимости);
Если НайденнаяВерсия = Неопределено Тогда
НайденнаяВерсия = ПоддерживаемыеВерсииПлатформы[ПоддерживаемыеВерсииПлатформы.Количество() - 1];
КонецЕсли;
НомераСборок = НайденнаяВерсия.Представление;
Возврат НомераСборок;
КонецФункции
// Ниже этой версии БСП не может запуститься и показать окно с рекомендациями.
Функция МинимальнаяВерсияПлатформыДляЗапуска() Экспорт
Возврат "8.3.21.1622; 8.3.22.1704";
КонецФункции
// Возвращаемое значение:
// СписокЗначений:
// * Значение - Строка - поддерживаемый номер версии (режим совместимости);
// * Представление - Строка - минимальные номера сборок платформы, разделитель - точка с запятой.
//
Функция ПоддерживаемыеВерсииПлатформы() Экспорт
ПоддерживаемыеВерсииПлатформы = Новый СписокЗначений;
ПоддерживаемыеВерсииПлатформы.Добавить("8.3.21", "8.3.21.1775; 8.3.22.1923");
ПоддерживаемыеВерсииПлатформы.Добавить("8.3.22", "8.3.22.2355; 8.3.23.2011; 8.3.24.1304");
ПоддерживаемыеВерсииПлатформы.Добавить("8.3.23", "8.3.23.2011; 8.3.24.1304");
ПоддерживаемыеВерсииПлатформы.Добавить("8.3.24", "8.3.24.1304");
Возврат ПоддерживаемыеВерсииПлатформы;
КонецФункции
Функция ВерсияРежимаСовместимости() Экспорт
СистемнаяИнформация = Новый СистемнаяИнформация();
РежимСовместимости = Метаданные.РежимСовместимости;
Если РежимСовместимости = Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда
ВерсияРежимаСовместимости = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения);
Иначе
ВерсияРежимаСовместимости = СтрСоединить(СтрРазделить(РежимСовместимости, СтрСоединить(СтрРазделить(РежимСовместимости, "1234567890", Ложь), ""), Ложь), ".");
КонецЕсли;
Возврат ВерсияРежимаСовместимости;
КонецФункции
// Выполняет проверку правильности заполнения минимальной и рекомендуемой версии платформы.
//
// Параметры:
// Минимальная - Строка - номер версия платформы.
// Рекомендуемая - Строка - номер версия платформы.
//
// Возвращаемое значение:
// Булево - Истина, если минимальная и рекомендуемая версия платформы заполнена неправильно.
//
Функция МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая)
// Минимальная версия платформы должна быть заполнена.
Если ПустаяСтрока(Минимальная) Тогда
Возврат Истина;
КонецЕсли;
// Минимальная версия платформы, заданная в конфигурации, не должна быть меньше минимальной версии платформы,
// заданной в библиотеке.
МинимальнаяБСП = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы());
Если Не ЭтоВерсияЗащищенногоПрограммногоКомплекса(Минимальная)
И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(МинимальнаяБСП, Минимальная) > 0 Тогда
Возврат Истина;
КонецЕсли;
// Минимальная версия платформы не должны быть больше рекомендуемой.
Возврат Не ПустаяСтрока(Минимальная)
И Не ПустаяСтрока(Рекомендуемая)
И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Минимальная, Рекомендуемая) > 0;
КонецФункции
Функция НедопустимыеВерсииПлатформы() Экспорт
Возврат "";
КонецФункции
Функция ЭтоВерсияЗащищенногоПрограммногоКомплекса(Версия)
Версии = Новый Массив;
Версии.Добавить("8.3.21.1676");
Версии.Добавить("8.3.21.1901");
Возврат Версии.Найти(Версия) <> Неопределено;
КонецФункции
// Для функции ОбщиеПараметрыБазовойФункциональности.
Процедура УточнитьВерсиюПлатформы(ОбщиеПараметры)
СистемнаяИнформация = Новый СистемнаяИнформация;
НоваяСборка = НоваяСборка(СистемнаяИнформация.ВерсияПриложения);
Если Не ЗначениеЗаполнено(НоваяСборка) Тогда
НоваяРекомендуемаяСборка = НоваяСборка(ОбщиеПараметры.МинимальнаяВерсияПлатформы);
Если ЗначениеЗаполнено(НоваяРекомендуемаяСборка) Тогда
МинимальнаяСборка = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы());
ОбщиеПараметры.МинимальнаяВерсияПлатформы = МинимальнаяСборка;
ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = МинимальнаяСборка;
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.РекомендуемаяВерсияПлатформы, НоваяРекомендуемаяСборка) < 0 Тогда
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяРекомендуемаяСборка;
КонецЕсли;
КонецЕсли;
ИначеЕсли ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.МинимальнаяВерсияПлатформы, НоваяСборка) < 0 Тогда
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяСборка;
ОбщиеПараметры.МинимальнаяВерсияПлатформы = НоваяСборка;
ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = НоваяСборка;
ОбщиеПараметры.РаботаВПрограммеЗапрещена = Истина;
КонецЕсли;
КонецПроцедуры
// Для процедуры УточнитьВерсиюПлатформы.
Функция НоваяСборка(ТекущаяСборка)
Если СтрНайти("8.3.22.1672,8.3.22.1603", ТекущаяСборка) Тогда
Возврат "8.3.22.1709";
ИначеЕсли СтрНайти("8.3.21.1607,8.3.21.1508,8.3.21.1484", ТекущаяСборка) Тогда
Возврат "8.3.21.1624";
КонецЕсли;
Возврат "";
КонецФункции
// Локализация
// Параметры:
// ОбщиеПараметры - см. ОбщиеПараметрыБазовойФункциональности
//
Процедура УточнитьМинимальнуюВерсиюПлатформыИзСервиса(ОбщиеПараметры)
Если Не ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеОбновленийПрограммы") Тогда
Возврат;
КонецЕсли;
// Проверка версии БИП начиная с которой появился программный интерфейс
МодульИнтернетПоддержкаПользователейКлиентСервер = ОбщийМодуль("ИнтернетПоддержкаПользователейКлиентСервер");
ВерсияБИП = МодульИнтернетПоддержкаПользователейКлиентСервер.ВерсияБиблиотеки();
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ВерсияБИП, "2.7.1.35") <= 0 Тогда
Возврат;
КонецЕсли;
Попытка
МодульПолучениеОбновленийПрограммы = ОбщийМодуль("ПолучениеОбновленийПрограммы");
ИнформацияОВерсияхПлатформы = МодульПолучениеОбновленийПрограммы.ИнформацияОВерсияхПлатформы();
// Контроль заполнения версий платформы по данным сервиса
Если ПустаяСтрока(ИнформацияОВерсияхПлатформы.МинимальнаяВерсияПлатформы)
И ПустаяСтрока(ИнформацияОВерсияхПлатформы.РекомендуемаяВерсияПлатформы) Тогда
Возврат;
КонецЕсли;
Минимальная = НомерСборкиПоТекущейВерсииПлатформы(ИнформацияОВерсияхПлатформы.МинимальнаяВерсияПлатформы);
Рекомендуемая = НомерСборкиПоТекущейВерсииПлатформы(ИнформацияОВерсияхПлатформы.РекомендуемаяВерсияПлатформы);
Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда
МодульПолучениеОбновленийПрограммы.УдалитьИнформациюОВерсияхПлатформы();
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Минимальная и рекомендуемая версии платформы ""1С:Предприятие"", полученные с сервиса обновления программ, не соответствуют следующим требованиям:
| - минимальная версия должна быть заполнена;
| - минимальная версия не должна быть меньше минимальной версии БСП (см. %1);
| - минимальная версия не должна быть меньше рекомендуемой версии.
|Минимальная версия сервиса обновления программ: %2
|Минимальная версия БСП: %3
|Рекомендуемая версия сервиса обновления программ: %4
|
|Минимальная и рекомендуемая версия платформы ""1С:Предприятие"" установлена по данным см. %5.
|Минимальная версия: %6
|Рекомендуемая версия: %7'",
КодОсновногоЯзыка()),
"ОбщегоНазначения.МинимальнаяВерсияПлатформы", Минимальная, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()),
Рекомендуемая, "ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности",
ОбщиеПараметры.МинимальнаяВерсияПлатформы, ОбщиеПараметры.РекомендуемаяВерсияПлатформы);
ЗаписьЖурналаРегистрации(НСтр("ru = 'Базовая функциональность'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,,
ТекстСообщения);
Возврат;
КонецЕсли;
ОбщиеПараметры.МинимальнаяВерсияПлатформы = Минимальная;
ОбщиеПараметры.РекомендуемаяВерсияПлатформы = Рекомендуемая;
Исключение
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось изменить минимальную и рекомендуемую версию платформы ""1С:Предприятие"", полученную с сервиса обновления программ, по причине:
|%1'",
КодОсновногоЯзыка()), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ЗаписьЖурналаРегистрации(НСтр("ru = 'Базовая функциональность'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,,
ТекстСообщения);
КонецПопытки;
КонецПроцедуры
// Конец Локализация
#КонецОбласти
#КонецОбласти
#КонецЕсли
`;
// Reset `lastIndex` if this regex is defined globally
// regex.lastIndex = 0;
let m;
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`Found match, group ${groupIndex}: ${match}`);
});
}
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for JavaScript, please visit: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions