using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main()
{
string pattern = @"(?<=(?:\/\/){1}[ [ruА-Яа-яёЁ])((?:[ruА-Яа-яёЁ\s\d \,\.\:\-\""\&\d\*\;\(\)\.\,\'\=\<\>\!-\?\@^#])*?)$(?:[\b\t\s]+((?:Функция|Процедура)\s+(?:[\w\d]|[А-Яа-я])+\([\w\W]*?\)\s*(?:Экспорт)?))";
string input = @"///////////////////////////////////////////////////////////////////////////////////////////////////////
// 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 = 'Базовая функциональность'"", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,,
ТекстСообщения);
КонецПопытки;
КонецПроцедуры
// Конец Локализация
#КонецОбласти
#КонецОбласти
#КонецЕсли
";
RegexOptions options = RegexOptions.Multiline | RegexOptions.IgnoreCase;
foreach (Match m in Regex.Matches(input, pattern, options))
{
Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
}
}
}
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 C#, please visit: https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex(v=vs.110).aspx