Regular Expressions 101

Save & Share

Flavor

  • PCRE2 (PHP >=7.3)
  • PCRE (PHP <7.3)
  • ECMAScript (JavaScript)
  • Python
  • Golang
  • Java 8
  • .NET 7.0 (C#)
  • Rust
  • Regex Flavor Guide

Function

  • Match
  • Substitution
  • List
  • Unit Tests

Tools

Sponsors
There are currently no sponsors. Become a sponsor today!
An explanation of your regex will be automatically generated as you type.
Detailed match information will be displayed here automatically.
  • All Tokens
  • Common Tokens
  • General Tokens
  • Anchors
  • Meta Sequences
  • Quantifiers
  • Group Constructs
  • Character Classes
  • Flags/Modifiers
  • Substitution
  • A single character of: a, b or c
    [abc]
  • A character except: a, b or c
    [^abc]
  • A character in the range: a-z
    [a-z]
  • A character not in the range: a-z
    [^a-z]
  • A character in the range: a-z or A-Z
    [a-zA-Z]
  • Any single character
    .
  • Alternate - match either a or b
    a|b
  • Any whitespace character
    \s
  • Any non-whitespace character
    \S
  • Any digit
    \d
  • Any non-digit
    \D
  • Any word character
    \w
  • Any non-word character
    \W
  • Non-capturing group
    (?:...)
  • Capturing group
    (...)
  • Zero or one of a
    a?
  • Zero or more of a
    a*
  • One or more of a
    a+
  • Exactly 3 of a
    a{3}
  • 3 or more of a
    a{3,}
  • Between 3 and 6 of a
    a{3,6}
  • Start of string
    ^
  • End of string
    $
  • A word boundary
    \b
  • Non-word boundary
    \B

Regular Expression
No Match

r"
"
gmi

Test String

Code Generator

Generated Code

re = /(?<=(?:\/\/){1}[ [ruА-Яа-яёЁ])((?:[ruА-Яа-яёЁ\s\d \,\.\:\-\"\&\d\*\;\(\)\.\,\'\=\<\>\!-\?\@^#])*?)$(?:[\b\t\s]+((?:Функция|Процедура)\s+(?:[\w\d]|[А-Яа-я])+\([\w\W]*?\)\s*(?:Экспорт)?))/mi str = '/////////////////////////////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2023, ООО 1С-Софт // Все права защищены. Эта программа и сопроводительные материалы предоставляются // в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0) // Текст лицензии доступен по ссылке: // https://creativecommons.org/licenses/by/4.0/legalcode /////////////////////////////////////////////////////////////////////////////////////////////////////// #Область ПрограммныйИнтерфейс #Область ОповещениеПользователя // Формирует и выводит сообщение, которое может быть связано с элементом управления формы. // // В фоновом задании длительной операции, если вызов выполнен вне транзакции, // сообщение записывается в служебный регистр и отправляется сразу на клиент, // если подключена система взаимодействия. // В конце фонового задания длительной операции, а также при отправке прогресса, // все сообщения извлекаются из очереди сообщений фонового задания, // записываются в служебный регистр и отправляются сразу на клиент, // если подключена система взаимодействия. // // АПК:142-выкл 4 необязательных параметра для совместимости // с устаревшей процедурой ОбщегоНазначенияКлиентСервер.СообщитьПользователю. // // Параметры: // ТекстСообщенияПользователю - Строка - текст сообщения. // КлючДанных - ЛюбаяСсылка - объект или ключ записи информационной базы, к которому это сообщение относится. // Поле - Строка - наименование реквизита формы. // ПутьКДанным - Строка - путь к данным (путь к реквизиту формы). // Отказ - Булево - выходной параметр, всегда устанавливается в значение Истина. // // Пример: // // 1. Для вывода сообщения у поля управляемой формы, связанного с реквизитом объекта: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = \'Сообщение об ошибке.\'"), , // "ПолеВРеквизитеФормыОбъект", // "Объект"); // // Альтернативный вариант использования в форме объекта: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = \'Сообщение об ошибке.\'"), , // "Объект.ПолеВРеквизитеФормыОбъект"); // // 2. Для вывода сообщения рядом с полем управляемой формы, связанным с реквизитом формы: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = \'Сообщение об ошибке.\'"), , // "ИмяРеквизитаФормы"); // // 3. Для вывода сообщения связанного с объектом информационной базы: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = \'Сообщение об ошибке.\'"), ОбъектИнформационнойБазы, "Ответственный",,Отказ); // // 4. Для вывода сообщения по ссылке на объект информационной базы: // ОбщегоНазначения.СообщитьПользователю( // НСтр("ru = \'Сообщение об ошибке.\'"), Ссылка, , , Отказ); // // Случаи некорректного использования: // 1. Передача одновременно параметров КлючДанных и ПутьКДанным. // 2. Передача в параметре КлючДанных значения типа отличного от допустимого. // 3. Установка ссылки без установки поля (и/или пути к данным). // Процедура СообщитьПользователю(Знач ТекстСообщенияПользователю, Знач КлючДанных = Неопределено, Знач Поле = "", Знач ПутьКДанным = "", Отказ = Ложь) Экспорт ЭтоОбъект = Ложь; Если КлючДанных <> Неопределено И XMLТипЗнч(КлючДанных) <> Неопределено Тогда ТипЗначенияСтрокой = XMLТипЗнч(КлючДанных).ИмяТипа; ЭтоОбъект = СтрНайти(ТипЗначенияСтрокой, "Object.") > 0; КонецЕсли; Сообщение = ОбщегоНазначенияСлужебныйКлиентСервер.СообщениеПользователю(ТекстСообщенияПользователю, КлючДанных, Поле, ПутьКДанным, Отказ, ЭтоОбъект); #Если НЕ МобильныйАвтономныйСервер Тогда Если СтандартныеПодсистемыПовтИсп.ЭтоСеансДлительнойОперации() И Не ТранзакцияАктивна() Тогда ДлительныеОперации.ОтправитьОповещениеКлиенту("СообщениеПользователю", Сообщение); Иначе Сообщение.Сообщить(); КонецЕсли; #Иначе Сообщение.Сообщить(); #КонецЕсли КонецПроцедуры // АПК:142-вкл #КонецОбласти #Если НЕ МобильныйАвтономныйСервер Тогда #Область ДанныеВБазе //////////////////////////////////////////////////////////////////////////////// // Общие процедуры и функции для работы с данными в базе. // Возвращает структуру, содержащую значения реквизитов, прочитанные из информационной базы по ссылке на объект. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, значения реквизитов которого необходимо получить. // - Строка - полное имя предопределенного элемента, значения реквизитов которого необходимо получить. // Реквизиты - Строка - имена реквизитов, перечисленные через запятую, в формате // требований к свойствам структуры. // Например, "Код, Наименование, Родитель". // - Структура // - ФиксированнаяСтруктура - в качестве ключа передается // псевдоним поля для возвращаемой структуры с результатом, а в качестве // значения (опционально) фактическое имя поля в таблице. // Если ключ задан, а значение не определено, то имя поля берется из ключа. // Допускается указание имени поля через точку, но при этом параметр КодЯзыка для такого поля // учитываться не будет. // - Массив из Строка // - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры. // ВыбратьРазрешенные - Булево - если Истина, то запрос к объекту выполняется с учетом прав пользователя; // если есть ограничение на уровне записей, то все реквизиты вернутся со // значением Неопределено; если нет прав для работы с таблицей, то возникнет исключение; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Структура - содержит имена (ключи) и значения затребованных реквизитов. // Если в параметр Реквизиты передана пустая строка, то возвращается пустая структура. // Если в параметр Ссылка передана пустая ссылка, то возвращается структура, // соответствующая именам реквизитов со значениями Неопределено. // Если в параметр Ссылка передана ссылка несуществующего объекта (битая ссылка), // то все реквизиты вернутся со значением Неопределено. // Функция ЗначенияРеквизитовОбъекта(Ссылка, Знач Реквизиты, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт // Если передано имя предопределенного. Если ТипЗнч(Ссылка) = Тип("Строка") Тогда ПолноеИмяПредопределенногоЭлемента = Ссылка; // Вычисление ссылки по имени предопределенного. // - дополнительно выполняет проверку метаданных предопределенного, выполняется предварительно. Попытка Ссылка = ПредопределенныйЭлемент(ПолноеИмяПредопределенногоЭлемента); Исключение ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный первый параметр %1 в функции %2: |%3\'"), "Ссылка", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); ВызватьИсключение ТекстОшибки; КонецПопытки; // Разбор полного имени предопределенного. ЧастиПолногоИмени = СтрРазделить(ПолноеИмяПредопределенногоЭлемента, "."); ПолноеИмяОбъектаМетаданных = ЧастиПолногоИмени[0] + "." + ЧастиПолногоИмени[1]; // Если предопределенный не создан в ИБ, то требуется выполнить проверку доступа к объекту. // В других сценариях проверка доступа выполняется в момент исполнения запроса. Если Ссылка = Неопределено Тогда МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных); Если Не ПравоДоступа("Чтение", МетаданныеОбъекта) Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Недостаточно прав для работы с таблицей ""%1""\'"), ПолноеИмяОбъектаМетаданных); КонецЕсли; КонецЕсли; Иначе // Если передана ссылка. Попытка ПолноеИмяОбъектаМетаданных = Ссылка.Метаданные().ПолноеИмя(); Исключение ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный первый параметр %1 в функции %2: |Значение должно быть ссылкой или именем предопределенного элемента.\'"), "Ссылка", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта"); КонецПопытки; КонецЕсли; // Разбор реквизитов, если второй параметр Строка. Если ТипЗнч(Реквизиты) = Тип("Строка") Тогда Если ПустаяСтрока(Реквизиты) Тогда Возврат Новый Структура; КонецЕсли; Реквизиты = СтрРазделить(Реквизиты, ",", Ложь); Для Индекс = 0 По Реквизиты.ВГраница() Цикл Реквизиты[Индекс] = СокрЛП(Реквизиты[Индекс]); КонецЦикла; КонецЕсли; МультиязычныеРеквизиты = Новый Соответствие; СуффиксЯзыка = ""; Если ЗначениеЗаполнено(КодЯзыка) Тогда Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка); Если ЗначениеЗаполнено(СуффиксЯзыка) Тогда МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(Ссылка); КонецЕсли; КонецЕсли; КонецЕсли; // Приведение реквизитов к единому формату. СтруктураПолей = Новый Структура; Если ТипЗнч(Реквизиты) = Тип("Структура") Или ТипЗнч(Реквизиты) = Тип("ФиксированнаяСтруктура") Тогда Для Каждого КлючИЗначение Из Реквизиты Цикл СтруктураПолей.Вставить(КлючИЗначение.Ключ, СокрЛП(КлючИЗначение.Значение)); КонецЦикла; ИначеЕсли ТипЗнч(Реквизиты) = Тип("Массив") Или ТипЗнч(Реквизиты) = Тип("ФиксированныйМассив") Тогда Для Каждого Реквизит Из Реквизиты Цикл Реквизит = СокрЛП(Реквизит); Попытка ПсевдонимПоля = СтрЗаменить(Реквизит, ".", ""); СтруктураПолей.Вставить(ПсевдонимПоля, Реквизит); Исключение // Если псевдоним не является ключом. // Поиск ошибки доступности полей. Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты); Если Результат.Ошибка Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: %3\'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Результат.ОписаниеОшибки); КонецЕсли; // Не удалось распознать ошибку, проброс первичной ошибки. ВызватьИсключение; КонецПопытки; КонецЦикла; Иначе ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный тип второго параметра %1 в функции %2: %3.\'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Строка(ТипЗнч(Реквизиты))); КонецЕсли; // Подготовка результата (после выполнения запроса переопределится). Результат = Новый Структура; // Формирование текста запроса к выбираемым полям. ТекстЗапросаПолей = ""; Для каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); ПсевдонимПоля = КлючИЗначение.Ключ; Если МультиязычныеРеквизиты[ИмяПоля] <> Неопределено Тогда ИмяПоля = ИмяПоля + СуффиксЯзыка; КонецЕсли; ТекстЗапросаПолей = ТекстЗапросаПолей + ?(ПустаяСтрока(ТекстЗапросаПолей), "", ",") + " | " + ИмяПоля + " КАК " + ПсевдонимПоля; // Предварительное добавление поля по псевдониму в возвращаемый результат. Результат.Вставить(ПсевдонимПоля); КонецЦикла; // Если предопределенного нет в ИБ. // - приведение результата к отсутствию объекта в ИБ или передаче пустой ссылки. Если Ссылка = Неопределено Тогда Возврат Результат; КонецЕсли; Если Тип("Структура") = ТипЗнч(Реквизиты) Или Тип("ФиксированнаяСтруктура") = ТипЗнч(Реквизиты) Тогда Реквизиты = Новый Массив; Для Каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); Реквизиты.Добавить(ИмяПоля); КонецЦикла; КонецЕсли; РеквизитыЧерезТочку = Новый Массив; Для Индекс = -Реквизиты.ВГраница() По 0 Цикл ИмяПоля = Реквизиты[-Индекс]; Если СтрНайти(ИмяПоля, ".") Тогда РеквизитыЧерезТочку.Добавить(ИмяПоля); Реквизиты.Удалить(-Индекс); КонецЕсли; КонецЦикла; Если ЗначениеЗаполнено(Реквизиты) Тогда ЗначенияРеквизитовОбъекта = ЗначенияРеквизитовОбъектов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Ссылка), Реквизиты, ВыбратьРазрешенные, КодЯзыка)[Ссылка]; Если ЗначенияРеквизитовОбъекта <> Неопределено Тогда Для Каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); Если СтрНайти(ИмяПоля, ".") = 0 И ЗначенияРеквизитовОбъекта.Свойство(ИмяПоля) Тогда Результат[КлючИЗначение.Ключ] = ЗначенияРеквизитовОбъекта[ИмяПоля]; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли; Если Не ЗначениеЗаполнено(РеквизитыЧерезТочку) Тогда Возврат Результат; КонецЕсли; Реквизиты = РеквизитыЧерезТочку; ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ |&ТекстЗапросаПолей |ИЗ | &ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы |ГДЕ | ПсевдонимЗаданнойТаблицы.Ссылка = &Ссылка"; Если Не ВыбратьРазрешенные Тогда ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @Query-part-1 КонецЕсли; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ТекстЗапросаПолей", ТекстЗапросаПолей); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных); // Выполнение запроса. Запрос = Новый Запрос; Запрос.УстановитьПараметр("Ссылка", Ссылка); Запрос.Текст = ТекстЗапроса; Попытка Выборка = Запрос.Выполнить().Выбрать(); Исключение // Если реквизиты были переданы строкой, то они уже конвертированы в массив. // Если реквизиты - массив, оставляем без изменений. // Если реквизиты - структура - конвертируем в массив. // В остальных случаях уже было бы выброшено исключение. Если Тип("Структура") = ТипЗнч(Реквизиты) Или Тип("ФиксированнаяСтруктура") = ТипЗнч(Реквизиты) Тогда Реквизиты = Новый Массив; Для каждого КлючИЗначение Из СтруктураПолей Цикл ИмяПоля = ?(ЗначениеЗаполнено(КлючИЗначение.Значение), КлючИЗначение.Значение, КлючИЗначение.Ключ); Реквизиты.Добавить(ИмяПоля); КонецЦикла; КонецЕсли; // Поиск ошибки доступности полей. Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты); Если Результат.Ошибка Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: %3\'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъекта", Результат.ОписаниеОшибки); КонецЕсли; // Не удалось распознать ошибку, проброс первичной ошибки. ВызватьИсключение; КонецПопытки; // Заполнение реквизитов. Если Выборка.Следующий() Тогда ЗаполнитьЗначенияСвойств(Результат, Выборка); КонецЕсли; Возврат Результат; КонецФункции // Возвращает значения реквизита, прочитанного из информационной базы по ссылке на объект. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует". // // Параметры: // Ссылка - ЛюбаяСсылка - объект, значения реквизитов которого необходимо получить. // - Строка - полное имя предопределенного элемента, значения реквизитов которого необходимо получить. // ИмяРеквизита - Строка - имя получаемого реквизита. // Допускается указание имени реквизита через точку, но при этом параметр КодЯзыка для // такого реквизита учитываться не будет. // ВыбратьРазрешенные - Булево - если Истина, то запрос к объекту выполняется с учетом прав пользователя; // если есть ограничение на уровне записей, то возвращается Неопределено; // если нет прав для работы с таблицей, то возникнет исключение; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Произвольный - если в параметр Ссылка передана пустая ссылка, то возвращается Неопределено. // Если в параметр Ссылка передана ссылка несуществующего объекта (битая ссылка), // то возвращается Неопределено. // Функция ЗначениеРеквизитаОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт Если ПустаяСтрока(ИмяРеквизита) Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: |Имя реквизита должно быть заполнено.\'"), "ИмяРеквизита", "ОбщегоНазначения.ЗначениеРеквизитаОбъекта"); КонецЕсли; Результат = ЗначенияРеквизитовОбъекта(Ссылка, ИмяРеквизита, ВыбратьРазрешенные, КодЯзыка); Возврат Результат[СтрЗаменить(ИмяРеквизита, ".", "")]; КонецФункции // Возвращает значения реквизитов, прочитанные из информационной базы для нескольких объектов. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует". // // Параметры: // Ссылки - Массив из ЛюбаяСсылка // - ФиксированныйМассив из ЛюбаяСсылка - ссылки на объекты. // Если массив пуст, то результатом будет пустое соответствие. // Реквизиты - Строка - имена реквизитов перечисленные через запятую, в формате требований к свойствам // структуры. Например, "Код, Наименование, Родитель". // - Массив из Строка // - ФиксированныйМассив из Строка - имена реквизитов в формате требований к свойствам структуры. // ВыбратьРазрешенные - Булево - если Истина, то запрос к объектам выполняется с учетом прав пользователя; // если какой-либо объект будет исключен из выборки по правам, то этот объект // будет исключен и из результата; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Соответствие из КлючИЗначение - список объектов и значений их реквизитов: // * Ключ - ЛюбаяСсылка - ссылка на объект; // * Значение - Структура: // ** Ключ - Строка - имя реквизита; // ** Значение - Произвольный - значение реквизита. // Функция ЗначенияРеквизитовОбъектов(Ссылки, Знач Реквизиты, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт Если ТипЗнч(Реквизиты) = Тип("Массив") Или ТипЗнч(Реквизиты) = Тип("ФиксированныйМассив") Тогда Реквизиты = СтрСоединить(Реквизиты, ","); КонецЕсли; Если ПустаяСтрока(Реквизиты) Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: |Поле объекта должно быть указано.\'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"); КонецЕсли; Если СтрНайти(Реквизиты, ".") <> 0 Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: |Обращение через точку не поддерживается.\'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"); КонецЕсли; ЗначенияРеквизитов = Новый Соответствие; Если Ссылки.Количество() = 0 Тогда Возврат ЗначенияРеквизитов; КонецЕсли; Если ЗначениеЗаполнено(КодЯзыка) Тогда КодЯзыка = СтрРазделить(КодЯзыка, "_", Истина)[0]; КонецЕсли; РеквизитыТекстЗапроса = Реквизиты; Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); Если ЗначениеЗаполнено(КодЯзыка) Тогда СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка); Если ЗначениеЗаполнено(СуффиксЯзыка) Тогда МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(Ссылки[0]); НаборРеквизитов = СтрРазделить(Реквизиты, ","); Для Позиция = 0 По НаборРеквизитов.ВГраница() Цикл ИмяРеквизита = СокрЛП(НаборРеквизитов[Позиция]); Если МультиязычныеРеквизиты[ИмяРеквизита] <> Неопределено Тогда ИмяССуффиксом = ИмяРеквизита + СуффиксЯзыка; НаборРеквизитов[Позиция] = ИмяССуффиксом + " КАК " + ИмяРеквизита; КонецЕсли; КонецЦикла; РеквизитыТекстЗапроса = СтрСоединить(НаборРеквизитов, ","); КонецЕсли; КонецЕсли; КонецЕсли; СсылкиПоТипам = Новый Соответствие; Для Каждого Ссылка Из Ссылки Цикл Тип = ТипЗнч(Ссылка); Если СсылкиПоТипам[Тип] = Неопределено Тогда СсылкиПоТипам[Тип] = Новый Массив; КонецЕсли; ЭлементПоТипу = СсылкиПоТипам[Тип]; // Массив ЭлементПоТипу.Добавить(Ссылка); КонецЦикла; ТекстыЗапросов = Новый Массив; ПараметрыЗапроса = Новый Структура; ИменаОбъектовМетаданных = Новый Массив; Для Каждого СсылкиПоТипу Из СсылкиПоТипам Цикл Тип = СсылкиПоТипу.Ключ; ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); Если ОбъектМетаданных = Неопределено Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный первый параметр %1 в функции %2: |Значения массива должны быть ссылками.\'"), "Ссылки", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов"); КонецЕсли; ПолноеИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя(); ИменаОбъектовМетаданных.Добавить(ПолноеИмяОбъектаМетаданных); ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ | Ссылка, | &Реквизиты |ИЗ | &ПолноеИмяОбъектаМетаданных КАК ПсевдонимЗаданнойТаблицы |ГДЕ | ПсевдонимЗаданнойТаблицы.Ссылка В (&Ссылки)"; Если Не ВыбратьРазрешенные Или ТекстыЗапросов.Количество() > 0 Тогда ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "РАЗРЕШЕННЫЕ", ""); // @Query-part-1 КонецЕсли; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Реквизиты", РеквизитыТекстЗапроса); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмяОбъектаМетаданных", ПолноеИмяОбъектаМетаданных); ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", ""); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра); // @Query-part-1 ПараметрыЗапроса.Вставить(ИмяПараметра, СсылкиПоТипу.Значение); Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); Если ЗначениеЗаполнено(КодЯзыка) И КодЯзыка <> КодОсновногоЯзыка() И МодульМультиязычностьСервер.ОбъектСодержитТЧПредставления(ПолноеИмяОбъектаМетаданных) Тогда МультиязычныеРеквизиты = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(ОбъектМетаданных); ПоляТаблиц = Новый Массив; ПоляТаблиц.Добавить("ПсевдонимЗаданнойТаблицы.Ссылка"); Для Каждого Реквизит Из СтрРазделить(Реквизиты, ",") Цикл Если МультиязычныеРеквизиты[Реквизит] <> Неопределено Тогда Если МультиязычныеРеквизиты[Реквизит] = Истина Тогда ПолеРеквизита = "ЕСТЬNULL(ТаблицаПредставления." + Реквизит + ", """")"; Иначе СуффиксЯзыка = МодульМультиязычностьСервер.СуффиксЯзыка(КодЯзыка); ПолеРеквизита = ?(ЗначениеЗаполнено(СуффиксЯзыка), Реквизит + СуффиксЯзыка, Реквизит); КонецЕсли; ПоляТаблиц.Добавить(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 КАК %2", ПолеРеквизита, Реквизит)); Иначе ПоляТаблиц.Добавить(Реквизит); КонецЕсли; КонецЦикла; ПоляТаблиц = СтрСоединить(ПоляТаблиц, "," + Символы.ПС); Таблицы = ПолноеИмяОбъектаМетаданных + " " + "КАК ПсевдонимЗаданнойТаблицы" + Символы.ПС + "ЛЕВОЕ СОЕДИНЕНИЕ" + " " + ПолноеИмяОбъектаМетаданных + ".Представления КАК ТаблицаПредставления" + Символы.ПС + "ПО ТаблицаПредставления.Ссылка = ПсевдонимЗаданнойТаблицы.Ссылка И ТаблицаПредставления.КодЯзыка = &КодЯзыка"; ИмяПараметра = "Ссылки" + СтрЗаменить(ПолноеИмяОбъектаМетаданных, ".", ""); Условия = "ПсевдонимЗаданнойТаблицы.Ссылка В (&" + ИмяПараметра + ")"; СтрокиЗапроса = Новый Массив; СтрокиЗапроса.Добавить("ВЫБРАТЬ" + ?(ВыбратьРазрешенные И Не ЗначениеЗаполнено(ТекстыЗапросов), " " + "РАЗРЕШЕННЫЕ", "")); // @Query-part-1, @Query-part-3 СтрокиЗапроса.Добавить(ПоляТаблиц); СтрокиЗапроса.Добавить("ИЗ"); // @Query-part-1 СтрокиЗапроса.Добавить(Таблицы); СтрокиЗапроса.Добавить("ГДЕ"); // @Query-part-1 СтрокиЗапроса.Добавить(Условия); ТекстЗапроса = СтрСоединить(СтрокиЗапроса, Символы.ПС); КонецЕсли; КонецЕсли; ТекстыЗапросов.Добавить(ТекстЗапроса); КонецЦикла; ТекстЗапроса = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("КодЯзыка", КодЯзыка); Для Каждого Параметр Из ПараметрыЗапроса Цикл Запрос.УстановитьПараметр(Параметр.Ключ, Параметр.Значение); КонецЦикла; Попытка Выборка = Запрос.Выполнить().Выбрать(); Исключение // Удаление пробелов. Реквизиты = СтрЗаменить(Реквизиты, " ", ""); // Преобразование параметра в массив полей. Реквизиты = СтрРазделить(Реквизиты, ","); // Поиск ошибки доступности полей. СписокОшибок = Новый Массив; Для Каждого ПолноеИмяОбъектаМетаданных Из ИменаОбъектовМетаданных Цикл Результат = ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, Реквизиты); Если Результат.Ошибка Тогда СписокОшибок.Добавить(Результат.ОписаниеОшибки); КонецЕсли; КонецЦикла; Если ЗначениеЗаполнено(СписокОшибок) Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: %3\'"), "Реквизиты", "ОбщегоНазначения.ЗначенияРеквизитовОбъектов", СтрСоединить(СписокОшибок, Символы.ПС)); КонецЕсли; // Не удалось распознать ошибку, проброс первичной ошибки. ВызватьИсключение; КонецПопытки; Пока Выборка.Следующий() Цикл Результат = Новый Структура(Реквизиты); ЗаполнитьЗначенияСвойств(Результат, Выборка); ЗначенияРеквизитов[Выборка.Ссылка] = Результат; КонецЦикла; Возврат ЗначенияРеквизитов; КонецФункции // Возвращает значения реквизита, прочитанного из информационной базы для нескольких объектов. // Рекомендуется использовать вместо обращения к реквизитам объекта через точку от ссылки на объект // для быстрого чтения отдельных реквизитов объекта из базы данных. // // Если необходимо зачитать реквизит независимо от прав текущего пользователя, // то следует использовать предварительный переход в привилегированный режим. // // Если передано имя несуществующего реквизита, то вызывается исключение "Поле объекта не существует". // // Параметры: // МассивСсылок - Массив из ЛюбаяСсылка // - ФиксированныйМассив из ЛюбаяСсылка // ИмяРеквизита - Строка - например, "Код". // ВыбратьРазрешенные - Булево - если Истина, то запрос к объектам выполняется с учетом прав пользователя; // если какой-либо объект будет исключен из выборки по правам, то этот объект // будет исключен и из результата; // если Ложь, то возникнет исключение при отсутствии прав на таблицу // или любой из реквизитов. // КодЯзыка - Строка - код языка для мультиязычного реквизита. Значение по умолчанию - основной язык конфигурации. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка - ссылка на объект, // * Значение - Произвольный - значение прочитанного реквизита. // Функция ЗначениеРеквизитаОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные = Ложь, Знач КодЯзыка = Неопределено) Экспорт Если ПустаяСтрока(ИмяРеквизита) Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неверный второй параметр %1 в функции %2: |Имя реквизита должно быть заполнено.\'"), "ИмяРеквизита", "ОбщегоНазначения.ЗначениеРеквизитаОбъектов"); КонецЕсли; ЗначенияРеквизитов = ЗначенияРеквизитовОбъектов(МассивСсылок, ИмяРеквизита, ВыбратьРазрешенные, КодЯзыка); Для каждого Элемент Из ЗначенияРеквизитов Цикл ЗначенияРеквизитов[Элемент.Ключ] = Элемент.Значение[ИмяРеквизита]; КонецЦикла; Возврат ЗначенияРеквизитов; КонецФункции // Добавляет или изменяет значение реквизита в объекте. // // Если передано имя несуществующего реквизита, то вызывается исключение. // // Параметры: // Объект - СправочникОбъект // - ДокументОбъект // - ПланВидовХарактеристикОбъект // - РегистрСведенийЗапись - заполняемый объект. // ИмяРеквизита - Строка - имя заполняемого реквизита. Например, "Комментарий" // Значение - Строка - значение помещаемое в реквизит. // КодЯзыка - Строка - код языка реквизита. Например, "ru". // Процедура УстановитьЗначениеРеквизита(Объект, ИмяРеквизита, Значение, КодЯзыка = Неопределено) Экспорт УстановитьЗначенияРеквизитов(Объект, Новый Структура(ИмяРеквизита, Значение), КодЯзыка); КонецПроцедуры // Добавляет или изменяет значения реквизитов в объекте. // // Если передано имя несуществующего реквизита, то вызывается исключение. // // Параметры: // Объект - СправочникОбъект // - ДокументОбъект // - ПланВидовХарактеристикОбъект // - РегистрСведенийЗапись - заполняемый объект. // Значения - Структура - где ключ это имя реквизита, а значение содержит строку помещаемую в реквизит. // КодЯзыка - Строка - код языка реквизита. Например, "ru". // Процедура УстановитьЗначенияРеквизитов(Объект, Значения, КодЯзыка = Неопределено) Экспорт Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); МодульМультиязычностьСервер.УстановитьЗначенияРеквизитов(Объект, Значения, КодЯзыка); Возврат; КонецЕсли; Для Каждого ЗначениеРеквизита Из Значения Цикл Значение = ЗначениеРеквизита.Значение; Если ТипЗнч(Значение) = Тип("Строка") И СтрокаВВидеНСтр(Значение) Тогда Значение = НСтр(ЗначениеРеквизита.Значение); КонецЕсли; Объект[ЗначениеРеквизита.Ключ] = Значение; КонецЦикла; КонецПроцедуры // Возвращает код основного языка информационной базы, например "ru". // На котором программно записываются автогенерируемые строки в информационную базу. // Например, при начальном заполнении информационной базы данными из макета, автогенерации комментария // к проводке или определении значения параметра ИмяСобытия метода ЗаписьЖурналаРегистрации. // // Возвращаемое значение: // Строка // Функция КодОсновногоЯзыка() Экспорт Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); Возврат МодульМультиязычностьСервер.КодОсновногоЯзыка(); КонецЕсли; Возврат Метаданные.ОсновнойЯзык.КодЯзыка; КонецФункции // Возвращает признак того, что для пользователя установлен язык интерфейса // соответствующий основному языку информационной базы. // // Возвращаемое значение: // Булево // Функция ЭтоОсновнойЯзык() Экспорт Возврат СтрСравнить(КодОсновногоЯзыка(), ТекущийЯзык().КодЯзыка) = 0; КонецФункции // Возвращает ссылку предопределенного элемента по его полному имени. // Предопределенные элементы могут содержаться только в следующих объектах: // - справочники; // - планы видов характеристик; // - планы счетов; // - планы видов расчета. // После изменения состава предопределенных следует выполнить метод // ОбновитьПовторноИспользуемыеЗначения(), который сбросит кэш ПовтИсп в текущем сеансе. // // Параметры: // ПолноеИмяПредопределенного - Строка - полный путь к предопределенному элементу, включая его имя. // Формат аналогичен функции глобального контекста ПредопределенноеЗначение(). // Например: // "Справочник.ВидыКонтактнойИнформации.EmailПользователя" // "ПланСчетов.Хозрасчетный.Материалы" // "ПланВидовРасчета.Начисления.ОплатаПоОкладу". // // Возвращаемое значение: // ЛюбаяСсылка - ссылка на предопределенный элемент. // Неопределено - если предопределенный элемент есть в метаданных, но не создан в ИБ. // Функция ПредопределенныйЭлемент(ПолноеИмяПредопределенного) Экспорт СтандартнаяОбработка = ОбщегоНазначенияСлужебныйКлиентСервер.ИспользоватьСтандартнуюФункциюПолученияПредопределенного( ПолноеИмяПредопределенного); Если СтандартнаяОбработка Тогда Возврат ПредопределенноеЗначение(ПолноеИмяПредопределенного); КонецЕсли; ПоляПредопределенного = ОбщегоНазначенияСлужебныйКлиентСервер.ИмяПредопределенногоПоПолям(ПолноеИмяПредопределенного); ПредопределенныеЗначения = СтандартныеПодсистемыПовтИсп.СсылкиПоИменамПредопределенных( ПоляПредопределенного.ПолноеИмяОбъектаМетаданных); Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредопределенныйЭлемент( ПолноеИмяПредопределенного, ПоляПредопределенного, ПредопределенныеЗначения); КонецФункции // Возвращает информацию о том, являются ли переданные элементы предопределенными. // Если нет прав доступа на уровне записей, то элемент не включается в результат. // Если нет прав доступа к таблице, то вызывается исключение. // // Параметры: // Элементы - Массив из ЛюбаяСсылка // // Возвращаемое значение: // Соответствие из КлючИЗначение - список объектов и значений их реквизитов: // * Ключ - ЛюбаяСсылка - ссылка на объект. // * Значение - Булево - Истина, если это ссылка на предопределенный элемент. // Функция ЭтоПредопределенныеЭлементы(Знач Элементы) Экспорт ИменаРеквизитов = Новый Массив; Для каждого ИмяРеквизита Из СтандартныеПодсистемыСервер.РеквизитыПредопределенныхДанных() Цикл ИменаРеквизитов.Добавить(ИмяРеквизита.Ключ); КонецЦикла; ЗначенияРеквизитов = СтандартныеПодсистемыСервер.ЗначенияРеквизитовОбъектовЕслиСуществуют(Элементы, ИменаРеквизитов); Результат = Новый Соответствие; Для каждого Элемент Из ЗначенияРеквизитов Цикл ЭтоПредопределенныйЭлемент = Ложь; Для каждого Значение Из Элемент.Значение Цикл Если ЗначениеЗаполнено(Значение.Значение) Тогда ЭтоПредопределенныйЭлемент = Истина; КонецЕсли; КонецЦикла; Результат[Элемент.Ключ] = ЭтоПредопределенныйЭлемент; КонецЦикла; Возврат Результат; КонецФункции // Проверяет статус проведения переданных документов и возвращает // те из них, которые не проведены. // // Параметры: // Документы - Массив из ДокументСсылка - документы, статус проведения которых необходимо проверить. // // Возвращаемое значение: // Массив из ДокументСсылка - непроведенные документы. // Функция ПроверитьПроведенностьДокументов(Знач Документы) Экспорт Результат = Новый Массив; ШаблонЗапроса = "ВЫБРАТЬ | ПсевдонимЗаданнойТаблицы.Ссылка КАК Ссылка |ИЗ | &ИмяДокумента КАК ПсевдонимЗаданнойТаблицы |ГДЕ | ПсевдонимЗаданнойТаблицы.Ссылка В(&МассивДокументов) | И НЕ ПсевдонимЗаданнойТаблицы.Проведен"; ТекстОбъединитьВсе = " | |ОБЪЕДИНИТЬ ВСЕ | |"; ИменаДокументов = Новый Массив; Для Каждого Документ Из Документы Цикл МетаданныеДокумента = Документ.Метаданные(); Если ИменаДокументов.Найти(МетаданныеДокумента.ПолноеИмя()) = Неопределено И Метаданные.Документы.Содержит(МетаданныеДокумента) И МетаданныеДокумента.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда ИменаДокументов.Добавить(МетаданныеДокумента.ПолноеИмя()); КонецЕсли; КонецЦикла; ТекстЗапроса = ""; Для Каждого ИмяДокумента Из ИменаДокументов Цикл Если Не ПустаяСтрока(ТекстЗапроса) Тогда ТекстЗапроса = ТекстЗапроса + ТекстОбъединитьВсе; КонецЕсли; ТекстПодзапроса = СтрЗаменить(ШаблонЗапроса, "&ИмяДокумента", ИмяДокумента); ТекстЗапроса = ТекстЗапроса + ТекстПодзапроса; КонецЦикла; Запрос = Новый Запрос; Запрос.Текст = ТекстЗапроса; Запрос.УстановитьПараметр("МассивДокументов", Документы); Если Не ПустаяСтрока(ТекстЗапроса) Тогда Результат = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"); КонецЕсли; Возврат Результат; КонецФункции // Выполняет попытку проведения документов. // // Параметры: // Документы - Массив из ДокументСсылка - документы, которые необходимо провести. // // Возвращаемое значение: // Массив из Структура: // * Ссылка - ДокументСсылка - документ, который не удалось провести, // * ОписаниеОшибки - Строка - текст описания ошибки при проведении. // Функция ПровестиДокументы(Документы) Экспорт НепроведенныеДокументы = Новый Массив; Для Каждого ДокументСсылка Из Документы Цикл ВыполненоУспешно = Ложь; ДокументОбъект = ДокументСсылка.ПолучитьОбъект(); Если ДокументОбъект.ПроверитьЗаполнение() Тогда РежимПроведения = РежимПроведенияДокумента.Неоперативный; Если ДокументОбъект.Дата >= НачалоДня(ТекущаяДатаСеанса()) И ДокументСсылка.Метаданные().ОперативноеПроведение = Метаданные.СвойстваОбъектов.ОперативноеПроведение.Разрешить Тогда РежимПроведения = РежимПроведенияДокумента.Оперативный; КонецЕсли; Попытка ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведения); ВыполненоУспешно = Истина; Исключение ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); КонецПопытки; Иначе ПредставлениеОшибки = НСтр("ru = \'Поля документа не заполнены.\'"); КонецЕсли; Если Не ВыполненоУспешно Тогда НепроведенныеДокументы.Добавить(Новый Структура("Ссылка,ОписаниеОшибки", ДокументСсылка, ПредставлениеОшибки)); КонецЕсли; КонецЦикла; Возврат НепроведенныеДокументы; КонецФункции // Проверяет наличие ссылок на объект в базе данных. // При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях. // // Параметры: // СсылкаИлиМассивСсылок - ЛюбаяСсылка // - Массив из ЛюбаяСсылка - объект или список объектов. // ИскатьСредиСлужебныхОбъектов - Булево - если Истина, то не будут учитываться // исключения поиска ссылок, заданные при разработке конфигурации. // Про исключение поиска ссылок см. подробнее // ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок. // // Возвращаемое значение: // Булево - Истина, если есть ссылки на объект. // Функция ЕстьСсылкиНаОбъект(Знач СсылкаИлиМассивСсылок, Знач ИскатьСредиСлужебныхОбъектов = Ложь) Экспорт Если ТипЗнч(СсылкаИлиМассивСсылок) = Тип("Массив") Тогда МассивСсылок = СсылкаИлиМассивСсылок; Иначе МассивСсылок = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СсылкаИлиМассивСсылок); КонецЕсли; УстановитьПривилегированныйРежим(Истина); МестаИспользования = НайтиПоСсылкам(МассивСсылок); УстановитьПривилегированныйРежим(Ложь); Если Не ИскатьСредиСлужебныхОбъектов Тогда Для каждого Элемент Из СлужебныеСвязиДанных(МестаИспользования) Цикл МестаИспользования.Удалить(Элемент.Ключ); КонецЦикла; КонецЕсли; Возврат МестаИспользования.Количество() > 0; КонецФункции // Определяет, указаны ли места использования в исключениях поиска ссылок. // // Параметры: // МестаИспользования - ТаблицаЗначений - результат функции НайтиПоСсылкам: // * Ссылка - ЛюбаяСсылка - проверяемая ссылка. // * Данные - ЛюбаяСсылка - место использования. // * Метаданные - ОбъектМетаданных - метаданные места использования. // ИсключенияПоискаСсылок - см. ИсключенияПоискаСсылок // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - СтрокаТаблицыЗначений // * Значение - Булево - всегда Истина. Если это не служебная связь данных, то в соответствии нет элемента. // Функция СлужебныеСвязиДанных(Знач МестаИспользования, Знач ИсключенияПоискаСсылок = Неопределено) Экспорт Если ИсключенияПоискаСсылок = Неопределено Тогда ИсключенияПоискаСсылок = ИсключенияПоискаСсылок(); КонецЕсли; Результат = Новый Соответствие; МестоИспользованияПоМетаданным = Новый Соответствие; Для каждого МестоИспользования Из МестаИспользования Цикл ИсключениеПоиска = ИсключенияПоискаСсылок[МестоИспользования.Метаданные]; // Данные могут быть как ссылкой, так и ключом записи регистра. Если ИсключениеПоиска = Неопределено Тогда Если МестоИспользования.Ссылка = МестоИспользования.Данные Тогда Результат[МестоИспользования] = Истина; // Ссылку саму на себя исключаем. КонецЕсли; Продолжить; ИначеЕсли ИсключениеПоиска = "*" Тогда Результат[МестоИспользования] = Истина; // Если указано исключить все - считаем все исключением. Продолжить; КонецЕсли; ЭтоСсылка = ЭтоСсылка(ТипЗнч(МестоИспользования.Данные)); Если Не ЭтоСсылка Тогда Для Каждого ПутьКРеквизиту Из ИсключениеПоиска Цикл ЗначениеРеквизита = Новый Структура(ПутьКРеквизиту); ЗаполнитьЗначенияСвойств(ЗначениеРеквизита, МестоИспользования.Данные); Если ЗначениеРеквизита[ПутьКРеквизиту] = МестоИспользования.Ссылка Тогда Результат[МестоИспользования] = Истина; Прервать; КонецЕсли; КонецЦикла; Продолжить; КонецЕсли; Если ИсключениеПоиска.Количество() = 0 Тогда Продолжить; КонецЕсли; ИмяТаблицы = МестоИспользования.Метаданные.ПолноеИмя(); Значение = МестоИспользованияПоМетаданным[ИмяТаблицы]; Если Значение = Неопределено Тогда Значение = Новый ТаблицаЗначений; Значение.Колонки.Добавить("Ссылка", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Данные", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Метаданные"); МестоИспользованияПоМетаданным[ИмяТаблицы] = Значение; КонецЕсли; ЗаполнитьЗначенияСвойств(Значение.Добавить(), МестоИспользования); КонецЦикла; Индекс = 1; Запрос = Новый Запрос; ТекстыЗапроса = Новый Массив; ВременныеТаблицы = Новый Массив; Для каждого МестоИспользования Из МестоИспользованияПоМетаданным Цикл ИмяТаблицы = МестоИспользования.Ключ; // Строка МестоИспользования = МестоИспользования.Значение; // ТаблицаЗначений // Проверка, есть ли по исключаемому пути в указанных данных проверяемая ссылка. Если МестоИспользования.Количество() > 1 Тогда ШаблонЗапроса = "ВЫБРАТЬ | Ссылки.Данные КАК Ссылка, | Ссылки.Ссылка КАК ПроверяемаяСсылка |ПОМЕСТИТЬ ВТТаблицаСсылок |ИЗ | &Ссылки КАК Ссылки |; | |ВЫБРАТЬ | ТаблицаСсылок.Ссылка КАК Ссылка, | ТаблицаСсылок.ПроверяемаяСсылка КАК ПроверяемаяСсылка |ИЗ | ВТТаблицаСсылок КАК ТаблицаСсылок | ЛЕВОЕ СОЕДИНЕНИЕ #ПолноеИмяОбъектаМетаданных КАК Таблица | ПО ТаблицаСсылок.Ссылка = Таблица.Ссылка |ГДЕ | &Условие"; ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "#ПолноеИмяОбъектаМетаданных", ИмяТаблицы); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВТТаблицаСсылок", "ВТТаблицаСсылок" + Формат(Индекс, "ЧГ=;ЧН=")); ИмяПараметра = "Ссылки" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылки", "&" + ИмяПараметра); Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования); ЧастиЗапроса = СтрРазделить(ТекстЗапроса, ";"); ВременныеТаблицы.Добавить(ЧастиЗапроса[0]); ТекстЗапроса = ЧастиЗапроса[1]; Иначе ШаблонЗапроса = "ВЫБРАТЬ | &СсылкаНаВладельца КАК Ссылка, | &ПроверяемаяСсылка КАК ПроверяемаяСсылка |ИЗ | #ПолноеИмяОбъектаМетаданных КАК Таблица |ГДЕ | Таблица.Ссылка = &СсылкаНаВладельца | И (&Условие)"; ТекстЗапроса = СтрЗаменить(ШаблонЗапроса, "#ПолноеИмяОбъектаМетаданных", ИмяТаблицы); ИмяПараметра = "СсылкаНаВладельца" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&СсылкаНаВладельца", "&" + ИмяПараметра); Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования[0].Данные); ИмяПараметра = "ПроверяемаяСсылка" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПроверяемаяСсылка", "&" + ИмяПараметра); Запрос.УстановитьПараметр(ИмяПараметра, МестоИспользования[0].Ссылка); КонецЕсли; ТекстУсловия = Новый Массив; // Относительный путь к реквизиту: "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]". Для Каждого ПутьКРеквизиту Из ИсключенияПоискаСсылок[МестоИспользования[0].Метаданные] Цикл ТекстУсловия.Добавить(ПутьКРеквизиту + " = " + ?(МестоИспользования.Количество() > 1, "ТаблицаСсылок.ПроверяемаяСсылка", "&" + ИмяПараметра)); КонецЦикла; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Условие", СтрСоединить(ТекстУсловия, " ИЛИ ")); ТекстыЗапроса.Добавить(ТекстЗапроса); Индекс = Индекс + 1; КонецЦикла; Если ТекстыЗапроса.Количество() = 0 Тогда Возврат Результат; КонецЕсли; Запрос.Текст = СтрСоединить(ВременныеТаблицы, ";" + Символы.ПС) + ?(ВременныеТаблицы.Количество() > 0, ";" + Символы.ПС, "") + СтрСоединить(ТекстыЗапроса, Символы.ПС + "ОБЪЕДИНИТЬ" + Символы.ПС); УстановитьПривилегированныйРежим(Истина); ВыборкаЗапроса = Запрос.Выполнить().Выбрать(); УстановитьПривилегированныйРежим(Ложь); МестаИспользования.Индексы.Добавить("Ссылка,Данные"); Пока ВыборкаЗапроса.Следующий() Цикл СлужебныеСвязиДанных = МестаИспользования.НайтиСтроки(Новый Структура("Ссылка,Данные", ВыборкаЗапроса.ПроверяемаяСсылка, ВыборкаЗапроса.Ссылка)); Для каждого СлужебнаяСвязьДанных Из СлужебныеСвязиДанных Цикл Результат[СлужебнаяСвязьДанных] = Истина; КонецЦикла; КонецЦикла; Возврат Результат; КонецФункции // Определяет, указано ли место использования в исключениях поиска ссылок. // // Параметры: // МестоИспользования - Структура: // * Ссылка - ЛюбаяСсылка - проверяемая ссылка. // * Данные - ЛюбаяСсылка - место использования. // * Метаданные - ОбъектМетаданных - метаданные места использования. // ИсключенияПоискаСсылок - см. ИсключенияПоискаСсылок // // Возвращаемое значение: // Булево // Функция ЭтоСлужебнаяСвязьДанных(Знач МестоИспользования, Знач ИсключенияПоискаСсылок = Неопределено) Экспорт Если ИсключенияПоискаСсылок = Неопределено Тогда ИсключенияПоискаСсылок = ИсключенияПоискаСсылок(); КонецЕсли; Значение = Новый ТаблицаЗначений; Значение.Колонки.Добавить("Ссылка", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Данные", ОписаниеТипаВсеСсылки()); Значение.Колонки.Добавить("Метаданные"); МестоИспользованияСтрока = Значение.Добавить(); ЗаполнитьЗначенияСвойств(МестоИспользованияСтрока, МестоИспользования); Результат = СлужебныеСвязиДанных(Значение, ИсключенияПоискаСсылок); Возврат Результат[МестоИспользованияСтрока] <> Неопределено; КонецФункции // Производит замену ссылок во всех данных. После замены неиспользуемые ссылки опционально удаляются. // Замена ссылок происходит с транзакциями по изменяемому объекту и его связям, не по анализируемой ссылке. // При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях. // Если описаны связи подчиненных и основных объектов (см. СвязиПодчиненныхОбъектов), то: // * при замене основных объектов будет выполнен поиск замен подчиненных объектов; // * если ВыполнятьАвтоматическийПоискЗамен = Истина, то будет выполнена попытка поиска замен для подчиненных объектов // по значениям полей связи. В случае, если объект не существует, будет выполнена процедура ПриПоискеЗаменыСсылок; // * если МетодПоиска в описании связей задан, то если автоматический поиск не нашел замен // или не выполнялся, будет вызван МетодПоиска для подбора замен. // // Параметры: // ПарыЗамен - Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка - что ищем (дубль). // * Значение - ЛюбаяСсылка - на что заменяем (оригинал). // Ссылки сами на себя и пустые ссылки для поиска будут проигнорированы. // // ПараметрыЗамены - см. ОбщегоНазначения.ПараметрыЗаменыСсылок // // Возвращаемое значение: // ТаблицаЗначений - неуспешные замены (ошибки): // * Ссылка - ЛюбаяСсылка - ссылка, которую заменяли. // * ОбъектОшибки - Произвольный - объект-причина ошибки. // * ПредставлениеОбъектаОшибки - Строка - строковое представление объекта ошибки. // * ТипОшибки - Строка - тип ошибки: // "ОшибкаБлокировки" - при обработке ссылки некоторые объекты были заблокированы. // "ДанныеИзменены" - в процессе обработки данные были изменены другим пользователем. // "ОшибкаЗаписи" - не смогли записать объект, или метод ВозможностьЗаменыЭлементов вернул отказ. // "ОшибкаУдаления" - не смогли удалить объект. // "НеизвестныеДанные" - при обработке были найдены данные, которые не планировались к замене. // * ТекстОшибки - Строка - подробное описание ошибки. // Функция ЗаменитьСсылки(Знач ПарыЗамен, Знач ПараметрыЗамены = Неопределено) Экспорт Статистика = Новый Соответствие; ТипСтрока = Новый ОписаниеТипов("Строка"); ОшибкиЗамены = Новый ТаблицаЗначений; ОшибкиЗамены.Колонки.Добавить("Ссылка"); ОшибкиЗамены.Колонки.Добавить("ОбъектОшибки"); ОшибкиЗамены.Колонки.Добавить("ПредставлениеОбъектаОшибки", ТипСтрока); ОшибкиЗамены.Колонки.Добавить("ТипОшибки", ТипСтрока); ОшибкиЗамены.Колонки.Добавить("ТекстОшибки", ТипСтрока); ОшибкиЗамены.Индексы.Добавить("Ссылка"); ОшибкиЗамены.Индексы.Добавить("Ссылка, ОбъектОшибки, ТипОшибки"); Результат = РезультатЗаменыСсылок(ОшибкиЗамены); ПараметрыВыполнения = НовыйПараметрыВыполненияЗаменыСсылок(ПараметрыЗамены); ПараметрыПоискаМестИспользования = ПараметрыПоискаМестИспользования(); ДополнитьИсключенияПоискаСсылокПодчиненнымиОбъектами(ПараметрыПоискаМестИспользования.ДополнительныеИсключенияПоискаСсылок); ПараметрыВыполнения.Вставить("ПараметрыПоискаМестИспользования", ПараметрыПоискаМестИспользования); ИнтеграцияПодсистемБСП.ПередПоискомМестИспользования(ПарыЗамен, ПараметрыВыполнения); Если ПарыЗамен.Количество() = 0 Тогда Возврат Результат.Ошибки; КонецЕсли; Дубли = СформироватьДубли(ПараметрыВыполнения, ПараметрыЗамены, ПарыЗамен, Результат); ТаблицаПоиска = МестаИспользования(Дубли,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования); // Для каждой ссылки объекта будем производить замены в порядке "Константа", "Объект", "Набор". // Одновременно пустая строка в этой колонке - флаг того, что эта замена не нужна или уже была произведена. ТаблицаПоиска.Колонки.Добавить("КлючЗамены", ТипСтрока); ТаблицаПоиска.Индексы.Добавить("Ссылка, КлючЗамены"); ТаблицаПоиска.Индексы.Добавить("Данные, КлючЗамены"); // Вспомогательные данные ТаблицаПоиска.Колонки.Добавить("ЦелеваяСсылка"); ТаблицаПоиска.Колонки.Добавить("Обработано", Новый ОписаниеТипов("Булево")); // Определяем порядок обработки и проверяем то, что можно обработать. ОшибкиРазметки = Новый Массив; ОбъектыСОшибками = Новый Массив; Количество = Дубли.Количество(); Для Номер = 1 По Количество Цикл ОбратныйИндекс = Количество - Номер; Дубль = Дубли[ОбратныйИндекс]; РезультатРазметки = РазметитьМестаИспользования(ПараметрыВыполнения, Дубль, ПарыЗамен[Дубль], ТаблицаПоиска); Если Не РезультатРазметки.Успех Тогда Дубли.Удалить(ОбратныйИндекс); Для Каждого Ошибка Из РезультатРазметки.ОшибкиРазметки Цикл Ошибка.Вставить("Дубль", Дубль); ОбъектыСОшибками.Добавить(Ошибка.Объект); КонецЦикла; ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОшибкиРазметки, РезультатРазметки.ОшибкиРазметки); КонецЕсли; КонецЦикла; Если ОшибкиРазметки.Количество() > 0 Тогда ПредставленияОбъектов = ПредметыСтрокой(ОбъектыСОшибками); Для Каждого Ошибка Из ОшибкиРазметки Цикл ЗарегистрироватьОшибкуЗамены(Результат, Ошибка.Дубль, ОписаниеОшибкиЗамены("НеизвестныеДанные", Ошибка.Объект, ПредставленияОбъектов[Ошибка.Объект], Ошибка.Текст)); КонецЦикла; КонецЕсли; // Замена и удаление найденных дублей. ПараметрыВыполнения.Вставить("ПарыЗамен", ПарыЗамен); ПараметрыВыполнения.Вставить("УспешныеЗамены", Новый Соответствие); ОтключитьОбновлениеКлючейДоступа(Истина); Попытка КоличествоДублей = Дубли.Количество(); Номер = 1; Для Каждого Дубль Из Дубли Цикл БылиОшибки = Результат.ЕстьОшибки; Результат.ЕстьОшибки = Ложь; // @skip-check query-in-loop - Порционная обработка большого объема данных. ЗаменитьСсылкиКороткимиТранзакциями(Результат, ПараметрыВыполнения, Дубль, ТаблицаПоиска); Если НЕ Результат.ЕстьОшибки Тогда ПараметрыВыполнения.УспешныеЗамены.Вставить(Дубль, ПараметрыВыполнения.ПарыЗамен[Дубль]); КонецЕсли; Результат.ЕстьОшибки = Результат.ЕстьОшибки ИЛИ БылиОшибки; ДополнительныеПараметры = Новый Структура; ДополнительныеПараметры.Вставить("НомерСеанса", НомерСеансаИнформационнойБазы()); ДополнительныеПараметры.Вставить("КоличествоОбработанных", Номер); ДлительныеОперации.СообщитьПрогресс(Номер, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Замена дублей... обработано (%1 из %2)\'"), Номер, КоличествоДублей), ДополнительныеПараметры); Номер = Номер + 1; ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, Результат.ЕстьОшибки); КонецЦикла; ОбщегоНазначенияПереопределяемый.ПослеЗаменыСсылок(Результат, ПараметрыВыполнения, ТаблицаПоиска); ОтключитьОбновлениеКлючейДоступа(Ложь); Исключение ОтключитьОбновлениеКлючейДоступа(Ложь); ВызватьИсключение; КонецПопытки; Если ПодсистемаСуществует("СтандартныеПодсистемы.УдалениеПомеченныхОбъектов") И ПараметрыВыполнения.УдалятьНепосредственно Тогда МодульУдалениеПомеченныхОбъектов = ОбщийМодуль("УдалениеПомеченныхОбъектов"); ДлительныеОперации.СообщитьПрогресс(0, НСтр("ru = \'Удаление дублей...\'")); РезультатУдаления = МодульУдалениеПомеченныхОбъектов.УдалитьПомеченныеОбъекты(Результат.ОчередьКНепосредственномуУдалению); ЗарегистрироватьОшибкиУдаления(Результат, РезультатУдаления.ПрепятствующиеУдалению); КонецЕсли; ОтправитьСтатистикуЗаменыСсылок(Статистика); Возврат Результат.Ошибки; КонецФункции // Конструктор структуры для параметра ПараметрыЗамены функции ОбщегоНазначения.ЗаменитьСсылки. // // Возвращаемое значение: // Структура: // * СпособУдаления - Строка - указывает, что делать с дублем после успешной замены: // "" - не предпринимать никаких действий (по умолчанию); // "Пометка" - помечать на удаление; // "Непосредственно" - удалять непосредственно. // * УчитыватьПрикладныеПравила - Булево - если Истина, то для каждой пары "дубль-оригинал" // вызывается функция ВозможностьЗаменыЭлементов модуля менеджера // (требуется подсистема "Поиск и удаление дублей"). По умолчанию, Ложь. // * ВключатьБизнесЛогику - Булево - режим записи объектов при замене в них ссылок дублей на оригиналы. // Если Истина (по умолчанию), то места использования дублей записываются в обычном режиме, // иначе запись ведется в режиме ОбменДанными.Загрузка = Истина. // * ЗаменаПарыВТранзакции - Булево - устарел. определяет размер транзакции при замене дублей. // Если Истина (по умолчанию), то все места использования одного дубля заменяются в одной транзакции. // Это может быть очень ресурсоемко в случае большого количества мест использований. // Если Ложь, то замена в каждом месте использования выполняется в отдельной транзакции. // * ПривилегированнаяЗапись - Булево - если Истина, то устанавливать привилегированный режим перед запись // объектов при замене в них ссылок дублей на оригиналы. По умолчанию Ложь. // Функция ПараметрыЗаменыСсылок() Экспорт Результат = Новый Структура; Результат.Вставить("СпособУдаления", ""); Результат.Вставить("УчитыватьПрикладныеПравила", Ложь); Результат.Вставить("ВключатьБизнесЛогику", Истина); Результат.Вставить("ЗаменаПарыВТранзакции", Ложь); Результат.Вставить("ПривилегированнаяЗапись", Ложь); Возврат Результат; КонецФункции // Получает все места использования ссылок. // Если какая-либо ссылка нигде не используется, то строк для нее в результирующей таблице не будет. // При вызове в неразделенном сеансе не выявляет ссылок в разделенных областях. // // Параметры: // НаборСсылок - Массив из ЛюбаяСсылка - ссылки, для которых ищем места использования. // АдресРезультата - Строка - адрес во временном хранилище, куда будет помещен копия результата замены. // ДополнительныеПараметры - см. ОбщегоНазначения.ПараметрыПоискаМестИспользования // // Возвращаемое значение: // ТаблицаЗначений: // * Ссылка - ЛюбаяСсылка - ссылка, которая анализируется. // * Данные - Произвольный - данные, содержащие анализируемую ссылку. // * Метаданные - ОбъектМетаданных - метаданные найденных данных. // * ПредставлениеДанных - Строка - представление данных, содержащих анализируемую ссылку. // * ТипСсылки - Тип - тип анализируемой ссылки. // * ВспомогательныеДанные - Булево - Истина, если данные используются анализируемой ссылкой как // вспомогательные данные (ведущее измерение или попали в исключение ПриДобавленииИсключенийПоискаСсылок). // * ЭтоСлужебныеДанные - Булево - данные попали в исключение ПриДобавленииИсключенийПоискаСсылок // Функция МестаИспользования(Знач НаборСсылок, Знач АдресРезультата = "", ДополнительныеПараметры = Неопределено) Экспорт МестаИспользования = Новый ТаблицаЗначений; УстановитьПривилегированныйРежим(Истина); МестаИспользования = НайтиПоСсылкам(НаборСсылок); // см. МестаИспользования. УстановитьПривилегированныйРежим(Ложь); // МестаИспользования - ТаблицаЗначений - где: // * Ссылка - ЛюбаяСсылка - Ссылка, которая анализируется. // * Данные - Произвольный - Данные, содержащие анализируемую ссылку. // * Метаданные - ОбъектМетаданных - Метаданные найденных данных. МестаИспользования.Колонки.Добавить("ПредставлениеДанных", Новый ОписаниеТипов("Строка")); МестаИспользования.Колонки.Добавить("ТипСсылки"); МестаИспользования.Колонки.Добавить("ИнформацияОМестеИспользования"); МестаИспользования.Колонки.Добавить("ВспомогательныеДанные", Новый ОписаниеТипов("Булево")); МестаИспользования.Колонки.Добавить("ЭтоСлужебныеДанные", Новый ОписаниеТипов("Булево")); МестаИспользования.Индексы.Добавить("Ссылка"); МестаИспользования.Индексы.Добавить("Данные"); МестаИспользования.Индексы.Добавить("ВспомогательныеДанные"); МестаИспользования.Индексы.Добавить("Ссылка, ВспомогательныеДанные"); ТипКлючиЗаписей = ОписаниеТипаКлючиЗаписей(); ТипВсеСсылки = ОписаниеТипаВсеСсылки(); МетаданныеПоследовательностей = Метаданные.Последовательности; МетаданныеКонстант = Метаданные.Константы; МетаданныеДокументов = Метаданные.Документы; ИсключенияПоискаСсылок = ИсключенияПоискаСсылок(); ДополнительныеИсключенияПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры( ДополнительныеПараметры, "ДополнительныеИсключенияПоискаСсылок", Новый Соответствие); Для каждого МетаданныеРеквизитыИсключения Из ДополнительныеИсключенияПоискаСсылок Цикл ЗначениеИсключения = ИсключенияПоискаСсылок[МетаданныеРеквизитыИсключения.Ключ]; Если ЗначениеИсключения = Неопределено Тогда ИсключенияПоискаСсылок.Вставить(МетаданныеРеквизитыИсключения.Ключ, МетаданныеРеквизитыИсключения.Значение); Иначе Если ТипЗнч(ЗначениеИсключения) = Тип("Массив") Тогда ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ЗначениеИсключения, МетаданныеРеквизитыИсключения.Значение); КонецЕсли; КонецЕсли; КонецЦикла; ОтменаИсключенийПоискаСсылок = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеПараметры, "ОтменаИсключенийПоискаСсылок", Новый Массив); Для каждого ОтменаИсключения Из ОтменаИсключенийПоискаСсылок Цикл ИсключенияПоискаСсылок.Удалить(ОтменаИсключения); КонецЦикла; СлужебныеСвязиДанных = СлужебныеСвязиДанных(МестаИспользования, ИсключенияПоискаСсылок); КэшИзмеренийРегистров = Новый Соответствие; Для Каждого МестоИспользования Из МестаИспользования Цикл ТипДанных = ТипЗнч(МестоИспользования.Данные); ЭтоСлужебныеДанные = СлужебныеСвязиДанных[МестоИспользования] <> Неопределено; ЭтоВспомогательныеДанные = ЭтоСлужебныеДанные; Если ТипДанных = Неопределено Или МетаданныеДокументов.Содержит(МестоИспользования.Метаданные) Тогда Представление = Строка(МестоИспользования.Данные); ИначеЕсли МетаданныеКонстант.Содержит(МестоИспользования.Метаданные) Тогда Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = \'константа\'") + ")"; ИначеЕсли МетаданныеПоследовательностей.Содержит(МестоИспользования.Метаданные) Тогда Представление = МестоИспользования.Метаданные.Представление() + " (" + НСтр("ru = \'последовательность\'") + ")"; ИначеЕсли ТипВсеСсылки.СодержитТип(ТипДанных) Тогда МетаПредставлениеОбъекта = Новый Структура("ПредставлениеОбъекта"); ЗаполнитьЗначенияСвойств(МетаПредставлениеОбъекта, МестоИспользования.Метаданные); Если ПустаяСтрока(МетаПредставлениеОбъекта.ПредставлениеОбъекта) Тогда МетаПредставление = МестоИспользования.Метаданные.Представление(); Иначе МетаПредставление = МетаПредставлениеОбъекта.ПредставлениеОбъекта; КонецЕсли; Представление = Строка(МестоИспользования.Данные); Если Не ПустаяСтрока(МетаПредставление) Тогда Представление = Представление + " (" + МетаПредставление + ")"; КонецЕсли; ИначеЕсли ТипКлючиЗаписей.СодержитТип(ТипДанных) Тогда Представление = МестоИспользования.Метаданные.ПредставлениеЗаписи; Если ПустаяСтрока(Представление) Тогда Представление = МестоИспользования.Метаданные.Представление(); КонецЕсли; ОписаниеИзмерений = Новый Массив; Для Каждого МетаданныеРеквизитыИсключения Из ОписаниеИзмеренийНабора(МестоИспользования.Метаданные, КэшИзмеренийРегистров) Цикл Значение = МестоИспользования.Данные[МетаданныеРеквизитыИсключения.Ключ]; Описание = МетаданныеРеквизитыИсключения.Значение; Если МестоИспользования.Ссылка = Значение Тогда Если Описание.Ведущее Тогда ЭтоВспомогательныеДанные = Истина; КонецЕсли; КонецЕсли; Если Не ЭтоСлужебныеДанные Тогда // для оптимизации ФорматЗначения = Описание.Формат; ОписаниеИзмерений.Добавить(Описание.Представление + " """ + ?(ФорматЗначения = Неопределено, Строка(Значение), Формат(Значение, ФорматЗначения)) + """"); КонецЕсли; КонецЦикла; Если ОписаниеИзмерений.Количество() > 0 Тогда Представление = Представление + " (" + СтрСоединить(ОписаниеИзмерений, ", ") + ")"; КонецЕсли; Иначе Представление = Строка(МестоИспользования.Данные); КонецЕсли; МестоИспользования.ПредставлениеДанных = Представление; МестоИспользования.ВспомогательныеДанные = ЭтоВспомогательныеДанные; МестоИспользования.ЭтоСлужебныеДанные = ЭтоСлужебныеДанные; МестоИспользования.ТипСсылки = ТипЗнч(МестоИспользования.Ссылка); КонецЦикла; Если Не ПустаяСтрока(АдресРезультата) Тогда ПоместитьВоВременноеХранилище(МестаИспользования, АдресРезультата); КонецЕсли; Возврат МестаИспользования; КонецФункции // Возвращает структуру для параметра ДополнительныеПараметры функции ОбщегоНазначения.МестаИспользования. // // Возвращаемое значение: // Структура: // * ДополнительныеИсключенияПоискаСсылок - Соответствие - позволяет расширить исключения поиска ссылок // см. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок // * ОтменаИсключенийПоискаСсылок - Массив из ОбъектМетаданных - полностью отменяет исключения поиска ссылок для // объектов метаданных. // Функция ПараметрыПоискаМестИспользования() Экспорт ПараметрыПоиска = Новый Структура; ПараметрыПоиска.Вставить("ДополнительныеИсключенияПоискаСсылок", Новый Соответствие); ПараметрыПоиска.Вставить("ОтменаИсключенийПоискаСсылок", Новый Соответствие); Возврат ПараметрыПоиска; КонецФункции // Возвращает исключения при поиске мест использования объектов. // // Возвращаемое значение: // Соответствие из КлючИЗначение - исключения поиска ссылок в разрезе объектов метаданных: // * Ключ - ОбъектМетаданных - объект метаданных, для которого применяются исключения. // * Значение - Строка // - Массив из Строка - описание исключенных реквизитов. // Если "*", то исключены все реквизиты объекта метаданных. // Если массив строк, то содержит относительные имена исключенных реквизитов. // Функция ИсключенияПоискаСсылок() Экспорт ИсключенияПоискаИнтеграция = Новый Массив; ИнтеграцияПодсистемБСП.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаИнтеграция); ИсключенияПоиска = Новый Массив; ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ИсключенияПоиска, ИсключенияПоискаИнтеграция); ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоиска); Результат = Новый Соответствие; Для Каждого ИсключениеПоиска Из ИсключенияПоиска Цикл // Определение полного имени реквизита и объекта метаданных - носителя реквизита. Если ТипЗнч(ИсключениеПоиска) = Тип("Строка") Тогда ПолноеИмя = ИсключениеПоиска; МассивПодстрок = СтрРазделить(ПолноеИмя, "."); КоличествоПодстрок = МассивПодстрок.Количество(); ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(МассивПодстрок[0] + "." + МассивПодстрок[1]); Иначе ОбъектМетаданных = ИсключениеПоиска; ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); МассивПодстрок = СтрРазделить(ПолноеИмя, "."); КоличествоПодстрок = МассивПодстрок.Количество(); Если КоличествоПодстрок > 2 Тогда Пока Истина Цикл Родитель = ОбъектМетаданных.Родитель(); Если ТипЗнч(Родитель) = Тип("ОбъектМетаданныхКонфигурация") Тогда Прервать; Иначе ОбъектМетаданных = Родитель; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли; // Регистрация. Если КоличествоПодстрок < 4 Тогда Результат.Вставить(ОбъектМетаданных, "*"); Иначе ПутиКРеквизитам = Результат.Получить(ОбъектМетаданных); Если ПутиКРеквизитам = "*" Тогда Продолжить; // Весь объект метаданных уже исключен. ИначеЕсли ПутиКРеквизитам = Неопределено Тогда ПутиКРеквизитам = Новый Массив; Результат.Вставить(ОбъектМетаданных, ПутиКРеквизитам); КонецЕсли; // Формат реквизита: // "<ВидОМ>.<ИмяОМ>.<ТипРеквизитаИлиТЧ>.<ИмяРеквизитаИлиТЧ>[.<ТипРеквизита>.<ИмяРеквизитаТЧ>]". // Примеры: // "РегистрСведений.ВерсииОбъектов.Реквизит.АвторВерсии", // "Документ._ДемоЗаказПокупателя.ТабличнаяЧасть.СчетаНаОплату.Реквизит.Счет", // "ПланВидовРасчета._ДемоОсновныеНачисления.СтандартнаяТабличнаяЧасть.БазовыеВидыРасчета.СтандартныйРеквизит.ВидРасчета". // Относительный путь к реквизиту должен получиться таким, чтобы его можно было использовать в условиях запроса: // "<ИмяРеквизитаИлиТЧ>[.<ИмяРеквизитаТЧ>]". Если КоличествоПодстрок = 4 Тогда ОтносительныйПутьКРеквизиту = МассивПодстрок[3]; Иначе ОтносительныйПутьКРеквизиту = МассивПодстрок[3] + "." + МассивПодстрок[5]; КонецЕсли; ПутиКРеквизитам.Добавить(ОтносительныйПутьКРеквизиту); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Возвращает связи подчиненных объектов и перечень реквизитов, по которым осуществляется связь. // // Есть возможность переопределить процедуру поиска подчиненных объектов. // Для этого в общем модуле или модуле менеджера необходимо реализовать процедуру // ПриПоискеЗаменыСсылок с параметрами: // ПарыЗамен - Соответствие - содержит пары значение оригинал/дубль. // НеобработанныеЗначенияОригиналов - Массив из Структура - дополнительная информация об обрабатываемых объектах: // * ЗаменяемоеЗначение - ПроизвольнаяСсылка - оригинальное значение заменяемого объекта. // * ИспользуемыеСвязи - см. ОбщегоНазначения.СвязиПодчиненныхОбъектовПоТипам // * ЗначениеКлючевыхРеквизитов - Структура - где Ключ - имя реквизита, значение - значение реквизита. // // Возвращаемое значение: // ТаблицаЗначений: // * ПодчиненныйОбъект - ОбъектМетаданных - объект метаданных подчиненного объекта. // * ПоляСвязей - Строка - имена реквизитов, определяющих связь между основными и подчиненными объектами. // * ПриПоискеЗаменыСсылок - Строка - опционально. Имя общего модуля или модуля менеджера, в котором определена // процедура ПриПоискеЗаменыСсылок. // * ВыполнятьАвтоматическийПоискЗаменСсылок - Булево - если указать Истина, то будет выполнена попытка поиска замен // для подчиненных объектов по значениям полей связи. В случае, если объект не существует, // будет выполнена процедура ПриПоискеЗаменыСсылок. См. также ЗаменитьСсылки. // Функция ПодчиненныеОбъекты() Экспорт ОписаниеСвязей = Новый ТаблицаЗначений; ОписаниеСвязей.Колонки.Добавить("ПодчиненныйОбъект", Новый ОписаниеТипов("ОбъектМетаданных")); ОписаниеСвязей.Колонки.Добавить("ПоляСвязей"); ОписаниеСвязей.Колонки.Добавить("ПриПоискеЗаменыСсылок", ОписаниеТипаСтрока(0)); ОписаниеСвязей.Колонки.Добавить("ВыполнятьАвтоматическийПоискЗаменСсылок", Новый ОписаниеТипов("Булево")); ИнтеграцияПодсистемБСП.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей); ОбщегоНазначенияПереопределяемый.ПриОпределенииПодчиненныхОбъектов(ОписаниеСвязей); // Если передали соответствие или структуру преобразуем к необходимому типу. Для каждого СтрокаСвязи Из ОписаниеСвязей Цикл ТипОписанияПолейСвязи = ТипЗнч(СтрокаСвязи.ПоляСвязей); Если ТипОписанияПолейСвязи = Тип("Структура") ИЛИ ТипОписанияПолейСвязи = Тип("Соответствие") Тогда ПоляСвязейСтрокой = ""; Для каждого КлючЗначение Из СтрокаСвязи.ПоляСвязей Цикл ПоляСвязейСтрокой = ПоляСвязейСтрокой + КлючЗначение.Ключ + ","; КонецЦикла; СтроковыеФункцииКлиентСервер.УдалитьПоследнийСимволВСтроке(ПоляСвязейСтрокой,1); СтрокаСвязи.ПоляСвязей = ПоляСвязейСтрокой; КонецЕсли; Если ТипОписанияПолейСвязи = Тип("Массив") Тогда СтрокаСвязи.ПоляСвязей = СтрСоединить(СтрокаСвязи.ПоляСвязей, ","); КонецЕсли; КонецЦикла; Возврат ОписаниеСвязей; КонецФункции // Возвращает связи подчиненных объектов с указанием типа поля связи. // // Возвращаемое значение: // ТаблицаЗначений: // * Ключ - Строка // * ТипРеквизита - Тип // * ИмяРеквизита - Строка // * Используется - Булево // * Метаданные - ОбъектМетаданных // Функция СвязиПодчиненныхОбъектовПоТипам() Экспорт Результат = Новый ТаблицаЗначений; Результат.Колонки.Добавить("ТипРеквизита", Новый ОписаниеТипов("Тип")); Результат.Колонки.Добавить("ИмяРеквизита", ОписаниеТипаСтрока(0)); Результат.Колонки.Добавить("Ключ", ОписаниеТипаСтрока(0)); Результат.Колонки.Добавить("Используется", Новый ОписаниеТипов("Булево")); Результат.Колонки.Добавить("Метаданные"); Возврат Результат; КонецФункции #КонецОбласти #Область УсловныеВызовы //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для вызова необязательных подсистем. // Возвращает Истина, если функциональная подсистема существует в конфигурации. // Предназначена для реализации вызова необязательной подсистемы (условного вызова). // У функциональной подсистемы снят флажок "Включать в командный интерфейс". // См. также ОбщегоНазначенияПереопределяемый.ПриОпределенииОтключенныхПодсистем // и ОбщегоНазначенияКлиент.ПодсистемаСуществует для вызова из клиентского кода. // // Параметры: // ПолноеИмяПодсистемы - Строка - полное имя объекта метаданных подсистема // без слов "Подсистема." и с учетом регистра символов. // Например: "СтандартныеПодсистемы.ВариантыОтчетов". // // Пример: // Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВариантыОтчетов") Тогда // МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов"); // МодульВариантыОтчетов.<Имя метода>(); // КонецЕсли; // // Возвращаемое значение: // Булево - Истина, если подсистема существует. // Функция ПодсистемаСуществует(ПолноеИмяПодсистемы) Экспорт ИменаПодсистем = СтандартныеПодсистемыПовтИсп.ИменаПодсистем(); Возврат ИменаПодсистем.Получить(ПолноеИмяПодсистемы) <> Неопределено; КонецФункции // Возвращает ссылку на общий модуль или модуль менеджера по имени. // // Параметры: // Имя - Строка - имя общего модуля. // // Возвращаемое значение: // ОбщийМодуль // МодульМенеджераОбъекта // // Пример: // Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда // МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации"); // МодульОбновлениеКонфигурации.<Имя метода>(); // КонецЕсли; // // Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолнотекстовыйПоиск") Тогда // МодульПолнотекстовыйПоискСервер = ОбщегоНазначения.ОбщийМодуль("ПолнотекстовыйПоискСервер"); // МодульПолнотекстовыйПоискСервер.<Имя метода>(); // КонецЕсли; // Функция ОбщийМодуль(Имя) Экспорт Если Метаданные.ОбщиеМодули.Найти(Имя) <> Неопределено Тогда // АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно. УстановитьБезопасныйРежим(Истина); Модуль = Вычислить(Имя); // АПК:488-вкл ИначеЕсли СтрЧислоВхождений(Имя, ".") = 1 Тогда Возврат СерверныйМодульМенеджера(Имя); Иначе Модуль = Неопределено; КонецЕсли; Если ТипЗнч(Модуль) <> Тип("ОбщийМодуль") Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Общий модуль ""%1"" не существует.\'"), Имя); КонецЕсли; Возврат Модуль; КонецФункции #КонецОбласти #Область ТекущееОкружение //////////////////////////////////////////////////////////////////////////////// // Функции описания текущего окружения клиентского приложения и операционной системы. // Возвращает Истина, если клиентское приложение запущено под управлением ОС Windows. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоWindowsКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоWindowsКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоWindowsКлиент"); Если ЭтоWindowsКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоWindowsКлиент; КонецФункции // Возвращает Истина, если текущий сеанс выполняется на сервере, работающем под управлением ОС Windows. // // Возвращаемое значение: // Булево - Истина, если сервер работает под управлением ОС Windows. // Функция ЭтоWindowsСервер() Экспорт СистемнаяИнформация = Новый СистемнаяИнформация; Возврат СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64; КонецФункции // Возвращает Истина, если клиентское приложение запущено под управлением ОС Linux. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоLinuxКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоLinuxКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоLinuxКлиент"); Если ЭтоLinuxКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоLinuxКлиент; КонецФункции // Возвращает Истина, если текущий сеанс выполняется на сервере, работающем под управлением ОС Linux. // // Возвращаемое значение: // Булево - Истина, если сервер работает под управлением ОС Linux. // Функция ЭтоLinuxСервер() Экспорт СистемнаяИнформация = Новый СистемнаяИнформация; Возврат СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Linux_x86_64 Или ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, "8.3.22.1923") >= 0 И (СистемнаяИнформация.ТипПлатформы = ТипПлатформы["Linux_ARM64"] Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы["Linux_E2K"]); КонецФункции // Возвращает Истина, если клиентское приложение запущено под управлением macОС. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоMacOSКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент"); Если ЭтоMacOSКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоMacOSКлиент; КонецФункции // Возвращает Истина, если клиентское приложение является Веб-клиентом. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоВебКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоВебКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоВебКлиент"); Если ЭтоВебКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоВебКлиент; КонецФункции // Возвращает Истина, если клиентское приложение является мобильным клиентом. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоМобильныйКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоМобильныйКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоМобильныйКлиент"); Если ЭтоМобильныйКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоМобильныйКлиент; КонецФункции // Возвращает Истина, если клиентское приложение подключено к базе через веб-сервер. // // Возвращаемое значение: // Булево - Истина, если подключен. // Функция КлиентПодключенЧерезВебСервер() Экспорт УстановитьПривилегированныйРежим(Истина); СтрокаСоединенияИнформационнойБазы = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("СтрокаСоединенияИнформационнойБазы"); Если СтрокаСоединенияИнформационнойБазы = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат СтрНайти(ВРег(СтрокаСоединенияИнформационнойБазы), "WS=") = 1; КонецФункции // Возвращает системную информацию клиента, если есть клиентское приложение. // До первого серверного вызова с клиента вернет Неопределено. // // Возвращаемое значение: // ФиксированнаяСтруктура: // * ВерсияОС - Строка // * ВерсияПриложения - Строка // * ИдентификаторКлиента - УникальныйИдентификатор // * ИнформацияПрограммыПросмотра - Строка // * ОперативнаяПамять - Число // * Процессор - Строка // * ТипПлатформы - см. ОбщегоНазначенияКлиентСервер.ИмяТипаПлатформы // Неопределено - если нет клиентского приложения или информация запрашивается // до первого серверного вызова, например, при первом вызове события // платформы УстановкаПараметровСеанса в модуле сеанса. // Функция СистемнаяИнформацияКлиента() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("СистемнаяИнформация"); КонецФункции // Возвращает имя используемого клиента, а для веб-браузера название и версию, если есть. // До первого серверного вызова с клиента вернет Неопределено. // // Возвращаемое значение: // Строка - варианты строк "ВебКлиент.<Название>[.<Версия>]", "ТонкийКлиент", // "ТолстыйКлиентУправляемоеПриложение", "ТолстыйКлиентОбычноеПриложение", // где <Название> - варианты строк "Chrome", "Firefox", "Safari", "IE", "Opera" // или "Другой", когда не определен (ни один из указанных), например "ВебКлиент.Chrome.109". // Неопределено - если нет клиентского приложения или информация запрашивается // до первого серверного вызова, например, при первом вызове события // платформы УстановкаПараметровСеанса в модуле сеанса. // Функция ИспользуемыйКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИспользуемыйКлиент"); КонецФункции // Возвращает Истина, если включен режим отладки. // // Возвращаемое значение: // Булево - Истина, если включен режим отладки. // Функция РежимОтладки() Экспорт ПараметрЗапускаПриложения = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере(Ложь).Получить("ПараметрЗапуска"); Возврат СтрНайти(ПараметрЗапускаПриложения, "РежимОтладки") > 0; КонецФункции // Возвращает объем оперативной памяти, доступной клиентскому приложению. // // Возвращаемое значение: // Число - количество гигабайтов оперативной памяти с точностью до десятых долей. // Неопределено - нет клиентского приложения, то есть ТекущийРежимЗапуска() = Неопределено. // Функция ОперативнаяПамятьДоступнаяКлиентскомуПриложению() Экспорт ДоступныйОбъем = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ОперативнаяПамять"); Возврат ДоступныйОбъем; КонецФункции // Определяет режим эксплуатации информационной базы файловый (Истина) или серверный (Ложь). // При проверке используется СтрокаСоединенияИнформационнойБазы, которую можно указать явно. // // Параметры: // СтрокаСоединенияИнформационнойБазы - Строка - параметр используется, если // нужно проверить строку соединения не текущей информационной базы. // // Возвращаемое значение: // Булево - Истина, если файловая. // Функция ИнформационнаяБазаФайловая(Знач СтрокаСоединенияИнформационнойБазы = "") Экспорт Если ПустаяСтрока(СтрокаСоединенияИнформационнойБазы) Тогда СтрокаСоединенияИнформационнойБазы = СтрокаСоединенияИнформационнойБазы(); КонецЕсли; Возврат СтрНайти(ВРег(СтрокаСоединенияИнформационнойБазы), "FILE=") = 1; КонецФункции // Возвращает Истина, если эта информационная база подключена к 1С:Fresh. // // Возвращаемое значение: // Булево - признак автономного рабочего места. // Функция ЭтоАвтономноеРабочееМесто() Экспорт Если ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда МодульОбменДаннымиСервер = ОбщийМодуль("ОбменДаннымиСервер"); Возврат МодульОбменДаннымиСервер.ЭтоАвтономноеРабочееМесто(); КонецЕсли; Возврат Ложь; КонецФункции // Возвращает признак того, что информационная база является распределенной (РИБ). // // Возвращаемое значение: // Булево // Функция ЭтоРаспределеннаяИнформационнаяБаза() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ(); КонецФункции // Определяет, что эта информационная база является подчиненным узлом // распределенной информационной базы (РИБ). // // Возвращаемое значение: // Булево - Истина, если эта информационная база является подчиненным узлом РИБ. // Функция ЭтоПодчиненныйУзелРИБ() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат ПланыОбмена.ГлавныйУзел() <> Неопределено; КонецФункции // Определяет, что эта информационная база является подчиненным узлом // распределенной информационной базы (РИБ) с фильтром. // // Возвращаемое значение: // Булево - Истина, если эта информационная база является подчиненным узлом РИБ с фильтром. // Функция ЭтоПодчиненныйУзелРИБСФильтром() Экспорт УстановитьПривилегированныйРежим(Истина); Если ПланыОбмена.ГлавныйУзел() <> Неопределено И ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда МодульОбменДаннымиСервер = ОбщийМодуль("ОбменДаннымиСервер"); Если МодульОбменДаннымиСервер.НазначениеПланаОбмена(ПланыОбмена.ГлавныйУзел().Метаданные().Имя) = "РИБСФильтром" Тогда Возврат Истина; КонецЕсли; КонецЕсли; Возврат Ложь; КонецФункции // Возвращает Истина при необходимости обновления конфигурации информационной базы подчиненного узла РИБ. // В главном узле всегда Ложь. // // Возвращаемое значение: // Булево - Истина, если требуется. // Функция ТребуетсяОбновлениеКонфигурацииПодчиненногоУзлаРИБ() Экспорт Возврат ЭтоПодчиненныйУзелРИБ() И КонфигурацияИзменена(); КонецФункции // Возвращает признак работы в режиме разделения данных по областям // (технически это признак условного разделения). // // Возвращает Ложь, если конфигурация не может работать в режиме разделения данных // (не содержит общих реквизитов, предназначенных для разделения данных). // // Возвращаемое значение: // Булево - Истина, если разделение включено, // Ложь, если разделение выключено или не поддерживается. // Функция РазделениеВключено() Экспорт Возврат СтандартныеПодсистемыПовтИсп.РазделениеВключено(); КонецФункции // Возвращает признак возможности обращения к разделенным данным (которые входят в состав разделителей). // Признак относится к сеансу, но может меняться во время работы сеанса, если разделение было включено // в самом сеансе, поэтому проверку следует делать непосредственно перед обращением к разделенным данным. // // Возвращает Истина, если конфигурация не может работать в режиме разделения данных // (не содержит общих реквизитов, предназначенных для разделения данных). // // Возвращаемое значение: // Булево - Истина, если разделение не поддерживается, либо разделение выключено, // либо разделение включено и разделители установлены. // Ложь, если разделение включено и разделители не установлены. // Функция ДоступноИспользованиеРазделенныхДанных() Экспорт Возврат СтандартныеПодсистемыПовтИсп.ДоступноИспользованиеРазделенныхДанных(); КонецФункции // Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ // для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию в сети Интернет. // Например, если такой адрес включить в электронное письмо, то из письма одним нажатием // можно перейти к форме объекта в самой программе. // // Возвращаемое значение: // Строка - адрес информационной базы, как он задан в настройке "Адрес в Интернете" в панели администрирования // (хранится в константе АдресПубликацииИнформационнойБазыВИнтернете). // Например, "http://1c.com/database". // // Пример: // ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта"; // возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта. // Функция АдресПубликацииИнформационнойБазыВИнтернете() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат Константы.АдресПубликацииИнформационнойБазыВИнтернете.Получить(); КонецФункции // Возвращает адрес публикации информационной базы для формирования прямых ссылок на объекты ИБ // для возможности перехода к ним пользователей, имеющих доступ к базе через публикацию локальной сети. // Например, если такой адрес включить в электронное письмо, то из письма за одно нажатие // можно перейти к форме объекта в самой программе. // // Возвращаемое значение: // Строка - адрес информационной базы, как он задан в настройке "Локальный адрес" в панели администрирования // (хранится в константе АдресПубликацииИнформационнойБазыВЛокальнойСети). // Например, "http://localserver/base". // // Пример: // ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети() + "/" + e1cib/app/Обработка.ВыгрузкаДанныхПроекта"; // возвращает прямую ссылку для открытия обработки ВыгрузкаДанныхПроекта. // Функция АдресПубликацииИнформационнойБазыВЛокальнойСети() Экспорт УстановитьПривилегированныйРежим(Истина); Возврат Константы.АдресПубликацииИнформационнойБазыВЛокальнойСети.Получить(); КонецФункции // Формирует ссылку для входа в программу для указанного пользователя. // // Параметры: // Пользователь - Строка - логин пользователя для входа в программу; // Пароль - Строка - пароль пользователя для входа в программу; // ВидПубликацииИБ - Строка - через какую публикацию пользователь входит в программу: // "ВИнтернете" или "ВЛокальнойСети". // // Возвращаемое значение: // Строка, Неопределено - адрес входа в программу или Неопределено, если адрес не настроен. // Функция АдресВходаВПрограмму(Пользователь, Пароль, ВидПубликацииИБ) Экспорт Результат = ""; Если НРег(ВидПубликацииИБ) = НРег("ВИнтернете") Тогда Результат = АдресПубликацииИнформационнойБазыВИнтернете(); ИначеЕсли НРег(ВидПубликацииИБ) = НРег("ВЛокальнойСети") Тогда Результат = АдресПубликацииИнформационнойБазыВЛокальнойСети(); КонецЕсли; Если ПустаяСтрока(Результат) Тогда Возврат Неопределено; КонецЕсли; Если Не СтрЗаканчиваетсяНа(Результат, "/") Тогда Результат = Результат + "/"; КонецЕсли; Результат = Результат + "?n=" + КодироватьСтроку(Пользователь, СпособКодированияСтроки.КодировкаURL); Если ЗначениеЗаполнено(Пароль) Тогда Результат = Результат + "&p=" + КодироватьСтроку(Пароль, СпособКодированияСтроки.КодировкаURL); КонецЕсли; Возврат Результат; КонецФункции // Возвращает редакцию конфигурации. // Редакцией принято называть две первые группы цифр полной версии конфигурации. // Например, у версии "1.2.3.4" редакция "1.2". // // Возвращаемое значение: // Строка - номер редакции конфигурации. // Функция РедакцияКонфигурации() Экспорт Результат = ""; ВерсияКонфигурации = Метаданные.Версия; Позиция = СтрНайти(ВерсияКонфигурации, "."); Если Позиция > 0 Тогда Результат = Лев(ВерсияКонфигурации, Позиция); ВерсияКонфигурации = Сред(ВерсияКонфигурации, Позиция + 1); Позиция = СтрНайти(ВерсияКонфигурации, "."); Если Позиция > 0 Тогда Результат = Результат + Лев(ВерсияКонфигурации, Позиция - 1); Иначе Результат = ""; КонецЕсли; КонецЕсли; Если ПустаяСтрока(Результат) Тогда Результат = Метаданные.Версия; КонецЕсли; Возврат Результат; КонецФункции // Общие параметры подсистемы. // // См. ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности // // Возвращаемое значение: // Структура: // * ИмяФормыПерсональныхНастроек - Строка - имя формы для редактирования персональных настроек. // * ЗапрашиватьПодтверждениеПриЗавершенииПрограммы - Булево - по умолчанию Истина. Если установить в Ложь, то // подтверждение при завершении работы программы не // будет запрашиваться, если явно не разрешить в // персональных настройках программы. // * МинимальнаяВерсияПлатформы - Строка - минимальная версии платформы, требуемая для запуска программы. // Запуск программы на версии платформы ниже указанной будет невозможен. // Например, "8.3.6.1650". // * РекомендуемаяВерсияПлатформы - Строка - рекомендуемая версия платформы для запуска программы. // Например, "8.3.8.2137". // * ОтключитьИдентификаторыОбъектовМетаданных - Булево - отключает заполнение справочников ИдентификаторыОбъектовМетаданных // и ИдентификаторыОбъектовРасширений, процедуру выгрузки и загрузки в узлах РИБ. // Для частичного встраивания отдельных функций библиотеки в конфигурации без постановки на поддержку. // * РекомендуемыйОбъемОперативнойПамяти - Число - объем памяти в гигабайтах, рекомендуемый для комфортной работы в // программе. // Устарели, следует использовать свойства МинимальнаяВерсияПлатформы и РекомендуемаяВерсияПлатформы: // * МинимальноНеобходимаяВерсияПлатформы - Строка - полный номер версии платформы для запуска программы. // Например, "8.3.4.365". // * РаботаВПрограммеЗапрещена - Булево - начальное значение Ложь. // Функция ОбщиеПараметрыБазовойФункциональности() Экспорт ОбщиеПараметры = Новый Структура; ОбщиеПараметры.Вставить("ИмяФормыПерсональныхНастроек", ""); ОбщиеПараметры.Вставить("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", Истина); ОбщиеПараметры.Вставить("ОтключитьИдентификаторыОбъектовМетаданных", Ложь); ОбщиеПараметры.Вставить("РекомендуемыйОбъемОперативнойПамяти", 4); ОбщиеПараметры.Вставить("МинимальнаяВерсияПлатформы", МинимальнаяВерсияПлатформы()); ОбщиеПараметры.Вставить("РекомендуемаяВерсияПлатформы", ОбщиеПараметры.МинимальнаяВерсияПлатформы); // Устарело, следует использовать свойства МинимальнаяВерсияПлатформы и РекомендуемаяВерсияПлатформы: ОбщиеПараметры.Вставить("МинимальноНеобходимаяВерсияПлатформы", ""); ОбщиеПараметры.Вставить("РаботаВПрограммеЗапрещена", Ложь); // Блокировать запуск, если версия ниже минимальной. ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности(ОбщиеПараметры); ОбщиеПараметры.МинимальнаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(ОбщиеПараметры.МинимальнаяВерсияПлатформы); ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НомерСборкиПоТекущейВерсииПлатформы(ОбщиеПараметры.РекомендуемаяВерсияПлатформы); // Локализация УточнитьМинимальнуюВерсиюПлатформыИзСервиса(ОбщиеПараметры); // Конец Локализация СистемнаяИнформация = Новый СистемнаяИнформация; Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СистемнаяИнформация.ВерсияПриложения, ОбщиеПараметры.МинимальнаяВерсияПлатформы) < 0 И ЭтоВерсияЗащищенногоПрограммногоКомплекса(СистемнаяИнформация.ВерсияПриложения) Тогда ОбщиеПараметры.МинимальнаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения; ОбщиеПараметры.РекомендуемаяВерсияПлатформы = СистемнаяИнформация.ВерсияПриложения; КонецЕсли; Минимальная = ОбщиеПараметры.МинимальнаяВерсияПлатформы; Рекомендуемая = ОбщиеПараметры.РекомендуемаяВерсияПлатформы; Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда ТекстСообщения = НСтр("ru = \'Указанные в %1 минимальная и рекомендуемая версии платформы не соответствуют следующим требованиям: | - минимальная версия должна быть заполнена; | - минимальная версия не должна быть меньше минимальной версии БСП (см. %2); | - минимальная версия не должна быть меньше рекомендуемой версии. |Минимальная версия: %3 |Минимальная версия БСП: %4 |Рекомендуемая версия: %5\'", КодОсновногоЯзыка()); ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения, "ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности", "ОбщегоНазначения.МинимальнаяВерсияПлатформы", Минимальная, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), Рекомендуемая); ЗаписьЖурналаРегистрации(НСтр("ru = \'Базовая функциональность\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,, ТекстСообщения); КонецЕсли; // Обратная совместимость. МинимальноНеобходимаяВерсияПлатформы = ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы; Если ЗначениеЗаполнено(МинимальноНеобходимаяВерсияПлатформы) Тогда Если ОбщиеПараметры.РаботаВПрограммеЗапрещена Тогда ОбщиеПараметры.МинимальнаяВерсияПлатформы = МинимальноНеобходимаяВерсияПлатформы; ОбщиеПараметры.РекомендуемаяВерсияПлатформы = ""; Иначе ОбщиеПараметры.РекомендуемаяВерсияПлатформы = МинимальноНеобходимаяВерсияПлатформы; ОбщиеПараметры.МинимальнаяВерсияПлатформы = ""; КонецЕсли; Иначе Текущая = СистемнаяИнформация.ВерсияПриложения; Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Минимальная, Текущая) > 0 Тогда ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = Минимальная; ОбщиеПараметры.РаботаВПрограммеЗапрещена = Истина; Иначе ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = Рекомендуемая; ОбщиеПараметры.РаботаВПрограммеЗапрещена = Ложь; КонецЕсли; КонецЕсли; УточнитьВерсиюПлатформы(ОбщиеПараметры); Возврат ОбщиеПараметры; КонецФункции // Возвращает описания всех библиотек конфигурации, включая // описание самой конфигурации. // // Возвращаемое значение: // Массив - структур со свойствами: // * Имя - Строка - имя подсистемы, например, "СтандартныеПодсистемы". // * ИдентификаторИнтернетПоддержки - Строка - уникальное имя программы в сервисах интернет-поддержки. // * Версия - Строка - версия в формате из четырех цифр, например "2.3.3.1". // * ЭтоКонфигурация - Булево - признак того, что данная подсистема является основной конфигурацией. // Функция ОписанияПодсистем() Экспорт Результат = Новый Массив; ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем(); Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл Параметры = Новый Структура; Параметры.Вставить("Имя"); Параметры.Вставить("ИдентификаторИнтернетПоддержки"); Параметры.Вставить("Версия"); Параметры.Вставить("ЭтоКонфигурация"); ЗаполнитьЗначенияСвойств(Параметры, ОписаниеПодсистемы.Значение); Результат.Добавить(Параметры); КонецЦикла; Возврат Результат; КонецФункции // Возвращает идентификатор Интернет-поддержки основной конфигурации. // // Возвращаемое значение: // Строка - уникальное имя программы в сервисах Интернет-поддержки. // Функция ИдентификаторИнтернетПоддержкиКонфигурации() Экспорт ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем(); Для Каждого ОписаниеПодсистемы Из ОписанияПодсистем.ПоИменам Цикл Если ОписаниеПодсистемы.Значение.ЭтоКонфигурация Тогда Возврат ОписаниеПодсистемы.Значение.ИдентификаторИнтернетПоддержки; КонецЕсли; КонецЦикла; Возврат ""; КонецФункции #КонецОбласти #Область Даты //////////////////////////////////////////////////////////////////////////////// // Функции для работы с датами с учетом часового пояса сеанса // Преобразует локальную дату к формату "YYYY-MM-DDThh:mm:ssTZD" согласно ISO 8601. // // Параметры: // ЛокальнаяДата - Дата - дата в часовом поясе сеанса. // // Возвращаемое значение: // Строка - представление даты. // Функция ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата) Экспорт Смещение = СмещениеСтандартногоВремени(ЧасовойПоясСеанса()); Возврат ОбщегоНазначенияСлужебныйКлиентСервер.ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата, Смещение); КонецФункции // Возвращает строковое представление интервала между переданными датами или // относительно переданной даты и текущей даты сеанса. // // Параметры: // ВремяНачала - Дата - начальная точка интервала. // ВремяОкончания - Дата - конечная точка интервала, если не задана - берется текущая дата сеанса. // // Возвращаемое значение: // Строка - представление интервала времени. // Функция ИнтервалВремениСтрокой(ВремяНачала, ВремяОкончания = Неопределено) Экспорт Если ВремяОкончания = Неопределено Тогда ВремяОкончания = ТекущаяДатаСеанса(); ИначеЕсли ВремяНачала > ВремяОкончания Тогда ВызватьИсключение НСтр("ru = \'Дата окончания интервала не может быть меньше даты начала.\'"); КонецЕсли; ВеличинаИнтервала = ВремяОкончания - ВремяНачала; ВеличинаИнтервалаВДнях = Цел(ВеличинаИнтервала/60/60/24); Если ВеличинаИнтервалаВДнях > 365 Тогда ОписаниеИнтервала = НСтр("ru = \'более года\'"); ИначеЕсли ВеличинаИнтервалаВДнях > 31 Тогда ОписаниеИнтервала = НСтр("ru = \'более месяца\'"); ИначеЕсли ВеличинаИнтервалаВДнях >= 1 Тогда ОписаниеИнтервала = Формат(ВеличинаИнтервалаВДнях, "ЧДЦ=0") + " " + ПользователиСлужебныйКлиентСервер.ПредметЦелогоЧисла(ВеличинаИнтервалаВДнях, "", НСтр("ru = \'день,дня,дней,,,,,,0\'")); Иначе ОписаниеИнтервала = НСтр("ru = \'менее одного дня\'"); КонецЕсли; Возврат ОписаниеИнтервала; КонецФункции //////////////////////////////////////////////////////////////////////////////// // Функции для работы с настройкой рабочей даты. // Сохраняет настройку рабочей даты пользователя. // // Параметры: // НоваяРабочаяДата - Дата - дата, которую необходимо установить в качестве рабочей даты пользователя. // ИмяПользователя - Строка - имя пользователя, для которого устанавливается рабочая дата. // Если не задано, то устанавливается для текущего пользователя. // Процедура УстановитьРабочуюДатуПользователя(НоваяРабочаяДата, ИмяПользователя = Неопределено) Экспорт КлючОбъекта = ВРег("РабочаяДата"); ХранилищеОбщихНастроекСохранить(КлючОбъекта, "", НоваяРабочаяДата, , ИмяПользователя); КонецПроцедуры // Возвращает значение настройки рабочей даты для пользователя. // // Параметры: // ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата. // Если не задано, то устанавливается для текущего пользователя. // // Возвращаемое значение: // Дата - значение настройки рабочей даты пользователя или пустая дата, если настройка не задана. // Функция РабочаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт КлючОбъекта = ВРег("РабочаяДата"); Результат = ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, "", \'0001-01-01\', , ИмяПользователя); Если ТипЗнч(Результат) <> Тип("Дата") Тогда Результат = \'0001-01-01\'; КонецЕсли; Возврат Результат; КонецФункции // Возвращает значение настройки рабочей даты для пользователя или текущей даты сеанса, // если рабочая дата пользователя не задана. // // Параметры: // ИмяПользователя - Строка - имя пользователя, для которого запрашивается рабочая дата. // Если не задано, то устанавливается для текущего пользователя. // // Возвращаемое значение: // Дата - значение настройки рабочей даты пользователя или текущая дата сеанса, если настройка не задана. // Функция ТекущаяДатаПользователя(ИмяПользователя = Неопределено) Экспорт Результат = РабочаяДатаПользователя(ИмяПользователя); Если НЕ ЗначениеЗаполнено(Результат) Тогда Результат = ТекущаяДатаСеанса(); КонецЕсли; Возврат НачалоДня(Результат); КонецФункции #КонецОбласти #Область Данные //////////////////////////////////////////////////////////////////////////////// // Общие процедуры и функции для работы с прикладными типами и коллекциями значений. // Возвращает строковое имя значения перечисления по его ссылке. // Вызывает исключение, если передано несуществующее значение перечисления // (например, удаленное в конфигурации или от отключенного расширения конфигурации). // // Параметры: // Значение - ПеречислениеСсылка - значение, для которого необходимо получить имя перечисления. // // Возвращаемое значение: // Строка // // Пример: // В результат будет помещено строковое значение "ФизическоеЛицо": // Результат = ОбщегоНазначения.ИмяЗначенияПеречисления(Перечисления.ЮридическоеФизическоеЛицо.ФизическоеЛицо); // Функция ИмяЗначенияПеречисления(Значение) Экспорт ОбъектМетаданных = Значение.Метаданные(); ИндексЗначения = Перечисления[ОбъектМетаданных.Имя].Индекс(Значение); Возврат ОбъектМетаданных.ЗначенияПеречисления[ИндексЗначения].Имя; КонецФункции // Процедура удаляет из массива МассивРеквизитов элементы, соответствующие именам // реквизитов объекта из массива МассивНепроверяемыхРеквизитов. // Для использования в обработчиках события ОбработкаПроверкиЗаполнения. // // Параметры: // МассивРеквизитов - Массив - коллекция имен реквизитов объекта. // МассивНепроверяемыхРеквизитов - Массив - коллекция имен реквизитов объекта, не требующих проверки. // Процедура УдалитьНепроверяемыеРеквизитыИзМассива(МассивРеквизитов, МассивНепроверяемыхРеквизитов) Экспорт Для Каждого ЭлементМассива Из МассивНепроверяемыхРеквизитов Цикл ПорядковыйНомер = МассивРеквизитов.Найти(ЭлементМассива); Если ПорядковыйНомер <> Неопределено Тогда МассивРеквизитов.Удалить(ПорядковыйНомер); КонецЕсли; КонецЦикла; КонецПроцедуры // Преобразует таблицу значений в массив структур. // Может использоваться для передачи на клиент данных в том случае, если таблица // значений содержит только такие значения, которые могут // быть переданы с сервера на клиент. // // Полученный массив содержит структуры, каждая из которых повторяет // структуру колонок таблицы значений. // // Не рекомендуется использовать для преобразования таблиц значений // с большим количеством строк. // // Параметры: // ТаблицаЗначений - ТаблицаЗначений - исходная таблица значений. // // Возвращаемое значение: // Массив - коллекция строк таблицы в виде структур. // Функция ТаблицаЗначенийВМассив(ТаблицаЗначений) Экспорт Массив = Новый Массив(); СтруктураСтрокой = ""; НужнаЗапятая = Ложь; Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл Если НужнаЗапятая Тогда СтруктураСтрокой = СтруктураСтрокой + ","; КонецЕсли; СтруктураСтрокой = СтруктураСтрокой + Колонка.Имя; НужнаЗапятая = Истина; КонецЦикла; Для Каждого Строка Из ТаблицаЗначений Цикл НоваяСтрока = Новый Структура(СтруктураСтрокой); ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка); Массив.Добавить(НоваяСтрока); КонецЦикла; Возврат Массив; КонецФункции // Преобразует строку таблицы значений в структуру. // Свойства структуры и их значения совпадают с колонками переданной строки. // // Параметры: // СтрокаТаблицыЗначений - СтрокаТаблицыЗначений // // Возвращаемое значение: // Структура - преобразованная строка таблицы значений. // Функция СтрокаТаблицыЗначенийВСтруктуру(СтрокаТаблицыЗначений) Экспорт Структура = Новый Структура; Для каждого Колонка Из СтрокаТаблицыЗначений.Владелец().Колонки Цикл Структура.Вставить(Колонка.Имя, СтрокаТаблицыЗначений[Колонка.Имя]); КонецЦикла; Возврат Структура; КонецФункции // Создает структуру, содержащую имена и значения измерений, ресурсов и реквизитов // переданного менеджера записи регистра сведений. // // Параметры: // МенеджерЗаписи - РегистрСведенийМенеджерЗаписиИмяРегистраСведений - менеджер записи, из которого надо получить структуру. // МетаданныеРегистра - ОбъектМетаданныхРегистрСведений - метаданные регистра сведений. // // Возвращаемое значение: // Структура - коллекция измерений ресурсов и реквизитов, переданного менеджеру записи. // Функция СтруктураПоМенеджеруЗаписи(МенеджерЗаписи, МетаданныеРегистра) Экспорт ЗаписьКакСтруктура = Новый Структура; Если МетаданныеРегистра.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда ЗаписьКакСтруктура.Вставить("Период", МенеджерЗаписи.Период); КонецЕсли; Для Каждого Поле Из МетаданныеРегистра.Измерения Цикл ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]); КонецЦикла; Для Каждого Поле Из МетаданныеРегистра.Ресурсы Цикл ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]); КонецЦикла; Для Каждого Поле Из МетаданныеРегистра.Реквизиты Цикл ЗаписьКакСтруктура.Вставить(Поле.Имя, МенеджерЗаписи[Поле.Имя]); КонецЦикла; Возврат ЗаписьКакСтруктура; КонецФункции // Создает массив и копирует в него значения, содержащиеся в колонке объекта, для // которого доступен обход посредством оператора Для каждого … Из. // // Параметры: // КоллекцияСтрок - ТаблицаЗначений // - ДеревоЗначений // - СписокЗначений // - ТабличнаяЧасть // - Соответствие // - Структура - коллекция, колонку которой нужно выгрузить в массив. // А так же другие объекты, для которых доступен обход // посредством оператора Для каждого … Из … Цикл. // ИмяКолонки - Строка - имя поля коллекции, значения которого нужно выгрузить. // ТолькоУникальныеЗначения - Булево - если Истина, то в массив будут включены // только различающиеся значения. // // Возвращаемое значение: // Массив - значения колонки. // Функция ВыгрузитьКолонку(КоллекцияСтрок, ИмяКолонки, ТолькоУникальныеЗначения = Ложь) Экспорт МассивЗначений = Новый Массив; УникальныеЗначения = Новый Соответствие; Для каждого СтрокаКоллекции Из КоллекцияСтрок Цикл Значение = СтрокаКоллекции[ИмяКолонки]; Если ТолькоУникальныеЗначения И УникальныеЗначения[Значение] <> Неопределено Тогда Продолжить; КонецЕсли; МассивЗначений.Добавить(Значение); УникальныеЗначения.Вставить(Значение, Истина); КонецЦикла; Возврат МассивЗначений; КонецФункции // Преобразует текст указанного формата XML в таблицу значений, // при этом колонки таблицы формируются на основе описания в XML. // // Схема XML: // <?xml version="1.0" encoding="utf-8"?> // <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> // <xs:element name="Items"> // <xs:complexType> // <xs:sequence> // <xs:element maxOccurs="unbounded" name="Item"> // <xs:complexType> // <xs:attribute name="Code" type="xs:integer" use="required" /> // <xs:attribute name="Name" type="xs:string" use="required" /> // <xs:attribute name="Socr" type="xs:string" use="required" /> // <xs:attribute name="Index" type="xs:string" use="required" /> // </xs:complexType> // </xs:element> // </xs:sequence> // <xs:attribute name="Description" type="xs:string" use="required" /> // <xs:attribute name="Columns" type="xs:string" use="required" /> // </xs:complexType> // </xs:element> // </xs:schema> // // Параметры: // XML - Строка // - ЧтениеXML - текст в формате XML или ЧтениеXML. // // Возвращаемое значение: // Структура: // * ИмяТаблицы - Строка - имя таблицы. // * Данные - ТаблицаЗначений - преобразованная из XML таблица. // // Пример: // КлассификаторТаблица = ОбщегоНазначения.ПрочитатьXMLВТаблицу( // Обработки.ЗагрузкаКурсовВалют.ПолучитьМакет("ОбщероссийскийКлассификаторВалют").ПолучитьТекст()).Данные; // Функция ПрочитатьXMLВТаблицу(Знач XML) Экспорт Если ТипЗнч(XML) <> Тип("ЧтениеXML") Тогда Чтение = Новый ЧтениеXML; Чтение.УстановитьСтроку(XML); Иначе Чтение = XML; КонецЕсли; // Прочитаем первый узел и проверим его. Если Не Чтение.Прочитать() Тогда ВызватьИсключение НСтр("ru = \'Пустой XML\'"); ИначеЕсли Чтение.Имя <> "Items" Тогда ВызватьИсключение НСтр("ru = \'Ошибка в структуре XML\'"); КонецЕсли; // Получим описание таблицы и создадим ее. ИмяТаблицы = Чтение.ПолучитьАтрибут("Description"); ИменаКолонок = СтрЗаменить(Чтение.ПолучитьАтрибут("Columns"), ",", Символы.ПС); Колонок = СтрЧислоСтрок(ИменаКолонок); ТаблицаЗначений = Новый ТаблицаЗначений; Для Сч = 1 По Колонок Цикл ТаблицаЗначений.Колонки.Добавить(СтрПолучитьСтроку(ИменаКолонок, Сч), Новый ОписаниеТипов("Строка")); КонецЦикла; // Заполним значения в таблице. Пока Чтение.Прочитать() Цикл Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И Чтение.Имя = "Items" Тогда Прервать; ИначеЕсли Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда Продолжить; ИначеЕсли Чтение.Имя <> "Item" Тогда ВызватьИсключение НСтр("ru = \'Ошибка в структуре XML\'"); КонецЕсли; новСтр = ТаблицаЗначений.Добавить(); Для Сч = 1 По Колонок Цикл ИмяКолонки = СтрПолучитьСтроку(ИменаКолонок, Сч); новСтр[Сч-1] = Чтение.ПолучитьАтрибут(ИмяКолонки); КонецЦикла; КонецЦикла; // Заполним результат Результат = Новый Структура; Результат.Вставить("ИмяТаблицы", ИмяТаблицы); Результат.Вставить("Данные", ТаблицаЗначений); Возврат Результат; КонецФункции // Сравнивает две коллекции строк (ТаблицаЗначений, ДеревоЗначений и т.д.), // для которых доступен обход посредством оператора Для каждого … Из … Цикл. // Сравниваемые коллекции должны отвечать следующим требованиям: // - доступен обход посредством оператора Для каждого … Из … Цикл, // - наличие в обеих коллекциях всех колонок, перечисленных в параметре ИменаКолонок // (если ИменаКолонок не заполнен - все колонки первой коллекции должны существовать во второй коллекции). // Также позволяет сравнивать массивы. // // Параметры: // КоллекцияСтрок1 - ТаблицаЗначений // - ДеревоЗначений // - СписокЗначений // - ТабличнаяЧасть // - Соответствие // - Массив // - ФиксированныйМассив // - Структура - коллекция, отвечающая вышеописанным требованиям. А также другие // объекты, для которых доступен обход посредством оператора Для каждого … Из … Цикл. // КоллекцияСтрок2 - ТаблицаЗначений // - ДеревоЗначений // - СписокЗначений // - ТабличнаяЧасть // - Соответствие // - Массив // - ФиксированныйМассив // - Структура - коллекция, отвечающая вышеописанным требованиям. А также другие // объекты, для которых доступен обход посредством оператора Для каждого … Из … Цикл. // ИменаКолонок - Строка - имена колонок через запятую, по которым производится сравнение. // Не обязательно для коллекций, состав колонок которых можно определить автоматически: // ТаблицаЗначений, СписокЗначений, Соответствие, Структура. // Если не указан, то сравнение производится по колонкам первой коллекции. // Для коллекций других типов является обязательным. // ИсключаяКолонки - Строка - имена колонок, которые игнорируются при сравнении. // УчитыватьПоследовательностьСтрок - Булево - если Истина, то коллекции признаются // идентичными, только если одинаковые строки размещены в коллекциях на одинаковых местах. // // Возвращаемое значение: // Булево - Истина, если идентичны. // Функция КоллекцииИдентичны(КоллекцияСтрок1, КоллекцияСтрок2, Знач ИменаКолонок = "", Знач ИсключаяКолонки = "", УчитыватьПоследовательностьСтрок = Ложь) Экспорт ТипКоллекции = ТипЗнч(КоллекцияСтрок1); СравниваютсяМассивы = (ТипКоллекции = Тип("Массив") Или ТипКоллекции = Тип("ФиксированныйМассив")); СравниваемыеКолонки = Неопределено; Если Не СравниваютсяМассивы Тогда СравниваемыеКолонки = СравниваемыеКолонки(КоллекцияСтрок1, ИменаКолонок, ИсключаяКолонки); КонецЕсли; Если УчитыватьПоследовательностьСтрок Тогда Возврат СравнитьСУчетомПоследовательности(КоллекцияСтрок1, КоллекцияСтрок2, СравниваемыеКолонки); ИначеЕсли СравниваютсяМассивы Тогда // Для массивов используется более простой алгоритм. Возврат СравнитьМассивы(КоллекцияСтрок1, КоллекцияСтрок2); Иначе Возврат СравнитьБезУчетаПоследовательности(КоллекцияСтрок1, КоллекцияСтрок2, СравниваемыеКолонки); КонецЕсли; КонецФункции // Сравнивает данные сложной структуры с учетом вложенности. // // Параметры: // Данные1 - Структура // - ФиксированнаяСтруктура // - Соответствие // - ФиксированноеСоответствие // - Массив // - ФиксированныйМассив // - ХранилищеЗначения // - ТаблицаЗначений // - Строка // - Число // - Булево - сравниваемые данные. // Данные2 - Произвольный - те же типы, что и для параметра Данные1. // // Возвращаемое значение: // Булево - Истина, если совпадают. // Функция ДанныеСовпадают(Данные1, Данные2) Экспорт Если ТипЗнч(Данные1) <> ТипЗнч(Данные2) Тогда Возврат Ложь; КонецЕсли; Если ТипЗнч(Данные1) = Тип("Структура") ИЛИ ТипЗнч(Данные1) = Тип("ФиксированнаяСтруктура") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; Для каждого КлючИЗначение Из Данные1 Цикл СтароеЗначение = Неопределено; Если НЕ Данные2.Свойство(КлючИЗначение.Ключ, СтароеЗначение) ИЛИ НЕ ДанныеСовпадают(КлючИЗначение.Значение, СтароеЗначение) Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("Соответствие") ИЛИ ТипЗнч(Данные1) = Тип("ФиксированноеСоответствие") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; КлючиНовогоСоответствия = Новый Соответствие; Для каждого КлючИЗначение Из Данные1 Цикл КлючиНовогоСоответствия.Вставить(КлючИЗначение.Ключ, Истина); СтароеЗначение = Данные2.Получить(КлючИЗначение.Ключ); Если НЕ ДанныеСовпадают(КлючИЗначение.Значение, СтароеЗначение) Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Для каждого КлючИЗначение Из Данные2 Цикл Если КлючиНовогоСоответствия[КлючИЗначение.Ключ] = Неопределено Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("Массив") ИЛИ ТипЗнч(Данные1) = Тип("ФиксированныйМассив") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; Индекс = Данные1.Количество()-1; Пока Индекс >= 0 Цикл Если НЕ ДанныеСовпадают(Данные1.Получить(Индекс), Данные2.Получить(Индекс)) Тогда Возврат Ложь; КонецЕсли; Индекс = Индекс - 1; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("ТаблицаЗначений") Тогда Если Данные1.Количество() <> Данные2.Количество() Тогда Возврат Ложь; КонецЕсли; Если Данные1.Колонки.Количество() <> Данные2.Колонки.Количество() Тогда Возврат Ложь; КонецЕсли; Для каждого Колонка Из Данные1.Колонки Цикл Если Данные2.Колонки.Найти(Колонка.Имя) = Неопределено Тогда Возврат Ложь; КонецЕсли; Индекс = Данные1.Количество()-1; Пока Индекс >= 0 Цикл Если НЕ ДанныеСовпадают(Данные1[Индекс][Колонка.Имя], Данные2[Индекс][Колонка.Имя]) Тогда Возврат Ложь; КонецЕсли; Индекс = Индекс - 1; КонецЦикла; КонецЦикла; Возврат Истина; ИначеЕсли ТипЗнч(Данные1) = Тип("ХранилищеЗначения") Тогда Если НЕ ДанныеСовпадают(Данные1.Получить(), Данные2.Получить()) Тогда Возврат Ложь; КонецЕсли; Возврат Истина; КонецЕсли; Возврат Данные1 = Данные2; КонецФункции // Фиксирует данные типов Структура, Соответствие, Массив с учетом вложенности. // // Параметры: // Данные - Структура // - Соответствие // - Массив - коллекции, значения которых являются примитивными типами, // хранилищем значения или не могут быть изменены. Поддерживаются типы значений: // Булево, Строка, Число, Дата, Неопределено, УникальныйИдентификатор, Null, Тип, // ХранилищеЗначения, ОбщийМодуль, ОбъектМетаданных, ТипЗначенияXDTO, ТипОбъектаXDTO, // ЛюбаяСсылка. // // ВызыватьИсключение - Булево - начальное значение Истина. Когда установлено Ложь, тогда в случае наличия // нефиксируемых данных исключение не будет вызвано, при этом данные будут // зафиксированы на сколько возможно. // // Возвращаемое значение: // ФиксированнаяСтруктура, ФиксированноеСоответствие, ФиксированныйМассив - фиксированные данные, аналогичные // переданным в параметре Данные. // Функция ФиксированныеДанные(Данные, ВызыватьИсключение = Истина) Экспорт Если ТипЗнч(Данные) = Тип("Массив") Тогда Массив = Новый Массив; Для каждого Значение Из Данные Цикл Если ТипЗнч(Значение) = Тип("Структура") ИЛИ ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда Массив.Добавить(ФиксированныеДанные(Значение, ВызыватьИсключение)); Иначе Если ВызыватьИсключение Тогда ПроверкаФиксированностиДанных(Значение, Истина); КонецЕсли; Массив.Добавить(Значение); КонецЕсли; КонецЦикла; Возврат Новый ФиксированныйМассив(Массив); ИначеЕсли ТипЗнч(Данные) = Тип("Структура") ИЛИ ТипЗнч(Данные) = Тип("Соответствие") Тогда Если ТипЗнч(Данные) = Тип("Структура") Тогда Коллекция = Новый Структура; Иначе Коллекция = Новый Соответствие; КонецЕсли; Для каждого КлючИЗначение Из Данные Цикл Значение = КлючИЗначение.Значение; Если ТипЗнч(Значение) = Тип("Структура") ИЛИ ТипЗнч(Значение) = Тип("Соответствие") ИЛИ ТипЗнч(Значение) = Тип("Массив") Тогда Коллекция.Вставить( КлючИЗначение.Ключ, ФиксированныеДанные(Значение, ВызыватьИсключение)); Иначе Если ВызыватьИсключение Тогда ПроверкаФиксированностиДанных(Значение, Истина); КонецЕсли; Коллекция.Вставить(КлючИЗначение.Ключ, Значение); КонецЕсли; КонецЦикла; Если ТипЗнч(Данные) = Тип("Структура") Тогда Возврат Новый ФиксированнаяСтруктура(Коллекция); Иначе Возврат Новый ФиксированноеСоответствие(Коллекция); КонецЕсли; ИначеЕсли ВызыватьИсключение Тогда ПроверкаФиксированностиДанных(Данные); КонецЕсли; Возврат Данные; КонецФункции // Вычисляет контрольную сумму для произвольных данных по указанному алгоритму. // // Параметры: // Данные - Произвольный - любое сериализуемое значение. // Алгоритм - ХешФункция - алгоритм расчета контрольной суммы. По умолчанию, MD5. // // Возвращаемое значение: // Строка - контрольная сумма строкой без пробелов (например 32 символа). // Функция КонтрольнаяСуммаСтрокой(Знач Данные, Знач Алгоритм = Неопределено) Экспорт Если Алгоритм = Неопределено Тогда Алгоритм = ХешФункция.MD5; КонецЕсли; ХешированиеДанных = Новый ХешированиеДанных(Алгоритм); Если ТипЗнч(Данные) <> Тип("Строка") И ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Тогда Данные = ЗначениеВСтрокуXML(Данные); КонецЕсли; ХешированиеДанных.Добавить(Данные); Если ТипЗнч(ХешированиеДанных.ХешСумма) = Тип("ДвоичныеДанные") Тогда Результат = СтрЗаменить(ХешированиеДанных.ХешСумма, " ", ""); ИначеЕсли ТипЗнч(ХешированиеДанных.ХешСумма) = Тип("Число") Тогда Результат = Формат(ХешированиеДанных.ХешСумма, "ЧГ="); КонецЕсли; Возврат Результат; КонецФункции // Сокращает строку до нужной длины, при этом обрезанная часть хешируется, // обеспечивая уникальность строки. Проверяет длину строки на входе и, в случае // превышения максимальной длины, преобразует ее конец по алгоритму MD5 в // уникальную строку из 32 символов. // // Параметры: // Строка - Строка - исходная строка произвольной длины. // МаксимальнаяДлина - Число - требуемое максимальное количество символов в строке, // минимальное значение: 32. // // Возвращаемое значение: // Строка - строка, не превышающая максимальную длину. // Функция СократитьСтрокуКонтрольнойСуммой(Строка, МаксимальнаяДлина) Экспорт Если МаксимальнаяДлина < 32 Тогда ОбщегоНазначенияКлиентСервер.Проверить(Ложь, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Параметр %1 не может быть меньше 32.\'"), "МаксимальнаяДлина"), "ОбщегоНазначения.СократитьСтрокуКонтрольнойСуммой"); КонецЕсли; Результат = Строка; Если СтрДлина(Строка) > МаксимальнаяДлина Тогда Результат = Лев(Строка, МаксимальнаяДлина - 32); ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5); ХешированиеДанных.Добавить(Сред(Строка, МаксимальнаяДлина - 32 + 1)); Результат = Результат + СтрЗаменить(ХешированиеДанных.ХешСумма, " ", ""); КонецЕсли; Возврат Результат; КонецФункции // Создает полную копию структуры, соответствия, массива, списка или таблицы значений, рекурсивно, // с учетом типов дочерних элементов. При этом содержимое значений объектных типов // (СправочникОбъект, ДокументОбъект и т.п.) не копируются, а возвращаются ссылки на исходный объект. // // Параметры: // Источник - Структура // - ФиксированнаяСтруктура // - Соответствие // - ФиксированноеСоответствие // - Массив // - ФиксированныйМассив // - СписокЗначений - объект, который необходимо скопировать. // ФиксироватьДанные - Булево - если Истина - фиксировать, если Ложь - снять фиксацию. // - Неопределено - не изменять. // // Возвращаемое значение: // Структура, // ФиксированнаяСтруктура, // Соответствие // ФиксированноеСоответствие // Массив // ФиксированныйМассив // СписокЗначений - копия объекта, переданного в параметре Источник. // Функция СкопироватьРекурсивно(Источник, ФиксироватьДанные = Неопределено) Экспорт Перем Приемник; ТипИсточника = ТипЗнч(Источник); Если ТипИсточника = Тип("ТаблицаЗначений") Тогда Приемник = Источник.Скопировать(); СкопироватьЗначенияТаблицыЗначений(Приемник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("ДеревоЗначений") Тогда Приемник = Источник.Скопировать(); СкопироватьЗначенияСтрокиДереваЗначений(Приемник.Строки, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("Структура") Или ТипИсточника = Тип("ФиксированнаяСтруктура") Тогда Приемник = СкопироватьСтруктуру(Источник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("Соответствие") Или ТипИсточника = Тип("ФиксированноеСоответствие") Тогда Приемник = СкопироватьСоответствие(Источник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("Массив") Или ТипИсточника = Тип("ФиксированныйМассив") Тогда Приемник = СкопироватьМассив(Источник, ФиксироватьДанные); ИначеЕсли ТипИсточника = Тип("СписокЗначений") Тогда Приемник = СкопироватьСписокЗначений(Источник, ФиксироватьДанные); Иначе Приемник = Источник; КонецЕсли; Возврат Приемник; КонецФункции // Возвращает описание предмета в виде текстовой строки. // Для документов возвращается представление, для остальных ссылочных типов возвращается // представление и тип в скобках, например, "Ножницы (Номенклатура)". // Для пустых ссылок, Неопределено или незаполненных значений примитивных типов возвращается "не задан". // // Параметры: // СсылкаНаПредмет - Произвольный. // // Возвращаемое значение: // Строка - например, "Ножницы (Номенклатура)", "Заказ клиента № 0001 от 01.01.2001" или "не задан". // Функция ПредметСтрокой(СсылкаНаПредмет) Экспорт Если СсылкаНаПредмет <> Неопределено Тогда Возврат ПредметыСтрокой(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СсылкаНаПредмет))[СсылкаНаПредмет]; Иначе Возврат НСтр("ru = \'не задан\'"); КонецЕсли; КонецФункции // Возвращает описания предметов СсылкиНаПредметы. // Для документов возвращается представление, для остальных ссылочных типов возвращается // представление и тип в скобках, например, "Ножницы (Номенклатура)". // Для пустых ссылок или незаполненных значений примитивных типов возвращается "не задан". // Значение "удален", если объект не существует в информационной базе. // Значения Неопределено пропускаются. // // Параметры: // СсылкиНаПредметы - Массив из ЛюбаяСсылка // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка // * Значение - Строка - например, "Ножницы (Номенклатура)", "Заказ клиента № 0001 от 01.01.2001" или "не задан". // Функция ПредметыСтрокой(Знач СсылкиНаПредметы) Экспорт ПроверяемыеСсылки = Новый Массив; Результат = Новый Соответствие; Для каждого СсылкаНаПредмет Из СсылкиНаПредметы Цикл Если СсылкаНаПредмет = Неопределено Тогда Результат[СсылкаНаПредмет] = НСтр("ru = \'не задан\'"); ИначеЕсли Не ЭтоСсылка(ТипЗнч(СсылкаНаПредмет)) Тогда Результат[СсылкаНаПредмет] = Строка(СсылкаНаПредмет); ИначеЕсли СсылкаНаПредмет.Пустая() Тогда Результат[СсылкаНаПредмет] = НСтр("ru = \'не задан\'"); ИначеЕсли Метаданные.Перечисления.Содержит(СсылкаНаПредмет.Метаданные()) Тогда Результат[СсылкаНаПредмет] = Строка(СсылкаНаПредмет); Иначе ПроверяемыеСсылки.Добавить(СсылкаНаПредмет); КонецЕсли; КонецЦикла; Для каждого СуществующаяСсылка Из ПредставленияСсылок(ПроверяемыеСсылки) Цикл СсылкаНаПредмет = СуществующаяСсылка.Ключ; Результат[СсылкаНаПредмет] = СуществующаяСсылка.Значение; Если Не Метаданные.Документы.Содержит(СсылкаНаПредмет.Метаданные()) Тогда ПредставлениеОбъекта = СсылкаНаПредмет.Метаданные().ПредставлениеОбъекта; Если ПустаяСтрока(ПредставлениеОбъекта) Тогда ПредставлениеОбъекта = СсылкаНаПредмет.Метаданные().Представление(); КонецЕсли; Результат[СсылкаНаПредмет] = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1 (%2)", Результат[СсылкаНаПредмет], ПредставлениеОбъекта); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Возвращает представления переданных ссылок. // // Параметры: // ПроверяемыеСсылки - Массив из ЛюбаяСсылка, ЛюбаяСсылка // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ЛюбаяСсылка // * Значение - Строка - представление ссылки или "удален", если ссылка не существует в информационной базе. // Функция ПредставленияСсылок(ПроверяемыеСсылки) Экспорт ОбъектыПоТипу = Новый Соответствие; Если ТипЗнч(ПроверяемыеСсылки) = Тип("Массив") Тогда Для каждого ПроверяемаяСсылка Из ПроверяемыеСсылки Цикл Объекты = ОбъектыПоТипу[ПроверяемаяСсылка.Метаданные()]; Если Объекты = Неопределено Тогда Объекты = Новый Массив; ОбъектыПоТипу[ПроверяемаяСсылка.Метаданные()] = Объекты; КонецЕсли; Объекты.Добавить(ПроверяемаяСсылка); КонецЦикла; Иначе ОбъектыПоТипу[ПроверяемыеСсылки.Метаданные()] = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПроверяемыеСсылки); КонецЕсли; Результат = Новый Соответствие; Если ОбъектыПоТипу.Количество() = 0 Тогда Возврат Результат; КонецЕсли; Запрос = Новый Запрос; ТекстыЗапросов = Новый Массив; Индекс = 0; Для каждого ТипОбъекта Из ОбъектыПоТипу Цикл ТекстЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ | Представление КАК Представление, | Таблица.Ссылка КАК Ссылка |ИЗ | &ИмяТаблицы КАК Таблица |ГДЕ | Таблица.Ссылка В (&Ссылка)"; Если ТекстыЗапросов.Количество() > 0 Тогда ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВЫБРАТЬ РАЗРЕШЕННЫЕ", "ВЫБРАТЬ"); // @query-part-1, @query-part-2 КонецЕсли; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ТипОбъекта.Ключ.ПолноеИмя()); ИмяПараметра = "Ссылка" + Формат(Индекс, "ЧГ=;ЧН="); ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&Ссылка", "&" + ИмяПараметра); ТекстыЗапросов.Добавить(ТекстЗапроса); Запрос.УстановитьПараметр(ИмяПараметра, ТипОбъекта.Значение); Индекс = Индекс + 1; КонецЦикла; Запрос.Текст = СтрСоединить(ТекстыЗапросов, Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС); // @query-part; УстановитьПривилегированныйРежим(Истина); ФактическиеСсылки = Запрос.Выполнить().Выгрузить(); УстановитьПривилегированныйРежим(Ложь); ПредставленияСсылок = Запрос.Выполнить().Выгрузить(); ПредставленияСсылок.Индексы.Добавить("Ссылка"); Для каждого Ссылка Из ФактическиеСсылки Цикл Если ЗначениеЗаполнено(Ссылка.Ссылка) Тогда ПредставлениеСсылки = ПредставленияСсылок.Найти(Ссылка.Ссылка, "Ссылка"); Результат[Ссылка.Ссылка] = ?(ПредставлениеСсылки <> Неопределено, ПредставлениеСсылки.Представление, Строка(Ссылка.Ссылка)); КонецЕсли; КонецЦикла; Для каждого Ссылка Из ПроверяемыеСсылки Цикл Если Результат[Ссылка] = Неопределено Тогда Результат[Ссылка] = НСтр("ru = \'удален\'"); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции #КонецОбласти #Область ДинамическийСписок // Создает структуру для второго параметра СвойстваСписка процедуры УстановитьСвойстваДинамическогоСписка. // // Возвращаемое значение: // Структура - любое поле может иметь значение Неопределено, если оно не устанавливается: // * ТекстЗапроса - Строка - новый текст запроса. // * ОсновнаяТаблица - Строка - имя основной таблицы. // * ДинамическоеСчитываниеДанных - Булево - признак использования динамического считывания. // Функция СтруктураСвойствДинамическогоСписка() Экспорт Возврат Новый Структура("ТекстЗапроса, ОсновнаяТаблица, ДинамическоеСчитываниеДанных"); КонецФункции // Установить текст запроса, основную таблицу или динамическое считывание в динамическом списке. // Устанавливать эти свойства следует за один вызов этой процедуры, чтобы не снижалась производительность. // // Параметры: // Список - ТаблицаФормы - элемент формы динамического списка, для которого устанавливаются свойства. // СвойстваСписка - см. СтруктураСвойствДинамическогоСписка // Процедура УстановитьСвойстваДинамическогоСписка(Список, СвойстваСписка) Экспорт Форма = Список.Родитель; ТипФормаКлиентскогоПриложения = Тип("ФормаКлиентскогоПриложения"); Пока ТипЗнч(Форма) <> ТипФормаКлиентскогоПриложения Цикл Форма = Форма.Родитель; КонецЦикла; ДинамическийСписок = Форма[Список.ПутьКДанным]; ТекстЗапроса = СвойстваСписка.ТекстЗапроса; Если Не ПустаяСтрока(ТекстЗапроса) Тогда ДинамическийСписок.ТекстЗапроса = ТекстЗапроса; КонецЕсли; ОсновнаяТаблица = СвойстваСписка.ОсновнаяТаблица; Если ОсновнаяТаблица <> Неопределено Тогда ДинамическийСписок.ОсновнаяТаблица = ОсновнаяТаблица; КонецЕсли; ДинамическоеСчитываниеДанных = СвойстваСписка.ДинамическоеСчитываниеДанных; Если ТипЗнч(ДинамическоеСчитываниеДанных) = Тип("Булево") Тогда ДинамическийСписок.ДинамическоеСчитываниеДанных = ДинамическоеСчитываниеДанных; КонецЕсли; КонецПроцедуры #КонецОбласти #Область ВнешнееСоединение //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с внешним соединением. // Возвращает CLSID COM-класса для работы с "1С:Предприятием 8" через COM-соединение. // // Параметры: // ИмяCOMСоединителя - Строка - имя COM-класса для работы с "1С:Предприятием 8" через COM-соединение. // // Возвращаемое значение: // Строка - строковое представление CLSID. // Функция ИдентификаторCOMСоединителя(Знач ИмяCOMСоединителя) Экспорт Если ИмяCOMСоединителя = "v83.COMConnector" Тогда Возврат "181E893D-73A4-4722-B61D-D604B3D67D47"; КонецЕсли; ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'На задан CLSID для класса %1.\'"), ИмяCOMСоединителя); КонецФункции // Устанавливает внешнее соединение с информационной базой по переданным параметрам подключения и возвращает указатель // на это соединение. // // Параметры: // Параметры - см. ОбщегоНазначенияКлиентСервер.СтруктураПараметровДляУстановкиВнешнегоСоединения // // Возвращаемое значение: // Структура: // * Соединение - COMОбъект // - Неопределено - COM-объект соединения или Неопределено в случае ошибки; // * КраткоеОписаниеОшибки - Строка - краткое описание ошибки; // * ПодробноеОписаниеОшибки - Строка - подробное описание ошибки; // * ОшибкаПодключенияКомпоненты - Булево - флаг ошибки подключения COM. // Функция УстановитьВнешнееСоединениеСБазой(Параметры) Экспорт ПодключениеНедоступно = ЭтоLinuxСервер(); КраткоеОписаниеОшибки = НСтр("ru = \'Прямое подключение к информационной базе недоступно на сервере под управлением ОС Linux.\'"); Возврат ОбщегоНазначенияСлужебныйКлиентСервер.УстановитьВнешнееСоединениеСБазой(Параметры, ПодключениеНедоступно, КраткоеОписаниеОшибки); КонецФункции #КонецОбласти #Область Метаданные //////////////////////////////////////////////////////////////////////////////// // Функции определения типов объектов метаданных. // Ссылочные типы данных // Определяет принадлежность объекта метаданных к общему типу "Документ". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к документам. // // Возвращаемое значение: // Булево - Истина, если объект является документом. // Функция ЭтоДокумент(ОбъектМетаданных) Экспорт Возврат Метаданные.Документы.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Справочник". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является справочником. // Функция ЭтоСправочник(ОбъектМетаданных) Экспорт Возврат Метаданные.Справочники.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Перечисление". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является перечислением. // Функция ЭтоПеречисление(ОбъектМетаданных) Экспорт Возврат Метаданные.Перечисления.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План обмена". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом обмена. // Функция ЭтоПланОбмена(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыОбмена.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План видов характеристик". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом видов характеристик. // Функция ЭтоПланВидовХарактеристик(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Бизнес-процесс". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является бизнес-процессом. // Функция ЭтоБизнесПроцесс(ОбъектМетаданных) Экспорт Возврат Метаданные.БизнесПроцессы.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Задача". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является задачей. // Функция ЭтоЗадача(ОбъектМетаданных) Экспорт Возврат Метаданные.Задачи.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План счетов". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом счетов. // Функция ЭтоПланСчетов(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "План видов расчета". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является планом видов расчета. // Функция ЭтоПланВидовРасчета(ОбъектМетаданных) Экспорт Возврат Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных); КонецФункции // Регистры // Определяет принадлежность объекта метаданных к общему типу "Регистр сведений". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром сведений. // Функция ЭтоРегистрСведений(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Регистр накопления". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром накопления. // Функция ЭтоРегистрНакопления(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Регистр бухгалтерии". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром бухгалтерии. // Функция ЭтоРегистрБухгалтерии(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к общему типу "Регистр расчета". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регистром расчета. // Функция ЭтоРегистрРасчета(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных); КонецФункции // Константы // Определяет принадлежность объекта метаданных к общему типу "Константа". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является константой. // Функция ЭтоКонстанта(ОбъектМетаданных) Экспорт Возврат Метаданные.Константы.Содержит(ОбъектМетаданных); КонецФункции // Журналы документов // Определяет принадлежность объекта метаданных к общему типу "Журнал документов". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является журналом документов. // Функция ЭтоЖурналДокументов(ОбъектМетаданных) Экспорт Возврат Метаданные.ЖурналыДокументов.Содержит(ОбъектМетаданных); КонецФункции // Последовательности // Определяет принадлежность объекта метаданных к общему типу "Последовательности". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является последовательностью. // Функция ЭтоПоследовательность(ОбъектМетаданных) Экспорт Возврат Метаданные.Последовательности.Содержит(ОбъектМетаданных); КонецФункции // РегламентныеЗадания // Определяет принадлежность объекта метаданных к общему типу "Регламентные задания". // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является регламентным заданием. // Функция ЭтоРегламентноеЗадание(ОбъектМетаданных) Экспорт Возврат Метаданные.РегламентныеЗадания.Содержит(ОбъектМетаданных); КонецФункции // Общие // Определяет принадлежность объекта метаданных к типу регистр. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект является каким-либо регистром. // Функция ЭтоРегистр(ОбъектМетаданных) Экспорт Возврат Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных) Или Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных) Или Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных) Или Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных); КонецФункции // Определяет принадлежность объекта метаданных к ссылочному типу. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо определить принадлежность к заданному типу. // // Возвращаемое значение: // Булево - Истина, если объект ссылочного типа. // Функция ЭтоОбъектСсылочногоТипа(ОбъектМетаданных) Экспорт ИмяОбъектаМетаданных = ОбъектМетаданных.ПолноеИмя(); Позиция = СтрНайти(ИмяОбъектаМетаданных, "."); Если Позиция > 0 Тогда ИмяБазовогоТипа = Лев(ИмяОбъектаМетаданных, Позиция - 1); Возврат ИмяБазовогоТипа = "Справочник" Или ИмяБазовогоТипа = "Документ" Или ИмяБазовогоТипа = "БизнесПроцесс" Или ИмяБазовогоТипа = "Задача" Или ИмяБазовогоТипа = "ПланСчетов" Или ИмяБазовогоТипа = "ПланОбмена" Или ИмяБазовогоТипа = "ПланВидовХарактеристик" Или ИмяБазовогоТипа = "ПланВидовРасчета"; Иначе Возврат Ложь; КонецЕсли; КонецФункции //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с типами, объектами метаданных и их строковыми представлениями. // Возвращает имена реквизитов объекта заданного типа. // // Параметры: // Ссылка - ЛюбаяСсылка - ссылка на элемент базы данных, для которого требуется получить результат функции; // Тип - Тип - тип значения реквизита. // // Возвращаемое значение: // Строка - строка реквизитов объекта метаданных конфигурации, разделенных символом ",". // // Пример: // РеквизитыОрганизации = ОбщегоНазначения.ИменаРеквизитовПоТипу(Документ.Ссылка, Тип("СправочникСсылка.Организации")); // Функция ИменаРеквизитовПоТипу(Ссылка, Тип) Экспорт Результат = ""; МетаданныеОбъекта = Ссылка.Метаданные(); Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл Если Реквизит.Тип.СодержитТип(Тип) Тогда Результат = Результат + ?(ПустаяСтрока(Результат), "", ", ") + Реквизит.Имя; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Возвращает имя базового типа по переданному значению объекта метаданных. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект метаданных, по которому необходимо определить базовый тип. // // Возвращаемое значение: // Строка - имя базового типа по переданному значению объекта метаданных. // // Пример: // ИмяБазовогоТипа = ОбщегоНазначения.ИмяБазовогоТипаПоОбъектуМетаданных(Метаданные.Справочники.Номенклатура); = "Справочники". // Функция ИмяБазовогоТипаПоОбъектуМетаданных(ОбъектМетаданных) Экспорт Если Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда Возврат "Документы"; ИначеЕсли Метаданные.Справочники.Содержит(ОбъектМетаданных) Тогда Возврат "Справочники"; ИначеЕсли Метаданные.Перечисления.Содержит(ОбъектМетаданных) Тогда Возврат "Перечисления"; ИначеЕсли Метаданные.РегистрыСведений.Содержит(ОбъектМетаданных) Тогда Возврат "РегистрыСведений"; ИначеЕсли Метаданные.РегистрыНакопления.Содержит(ОбъектМетаданных) Тогда Возврат "РегистрыНакопления"; ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМетаданных) Тогда Возврат "РегистрыБухгалтерии"; ИначеЕсли Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных) Тогда Возврат "РегистрыРасчета"; ИначеЕсли Метаданные.ПланыОбмена.Содержит(ОбъектМетаданных) Тогда Возврат "ПланыОбмена"; ИначеЕсли Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных) Тогда Возврат "ПланыВидовХарактеристик"; ИначеЕсли Метаданные.БизнесПроцессы.Содержит(ОбъектМетаданных) Тогда Возврат "БизнесПроцессы"; ИначеЕсли Метаданные.Задачи.Содержит(ОбъектМетаданных) Тогда Возврат "Задачи"; ИначеЕсли Метаданные.ПланыСчетов.Содержит(ОбъектМетаданных) Тогда Возврат "ПланыСчетов"; ИначеЕсли Метаданные.ПланыВидовРасчета.Содержит(ОбъектМетаданных) Тогда Возврат "ПланыВидовРасчета"; ИначеЕсли Метаданные.Константы.Содержит(ОбъектМетаданных) Тогда Возврат "Константы"; ИначеЕсли Метаданные.ЖурналыДокументов.Содержит(ОбъектМетаданных) Тогда Возврат "ЖурналыДокументов"; ИначеЕсли Метаданные.Последовательности.Содержит(ОбъектМетаданных) Тогда Возврат "Последовательности"; ИначеЕсли Метаданные.РегламентныеЗадания.Содержит(ОбъектМетаданных) Тогда Возврат "РегламентныеЗадания"; ИначеЕсли Метаданные.РегистрыРасчета.Содержит(ОбъектМетаданных.Родитель()) И ОбъектМетаданных.Родитель().Перерасчеты.Найти(ОбъектМетаданных.Имя) = ОбъектМетаданных Тогда Возврат "Перерасчеты"; ИначеЕсли Метаданные.Обработки.Содержит(ОбъектМетаданных) Тогда Возврат "Обработки"; ИначеЕсли Метаданные.Отчеты.Содержит(ОбъектМетаданных) Тогда Возврат "Отчеты"; ИначеЕсли Метаданные.Подсистемы.Содержит(ОбъектМетаданных) Тогда Возврат "Подсистемы"; ИначеЕсли Метаданные.ОбщиеМодули.Содержит(ОбъектМетаданных) Тогда Возврат "ОбщиеМодули"; ИначеЕсли Метаданные.ПараметрыСеанса.Содержит(ОбъектМетаданных) Тогда Возврат "ПараметрыСеанса"; ИначеЕсли Метаданные.Роли.Содержит(ОбъектМетаданных) Тогда Возврат "Роли"; ИначеЕсли Метаданные.ОбщиеРеквизиты.Содержит(ОбъектМетаданных) Тогда Возврат "ОбщиеРеквизиты"; ИначеЕсли Метаданные.КритерииОтбора.Содержит(ОбъектМетаданных) Тогда Возврат "КритерииОтбора"; ИначеЕсли Метаданные.ПодпискиНаСобытия.Содержит(ОбъектМетаданных) Тогда Возврат "ПодпискиНаСобытия"; ИначеЕсли Метаданные.ФункциональныеОпции.Содержит(ОбъектМетаданных) Тогда Возврат "ФункциональныеОпции"; ИначеЕсли Метаданные.ПараметрыФункциональныхОпций.Содержит(ОбъектМетаданных) Тогда Возврат "ПараметрыФункциональныхОпций"; ИначеЕсли Метаданные.ХранилищаНастроек.Содержит(ОбъектМетаданных) Тогда Возврат "ХранилищаНастроек"; ИначеЕсли Метаданные.ОбщиеФормы.Содержит(ОбъектМетаданных) Тогда Возврат "ОбщиеФормы"; ИначеЕсли Метаданные.ОбщиеКоманды.Содержит(ОбъектМетаданных) Тогда Возврат "ОбщиеКоманды"; ИначеЕсли Метаданные.ГруппыКоманд.Содержит(ОбъектМетаданных) Тогда Возврат "ГруппыКоманд"; ИначеЕсли Метаданные.ОбщиеМакеты.Содержит(ОбъектМетаданных) Тогда Возврат "ОбщиеМакеты"; ИначеЕсли Метаданные.ОбщиеКартинки.Содержит(ОбъектМетаданных) Тогда Возврат "ОбщиеКартинки"; ИначеЕсли Метаданные.ПакетыXDTO.Содержит(ОбъектМетаданных) Тогда Возврат "ПакетыXDTO"; ИначеЕсли Метаданные.WebСервисы.Содержит(ОбъектМетаданных) Тогда Возврат "WebСервисы"; ИначеЕсли Метаданные.WSСсылки.Содержит(ОбъектМетаданных) Тогда Возврат "WSСсылки"; ИначеЕсли Метаданные.Стили.Содержит(ОбъектМетаданных) Тогда Возврат "Стили"; ИначеЕсли Метаданные.Языки.Содержит(ОбъектМетаданных) Тогда Возврат "Языки"; ИначеЕсли Метаданные.ВнешниеИсточникиДанных.Содержит(ОбъектМетаданных) Тогда Возврат "ВнешниеИсточникиДанных"; Иначе Возврат ""; КонецЕсли; КонецФункции // Возвращает менеджер объекта по полному имени объекта метаданных. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // // Параметры: // ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Справочник.Организации". // // Возвращаемое значение: // СправочникМенеджер, ДокументМенеджер, ОбработкаМенеджер, РегистрСведенийМенеджер - менеджер объекта. // // Пример: // МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени("Справочник.Организации"); // ПустаяСсылка = МенеджерСправочника.ПустаяСсылка(); // Функция МенеджерОбъектаПоПолномуИмени(ПолноеИмя) Экспорт Перем КлассОМ, ИмяОМ, Менеджер; ЧастиИмени = СтрРазделить(ПолноеИмя, "."); Если ЧастиИмени.Количество() >= 2 Тогда КлассОМ = ЧастиИмени[0]; ИмяОМ = ЧастиИмени[1]; Иначе Менеджер = Неопределено; КонецЕсли; Если ВРег(КлассОМ) = "ПЛАНОБМЕНА" Тогда Менеджер = ПланыОбмена; ИначеЕсли ВРег(КлассОМ) = "СПРАВОЧНИК" Тогда Менеджер = Справочники; ИначеЕсли ВРег(КлассОМ) = "ДОКУМЕНТ" Тогда Менеджер = Документы; ИначеЕсли ВРег(КлассОМ) = "ЖУРНАЛДОКУМЕНТОВ" Тогда Менеджер = ЖурналыДокументов; ИначеЕсли ВРег(КлассОМ) = "ПЕРЕЧИСЛЕНИЕ" Тогда Менеджер = Перечисления; ИначеЕсли ВРег(КлассОМ) = "ОТЧЕТ" Тогда Менеджер = Отчеты; ИначеЕсли ВРег(КлассОМ) = "ОБРАБОТКА" Тогда Менеджер = Обработки; ИначеЕсли ВРег(КлассОМ) = "ПЛАНВИДОВХАРАКТЕРИСТИК" Тогда Менеджер = ПланыВидовХарактеристик; ИначеЕсли ВРег(КлассОМ) = "ПЛАНСЧЕТОВ" Тогда Менеджер = ПланыСчетов; ИначеЕсли ВРег(КлассОМ) = "ПЛАНВИДОВРАСЧЕТА" Тогда Менеджер = ПланыВидовРасчета; ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРСВЕДЕНИЙ" Тогда Менеджер = РегистрыСведений; ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРНАКОПЛЕНИЯ" Тогда Менеджер = РегистрыНакопления; ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРБУХГАЛТЕРИИ" Тогда Менеджер = РегистрыБухгалтерии; ИначеЕсли ВРег(КлассОМ) = "РЕГИСТРРАСЧЕТА" Тогда Если ЧастиИмени.Количество() = 2 Тогда Менеджер = РегистрыРасчета; ИначеЕсли ЧастиИмени.Количество() = 4 Тогда КлассПодчиненногоОМ = ЧастиИмени[2]; ИмяПодчиненногоОМ = ЧастиИмени[3]; Если ВРег(КлассПодчиненногоОМ) = "ПЕРЕРАСЧЕТ" Тогда Менеджер = РегистрыРасчета[ИмяОМ].Перерасчеты; ИмяОм = ИмяПодчиненногоОМ; Иначе Менеджер = Неопределено; КонецЕсли; Иначе Менеджер = Неопределено; КонецЕсли; ИначеЕсли ВРег(КлассОМ) = "БИЗНЕСПРОЦЕСС" Тогда Менеджер = БизнесПроцессы; ИначеЕсли ВРег(КлассОМ) = "ЗАДАЧА" Тогда Менеджер = Задачи; ИначеЕсли ВРег(КлассОМ) = "КОНСТАНТА" Тогда Менеджер = Константы; ИначеЕсли ВРег(КлассОМ) = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Тогда Менеджер = Последовательности; Иначе Менеджер = Неопределено; КонецЕсли; Если Менеджер = Неопределено Тогда ПроверитьОбъектМетаданныхСуществует(ПолноеИмя); ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Объект метаданных ""%1"" не имеет менеджера объекта.\'"), ПолноеИмя); КонецЕсли; Попытка Возврат Менеджер[ИмяОМ]; Исключение ПроверитьОбъектМетаданныхСуществует(ПолноеИмя); ВызватьИсключение; КонецПопытки; КонецФункции // Возвращает менеджер объекта по ссылке на объект. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // См. также ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, менеджер которого требуется получить. // // Возвращаемое значение: // СправочникМенеджер, ДокументМенеджер, ОбработкаМенеджер, РегистрСведенийМенеджер - менеджер объекта. // // Пример: // МенеджерСправочника = ОбщегоНазначения.МенеджерОбъектаПоСсылке(СсылкаНаОрганизацию); // ПустаяСсылка = МенеджерСправочника.ПустаяСсылка(); // Функция МенеджерОбъектаПоСсылке(Ссылка) Экспорт ИмяОбъекта = Ссылка.Метаданные().Имя; ТипСсылки = ТипЗнч(Ссылка); Если Справочники.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат Справочники[ИмяОбъекта]; ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат Документы[ИмяОбъекта]; ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат БизнесПроцессы[ИмяОбъекта]; ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат ПланыВидовХарактеристик[ИмяОбъекта]; ИначеЕсли ПланыСчетов.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат ПланыСчетов[ИмяОбъекта]; ИначеЕсли ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат ПланыВидовРасчета[ИмяОбъекта]; ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат Задачи[ИмяОбъекта]; ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат ПланыОбмена[ИмяОбъекта]; ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипСсылки) Тогда Возврат Перечисления[ИмяОбъекта]; Иначе Возврат Неопределено; КонецЕсли; КонецФункции // Проверка того, что переданный тип является ссылочным типом данных. // Для типа Неопределено возвращается Ложь. // // Параметры: // ПроверяемыйТип - Тип - для проверки на ссылочный тип данных. // // Возвращаемое значение: // Булево - Истина, если это ссылка. // Функция ЭтоСсылка(ПроверяемыйТип) Экспорт Возврат ПроверяемыйТип <> Тип("Неопределено") И ОписаниеТипаВсеСсылки().СодержитТип(ПроверяемыйТип); КонецФункции // Проверяет физическое наличие записи в информационной базе данных о переданном значении ссылки. // // Параметры: // ПроверяемаяСсылка - ЛюбаяСсылка - значение любой ссылки информационной базы данных. // // Возвращаемое значение: // Булево - Истина, если существует. // Функция СсылкаСуществует(ПроверяемаяСсылка) Экспорт ТекстЗапроса = "ВЫБРАТЬ ПЕРВЫЕ 1 | 1 КАК Поле1 |ИЗ | &ИмяТаблицы КАК Таблица |ГДЕ | Таблица.Ссылка = &Ссылка"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИмяТаблицыПоСсылке(ПроверяемаяСсылка)); Запрос = Новый Запрос; Запрос.Текст = ТекстЗапроса; Запрос.УстановитьПараметр("Ссылка", ПроверяемаяСсылка); УстановитьПривилегированныйРежим(Истина); Возврат НЕ Запрос.Выполнить().Пустой(); КонецФункции // Возвращает имя вида объектов метаданных по ссылке на объект. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // См. так же ВидОбъектаПоТипу. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, вид которого требуется получить. // // Возвращаемое значение: // Строка - имя вида объектов метаданных. Например: "Справочник", "Документ". // Функция ВидОбъектаПоСсылке(Ссылка) Экспорт Возврат ВидОбъектаПоТипу(ТипЗнч(Ссылка)); КонецФункции // Возвращает имя вида объектов метаданных по типу объекта. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // См. так же ВидОбъектаПоСсылке. // // Параметры: // ТипОбъекта - Тип - тип прикладного объекта, определенный в конфигурации. // // Возвращаемое значение: // Строка - имя вида объектов метаданных. Например: "Справочник", "Документ". // Функция ВидОбъектаПоТипу(ТипОбъекта) Экспорт Если Справочники.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "Справочник"; ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "Документ"; ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "БизнесПроцесс"; ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "ПланВидовХарактеристик"; ИначеЕсли ПланыСчетов.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "ПланСчетов"; ИначеЕсли ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "ПланВидовРасчета"; ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "Задача"; ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "ПланОбмена"; ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(ТипОбъекта) Тогда Возврат "Перечисление"; Иначе ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Неверный тип значения параметра (%1)\'"), Строка(ТипОбъекта)); КонецЕсли; КонецФункции // Возвращает полное имя объекта метаданных по переданному значению ссылки. // // Параметры: // Ссылка - ЛюбаяСсылка - объект, для которого необходимо получить имя таблицы ИБ. // // Возвращаемое значение: // Строка - полное имя объекта метаданных для указанного объекта. Например: "Справочник.Номенклатура". // Функция ИмяТаблицыПоСсылке(Ссылка) Экспорт Возврат Ссылка.Метаданные().ПолноеИмя(); КонецФункции // Проверяет, что переданное значение имеет ссылочный тип данных. // // Параметры: // Значение - Произвольный - проверяемое значение. // // Возвращаемое значение: // Булево - Истина, если тип значения ссылочный. // Функция ЗначениеСсылочногоТипа(Значение) Экспорт Возврат ЭтоСсылка(ТипЗнч(Значение)); КонецФункции // Проверяет, является ли элемент справочника или плана видов характеристик группой элементов. // // Параметры: // Объект - СправочникСсылка // - ПланВидовХарактеристикСсылка // - СправочникОбъект // - ПланВидовХарактеристикОбъект - проверяемый объект. // // Возвращаемое значение: // Булево // Функция ОбъектЯвляетсяГруппой(Объект) Экспорт Если ЗначениеСсылочногоТипа(Объект) Тогда Ссылка = Объект; Иначе Ссылка = Объект.Ссылка; КонецЕсли; МетаданныеОбъекта = Ссылка.Метаданные(); Если ЭтоСправочник(МетаданныеОбъекта) Тогда Если Не МетаданныеОбъекта.Иерархический Или МетаданныеОбъекта.ВидИерархии <> Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда Возврат Ложь; КонецЕсли; ИначеЕсли Не ЭтоПланВидовХарактеристик(МетаданныеОбъекта) Или Не МетаданныеОбъекта.Иерархический Тогда Возврат Ложь; КонецЕсли; Если Ссылка <> Объект Тогда Возврат Объект.ЭтоГруппа; КонецЕсли; Возврат ЗначениеРеквизитаОбъекта(Ссылка, "ЭтоГруппа") = Истина; КонецФункции // Возвращает ссылку, соответствующую объекту метаданных, для использования в базе данных. // См. также ОбщегоНазначения.ИдентификаторыОбъектовМетаданных. // // Ссылки возвращаются для следующих объектов метаданных: // - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - ПланыОбмена; // - Константы; // - Справочники; // - Документы; // - ЖурналыДокументов; // - Отчеты; // - Обработки; // - ПланыВидовХарактеристик; // - ПланыСчетов; // - ПланыВидовРасчета; // - РегистрыСведений; // - РегистрыНакопления; // - РегистрыБухгалтерии; // - РегистрыРасчета; // - БизнесПроцессы; // - Задачи. // // Параметры: // ОписаниеОбъектаМетаданных - ОбъектМетаданных - объект метаданных конфигурации; // - Тип - тип, который можно использовать в функции Метаданные.НайтиПоТипу; // - Строка - полное имя объекта метаданных, которое можно // использовать в функции Метаданные.НайтиПоПолномуИмени. // // ВызыватьИсключение - Булево - если Ложь, то вместо вызова исключения возвращается Null для несуществующего // или неподдерживаемого объекта метаданных. // // Возвращаемое значение: // СправочникСсылка.ИдентификаторыОбъектовМетаданных // СправочникСсылка.ИдентификаторыОбъектовРасширений // Null // // Пример: // Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ТипЗнч(Ссылка)); // Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных); // Идентификатор = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Справочник.Организации"); // Функция ИдентификаторОбъектаМетаданных(ОписаниеОбъектаМетаданных, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторОбъектаМетаданных( ОписаниеОбъектаМетаданных, ВызыватьИсключение); КонецФункции // Возвращает ссылки, соответствующие объектам метаданных, для использования в базе данных. // См. также ОбщегоНазначения.ИдентификаторОбъектаМетаданных. // // Ссылки возвращаются для следующих объектов метаданных: // - Подсистемы (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - Роли (см. также ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных); // - ПланыОбмена. // - Константы. // - Справочники. // - Документы. // - ЖурналыДокументов. // - Отчеты. // - Обработки. // - ПланыВидовХарактеристик. // - ПланыСчетов. // - ПланыВидовРасчета. // - РегистрыСведений. // - РегистрыНакопления. // - РегистрыБухгалтерии. // - РегистрыРасчета. // - БизнесПроцессы. // - Задачи. // // Параметры: // ОписаниеОбъектовМетаданных - Массив из ОбъектМетаданных - объекты метаданных конфигурации; // - Массив из Строка - полные имена объектов метаданных, которые можно использовать // в функции Метаданные.НайтиПоПолномуИмени; // - Массив из Тип - типы, которые можно использовать в функции Метаданные.НайтиПоТипу. // ВызыватьИсключение - Булево - если Ложь, то несуществующие и неподдерживаемые объекты метаданных // будут пропущены в возвращаемом значении. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - Строка - полное имя указанного объекта метаданных. // * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - найденный идентификатор. // // Пример: // ПолныеИмена = Новый Массив; // ПолныеИмена.Добавить(Метаданные.Справочники.Валюты.ПолноеИмя()); // ПолныеИмена.Добавить(Метаданные.РегистрыСведений.КурсыВалют.ПолноеИмя()); // Идентификаторы = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена); // Функция ИдентификаторыОбъектовМетаданных(ОписаниеОбъектовМетаданных, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ИдентификаторыОбъектовМетаданных( ОписаниеОбъектовМетаданных, ВызыватьИсключение); КонецФункции // Возвращает объект метаданных по переданному идентификатору. // // Параметры: // Идентификатор - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор // объекта метаданных конфигурации или расширения конфигурации. // // ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных // не существует или недоступен, возвращает соответственно // Null или Неопределено вместо вызова исключения. // // Возвращаемое значение: // ОбъектМетаданных - объект метаданных, соответствующий идентификатору. // // Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что // для указанного идентификатора объект метаданных не существует (идентификатор устарел). // // Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, // что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен. // Для расширений конфигурации это значит, что расширение установлено, но не подключено, // либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка. // Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект // метаданных имеется, а в текущем (старом) сеансе нет. // Функция ОбъектМетаданныхПоИдентификатору(Идентификатор, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектМетаданныхПоИдентификатору( Идентификатор, ВызыватьИсключение); КонецФункции // Возвращает объекты метаданных по переданным идентификаторам. // // Параметры: // Идентификаторы - Массив - со значениями: // * Значение - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификаторы // объектов метаданных конфигурации или расширений конфигурации. // // ВызыватьИсключение - Булево - если Ложь, тогда в случае, когда объект метаданных // не существует или недоступен, возвращает соответственно // Null или Неопределено вместо вызова исключения. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - СправочникСсылка.ИдентификаторыОбъектовМетаданных // - СправочникСсылка.ИдентификаторыОбъектовРасширений - переданный идентификатор. // * Значение - ОбъектМетаданных - объект метаданных, соответствующий идентификатору. // - Null - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, что // для указанного идентификатора объект метаданных не существует (идентификатор устарел). // - Неопределено - возвращается, когда ВызыватьИсключение = Ложь. Обозначает, // что идентификатор действующий, но в текущем сеансе ОбъектМетаданных не может быть получен. // Для расширений конфигурации это значит, что расширение установлено, но не подключено, // либо потому что перезапуск еще не выполнен, либо при подключении произошла ошибка. // Для конфигурации это значит, что в новом сеансе (новом динамическом поколении) объект // метаданных имеется, а в текущем (старом) сеансе нет. // Функция ОбъектыМетаданныхПоИдентификаторам(Идентификаторы, ВызыватьИсключение = Истина) Экспорт Возврат Справочники.ИдентификаторыОбъектовМетаданных.ОбъектыМетаданныхПоИдентификаторам( Идентификаторы, ВызыватьИсключение); КонецФункции // Возвращает ОбъектМетаданных, быстро найденный по полному имени. // Более производительный аналог метода платформы Метаданные.НайтиПоПолномуИмени // для корневых объектов метаданных. // // Параметры: // ПолноеИмя - Строка - полное имя объекта метаданных, например, Справочник.Организации // // Возвращаемое значение: // ОбъектМетаданных - когда найден // Неопределено - когда не найден // Функция ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) Экспорт ПозицияТочки = СтрНайти(ПолноеИмя, "."); ИмяБазовогоТипа = Лев(ПолноеИмя, ПозицияТочки - 1); ИменаКоллекций = СтандартныеПодсистемыПовтИсп.ИменаКоллекцийПоИменамБазовыхТипов(); Коллекция = ИменаКоллекций.Получить(ВРег(ИмяБазовогоТипа)); Если Коллекция <> Неопределено Тогда Если Коллекция <> "Подсистемы" Тогда ИмяОбъекта = Сред(ПолноеИмя, ПозицияТочки + 1); ОбъектМетаданных = Метаданные[Коллекция].Найти(ИмяОбъекта); Иначе ИменаПодсистем = СтрРазделить(ВРег(ПолноеИмя), "."); Количество = ИменаПодсистем.Количество(); Подсистема = Метаданные; ОбъектМетаданных = Неопределено; Индекс = 0; Пока Истина Цикл Индекс = Индекс + 1; Если Индекс >= Количество Тогда Прервать; КонецЕсли; ИмяПодсистемы = ИменаПодсистем[Индекс]; Подсистема = Подсистема.Подсистемы.Найти(ИмяПодсистемы); Если Подсистема = Неопределено Тогда Прервать; КонецЕсли; Индекс = Индекс + 1; Если Индекс = Количество Тогда ОбъектМетаданных = Подсистема; Прервать; КонецЕсли; КонецЦикла; КонецЕсли; КонецЕсли; Если ОбъектМетаданных = Неопределено Тогда ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмя); КонецЕсли; Возврат ОбъектМетаданных; КонецФункции // Определяет доступность объекта метаданных по функциональным опциям. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных // - Строка - проверяемый объект метаданных. // // Возвращаемое значение: // Булево - Истина, если объект доступен. // Функция ОбъектМетаданныхДоступенПоФункциональнымОпциям(Знач ОбъектМетаданных) Экспорт Если ОбъектМетаданных = Неопределено Тогда Возврат Ложь; КонецЕсли; Если ТипЗнч(ОбъектМетаданных) <> Тип("Строка") Тогда ПолноеИмя = ОбъектМетаданных.ПолноеИмя(); Иначе ПолноеИмя = ОбъектМетаданных; КонецЕсли; Возврат СтандартныеПодсистемыПовтИсп.ДоступностьОбъектовПоОпциям().Получить(ПолноеИмя) <> Ложь; КонецФункции // Добавляет описание переименования объекта метаданных при переходе на указанную версию конфигурации. // Добавление выполняется в структуру Итог, которая передается в // процедуру ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных. // // Параметры: // Итог - см. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.Итог // ВерсияИБ - Строка - версия конечной конфигурации, при переходе на которую нужно // выполнить переименование, например, "2.1.2.14". // СтароеПолноеИмя - Строка - старое полное имя объекта метаданных, которое нужно переименовать, // например "Подсистема._ДемоПодсистемы". // НовоеПолноеИмя - Строка - новое полное имя объекта метаданных, на которое нужно переименовать, // например "Подсистема._ДемоСервисныеПодсистемы". // ИдентификаторБиблиотеки - Строка - внутренний идентификатор библиотеки, к которой относится ВерсияИБ. // Для основной конфигурации не требуется. // Например, "СтандартныеПодсистемы" - как указано // в ОбновлениеИнформационнойБазыБСП.ПриДобавленииПодсистемы. // Пример: // ОбщегоНазначения.ДобавитьПереименование(Итог, "2.1.2.14", // "Подсистема._ДемоПодсистемы", // "Подсистема._ДемоСервисныеПодсистемы"); // Процедура ДобавитьПереименование(Итог, ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки = "") Экспорт Справочники.ИдентификаторыОбъектовМетаданных.ДобавитьПереименование(Итог, ВерсияИБ, СтароеПолноеИмя, НовоеПолноеИмя, ИдентификаторБиблиотеки); КонецПроцедуры // Возвращает строковое представление типа, например, "СправочникСсылка.ИмяОбъекта", "ДокументСсылка.ИмяОбъекта". // Для остальных типов приводит тип к строке, например "Число". // // Параметры: // Тип - Тип - для которого надо получить представление. // // Возвращаемое значение: // Строка // Функция СтроковоеПредставлениеТипа(Тип) Экспорт Представление = ""; Если ЭтоСсылка(Тип) Тогда ПолноеИмя = Метаданные.НайтиПоТипу(Тип).ПолноеИмя(); ИмяОбъекта = СтрРазделить(ПолноеИмя, ".")[1]; Если Справочники.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "СправочникСсылка"; ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ДокументСсылка"; ИначеЕсли БизнесПроцессы.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "БизнесПроцессСсылка"; ИначеЕсли БизнесПроцессы.ТипВсеСсылкиТочекМаршрутаБизнесПроцессов().СодержитТип(Тип) Тогда Представление = "ТочкаМаршрутаБизнесПроцессаСсылка"; ИначеЕсли ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ПланВидовХарактеристикСсылка"; ИначеЕсли ПланыСчетов.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ПланСчетовСсылка"; ИначеЕсли ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ПланВидовРасчетаСсылка"; ИначеЕсли Задачи.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ЗадачаСсылка"; ИначеЕсли ПланыОбмена.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ПланОбменаСсылка"; ИначеЕсли Перечисления.ТипВсеСсылки().СодержитТип(Тип) Тогда Представление = "ПеречислениеСсылка"; КонецЕсли; Результат = ?(Представление = "", Представление, Представление + "." + ИмяОбъекта); ИначеЕсли Тип = Тип("Неопределено") Тогда Результат = "Неопределено"; ИначеЕсли Тип = Тип("Строка") Тогда Результат = "Строка"; ИначеЕсли Тип = Тип("Число") Тогда Результат = "Число"; ИначеЕсли Тип = Тип("Булево") Тогда Результат = "Булево"; ИначеЕсли Тип = Тип("Дата") Тогда Результат = "Дата"; Иначе Результат = Строка(Тип); КонецЕсли; Возврат Результат; КонецФункции // Возвращает таблицу значений с описанием требуемых свойств всех реквизитов объекта метаданных. // Получает значения свойств стандартных реквизитов и пользовательских реквизитов (созданных в режиме конфигуратора). // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - объект, для которого необходимо получить значение свойств реквизитов. // Например: Метаданные.Документ.РеализацияТоваровИУслуг // Свойства - Строка - свойства реквизитов, перечисленные через запятую, значение которых необходимо получить. // Например: "Имя, Тип, Синоним, Подсказка". // // Возвращаемое значение: // ТаблицаЗначений - описание требуемых свойств всех реквизитов объекта метаданных. // Функция ОписаниеСвойствОбъекта(ОбъектМетаданных, Свойства) Экспорт МассивСвойств = СтрРазделить(Свойства, ","); // Возвращаемое значение функции. ТаблицаОписанияСвойствОбъекта = Новый ТаблицаЗначений; // Добавляем в таблицу поля согласно именам переданных свойств. Для Каждого ИмяСвойства Из МассивСвойств Цикл ТаблицаОписанияСвойствОбъекта.Колонки.Добавить(СокрЛП(ИмяСвойства)); КонецЦикла; // Заполняем строку таблицы свойствами реквизитов объекта метаданных. Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит); КонецЦикла; // Заполняем строку таблицы свойствами стандартных реквизитов объекта метаданных. Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл ЗаполнитьЗначенияСвойств(ТаблицаОписанияСвойствОбъекта.Добавить(), Реквизит); КонецЦикла; Возврат ТаблицаОписанияСвойствОбъекта; КонецФункции // Возвращает признак того, что реквизит входит в подмножество стандартных реквизитов. // // Параметры: // СтандартныеРеквизиты - ОписанияСтандартныхРеквизитов - тип и значение, описывающие коллекцию настроек различных // стандартных реквизитов; // ИмяРеквизита - Строка - реквизит, который необходимо проверить на принадлежность множеству стандартных // реквизитов. // // Возвращаемое значение: // Булево - Истина, если реквизит входит в подмножество стандартных реквизитов. // Функция ЭтоСтандартныйРеквизит(СтандартныеРеквизиты, ИмяРеквизита) Экспорт Для Каждого Реквизит Из СтандартныеРеквизиты Цикл Если Реквизит.Имя = ИмяРеквизита Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции // Позволяет определить, есть ли среди реквизитов объекта реквизит с переданным именем. // // Параметры: // ИмяРеквизита - Строка - имя реквизита; // МетаданныеОбъекта - ОбъектМетаданных - объект, в котором требуется проверить наличие реквизита. // // Возвращаемое значение: // Булево - Истина, если есть. // Функция ЕстьРеквизитОбъекта(ИмяРеквизита, МетаданныеОбъекта) Экспорт Реквизиты = МетаданныеОбъекта.Реквизиты; // КоллекцияОбъектовМетаданных Возврат НЕ (Реквизиты.Найти(ИмяРеквизита) = Неопределено); КонецФункции // Проверить, что описание типа состоит из единственного типа значения и // совпадает с нужным типом. // // Параметры: // ОписаниеТипа - ОписаниеТипов - проверяемая коллекция типов; // ТипЗначения - Тип - проверяемый тип. // // Возвращаемое значение: // Булево - Истина, если совпадает. // // Пример: // Если ОбщегоНазначения.ОписаниеТипаСостоитИзТипа(ТипЗначенияСвойства, Тип("Булево") Тогда // // Выводим поле в виде флажка. // КонецЕсли; // Функция ОписаниеТипаСостоитИзТипа(ОписаниеТипа, ТипЗначения) Экспорт Если ОписаниеТипа.Типы().Количество() = 1 И ОписаниеТипа.Типы().Получить(0) = ТипЗначения Тогда Возврат Истина; КонецЕсли; Возврат Ложь; КонецФункции // Создает объект ОписаниеТипов, содержащий тип Строка. // // Параметры: // ДлинаСтроки - Число - длина строки. // // Возвращаемое значение: // ОписаниеТипов - описание типа Строка. // Функция ОписаниеТипаСтрока(ДлинаСтроки) Экспорт Возврат Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(ДлинаСтроки)); КонецФункции // Создает объект ОписаниеТипов, содержащий тип Число. // // Параметры: // Разрядность - Число - общее количество разрядов числа (количество разрядов // целой части плюс количество разрядов дробной части). // РазрядностьДробнойЧасти - Число - число разрядов дробной части. // ЗнакЧисла - ДопустимыйЗнак - допустимый знак числа. // // Возвращаемое значение: // ОписаниеТипов - описание типа Число. // Функция ОписаниеТипаЧисло(Разрядность, РазрядностьДробнойЧасти = 0, Знач ЗнакЧисла = Неопределено) Экспорт Если ЗнакЧисла = Неопределено Тогда ЗнакЧисла = ДопустимыйЗнак.Любой; КонецЕсли; Возврат Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(Разрядность, РазрядностьДробнойЧасти, ЗнакЧисла)); КонецФункции // Создает объект ОписаниеТипов, содержащий тип Дата. // // Параметры: // ЧастиДаты - ЧастиДаты - набор вариантов использования значений типа Дата. // // Возвращаемое значение: // ОписаниеТипов - описание типа Дата. // Функция ОписаниеТипаДата(ЧастиДаты) Экспорт Возврат Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты)); КонецФункции // Возвращает описание типа, включающего в себя все возможные ссылочные типы конфигурации. // // Возвращаемое значение: // ОписаниеТипов - все ссылочные типы конфигурации. // Функция ОписаниеТипаВсеСсылки() Экспорт Возврат СтандартныеПодсистемыПовтИсп.ОписаниеТипаВсеСсылки(); КонецФункции // Возвращает строковое представление списка, заданное в свойствах объекта метаданных. // В зависимости от того, какие свойства объекта метаданных заполнены, функция возвращают одно из них в указанном // порядке: Расширенное представление списка, Представление списка, Синоним или Имя. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - произвольный объект. // // Возвращаемое значение: // Строка - представление списка. // Функция ПредставлениеСписка(ОбъектМетаданных) Экспорт СвойстваОбъекта = Новый Структура("РасширенноеПредставлениеСписка,ПредставлениеСписка"); ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных); Если ЗначениеЗаполнено(СвойстваОбъекта.РасширенноеПредставлениеСписка) Тогда Результат = СвойстваОбъекта.РасширенноеПредставлениеСписка; ИначеЕсли ЗначениеЗаполнено(СвойстваОбъекта.ПредставлениеСписка) Тогда Результат = СвойстваОбъекта.ПредставлениеСписка; Иначе Результат = ОбъектМетаданных.Представление(); КонецЕсли; Возврат Результат; КонецФункции // Возвращает строковое представление объекта, заданное в свойствах объекта метаданных. // В зависимости от того, какие свойства объекта метаданных заполнены, функция возвращают одно из них в указанном // порядке: Расширенное представление объекта, Представление объекта, Синоним или Имя. // // Параметры: // ОбъектМетаданных - ОбъектМетаданных - произвольный объект. // // Возвращаемое значение: // Строка - представление объекта. // Функция ПредставлениеОбъекта(ОбъектМетаданных) Экспорт СвойстваОбъекта = Новый Структура("РасширенноеПредставлениеОбъекта,ПредставлениеОбъекта"); ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных); Если ЗначениеЗаполнено(СвойстваОбъекта.РасширенноеПредставлениеОбъекта) Тогда Результат = СвойстваОбъекта.РасширенноеПредставлениеОбъекта; ИначеЕсли ЗначениеЗаполнено(СвойстваОбъекта.ПредставлениеОбъекта) Тогда Результат = СвойстваОбъекта.ПредставлениеОбъекта; Иначе Результат = ОбъектМетаданных.Представление(); КонецЕсли; Возврат Результат; КонецФункции #КонецОбласти #Область ХранилищеНастроек //////////////////////////////////////////////////////////////////////////////// // Сохранение, чтение и удаление настроек из хранилищ. // Сохраняет настройку в хранилище общих настроек, как метод платформы Сохранить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // Настройки - Произвольный - см. синтакс-помощник платформы. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеОбщихНастроекСохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт ХранилищеСохранить(ХранилищеОбщихНастроек, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения); КонецПроцедуры // Сохраняет несколько настроек в хранилище общих настроек, как метод платформы Сохранить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // НесколькоНастроек - Массив - со значениями: // * Значение - Структура: // * Объект - Строка - см. параметр КлючОбъекта в синтакс-помощнике платформы. // * Настройка - Строка - см. параметр КлючНастроек в синтакс-помощнике платформы. // * Значение - Произвольный - см. параметр Настройки в синтакс-помощнике платформы. // // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеОбщихНастроекСохранитьМассив(НесколькоНастроек, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда Возврат; КонецЕсли; Для Каждого Элемент Из НесколькоНастроек Цикл ХранилищеОбщихНастроек.Сохранить(Элемент.Объект, КлючНастроек(Элемент.Настройка), Элемент.Значение); КонецЦикла; Если ОбновитьПовторноИспользуемыеЗначения Тогда ОбновитьПовторноИспользуемыеЗначения(); КонецЕсли; КонецПроцедуры // Загружает настройку из хранилища общих настроек, как метод платформы Загрузить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют. // Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки. // // В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно // - возвращаемая ссылка заменяется на указанное значение по умолчанию; // - из данных типа Массив ссылки удаляются; // - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено; // - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют. // Если не указано, возвращается значение Неопределено. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // // Возвращаемое значение: // Произвольный - см. синтакс-помощник платформы. // Функция ХранилищеОбщихНастроекЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт Возврат ХранилищеЗагрузить(ХранилищеОбщихНастроек, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя); КонецФункции // Удаляет настройку из хранилища общих настроек, как метод платформы Удалить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка // - Неопределено - см. синтакс-помощник платформы. // КлючНастроек - Строка // - Неопределено - см. синтакс-помощник платформы. // ИмяПользователя - Строка // - Неопределено - см. синтакс-помощник платформы. // Процедура ХранилищеОбщихНастроекУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт ХранилищеУдалить(ХранилищеОбщихНастроек, КлючОбъекта, КлючНастроек, ИмяПользователя); КонецПроцедуры // Сохраняет настройку в хранилище системных настроек, как метод платформы Сохранить // объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек // более 128 символов путем хеширования части, которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // Настройки - Произвольный - см. синтакс-помощник платформы. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеСистемныхНастроекСохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт ХранилищеСохранить(ХранилищеСистемныхНастроек, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения); КонецПроцедуры // Загружает настройку из хранилища системных настроек, как метод платформы Загрузить, // объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек // более 128 символов путем хеширования части, которая превышает 96 символов. // Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют. // Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки. // // В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно: // - возвращаемая ссылка заменяется на указанное значение по умолчанию; // - из данных типа Массив ссылки удаляются; // - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено; // - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют. // Если не указано, возвращается значение Неопределено. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // // Возвращаемое значение: // Произвольный - см. синтакс-помощник платформы. // Функция ХранилищеСистемныхНастроекЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт Возврат ХранилищеЗагрузить(ХранилищеСистемныхНастроек, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя); КонецФункции // Удаляет настройку из хранилища системных настроек, как метод платформы Удалить, // объекта СтандартноеХранилищеНастроекМенеджер, но с поддержкой длины ключа настроек // более 128 символов путем хеширования части, которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка // - Неопределено - см. синтакс-помощник платформы. // КлючНастроек - Строка // - Неопределено - см. синтакс-помощник платформы. // ИмяПользователя - Строка // - Неопределено - см. синтакс-помощник платформы. // Процедура ХранилищеСистемныхНастроекУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт ХранилищеУдалить(ХранилищеСистемныхНастроек, КлючОбъекта, КлючНастроек, ИмяПользователя); КонецПроцедуры // Сохраняет настройку в хранилище настроек данных форм, как метод платформы Сохранить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, сохранение пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // Настройки - Произвольный - см. синтакс-помощник платформы. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // ОбновитьПовторноИспользуемыеЗначения - Булево - выполнить одноименный метод платформы. // Процедура ХранилищеНастроекДанныхФормСохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено, ОбновитьПовторноИспользуемыеЗначения = Ложь) Экспорт ХранилищеСохранить(ХранилищеНастроекДанныхФорм, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения); КонецПроцедуры // Загружает настройку из хранилища настроек данных форм, как метод платформы Загрузить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Кроме того, возвращает указанное значение по умолчанию, если настройки не существуют. // Если нет права СохранениеДанныхПользователя, возвращается значение по умолчанию без ошибки. // // В возвращаемом значении очищаются ссылки на несуществующий объект в базе данных, а именно // - возвращаемая ссылка заменяется на указанное значение по умолчанию; // - из данных типа Массив ссылки удаляются; // - у данных типа Структура и Соответствие ключ не меняется, а значение устанавливается Неопределено; // - анализ значений в данных типа Массив, Структура, Соответствие выполняется рекурсивно. // // Параметры: // КлючОбъекта - Строка - см. синтакс-помощник платформы. // КлючНастроек - Строка - см. синтакс-помощник платформы. // ЗначениеПоУмолчанию - Произвольный - значение, которое возвращается, если настройки не существуют. // Если не указано, возвращается значение Неопределено. // ОписаниеНастроек - ОписаниеНастроек - см. синтакс-помощник платформы. // ИмяПользователя - Строка - см. синтакс-помощник платформы. // // Возвращаемое значение: // Произвольный - см. синтакс-помощник платформы. // Функция ХранилищеНастроекДанныхФормЗагрузить(КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию = Неопределено, ОписаниеНастроек = Неопределено, ИмяПользователя = Неопределено) Экспорт Возврат ХранилищеЗагрузить(ХранилищеНастроекДанныхФорм, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя); КонецФункции // Удаляет настройку из хранилища настроек данных форм, как метод платформы Удалить, // объектов СтандартноеХранилищеНастроекМенеджер или ХранилищеНастроекМенеджер.<Имя хранилища>, // но с поддержкой длины ключа настроек более 128 символов путем хеширования части, // которая превышает 96 символов. // Если нет права СохранениеДанныхПользователя, удаление пропускается без ошибки. // // Параметры: // КлючОбъекта - Строка // - Неопределено - см. синтакс-помощник платформы. // КлючНастроек - Строка // - Неопределено - см. синтакс-помощник платформы. // ИмяПользователя - Строка // - Неопределено - см. синтакс-помощник платформы. // Процедура ХранилищеНастроекДанныхФормУдалить(КлючОбъекта, КлючНастроек, ИмяПользователя) Экспорт ХранилищеУдалить(ХранилищеНастроекДанныхФорм, КлючОбъекта, КлючНастроек, ИмяПользователя); КонецПроцедуры #КонецОбласти #Область СериализацияXML // Преобразует (сериализует) любое значение в XML-строку. // Преобразованы в могут быть только те объекты, для которых в синтакс-помощнике указано, что они сериализуются. // См. также ЗначениеИзСтрокиXML. // // Параметры: // Значение - Произвольный - значение, которое необходимо сериализовать в XML-строку. // // Возвращаемое значение: // Строка - XML-строка. // Функция ЗначениеВСтрокуXML(Значение) Экспорт ЗаписьXML = Новый ЗаписьXML; ЗаписьXML.УстановитьСтроку(); СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение, НазначениеТипаXML.Явное); Возврат ЗаписьXML.Закрыть(); КонецФункции // Выполняет преобразование (десериализацию) XML-строки в значение. // См. также ЗначениеВСтрокуXML. // // Параметры: // СтрокаXML - Строка - XML-строка, с сериализованным объектом.. // // Возвращаемое значение: // Произвольный - значение, полученное из переданной XML-строки. // Функция ЗначениеИзСтрокиXML(СтрокаXML) Экспорт ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(СтрокаXML); Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML); КонецФункции // Возвращает XML-представление XDTO-объекта. // // Параметры: // ОбъектXDTO - ОбъектXDTO - объект, для которого требуется сформировать XML-представление. // Фабрика - ФабрикаXDTO - фабрика, с использованием которой требуется формировать XML-представление. // Если параметр не указан - будет использоваться глобальная фабрика XDTO. // // Возвращаемое значение: // Строка - XML-представление XDTO-объекта. // Функция ОбъектXDTOВСтрокуXML(Знач ОбъектXDTO, Знач Фабрика = Неопределено) Экспорт ОбъектXDTO.Проверить(); Если Фабрика = Неопределено Тогда Фабрика = ФабрикаXDTO; КонецЕсли; Запись = Новый ЗаписьXML(); Запись.УстановитьСтроку(); Фабрика.ЗаписатьXML(Запись, ОбъектXDTO, , , , НазначениеТипаXML.Явное); Возврат Запись.Закрыть(); КонецФункции // Формирует XDTO-объект по XML-представлению. // // Параметры: // СтрокаXML - Строка - XML-представление XDTO-объекта, // Фабрика - ФабрикаXDTO - фабрика, с использованием которой требуется формировать XDTO-объект. // Если параметр не указан - будет использоваться глобальная фабрика XDTO. // // Возвращаемое значение: // ОбъектXDTO - XDTO-объект. // Функция ОбъектXDTOИзСтрокиXML(Знач СтрокаXML, Знач Фабрика = Неопределено) Экспорт Если Фабрика = Неопределено Тогда Фабрика = ФабрикаXDTO; КонецЕсли; Чтение = Новый ЧтениеXML(); Чтение.УстановитьСтроку(СтрокаXML); Возврат Фабрика.ПрочитатьXML(Чтение); КонецФункции #КонецОбласти #Область СериализацияJSON // Преобразует значение в строку JSON при помощи метода глобального контекста ЗаписатьJSON. // Допускаются не все типы значений, подробности см. в синтакс-помощнике. // Даты преобразуются в формат ISO (YYYY-MM-DDThh:mm:ssZ). // // Параметры: // Значение - Произвольный // // Возвращаемое значение: // Строка // Функция ЗначениеВJSON(Знач Значение) Экспорт ЗаписьJSON = Новый ЗаписьJSON; ЗаписьJSON.УстановитьСтроку(); ЗаписатьJSON(ЗаписьJSON, Значение); Возврат ЗаписьJSON.Закрыть(); КонецФункции // Преобразует строку в формате JSON в значение при помощи метода глобального контекста ПрочитатьJSON. // См. ограничения в синтакс-помощнике. // Объекты JSON по умолчанию преобразует в значения типа Соответствие. // Имена свойств со значением типа Дата необходимо явно указывать, чтобы было выполнено преобразование. // Ожидаемый формат дат - ISO (YYYY-MM-DDThh:mm:ssZ). // // Параметры: // Строка - Строка - значение в формате JSON. // ИменаСвойствСоЗначениямиДата - Строка - имя свойства, содержащее значение типа Дата. Допустимо указывать несколько // свойств через запятую. // - Массив из Строка // ПрочитатьВСоответствие - Булево - если Ложь, то объекты JSON будут преобразованы в значение типа Структура. // // Возвращаемое значение: // Произвольный // Функция JSONВЗначение(Знач Строка, Знач ИменаСвойствСоЗначениямиДата = Неопределено, Знач ПрочитатьВСоответствие = Истина) Экспорт Если ТипЗнч(ИменаСвойствСоЗначениямиДата) = Тип("Строка") Тогда ИменаСвойствСоЗначениямиДата = СтрРазделить(ИменаСвойствСоЗначениямиДата, ", " + Символы.ПС, Ложь); КонецЕсли; ЧтениеJSON = Новый ЧтениеJSON; ЧтениеJSON.УстановитьСтроку(Строка); Возврат ПрочитатьJSON(ЧтениеJSON, ПрочитатьВСоответствие, ИменаСвойствСоЗначениямиДата); КонецФункции #КонецОбласти #Область ВебСервисы // Возвращает структуру параметров для функции СоздатьWSПрокси. // // Возвращаемое значение: // см. СоздатьWSПрокси.ПараметрыПодключенияWSПрокси // Функция ПараметрыПодключенияWSПрокси() Экспорт Результат = Новый Структура; Результат.Вставить("АдресWSDL"); Результат.Вставить("URIПространстваИмен"); Результат.Вставить("ИмяСервиса"); Результат.Вставить("ИмяТочкиПодключения", ""); Результат.Вставить("ИмяПользователя"); Результат.Вставить("Пароль"); Результат.Вставить("Таймаут", 0); Результат.Вставить("Местоположение"); Результат.Вставить("ИспользоватьАутентификациюОС", Ложь); Результат.Вставить("ДелатьКонтрольныйВызов", Ложь); Результат.Вставить("ЗащищенноеСоединение", Неопределено); Возврат Результат; КонецФункции // Конструктор объекта WSПрокси с дополнительными возможностями по сравнению с конструктором Новый WSПрокси: // - создает WSОпределения; // - кэширует файл WSDL для ускорения работы с веб-сервисом; // - не требуется указание ИнтернетПрокси (используется автоматически, если настроен); // - позволяет делать быструю проверку доступности сервиса с помощью операции Ping. // // Параметры: // ПараметрыПодключенияWSПрокси - Структура: // * АдресWSDL - Строка - месторасположение wsdl, например, "http://webservice.net/webservice.asmx?wsdl". // * URIПространстваИмен - Строка - URI пространства имен web-сервиса, например, "http://www.webservice.net/WebService/1.0.0.1". // * ИмяСервиса - Строка - имя сервиса, например, "WebService_1_0_0_1". // * ИмяТочкиПодключения - Строка - необязательный параметр. Если не задано, образуется как "<ИмяСервиса>Soap". // * ИмяПользователя - Строка - необязательный параметр. Имя пользователя для входа на сервер. // * Пароль - Строка - необязательный параметр. Пароль пользователя. // * Таймаут - Число - необязательный параметр. Таймаут на операции веб-сервиса, выполняемые // через прокси. В секундах. // * Местоположение - Строка - необязательный параметр. Фактический адрес сервиса. Используется, если // адрес реального расположения сервиса отличается от адреса, который указан // в WSDL-файле. // * ИспользоватьАутентификациюОС - Булево - необязательный параметр. Включает использование авторизации NTLM или // Negotiate на сервере. // * ДелатьКонтрольныйВызов - Булево - необязательный параметр. Выполнять проверку доступности сервиса (требуется // поддержка команды Ping в веб-сервисе). По умолчанию, Ложь. // * ЗащищенноеСоединение - ЗащищенноеСоединениеOpenSSL // - Неопределено - необязательные параметры защищенного соединения. // // Возвращаемое значение: // WSПрокси // // Пример: // ПараметрыПодключения = ОбщегоНазначения.ПараметрыПодключенияWSПрокси(); // ПараметрыПодключения.АдресWSDL = "http://webservice.net/webservice.asmx?wsdl"; // ПараметрыПодключения.URIПространстваИмен = "http://www.webservice.net/WebService/1.0.0.1"; // ПараметрыПодключения.ИмяСервиса = "WebService_1_0_0_1"; // ПараметрыПодключения.Таймаут = 20; // Прокси = ОбщегоНазначения.СоздатьWSПрокси(ПараметрыПодключения); // Функция СоздатьWSПрокси(Знач ПараметрыПодключенияWSПрокси) Экспорт ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("СоздатьWSПрокси", "Параметры", ПараметрыПодключенияWSПрокси, Тип("Структура"), Новый Структура("АдресWSDL,URIПространстваИмен,ИмяСервиса", Тип("Строка"), Тип("Строка"), Тип("Строка"))); ПараметрыПодключения = ПараметрыПодключенияWSПрокси(); ЗаполнитьЗначенияСвойств(ПараметрыПодключения, ПараметрыПодключенияWSПрокси); ДелатьКонтрольныйВызов = ПараметрыПодключения.ДелатьКонтрольныйВызов; Таймаут = ПараметрыПодключения.Таймаут; Если ДелатьКонтрольныйВызов И Таймаут <> Неопределено И Таймаут > 20 Тогда ПараметрыПодключения.Таймаут = 7; WSПроксиPing = РегистрыСведений.КэшПрограммныхИнтерфейсов.ВнутренняяWSПрокси(ПараметрыПодключения); Попытка WSПроксиPing.Ping(); Исключение АдресТочкиПодключения = WSПроксиPing.ТочкаПодключения.Местоположение; ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Не удалось проверить доступность web-сервиса |%1 |по причине: |%2\'"), ПараметрыПодключения.АдресWSDL, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); Если ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда МодульПолучениеФайловИзИнтернета = ОбщийМодуль("ПолучениеФайловИзИнтернета"); РезультатДиагностики = МодульПолучениеФайловИзИнтернета.ДиагностикаСоединения(АдресТочкиПодключения); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'%1 |Результат диагностики: |%2\'"), ТекстОшибки, РезультатДиагностики.ОписаниеОшибки); КонецЕсли; ВызватьИсключение ТекстОшибки; КонецПопытки; ПараметрыПодключения.Таймаут = Таймаут; КонецЕсли; Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ВнутренняяWSПрокси(ПараметрыПодключения); КонецФункции ///////////////////////////////////////////////////////////////////////////////// // Версионирование программных интерфейсов. // Возвращает номера версий программных интерфейсов удаленной системы, доступной через веб-сервис. // Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах // с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии, // то только в этом случае допустимо вызывать у него новую функцию. // // В целях экономии трафика при интенсивном взаимодействии между вызывающей и вызываемой сторонами // сведения о версиях кэшируются на одни сутки. Если для целей отладки требуется сбросить кэш раньше этого времени, // следует удалить соответствующие записи из регистра сведений КэшПрограммныхИнтерфейсов. // // Параметры: // Адрес - Строка - адрес веб-сервиса версионирования интерфейсов InterfaceVersion; // Пользователь - Строка - имя пользователя веб-сервиса; // Пароль - Строка - пароль пользователя веб-сервиса; // Интерфейс - Строка - имя запрашиваемого программного интерфейса, например, "СервисПередачиФайлов". // // Возвращаемое значение: // ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса. // Например, "1.0.2.1". // // Пример: // Версии = ПолучитьВерсииИнтерфейса("http://vsrvx/sm", "ivanov",, "СервисПередачиФайлов"); // // Также для обратной совместимости поддерживается устаревший вариант вызова: // ПараметрыПодключения = Новый Структура; // ПараметрыПодключения.Вставить("URL", "http://vsrvx/sm"); // ПараметрыПодключения.Вставить("UserName", "ivanov"); // ПараметрыПодключения.Вставить("Password", ""); // Версии = ПолучитьВерсииИнтерфейса(ПараметрыПодключения, "СервисПередачиФайлов"); // Функция ПолучитьВерсииИнтерфейса(Знач Адрес, Знач Пользователь, Знач Пароль = Неопределено, Знач Интерфейс = Неопределено) Экспорт Если ТипЗнч(Адрес) = Тип("Структура") Тогда // для обратной совместимости ПараметрыПодключения = Адрес; ИмяИнтерфейса = Пользователь; Иначе ПараметрыПодключения = Новый Структура; ПараметрыПодключения.Вставить("URL", Адрес); ПараметрыПодключения.Вставить("UserName", Пользователь); ПараметрыПодключения.Вставить("Password", Пароль); ИмяИнтерфейса = Интерфейс; КонецЕсли; Если Не ПараметрыПодключения.Свойство("URL") Или Не ЗначениеЗаполнено(ПараметрыПодключения.URL) Тогда ВызватьИсключение(НСтр("ru = \'Не задан URL сервиса.\'")); КонецЕсли; ПараметрыПолучения = Новый Массив; ПараметрыПолучения.Добавить(ПараметрыПодключения); ПараметрыПолучения.Добавить(ИмяИнтерфейса); Возврат РегистрыСведений.КэшПрограммныхИнтерфейсов.ДанныеКэшаВерсий( РегистрыСведений.КэшПрограммныхИнтерфейсов.ИдентификаторЗаписиКэшаВерсий(ПараметрыПодключения.URL, ИмяИнтерфейса), Перечисления.ТипыДанныхКэшаПрограммныхИнтерфейсов.ВерсииИнтерфейса, ПараметрыПолучения, Истина); КонецФункции // Возвращает номера версий программных интерфейсов удаленной системы, подключенной через внешнее соединение. // Позволяет обеспечивать полную обратную совместимость при изменениях в программных интерфейсах // с помощью их явного версионирования. Например, если программный интерфейс выше определенной версии, // то только в этом случае допустимо вызывать у него новую функцию. // // Параметры: // ВнешнееСоединение - COMОбъект - внешнее соединение, которое используется для работы с удаленной системой. // ИмяИнтерфейса - Строка - имя запрашиваемого программного интерфейса, например "СервисПередачиФайлов". // // Возвращаемое значение: // ФиксированныйМассив - массив строк, каждая строка является представлением номера версии интерфейса. // Например "1.0.2.1". // // Пример: // Версии = ОбщегоНазначения.ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, "СервисПередачиФайлов"); // Функция ПолучитьВерсииИнтерфейсаЧерезВнешнееСоединение(ВнешнееСоединение, Знач ИмяИнтерфейса) Экспорт Попытка ВерсииИнтерфейсаXML = ВнешнееСоединение.СтандартныеПодсистемыСервер.ПоддерживаемыеВерсии(ИмяИнтерфейса); Исключение СтрокаСообщения = НСтр("ru = \'Корреспондент не поддерживает версионирование программных интерфейсов. |Описание ошибки: %1\'"); СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); ЗаписьЖурналаРегистрации(НСтр("ru = \'Получение версий интерфейса\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , , СтрокаСообщения); Возврат Новый ФиксированныйМассив(Новый Массив); КонецПопытки; Возврат Новый ФиксированныйМассив(ЗначениеИзСтрокиXML(ВерсииИнтерфейсаXML)); КонецФункции // Удаляет записи кэша версий программных интерфейсов, содержащих в идентификаторе указанную подстроку. // В качестве подстроки может использоваться, например, имя интерфейса, более не используемого в конфигурации. // // Параметры: // ПодстрокаПоискаИдентификаторов - Строка - подстрока поиска идентификаторов. // Не может содержать символов %, _ и [. // Процедура УдалитьЗаписиКэшаВерсий(Знач ПодстрокаПоискаИдентификаторов) Экспорт НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; Блокировка.Добавить("РегистрСведений.КэшПрограммныхИнтерфейсов"); Блокировка.Заблокировать(); ТекстЗапроса = "ВЫБРАТЬ | ТаблицаКэша.Идентификатор КАК Идентификатор, | ТаблицаКэша.ТипДанных КАК ТипДанных |ИЗ | РегистрСведений.КэшПрограммныхИнтерфейсов КАК ТаблицаКэша |ГДЕ | ТаблицаКэша.Идентификатор ПОДОБНО ""%ПодстрокаПоиска%"" СПЕЦСИМВОЛ ""~"""; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ПодстрокаПоиска", СформироватьСтрокуДляПоискаВЗапросе(ПодстрокаПоискаИдентификаторов)); Запрос = Новый Запрос(ТекстЗапроса); Результат = Запрос.Выполнить(); Выборка = Результат.Выбрать(); Пока Выборка.Следующий() Цикл Запись = РегистрыСведений.КэшПрограммныхИнтерфейсов.СоздатьМенеджерЗаписи(); Запись.Идентификатор = Выборка.Идентификатор; Запись.ТипДанных = Выборка.ТипДанных; Запись.Удалить(); КонецЦикла; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ВызватьИсключение; КонецПопытки; КонецПроцедуры #КонецОбласти #Область БезопасноеХранилище //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с хранилищем паролей. // Записывает конфиденциальные данные в безопасное хранилище. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владелец - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы, // представляющий объект-владелец сохраняемого пароля или строка до 128 символов. // Для объектов других типов в качестве владельца рекомендуется использовать ссылку на // элемент метаданных этого типа в справочнике ИдентификаторыОбъектовМетаданных // или ключ в виде строки с учетом имен подсистем. // Например, для БСП: // Владелец = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("РегистрСведений.АдресныеОбъекты"); // если нужно 1 хранилище на подсистему БСП: // Владелец = "СтандартныеПодсистемы.УправлениеДоступом"; // если нужно более 1 хранилища на подсистему БСП: // Владелец = "СтандартныеПодсистемы.УправлениеДоступом.<Уточнение>"; // Данные - Произвольный - данные помещаемые в безопасное хранилище. Неопределенно - удаляет все данные. // Для удаления данных по ключу следует использовать процедуру УдалитьДанныеИзБезопасногоХранилища. // - Структура - если параметр Ключ содержит Неопределено. Подробнее см. описание параметра Ключ // Ключ - Строка - ключ сохраняемых настроек, по умолчанию "Пароль". // Ключ должен соответствовать правилам имен идентификаторов: // 1. Первым символом ключа должна быть буква или символ подчеркивания (_). // 2. Каждый из последующих символов может быть буквой, цифрой или символом подчеркивания (_). // Неопределено - для добавления набора данных структурой, где ключ структуры - это имя ключа данных, // а значение - сохраняемые данные. Пример использования см. ниже. // // Пример: // // Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) // Если ТекущийПользовательМожетИзменятьПароль Тогда // УстановитьПривилегированныйРежим(Истина); // ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Логин, "Логин"); // ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, Пароль); // УстановитьПривилегированныйРежим(Ложь); // КонецЕсли; // КонецПроцедуры // // Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) // Если ТекущийПользовательМожетИзменятьПароль Тогда // ЛогинИПароль = Новый Структура; // ЛогинИПароль.Вставить("Логин", Логин); // ЛогинИПароль.Вставить("Пароль", Пароль); // УстановитьПривилегированныйРежим(Истина); // ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище(ТекущийОбъект.Ссылка, ЛогинИПароль, Неопределено); // УстановитьПривилегированныйРежим(Ложь); // КонецЕсли; // КонецПроцедуры // Процедура ЗаписатьДанныеВБезопасноеХранилище(Владелец, Данные, Ключ = "Пароль") Экспорт ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Недопустимое значение параметра %1 в %2. |параметр должен содержать ссылку; передано значение: %3 (тип %4).\'"), "Владелец", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Владелец, ТипЗнч(Владелец))); Если ЗначениеЗаполнено(Ключ) Тогда ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Ключ) = Тип("Строка"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Недопустимое значение параметра %1 в %2. |параметр должен содержать строку; передано значение: %3 (тип %4).\'"), "Ключ", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Ключ, ТипЗнч(Ключ))); Иначе ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Данные) = Тип("Структура"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Недопустимое значение параметра %1 в %2. |Если Ключ = Неопределено, то параметр должен содержать структуру; передано значение: %3 (тип %4).\'"), "Данные", "ОбщегоНазначения.ЗаписатьДанныеВБезопасноеХранилище", Данные, ТипЗнч(Данные))); КонецЕсли; ЭтоОбластьДанных = РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных(); Если ЭтоОбластьДанных Тогда БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи(); Иначе БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи(); КонецЕсли; БезопасноеХранилищеДанных.Владелец = Владелец; БезопасноеХранилищеДанных.Прочитать(); Если Данные <> Неопределено Тогда Если БезопасноеХранилищеДанных.Выбран() Тогда ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить(); Если ТипЗнч(ДанныеДляСохранения) <> Тип("Структура") Тогда ДанныеДляСохранения = Новый Структура(); КонецЕсли; Если ЗначениеЗаполнено(Ключ) Тогда ДанныеДляСохранения.Вставить(Ключ, Данные); Иначе ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ДанныеДляСохранения, Данные, Истина); КонецЕсли; ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(6)); БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения; БезопасноеХранилищеДанных.Записать(); Иначе ДанныеДляСохранения = ?(ЗначениеЗаполнено(Ключ), Новый Структура(Ключ, Данные), Данные); ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(6)); БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения; БезопасноеХранилищеДанных.Владелец = Владелец; БезопасноеХранилищеДанных.Записать(); КонецЕсли; Иначе БезопасноеХранилищеДанных.Удалить(); КонецЕсли; КонецПроцедуры // Возвращает данные из безопасного хранилища. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владельцы - Массив из ПланОбменаСсылка // - Массив из СправочникСсылка // - Массив из Строка - ссылки на объекты информационной базы, // представляющих объекты-владельцы или уникальные строки(до 128 символов) владельцев данных. // Ключи - Строка - содержит имя ключа данных или список имен ключей, указанных через запятую. // - Неопределено - будут возвращены все сохраненные данные переданных владельцев. // ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме. // // Возвращаемое значение: // Соответствие из КлючИЗначение: // * Ключ - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы // или строка до 128 символов идентифицирующая владельца данных. // * Значение - Произвольный - если в параметре Ключи указан один ключ, // то возвращается его значение произвольного типа. // - Структура - если в параметре Ключи указано несколько ключей или Неопределено, // где ключ структуры - это имя ключа сохраненных данных, // а значение - данные произвольного типа. Когда для ключа отсутствуют данные, // то значение содержит Неопределено. // - Неопределено - если данные по ключу отсутствуют. // // Пример: // Процедура РассылкаПриглашений(Пользователи) // // УстановитьПривилегированныйРежим(Истина); // ДанныеАвторизации = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(Пользователи, "Логин, Пароль"); // УстановитьПривилегированныйРежим(Ложь); // // Для каждого Пользователь Из Пользователи Цикл // ОтправитьПриглашение(Пользователь, ДанныеАвторизации[Пользователь]); // КонецЦикла; // // КонецПроцедуры // Функция ПрочитатьДанныеВладельцевИзБезопасногоХранилища(Владельцы, Ключи = "Пароль", ОбщиеДанные = Неопределено) Экспорт ОбщегоНазначенияКлиентСервер.Проверить(ТипЗнч(Владельцы) = Тип("Массив"), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Недопустимое значение параметра %1 в %2. |параметр должен содержать массив; передано значение: %3 (тип %4).\'"), "Владельцы", "ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища", Владельцы, ТипЗнч(Владельцы))); Результат = ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные); Возврат Результат; КонецФункции // Возвращает данные из безопасного хранилища. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владелец - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы, // представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов). // Ключи - Строка - содержит список имен сохраненных данных, указанных через запятую. // - Неопределено - будут возвращены все сохраненные данные владельца. // ОбщиеДанные - Булево - Истина, если требуется в модели сервиса получить данные из общих данных в разделенном режиме. // // Возвращаемое значение: // Произвольный, Структура, Неопределено - данные из безопасного хранилища. Если указан один ключ, // то возвращается его значение, иначе структура. // Если данные отсутствуют - Неопределенно. // // Пример: // Если ТекущийПользовательМожетИзменятьПароль Тогда // УстановитьПривилегированныйРежим(Истина); // Логин = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, "Логин"); // Пароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка); // УстановитьПривилегированныйРежим(Ложь); // Иначе // Элементы.ГруппаЛогинИПароль.Видимость = Ложь; // КонецЕсли; // // УстановитьПривилегированныйРежим(Истина); // ЛогинИПароль = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(ТекущийОбъект.Ссылка, Неопределено); // Функция ПрочитатьДанныеИзБезопасногоХранилища(Владелец, Ключи = "Пароль", ОбщиеДанные = Неопределено) Экспорт Владельцы = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец); ДанныеВладельца = ПрочитатьДанныеВладельцевИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные); Результат = ДанныеВладельца[Владелец]; Возврат Результат; КонецФункции // Удаляет конфиденциальные данные в безопасное хранилище. // Вызывающий код должен самостоятельно устанавливать привилегированный режим. // // Безопасное хранилище недоступно для чтения пользователям (кроме администраторов), // а доступно только коду, который делает обращения только к своей части данных и // в том контексте, который предполагает чтение или запись конфиденциальных данных. // // Параметры: // Владелец - ПланОбменаСсылка // - СправочникСсылка // - Строка - ссылка на объект информационной базы, // представляющий объект-владелец сохраняемого пароля или уникальная строка(до 128 символов). // - Массив - ссылки на объекты информационной базы для удаления данным по нескольким владельцам. // Ключи - Строка - содержит список имен удаляемых данных, указанных через запятую. // Неопределено - удаляет все данные. // // Пример: // Процедура ПередУдалением(Отказ) // // // Проверка значения свойства ОбменДанными.Загрузка отсутствует, так как удалять данные // // из безопасного хранилища нужно даже при удалении объекта при обмене данными. // // УстановитьПривилегированныйРежим(Истина); // ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища(Ссылка); // УстановитьПривилегированныйРежим(Ложь); // // КонецПроцедуры // Процедура УдалитьДанныеИзБезопасногоХранилища(Владелец, Ключи = Неопределено) Экспорт ОбщегоНазначенияКлиентСервер.Проверить(ЗначениеЗаполнено(Владелец), СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Недопустимое значение параметра %1 в %2. |параметр должен содержать ссылку; передано значение: %3 (тип %4).\'"), "Владелец", "ОбщегоНазначения.УдалитьДанныеИзБезопасногоХранилища", Владелец, ТипЗнч(Владелец))); Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() Тогда БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанныхОбластейДанных.СоздатьМенеджерЗаписи(); Иначе БезопасноеХранилищеДанных = РегистрыСведений.БезопасноеХранилищеДанных.СоздатьМенеджерЗаписи(); КонецЕсли; Владельцы = ?(ТипЗнч(Владелец) = Тип("Массив"), Владелец, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Владелец)); Для Каждого ВладелецДанных Из Владельцы Цикл БезопасноеХранилищеДанных.Владелец = ВладелецДанных; БезопасноеХранилищеДанных.Прочитать(); Если ТипЗнч(БезопасноеХранилищеДанных.Данные) = Тип("ХранилищеЗначения") Тогда ДанныеДляСохранения = БезопасноеХранилищеДанных.Данные.Получить(); Если Ключи <> Неопределено И ТипЗнч(ДанныеДляСохранения) = Тип("Структура") Тогда СписокКлючей = СтрРазделить(Ключи, ",", Ложь); Если БезопасноеХранилищеДанных.Выбран() И СписокКлючей.Количество() > 0 Тогда Для каждого КлючДляУдаления Из СписокКлючей Цикл Если ДанныеДляСохранения.Свойство(КлючДляУдаления) Тогда ДанныеДляСохранения.Удалить(КлючДляУдаления); КонецЕсли; КонецЦикла; ДанныеДляХранилищеЗначения = Новый ХранилищеЗначения(ДанныеДляСохранения, Новый СжатиеДанных(6)); БезопасноеХранилищеДанных.Данные = ДанныеДляХранилищеЗначения; БезопасноеХранилищеДанных.Записать(); Возврат; КонецЕсли; КонецЕсли; КонецЕсли; БезопасноеХранилищеДанных.Удалить(); КонецЦикла; КонецПроцедуры #КонецОбласти #Область БуферОбмена //////////////////////////////////////////////////////////////////////////////// // Процедуры и функции для работы с внутренним буфером обмена. // Помещает выделенные строки табличной части во внутренний буфер обмена // откуда их можно получить с помощью СтрокиИзБуфераОбмена. // // Параметры: // ТабличнаяЧасть - ДанныеФормыКоллекция - табличная часть, строки которой // необходимо поместить во внутренний буфер обмена. // ВыделенныеСтроки - Массив - массив идентификаторов выделенных строк. // Источник - Строка - произвольный строковый идентификатор, например, имя объекта, // строки табличной части которого помещаются во внутренний буфер обмена. // Процедура СкопироватьСтрокиВБуферОбмена(ТабличнаяЧасть, ВыделенныеСтроки, Источник = Неопределено) Экспорт Если ВыделенныеСтроки = Неопределено Тогда Возврат; КонецЕсли; ТаблицаЗначений = ТабличнаяЧасть.Выгрузить(); ТаблицаЗначений.Очистить(); УдаляемыеКолонки = Новый Массив; УдаляемыеКолонки.Добавить("ИсходныйНомерСтроки"); УдаляемыеКолонки.Добавить("НомерСтроки"); Для Каждого ИмяКолонки Из УдаляемыеКолонки Цикл Колонка = ТаблицаЗначений.Колонки.Найти(ИмяКолонки); Если Колонка = Неопределено Тогда Продолжить; КонецЕсли; ТаблицаЗначений.Колонки.Удалить(Колонка); КонецЦикла; Для Каждого ИдентификаторСтроки Из ВыделенныеСтроки Цикл КопируемаяСтрока = ТабличнаяЧасть.НайтиПоИдентификатору(ИдентификаторСтроки); ЗаполнитьЗначенияСвойств(ТаблицаЗначений.Добавить(), КопируемаяСтрока); КонецЦикла; СкопироватьВБуферОбмена(ТаблицаЗначений, Источник); КонецПроцедуры // Помещает произвольные данные во внутренний буфер обмена, откуда их можно получить с помощью СтрокиИзБуфераОбмена. // // Параметры: // Данные - Произвольный - данные, которые необходимо поместить в внутренний буфер обмена. // Источник - Строка - произвольный строковый идентификатор, например, имя объекта, // строки табличной части которого помещаются во внутренний буфер обмена. // Процедура СкопироватьВБуферОбмена(Данные, Источник = Неопределено) Экспорт ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; Если ЗначениеЗаполнено(ТекущийБуферОбмена.Данные) Тогда Адрес = ТекущийБуферОбмена.Данные; Иначе Адрес = Новый УникальныйИдентификатор; КонецЕсли; ДанныеВХранилище = ПоместитьВоВременноеХранилище(Данные, Адрес); СтруктураБуфераОбмена = Новый Структура; СтруктураБуфераОбмена.Вставить("Источник", Источник); СтруктураБуфераОбмена.Вставить("Данные", ДанныеВХранилище); ПараметрыСеанса.БуферОбмена = Новый ФиксированнаяСтруктура(СтруктураБуфераОбмена); КонецПроцедуры // Получает строки табличной части, помещенные во внутренний буфер обмена с помощью СкопироватьСтрокиВБуферОбмена. // // Возвращаемое значение: // Структура: // * Данные - Произвольный - данные из внутреннего буфера обмена. // Например, ТаблицаЗначений при вызове СкопироватьСтрокиВБуферОбмена. // * Источник - Строка - объект, к которому относятся данные. // Если при помещении во внутренний буфер не был указан, то Неопределено. // Функция СтрокиИзБуфераОбмена() Экспорт Результат = Новый Структура; Результат.Вставить("Источник", Неопределено); Результат.Вставить("Данные", Неопределено); Если ПустойБуферОбмена() Тогда Возврат Результат; КонецЕсли; ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена Результат.Источник = ТекущийБуферОбмена.Источник; Результат.Данные = ПолучитьИзВременногоХранилища(ТекущийБуферОбмена.Данные); Возврат Результат; КонецФункции // Проверяет наличие сохраненных данных во внутренний буфере обмена. // // Параметры: // Источник - Строка - если передан, то проверяется наличие данных // в внутреннем буфере обмена с этим ключом. // По умолчанию - Неопределено. // Возвращаемое значение: // Булево - Истина, если пустой. // Функция ПустойБуферОбмена(Источник = Неопределено) Экспорт ТекущийБуферОбмена = ПараметрыСеанса.БуферОбмена; // см. СтрокиИзБуфераОбмена ИсточникСовпадает = Истина; Если Источник <> Неопределено Тогда ИсточникСовпадает = (Источник = ТекущийБуферОбмена.Источник); КонецЕсли; Возврат (Не ИсточникСовпадает Или Не ЗначениеЗаполнено(ТекущийБуферОбмена.Данные)); КонецФункции #КонецОбласти #Область БезопасноеВыполнениеВнешнегоКода //////////////////////////////////////////////////////////////////////////////// // Функции для поддержки работы конфигурации с профилем безопасности, в котором // запрещено подключение внешних модулей без установки безопасного режима. // // Выполнить экспортную процедуру по имени с уровнем привилегий конфигурации. // При включении профилей безопасности для вызова оператора Выполнить() используется // переход в безопасный режим с профилем безопасности, используемым для информационной базы // (если выше по стеку не был установлен другой безопасный режим). // // Параметры: // ИмяМетода - Строка - имя экспортной процедуры в формате // <имя объекта>.<имя процедуры>, где <имя объекта> - это // общий модуль или модуль менеджера объекта. // Параметры - Массив - параметры передаются в процедуру <ИмяЭкспортнойПроцедуры> // в порядке расположения элементов массива. // // Пример: // Параметры = Новый Массив(); // Параметры.Добавить("1"); // ОбщегоНазначения.ВыполнитьМетодКонфигурации("МойОбщийМодуль.МояПроцедура", Параметры); // Процедура ВыполнитьМетодКонфигурации(Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт ПроверитьИмяПроцедурыКонфигурации(ИмяМетода); Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме"); Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности() И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы(); Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда УстановитьБезопасныйРежим(ПрофильИнформационнойБазы); Если БезопасныйРежим() = Истина Тогда УстановитьБезопасныйРежим(Ложь); КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; ПараметрыСтрока = ""; Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда Для Индекс = 0 По Параметры.ВГраница() Цикл ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],"; КонецЦикла; ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1); КонецЕсли; Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")"; КонецПроцедуры // Выполнить экспортную процедуру объекта встроенного языка по имени. // При включении профилей безопасности для вызова оператора Выполнить() используется // переход в безопасный режим с профилем безопасности, используемым для информационной базы // (если выше по стеку не был установлен другой безопасный режим). // // Параметры: // Объект - Произвольный - объект встроенного языка 1С:Предприятия, содержащий методы (например, ОбработкаОбъект). // ИмяМетода - Строка - имя экспортной процедуры модуля объекта обработки. // Параметры - Массив - параметры передаются в процедуру <ИмяПроцедуры> // в порядке расположения элементов массива. // Процедура ВыполнитьМетодОбъекта(Знач Объект, Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт // Проверка имени метода на корректность. Попытка Тест = Новый Структура(ИмяМетода, ИмяМетода); Если Тест = Неопределено Тогда ВызватьИсключение НСтр("ru = \'Синтетический тест\'"); КонецЕсли; Исключение ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Некорректное значение параметра %1 (%2) в %3.\'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.ВыполнитьМетодОбъекта"); КонецПопытки; Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме"); Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности() И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме"); ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы(); Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда УстановитьБезопасныйРежим(ПрофильИнформационнойБазы); Если БезопасныйРежим() = Истина Тогда УстановитьБезопасныйРежим(Ложь); КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; ПараметрыСтрока = ""; Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда Для Индекс = 0 По Параметры.ВГраница() Цикл ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],"; КонецЦикла; ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1); КонецЕсли; Выполнить "Объект." + ИмяМетода + "(" + ПараметрыСтрока + ")"; КонецПроцедуры // Выполняет произвольный алгоритм на встроенном языке 1С:Предприятия, предварительно устанавливая // безопасный режим выполнения кода и безопасный режим разделения данных для всех разделителей, // присутствующих в составе конфигурации. // // Параметры: // Алгоритм - Строка - алгоритм на встроенном языке "1С:Предприятия". // Параметры - Произвольный - контекст, который требуется для выполнения алгоритма. // В тексте алгоритма обращение к контексту должно происходить по имени "Параметры". // Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям // "Значение1" и "Значение2", переданным в Параметры, как свойства. // // Пример: // // Параметры = Новый Структура; // Параметры.Вставить("Значение1", 1); // Параметры.Вставить("Значение2", 10); // ОбщегоНазначения.ВыполнитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры); // Процедура ВыполнитьВБезопасномРежиме(Знач Алгоритм, Знач Параметры = Неопределено) Экспорт УстановитьБезопасныйРежим(Истина); Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации(); Иначе МассивРазделителей = Новый Массив; КонецЕсли; Для Каждого ИмяРазделителя Из МассивРазделителей Цикл УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина); КонецЦикла; Выполнить Алгоритм; КонецПроцедуры // Вычисляет переданное выражение, предварительно устанавливая безопасный режим выполнения кода // и безопасный режим разделения данных для всех разделителей, присутствующих в составе конфигурации. // // Параметры: // Выражение - Строка - выражение на встроенном языке 1С:Предприятия. // Параметры - Произвольный - контекст, который требуется для вычисления выражения. // В тексте выражения обращение к контексту должно происходить по имени "Параметры". // Например, выражение "Параметры.Значение1 = Параметры.Значение2" обращается к значениям // "Значение1" и "Значение2" переданные в Параметры, как свойства. // // Возвращаемое значение: // Произвольный - результат вычисления выражения. // // Пример: // // // Пример 1 // Параметры = Новый Структура; // Параметры.Вставить("Значение1", 1); // Параметры.Вставить("Значение2", 10); // Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("Параметры.Значение1 = Параметры.Значение2", Параметры); // // // Пример 2 // Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме("СтандартныеПодсистемыСервер.ВерсияБиблиотеки()"); // Функция ВычислитьВБезопасномРежиме(Знач Выражение, Знач Параметры = Неопределено) Экспорт УстановитьБезопасныйРежим(Истина); Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); МассивРазделителей = МодульРаботаВМоделиСервиса.РазделителиКонфигурации(); Иначе МассивРазделителей = Новый Массив; КонецЕсли; Для Каждого ИмяРазделителя Из МассивРазделителей Цикл УстановитьБезопасныйРежимРазделенияДанных(ИмяРазделителя, Истина); КонецЦикла; Возврат Вычислить(Выражение); КонецФункции // Возвращает описание защиты от опасных действий с отключенными предупреждениями. // // Возвращаемое значение: // ОписаниеЗащитыОтОпасныхДействий - со свойством ПредупреждатьОбОпасныхДействиях = Ложь. // Функция ОписаниеЗащитыБезПредупреждений() Экспорт ОписаниеЗащиты = Новый ОписаниеЗащитыОтОпасныхДействий; ОписаниеЗащиты.ПредупреждатьОбОпасныхДействиях = Ложь; Возврат ОписаниеЗащиты; КонецФункции #КонецОбласти #Область Запросы // Подготавливает строку для использования в качестве шаблона поиска в запросе с оператором ПОДОБНО. // Экранирует служебные символы, если они есть в строке. // // Параметры: // СтрокаПоиска - Строка - произвольная строка. // // Возвращаемое значение: // Строка // // Пример: // ВЫБРАТЬ // Номенклатура.Ссылка КАК Ссылка // ИЗ // Справочник.Номенклатура КАК Номенклатура // ГДЕ // Номенклатура.Наименование ПОДОБНО &Шаблон СПЕЦСИМВОЛ "~" // // Запрос.УстановитьПараметр("Шаблон", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИскомыйТекст)); // Функция СформироватьСтрокуДляПоискаВЗапросе(Знач СтрокаПоиска) Экспорт Результат = СтрокаПоиска; Результат = СтрЗаменить(Результат, "~", "~~"); Результат = СтрЗаменить(Результат, "%", "~%"); Результат = СтрЗаменить(Результат, "_", "~_"); Результат = СтрЗаменить(Результат, "[", "~["); Результат = СтрЗаменить(Результат, "]", "~]"); Результат = СтрЗаменить(Результат, "^", "~^"); Возврат Результат; КонецФункции // Возвращает фрагмент текста запроса, отделяющего один запрос от другого. // // Возвращаемое значение: // Строка - разделитель запросов. // Функция РазделительПакетаЗапросов() Экспорт Возврат " |; | |//////////////////////////////////////////////////////////////////////////////// |"; КонецФункции #КонецОбласти #Область Прочее // Выполняет проверки перед выполнением обработчика регламентного задания и прерывает выполнение, // если его запуск в данный момент невозможен, например: // - еще не завершено обновление программы; // - запуск через консоль или другим способом, минуя включение функциональной опции // (если регламентное задание зависит от функциональных опций); // - попытка выполнения задания, работающего с внешними ресурсами в копии информационной базы. // // Параметры: // РегламентноеЗадание - ОбъектМетаданныхРегламентноеЗадание - регламентное задание, // из которого вызывается данная процедура. // // Пример: // ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.<ИмяРегламентногоЗадания>); // Процедура ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание = Неопределено) Экспорт УстановитьПривилегированныйРежим(Истина); Если РегистрыСведений.ПараметрыРаботыПрограммы.НеобходимоОбновление() Тогда Текст = НСтр("ru = \'Вход в программу временно невозможен в связи с обновлением на новую версию. |Рекомендуется запрещать выполнение регламентных заданий на время обновления.\'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; Если Не РазделениеВключено() И ПланыОбмена.ГлавныйУзел() = Неопределено И ЗначениеЗаполнено(Константы.ГлавныйУзел.Получить()) Тогда Текст = НСтр("ru = \'Вход в программу временно невозможен до восстановления связи с главным узлом. |Рекомендуется запрещать выполнение регламентных заданий на время восстановления.\'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; Если РегламентноеЗадание <> Неопределено И ПодсистемаСуществует("СтандартныеПодсистемы.РегламентныеЗадания") Тогда МодульБлокировкаРаботыСВнешнимиРесурсами = ОбщийМодуль("БлокировкаРаботыСВнешнимиРесурсами"); МодульБлокировкаРаботыСВнешнимиРесурсами.ПриНачалеВыполненияРегламентногоЗадания(РегламентноеЗадание); МодульРегламентныеЗаданияСлужебный = ОбщийМодуль("РегламентныеЗаданияСлужебный"); Доступно = МодульРегламентныеЗаданияСлужебный.РегламентноеЗаданиеДоступноПоФункциональнымОпциям(РегламентноеЗадание); Если Не Доступно Тогда Задания = РегламентныеЗаданияСервер.НайтиЗадания(Новый Структура("Метаданные", РегламентноеЗадание)); Для Каждого Задание Из Задания Цикл РегламентныеЗаданияСервер.ИзменитьЗадание(Задание.УникальныйИдентификатор, Новый Структура("Использование", Ложь)); КонецЦикла; Текст = НСтр("ru = \'Регламентное задание недоступно по функциональным опциям или |не поддерживает работу в текущем режиме работы программы. |Выполнение прервано. Задание отключено.\'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; КонецЕсли; Если СтандартныеПодсистемыСервер.ТребуетсяУстановкаРегиональныхНастроекИнформационнойБазы() Тогда Текст = НСтр("ru = \'Регламентное задание недоступно до установки начальных региональных настроек программы. |Выполнение прервано.\'"); РегламентныеЗаданияСервер.ОтменитьВыполнениеЗадания(РегламентноеЗадание, Текст); ВызватьИсключение Текст; КонецЕсли; Справочники.ВерсииРасширений.ЗарегистрироватьИспользованиеВерсииРасширений(); РегистрыСведений.ПараметрыРаботыВерсийРасширений.ПриУспешномНачалеВыполненияРегламентногоЗадания(); КонецПроцедуры // Переводит параметры сеанса в состояние "Не установлено". // // Параметры: // ПараметрыДляОчистки - Строка - имена параметров сеанса для очистки, разделенные ",". // Исключения - Строка - имена параметров сеанса не предназначенные для очистки, разделенные ",". // Процедура ОчиститьПараметрыСеанса(ПараметрыДляОчистки = "", Исключения = "") Экспорт МассивИсключений = СтрРазделить(Исключения, ","); МассивПараметровДляОчистки = СтрРазделить(ПараметрыДляОчистки, ",", Ложь); Если МассивПараметровДляОчистки.Количество() = 0 Тогда Для Каждого ПараметрСеанса Из Метаданные.ПараметрыСеанса Цикл Если МассивИсключений.Найти(ПараметрСеанса.Имя) = Неопределено Тогда МассивПараметровДляОчистки.Добавить(ПараметрСеанса.Имя); КонецЕсли; КонецЦикла; КонецЕсли; Индекс = МассивПараметровДляОчистки.Найти("ПараметрыКлиентаНаСервере"); Если Индекс <> Неопределено Тогда МассивПараметровДляОчистки.Удалить(Индекс); КонецЕсли; Индекс = МассивПараметровДляОчистки.Найти("ОсновнойЯзык"); Если Индекс <> Неопределено Тогда МассивПараметровДляОчистки.Удалить(Индекс); КонецЕсли; Индекс = МассивПараметровДляОчистки.Найти("УстановленныеРасширения"); Если Индекс <> Неопределено Тогда МассивПараметровДляОчистки.Удалить(Индекс); КонецЕсли; ПараметрыСеанса.Очистить(МассивПараметровДляОчистки); КонецПроцедуры // Проверяет, умещаются ли переданные табличные документы на страницу при печати. // // Параметры: // ТабДокумент - ТабличныйДокумент - табличный документ. // ВыводимыеОбласти - Массив // - ТабличныйДокумент - массив из проверяемых таблиц или табличный документ. // РезультатПриОшибке - Булево - какой возвращать результат при возникновении ошибки. // // Возвращаемое значение: // Булево - умещаются или нет переданные документы. // Функция ПроверитьВыводТабличногоДокумента(ТабДокумент, ВыводимыеОбласти, РезультатПриОшибке = Истина) Экспорт Попытка Возврат ТабДокумент.ПроверитьВывод(ВыводимыеОбласти); Исключение Возврат РезультатПриОшибке; КонецПопытки; КонецФункции // Сохраняет персональные настройки пользователя, относящиеся к подсистеме БазоваяФункциональность. // Для получения настроек предусмотрены следующие функции: // - ОбщегоНазначенияКлиент.ПредлагатьУстановкуРасширенияРаботыСФайлами(), // - СтандартныеПодсистемыСервер.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы(), // - СтандартныеПодсистемыСервер.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы(). // // Параметры: // Настройки - Структура: // * НапоминатьОбУстановкеРасширенияРаботыСФайлами - Булево - признак необходимости // напоминания об установке расширения. // * ЗапрашиватьПодтверждениеПриЗавершенииПрограммы - Булево - запрашивать подтверждение по завершении работы. // * ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы - Булево - показывать оповещение при // динамическом обновлении программы. // Процедура СохранитьПерсональныеНастройки(Настройки) Экспорт Если Настройки.Свойство("НапоминатьОбУстановкеРасширенияРаботыСФайлами") Тогда Если ЭтоВебКлиент() Тогда ИдентификаторКлиента = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ИдентификаторКлиента"); Если ИдентификаторКлиента = Неопределено Тогда СистемнаяИнформация = Новый СистемнаяИнформация; ИдентификаторКлиента = СистемнаяИнформация.ИдентификаторКлиента; КонецЕсли; ХранилищеОбщихНастроекСохранить( "НастройкиПрограммы/ПредлагатьУстановкуРасширенияРаботыСФайлами", ИдентификаторКлиента, Настройки.НапоминатьОбУстановкеРасширенияРаботыСФайлами); КонецЕсли; КонецЕсли; Если Настройки.Свойство("ЗапрашиватьПодтверждениеПриЗавершенииПрограммы") Тогда ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя", "ЗапрашиватьПодтверждениеПриЗавершенииПрограммы", Настройки.ЗапрашиватьПодтверждениеПриЗавершенииПрограммы); КонецЕсли; Если Настройки.Свойство("ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы") Тогда ХранилищеОбщихНастроекСохранить("ОбщиеНастройкиПользователя", "ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы", Настройки.ПоказыватьПредупреждениеОбУстановленныхОбновленияхПрограммы); КонецЕсли; КонецПроцедуры // Выполняет пропорциональное распределение суммы в соответствии // с заданными коэффициентами распределения. // // Параметры: // РаспределяемаяСумма - Число - сумма, которую надо распределить, если сумма равна 0 - то возвращается Неопределено; // Если передана отрицательная - расчет по модулю и после инверсия знаков результата. // Коэффициенты - Массив из Число - коэффициенты распределения, должны быть положительны или отрицательными // одновременно. // Точность - Число - точность округления при распределении. // // Возвращаемое значение: // Массив из Число - массив размерностью равный массиву коэффициентов, содержит // суммы в соответствии с весом коэффициента (из массива коэффициентов). // В случае, если распределить невозможно (кол-во коэффициентов = 0 // есть коэффициенты с отрицательным значением или суммарный вес коэффициентов = 0), // тогда будет возвращено Неопределено. // // Пример: // // Коэффициенты = Новый Массив; // Коэффициенты.Добавить(1); // Коэффициенты.Добавить(2); // Результат = ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам(1, Коэффициенты); // // Результат = [0.33, 0.67] // Функция РаспределитьСуммуПропорциональноКоэффициентам( Знач РаспределяемаяСумма, Коэффициенты, Знач Точность = 2) Экспорт Возврат ОбщегоНазначенияКлиентСервер.РаспределитьСуммуПропорциональноКоэффициентам( РаспределяемаяСумма, Коэффициенты, Точность); КонецФункции // Процедура предназначена для заполнения реквизита формы типа ДанныеФормыДерево. // // Параметры: // КоллекцияЭлементовДерева - ДанныеФормыКоллекцияЭлементовДерева - реквизит, который нужно заполнить. // ДеревоЗначений - ДеревоЗначений - данные для заполнения. // Процедура ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(КоллекцияЭлементовДерева, ДеревоЗначений) Экспорт Для Каждого Строка Из ДеревоЗначений.Строки Цикл ЭлементДерева = КоллекцияЭлементовДерева.Добавить(); ЗаполнитьЗначенияСвойств(ЭлементДерева, Строка); Если Строка.Строки.Количество() > 0 Тогда ЗаполнитьКоллекциюЭлементовДереваДанныхФормы(ЭлементДерева.ПолучитьЭлементы(), Строка); КонецЕсли; КонецЦикла; КонецПроцедуры // Подключает внешнюю компоненту, выполненную по технологии Native API или COM, // из макета конфигурации (хранится в виде ZIP-архива). // // Параметры: // Идентификатор - Строка - идентификатор объекта внешней компоненты. // ПолноеИмяМакета - Строка - полное имя макета конфигурации с ZIP-архивом. // Изолированно - Булево, Неопределено - (по умолчанию Ложь) если Истина, компонента будет подключена // изолированно, в этом случае внешняя компонента загружается в отдельный процесс операционной системы; // Ложь - в этом случае внешняя компонента будет выполняться в том же процессе операционной системы, // который выполняет код встроенного языка; Неопределено - поддерживается поведение платформы по умолчанию: // не изолированно - если компонентой поддерживается только этот режим, изолированно - в остальных случаях. // См. https://its.1c.eu/db/v83doc#bookmark:dev:TI000001866 // // // Возвращаемое значение: // ОбъектВнешнейКомпоненты, Неопределено - экземпляр объекта внешней компоненты или Неопределено, если не удалось создать. // // Пример: // // ПодключаемыйМодуль = ОбщегоНазначения.ПодключитьКомпонентуИзМакета( // "QRCodeExtension", // "ОбщийМакет.КомпонентаПечатиQRКода"); // // Если ПодключаемыйМодуль <> Неопределено Тогда // // ПодключаемыйМодуль содержит созданный экземпляр подключенной компоненты. // КонецЕсли; // // ПодключаемыйМодуль = Неопределено; // Функция ПодключитьКомпонентуИзМакета(Знач Идентификатор, Знач ПолноеИмяМакета, Знач Изолированно = Ложь) Экспорт РезультатПроверкиВнешнейКомпоненты = Неопределено; Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный"); РезультатПроверкиВнешнейКомпоненты = МодульВнешниеКомпонентыСлужебный.ПроверитьПодключениеКомпоненты(Идентификатор); РезультатПроверкиВнешнейКомпоненты.Вставить("Доступна", Не ЗначениеЗаполнено(РезультатПроверкиВнешнейКомпоненты.ОписаниеОшибки)); КонецЕсли; КомпонентаПоследнейВерсии = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии( Идентификатор, ПолноеИмяМакета, РезультатПроверкиВнешнейКомпоненты); Результат = ПодключитьКомпонентуПоИдентификатору(Идентификатор, КомпонентаПоследнейВерсии.Местоположение, Изолированно); Возврат Результат.ПодключаемыйМодуль; КонецФункции #КонецОбласти #Область УстаревшиеПроцедурыИФункции // Устарела. Следует использовать // ОбщегоНазначения.РазделениеВключено И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных. // // Возвращаемое значение: // Булево // Функция ИспользованиеРазделителяСеанса() Экспорт Если Не РазделениеВключено() Тогда Возврат Ложь; КонецЕсли; Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); Возврат МодульРаботаВМоделиСервиса.ИспользованиеРазделителяСеанса(); КонецЕсли; КонецФункции // Устарела. Следует использовать ФайловаяСистема.СоздатьВременныйКаталог // Создает временный каталог. После окончания работы с временным каталогом его необходимо удалить // с помощью ОбщегоНазначения.УдалитьВременныйКаталог. // // Параметры: // Расширение - Строка - расширение каталога, которое идентифицирует назначение временного каталога // и подсистему, которая его создала. // Рекомендуется указывать на английском языке. // // Возвращаемое значение: // Строка - полный путь к каталогу с разделителем пути. // Функция СоздатьВременныйКаталог(Знач Расширение = "") Экспорт Возврат ФайловаяСистема.СоздатьВременныйКаталог(Расширение); КонецФункции // Устарела. Следует использовать ФайловаяСистема.УдалитьВременныйКаталог // Удаляет временный каталог вместе с его содержимым, если возможно. // Если временный каталог не может быть удален (например, он занят каким-то процессом), // то в журнал регистрации записывается соответствующее предупреждение, а процедура завершается. // // Для совместного использования с ОбщегоНазначения.СоздатьВременныйКаталог, // после окончания работы с временным каталогом. // // Параметры: // ПутьККаталогу - Строка - полный путь к временному каталогу. // Процедура УдалитьВременныйКаталог(Знач ПутьККаталогу) Экспорт ФайловаяСистема.УдалитьВременныйКаталог(ПутьККаталогу); КонецПроцедуры // Устарела. Проверяет наличие механизма платформы, предупреждающего об опасных действиях. // // Возвращаемое значение: // Булево - если Истина, тогда работает механизм предупреждений безопасности. // Функция ЕстьЗащитаОтОпасныхДействий() Экспорт Возврат Истина; КонецФункции // Устарела. Создает и возвращает экземпляр отчета или обработки по полному имени объекта метаданных. // // Параметры: // ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Отчет.БизнесПроцессы". // // Возвращаемое значение: // ОтчетОбъект // ОбработкаОбъект - экземпляр отчета или обработки. // Функция ОбъектПоПолномуИмени(ПолноеИмя) Экспорт МассивСтрок = СтрРазделить(ПолноеИмя, "."); Если МассивСтрок.Количество() >= 2 Тогда Вид = ВРег(МассивСтрок[0]); Имя = МассивСтрок[1]; Иначе ВызватьИсключение СтрЗаменить(НСтр("ru = \'Некорректное полное имя отчета или обработки ""%1"".\'"), "%1", ПолноеИмя); КонецЕсли; Если Вид = "ОТЧЕТ" Тогда Возврат Отчеты[Имя].Создать(); ИначеЕсли Вид = "ОБРАБОТКА" Тогда Возврат Обработки[Имя].Создать(); Иначе ВызватьИсключение СтрЗаменить(НСтр("ru = \'""%1"" не является отчетом или обработкой.\'"), "%1", ПолноеИмя); КонецЕсли; КонецФункции // Устарела. Следует использовать ОбщегоНазначения.ЭтоMacOSКлиент // Возвращает Истина, если клиентское приложение запущено под управлением ОС X. // // Возвращаемое значение: // Булево - если нет клиентского приложения, возвращается Ложь. // Функция ЭтоOSXКлиент() Экспорт УстановитьПривилегированныйРежим(Истина); ЭтоMacOSКлиент = СтандартныеПодсистемыСервер.ПараметрыКлиентаНаСервере().Получить("ЭтоMacOSКлиент"); Если ЭтоMacOSКлиент = Неопределено Тогда Возврат Ложь; // Нет клиентского приложения. КонецЕсли; Возврат ЭтоMacOSКлиент; КонецФункции #КонецОбласти #КонецЕсли #КонецОбласти #Если НЕ МобильныйАвтономныйСервер Тогда #Область СлужебныйПрограммныйИнтерфейс // Выгружает запрос в строку XML, которую можно вставить в Консоль запросов. // Для переноса запроса и всех его параметров в Консоль запросов, необходимо вызвать функцию в окне. // "Вычислить выражение" (Shift + F9), скопировать полученный XML в поле "Текст запроса" // консоли запросов и выполнить команду "Заполнить из XML" из меню "Еще". // Подробнее об использование функции смотрите в справке к консоли запросов. // // Параметры: // Запрос - Запрос - запрос, который необходимо выгрузить в формат строки XML. // // Возвращаемое значение: // Строка - строка в формате XML, которую можно извлечь при помощи метода "ОбщегоНазначения.ЗначениеИзСтрокиXML". // После извлечения получится объект типа "Структура" с полями: // * Текст - Строка - текст запроса. // * Параметры - Структура - параметры запроса. // Функция ЗапросВСтрокуXML(Запрос) Экспорт // АПК:299 - используется при отладке запросов, см. описание функции. Структура = Новый Структура("Текст, Параметры"); ЗаполнитьЗначенияСвойств(Структура, Запрос); Возврат ЗначениеВСтрокуXML(Структура); КонецФункции Функция ПодключитьКомпонентуПоИдентификатору(Знач Идентификатор, Знач Местоположение, Знач Изолированно = Ложь) Экспорт ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение); Результат = Новый Структура; Результат.Вставить("Подключено", Ложь); Результат.Вставить("ПодключаемыйМодуль", Неопределено); Результат.Вставить("ОписаниеОшибки", ""); Попытка #Если МобильноеПриложениеСервер Тогда РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName"); #Иначе РезультатПодключения = ПодключитьВнешнююКомпоненту(Местоположение, Идентификатор + "SymbolicName",, ОбщегоНазначенияСлужебныйКлиентСервер.ТипПодключенияКомпоненты(Изолированно)); #КонецЕсли Исключение Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине: |%2.\'"), Идентификатор, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); ЗаписьЖурналаРегистрации(НСтр("ru = \'Подключение внешней компоненты на сервере\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, Результат.ОписаниеОшибки); Возврат Результат; КонецПопытки; Если Не РезультатПодключения Тогда Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Не удалось подключить внешнюю компоненту ""%1"" на сервере по причине: |Метод %2 вернул Ложь.\'"), Идентификатор, "ПодключитьВнешнююКомпоненту"); ЗаписьЖурналаРегистрации(НСтр("ru = \'Подключение внешней компоненты на сервере\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, Результат.ОписаниеОшибки); Возврат Результат; КонецЕсли; ПодключаемыйМодуль = Неопределено; Попытка ПодключаемыйМодуль = Новый("AddIn." + Идентификатор + "SymbolicName" + "." + Идентификатор); Если ПодключаемыйМодуль = Неопределено Тогда ВызватьИсключение НСтр("ru = \'Оператор Новый вернул Неопределено\'"); КонецЕсли; Исключение ПодключаемыйМодуль = Неопределено; ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); КонецПопытки; Если ПодключаемыйМодуль = Неопределено Тогда Результат.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Не удалось создать объект внешней компоненты ""%1"", подключенной на сервере, по причине: |%2\'"), Идентификатор, ТекстОшибки); ЗаписьЖурналаРегистрации(НСтр("ru = \'Подключение внешней компоненты на сервере\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка,,, Результат.ОписаниеОшибки); Возврат Результат; КонецЕсли; Результат.Подключено = Истина; Результат.ПодключаемыйМодуль = ПодключаемыйМодуль; Возврат Результат; КонецФункции Функция СтрокаВВидеНСтр(Знач ПроверяемаяСтрока) Экспорт ПроверяемаяСтрока = СтрЗаменить(ПроверяемаяСтрока, " ", ""); ВариантыСовпадений = Новый Массив; Для каждого Язык Из Метаданные.Языки Цикл ВариантыСовпадений.Добавить(Язык.КодЯзыка + "="); КонецЦикла; Для каждого ВариантСовпадения Из ВариантыСовпадений Цикл Если СтрНайти(ПроверяемаяСтрока, ВариантСовпадения) > 0 Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции // Устанавливает условное оформление списка выбора // // Параметры: // Форма - ФормаКлиентскогоПриложения - форма, для которой устанавливается оформление. // ИмяЭлемента - Строка - имя элемента, для которого устанавливается оформление. // ИмяПоляКомпоновкиДанных - Строка - имя поля компоновки данных. // Процедура УстановитьУсловноеОформлениеСпискаВыбора(Форма, ИмяЭлемента, ИмяПоляКомпоновкиДанных) Экспорт Элементы = Форма.Элементы; УсловноеОформление = Форма.УсловноеОформление; Для каждого ЭлементВыбора Из Элементы[ИмяЭлемента].СписокВыбора Цикл Элемент = УсловноеОформление.Элементы.Добавить(); ПолеЭлемента = Элемент.Поля.Элементы.Добавить(); ЭлементФормы = Элементы[ИмяЭлемента]; // ПолеФормы ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(ЭлементФормы.Имя); ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных")); ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоляКомпоновкиДанных); ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно; ОтборЭлемента.ПравоеЗначение = ЭлементВыбора.Значение; Элемент.Оформление.УстановитьЗначениеПараметра("Текст", ЭлементВыбора.Представление); КонецЦикла; КонецПроцедуры // Возвращает суффикс текущего языка для мультиязычных реквизитов. // // Возвращаемое значение: // Строка - "Язык1" или "Язык2", если язык пользователя является дополнительным // Пустая строка, если язык пользователя является основным. // Неопределено - мультиязычное хранение данных не используется. // Функция СуффиксЯзыкаТекущегоПользователя() Экспорт Результат = Новый Структура(); Результат.Вставить("СуффиксТекущегоЯзыка", ""); Результат.Вставить("ЭтоОсновнойЯзык", ""); Если ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда МодульМультиязычностьСервер = ОбщийМодуль("МультиязычностьСервер"); СуффиксТекущегоЯзыка = МодульМультиязычностьСервер.СуффиксТекущегоЯзыка(); Если ЗначениеЗаполнено(СуффиксТекущегоЯзыка) Тогда Возврат СуффиксТекущегоЯзыка; КонецЕсли; Иначе СуффиксТекущегоЯзыка = ""; КонецЕсли; Если ЭтоОсновнойЯзык() Тогда Возврат СуффиксТекущегоЯзыка; КонецЕсли; Возврат Неопределено; КонецФункции // Сокращает имя файла с расширением. // Сокращение имени, производится, когда имя файла с расширением превышает размер 255 байт. // Сокращение ими файла достигая за счет сокращения имени файла без расширения и // добавления значения хеш функции сокращенной строки. // // Параметры: // ИмяФайла - Строка - имя файла с расширением // Процедура СократитьИмяФайла(ИмяФайла) Экспорт ОграничениеВБайтах = 255; Если РазмерСтрокиВБайтах(ИмяФайла) <= ОграничениеВБайтах Тогда Возврат; КонецЕсли; Файл = Новый Файл(ИмяФайла); ИмяБезРасширения = Файл.ИмяБезРасширения; ОграничениеВБайтах = ОграничениеВБайтах - РазмерСтрокиВБайтах(Файл.Расширение); ДлинаСтроки = СтрДлина(ИмяБезРасширения); ИспользуемоеКоличествоСимволов = ОграничениеВБайтах - 32; БольшееКоличествоСимволов = Мин(ДлинаСтроки, ОграничениеВБайтах); МеньшееКоличествоСимволов = Цел((ОграничениеВБайтах - 32)/4); Уменьшить = Истина; Пока Истина Цикл Если Уменьшить Тогда ИспользуемоеКоличествоСимволов = МеньшееКоличествоСимволов + Цел((ИспользуемоеКоличествоСимволов-МеньшееКоличествоСимволов)/2); Иначе ИспользуемоеКоличествоСимволов = ИспользуемоеКоличествоСимволов + Цел((БольшееКоличествоСимволов - ИспользуемоеКоличествоСимволов)/2); КонецЕсли; РазмерСтрокиВБайтах = РазмерСтрокиВБайтах(ИмяБезРасширения)+32; Если РазмерСтрокиВБайтах = ОграничениеВБайтах Или БольшееКоличествоСимволов - МеньшееКоличествоСимволов = 1 Тогда Прервать; КонецЕсли; Если РазмерСтрокиВБайтах > ОграничениеВБайтах Тогда Уменьшить = Истина; БольшееКоличествоСимволов = ИспользуемоеКоличествоСимволов; Иначе Уменьшить = Ложь; МеньшееКоличествоСимволов = ИспользуемоеКоличествоСимволов; КонецЕсли; КонецЦикла; СокращеннаяСтрока = СократитьСтрокуКонтрольнойСуммой(ИмяБезРасширения, ИспользуемоеКоличествоСимволов+32); ИмяФайла = СокращеннаяСтрока+Файл.Расширение; КонецПроцедуры // Служебные объекты и объекты при загрузке из резервной копии, // должны записываться без какой-либо прикладной логики. // // Запись служебных объектов без отключения прикладной логики, // может привести к зацикливанию, снижению производительности, // а также избыточным изменениях, которые в некоторых случаях // могут неожиданно повлиять на логику работы. // // Служебными являются объекты, которые обычно не участвуют // в обмене данными, не зависят от других объектов, например: // - кэши; // - даты обновления кэшей и аналогичные признаки; // - промежуточные данные для передачи параметров в фоновые задания; // - вспомогательные служебные данные (например, ключи доступа, // идентификаторы объектов метаданных). // // При использовании подсистемы Управление доступом, требуется // отдельно вызывать процедуру ОтключитьОбновлениеКлючейДоступа // общего модуля УправлениеДоступом. // // Процедура включает режим загрузки данных, // отключает регистрацию объектов на планах обмена, // отключает контроль механизма удаления помеченных объектов. // // Параметры: // Объект - ПланОбменаОбъект // - КонстантаМенеджерЗначения // - СправочникОбъект // - ДокументОбъект // - ПоследовательностьНаборЗаписей // - ПланВидовХарактеристикОбъект // - ПланСчетовОбъект // - ПланВидовРасчетаОбъект // - БизнесПроцессОбъект // - ЗадачаОбъект // - УдалениеОбъекта // - РегистрСведенийНаборЗаписей // - РегистрНакопленияНаборЗаписей // - РегистрБухгалтерииНаборЗаписей // - РегистрРасчетаНаборЗаписей // - ПерерасчетНаборЗаписей // // ЭтоУзелПланаОбмена - Булево // Процедура ОтключитьКонтрольЗаписи(Объект, ЭтоУзелПланаОбмена = Ложь) Экспорт Объект.ДополнительныеСвойства.Вставить("НеВыполнятьКонтрольУдаляемых"); Объект.ДополнительныеСвойства.Вставить("ОтключитьМеханизмРегистрацииОбъектов"); Объект.ОбменДанными.Загрузка = Истина; Если Не ЭтоУзелПланаОбмена Тогда Объект.ОбменДанными.Получатели.АвтоЗаполнение = Ложь; КонецЕсли; КонецПроцедуры #КонецОбласти #Область СлужебныеПроцедурыИФункции #Область ДанныеВБазе #Область ЗначенияРеквизитов // Проверяет существование указанных реквизитов у объекта метаданных. // // Параметры: // ПолноеИмяОбъектаМетаданных - Строка - полное имя проверяемого объекта. // ПроверяемыеВыражения - Массив - имена полей или проверяемые выражения объекта метаданных. // // Возвращаемое значение: // Структура: // * Ошибка - Булево - найдена ошибка. // * ОписаниеОшибки - Строка - описание найденных ошибок. // // Пример: // // Реквизиты = Новый Массив; // Реквизиты.Добавить("Номер"); // Реквизиты.Добавить("Валюта.НаименованиеПолное"); // // Результат = ОбщегоНазначения.ПроверитьСуществованиеРеквизитовОбъекта("Документ._ДемоЗаказПокупателя", Реквизиты); // // Если Результат.Ошибка Тогда // ВызватьИсключение Результат.ОписаниеОшибки; // КонецЕсли; // Функция ПроверитьСуществованиеРеквизитовОбъекта(ПолноеИмяОбъектаМетаданных, ПроверяемыеВыражения) МетаданныеОбъекта = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъектаМетаданных); Если МетаданныеОбъекта = Неопределено Тогда Возврат Новый Структура("Ошибка, ОписаниеОшибки", Истина, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Несуществующий объект метаданных ""%1"".\'"), ПолноеИмяОбъектаМетаданных)); КонецЕсли; // Разрешение вызова из безопасного режима внешней обработки или расширения. // Информация о доступности полей источника схемы при проверке метаданных не является секретной. УстановитьОтключениеБезопасногоРежима(Истина); УстановитьПривилегированныйРежим(Истина); Схема = Новый СхемаЗапроса; Пакет = Схема.ПакетЗапросов.Добавить(Тип("ЗапросВыбораСхемыЗапроса")); Оператор = Пакет.Операторы.Получить(0); Источник = Оператор.Источники.Добавить(ПолноеИмяОбъектаМетаданных, "Таблица"); ТекстОшибки = ""; Для Каждого ТекущееВыражение Из ПроверяемыеВыражения Цикл Если Не ПолеИсточникаСхемыЗапросаДоступно(Источник, ТекущееВыражение) Тогда ТекстОшибки = ТекстОшибки + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Поле объекта ""%1"" не существует.\'"), ТекущееВыражение); КонецЕсли; КонецЦикла; Возврат Новый Структура("Ошибка, ОписаниеОшибки", Не ПустаяСтрока(ТекстОшибки), ТекстОшибки); КонецФункции // Используется в ПроверитьСуществованиеРеквизитовОбъекта. // Выполняет проверку доступности поля проверяемого выражения в источнике оператора схемы запроса. // Функция ПолеИсточникаСхемыЗапросаДоступно(ИсточникОператора, ПроверяемоеВыражение) ЧастиИмениПоля = СтрРазделить(ПроверяемоеВыражение, "."); ДоступныеПоля = ИсточникОператора.Источник.ДоступныеПоля; ТекущаяЧастьИмениПоля = 0; Пока ТекущаяЧастьИмениПоля < ЧастиИмениПоля.Количество() Цикл ТекущееПоле = ДоступныеПоля.Найти(ЧастиИмениПоля.Получить(ТекущаяЧастьИмениПоля)); Если ТекущееПоле = Неопределено Тогда Возврат Ложь; КонецЕсли; // Инкрементация следующей части имени поля и соответствующего списка доступности полей. ТекущаяЧастьИмениПоля = ТекущаяЧастьИмениПоля + 1; ДоступныеПоля = ТекущееПоле.Поля; КонецЦикла; Возврат Истина; КонецФункции #КонецОбласти #Область ЗаменитьСсылки Функция РазметитьМестаИспользования(Знач ПараметрыВыполнения, Знач Ссылка, Знач ЦелеваяСсылка, Знач ТаблицаПоиска) УстановитьПривилегированныйРежим(Истина); // Устанавливаем порядок известных и проверяем наличие неопознанных объектов. Результат = Новый Структура; Результат.Вставить("МестаИспользования", ТаблицаПоиска.НайтиСтроки(Новый Структура("Ссылка", Ссылка))); Результат.Вставить("ОшибкиРазметки", Новый Массив); Результат.Вставить("Успех", Истина); Для Каждого МестоИспользования Из Результат.МестаИспользования Цикл Если МестоИспользования.ЭтоСлужебныеДанные Тогда Продолжить; // Зависимые данные не обрабатываются. КонецЕсли; Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения); Если Информация.Вид = "КОНСТАНТА" Тогда МестоИспользования.КлючЗамены = "Константа"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Вид = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Тогда МестоИспользования.КлючЗамены = "Последовательность"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Вид = "РЕГИСТРСВЕДЕНИЙ" Тогда МестоИспользования.КлючЗамены = "РегистрСведений"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Вид = "РЕГИСТРБУХГАЛТЕРИИ" Или Информация.Вид = "РЕГИСТРНАКОПЛЕНИЯ" Или Информация.Вид = "РЕГИСТРРАСЧЕТА" Тогда МестоИспользования.КлючЗамены = "КлючЗаписи"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; ИначеЕсли Информация.Ссылочный Тогда МестоИспользования.КлючЗамены = "Объект"; МестоИспользования.ЦелеваяСсылка = ЦелеваяСсылка; Иначе // Неизвестный объект для замены ссылок. Результат.Успех = Ложь; Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Замена ссылок в ""%1"" не поддерживается.\'"), Информация.ПолноеИмя); ОписаниеОшибки = Новый Структура("Объект, Текст", МестоИспользования.Данные, Текст); Результат.ОшибкиРазметки.Добавить(ОписаниеОшибки); КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Параметры: // ТаблицаПоиска - см. МестаИспользования // Процедура ЗаменитьСсылкиКороткимиТранзакциями(Результат, Знач ПараметрыВыполнения, Знач Дубль, Знач ТаблицаПоиска) // Основной цикл обработки ФильтрСсылок = Новый Структура("Ссылка, КлючЗамены"); Результат.ЕстьОшибки = Ложь; ФильтрСсылок.Ссылка = Дубль; ФильтрСсылок.КлючЗамены = "Константа"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВКонстанте(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "Объект"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВОбъекте(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "КлючЗаписи"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "Последовательность"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВНаборе(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ФильтрСсылок.КлючЗамены = "РегистрСведений"; МестаИспользования = ТаблицаПоиска.НайтиСтроки(ФильтрСсылок); Для Каждого МестоИспользования Из МестаИспользования Цикл ПроизвестиЗаменуВРегистреСведений(Результат, МестоИспользования, ПараметрыВыполнения); КонецЦикла; ПроизводимыеЗамены = Новый Массив; ПроизводимыеЗамены.Добавить(Дубль); Если ПараметрыВыполнения.УдалятьНепосредственно ИЛИ ПараметрыВыполнения.ПомечатьНаУдаление Тогда УстановитьПометкуУдаленияДляОбъектов(Результат, ПроизводимыеЗамены, ПараметрыВыполнения); Иначе ТаблицаПовторногоПоиска = МестаИспользования(ПроизводимыеЗамены,, ПараметрыВыполнения.ПараметрыПоискаМестИспользования); ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска); КонецЕсли; КонецПроцедуры Процедура ПроизвестиЗаменуВКонстанте(Результат, Знач МестоИспользования, Знач ПараметрыЗаписи) УстановитьПривилегированныйРежим(Истина); Данные = МестоИспользования.Данные; МетаданныеКонстанты = МестоИспользования.Метаданные; ПредставлениеДанных = Строка(Данные); // Будем производить сразу все замены для этих данных. Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Константа"); ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования // Помечаем как обработанные Для Каждого Строка Из ОбрабатываемыеСтроки Цикл Строка.КлючЗамены = ""; КонецЦикла; СостояниеОперации = ""; Ошибка = ""; НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; Блокировка.Добавить(МетаданныеКонстанты.ПолноеИмя()); Попытка Блокировка.Заблокировать(); Исключение Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Не удалось заблокировать константу %1\'"), ПредставлениеДанных); СостояниеОперации = "ОшибкаБлокировки"; ВызватьИсключение; КонецПопытки; МенеджерКонстанты = Константы[МетаданныеКонстанты.Имя].СоздатьМенеджерЗначения(); МенеджерКонстанты.Прочитать(); ЗаменаПроизведена = Ложь; Для Каждого Строка Из ОбрабатываемыеСтроки Цикл Если МенеджерКонстанты.Значение = Строка.Ссылка Тогда МенеджерКонстанты.Значение = Строка.ЦелеваяСсылка; ЗаменаПроизведена = Истина; КонецЕсли; КонецЦикла; Если Не ЗаменаПроизведена Тогда ОтменитьТранзакцию(); Возврат; КонецЕсли; // Пытаемся сохранить Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Попытка ЗаписатьОбъект(МенеджерКонстанты, ПараметрыЗаписи); Исключение ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Не удалось записать %1 по причине: %2\'"), ПредставлениеДанных, ОписаниеОшибки); СостояниеОперации = "ОшибкаЗаписи"; ВызватьИсключение; КонецПопытки; Если Не ПараметрыЗаписи.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Истина); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, МетаданныеКонстанты,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); Если СостояниеОперации = "ОшибкаЗаписи" Тогда Для Каждого Строка Из ОбрабатываемыеСтроки Цикл ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка, ОписаниеОшибкиЗамены("ОшибкаЗаписи", Данные, ПредставлениеДанных, Ошибка)); КонецЦикла; Иначе ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка, ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, Ошибка)); КонецЕсли; КонецПопытки; КонецПроцедуры Процедура ПроизвестиЗаменуВОбъекте(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения) УстановитьПривилегированныйРежим(Истина); Данные = МестоИспользования.Данные; // Будем производить сразу все замены для этих данных. Фильтр = Новый Структура("Данные, КлючЗамены", Данные, "Объект"); ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования ПредставлениеДанных = ПредметСтрокой(Данные); СостояниеОперации = ""; ТекстОшибки = ""; НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования); Попытка Блокировка.Заблокировать(); Исключение СостояниеОперации = "ОшибкаБлокировки"; ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Не удалось заблокировать объект ""%1"": |%2\'"), ПредставлениеДанных, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); ВызватьИсключение; КонецПопытки; ОбъектыЗаписи = ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки); // Пытаемся сохранить, сам объект идет последним. Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Попытка Если ПараметрыВыполнения.ВключатьБизнесЛогику Тогда // Первая запись без контроля, чтобы устранить циклические ссылки. НовыеПараметрыВыполнения = СкопироватьРекурсивно(ПараметрыВыполнения); НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Ложь; Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения); КонецЦикла; // Вторая запись c контролем. НовыеПараметрыВыполнения.ВключатьБизнесЛогику = Истина; Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл ЗаписатьОбъект(КлючЗначение.Ключ, НовыеПараметрыВыполнения); КонецЦикла; Иначе // Запись без контроля бизнес-логики. Для Каждого КлючЗначение Из ОбъектыЗаписи Цикл ЗаписатьОбъект(КлючЗначение.Ключ, ПараметрыВыполнения); КонецЦикла; КонецЕсли; Исключение СостояниеОперации = "ОшибкаЗаписи"; ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Не удалось записать %1 по причине: %2\'"), ПредставлениеДанных, ОписаниеОшибки); ВызватьИсключение; КонецПопытки; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); Информация = ИнформацияОбОшибке(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, МестоИспользования.Метаданные,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация)); Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, ТекстОшибки); Если СостояниеОперации = "ОшибкаЗаписи" Тогда Для Каждого Строка Из ОбрабатываемыеСтроки Цикл ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка, Ошибка); КонецЦикла; Иначе ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка); КонецЕсли; КонецПопытки; // Помечаем как обработанные Для Каждого Строка Из ОбрабатываемыеСтроки Цикл Строка.КлючЗамены = ""; КонецЦикла; КонецПроцедуры Процедура ПроизвестиЗаменуВНаборе(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения) УстановитьПривилегированныйРежим(Истина); Данные = МестоИспользования.Данные; Мета = МестоИспользования.Метаданные; ПредставлениеДанных = Строка(Данные); // Будем производить сразу все замены для этих данных. Фильтр = Новый Структура("Данные, КлючЗамены"); ЗаполнитьЗначенияСвойств(Фильтр, МестоИспользования); ОбрабатываемыеСтроки = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования ОписаниеНабора = ОписаниеКлючаЗаписи(Мета); НаборЗаписей = ОписаниеНабора.НаборЗаписей; // РегистрСведенийНаборЗаписей ПарыЗамен = Новый Соответствие; Для Каждого Строка Из ОбрабатываемыеСтроки Цикл ПарыЗамен.Вставить(Строка.Ссылка, Строка.ЦелеваяСсылка); КонецЦикла; // Помечаем как обработанные Для Каждого Строка Из ОбрабатываемыеСтроки Цикл Строка.КлючЗамены = ""; КонецЦикла; СостояниеОперации = ""; Ошибка = ""; НачатьТранзакцию(); Попытка // Блокировка и подготовка набора. Блокировка = Новый БлокировкаДанных; Для Каждого КлючЗначение Из ОписаниеНабора.СписокИзмерений Цикл ТипИзмерения = КлючЗначение.Значение; Имя = КлючЗначение.Ключ; Значение = Данные[Имя]; Для Каждого Строка Из ОбрабатываемыеСтроки Цикл ТекущаяСсылка = Строка.Ссылка; Если ТипИзмерения.СодержитТип(ТипЗнч(ТекущаяСсылка)) Тогда Блокировка.Добавить(ОписаниеНабора.ПространствоБлокировки).УстановитьЗначение(Имя, ТекущаяСсылка); КонецЕсли; КонецЦикла; НаборЗаписей.Отбор[Имя].Установить(Значение); КонецЦикла; Попытка Блокировка.Заблокировать(); Исключение Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Не удалось заблокировать набор %1\'"), ПредставлениеДанных); СостояниеОперации = "ОшибкаБлокировки"; ВызватьИсключение; КонецПопытки; НаборЗаписей.Прочитать(); ЗаменитьВКоллекцииСтрок("НаборЗаписей", "НаборЗаписей", НаборЗаписей, НаборЗаписей, ОписаниеНабора.СписокПолей, ПарыЗамен); Если НаборЗаписей.Модифицированность() Тогда ОтменитьТранзакцию(); Возврат; КонецЕсли; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Попытка ЗаписатьОбъект(НаборЗаписей, ПараметрыВыполнения); Исключение ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Не удалось записать %1 по причине: %2\'"), ПредставлениеДанных, ОписаниеОшибки); СостояниеОперации = "ОшибкаЗаписи"; ВызватьИсключение; КонецПопытки; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Истина); КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); Информация = ИнформацияОбОшибке(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, Мета,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация)); Ошибка = ОписаниеОшибкиЗамены(СостояниеОперации, Данные, ПредставлениеДанных, Ошибка); Если СостояниеОперации = "ОшибкаЗаписи" Тогда Для Каждого Строка Из ОбрабатываемыеСтроки Цикл ЗарегистрироватьОшибкуЗамены(Результат, Строка.Ссылка, Ошибка); КонецЦикла; Иначе ЗарегистрироватьОшибкуЗамены(Результат, МестоИспользования.Ссылка, Ошибка); КонецЕсли; КонецПопытки; КонецПроцедуры Процедура ПроизвестиЗаменуВРегистреСведений(Результат, Знач МестоИспользования, Знач ПараметрыВыполнения) Если МестоИспользования.Обработано Тогда Возврат; КонецЕсли; МестоИспользования.Обработано = Истина; // В случае, если дубль указан в измерениях набора, тогда используется 2 набора записей: // НаборЗаписейДубля - чтение старых значений (по старым измерениям) и удаление старых значений. // НаборЗаписейОригинала - чтение актуальных значений (по новым измерениям) и запись новых значений. // Данные дублей и оригиналов объединяются по правилам: // Приоритет у данных оригинала. // Если в оригинале нет данных, то берутся данные из дубля. // Набор оригинала записывается, а набор дубля удаляется. // // В случае, если дубль не указан в измерениях набора, тогда используется 1 набор записей: // НаборЗаписейДубля - чтение старых значений и запись новых значений. // // Замена ссылок в ресурсах и реквизитах производится в обоих случаях. УстановитьПривилегированныйРежим(Истина); Дубль = МестоИспользования.Ссылка; Оригинал = МестоИспользования.ЦелеваяСсылка; МетаданныеРегистра = МестоИспользования.Метаданные; КлючЗаписиРегистра = МестоИспользования.Данные; Информация = ИнформацияОТипе(МетаданныеРегистра, ПараметрыВыполнения); ТребуетсяДваНабора = Ложь; Для Каждого КлючЗначение Из Информация.Измерения Цикл ЗначениеИзмеренияДубля = КлючЗаписиРегистра[КлючЗначение.Ключ]; Если ЗначениеИзмеренияДубля = Дубль Или ПараметрыВыполнения.УспешныеЗамены[ЗначениеИзмеренияДубля] = Дубль Тогда ТребуетсяДваНабора = Истина; // Дубль указан в измерениях. Прервать; КонецЕсли; КонецЦикла; Менеджер = МенеджерОбъектаПоПолномуИмени(Информация.ПолноеИмя); НаборЗаписейДубля = Менеджер.СоздатьНаборЗаписей(); Если ТребуетсяДваНабора Тогда ЗначенияИзмеренийОригинала = Новый Структура; НаборЗаписейОригинала = Менеджер.СоздатьНаборЗаписей(); КонецЕсли; НачатьТранзакцию(); Попытка Блокировка = Новый БлокировкаДанных; БлокировкаДубля = Блокировка.Добавить(Информация.ПолноеИмя); Если ТребуетсяДваНабора Тогда БлокировкаОригинала = Блокировка.Добавить(Информация.ПолноеИмя); КонецЕсли; Для Каждого КлючЗначение Из Информация.Измерения Цикл ЗначениеИзмеренияДубля = КлючЗаписиРегистра[КлючЗначение.Ключ]; // Для решения проблемы уникальности // выполняется замена старых значений измерений ключа записи на актуальные. // Соответствие старых и актуальных обеспечивает соответствием УспешныеЗамены. // Данные соответствия актуальны на текущий момент времени, // т.к. пополняются только после успешной обработки очередной пары и фиксации транзакции. НовоеЗначениеИзмеренияДубля = ПараметрыВыполнения.УспешныеЗамены[ЗначениеИзмеренияДубля]; Если НовоеЗначениеИзмеренияДубля <> Неопределено Тогда ЗначениеИзмеренияДубля = НовоеЗначениеИзмеренияДубля; КонецЕсли; НаборЗаписейДубля.Отбор[КлючЗначение.Ключ].Установить(ЗначениеИзмеренияДубля); // Замена в конкретной паре и блокировка на конкретную замену. БлокировкаДубля.УстановитьЗначение(КлючЗначение.Ключ, ЗначениеИзмеренияДубля); Если ТребуетсяДваНабора Тогда Если ЗначениеИзмеренияДубля = Дубль Тогда ЗначениеИзмеренияОригинала = Оригинал; Иначе ЗначениеИзмеренияОригинала = ЗначениеИзмеренияДубля; КонецЕсли; НаборЗаписейОригинала.Отбор[КлючЗначение.Ключ].Установить(ЗначениеИзмеренияОригинала); ЗначенияИзмеренийОригинала.Вставить(КлючЗначение.Ключ, ЗначениеИзмеренияОригинала); // Замена в конкретной паре и блокировка на конкретную замену. БлокировкаОригинала.УстановитьЗначение(КлючЗначение.Ключ, ЗначениеИзмеренияОригинала); КонецЕсли; КонецЦикла; // Установка блокировки. Попытка Блокировка.Заблокировать(); Исключение // Вид ошибки "БлокировкаДляРегистра". ВызватьИсключение; КонецПопытки; // Откуда читаем? НаборЗаписейДубля.Прочитать(); Если НаборЗаписейДубля.Количество() = 0 Тогда // Нечего писать. ОтменитьТранзакцию(); // Замена не требуется. Возврат; КонецЕсли; ЗаписьДубля = НаборЗаписейДубля[0]; // Куда пишем? Если ТребуетсяДваНабора Тогда // Пишем в набор с другими измерениями. НаборЗаписейОригинала.Прочитать(); Если НаборЗаписейОригинала.Количество() = 0 Тогда ЗаписьОригинала = НаборЗаписейОригинала.Добавить(); ЗаполнитьЗначенияСвойств(ЗаписьОригинала, ЗаписьДубля); ЗаполнитьЗначенияСвойств(ЗаписьОригинала, ЗначенияИзмеренийОригинала); Иначе ЗаписьОригинала = НаборЗаписейОригинала[0]; КонецЕсли; Иначе // Пишем туда-же, откуда и читаем. НаборЗаписейОригинала = НаборЗаписейДубля; ЗаписьОригинала = ЗаписьДубля; // Ситуация с нулевым количеством записей в наборе обработана выше. КонецЕсли; // Замена дубля на оригинал в ресурсах и реквизитах. Для Каждого КлючЗначение Из Информация.Ресурсы Цикл ЗначениеРеквизитаВОригинале = ЗаписьОригинала[КлючЗначение.Ключ]; Если ЗначениеРеквизитаВОригинале = Дубль Тогда ЗаписьОригинала[КлючЗначение.Ключ] = Оригинал; КонецЕсли; КонецЦикла; Для Каждого КлючЗначение Из Информация.Реквизиты Цикл ЗначениеРеквизитаВОригинале = ЗаписьОригинала[КлючЗначение.Ключ]; Если ЗначениеРеквизитаВОригинале = Дубль Тогда ЗаписьОригинала[КлючЗначение.Ключ] = Оригинал; КонецЕсли; КонецЦикла; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; // Удаление данных дубля. Если ТребуетсяДваНабора Тогда НаборЗаписейДубля.Очистить(); Попытка ЗаписатьОбъект(НаборЗаписейДубля, ПараметрыВыполнения); Исключение // Вид ошибки "УдалитьНаборДубля". ВызватьИсключение; КонецПопытки; КонецЕсли; // Запись данных оригинала. Если НаборЗаписейОригинала.Модифицированность() Тогда Попытка ЗаписатьОбъект(НаборЗаписейОригинала, ПараметрыВыполнения); Исключение // Вид ошибки "ЗаписатьНаборОригинала". ВызватьИсключение; КонецПопытки; КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); ЗарегистрироватьОшибкуВТаблицу(Результат, Дубль, Оригинал, КлючЗаписиРегистра, Информация, "БлокировкаДляРегистра", ИнформацияОбОшибке()); КонецПопытки КонецПроцедуры Функция ИзмененныеОбъектыПриЗаменеВОбъекте(ПараметрыВыполнения, МестоИспользования, ОбрабатываемыеСтроки) Данные = МестоИспользования.Данные; ОписаниеПоследовательностей = ОписаниеПоследовательностей(МестоИспользования.Метаданные); ОписаниеДвижений = ОписаниеДвижений(МестоИспользования.Метаданные); ОписаниеЗадач = ОписаниеЗадач(МестоИспользования.Метаданные); УстановитьПривилегированныйРежим(Истина); // Возвращаем измененные обработанные объекты. Измененные = Новый Соответствие; // Считываем Описание = ОписаниеОбъекта(Данные.Метаданные()); Попытка Объект = Данные.ПолучитьОбъект(); Исключение // Был уже обработан с ошибками. Объект = Неопределено; КонецПопытки; Если Объект = Неопределено Тогда Возврат Измененные; КонецЕсли; Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл ОписаниеДвижения.НаборЗаписей.Отбор.Регистратор.Установить(Данные); ОписаниеДвижения.НаборЗаписей.Прочитать(); КонецЦикла; Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл ОписаниеПоследовательности.НаборЗаписей.Отбор.Регистратор.Установить(Данные); ОписаниеПоследовательности.НаборЗаписей.Прочитать(); КонецЦикла; // Заменяем сразу все варианты. ПарыЗамен = Новый Соответствие; Для Каждого МестоИспользования Из ОбрабатываемыеСтроки Цикл ПарыЗамен.Вставить(МестоИспользования.Ссылка, МестоИспользования.ЦелеваяСсылка); КонецЦикла; ВыполнитьЗаменуВРеквизитахОбъекта(Объект, Описание, ПарыЗамен); // Движения Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл ЗаменитьВКоллекцииСтрок( "Движения", ОписаниеДвижения.ПространствоБлокировки, ОписаниеДвижения.НаборЗаписей, ОписаниеДвижения.НаборЗаписей, ОписаниеДвижения.СписокПолей, ПарыЗамен); КонецЦикла; // Последовательности Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл ЗаменитьВКоллекцииСтрок( "Последовательности", ОписаниеПоследовательности.ПространствоБлокировки, ОписаниеПоследовательности.НаборЗаписей, ОписаниеПоследовательности.НаборЗаписей, ОписаниеПоследовательности.СписокПолей, ПарыЗамен); КонецЦикла; Для Каждого ОписаниеДвижения Из ОписаниеДвижений Цикл Если ОписаниеДвижения.НаборЗаписей.Модифицированность() Тогда Измененные.Вставить(ОписаниеДвижения.НаборЗаписей, Ложь); КонецЕсли; КонецЦикла; Для Каждого ОписаниеПоследовательности Из ОписаниеПоследовательностей Цикл Если ОписаниеПоследовательности.НаборЗаписей.Модифицированность() Тогда Измененные.Вставить(ОписаниеПоследовательности.НаборЗаписей, Ложь); КонецЕсли; КонецЦикла; Если ОписаниеЗадач <> Неопределено Тогда ЗадачаПроцесса = ЗадачиПроцесса(Данные, ОписаниеЗадач.ПространствоБлокировки); Пока ЗадачаПроцесса.Следующий() Цикл ЗадачаОбъект = ЗадачаПроцесса.Ссылка.ПолучитьОбъект(); Фильтр = Новый Структура("Данные, КлючЗамены", ЗадачаПроцесса.Ссылка, "Объект"); ОбрабатываемыеСтрокиЗадачи = МестоИспользования.Владелец().НайтиСтроки(Фильтр); // см. МестаИспользования Для каждого МестоИспользованияЗадачи Из ОбрабатываемыеСтрокиЗадачи Цикл ПарыЗамен.Вставить(МестоИспользованияЗадачи.Ссылка, МестоИспользованияЗадачи.ЦелеваяСсылка); КонецЦикла; ВыполнитьЗаменуВРеквизитахОбъекта(ЗадачаОбъект, ОписаниеЗадач, ПарыЗамен); Если ЗадачаОбъект.Модифицированность() Тогда Измененные.Вставить(ЗадачаОбъект, Ложь); КонецЕсли; КонецЦикла; КонецЕсли; // Сам объект последний - для возможного перепроведения. Если Объект.Модифицированность() Тогда Измененные.Вставить(Объект, Описание.МожетБытьПроведен); КонецЕсли; Возврат Измененные; КонецФункции Функция ЗадачиПроцесса(БизнесПроцесс, ТипЗадач) ТекстЗапроса = "ВЫБРАТЬ | ИмяТаблицы.Ссылка |ИЗ | &ИмяТаблицы КАК ИмяТаблицы |ГДЕ | ИмяТаблицы.БизнесПроцесс = &БизнесПроцесс"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ТипЗадач); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("БизнесПроцесс", БизнесПроцесс); Возврат Запрос.Выполнить().Выбрать(); КонецФункции Процедура ВыполнитьЗаменуВРеквизитахОбъекта(Объект, Описание, ПарыЗамен) // Реквизиты Для Каждого КлючЗначение Из Описание.Реквизиты Цикл Имя = КлючЗначение.Ключ; ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "Реквизиты", Имя); Объект[Имя] = ЦелеваяСсылка; КонецЕсли; КонецЦикла; // Стандартные реквизиты Для Каждого КлючЗначение Из Описание.СтандартныеРеквизиты Цикл Имя = КлючЗначение.Ключ; ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "СтандартныеРеквизиты", Имя); Объект[Имя] = ЦелеваяСсылка; КонецЕсли; КонецЦикла; // Табличные части Для Каждого Элемент Из Описание.ТабличныеЧасти Цикл ЗаменитьВКоллекцииСтрок( "ТабличныеЧасти", Элемент.Имя, Объект, Объект[Элемент.Имя], Элемент.СписокПолей, ПарыЗамен); КонецЦикла; // Стандартные табличные части. Для Каждого Элемент Из Описание.СтандартныеТабличныеЧасти Цикл ЗаменитьВКоллекцииСтрок( "СтандартныеТабличныеЧасти", Элемент.Имя, Объект, Объект[Элемент.Имя], Элемент.СписокПолей, ПарыЗамен); КонецЦикла; Для Каждого Реквизит Из Описание.РеквизитыАдресации Цикл Имя = Реквизит.Ключ; ЦелеваяСсылка = ПарыЗамен[ Объект[Имя] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Объект[Имя], ЦелеваяСсылка, "РеквизитыАдресации", Имя); Объект[Имя] = ЦелеваяСсылка; КонецЕсли; КонецЦикла; КонецПроцедуры Процедура ЗарегистрироватьФактЗамены(Объект, СсылкаДубля, СсылкаОригинала, ВидРеквизита, ИмяРеквизита, Индекс = Неопределено, ИмяКолонки = Неопределено) ЕстьДополнительныеСвойства = Новый Структура("ДополнительныеСвойства"); ЗаполнитьЗначенияСвойств(ЕстьДополнительныеСвойства, Объект); Если ТипЗнч(ЕстьДополнительныеСвойства.ДополнительныеСвойства) <> Тип("Структура") Тогда Возврат; КонецЕсли; ДополнительныеСвойства = Объект.ДополнительныеСвойства; ДополнительныеСвойства.Вставить("ЗаменаСсылок", Истина); ВыполненныеЗамены = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ДополнительныеСвойства, "ВыполненныеЗамены"); Если ВыполненныеЗамены = Неопределено Тогда ВыполненныеЗамены = Новый Массив; ДополнительныеСвойства.Вставить("ВыполненныеЗамены", ВыполненныеЗамены); КонецЕсли; ОписаниеЗамены = Новый Структура; ОписаниеЗамены.Вставить("СсылкаДубля", СсылкаДубля); ОписаниеЗамены.Вставить("СсылкаОригинала", СсылкаОригинала); ОписаниеЗамены.Вставить("ВидРеквизита", ВидРеквизита); ОписаниеЗамены.Вставить("ИмяРеквизита", ИмяРеквизита); ОписаниеЗамены.Вставить("Индекс", Индекс); ОписаниеЗамены.Вставить("ИмяКолонки", ИмяКолонки); ВыполненныеЗамены.Добавить(ОписаниеЗамены); КонецПроцедуры Процедура УстановитьПометкуУдаленияДляОбъектов(Результат, Знач УдаляемыеСсылки, Знач ПараметрыВыполнения) УстановитьПривилегированныйРежим(Истина); ЕстьВнешняяТранзакция = ТранзакцияАктивна(); ВсеМестаИспользования = МестаИспользования(УдаляемыеСсылки,,ПараметрыВыполнения.ПараметрыПоискаМестИспользования); Для Каждого УдаляемаяСсылка Из УдаляемыеСсылки Цикл Информация = ИнформацияОТипе(ТипЗнч(УдаляемаяСсылка), ПараметрыВыполнения); Блокировка = Новый БлокировкаДанных; Блокировка.Добавить(Информация.ПолноеИмя).УстановитьЗначение("Ссылка", УдаляемаяСсылка); НачатьТранзакцию(); Попытка ЭтоОшибкаБлокировки = Истина; Блокировка.Заблокировать(); ЭтоОшибкаБлокировки = Ложь; Успешно = УстановитьПометкуУдаления(Результат, УдаляемаяСсылка, ВсеМестаИспользования, ПараметрыВыполнения, ЕстьВнешняяТранзакция); Если Не Успешно Тогда ОтменитьТранзакцию(); Продолжить; КонецЕсли; ЗафиксироватьТранзакцию(); Исключение ОтменитьТранзакцию(); Если ЭтоОшибкаБлокировки Тогда ЗарегистрироватьОшибкуВТаблицу(Результат, УдаляемаяСсылка, Неопределено, УдаляемаяСсылка, Информация, "БлокировкаДляУдаленияДубля", ИнформацияОбОшибке()); КонецЕсли; Если ЕстьВнешняяТранзакция Тогда ВызватьИсключение; КонецЕсли; КонецПопытки; КонецЦикла; КонецПроцедуры Функция УстановитьПометкуУдаления(Результат, Знач УдаляемаяСсылка, Знач ВсеМестаИспользования, Знач ПараметрыВыполнения, ЕстьВнешняяТранзакция) УстановитьПривилегированныйРежим(Истина); ПредставлениеСсылки = ПредметСтрокой(УдаляемаяСсылка); Фильтр = Новый Структура("Ссылка"); Фильтр.Ссылка = УдаляемаяСсылка; МестаИспользования = ВсеМестаИспользования.НайтиСтроки(Фильтр); Индекс = МестаИспользования.ВГраница(); Пока Индекс >= 0 Цикл Если МестаИспользования[Индекс].ВспомогательныеДанные Тогда МестаИспользования.Удалить(Индекс); КонецЕсли; Индекс = Индекс - 1; КонецЦикла; Если МестаИспользования.Количество() > 0 Тогда ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, МестаИспользования); Возврат Ложь; // Остались места использования, нельзя удалять. КонецЕсли; Объект = УдаляемаяСсылка.ПолучитьОбъект(); // ДокументОбъект, СправочникОбъект Если Объект = Неопределено Тогда Возврат Ложь; // Уже удален. КонецЕсли; Если Не ПараметрыВыполнения.ПривилегированнаяЗапись Тогда УстановитьПривилегированныйРежим(Ложь); КонецЕсли; Успешно = Истина; Попытка ОбработатьОбъектСПерехватомСообщений(Объект, "ПометкаУдаления", Неопределено, ПараметрыВыполнения); Результат.ОчередьКНепосредственномуУдалению.Добавить(Объект.Ссылка); Исключение ТекстОшибки = НСтр("ru = \'Элемент не был помечен на удаление по причине:\'"); ТекстОшибки = ТекстОшибки + Символы.ПС + СокрЛП(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке())); ОписаниеОшибки = ОписаниеОшибкиЗамены("ОшибкаУдаления", УдаляемаяСсылка, ПредставлениеСсылки, ТекстОшибки); ЗарегистрироватьОшибкуЗамены(Результат, УдаляемаяСсылка, ОписаниеОшибки); Успешно = Ложь; Если ЕстьВнешняяТранзакция Тогда ВызватьИсключение; КонецЕсли; КонецПопытки; Возврат Успешно; КонецФункции Процедура ДобавитьРезультатыЗаменыИзмененныхОбъектов(Результат, ТаблицаПовторногоПоиска) Фильтр = Новый Структура("ТипОшибки, Ссылка, ОбъектОшибки", ""); Для Каждого Строка Из ТаблицаПовторногоПоиска Цикл Тест = Новый Структура("ВспомогательныеДанные", Ложь); ЗаполнитьЗначенияСвойств(Тест, Строка); Если Тест.ВспомогательныеДанные Тогда Продолжить; КонецЕсли; Данные = Строка.Данные; Ссылка = Строка.Ссылка; ПредставлениеДанных = Строка(Данные); Фильтр.ОбъектОшибки = Данные; Фильтр.Ссылка = Ссылка; Если Результат.Ошибки.НайтиСтроки(Фильтр).Количество() > 0 Тогда Продолжить; // По данной проблеме уже записана ошибка. КонецЕсли; ЗарегистрироватьОшибкуЗамены(Результат, Ссылка, ОписаниеОшибкиЗамены("ДанныеИзменены", Данные, ПредставлениеДанных, НСтр("ru = \'Заменены не все места использования. Возможно места использования были добавлены или изменены другим пользователем.\'"))); КонецЦикла; КонецПроцедуры Процедура ЗаблокироватьМестоИспользования(ПараметрыВыполнения, Блокировка, МестоИспользования) Если МестоИспользования.КлючЗамены = "Константа" Тогда Блокировка.Добавить(МестоИспользования.Метаданные.ПолноеИмя()); ИначеЕсли МестоИспользования.КлючЗамены = "Объект" Тогда СсылкаОбъекта = МестоИспользования.Данные; МетаданныеОбъекта = МестоИспользования.Метаданные; // Сам объект. Блокировка.Добавить(МетаданныеОбъекта.ПолноеИмя()).УстановитьЗначение("Ссылка", СсылкаОбъекта); // Движения по регистратору. ОписаниеДвижений = ОписаниеДвижений(МетаданныеОбъекта); Для Каждого Элемент Из ОписаниеДвижений Цикл Блокировка.Добавить(Элемент.ПространствоБлокировки + ".НаборЗаписей").УстановитьЗначение("Регистратор", СсылкаОбъекта); КонецЦикла; // Последовательности. ОписаниеПоследовательностей = ОписаниеПоследовательностей(МетаданныеОбъекта); Для Каждого Элемент Из ОписаниеПоследовательностей Цикл Блокировка.Добавить(Элемент.ПространствоБлокировки).УстановитьЗначение("Регистратор", СсылкаОбъекта); КонецЦикла; // Задачи (для бизнес-процессов) ОписаниеЗадач = ОписаниеЗадач(МетаданныеОбъекта); Если ОписаниеЗадач <> Неопределено Тогда Блокировка.Добавить(ОписаниеЗадач.ПространствоБлокировки).УстановитьЗначение("БизнесПроцесс", СсылкаОбъекта); КонецЕсли; ИначеЕсли МестоИспользования.КлючЗамены = "Последовательность" Тогда СсылкаОбъекта = МестоИспользования.Данные; МетаданныеОбъекта = МестоИспользования.Метаданные; ОписаниеПоследовательностей = ОписаниеПоследовательностей(МетаданныеОбъекта); Для Каждого Элемент Из ОписаниеПоследовательностей Цикл Блокировка.Добавить(Элемент.ПространствоБлокировки).УстановитьЗначение("Регистратор", СсылкаОбъекта); КонецЦикла; ИначеЕсли МестоИспользования.КлючЗамены = "КлючЗаписи" Или МестоИспользования.КлючЗамены = "РегистрСведений" Тогда Информация = ИнформацияОТипе(МестоИспользования.Метаданные, ПараметрыВыполнения); ТипДубля = МестоИспользования.ТипСсылки; ТипОригинала = ТипЗнч(МестоИспользования.ЦелеваяСсылка); Для Каждого КлючЗначение Из Информация.Измерения Цикл ТипИзмерения = КлючЗначение.Значение.Тип; Если ТипИзмерения.СодержитТип(ТипДубля) Тогда БлокировкаПоИзмерению = Блокировка.Добавить(Информация.ПолноеИмя); БлокировкаПоИзмерению.УстановитьЗначение(КлючЗначение.Ключ, МестоИспользования.Ссылка); КонецЕсли; Если ТипИзмерения.СодержитТип(ТипОригинала) Тогда БлокировкаПоИзмерению = Блокировка.Добавить(Информация.ПолноеИмя); БлокировкаПоИзмерению.УстановитьЗначение(КлючЗначение.Ключ, МестоИспользования.ЦелеваяСсылка); КонецЕсли; КонецЦикла; КонецЕсли; КонецПроцедуры Процедура ОтключитьОбновлениеКлючейДоступа(Значение) Если ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда УстановитьПривилегированныйРежим(Истина); МодульУправлениеДоступом = ОбщийМодуль("УправлениеДоступом"); МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Значение); КонецЕсли; КонецПроцедуры // Параметры: // ОбъектМетаданных - ОбъектМетаданных // // Возвращаемое значение: // Массив из Структура: // * СписокПолей - Структура // * СтруктураИзмерений - Структура // * СписокВедущих - Структура // * НаборЗаписей - РегистрСведенийНаборЗаписей // * ПространствоБлокировки - Строка // Функция ОписаниеДвижений(Знач ОбъектМетаданных) ОписаниеДвижений = Новый Массив; Если Не Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда Возврат ОписаниеДвижений; КонецЕсли; Для Каждого Движение Из ОбъектМетаданных.Движения Цикл Если Метаданные.РегистрыНакопления.Содержит(Движение) Тогда НаборЗаписей = РегистрыНакопления[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, НомерСтроки, Период, Регистратор"; ИначеЕсли Метаданные.РегистрыСведений.Содержит(Движение) Тогда НаборЗаписей = РегистрыСведений[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, ВидДвижения, НомерСтроки, Период, Регистратор"; ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(Движение) Тогда НаборЗаписей = РегистрыБухгалтерии[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, ВидДвижения, НомерСтроки, Период, Регистратор"; ИначеЕсли Метаданные.РегистрыРасчета.Содержит(Движение) Тогда НаборЗаписей = РегистрыРасчета[Движение.Имя].СоздатьНаборЗаписей(); ИсключатьПоля = "Активность, БазовыйПериодКонец, БазовыйПериодНачало, НомерСтроки, ПериодДействия, |ПериодДействияКонец, ПериодДействияНачало, ПериодРегистрации, Регистратор, Сторно, |ФактическийПериодДействия"; Иначе // Неизвестный тип Продолжить; КонецЕсли; // Поля ссылочного типа и измерения - кандидаты. // @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы. Описание = СпискиПолейОбъекта(НаборЗаписей, Движение.Измерения, ИсключатьПоля); Если Описание.СписокПолей.Количество() = 0 Тогда // Незачем обрабатывать Продолжить; КонецЕсли; Описание.Вставить("НаборЗаписей", НаборЗаписей); Описание.Вставить("ПространствоБлокировки", Движение.ПолноеИмя() ); ОписаниеДвижений.Добавить(Описание); КонецЦикла; Возврат ОписаниеДвижений; КонецФункции // Параметры: // Мета - ОбъектМетаданных // // Возвращаемое значение: // Массив из Структура: // * НаборЗаписей - ПоследовательностьНаборЗаписей // * ПространствоБлокировки - Строка // * Измерения - Структура // Функция ОписаниеПоследовательностей(Знач Мета) ОписаниеПоследовательностей = Новый Массив; Если Не Метаданные.Документы.Содержит(Мета) Тогда Возврат ОписаниеПоследовательностей; КонецЕсли; Для Каждого Последовательность Из Метаданные.Последовательности Цикл Если Не Последовательность.Документы.Содержит(Мета) Тогда Продолжить; КонецЕсли; ИмяТаблицы = Последовательность.ПолноеИмя(); // @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы. Описание = СпискиПолейОбъекта(ИмяТаблицы, Последовательность.Измерения, "Регистратор"); Если Описание.СписокПолей.Количество() > 0 Тогда Описание.Вставить("НаборЗаписей", Последовательности[Последовательность.Имя].СоздатьНаборЗаписей()); Описание.Вставить("ПространствоБлокировки", ИмяТаблицы + ".Записи"); Описание.Вставить("Измерения", Новый Структура); ОписаниеПоследовательностей.Добавить(Описание); КонецЕсли; КонецЦикла; Возврат ОписаниеПоследовательностей; КонецФункции // Возвращаемое значение: // Структура: // * СтандартныеРеквизиты - Структура // * РеквизитыАдресации - Структура // * Реквизиты - Структура // * СтандартныеТабличныеЧасти - Массив из Структура: // ** Имя - Строка // ** СписокПолей - Структура // * ТабличныеЧасти - Массив из Структура: // ** Имя - Строка // ** СписокПолей - Структура // * МожетБытьПроведен - Булево // Функция ОписаниеОбъекта(Знач ОбъектМетаданных) ТипВсеСсылки = ОписаниеТипаВсеСсылки(); Кандидаты = Новый Структура("Реквизиты, СтандартныеРеквизиты, ТабличныеЧасти, СтандартныеТабличныеЧасти, РеквизитыАдресации"); ЗаполнитьЗначенияСвойств(Кандидаты, ОбъектМетаданных); ОписаниеОбъекта = Новый Структура; ОписаниеОбъекта.Вставить("Реквизиты", Новый Структура); Если Кандидаты.Реквизиты <> Неопределено Тогда Для Каждого МетаРеквизит Из Кандидаты.Реквизиты Цикл Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда ОписаниеОбъекта.Реквизиты.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("СтандартныеРеквизиты", Новый Структура); Если Кандидаты.СтандартныеРеквизиты <> Неопределено Тогда Исключаемые = Новый Структура("Ссылка"); Для Каждого МетаРеквизит Из Кандидаты.СтандартныеРеквизиты Цикл Имя = МетаРеквизит.Имя; Если Не Исключаемые.Свойство(Имя) И ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда ОписаниеОбъекта.Реквизиты.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("ТабличныеЧасти", Новый Массив); Если Кандидаты.ТабличныеЧасти <> Неопределено Тогда Для Каждого МетаТаблица Из Кандидаты.ТабличныеЧасти Цикл СписокПолей = Новый Структура; Для Каждого МетаРеквизит Из МетаТаблица.Реквизиты Цикл Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда СписокПолей.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; Если СписокПолей.Количество() > 0 Тогда ОписаниеОбъекта.ТабличныеЧасти.Добавить(Новый Структура("Имя, СписокПолей", МетаТаблица.Имя, СписокПолей)); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("СтандартныеТабличныеЧасти", Новый Массив); Если Кандидаты.СтандартныеТабличныеЧасти <> Неопределено Тогда Для Каждого МетаТаблица Из Кандидаты.СтандартныеТабличныеЧасти Цикл СписокПолей = Новый Структура; Для Каждого МетаРеквизит Из МетаТаблица.СтандартныеРеквизиты Цикл Если ОписанияТиповПересекаются(МетаРеквизит.Тип, ТипВсеСсылки) Тогда СписокПолей.Вставить(МетаРеквизит.Имя); КонецЕсли; КонецЦикла; Если СписокПолей.Количество() > 0 Тогда ОписаниеОбъекта.СтандартныеТабличныеЧасти.Добавить(Новый Структура("Имя, СписокПолей", МетаТаблица.Имя, СписокПолей)); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("РеквизитыАдресации", Новый Структура); Если Кандидаты.РеквизитыАдресации <> Неопределено Тогда Для Каждого Реквизит Из Кандидаты.РеквизитыАдресации Цикл Если ОписанияТиповПересекаются(Реквизит.Тип, ТипВсеСсылки) Тогда ОписаниеОбъекта.РеквизитыАдресации.Вставить(Реквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ОписаниеОбъекта.Вставить("МожетБытьПроведен", Метаданные.Документы.Содержит(ОбъектМетаданных)); Возврат ОписаниеОбъекта; КонецФункции // Параметры: // ОбъектМетаданных - ОбъектМетаданных // // Возвращаемое значение: // Массив из Структура: // * СписокПолей - Структура // * СтруктураИзмерений - Структура // * СписокВедущих - Структура // * НаборЗаписей - РегистрСведенийНаборЗаписей // * ПространствоБлокировки - Строка // Функция ОписаниеЗадач(Знач Мета) ОписаниеЗадач = Неопределено; Если НЕ Метаданные.БизнесПроцессы.Содержит(Мета) Тогда Возврат ОписаниеЗадач; КонецЕсли; ОписаниеЗадач = ОписаниеОбъекта(Мета.Задача); ОписаниеЗадач.Вставить("ПространствоБлокировки", Мета.Задача.ПолноеИмя()); Возврат ОписаниеЗадач; КонецФункции Функция ОписаниеКлючаЗаписи(Знач МетаданныеТаблицы) ИмяТаблицы = МетаданныеТаблицы.ПолноеИмя(); // Поля ссылочного типа - кандидаты и набор измерений. // @skip-check query-in-loop - Пустой запрос для получения списка полей таблицы. ОписаниеКлюча = СпискиПолейОбъекта(ИмяТаблицы, МетаданныеТаблицы.Измерения, "Период, Регистратор"); Если Метаданные.РегистрыСведений.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыСведений[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.РегистрыНакопления.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыНакопления[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.РегистрыБухгалтерии.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыБухгалтерии[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.РегистрыРасчета.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = РегистрыРасчета[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); ИначеЕсли Метаданные.Последовательности.Содержит(МетаданныеТаблицы) Тогда НаборЗаписей = Последовательности[МетаданныеТаблицы.Имя].СоздатьНаборЗаписей(); Иначе НаборЗаписей = Неопределено; КонецЕсли; ОписаниеКлюча.Вставить("НаборЗаписей", НаборЗаписей); ОписаниеКлюча.Вставить("ПространствоБлокировки", ИмяТаблицы); Возврат ОписаниеКлюча; КонецФункции Функция ОписанияТиповПересекаются(Знач Описание1, Знач Описание2) Для Каждого Тип Из Описание1.Типы() Цикл Если Описание2.СодержитТип(Тип) Тогда Возврат Истина; КонецЕсли; КонецЦикла; Возврат Ложь; КонецФункции // Возвращает описание по имени таблицы или по набору записей. Функция СпискиПолейОбъекта(Знач ИсточникДанных, Знач МетаданныеИзмеренийРегистра, Знач ИсключатьПоля) Описание = Новый Структура; Описание.Вставить("СписокПолей", Новый Структура); Описание.Вставить("СтруктураИзмерений", Новый Структура); Описание.Вставить("СписокВедущих", Новый Структура); ТипКонтроля = ОписаниеТипаВсеСсылки(); Исключаемые = Новый Структура(ИсключатьПоля); ТипИсточникаДанных = ТипЗнч(ИсточникДанных); Если ТипИсточникаДанных = Тип("Строка") Тогда // Источник - имя таблицы, получаем поля запросом. ТекстЗапроса = "ВЫБРАТЬ * ИЗ &ИмяТаблицы ГДЕ ЛОЖЬ"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", ИсточникДанных); Запрос = Новый Запрос(ТекстЗапроса); ИсточникПолей = Запрос.Выполнить(); Иначе // Источник - набор записей ИсточникПолей = ИсточникДанных.ВыгрузитьКолонки(); КонецЕсли; Для Каждого Колонка Из ИсточникПолей.Колонки Цикл Имя = Колонка.Имя; Если Не Исключаемые.Свойство(Имя) И ОписанияТиповПересекаются(Колонка.ТипЗначения, ТипКонтроля) Тогда Описание.СписокПолей.Вставить(Имя); // И проверка на ведущее измерение. Мета = МетаданныеИзмеренийРегистра.Найти(Имя); Если Мета <> Неопределено Тогда Описание.СтруктураИзмерений.Вставить(Имя, Мета.Тип); Тест = Новый Структура("Ведущее", Ложь); ЗаполнитьЗначенияСвойств(Тест, Мета); Если Тест.Ведущее Тогда Описание.СписокВедущих.Вставить(Имя, Мета.Тип); КонецЕсли; КонецЕсли; КонецЕсли; КонецЦикла; Возврат Описание; КонецФункции Процедура ЗаменитьВКоллекцииСтрок(ВидКоллекции, ИмяКоллекции, Объект, Коллекция, Знач СписокПолей, Знач ПарыЗамен) ИзмененнаяКоллекция = Коллекция.Выгрузить(); Модифицировано = Ложь; ИменаИзмененныхРеквизитов = Новый Массив; Для Каждого Строка Из ИзмененнаяКоллекция Цикл Для Каждого КлючЗначение Из СписокПолей Цикл ИмяРеквизита = КлючЗначение.Ключ; ЦелеваяСсылка = ПарыЗамен[ Строка[ИмяРеквизита] ]; Если ЦелеваяСсылка <> Неопределено Тогда ЗарегистрироватьФактЗамены(Объект, Строка[ИмяРеквизита], ЦелеваяСсылка, ВидКоллекции, ИмяКоллекции, ИзмененнаяКоллекция.Индекс(Строка), ИмяРеквизита); Строка[ИмяРеквизита] = ЦелеваяСсылка; Модифицировано = Истина; ИменаИзмененныхРеквизитов.Добавить(ИмяРеквизита); КонецЕсли; КонецЦикла; КонецЦикла; Если Модифицировано Тогда ЭтоРегистрБухгалтерии = ВидКоллекции = "Движения" И ЭтоРегистрБухгалтерии(Коллекция.Метаданные()); Если ЭтоРегистрБухгалтерии Тогда ЗагрузитьИзмененныйНаборВРегистрБухгалтерии(Коллекция, ИзмененнаяКоллекция, ИменаИзмененныхРеквизитов); Иначе Коллекция.Загрузить(ИзмененнаяКоллекция); КонецЕсли; КонецЕсли; КонецПроцедуры Процедура ЗагрузитьИзмененныйНаборВРегистрБухгалтерии(НаборЗаписей, ИзмененнаяКоллекция, ИменаИзмененныхРеквизитов) НеизмененныеИзмерения = Новый Соответствие; ИзмененныеИзмерения = Новый Соответствие; МетаданныеРегистра = НаборЗаписей.Метаданные(); Для каждого Измерение Из МетаданныеРегистра.Измерения Цикл ИменаИзмерений = Новый Массив; Если Измерение.Балансовый ИЛИ НЕ МетаданныеРегистра.Корреспонденция Тогда ИменаИзмерений.Добавить(Измерение.Имя); Иначе ИменаИзмерений.Добавить(Измерение.Имя + "Дт"); ИменаИзмерений.Добавить(Измерение.Имя + "Кт"); КонецЕсли; Для каждого ИмяИзмерения Из ИменаИзмерений Цикл Если ИменаИзмененныхРеквизитов.Найти(ИмяИзмерения) = Неопределено Тогда НеизмененныеИзмерения.Вставить(ИмяИзмерения, НаборЗаписей.ВыгрузитьКолонку(ИмяИзмерения)); Иначе ИзмененныеИзмерения.Вставить(ИмяИзмерения, НаборЗаписей.ВыгрузитьКолонку(ИмяИзмерения)); КонецЕсли; КонецЦикла; КонецЦикла; Для Сч = 0 По НаборЗаписей.Количество()-1 Цикл Для каждого ИмяИзмеренияЗначения Из ИзмененныеИзмерения Цикл Если НаборЗаписей[Сч][ИмяИзмеренияЗначения.Ключ] = NULL Тогда ИмяИзмеренияЗначения.Значение[Сч] = NULL; Иначе ИмяИзмеренияЗначения.Значение[Сч] = ИзмененнаяКоллекция[Сч][ИмяИзмеренияЗначения.Ключ]; КонецЕсли; КонецЦикла; КонецЦикла; НаборЗаписей.Загрузить(ИзмененнаяКоллекция); Для каждого ИзмеренияЗначенияВКолонке Из НеизмененныеИзмерения Цикл НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ); КонецЦикла; Для каждого ИзмеренияЗначенияВКолонке Из ИзмененныеИзмерения Цикл НаборЗаписей.ЗагрузитьКолонку(ИзмеренияЗначенияВКолонке.Значение, ИзмеренияЗначенияВКолонке.Ключ); КонецЦикла; КонецПроцедуры Процедура ОбработатьОбъектСПерехватомСообщений(Знач Объект, Знач Действие, Знач РежимЗаписи, Знач ПараметрыЗаписи) // Текущие сообщения до исключения запоминаем. ПредыдущиеСообщения = ПолучитьСообщенияПользователю(Истина); СообщатьПовторно = ТекущийРежимЗапуска() <> Неопределено; Попытка Если Действие = "Запись" Тогда Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику; Если РежимЗаписи = Неопределено Тогда Объект.Записать(); Иначе Объект.Записать(РежимЗаписи); КонецЕсли; ИначеЕсли Действие = "ПометкаУдаления" Тогда МетаданныеОбъекта = Объект.Метаданные(); Если ЭтоСправочник(МетаданныеОбъекта) Или ЭтоПланВидовХарактеристик(МетаданныеОбъекта) Или ЭтоПланСчетов(МетаданныеОбъекта) Тогда Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику; Объект.УстановитьПометкуУдаления(Истина, Ложь); ИначеЕсли ЭтоДокумент(МетаданныеОбъекта) И МетаданныеОбъекта.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда Объект.УстановитьПометкуУдаления(Истина); Иначе Объект.ОбменДанными.Загрузка = Не ПараметрыЗаписи.ВключатьБизнесЛогику; Объект.УстановитьПометкуУдаления(Истина); КонецЕсли; КонецЕсли; Исключение // Перехватываем все сообщенное при ошибке и добавляем их в одно исключение. ТекстИсключения = ""; Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Ложь) Цикл ТекстИсключения = ТекстИсключения + Символы.ПС + Сообщение.Текст; КонецЦикла; // Сообщаем предыдущие Если СообщатьПовторно Тогда СообщитьОтложенныеСообщения(ПредыдущиеСообщения); КонецЕсли; Если ТекстИсключения = "" Тогда ВызватьИсключение; КонецЕсли; ВызватьИсключение СокрЛП(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()) + Символы.ПС + СокрЛП(ТекстИсключения)); КонецПопытки; Если СообщатьПовторно Тогда СообщитьОтложенныеСообщения(ПредыдущиеСообщения); КонецЕсли; КонецПроцедуры Процедура СообщитьОтложенныеСообщения(Знач Сообщения) Для Каждого Сообщение Из Сообщения Цикл Сообщение.Сообщить(); КонецЦикла; КонецПроцедуры Процедура ЗаписатьОбъект(Знач Объект, Знач ПараметрыЗаписи) МетаданныеОбъекта = Объект.Метаданные(); Если ЭтоДокумент(МетаданныеОбъекта) Тогда ОбработатьОбъектСПерехватомСообщений(Объект, "Запись", РежимЗаписиДокумента.Запись, ПараметрыЗаписи); Возврат; КонецЕсли; // Проверка на возможные циклические ссылки. СвойстваОбъекта = Новый Структура("Иерархический, ВидыСубконто, Владельцы", Ложь, Неопределено, Новый Массив); ЗаполнитьЗначенияСвойств(СвойстваОбъекта, МетаданныеОбъекта); // По родителю Если СвойстваОбъекта.Иерархический Или СвойстваОбъекта.ВидыСубконто <> Неопределено Тогда Если Объект.Родитель = Объект.Ссылка Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'При записи ""%1"" возникает циклическая ссылка в иерархии.\'"), Строка(Объект)); КонецЕсли; КонецЕсли; // По владельцу Если СвойстваОбъекта.Владельцы.Количество() > 1 И Объект.Владелец = Объект.Ссылка Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'При записи ""%1"" возникает циклическая ссылка в подчинении.\'"), Строка(Объект)); КонецЕсли; // Для последовательностей право "Изменение" может отсутствовать даже у роли "АдминистраторСистемы". Если ЭтоПоследовательность(МетаданныеОбъекта) И Не ПравоДоступа("Изменение", МетаданныеОбъекта) И Пользователи.ЭтоПолноправныйПользователь(,, Ложь) Тогда УстановитьПривилегированныйРежим(Истина); КонецЕсли; // Просто запись ОбработатьОбъектСПерехватомСообщений(Объект, "Запись", Неопределено, ПараметрыЗаписи); КонецПроцедуры Функция СобытиеЖурналаРегистрацииЗаменыСсылок() Возврат НСтр("ru = \'Поиск и удаление ссылок\'", КодОсновногоЯзыка()); КонецФункции // Параметры: // Результат - см. РезультатЗаменыСсылок // Ссылка - ЛюбаяСсылка // ОписаниеОшибки - см. ОписаниеОшибкиЗамены // Процедура ЗарегистрироватьОшибкуЗамены(Результат, Знач Ссылка, Знач ОписаниеОшибки) Результат.ЕстьОшибки = Истина; Строка = Результат.Ошибки.Добавить(); Строка.Ссылка = Ссылка; Строка.ПредставлениеОбъектаОшибки = ОписаниеОшибки.ПредставлениеОбъектаОшибки; Строка.ОбъектОшибки = ОписаниеОшибки.ОбъектОшибки; Строка.ТекстОшибки = ОписаниеОшибки.ТекстОшибки; Строка.ТипОшибки = ОписаниеОшибки.ТипОшибки; КонецПроцедуры // Возвращаемое значение: // Структура: // * ТипОшибки - Строка // * ОбъектОшибки - ЛюбаяСсылка // * ПредставлениеОбъектаОшибки - Строка // * ТекстОшибки - Строка // Функция ОписаниеОшибкиЗамены(Знач ТипОшибки, Знач ОбъектОшибки, Знач ПредставлениеОбъектаОшибки, Знач ТекстОшибки) Результат = Новый Структура; Результат.Вставить("ТипОшибки", ТипОшибки); Результат.Вставить("ОбъектОшибки", ОбъектОшибки); Результат.Вставить("ПредставлениеОбъектаОшибки", ПредставлениеОбъектаОшибки); Результат.Вставить("ТекстОшибки", ТекстОшибки); Возврат Результат; КонецФункции // Возвращаемое значение: // Структура: // * ЕстьОшибки - Булево // * ОчередьКНепосредственномуУдалению - Массив // * Ошибки - см. ОбщегоНазначения.ЗаменитьСсылки // Функция РезультатЗаменыСсылок(Знач ОшибкиЗамены) Результат = Новый Структура; Результат.Вставить("ЕстьОшибки", Ложь); Результат.Вставить("ОчередьКНепосредственномуУдалению", Новый Массив); Результат.Вставить("Ошибки", ОшибкиЗамены); Возврат Результат КонецФункции Процедура ЗарегистрироватьОшибкуВТаблицу(Результат, Дубль, Оригинал, Данные, Информация, ТипОшибки, ИнформацияОбОшибке) Результат.ЕстьОшибки = Истина; ЗаписьЖурналаРегистрации( СобытиеЖурналаРегистрацииЗаменыСсылок(), УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)); ПолноеПредставлениеДанных = Строка(Данные) + " (" + Информация.ПредставлениеЭлемента + ")"; Ошибка = Результат.Ошибки.Добавить(); Ошибка.Ссылка = Дубль; Ошибка.ОбъектОшибки = Данные; Ошибка.ПредставлениеОбъектаОшибки = ПолноеПредставлениеДанных; Если ТипОшибки = "БлокировкаДляРегистра" Тогда НовыйШаблон = НСтр("ru = \'Не удалось начать редактирование %1: %2\'"); Ошибка.ТипОшибки = "ОшибкаБлокировки"; ИначеЕсли ТипОшибки = "БлокировкаДляУдаленияДубля" Тогда НовыйШаблон = НСтр("ru = \'Не удалось начать удаление: %2\'"); Ошибка.ТипОшибки = "ОшибкаБлокировки"; ИначеЕсли ТипОшибки = "УдалитьНаборДубля" Тогда НовыйШаблон = НСтр("ru = \'Не удалось очистить сведения о дубле в %1: %2\'"); Ошибка.ТипОшибки = "ОшибкаЗаписи"; ИначеЕсли ТипОшибки = "ЗаписатьНаборОригинала" Тогда НовыйШаблон = НСтр("ru = \'Не удалось обновить сведения в %1: %2\'"); Ошибка.ТипОшибки = "ОшибкаЗаписи"; Иначе НовыйШаблон = ТипОшибки + " (%1): %2"; Ошибка.ТипОшибки = ТипОшибки; КонецЕсли; НовыйШаблон = НовыйШаблон + Символы.ПС + Символы.ПС + НСтр("ru = \'Подробности в журнале регистрации.\'"); КраткоеПредставление = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке); Ошибка.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НовыйШаблон, ПолноеПредставлениеДанных, КраткоеПредставление); КонецПроцедуры // Формирует информацию о типе объекта метаданных: полное имя, представления, вид и т.п. Функция ИнформацияОТипе(ПолноеИмяИлиМетаданныеИлиТип, Кэш) ТипПервогоПараметра = ТипЗнч(ПолноеИмяИлиМетаданныеИлиТип); Если ТипПервогоПараметра = Тип("Строка") Тогда ОбъектМетаданных = ОбъектМетаданныхПоПолномуИмени(ПолноеИмяИлиМетаданныеИлиТип); Иначе Если ТипПервогоПараметра = Тип("Тип") Тогда // Поиск объекта метаданных. ОбъектМетаданных = Метаданные.НайтиПоТипу(ПолноеИмяИлиМетаданныеИлиТип); Иначе ОбъектМетаданных = ПолноеИмяИлиМетаданныеИлиТип; КонецЕсли; КонецЕсли; ПолноеИмя = ВРег(ОбъектМетаданных.ПолноеИмя()); ИнформацияОТипах = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Кэш, "ИнформацияОТипах"); Если ИнформацияОТипах = Неопределено Тогда ИнформацияОТипах = Новый Соответствие; Кэш.Вставить("ИнформацияОТипах", ИнформацияОТипах); Иначе Информация = ИнформацияОТипах.Получить(ПолноеИмя); Если Информация <> Неопределено Тогда Возврат Информация; КонецЕсли; КонецЕсли; Информация = Новый Структура("ПолноеИмя, ПредставлениеЭлемента, |Вид, Ссылочный, Технический, Разделенный, |Иерархический, |ЕстьПодчиненные, ИменаПодчиненных, |Измерения, Реквизиты, Ресурсы"); ИнформацияОТипах.Вставить(ПолноеИмя, Информация); // Заполнение базовой информации. Информация.ПолноеИмя = ПолноеИмя; // Представление элемента. Информация.ПредставлениеЭлемента = ПредставлениеОбъекта(ОбъектМетаданных); // Вид и его свойства. Информация.Вид = Лев(Информация.ПолноеИмя, СтрНайти(Информация.ПолноеИмя, ".")-1); Если Информация.Вид = "СПРАВОЧНИК" Или Информация.Вид = "ДОКУМЕНТ" Или Информация.Вид = "ПЕРЕЧИСЛЕНИЕ" Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Или Информация.Вид = "ПЛАНСЧЕТОВ" Или Информация.Вид = "ПЛАНВИДОВРАСЧЕТА" Или Информация.Вид = "БИЗНЕСПРОЦЕСС" Или Информация.Вид = "ЗАДАЧА" Или Информация.Вид = "ПЛАНОБМЕНА" Тогда Информация.Ссылочный = Истина; Иначе Информация.Ссылочный = Ложь; КонецЕсли; Если Информация.Вид = "СПРАВОЧНИК" Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Тогда Информация.Иерархический = ОбъектМетаданных.Иерархический; ИначеЕсли Информация.Вид = "ПЛАНСЧЕТОВ" Тогда Информация.Иерархический = Истина; Иначе Информация.Иерархический = Ложь; КонецЕсли; Информация.ЕстьПодчиненные = Ложь; Если Информация.Вид = "СПРАВОЧНИК" Или Информация.Вид = "ПЛАНВИДОВХАРАКТЕРИСТИК" Или Информация.Вид = "ПЛАНОБМЕНА" Или Информация.Вид = "ПЛАНСЧЕТОВ" Или Информация.Вид = "ПЛАНВИДОВРАСЧЕТА" Тогда Для Каждого Справочник Из Метаданные.Справочники Цикл Если Справочник.Владельцы.Содержит(ОбъектМетаданных) Тогда Если Информация.ЕстьПодчиненные = Ложь Тогда Информация.ЕстьПодчиненные = Истина; Информация.ИменаПодчиненных = Новый Массив; КонецЕсли; ИменаПодчиненных = Информация.ИменаПодчиненных; // Массив - ИменаПодчиненных.Добавить(Справочник.ПолноеИмя()); КонецЕсли; КонецЦикла; КонецЕсли; Если Информация.ПолноеИмя = "СПРАВОЧНИК.ИДЕНТИФИКАТОРЫОБЪЕКТОВМЕТАДАННЫХ" Или Информация.ПолноеИмя = "СПРАВОЧНИК.ПРЕДОПРЕДЕЛЕННЫЕВАРИАНТЫОТЧЕТОВ" Тогда Информация.Технический = Истина; Информация.Разделенный = Ложь; Иначе Информация.Технический = Ложь; Если Не Кэш.Свойство("МодельСервиса") Тогда Кэш.Вставить("МодельСервиса", РазделениеВключено()); Если Кэш.МодельСервиса Тогда Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); РазделительОсновныхДанных = МодульРаботаВМоделиСервиса.РазделительОсновныхДанных(); РазделительВспомогательныхДанных = МодульРаботаВМоделиСервиса.РазделительВспомогательныхДанных(); Иначе РазделительОсновныхДанных = Неопределено; РазделительВспомогательныхДанных = Неопределено; КонецЕсли; Кэш.Вставить("ВОбластиДанных", РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных()); Кэш.Вставить("РазделительОсновныхДанных", РазделительОсновныхДанных); Кэш.Вставить("РазделительВспомогательныхДанных", РазделительВспомогательныхДанных); КонецЕсли; КонецЕсли; Если Кэш.МодельСервиса Тогда Если ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда МодульРаботаВМоделиСервиса = ОбщийМодуль("РаботаВМоделиСервиса"); ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(ОбъектМетаданных); Иначе ЭтоРазделенныйОбъектМетаданных = Истина; КонецЕсли; Информация.Разделенный = ЭтоРазделенныйОбъектМетаданных; КонецЕсли; КонецЕсли; Информация.Измерения = Новый Структура; Информация.Реквизиты = Новый Структура; Информация.Ресурсы = Новый Структура; ВидыРеквизитов = Новый Структура("СтандартныеРеквизиты, Реквизиты, Измерения, Ресурсы"); ЗаполнитьЗначенияСвойств(ВидыРеквизитов, ОбъектМетаданных); Для Каждого КлючИЗначение Из ВидыРеквизитов Цикл Коллекция = КлючИЗначение.Значение; // КоллекцияОбъектовМетаданных Если ТипЗнч(Коллекция) = Тип("КоллекцияОбъектовМетаданных") Тогда КудаПишем = ?(Информация.Свойство(КлючИЗначение.Ключ), Информация[КлючИЗначение.Ключ], Информация.Реквизиты); Для Каждого Реквизит Из Коллекция Цикл КудаПишем.Вставить(Реквизит.Имя, ИнформацияПоРеквизиту(Реквизит)); КонецЦикла; КонецЕсли; КонецЦикла; Если Информация.Вид = "РЕГИСТРСВЕДЕНИЙ" И ОбъектМетаданных.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда ИнформацияПоРеквизиту = Новый Структура("Ведущее, Представление, Формат, Тип, ЗначениеПоУмолчанию, ЗаполнятьИзДанныхЗаполнения"); ИнформацияПоРеквизиту.Ведущее = Ложь; ИнформацияПоРеквизиту.ЗаполнятьИзДанныхЗаполнения = Ложь; Если ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.ПозицияРегистратора Тогда ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("МоментВремени"); ИначеЕсли ОбъектМетаданных.ПериодичностьРегистраСведений = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Секунда Тогда ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)); Иначе ИнформацияПоРеквизиту.Тип = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)); КонецЕсли; Информация.Измерения.Вставить("Период", ИнформацияПоРеквизиту); КонецЕсли; Возврат Информация; КонецФункции // Параметры: // МетаданныеРеквизита - ОбъектМетаданныхРеквизит // Функция ИнформацияПоРеквизиту(МетаданныеРеквизита) // ОписаниеСтандартногоРеквизита // ОбъектМетаданных: Измерение // ОбъектМетаданных: Ресурс // ОбъектМетаданных: Реквизит Информация = Новый Структура("Ведущее, Представление, Формат, Тип, ЗначениеПоУмолчанию, ЗаполнятьИзДанныхЗаполнения"); ЗаполнитьЗначенияСвойств(Информация, МетаданныеРеквизита); Информация.Представление = МетаданныеРеквизита.Представление(); Если Информация.ЗаполнятьИзДанныхЗаполнения = Истина Тогда Информация.ЗначениеПоУмолчанию = МетаданныеРеквизита.ЗначениеЗаполнения; Иначе Информация.ЗначениеПоУмолчанию = МетаданныеРеквизита.Тип.ПривестиЗначение(); КонецЕсли; Возврат Информация; КонецФункции Процедура ДобавитьВСтатистикуЗаменыСсылок(Статистика, Дубль, ЕстьОшибки) КлючДубля = Дубль.Метаданные().ПолноеИмя(); ЭлементСтатистики = Статистика[КлючДубля]; Если ЭлементСтатистики = Неопределено Тогда ЭлементСтатистики = Новый Структура("КоличествоЭлементов, КоличествоОшибок",0,0); Статистика.Вставить(КлючДубля, ЭлементСтатистики); КонецЕсли; ЭлементСтатистики.КоличествоЭлементов = ЭлементСтатистики.КоличествоЭлементов + 1; ЭлементСтатистики.КоличествоОшибок = ЭлементСтатистики.КоличествоОшибок + ?(ЕстьОшибки, 1,0); КонецПроцедуры Процедура ОтправитьСтатистикуЗаменыСсылок(Статистика) Если НЕ ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда Возврат; КонецЕсли; МодульЦентрМониторинга = ОбщийМодуль("ЦентрМониторинга"); Для каждого ЭлементСтатистики Из Статистика Цикл МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики( "БазоваяФункциональность.ЗаменаСсылок." + ЭлементСтатистики.Ключ, ЭлементСтатистики.Значение.КоличествоЭлементов); МодульЦентрМониторинга.ЗаписатьОперациюБизнесСтатистики( "БазоваяФункциональность.ЗаменаСсылокКоличествоОшибок." + ЭлементСтатистики.Ключ, ЭлементСтатистики.Значение.КоличествоОшибок); КонецЦикла; КонецПроцедуры Процедура ДополнитьИсключенияПоискаСсылокПодчиненнымиОбъектами(Знач ИсключенияПоискаСсылок) Для каждого ОписаниеПодчиненногоОбъекта Из ПодчиненныеОбъекты() Цикл ПоляСвязи = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок( ОписаниеПодчиненногоОбъекта.ПоляСвязей, ",",, Истина); ЗначениеИсключенияПоискаСсылок = Новый Массив; Для каждого ПолеСвязи Из ПоляСвязи Цикл ЗначениеИсключенияПоискаСсылок.Добавить(ПолеСвязи); КонецЦикла; ИсключенияПоискаСсылок.Вставить(ОписаниеПодчиненногоОбъекта.ПодчиненныйОбъект, ЗначениеИсключенияПоискаСсылок); КонецЦикла; КонецПроцедуры Процедура ЗарегистрироватьОшибкиУдаления(Результат, ПрепятствующиеУдалению) ПредставленияСсылок = ПредметыСтрокой(ПрепятствующиеУдалению.ВыгрузитьКолонку("МестоИспользования")); Для каждого ПрепятствующиеУдалению Из ПрепятствующиеУдалению Цикл ТекстОшибки = НСтр("ru = \'Элемент не удален, т.к. на него есть ссылки\'"); ОписаниеОшибки = ОписаниеОшибкиЗамены("ОшибкаУдаления", ПрепятствующиеУдалению.МестоИспользования, ПредставленияСсылок[ПрепятствующиеУдалению.МестоИспользования], ТекстОшибки); ЗарегистрироватьОшибкуЗамены(Результат, ПрепятствующиеУдалению.УдаляемыйСсылка, ОписаниеОшибки); КонецЦикла; КонецПроцедуры Функция СформироватьДубли(ПараметрыВыполнения, ПараметрыЗамены, ПарыЗамен, Результат) Дубли = Новый Массив; Для Каждого КлючЗначение Из ПарыЗамен Цикл Дубль = КлючЗначение.Ключ; Оригинал = КлючЗначение.Значение; Если Дубль = Оригинал Или Дубль.Пустая() Тогда Продолжить; // Самого на себя и пустые ссылки не заменяем. КонецЕсли; Дубли.Добавить(Дубль); // Пропускаем промежуточные замены, чтобы не строить граф (если A->B и B->C то вместо A->B производится замена A->C). ОригиналОригинала = ПарыЗамен[Оригинал]; ЕстьОригиналОригинала = (ОригиналОригинала <> Неопределено И ОригиналОригинала <> Дубль И ОригиналОригинала <> Оригинал); Если ЕстьОригиналОригинала Тогда Пока ЕстьОригиналОригинала Цикл Оригинал = ОригиналОригинала; ОригиналОригинала = ПарыЗамен[Оригинал]; ЕстьОригиналОригинала = (ОригиналОригинала <> Неопределено И ОригиналОригинала <> Дубль И ОригиналОригинала <> Оригинал); КонецЦикла; ПарыЗамен.Вставить(Дубль, Оригинал); КонецЕсли; КонецЦикла; Если ПараметрыВыполнения.УчитыватьПрикладныеПравила И ПодсистемаСуществует("СтандартныеПодсистемы.ПоискИУдалениеДублей") Тогда МодульПоискИУдалениеДублей = ОбщийМодуль("ПоискИУдалениеДублей"); Ошибки = МодульПоискИУдалениеДублей.ПроверитьВозможностьЗаменыЭлементов(ПарыЗамен, ПараметрыЗамены); ОригиналыОбъектов = Новый Массив; Для Каждого КлючЗначение Из Ошибки Цикл Дубль = КлючЗначение.Ключ; ОригиналыОбъектов.Добавить(ПарыЗамен[Дубль]); Индекс = Дубли.Найти(Дубль); Если Индекс <> Неопределено Тогда Дубли.Удалить(Индекс); // пропускаем проблемный элемент. КонецЕсли; КонецЦикла; ПредставленияОбъектов = ПредметыСтрокой(ОригиналыОбъектов); Для Каждого КлючЗначение Из Ошибки Цикл Дубль = КлючЗначение.Ключ; Оригинал = ПарыЗамен[Дубль]; ТекстОшибки = КлючЗначение.Значение; Причина = ОписаниеОшибкиЗамены("ОшибкаЗаписи", Оригинал, ПредставленияОбъектов[Оригинал], ТекстОшибки); ЗарегистрироватьОшибкуЗамены(Результат, Дубль, Причина); КонецЦикла; КонецЕсли; Возврат Дубли; КонецФункции Функция НовыйПараметрыВыполненияЗаменыСсылок(Знач ПараметрыЗамены) ПараметрыПоУмолчанию = ПараметрыЗаменыСсылок(); ПараметрыВыполнения = Новый Структура; ПараметрыВыполнения.Вставить("УдалятьНепосредственно", ПараметрыПоУмолчанию.СпособУдаления = "Непосредственно"); ПараметрыВыполнения.Вставить("ПомечатьНаУдаление", ПараметрыПоУмолчанию.СпособУдаления = "Пометка"); ПараметрыВыполнения.Вставить("ВключатьБизнесЛогику", ПараметрыПоУмолчанию.ВключатьБизнесЛогику); ПараметрыВыполнения.Вставить("ПривилегированнаяЗапись", ПараметрыПоУмолчанию.ПривилегированнаяЗапись); ПараметрыВыполнения.Вставить("УчитыватьПрикладныеПравила", ПараметрыПоУмолчанию.УчитыватьПрикладныеПравила); ПараметрыВыполнения.Вставить("МестаЗамены", Новый Массив); // Переданные параметры обрабатываются условно для обратной совместимости. ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "СпособУдаления"); Если ЗначениеПараметра = "Непосредственно" Тогда ПараметрыВыполнения.УдалятьНепосредственно = Истина; ПараметрыВыполнения.ПомечатьНаУдаление = Ложь; ИначеЕсли ЗначениеПараметра = "Пометка" Тогда ПараметрыВыполнения.УдалятьНепосредственно = Ложь; ПараметрыВыполнения.ПомечатьНаУдаление = Истина; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "ВключатьБизнесЛогику"); Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда ПараметрыВыполнения.ВключатьБизнесЛогику = ЗначениеПараметра; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "ПривилегированнаяЗапись"); Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда ПараметрыВыполнения.ПривилегированнаяЗапись = ЗначениеПараметра; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "УчитыватьПрикладныеПравила"); Если ТипЗнч(ЗначениеПараметра) = Тип("Булево") Тогда ПараметрыВыполнения.УчитыватьПрикладныеПравила = ЗначениеПараметра; КонецЕсли; ЗначениеПараметра = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗамены, "МестаЗамены", Новый Массив); Если (ЗначениеПараметра.Количество() > 0) Тогда ПараметрыВыполнения.МестаЗамены = Новый Массив(Новый ФиксированныйМассив(ЗначениеПараметра)); КонецЕсли; Возврат ПараметрыВыполнения; КонецФункции #КонецОбласти #Область МестаИспользования Функция ОписаниеТипаКлючиЗаписей() ДобавляемыеТипы = Новый Массив; Для Каждого Мета Из Метаданные.РегистрыСведений Цикл ДобавляемыеТипы.Добавить(Тип("РегистрСведенийКлючЗаписи." + Мета.Имя)); КонецЦикла; Для Каждого Мета Из Метаданные.РегистрыНакопления Цикл ДобавляемыеТипы.Добавить(Тип("РегистрНакопленияКлючЗаписи." + Мета.Имя)); КонецЦикла; Для Каждого Мета Из Метаданные.РегистрыБухгалтерии Цикл ДобавляемыеТипы.Добавить(Тип("РегистрБухгалтерииКлючЗаписи." + Мета.Имя)); КонецЦикла; Для Каждого Мета Из Метаданные.РегистрыРасчета Цикл ДобавляемыеТипы.Добавить(Тип("РегистрРасчетаКлючЗаписи." + Мета.Имя)); КонецЦикла; Возврат Новый ОписаниеТипов(ДобавляемыеТипы); КонецФункции Функция ОписаниеИзмеренийНабора(Знач МетаданныеРегистра, КэшИзмеренийРегистров) ОписаниеИзмерений = КэшИзмеренийРегистров[МетаданныеРегистра]; Если ОписаниеИзмерений <> Неопределено Тогда Возврат ОписаниеИзмерений; КонецЕсли; // Период и регистратор, если есть. ОписаниеИзмерений = Новый Структура; ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип", Ложь); Если Метаданные.РегистрыСведений.Содержит(МетаданныеРегистра) Тогда // Возможно есть период МетаПериод = МетаданныеРегистра.ПериодичностьРегистраСведений; Периодичность = Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений; Если МетаПериод = Периодичность.ПозицияРегистратора Тогда ДанныеИзмерения.Тип = Документы.ТипВсеСсылки(); ДанныеИзмерения.Представление = НСтр("ru = \'Регистратор\'"); ДанныеИзмерения.Ведущее = Истина; ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Год Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = \'Период\'"); ДанныеИзмерения.Формат = НСтр("ru = \'ДФ=\'\'yyyy ""г.""\'\'; ДП=\'\'Дата не задана\'\'\'"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.День Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = \'Период\'"); ДанныеИзмерения.Формат = НСтр("ru = \'ДЛФ=D; ДП=\'\'Дата не задана\'\'\'"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Квартал Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = \'Период\'"); ДанныеИзмерения.Формат = НСтр("ru = \'ДФ=\'\'к """"квартал """"yyyy """"г.""""\'\'; ДП=\'\'Дата не задана\'\'\'"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Месяц Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = \'Период\'"); ДанныеИзмерения.Формат = НСтр("ru = \'ДФ=\'\'ММММ yyyy """"г.""""\'\'; ДП=\'\'Дата не задана\'\'\'"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); ИначеЕсли МетаПериод = Периодичность.Секунда Тогда ДанныеИзмерения.Тип = Новый ОписаниеТипов("Дата"); ДанныеИзмерения.Представление = НСтр("ru = \'Период\'"); ДанныеИзмерения.Формат = НСтр("ru = \'ДЛФ=DT; ДП=\'\'Дата не задана\'\'\'"); ОписаниеИзмерений.Вставить("Период", ДанныеИзмерения); КонецЕсли; Иначе ДанныеИзмерения.Тип = Документы.ТипВсеСсылки(); ДанныеИзмерения.Представление = НСтр("ru = \'Регистратор\'"); ДанныеИзмерения.Ведущее = Истина; ОписаниеИзмерений.Вставить("Регистратор", ДанныеИзмерения); КонецЕсли; // Все измерения Для Каждого МетаИзмерение Из МетаданныеРегистра.Измерения Цикл ДанныеИзмерения = Новый Структура("Ведущее, Представление, Формат, Тип"); ДанныеИзмерения.Тип = МетаИзмерение.Тип; ДанныеИзмерения.Представление = МетаИзмерение.Представление(); ДанныеИзмерения.Ведущее = МетаИзмерение.Ведущее; ОписаниеИзмерений.Вставить(МетаИзмерение.Имя, ДанныеИзмерения); КонецЦикла; КэшИзмеренийРегистров[МетаданныеРегистра] = ОписаниеИзмерений; Возврат ОписаниеИзмерений; КонецФункции #КонецОбласти #КонецОбласти #Область УсловныеВызовы // Возвращает серверный модуль менеджера по имени объекта. Функция СерверныйМодульМенеджера(Имя) ОбъектНайден = Ложь; ЧастиИмени = СтрРазделить(Имя, "."); Если ЧастиИмени.Количество() = 2 Тогда ИмяВида = ВРег(ЧастиИмени[0]); ИмяОбъекта = ЧастиИмени[1]; Если ИмяВида = ВРег("Константы") Тогда Если Метаданные.Константы.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("РегистрыСведений") Тогда Если Метаданные.РегистрыСведений.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("РегистрыНакопления") Тогда Если Метаданные.РегистрыНакопления.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("РегистрыБухгалтерии") Тогда Если Метаданные.РегистрыБухгалтерии.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("РегистрыРасчета") Тогда Если Метаданные.РегистрыРасчета.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("Справочники") Тогда Если Метаданные.Справочники.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("Документы") Тогда Если Метаданные.Документы.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("Отчеты") Тогда Если Метаданные.Отчеты.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("Обработки") Тогда Если Метаданные.Обработки.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("БизнесПроцессы") Тогда Если Метаданные.БизнесПроцессы.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("ЖурналыДокументов") Тогда Если Метаданные.ЖурналыДокументов.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("Задачи") Тогда Если Метаданные.Задачи.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("ПланыСчетов") Тогда Если Метаданные.ПланыСчетов.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("ПланыОбмена") Тогда Если Метаданные.ПланыОбмена.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("ПланыВидовХарактеристик") Тогда Если Метаданные.ПланыВидовХарактеристик.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; ИначеЕсли ИмяВида = ВРег("ПланыВидовРасчета") Тогда Если Метаданные.ПланыВидовРасчета.Найти(ИмяОбъекта) <> Неопределено Тогда ОбъектНайден = Истина; КонецЕсли; КонецЕсли; КонецЕсли; Если Не ОбъектНайден Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Объект метаданных ""%1"" не существует.\'"), Имя); КонецЕсли; // АПК:488-выкл ВычислитьВБезопасномРежиме не используется, чтобы избежать вызова ОбщийМодуль рекурсивно. УстановитьБезопасныйРежим(Истина); Модуль = Вычислить(Имя); // АПК:488-вкл Возврат Модуль; КонецФункции #КонецОбласти #Область Данные Функция СравниваемыеКолонки(Знач КоллекцияСтрок, Знач ИменаКолонок, Знач ИсключаяКолонки) Если ПустаяСтрока(ИменаКолонок) Тогда ТипКоллекции = ТипЗнч(КоллекцияСтрок); ЭтоСписокЗначений = (ТипКоллекции = Тип("СписокЗначений")); ЭтоТаблицаЗначений = (ТипКоллекции = Тип("ТаблицаЗначений")); ЭтоКоллекцияКлючИЗначение = (ТипКоллекции = Тип("Соответствие")) Или (ТипКоллекции = Тип("Структура")) Или (ТипКоллекции = Тип("ФиксированноеСоответствие")) Или (ТипКоллекции = Тип("ФиксированнаяСтруктура")); СравниваемыеКолонки = Новый Массив; Если ЭтоТаблицаЗначений Тогда Для Каждого Колонка Из КоллекцияСтрок.Колонки Цикл СравниваемыеКолонки.Добавить(Колонка.Имя); КонецЦикла; ИначеЕсли ЭтоСписокЗначений Тогда СравниваемыеКолонки.Добавить("Значение"); СравниваемыеКолонки.Добавить("Картинка"); СравниваемыеКолонки.Добавить("Пометка"); СравниваемыеКолонки.Добавить("Представление"); ИначеЕсли ЭтоКоллекцияКлючИЗначение Тогда СравниваемыеКолонки.Добавить("Ключ"); СравниваемыеКолонки.Добавить("Значение"); Иначе ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Для коллекции типа %1 укажите имена полей, по которым производится сравнение в %2.\'"), ТипКоллекции, "ОбщегоНазначения.КоллекцииИдентичны"); КонецЕсли; Иначе СравниваемыеКолонки = СтрРазделить(СтрЗаменить(ИменаКолонок, " ", ""), ","); КонецЕсли; // Вычитаем исключаемые поля Если Не ПустаяСтрока(ИсключаяКолонки) Тогда ИсключаяКолонки = СтрРазделить(СтрЗаменить(ИсключаяКолонки, " ", ""), ","); СравниваемыеКолонки = ОбщегоНазначенияКлиентСервер.РазностьМассивов(СравниваемыеКолонки, ИсключаяКолонки); КонецЕсли; Возврат СравниваемыеКолонки; КонецФункции Функция СравнитьСУчетомПоследовательности(Знач КоллекцияСтрок1, Знач КоллекцияСтрок2, Знач СравниваемыеКолонки) ТипКоллекции = ТипЗнч(КоллекцияСтрок1); СравниваютсяМассивы = (ТипКоллекции = Тип("Массив") Или ТипКоллекции = Тип("ФиксированныйМассив")); // Параллельный обход обеих коллекций. НомерСтрокиКоллекции1 = 0; Для Каждого СтрокаКоллекции1 Из КоллекцияСтрок1 Цикл // Спозиционируемся на аналогичную строку второй коллекции. НомерСтрокиКоллекции2 = 0; ЕстьСтрокиКоллекции2 = Ложь; Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл ЕстьСтрокиКоллекции2 = Истина; Если НомерСтрокиКоллекции2 = НомерСтрокиКоллекции1 Тогда Прервать; КонецЕсли; НомерСтрокиКоллекции2 = НомерСтрокиКоллекции2 + 1; КонецЦикла; Если Не ЕстьСтрокиКоллекции2 Тогда // Во второй коллекции вообще нет строк. Возврат Ложь; КонецЕсли; // Сравниваем значения полей двух строк. Если СравниваютсяМассивы Тогда Если СтрокаКоллекции1 <> СтрокаКоллекции2 Тогда Возврат Ложь; КонецЕсли; Иначе Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл Если СтрокаКоллекции1[ИмяКолонки] <> СтрокаКоллекции2[ИмяКолонки] Тогда Возврат Ложь; КонецЕсли; КонецЦикла; КонецЕсли; НомерСтрокиКоллекции1 = НомерСтрокиКоллекции1 + 1; КонецЦикла; КоличествоСтрокКоллекции1 = НомерСтрокиКоллекции1; // Отдельно подсчитаем количество строк второй коллекции. КоличествоСтрокКоллекции2 = 0; Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл КоличествоСтрокКоллекции2 = КоличествоСтрокКоллекции2 + 1; КонецЦикла; // Если в первой коллекции не оказалось строк, // то их не должно быть и во второй. Если КоличествоСтрокКоллекции1 = 0 Тогда Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл Возврат Ложь; КонецЦикла; КоличествоСтрокКоллекции2 = 0; КонецЕсли; // Количество строк не должно отличаться. Если КоличествоСтрокКоллекции1 <> КоличествоСтрокКоллекции2 Тогда Возврат Ложь; КонецЕсли; Возврат Истина; КонецФункции Функция СравнитьБезУчетаПоследовательности(Знач КоллекцияСтрок1, Знач КоллекцияСтрок2, Знач СравниваемыеКолонки) // Строки отбора накапливаем по первой коллекции для того, чтобы: // - повторно не искать одинаковые строки, // - убедиться, что во второй коллекции ни одной такой строки, которой нет в накопленных. СтрокиОтбора = Новый ТаблицаЗначений; ПараметрыОтбора = Новый Структура; Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл СтрокиОтбора.Колонки.Добавить(ИмяКолонки); ПараметрыОтбора.Вставить(ИмяКолонки); КонецЦикла; ЕстьСтрокиКоллекции1 = Ложь; Для Каждого СтрокаОтбора Из КоллекцияСтрок1 Цикл ЗаполнитьЗначенияСвойств(ПараметрыОтбора, СтрокаОтбора); Если СтрокиОтбора.НайтиСтроки(ПараметрыОтбора).Количество() > 0 Тогда // Строку с такими полями уже искали. Продолжить; КонецЕсли; ЗаполнитьЗначенияСвойств(СтрокиОтбора.Добавить(), СтрокаОтбора); // Подсчитаем количество таких строк в первой коллекции. НайденоСтрокКоллекции1 = 0; Для Каждого СтрокаКоллекции1 Из КоллекцияСтрок1 Цикл СтрокаПодходит = Истина; Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл Если СтрокаКоллекции1[ИмяКолонки] <> СтрокаОтбора[ИмяКолонки] Тогда СтрокаПодходит = Ложь; Прервать; КонецЕсли; КонецЦикла; Если СтрокаПодходит Тогда НайденоСтрокКоллекции1 = НайденоСтрокКоллекции1 + 1; КонецЕсли; КонецЦикла; // Подсчитаем количество таких строк во второй коллекции. НайденоСтрокКоллекции2 = 0; Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл СтрокаПодходит = Истина; Для Каждого ИмяКолонки Из СравниваемыеКолонки Цикл Если СтрокаКоллекции2[ИмяКолонки] <> СтрокаОтбора[ИмяКолонки] Тогда СтрокаПодходит = Ложь; Прервать; КонецЕсли; КонецЦикла; Если СтрокаПодходит Тогда НайденоСтрокКоллекции2 = НайденоСтрокКоллекции2 + 1; // Если количество таких строк во второй коллекции превысило количество в первой, // то уже можно сделать вывод, что коллекции не идентичны. Если НайденоСтрокКоллекции2 > НайденоСтрокКоллекции1 Тогда Возврат Ложь; КонецЕсли; КонецЕсли; КонецЦикла; // Количество таких строк не должно отличаться. Если НайденоСтрокКоллекции1 <> НайденоСтрокКоллекции2 Тогда Возврат Ложь; КонецЕсли; ЕстьСтрокиКоллекции1 = Истина; КонецЦикла; // Если в первой коллекции не оказалось строк, // то их не должно быть и во второй. Если Не ЕстьСтрокиКоллекции1 Тогда Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл Возврат Ложь; КонецЦикла; КонецЕсли; // Проверим, что во второй коллекции нет ни одной такой строки, которой нет в накопленных. Для Каждого СтрокаКоллекции2 Из КоллекцияСтрок2 Цикл ЗаполнитьЗначенияСвойств(ПараметрыОтбора, СтрокаКоллекции2); Если СтрокиОтбора.НайтиСтроки(ПараметрыОтбора).Количество() = 0 Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; КонецФункции Функция СравнитьМассивы(Знач Массив1, Знач Массив2) Если Массив1.Количество() <> Массив2.Количество() Тогда Возврат Ложь; КонецЕсли; Для Каждого Элемент Из Массив1 Цикл Если Массив2.Найти(Элемент) = Неопределено Тогда Возврат Ложь; КонецЕсли; КонецЦикла; Возврат Истина; КонецФункции Процедура ПроверкаФиксированностиДанных(Данные, ДанныеВЗначенииФиксированныхТипов = Ложь) ТипДанных = ТипЗнч(Данные); СоставТипов = Новый ОписаниеТипов( "ХранилищеЗначения, |ФиксированныйМассив, |ФиксированнаяСтруктура, |ФиксированноеСоответствие"); Если СоставТипов.СодержитТип(ТипДанных) Тогда Возврат; КонецЕсли; Если ДанныеВЗначенииФиксированныхТипов Тогда СоставТипов = Новый ОписаниеТипов( "Булево,Строка,Число,Дата, |Неопределено,УникальныйИдентификатор,Null,Тип, |ХранилищеЗначения,ОбщийМодуль,ОбъектМетаданных, |ТипЗначенияXDTO,ТипОбъектаXDTO, |ИдентификаторОбсужденияСистемыВзаимодействия"); Если СоставТипов.СодержитТип(ТипДанных) Или ЭтоСсылка(ТипДанных) Тогда Возврат; КонецЕсли; КонецЕсли; ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Данные типа %1 не могут быть зафиксированы в функции %2.\'"), Строка(ТипДанных), "ОбщегоНазначения.ФиксированныеДанные"); КонецПроцедуры Функция РазмерСтрокиВБайтах(Знач Строка) Возврат ПолучитьДвоичныеДанныеИзСтроки(Строка, "UTF-8").Размер(); КонецФункции #Область СкопироватьРекурсивно Функция СкопироватьСтруктуру(СтруктураИсточник, ФиксироватьДанные) СтруктураРезультат = Новый Структура; Для Каждого КлючИЗначение Из СтруктураИсточник Цикл СтруктураРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные)); КонецЦикла; Если ФиксироватьДанные = Истина Или ФиксироватьДанные = Неопределено И ТипЗнч(СтруктураИсточник) = Тип("ФиксированнаяСтруктура") Тогда Возврат Новый ФиксированнаяСтруктура(СтруктураРезультат); КонецЕсли; Возврат СтруктураРезультат; КонецФункции Функция СкопироватьСоответствие(СоответствиеИсточник, ФиксироватьДанные) СоответствиеРезультат = Новый Соответствие; Для Каждого КлючИЗначение Из СоответствиеИсточник Цикл СоответствиеРезультат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение, ФиксироватьДанные)); КонецЦикла; Если ФиксироватьДанные = Истина Или ФиксироватьДанные = Неопределено И ТипЗнч(СоответствиеИсточник) = Тип("ФиксированноеСоответствие") Тогда Возврат Новый ФиксированноеСоответствие(СоответствиеРезультат); КонецЕсли; Возврат СоответствиеРезультат; КонецФункции Функция СкопироватьМассив(МассивИсточник, ФиксироватьДанные) МассивРезультат = Новый Массив; Для Каждого Элемент Из МассивИсточник Цикл МассивРезультат.Добавить(СкопироватьРекурсивно(Элемент, ФиксироватьДанные)); КонецЦикла; Если ФиксироватьДанные = Истина Или ФиксироватьДанные = Неопределено И ТипЗнч(МассивИсточник) = Тип("ФиксированныйМассив") Тогда Возврат Новый ФиксированныйМассив(МассивРезультат); КонецЕсли; Возврат МассивРезультат; КонецФункции Функция СкопироватьСписокЗначений(СписокИсточник, ФиксироватьДанные) СписокРезультат = Новый СписокЗначений; Для Каждого ЭлементСписка Из СписокИсточник Цикл СписокРезультат.Добавить( СкопироватьРекурсивно(ЭлементСписка.Значение, ФиксироватьДанные), ЭлементСписка.Представление, ЭлементСписка.Пометка, ЭлементСписка.Картинка); КонецЦикла; Возврат СписокРезультат; КонецФункции Процедура СкопироватьЗначенияТаблицыЗначений(ТаблицаЗначений, ФиксироватьДанные) Для Каждого СтрокаТаблицыЗначений Из ТаблицаЗначений Цикл Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл СтрокаТаблицыЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаТаблицыЗначений[Колонка.Имя], ФиксироватьДанные); КонецЦикла; КонецЦикла; КонецПроцедуры Процедура СкопироватьЗначенияСтрокиДереваЗначений(СтрокиДереваЗначений, ФиксироватьДанные); Для Каждого СтрокаДереваЗначений Из СтрокиДереваЗначений Цикл Для Каждого Колонка Из СтрокаДереваЗначений.Владелец().Колонки Цикл СтрокаДереваЗначений[Колонка.Имя] = СкопироватьРекурсивно(СтрокаДереваЗначений[Колонка.Имя], ФиксироватьДанные); КонецЦикла; СкопироватьЗначенияСтрокиДереваЗначений(СтрокаДереваЗначений.Строки, ФиксироватьДанные); КонецЦикла; КонецПроцедуры #КонецОбласти #КонецОбласти #Область Метаданные Процедура ПроверитьОбъектМетаданныхСуществует(ПолноеИмя) Если ОбъектМетаданныхПоПолномуИмени(ПолноеИмя) = Неопределено Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неизвестный тип объекта метаданных ""%1"".\'"), ПолноеИмя); КонецЕсли; КонецПроцедуры #КонецОбласти #Область ХранилищеНастроек Процедура ХранилищеСохранить(МенеджерХранилища, КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя, ОбновитьПовторноИспользуемыеЗначения) Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда Возврат; КонецЕсли; МенеджерХранилища.Сохранить(КлючОбъекта, КлючНастроек(КлючНастроек), Настройки, ОписаниеНастроек, ИмяПользователя); Если ОбновитьПовторноИспользуемыеЗначения Тогда ОбновитьПовторноИспользуемыеЗначения(); КонецЕсли; КонецПроцедуры Функция ХранилищеЗагрузить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ЗначениеПоУмолчанию, ОписаниеНастроек, ИмяПользователя) Результат = Неопределено; Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда Результат = МенеджерХранилища.Загрузить(КлючОбъекта, КлючНастроек(КлючНастроек), ОписаниеНастроек, ИмяПользователя); КонецЕсли; Если Результат = Неопределено Тогда Результат = ЗначениеПоУмолчанию; Иначе УстановитьПривилегированныйРежим(Истина); Если ОчиститьНесуществующиеСсылки(Результат) Тогда Результат = ЗначениеПоУмолчанию; КонецЕсли; КонецЕсли; Возврат Результат; КонецФункции // Удаляет из переданной коллекции ссылки, ссылающиеся на несуществующие данные в информационной базе. // Не очищает переданное значение, если в нем передана несуществующая ссылка, а возвращает Ложь. // // Параметры: // Значение - ЛюбаяСсылка // - Произвольный - проверяемое значение или коллекция. // // Возвращаемое значение: // Булево - Истина, если Значение ссылочного типа и объект не существует в информационной базе. // Ложь, если Значение не ссылочного типа или объект существует. // Функция ОчиститьНесуществующиеСсылки(Значение) Тип = ТипЗнч(Значение); Если Тип = Тип("Неопределено") Или Тип = Тип("Булево") Или Тип = Тип("Строка") Или Тип = Тип("Число") Или Тип = Тип("Дата") Тогда // Оптимизация - часто используемые примитивные типы. Возврат Ложь; // Не ссылка. ИначеЕсли Тип = Тип("Массив") Тогда Количество = Значение.Количество(); Для Номер = 1 По Количество Цикл ОбратныйИндекс = Количество - Номер; // @skip-check query-in-loop - выборка ссылок из разных таблиц. Если ОчиститьНесуществующиеСсылки(Значение[ОбратныйИндекс]) Тогда Значение.Удалить(ОбратныйИндекс); КонецЕсли; КонецЦикла; Возврат Ложь; // Не ссылка. ИначеЕсли Тип = Тип("Структура") Или Тип = Тип("Соответствие") Тогда Для Каждого КлючИЗначение Из Значение Цикл // @skip-check query-in-loop - выборка ссылок из разных таблиц. Если ОчиститьНесуществующиеСсылки(КлючИЗначение.Значение) Тогда Значение.Вставить(КлючИЗначение.Ключ, Неопределено); КонецЕсли; КонецЦикла; Возврат Ложь; // Не ссылка. ИначеЕсли Документы.ТипВсеСсылки().СодержитТип(Тип) Или Справочники.ТипВсеСсылки().СодержитТип(Тип) Или Перечисления.ТипВсеСсылки().СодержитТип(Тип) Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(Тип) Или ПланыСчетов.ТипВсеСсылки().СодержитТип(Тип) Или ПланыВидовРасчета.ТипВсеСсылки().СодержитТип(Тип) Или ПланыОбмена.ТипВсеСсылки().СодержитТип(Тип) Или БизнесПроцессы.ТипВсеСсылки().СодержитТип(Тип) Или Задачи.ТипВсеСсылки().СодержитТип(Тип) Тогда // Ссылочный тип, исключая ТочкаМаршрутаБизнесПроцессаСсылка. Если Значение.Пустая() Тогда Возврат Ложь; // Ссылка пустая. КонецЕсли; Возврат ЗначениеРеквизитаОбъекта(Значение, "Ссылка") = Неопределено; Иначе Возврат Ложь; // Не ссылка. КонецЕсли; КонецФункции Процедура ХранилищеУдалить(МенеджерХранилища, КлючОбъекта, КлючНастроек, ИмяПользователя) Если ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда МенеджерХранилища.Удалить(КлючОбъекта, КлючНастроек(КлючНастроек), ИмяПользователя); КонецЕсли; КонецПроцедуры // Возвращает строку ключа настроек, не превышающую допустимую длину 128 символов. // Если указанная строка превышает 128, тогда вместо символов сверх 96 символов // добавляется их хеш-сумма по алгоритму MD5 размером 32 символа. // // Параметры: // Строка - Строка - строка произвольной длины. // // Возвращаемое значение: // Строка - не более 128 символов. // Функция КлючНастроек(Знач Строка) Возврат СократитьСтрокуКонтрольнойСуммой(Строка, 128); КонецФункции #КонецОбласти #Область БезопасноеХранилище Функция ДанныеИзБезопасногоХранилища(Владельцы, Ключи, ОбщиеДанные) ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанных"; Если РазделениеВключено() И ДоступноИспользованиеРазделенныхДанных() И ОбщиеДанные <> Истина Тогда ИмяБезопасногоХранилищаДанных = "РегистрСведений.БезопасноеХранилищеДанныхОбластейДанных"; КонецЕсли; ТекстЗапроса = "ВЫБРАТЬ | БезопасноеХранилищеДанных.Владелец КАК ВладелецДанных, | БезопасноеХранилищеДанных.Данные КАК Данные |ИЗ | #ИмяБезопасногоХранилищаДанных КАК БезопасноеХранилищеДанных |ГДЕ | БезопасноеХранилищеДанных.Владелец В (&Владельцы)"; ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#ИмяБезопасногоХранилищаДанных", ИмяБезопасногоХранилищаДанных); Запрос = Новый Запрос(ТекстЗапроса); Запрос.УстановитьПараметр("Владельцы", Владельцы); РезультатЗапроса = Запрос.Выполнить().Выбрать(); Результат = Новый Соответствие(); НаборДанныхКлюча = ?(ЗначениеЗаполнено(Ключи) И СтрНайти(Ключи, ","), Новый Структура(Ключи), Неопределено); Для Каждого ВладелецДанных Из Владельцы Цикл Результат.Вставить(ВладелецДанных, НаборДанныхКлюча); КонецЦикла; Пока РезультатЗапроса.Следующий() Цикл ДанныеВладельца = Новый Структура(Ключи); Если ЗначениеЗаполнено(РезультатЗапроса.Данные) Тогда СохраненныеДанные = РезультатЗапроса.Данные.Получить(); Если ЗначениеЗаполнено(СохраненныеДанные) Тогда Если ЗначениеЗаполнено(Ключи) Тогда ВладелецДанных = Результат[РезультатЗапроса.ВладелецДанных]; ЗаполнитьЗначенияСвойств(ДанныеВладельца, СохраненныеДанные); Иначе ДанныеВладельца = СохраненныеДанные; КонецЕсли; Если Ключи <> Неопределено И ДанныеВладельца <> Неопределено И ДанныеВладельца.Количество() = 1 Тогда ЗначениеПоКлючу = ?(ДанныеВладельца.Свойство(Ключи), ДанныеВладельца[Ключи], Неопределено); Результат.Вставить(РезультатЗапроса.ВладелецДанных, ЗначениеПоКлючу); Иначе Результат.Вставить(РезультатЗапроса.ВладелецДанных, ДанныеВладельца); КонецЕсли; КонецЕсли; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции #КонецОбласти #Область БезопасноеВыполнениеВнешнегоКода // Проверяет, что переданное имя ИмяПроцедуры является именем экспортной процедуры конфигурации. // Может использоваться для проверки, что переданная строка не содержит произвольного алгоритма // на встроенном языке 1С:Предприятия перед использованием его в операторах Выполнить и Вычислить // при их использовании для динамического вызова методов код конфигурации. // // В случае если переданная строка не является именем процедуры конфигурации, генерируется исключение. // // Предназначена для вызова из см. процедуру ВыполнитьМетодКонфигурации. // // Параметры: // ИмяПроцедуры - Строка - проверяемое имя экспортной процедуры. // Процедура ПроверитьИмяПроцедурыКонфигурации(Знач ИмяПроцедуры) ЧастиИмени = СтрРазделить(ИмяПроцедуры, "."); Если ЧастиИмени.Количество() <> 2 И ЧастиИмени.Количество() <> 3 Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неправильный формат параметра %1 (передано значение: ""%2"") в %3.\'"), "ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации"); КонецЕсли; ИмяОбъекта = ЧастиИмени[0]; Если ЧастиИмени.Количество() = 2 И Метаданные.ОбщиеМодули.Найти(ИмяОбъекта) = Неопределено Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неправильный формат параметра %1 (передано значение: ""%2"") в %3: |Не существует общий модуль ""%4"".\'"), "ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации", ИмяОбъекта); КонецЕсли; Если ЧастиИмени.Количество() = 3 Тогда ПолноеИмяОбъекта = ЧастиИмени[0] + "." + ЧастиИмени[1]; Попытка Менеджер = МенеджерОбъектаПоИмени(ПолноеИмяОбъекта); Исключение Менеджер = Неопределено; КонецПопытки; Если Менеджер = Неопределено Тогда ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неправильный формат параметра %1 (передано значение: ""%2"") в %3: |Не существует менеджер объекта ""%4"".\'"), "ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации", ПолноеИмяОбъекта); КонецЕсли; КонецЕсли; ИмяМетодаОбъекта = ЧастиИмени[ЧастиИмени.ВГраница()]; ВременнаяСтруктура = Новый Структура; Попытка // Проверка того, что ИмяПроцедуры является допустимым идентификатором. // Например: МояПроцедура. ВременнаяСтруктура.Вставить(ИмяМетодаОбъекта); Исключение ЗаписьЖурналаРегистрации(НСтр("ru = \'Безопасное выполнение метода\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Неправильный формат параметра %1 (передано значение: ""%2"") в %3: |Имя метода ""%4"" не соответствует требованиям образования имен процедур и функций.\'"), "ИмяПроцедуры", ИмяПроцедуры, "ОбщегоНазначения.ВыполнитьМетодКонфигурации", ИмяМетодаОбъекта); КонецПопытки; КонецПроцедуры // Возвращает менеджер объекта по имени. // Ограничение: не обрабатываются точки маршрутов бизнес-процессов. // // Параметры: // Имя - Строка - имя например, "Справочник", "Справочники", "Справочник.Организации". // // Возвращаемое значение: // СправочникиМенеджер // СправочникМенеджер // ДокументыМенеджер // ДокументМенеджер // ... // Функция МенеджерОбъектаПоИмени(Имя) Перем КлассОМ, ИмяОМ, Менеджер; ЧастиИмени = СтрРазделить(Имя, "."); Если ЧастиИмени.Количество() > 0 Тогда КлассОМ = ВРег(ЧастиИмени[0]); КонецЕсли; Если ЧастиИмени.Количество() > 1 Тогда ИмяОМ = ЧастиИмени[1]; КонецЕсли; Если КлассОМ = "ПЛАНОБМЕНА" Или КлассОМ = "ПЛАНЫОБМЕНА" Тогда Менеджер = ПланыОбмена; ИначеЕсли КлассОМ = "СПРАВОЧНИК" Или КлассОМ = "СПРАВОЧНИКИ" Тогда Менеджер = Справочники; ИначеЕсли КлассОМ = "ДОКУМЕНТ" Или КлассОМ = "ДОКУМЕНТЫ" Тогда Менеджер = Документы; ИначеЕсли КлассОМ = "ЖУРНАЛДОКУМЕНТОВ" Или КлассОМ = "ЖУРНАЛЫДОКУМЕНТОВ" Тогда Менеджер = ЖурналыДокументов; ИначеЕсли КлассОМ = "ПЕРЕЧИСЛЕНИЕ" Или КлассОМ = "ПЕРЕЧИСЛЕНИЯ" Тогда Менеджер = Перечисления; ИначеЕсли КлассОМ = "ОБЩИЙМОДУЛЬ" Или КлассОМ = "ОБЩИЕМОДУЛИ" Тогда Возврат ОбщийМодуль(ИмяОМ); ИначеЕсли КлассОМ = "ОТЧЕТ" Или КлассОМ = "ОТЧЕТЫ" Тогда Менеджер = Отчеты; ИначеЕсли КлассОМ = "ОБРАБОТКА" Или КлассОМ = "ОБРАБОТКИ" Тогда Менеджер = Обработки; ИначеЕсли КлассОМ = "ПЛАНВИДОВХАРАКТЕРИСТИК" Или КлассОМ = "ПЛАНЫВИДОВХАРАКТЕРИСТИК" Тогда Менеджер = ПланыВидовХарактеристик; ИначеЕсли КлассОМ = "ПЛАНСЧЕТОВ" Или КлассОМ = "ПЛАНЫСЧЕТОВ" Тогда Менеджер = ПланыСчетов; ИначеЕсли КлассОМ = "ПЛАНВИДОВРАСЧЕТА" Или КлассОМ = "ПЛАНЫВИДОВРАСЧЕТА" Тогда Менеджер = ПланыВидовРасчета; ИначеЕсли КлассОМ = "РЕГИСТРСВЕДЕНИЙ" Или КлассОМ = "РЕГИСТРЫСВЕДЕНИЙ" Тогда Менеджер = РегистрыСведений; ИначеЕсли КлассОМ = "РЕГИСТРНАКОПЛЕНИЯ" Или КлассОМ = "РЕГИСТРЫНАКОПЛЕНИЯ" Тогда Менеджер = РегистрыНакопления; ИначеЕсли КлассОМ = "РЕГИСТРБУХГАЛТЕРИИ" Или КлассОМ = "РЕГИСТРЫБУХГАЛТЕРИИ" Тогда Менеджер = РегистрыБухгалтерии; ИначеЕсли КлассОМ = "РЕГИСТРРАСЧЕТА" Или КлассОМ = "РЕГИСТРЫРАСЧЕТА" Тогда Если ЧастиИмени.Количество() < 3 Тогда // Регистр расчета Менеджер = РегистрыРасчета; Иначе КлассПодчиненногоОМ = ВРег(ЧастиИмени[2]); Если ЧастиИмени.Количество() > 3 Тогда ИмяПодчиненногоОМ = ЧастиИмени[3]; КонецЕсли; Если КлассПодчиненногоОМ = "ПЕРЕРАСЧЕТ" Или КлассПодчиненногоОМ = "ПЕРЕРАСЧЕТЫ" Тогда // Перерасчет Попытка Менеджер = РегистрыРасчета[ИмяОМ].Перерасчеты; ИмяОМ = ИмяПодчиненногоОМ; Исключение Менеджер = Неопределено; КонецПопытки; КонецЕсли; КонецЕсли; ИначеЕсли КлассОМ = "БИЗНЕСПРОЦЕСС" Или КлассОМ = "БИЗНЕСПРОЦЕССЫ" Тогда Менеджер = БизнесПроцессы; ИначеЕсли КлассОМ = "ЗАДАЧА" Или КлассОМ = "ЗАДАЧИ" Тогда Менеджер = Задачи; ИначеЕсли КлассОМ = "КОНСТАНТА" Или КлассОМ = "КОНСТАНТЫ" Тогда Менеджер = Константы; ИначеЕсли КлассОМ = "ПОСЛЕДОВАТЕЛЬНОСТЬ" Или КлассОМ = "ПОСЛЕДОВАТЕЛЬНОСТИ" Тогда Менеджер = Последовательности; КонецЕсли; Если Менеджер <> Неопределено Тогда Если ЗначениеЗаполнено(ИмяОМ) Тогда Попытка Возврат Менеджер[ИмяОМ]; Исключение Менеджер = Неопределено; КонецПопытки; Иначе Возврат Менеджер; КонецЕсли; КонецЕсли; ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = \'Не удалось получить менеджер для объекта ""%1""\'"), Имя); КонецФункции // Вызвать экспортную функцию по имени с уровнем привилегий конфигурации. // При включении профилей безопасности для вызова оператора Выполнить() используется // переход в безопасный режим с профилем безопасности, используемом для информационной базы // (если выше по стеку не был установлен другой безопасный режим). // // Параметры: // ИмяМетода - Строка - имя экспортной функции в формате // <имя объекта>.<имя процедуры>, где <имя объекта> - это // общий модуль или модуль менеджера объекта. // Параметры - Массив - параметры передаются в функцию <ИмяМетода> // в порядке расположения элементов массива. // // Возвращаемое значение: // Произвольный - результат вызываемой функции. // Функция ВызватьФункциюКонфигурации(Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт ПроверитьИмяПроцедурыКонфигурации(ИмяМетода); Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме"); Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности() И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы(); Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда УстановитьБезопасныйРежим(ПрофильИнформационнойБазы); Если БезопасныйРежим() = Истина Тогда УстановитьБезопасныйРежим(Ложь); КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; ПараметрыСтрока = ""; Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда Для Индекс = 0 По Параметры.ВГраница() Цикл ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],"; КонецЦикла; ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1); КонецЕсли; Возврат Вычислить(ИмяМетода + "(" + ПараметрыСтрока + ")"); // АПК:488 Исполняемый код безопасен. КонецФункции // Вызвать экспортную функцию объекта встроенного языка по имени. // При включении профилей безопасности для вызова оператора Выполнить() используется // переход в безопасный режим с профилем безопасности, используемом для информационной базы // (если выше по стеку не был установлен другой безопасный режим). // // Параметры: // Объект - Произвольный - объект встроенного языка 1С:Предприятия, содержащий методы (например, ОбработкаОбъект). // ИмяМетода - Строка - имя экспортной функции модуля объекта обработки. // Параметры - Массив - параметры передаются в функцию <ИмяМетода> // в порядке расположения элементов массива. // // Возвращаемое значение: // Произвольный - результат вызываемой функции. // Функция ВызватьФункциюОбъекта(Знач Объект, Знач ИмяМетода, Знач Параметры = Неопределено) Экспорт // Проверка имени метода на корректность. Попытка Тест = Новый Структура; Тест.Вставить(ИмяМетода, ИмяМетода); Исключение ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Некорректное значение параметра %1 (%2) в %3.\'"), "ИмяМетода", ИмяМетода, "ОбщегоНазначения.ВыполнитьМетодОбъекта"); КонецПопытки; Если ПодсистемаСуществует("СтандартныеПодсистемы.ПрофилиБезопасности") Тогда МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме"); Если МодульРаботаВБезопасномРежиме.ИспользуютсяПрофилиБезопасности() И Не МодульРаботаВБезопасномРежиме.УстановленБезопасныйРежим() Тогда МодульРаботаВБезопасномРежиме = ОбщийМодуль("РаботаВБезопасномРежиме"); ПрофильИнформационнойБазы = МодульРаботаВБезопасномРежиме.ПрофильБезопасностиИнформационнойБазы(); Если ЗначениеЗаполнено(ПрофильИнформационнойБазы) Тогда УстановитьБезопасныйРежим(ПрофильИнформационнойБазы); Если БезопасныйРежим() = Истина Тогда УстановитьБезопасныйРежим(Ложь); КонецЕсли; КонецЕсли; КонецЕсли; КонецЕсли; ПараметрыСтрока = ""; Если Параметры <> Неопределено И Параметры.Количество() > 0 Тогда Для Индекс = 0 По Параметры.ВГраница() Цикл ПараметрыСтрока = ПараметрыСтрока + "Параметры[" + XMLСтрока(Индекс) + "],"; КонецЦикла; ПараметрыСтрока = Сред(ПараметрыСтрока, 1, СтрДлина(ПараметрыСтрока) - 1); КонецЕсли; Возврат Вычислить("Объект." + ИмяМетода + "(" + ПараметрыСтрока + ")"); // АПК:488 Исполняемый код безопасен. КонецФункции #КонецОбласти #Область ВнешниеКомпоненты Процедура ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение) Если МакетСуществует(Местоположение) Тогда Возврат; КонецЕсли; Если ПодсистемаСуществует("СтандартныеПодсистемы.ВнешниеКомпоненты") Тогда МодульВнешниеКомпонентыСлужебный = ОбщийМодуль("ВнешниеКомпонентыСлужебный"); МодульВнешниеКомпонентыСлужебный.ПроверитьМестоположениеКомпоненты(Идентификатор, Местоположение); Иначе ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Указан несуществующий макет ""%1"" при подключении внешней компоненты ""%2"".\'"), Местоположение, Идентификатор); КонецЕсли; КонецПроцедуры Функция МакетСуществует(ПолноеИмяМакета) Макет = Метаданные.НайтиПоПолномуИмени(ПолноеИмяМакета); Если ТипЗнч(Макет) = Тип("ОбъектМетаданных") Тогда Шаблон = Новый Структура("ТипМакета"); ЗаполнитьЗначенияСвойств(Шаблон, Макет); ТипМакета = Неопределено; Если Шаблон.Свойство("ТипМакета", ТипМакета) Тогда Возврат ТипМакета <> Неопределено; КонецЕсли; КонецЕсли; Возврат Ложь; КонецФункции #КонецОбласти #Область ТекущееОкружение Функция НомерСборкиПоТекущейВерсииПлатформы(НомераСборокСтрокой) НомераСборок = СтрРазделить(НомераСборокСтрокой, ";", Истина); СборкиПоВерсиям = Новый Соответствие; Для Каждого НомерСборки Из НомераСборок Цикл НомерВерсии = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(НомерСборки); СборкиПоВерсиям.Вставить(СокрЛП(НомерВерсии), СокрЛП(НомерСборки)); КонецЦикла; СистемнаяИнформация = Новый СистемнаяИнформация; ТекущаяВерсия = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения); Результат = СборкиПоВерсиям[ТекущаяВерсия]; Если Не ЗначениеЗаполнено(Результат) Тогда Результат = НомераСборок[0]; КонецЕсли; Возврат Результат; КонецФункции // Ниже этой версии БСП может запуститься и показать окно с рекомендациями, если она выше чем в МинимальнаяВерсияПлатформыДляЗапуска. Функция МинимальнаяВерсияПлатформы() Экспорт // АПК:581 - экспортная, так как используется при тестировании. ВерсияРежимаСовместимости = ВерсияРежимаСовместимости(); ПоддерживаемыеВерсииПлатформы = ПоддерживаемыеВерсииПлатформы(); НайденнаяВерсия = ПоддерживаемыеВерсииПлатформы.НайтиПоЗначению(ВерсияРежимаСовместимости); Если НайденнаяВерсия = Неопределено Тогда НайденнаяВерсия = ПоддерживаемыеВерсииПлатформы[ПоддерживаемыеВерсииПлатформы.Количество() - 1]; КонецЕсли; НомераСборок = НайденнаяВерсия.Представление; Возврат НомераСборок; КонецФункции // Ниже этой версии БСП не может запуститься и показать окно с рекомендациями. Функция МинимальнаяВерсияПлатформыДляЗапуска() Экспорт Возврат "8.3.21.1622; 8.3.22.1704"; КонецФункции // Возвращаемое значение: // СписокЗначений: // * Значение - Строка - поддерживаемый номер версии (режим совместимости); // * Представление - Строка - минимальные номера сборок платформы, разделитель - точка с запятой. // Функция ПоддерживаемыеВерсииПлатформы() Экспорт ПоддерживаемыеВерсииПлатформы = Новый СписокЗначений; ПоддерживаемыеВерсииПлатформы.Добавить("8.3.21", "8.3.21.1775; 8.3.22.1923"); ПоддерживаемыеВерсииПлатформы.Добавить("8.3.22", "8.3.22.2355; 8.3.23.2011; 8.3.24.1304"); ПоддерживаемыеВерсииПлатформы.Добавить("8.3.23", "8.3.23.2011; 8.3.24.1304"); ПоддерживаемыеВерсииПлатформы.Добавить("8.3.24", "8.3.24.1304"); Возврат ПоддерживаемыеВерсииПлатформы; КонецФункции Функция ВерсияРежимаСовместимости() Экспорт СистемнаяИнформация = Новый СистемнаяИнформация(); РежимСовместимости = Метаданные.РежимСовместимости; Если РежимСовместимости = Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда ВерсияРежимаСовместимости = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(СистемнаяИнформация.ВерсияПриложения); Иначе ВерсияРежимаСовместимости = СтрСоединить(СтрРазделить(РежимСовместимости, СтрСоединить(СтрРазделить(РежимСовместимости, "1234567890", Ложь), ""), Ложь), "."); КонецЕсли; Возврат ВерсияРежимаСовместимости; КонецФункции // Выполняет проверку правильности заполнения минимальной и рекомендуемой версии платформы. // // Параметры: // Минимальная - Строка - номер версия платформы. // Рекомендуемая - Строка - номер версия платформы. // // Возвращаемое значение: // Булево - Истина, если минимальная и рекомендуемая версия платформы заполнена неправильно. // Функция МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) // Минимальная версия платформы должна быть заполнена. Если ПустаяСтрока(Минимальная) Тогда Возврат Истина; КонецЕсли; // Минимальная версия платформы, заданная в конфигурации, не должна быть меньше минимальной версии платформы, // заданной в библиотеке. МинимальнаяБСП = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()); Если Не ЭтоВерсияЗащищенногоПрограммногоКомплекса(Минимальная) И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(МинимальнаяБСП, Минимальная) > 0 Тогда Возврат Истина; КонецЕсли; // Минимальная версия платформы не должны быть больше рекомендуемой. Возврат Не ПустаяСтрока(Минимальная) И Не ПустаяСтрока(Рекомендуемая) И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Минимальная, Рекомендуемая) > 0; КонецФункции Функция НедопустимыеВерсииПлатформы() Экспорт Возврат ""; КонецФункции Функция ЭтоВерсияЗащищенногоПрограммногоКомплекса(Версия) Версии = Новый Массив; Версии.Добавить("8.3.21.1676"); Версии.Добавить("8.3.21.1901"); Возврат Версии.Найти(Версия) <> Неопределено; КонецФункции // Для функции ОбщиеПараметрыБазовойФункциональности. Процедура УточнитьВерсиюПлатформы(ОбщиеПараметры) СистемнаяИнформация = Новый СистемнаяИнформация; НоваяСборка = НоваяСборка(СистемнаяИнформация.ВерсияПриложения); Если Не ЗначениеЗаполнено(НоваяСборка) Тогда НоваяРекомендуемаяСборка = НоваяСборка(ОбщиеПараметры.МинимальнаяВерсияПлатформы); Если ЗначениеЗаполнено(НоваяРекомендуемаяСборка) Тогда МинимальнаяСборка = НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()); ОбщиеПараметры.МинимальнаяВерсияПлатформы = МинимальнаяСборка; ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = МинимальнаяСборка; Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.РекомендуемаяВерсияПлатформы, НоваяРекомендуемаяСборка) < 0 Тогда ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяРекомендуемаяСборка; КонецЕсли; КонецЕсли; ИначеЕсли ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ОбщиеПараметры.МинимальнаяВерсияПлатформы, НоваяСборка) < 0 Тогда ОбщиеПараметры.РекомендуемаяВерсияПлатформы = НоваяСборка; ОбщиеПараметры.МинимальнаяВерсияПлатформы = НоваяСборка; ОбщиеПараметры.МинимальноНеобходимаяВерсияПлатформы = НоваяСборка; ОбщиеПараметры.РаботаВПрограммеЗапрещена = Истина; КонецЕсли; КонецПроцедуры // Для процедуры УточнитьВерсиюПлатформы. Функция НоваяСборка(ТекущаяСборка) Если СтрНайти("8.3.22.1672,8.3.22.1603", ТекущаяСборка) Тогда Возврат "8.3.22.1709"; ИначеЕсли СтрНайти("8.3.21.1607,8.3.21.1508,8.3.21.1484", ТекущаяСборка) Тогда Возврат "8.3.21.1624"; КонецЕсли; Возврат ""; КонецФункции // Локализация // Параметры: // ОбщиеПараметры - см. ОбщиеПараметрыБазовойФункциональности // Процедура УточнитьМинимальнуюВерсиюПлатформыИзСервиса(ОбщиеПараметры) Если Не ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеОбновленийПрограммы") Тогда Возврат; КонецЕсли; // Проверка версии БИП начиная с которой появился программный интерфейс МодульИнтернетПоддержкаПользователейКлиентСервер = ОбщийМодуль("ИнтернетПоддержкаПользователейКлиентСервер"); ВерсияБИП = МодульИнтернетПоддержкаПользователейКлиентСервер.ВерсияБиблиотеки(); Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ВерсияБИП, "2.7.1.35") <= 0 Тогда Возврат; КонецЕсли; Попытка МодульПолучениеОбновленийПрограммы = ОбщийМодуль("ПолучениеОбновленийПрограммы"); ИнформацияОВерсияхПлатформы = МодульПолучениеОбновленийПрограммы.ИнформацияОВерсияхПлатформы(); // Контроль заполнения версий платформы по данным сервиса Если ПустаяСтрока(ИнформацияОВерсияхПлатформы.МинимальнаяВерсияПлатформы) И ПустаяСтрока(ИнформацияОВерсияхПлатформы.РекомендуемаяВерсияПлатформы) Тогда Возврат; КонецЕсли; Минимальная = НомерСборкиПоТекущейВерсииПлатформы(ИнформацияОВерсияхПлатформы.МинимальнаяВерсияПлатформы); Рекомендуемая = НомерСборкиПоТекущейВерсииПлатформы(ИнформацияОВерсияхПлатформы.РекомендуемаяВерсияПлатформы); Если МинимальнаяИРекомендуемаяВерсияПлатформыЗаполненаНеПравильно(Минимальная, Рекомендуемая) Тогда МодульПолучениеОбновленийПрограммы.УдалитьИнформациюОВерсияхПлатформы(); ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Минимальная и рекомендуемая версии платформы ""1С:Предприятие"", полученные с сервиса обновления программ, не соответствуют следующим требованиям: | - минимальная версия должна быть заполнена; | - минимальная версия не должна быть меньше минимальной версии БСП (см. %1); | - минимальная версия не должна быть меньше рекомендуемой версии. |Минимальная версия сервиса обновления программ: %2 |Минимальная версия БСП: %3 |Рекомендуемая версия сервиса обновления программ: %4 | |Минимальная и рекомендуемая версия платформы ""1С:Предприятие"" установлена по данным см. %5. |Минимальная версия: %6 |Рекомендуемая версия: %7\'", КодОсновногоЯзыка()), "ОбщегоНазначения.МинимальнаяВерсияПлатформы", Минимальная, НомерСборкиПоТекущейВерсииПлатформы(МинимальнаяВерсияПлатформы()), Рекомендуемая, "ОбщегоНазначенияПереопределяемый.ПриОпределенииОбщихПараметровБазовойФункциональности", ОбщиеПараметры.МинимальнаяВерсияПлатформы, ОбщиеПараметры.РекомендуемаяВерсияПлатформы); ЗаписьЖурналаРегистрации(НСтр("ru = \'Базовая функциональность\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,, ТекстСообщения); Возврат; КонецЕсли; ОбщиеПараметры.МинимальнаяВерсияПлатформы = Минимальная; ОбщиеПараметры.РекомендуемаяВерсияПлатформы = Рекомендуемая; Исключение ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = \'Не удалось изменить минимальную и рекомендуемую версию платформы ""1С:Предприятие"", полученную с сервиса обновления программ, по причине: |%1\'", КодОсновногоЯзыка()), ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); ЗаписьЖурналаРегистрации(НСтр("ru = \'Базовая функциональность\'", КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Предупреждение,,, ТекстСообщения); КонецПопытки; КонецПроцедуры // Конец Локализация #КонецОбласти #КонецОбласти #КонецЕсли ' # Print the match result str.scan(re) do |match| puts match.to_s end

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 Ruby, please visit: http://ruby-doc.org/core-2.2.0/Regexp.html